test(security): make Cloudflare block tests deterministic under CI Redis
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m39s
CI / tests-unit (push) Successful in 1m42s
CI / tests-ui (push) Successful in 2m31s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m1s
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m39s
CI / tests-unit (push) Successful in 1m42s
CI / tests-ui (push) Successful in 2m31s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m1s
cloudflare-api unit tests drove the real Redis connection when REDIS_URL was set (CI), causing cross-test bleed. Mock @/lib/redis with an in-memory fake identical to the gate integration test.
This commit is contained in:
1 parent
4479753160
commit
6264f9fb20
1 file changed
+54
@@ -10,6 +10,58 @@ import {
|
|||||||
verifyCloudflareConnection,
|
verifyCloudflareConnection,
|
||||||
} from "./cloudflare-api";
|
} from "./cloudflare-api";
|
||||||
|
|
||||||
|
// The coordination state must be deterministic in CI too (where REDIS_URL is
|
||||||
|
// set), so the unit test drives a small in-memory Redis fake.
|
||||||
|
const state = vi.hoisted(() => ({ map: new Map<string, string>() }));
|
||||||
|
|
||||||
|
vi.mock("@/lib/redis", () => ({
|
||||||
|
redis: {
|
||||||
|
get: async (key: string) => state.map.get(key) ?? null,
|
||||||
|
set: async (
|
||||||
|
key: string,
|
||||||
|
value: string,
|
||||||
|
_mode?: string,
|
||||||
|
_seconds?: number,
|
||||||
|
nx?: string,
|
||||||
|
) => {
|
||||||
|
if (nx === "NX" && state.map.has(key)) return null;
|
||||||
|
state.map.set(key, value);
|
||||||
|
return "OK";
|
||||||
|
},
|
||||||
|
del: async (...keys: string[]) => {
|
||||||
|
for (const key of keys) state.map.delete(key);
|
||||||
|
return keys.length;
|
||||||
|
},
|
||||||
|
incr: async (key: string) => {
|
||||||
|
const next = (Number(state.map.get(key)) || 0) + 1;
|
||||||
|
state.map.set(key, String(next));
|
||||||
|
return next;
|
||||||
|
},
|
||||||
|
pexpire: async () => 1,
|
||||||
|
pttl: async () => 60_000,
|
||||||
|
sadd: async (key: string, member: string) => {
|
||||||
|
const members = new Set(
|
||||||
|
(state.map.get(key) ?? "").split("\u0001").filter(Boolean),
|
||||||
|
);
|
||||||
|
members.add(member);
|
||||||
|
state.map.set(key, [...members].join("\u0001"));
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
srem: async (key: string, member: string) => {
|
||||||
|
const members = new Set(
|
||||||
|
(state.map.get(key) ?? "").split("\u0001").filter(Boolean),
|
||||||
|
);
|
||||||
|
const before = members.size;
|
||||||
|
members.delete(member);
|
||||||
|
state.map.set(key, [...members].join("\u0001"));
|
||||||
|
return before - members.size;
|
||||||
|
},
|
||||||
|
smembers: async (key: string) =>
|
||||||
|
(state.map.get(key) ?? "").split("\u0001").filter(Boolean),
|
||||||
|
},
|
||||||
|
__esModule: true,
|
||||||
|
}));
|
||||||
|
|
||||||
function jsonResponse(body: unknown, status = 200): Response {
|
function jsonResponse(body: unknown, status = 200): Response {
|
||||||
return new Response(JSON.stringify(body), {
|
return new Response(JSON.stringify(body), {
|
||||||
status,
|
status,
|
||||||
@@ -28,6 +80,7 @@ describe("cloudflare-api", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.unstubAllGlobals();
|
vi.unstubAllGlobals();
|
||||||
vi.unstubAllEnvs();
|
vi.unstubAllEnvs();
|
||||||
|
state.map.clear();
|
||||||
resetCloudflareAutoBlockCache();
|
resetCloudflareAutoBlockCache();
|
||||||
fetchMock = vi.fn();
|
fetchMock = vi.fn();
|
||||||
vi.stubGlobal("fetch", fetchMock);
|
vi.stubGlobal("fetch", fetchMock);
|
||||||
@@ -36,6 +89,7 @@ describe("cloudflare-api", () => {
|
|||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.unstubAllGlobals();
|
vi.unstubAllGlobals();
|
||||||
vi.unstubAllEnvs();
|
vi.unstubAllEnvs();
|
||||||
|
state.map.clear();
|
||||||
resetCloudflareAutoBlockCache();
|
resetCloudflareAutoBlockCache();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user