import { describe, expect, mock, test } from "bun:test"; const owners = new Map([["repo", "alice"]]); mock.module("cloudflare:workers", () => ({ env: {}, waitUntil: () => undefined })); mock.module("../db", () => ({ first: async (_sql: string, repoId: string) => (owners.has(repoId) ? { owner_id: owners.get(repoId) } : null), all: async () => [], run: async () => ({ meta: { changes: 0 } }), })); mock.module("./directory", () => ({ noteScratchAccount: async () => undefined, claimLocator: async (_kind: string, _key: string, scope: string) => scope, })); mock.module("../scoped-db/locators", () => ({ locate: async () => null, locatedScopes: async () => [], forgetLocator: async () => undefined, forgetScope: async () => undefined, registerLocator: async () => undefined, })); const { memoryScopes } = await import("../scoped-db/testing"); const scopes = memoryScopes(); mock.module("../scoped-db", () => scopes.module); const { publishScopeGauges, retractScopeGauges, sumScopeGauges } = await import("./scope-gauges"); function sqlOf(accountId: string) { const db = scopes.raw("account", accountId); return { exec: (query: string, ...params: Array) => { const rows = db.query(query).all(...params) as never[]; return { toArray: () => rows }; }, }; } function gauges(accountId: string): Record { const rows = scopes.raw("account", accountId).query("SELECT meter, value FROM scope_gauges").all() as Array<{ meter: string; value: number; }>; return Object.fromEntries(rows.map((row) => [row.meter, row.value])); } describe("scope gauges", () => { test("a repository reports its storage to its owner, moves it on transfer and retracts it on deletion", async () => { scopes.raw("repo", "repo").exec(` INSERT INTO action_caches (id, repo_id, ref, key, version, size, r2_key, created_at, last_used_at) VALUES ('c1', 'repo', 'main', 'a', '1', 10, 'k1', 0, 0), ('c2', 'repo', 'dev', 'a', '1', 10, 'k1', 0, 0), ('c3', 'repo', 'main', 'b', '1', -5, 'k2', 0, 0); INSERT INTO repo_storage_estimates (repo_id, pack_bytes, updated_at) VALUES ('repo', 300, 0);`); await publishScopeGauges("repo"); expect(gauges("alice")).toEqual({ "storage.ci_cache": 10, "storage.artifacts": 300, "storage.r2": 0 }); owners.set("repo", "acme"); await publishScopeGauges("repo"); expect(gauges("alice")).toEqual({}); expect(gauges("acme")["storage.artifacts"]).toBe(300); const sql = sqlOf("acme"); sumScopeGauges(sql, "acme", Date.UTC(2026, 9, 17)); const billed = scopes .raw("account", "acme") .query("SELECT meter, current FROM usage_gauges WHERE meter = 'storage.artifacts'") .all(); expect(billed).toEqual([{ meter: "storage.artifacts", current: 300 }]); await retractScopeGauges("repo"); expect(gauges("acme")).toEqual({}); }); });