Something went wrong. Try again.
Automations and webhooks for the AT Protocol airglow.run
automation webhook atproto atprotocol
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116import { 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); });});