44 lines · 1.9 KB
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 } = 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])).toEqual([["alice", "repo-1"]]);
  });

  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 },
      { actorId: "alice", repoId: "recent", at: 5_000 },
      { actorId: "alice", repoId: "recent", at: 9_000 },
    ]);
    kv.set("backfill:activity-repos", "done");
    expect((await activityRepoIds("alice", null)).sort()).toEqual(["old", "recent"]);
    expect(await activityRepoIds("alice", { start: 1_000, end: 10_000 })).toEqual(["recent"]);