MessageWeave/cloudflare-worker/test/index.test.js

159 lines
5.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 集成测试:Cloudflare Worker 主入口 handle fetch(ARCH-LB-WORKER / SAF-LB-PASSTHRU)。
* 验证:路由分发、/healthz 聚合、未白名单 404、method 拦截、配置异常 fail-closed、鉴权头透传。
* 运行:cd cloudflare-worker && node --test
*/
import test from "node:test";
import assert from "node:assert/strict";
import { handleFetch } from "../src/index.js";
function makeEnv(overrides = {}) {
return {
BACKEND_ORIGINS_JSON: JSON.stringify(["https://a.example", "https://b.example"]),
LB_REQUEST_TIMEOUT_MS: "5000",
LB_MAX_ATTEMPTS: "2",
...overrides,
};
}
/** 安装/卸载 globalThis.fetch mock。 */
function stubFetch(impl) {
const orig = globalThis.fetch;
globalThis.fetch = impl;
return () => {
globalThis.fetch = orig;
};
}
test("Worker GET /healthz aggregates backend probes without touching forwarded routes", async () => {
const restore = stubFetch(async (url) => new Response("ok", { status: 200 }));
try {
const res = await handleFetch(new Request("https://lb.example/healthz", { method: "GET" }), makeEnv());
assert.equal(res.status, 200);
const body = await res.json();
assert.equal(body.status, "ok");
assert.equal(body.available, 2);
assert.equal(body.total, 2);
assert.ok(Array.isArray(body.backends));
} finally {
restore();
}
});
test("Worker: unknown route => 404 (C-LB-SINGLE-REG-URL)", async () => {
const res = await handleFetch(
new Request("https://lb.example/unknown", { method: "POST", body: "{}" }),
makeEnv(),
);
assert.equal(res.status, 404);
assert.match(await res.text(), /route not forwarded/);
});
test("Worker: wrong method on safelist route => 405", async () => {
const res = await handleFetch(
new Request("https://lb.example/webhook/tg", { method: "GET" }),
makeEnv(),
);
assert.equal(res.status, 405);
});
test("Worker: business config PUT is forwarded with the session bearer and empty 204 response", async () => {
const restore = stubFetch(async (url, init) => {
assert.match(url, /^https:\/\/(a|b)\.example\/api\/business-config$/);
assert.equal(init.method, "PUT");
assert.equal(init.headers.get("authorization"), "Bearer opaque-session");
assert.equal(await new Response(init.body).text(), "{\"llm_enabled\":false}");
return new Response(null, { status: 204 });
});
try {
const res = await handleFetch(
new Request("https://lb.example/api/business-config", {
method: "PUT",
headers: { authorization: "Bearer opaque-session", "content-type": "application/json" },
body: "{\"llm_enabled\":false}",
}),
makeEnv(),
);
assert.equal(res.status, 204);
} finally {
restore();
}
});
test("Worker: public setup status is forwarded without an authorization header", async () => {
const restore = stubFetch(async (url, init) => {
assert.match(url, /^https:\/\/(a|b)\.example\/api\/status$/);
assert.equal(init.method, "GET");
assert.equal(new Headers(init.headers).has("authorization"), false);
return new Response(JSON.stringify({
ready: false,
mode: "configuration-setup",
missing: ["REDIS_URL"],
}), { status: 200, headers: { "content-type": "application/json" } });
});
try {
const res = await handleFetch(new Request("https://lb.example/api/status"), makeEnv());
assert.equal(res.status, 200);
assert.deepEqual(await res.json(), {
ready: false,
mode: "configuration-setup",
missing: ["REDIS_URL"],
});
} finally {
restore();
}
});
test("Worker: misconfigured origins => 503 fail-closed (no env leak)", async () => {
const res = await handleFetch(
new Request("https://lb.example/reconcile", { method: "POST", body: "{}" }),
makeEnv({ BACKEND_ORIGINS_JSON: "not-json" }),
);
assert.equal(res.status, 503);
assert.equal(await res.text(), "misconfigured backends");
});
test("Worker: valid env, GET /ready forwarded to backend with auth header intact", async () => {
const restore = stubFetch(async (url, init) => {
assert.match(url, /^https:\/\/(a|b)\.example\/ready$/);
return new Response("ready", { status: 200, headers: { "content-type": "text/plain" } });
});
try {
const res = await handleFetch(
new Request("https://lb.example/ready", {
method: "GET",
headers: { authorization: "Bearer lb-test" },
}),
makeEnv(),
);
assert.equal(res.status, 200);
} finally {
restore();
}
});
test("Worker: POST /api/push/register and /api/push/disable are forwarded", async () => {
const seen = [];
const restore = stubFetch(async (url, init) => {
seen.push([url, init.method]);
return new Response("{\"error\":\"invalid_request\",\"request_id\":\"x\"}", {
status: 400,
headers: { "content-type": "application/json" },
});
});
try {
for (const path of ["/api/push/register", "/api/push/disable"]) {
const res = await handleFetch(
new Request(`https://lb.example${path}`, { method: "POST", body: "{}" }),
makeEnv(),
);
assert.equal(res.status, 400);
assert.deepEqual(await res.json(), { error: "invalid_request", request_id: "x" });
}
assert.equal(seen.length, 2);
assert.ok(seen.every(([url, method]) => method === "POST"));
} finally {
restore();
}
});