import { beforeEach, describe, expect, mock, test } from "bun:test"; import { fakeStorage } from "./do-test-storage"; mock.module("cloudflare:workers", () => ({ env: {}, waitUntil: () => undefined, DurableObject: class { ctx: unknown; env: unknown; constructor(ctx: unknown, env: unknown) { this.ctx = ctx; this.env = env; } }, })); let failKeys = new Set(); let flushedKeys: string[] = []; mock.module("./metering/record", () => ({ periodOf: () => "2026-10", eventStatements: (input: { idempotencyKey: string }) => [{ key: input.idempotencyKey }], })); const d1 = { first: async () => null, stmt: () => ({}), batch: async (statements: { key: string }[]) => { if (statements.some((statement) => failKeys.has(statement.key))) throw new Error("rejected"); flushedKeys.push(...statements.map((statement) => statement.key)); return []; }, }; mock.module("./db", () => d1); // The meter buffer flushes into the billed account's object; the same fake records those batches. mock.module("./scoped-db", () => ({ accountDb: () => d1, repoDb: () => d1, stmt: d1.stmt })); mock.module("./repos", () => ({ inboxReadableSql: () => "1", loadRepoById: async () => ({ id: "r1" }) })); mock.module("./notification-store", () => ({ unreadNotificationCount: async () => 0 })); let credentialLookups = 0; let allowed = true; let live = true; let livenessChecks = 0; mock.module("./token-scope", () => ({ patCredentialById: async () => { credentialLookups++; return { viewer: { id: "u1" } }; }, credentialAllows: async () => allowed, tokenIsLive: async () => { livenessChecks++; return live; }, })); mock.module("./mcp/event-access", () => ({ readableEventTypes: async () => new Set(["push"]) })); const { MeterBuffer } = await import("./metering/meter-buffer-do"); const { UserInbox } = await import("./user-inbox-do"); const { McpHub } = await import("./mcp/hub-do"); const { ISOLATE_AFTER } = await import("./do-flush"); beforeEach(() => { failKeys = new Set(); flushedKeys = []; credentialLookups = 0; allowed = true; live = true; livenessChecks = 0; }); describe("UserInbox email budget", () => { test("allows up to the limit per window and survives a fresh instance", async () => { const storage = fakeStorage(); const inbox = new UserInbox({ storage } as never, {} as never); expect(await inbox.takeEmailBudget(2, 3_600_000)).toBe(true); expect(await inbox.takeEmailBudget(2, 3_600_000)).toBe(true); const restarted = new UserInbox({ storage } as never, {} as never); expect(await restarted.takeEmailBudget(2, 3_600_000)).toBe(false); }); }); describe("MeterBuffer poison events", () => { test("a repeatedly rejected event is dead-lettered and no longer blocks the rest", async () => { const storage = fakeStorage(); const buffer = new MeterBuffer({ storage } as never, {} as never); const input = (key: string) => ({ idempotencyKey: key, meter: "ops.git_ops", quantity: 1 }) as never; await buffer.add(input("bad"), "a1", 1); await buffer.add(input("good"), "a1", 2); failKeys = new Set(["bad"]); for (let attempt = 0; attempt <= ISOLATE_AFTER; attempt++) await buffer.alarm(); expect(flushedKeys).toEqual(["good"]); expect((await buffer.deadLetters()).map((row) => row.key)).toEqual(["bad"]); expect(await buffer.has("bad")).toBe(true); expect(await storage.get("attempts")).toBeUndefined(); }); }); describe("McpHub access cache", () => { async function hub() { const storage = fakeStorage(); const object = new McpHub({ storage, getWebSockets: () => [], id: { toString: () => "s1" } } as never, {} as never); await storage.put("session", { kind: "listen", tokenId: "t1", resourceUris: [], repos: ["r1"], toolEvents: {} }); return object; } const event = { seq: 1, type: "push", at: 0, data: "{}" }; test("reuses a granted check instead of re-reading the token on every event", async () => { const object = await hub(); expect(await object.deliver("r1", "o/r", event)).toBe(true); expect(await object.deliver("r1", "o/r", event)).toBe(true); expect(credentialLookups).toBe(1); expect(livenessChecks).toBe(1); }); test("a revoked token stops receiving events on the very next delivery, cache or not", async () => { const object = await hub(); expect(await object.deliver("r1", "o/r", event)).toBe(true); live = false; expect(await object.deliver("r1", "o/r", event)).toBe(false); }); test("invalidation forces a fresh check that sees the revocation", async () => { const object = await hub(); await object.deliver("r1", "o/r", event); allowed = false; await object.invalidateAccess("r1"); expect(await object.deliver("r1", "o/r", event)).toBe(false); expect(credentialLookups).toBe(2); }); });