49 lines · 2.2 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, 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 },