import test from "node:test"; import assert from "node:assert/strict"; import http from "node:http"; import { spawn } from "node:child_process"; function listen(server) { return new Promise((resolve) => { server.listen(0, "127.0.0.1", () => { const address = server.address(); resolve(address.port); }); }); } function closeServer(server) { return new Promise((resolve) => server.close(() => resolve())); } async function waitForHealth(url, timeoutMs = 5000) { const start = Date.now(); while (Date.now() - start < timeoutMs) { try { const response = await fetch(`${url}/health`); if (response.ok) return; } catch {} await new Promise((resolve) => setTimeout(resolve, 100)); } throw new Error("BFF health timeout"); } async function startBff(env) { const child = spawn("node", ["server.mjs"], { cwd: new URL("..", import.meta.url), env: { ...process.env, ...env }, stdio: ["ignore", "pipe", "pipe"] }); const logs = []; child.stdout.on("data", (chunk) => logs.push(chunk.toString("utf-8"))); child.stderr.on("data", (chunk) => logs.push(chunk.toString("utf-8"))); const port = Number(env.PORT); const baseUrl = `http://127.0.0.1:${port}`; await waitForHealth(baseUrl); return { baseUrl, logs, stop: async () => { child.kill("SIGTERM"); await new Promise((resolve) => child.on("exit", () => resolve())); } }; } function createUpstreamStub(options = {}) { const state = { evaluateMode: options.evaluateMode || "success", evaluatePayload: null, exposurePayload: null }; const server = http.createServer(async (req, res) => { if (req.method === "POST" && req.url === "/api/feature-control/evaluate") { const chunks = []; for await (const chunk of req) chunks.push(chunk); state.evaluatePayload = JSON.parse(Buffer.concat(chunks).toString("utf-8")); if (state.evaluateMode === "429") { res.writeHead(429, { "Content-Type": "application/json" }); res.end(JSON.stringify({ code: "FEATURE_CONTROL_RATE_LIMIT", message: "rate" })); return; } if (state.evaluateMode === "500") { res.writeHead(500, { "Content-Type": "application/json" }); res.end(JSON.stringify({ code: "FEATURE_CONTROL_ERROR", message: "boom" })); return; } if (state.evaluateMode === "timeout") { await new Promise((resolve) => setTimeout(resolve, 600)); } res.writeHead(200, { "Content-Type": "application/json" }); res.end( JSON.stringify({ error: false, code: "FEATURE_CONTROL_EVALUATED", result: { evaluatedAt: "2026-04-16T12:00:00.000Z", configVersion: 7, flags: { "fc.promo": { enabled: true, variant: "on", payload: null, reason: "rollout" }, "fc.promo-codes": { enabled: true, variant: "on", payload: null, reason: "rollout" }, "fc.ios": { enabled: true, variant: "on", payload: null, reason: "audience" } } } }) ); return; } if (req.method === "POST" && req.url === "/api/feature-control/telemetry/exposure") { const chunks = []; for await (const chunk of req) chunks.push(chunk); state.exposurePayload = JSON.parse(Buffer.concat(chunks).toString("utf-8")); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: false, code: "FEATURE_CONTROL_EXPOSURE_TRACKED", result: { accepted: true } })); return; } res.writeHead(404).end(); }); return { server, state }; } function bootstrapBody() { return { environment: "production", keys: ["fc.promo", "fc.promo-codes", "fc.ios"], context: { subjectType: "customer", subjectId: "cust_123", storeId: "store_001", platform: "ios", appVersion: "2.3.1", attributes: { city: "Campinas" } } }; } test("bootstrap sucesso retorna flags simplificadas e raw", async () => { const upstream = createUpstreamStub({ evaluateMode: "success" }); const upstreamPort = await listen(upstream.server); const bffPort = upstreamPort + 1000; const bff = await startBff({ PORT: String(bffPort), ATOMENTA_ORIGIN: `http://127.0.0.1:${upstreamPort}`, FEATURE_CONTROL_MODULE_TOKEN: "token", FEATURE_CONTROL_TIMEOUT_MS: "300" }); try { const response = await fetch(`${bff.baseUrl}/feature-control/bootstrap`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(bootstrapBody()) }); assert.equal(response.status, 200); const json = await response.json(); assert.equal(json.ok, true); assert.equal(json.configVersion, 7); assert.equal(json.flags.promo, true); assert.equal(json.flags.promoCodes, true); assert.equal(json.flags.ios, true); assert.ok(json.raw["fc.promo"]); assert.equal(upstream.state.evaluatePayload.context.subjectId, "cust_123"); } finally { await bff.stop(); await closeServer(upstream.server); } }); test("bootstrap com 429 devolve fallback sem quebrar cliente", async () => { const upstream = createUpstreamStub({ evaluateMode: "429" }); const upstreamPort = await listen(upstream.server); const bffPort = upstreamPort + 1000; const bff = await startBff({ PORT: String(bffPort), ATOMENTA_ORIGIN: `http://127.0.0.1:${upstreamPort}`, FEATURE_CONTROL_MODULE_TOKEN: "token", FEATURE_CONTROL_DEFAULTS_JSON: JSON.stringify({ "fc.promo": { enabled: false, variant: "off" } }) }); try { const response = await fetch(`${bff.baseUrl}/feature-control/bootstrap`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(bootstrapBody()) }); assert.equal(response.status, 200); const json = await response.json(); assert.equal(json.source, "fallback"); assert.equal(json.upstreamError.status, 429); assert.equal(json.flags.promo, "off"); } finally { await bff.stop(); await closeServer(upstream.server); } }); test("bootstrap com timeout devolve fallback", async () => { const upstream = createUpstreamStub({ evaluateMode: "timeout" }); const upstreamPort = await listen(upstream.server); const bffPort = upstreamPort + 1000; const bff = await startBff({ PORT: String(bffPort), ATOMENTA_ORIGIN: `http://127.0.0.1:${upstreamPort}`, FEATURE_CONTROL_MODULE_TOKEN: "token", FEATURE_CONTROL_TIMEOUT_MS: "100" }); try { const response = await fetch(`${bff.baseUrl}/feature-control/bootstrap`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(bootstrapBody()) }); assert.equal(response.status, 200); const json = await response.json(); assert.equal(json.source, "fallback"); assert.equal(json.upstreamError.code, "FEATURE_CONTROL_UPSTREAM_TIMEOUT"); } finally { await bff.stop(); await closeServer(upstream.server); } }); test("telemetria de exposure encaminha lote para upstream", async () => { const upstream = createUpstreamStub({ evaluateMode: "success" }); const upstreamPort = await listen(upstream.server); const bffPort = upstreamPort + 1000; const bff = await startBff({ PORT: String(bffPort), ATOMENTA_ORIGIN: `http://127.0.0.1:${upstreamPort}`, FEATURE_CONTROL_MODULE_TOKEN: "token" }); try { const response = await fetch(`${bff.baseUrl}/feature-control/telemetry/exposure`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ events: [ { featureKey: "fc.promo", variant: "on", subjectType: "customer", storeId: "store_1" } ] }) }); assert.equal(response.status, 200); const json = await response.json(); assert.equal(json.ok, true); assert.equal(upstream.state.exposurePayload.events[0].featureKey, "fc.promo"); } finally { await bff.stop(); await closeServer(upstream.server); } }); test("telemetria rejeita payload sem eventos", async () => { const upstream = createUpstreamStub({ evaluateMode: "success" }); const upstreamPort = await listen(upstream.server); const bffPort = upstreamPort + 1000; const bff = await startBff({ PORT: String(bffPort), ATOMENTA_ORIGIN: `http://127.0.0.1:${upstreamPort}`, FEATURE_CONTROL_MODULE_TOKEN: "token" }); try { const response = await fetch(`${bff.baseUrl}/feature-control/telemetry/exposure`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ events: [] }) }); assert.equal(response.status, 400); const json = await response.json(); assert.equal(json.ok, false); assert.equal(json.code, "FEATURE_CONTROL_EVENTS_REQUIRED"); } finally { await bff.stop(); await closeServer(upstream.server); } });