import { describe, it, expect, vi, beforeEach } from "vitest"; const { mockConfig } = vi.hoisted(() => ({ mockConfig: { databasePath: ":memory:", nsidAllowlist: [] as string[], nsidBlocklist: [] as string[], nsidRequireDids: [] as string[], syncShardCount: 1, syncJetstreamMaxLookbackUs: 24 * 3600 * 1_000_000, }, })); vi.mock("../config.js", () => ({ config: mockConfig })); vi.mock("@/config.js", () => ({ config: mockConfig })); vi.mock("@/db/index.js", async () => { const { createTestDb } = await import("../test/db.js"); return { db: createTestDb() }; }); import { db } from "../db/index.js"; import { syncSets, users } from "../db/schema.js"; import { saveEnabledSet, disableSet } from "./store.js"; import { shardFor, syncPartitions } from "./subscriptions.js"; import { seedUser } from "./test-helpers.js"; import { eq } from "drizzle-orm"; const A = "did:plc:aaaaaaaaaaaaaaaaaaaaaaaa"; const B = "did:plc:bbbbbbbbbbbbbbbbbbbbbbbb"; const NOW = new Date(Date.UTC(2026, 8, 14, 12)); beforeEach(() => { db.delete(users).run(); seedUser(A, NOW); seedUser(B, NOW); mockConfig.nsidBlocklist = []; mockConfig.nsidRequireDids = []; mockConfig.syncShardCount = 1; }); describe("syncPartitions", () => { it("returns nothing when no set is enabled", () => { saveEnabledSet(A, ["bluesky", "tangled"], NOW); disableSet(A, NOW); expect(syncPartitions()).toEqual([]); }); it("puts every enabled user in one shard with the union of their follow collections", () => { saveEnabledSet(A, ["bluesky", "tangled"], NOW); saveEnabledSet(B, ["tangled", "grain"], NOW); const [shard, profiles] = syncPartitions(); expect(shard!.key).toBe("sync:0"); expect(shard!.wantedDids).toEqual([A, B]); expect([...shard!.cells.keys()].sort()).toEqual( [ "app.bsky.graph.follow\0create", "app.bsky.graph.follow\0delete", "sh.tangled.graph.follow\0create", "sh.tangled.graph.follow\0delete", "social.grain.graph.follow\0create", "social.grain.graph.follow\0delete", ].sort(), ); expect(shard!.lookbackUs!()).toBe(24 * 3600 * 1_000_000); expect(shard!.resumeFallbackPrefix).toBe("sync:"); expect(profiles!.key).toBe(""); expect([...profiles!.cells.keys()].sort()).toEqual([ "sh.tangled.actor.profile\0create", "social.grain.actor.profile\0create", ]); }); it("keeps a paused user subscribed", () => { const { set } = saveEnabledSet(A, ["bluesky", "tangled"], NOW); db.update(syncSets).set({ pausedAt: NOW }).where(eq(syncSets.id, set.id)).run(); expect(syncPartitions()[0]!.wantedDids).toEqual([A]); }); it("drops blocklisted follow collections, and users left with none", () => { mockConfig.nsidBlocklist = ["app.bsky.*"]; saveEnabledSet(A, ["bluesky"], NOW); saveEnabledSet(B, ["bluesky", "tangled"], NOW); const [shard] = syncPartitions(); expect(shard!.wantedDids).toEqual([B]); expect([...shard!.cells.keys()]).not.toContain("app.bsky.graph.follow\0create"); }); it("skips a profile collection that requires wantedDids, with a warning", () => { const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); mockConfig.nsidRequireDids = ["sh.tangled.*"]; saveEnabledSet(A, ["bluesky", "tangled"], NOW); const partitions = syncPartitions(); expect(partitions.map((p) => p.key)).toEqual(["sync:0"]); expect(warn).toHaveBeenCalledWith(expect.stringContaining("sh.tangled.actor.profile")); warn.mockRestore(); }); it("spreads users across shards by a stable hash", () => { mockConfig.syncShardCount = 8; expect(shardFor(A, 8)).toBe(shardFor(A, 8)); saveEnabledSet(A, ["bluesky", "tangled"], NOW); saveEnabledSet(B, ["bluesky", "tangled"], NOW); const keys = syncPartitions() .filter((p) => p.key !== "") .map((p) => p.key); const expected = [...new Set([shardFor(A, 8), shardFor(B, 8)])] .sort((x, y) => x - y) .map((n) => `sync:${n}`); expect(keys).toEqual(expected); }); });