1234import { expect, test } from "bun:test";5import { existsSync, renameSync } from "node:fs";6import { mkdtemp } from "node:fs/promises";7import { tmpdir } from "node:os";8import { join } from "node:path";9import { startSyncWorker } from "../src/bucket/sync.ts";10import { fileAt, headId } from "../src/mirror/queries.ts";11import { closeMirror, openMirror } from "../src/mirror/store.ts";12import { openKeprDb } from "../src/server/db.ts";13import { makeKohBucket } from "./fixture.ts";1415test("the sync worker syncs, reports, holds and hides", async () => {16 const fx = await makeKohBucket("worked");17 const dataDir = await mkdtemp(join(tmpdir(), "kepr-worker-"));18 const kepr = openKeprDb(dataDir);19 const synced: string[] = [];20 const syncer = startSyncWorker(dataDir, { kind: "folder", path: fx.bucketDir }, (repo) =>21 synced.push(repo),22 );23 await syncer.syncAll();24 const mirror = () => openMirror(join(dataDir, "mirror"), fx.repo);25 const head = fx.saveIds[0] as string;26 expect(headId(mirror())).toBe(head);27 for (let i = 0; i < 100 && !synced.includes(fx.repo); i++) await Bun.sleep(10);28 expect(synced).toContain(fx.repo);2930 const order: string[] = [];31 let release = () => {};32 const held = syncer.hold(async () => {33 order.push("held");34 await new Promise<void>((resolve) => {35 release = resolve;36 });37 order.push("released");38 });39 for (let i = 0; i < 100 && order.length === 0; i++) await Bun.sleep(10);40 const synced2 = syncer.syncAll().then(() => order.push("synced"));41 await Bun.sleep(50);42 expect(order).toEqual(["held"]);43 release();44 await Promise.all([held, synced2]);45 expect(order).toEqual(["held", "released", "synced"]);4647 kepr.query("UPDATE repos SET hidden_paths = 'secret.txt' WHERE name = ?").run(fx.repo);48 await syncer.applyHidden([fx.repo]);49 expect(fileAt(mirror(), head, "secret.txt")).toBeNull();50 expect(fileAt(mirror(), head, "src/main.ts")).not.toBeNull();51});5253test("a hidden list edited during a rename reaches the repo under its new name", async () => {54 const fx = await makeKohBucket("before");55 const dataDir = await mkdtemp(join(tmpdir(), "kepr-worker-"));56 const mirrorDir = join(dataDir, "mirror");57 const kepr = openKeprDb(dataDir);58 const syncer = startSyncWorker(dataDir, { kind: "folder", path: fx.bucketDir }, () => {});59 await syncer.syncAll();60 const head = fx.saveIds[0] as string;61 let edited: Promise<void> = Promise.resolve();62 await syncer.hold(async () => {63 kepr.query("UPDATE repos SET hidden_paths = 'secret.txt' WHERE name = 'before'").run();64 edited = syncer.applyHidden(["before"]);65 66 kepr.query("UPDATE repos SET name = 'after' WHERE name = 'before'").run();67 kepr.query("INSERT INTO renamed (old, new) VALUES ('before', 'after')").run();68 closeMirror(mirrorDir, "before");69 for (const suffix of ["", "-wal", "-shm"]) {70 const path = join(mirrorDir, `before.db${suffix}`);71 if (existsSync(path)) renameSync(path, join(mirrorDir, `after.db${suffix}`));72 }73 });74 await edited;75 expect(fileAt(openMirror(mirrorDir, "after"), head, "secret.txt")).toBeNull();76 expect(existsSync(join(mirrorDir, "before.db"))).toBe(false);77});