import { describe, expect, mock, test } from "bun:test";
const kv = new Map<string, string>([["backfill:attachment-bytes", "done"]]);
mock.module("cloudflare:workers", () => ({
env: { KV: { get: async (key: string) => kv.get(key) ?? null, put: async () => undefined } },
}));
mock.module("./db", () => ({
all: async () => [],
first: async () => null,
run: async () => ({ meta: { changes: 0 } }),
}));
const { memoryScopes } = await import("./scoped-db/testing");
const scopes = memoryScopes();
mock.module("./scoped-db", () => scopes.module);
const { attachmentUsage, forgetRepoAttachmentBytes, syncAttachmentBytes } = await import("./attachment-bytes");
function attach(repoId: string, id: string, owner: string, uploader: string, size: number): void {
scopes
.raw("repo", repoId)
.query(
`INSERT INTO attachments (id, owner_id, repo_id, uploader_id, name, content_type, size, r2_key, created_at)
VALUES (?, ?, ?, ?, 'f', 'text/plain', ?, 'k', 0)`,
)
.run(id, owner, repoId, uploader, size);
}
describe("attachment bytes", () => {
test("quota totals come from the accounts' own entries, recomputed per repository", async () => {
attach("r1", "a", "org", "alice", 100);
attach("r2", "b", "org", "bob", 50);
attach("r2", "c", "alice", "alice", 7);
await syncAttachmentBytes("r1", ["org", "alice"]);
await syncAttachmentBytes("r2", ["org", "alice", "bob"]);
await syncAttachmentBytes("r2", ["org", "alice", "bob"]);
expect(await attachmentUsage("org", "alice")).toEqual({ owner_total: 150, uploader_total: 107 });
await forgetRepoAttachmentBytes("r2");
expect(await attachmentUsage("org", "bob")).toEqual({ owner_total: 100, uploader_total: 0 });
});
});