import { describe, expect, mock, test } from "bun:test";
const kv = new Map<string, string>();
mock.module("cloudflare:workers", () => ({
env: { KV: { get: async (key: string) => kv.get(key) ?? null, put: async () => undefined } },
}));
mock.module("./db", () => ({
all: async () => [{ id: "every-repo" }],
first: async () => null,
run: async () => ({ meta: { changes: 0 } }),
chunks: <T>(items: T[]) => [items],
}));
const { memoryScopes } = await import("./scoped-db/testing");
const scopes = memoryScopes();
mock.module("./scoped-db", () => scopes.module);
const { activityRepoIds, activityTouches, indexActivity, touchedRepoIds } = await import("./activity-index");
const { repoActivityStatement } = await import("./issue-scope");
describe("activity index", () => {
test("picks counted activity inserts out of a batch", () => {
const statements = [
repoActivityStatement("alice", "repo-1", "issue_opened", {}),
repoActivityStatement("alice", "repo-1", "view", {}),
repoActivityStatement(null, "repo-1", "issue_opened", {}),
{ sql: "UPDATE issues SET title = ?", params: ["x"] },
];
expect(activityTouches(statements).map((touch) => [touch.actorId, touch.repoId, touch.counted])).toEqual([
["alice", "repo-1", true],
["alice", "repo-1", false],
]);
});
test("before the backfill is done every repository is a candidate; afterwards only indexed ones in range", async () => {
expect(await activityRepoIds("alice", null)).toEqual(["every-repo"]);
await indexActivity([
{ actorId: "alice", repoId: "old", at: 100, counted: true },
{ actorId: "alice", repoId: "recent", at: 5_000, counted: true },
{ actorId: "alice", repoId: "recent", at: 9_000, counted: true },
{ actorId: "alice", repoId: "pushed-only", at: 9_500, counted: false },