worker.test.ts

3.1 KB · raw

1// Covers the sync on its own thread (2026-10-02): a real worker syncs a koh3-made bucket, holds2// syncs off while the app works, and applies hidden lists.34import { 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, 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 syncer = startSyncWorker(dataDir, { kind: "folder", path: fx.bucketDir });20	await syncer.syncAll();21	const mirror = () => openMirror(join(dataDir, "mirror"), fx.repo);22	const head = fx.saveIds[0] as string;23	expect(headId(mirror())).toBe(head);2425	const order: string[] = [];26	let release = () => {};27	const held = syncer.hold(async () => {28		order.push("held");29		await new Promise<void>((resolve) => {30			release = resolve;31		});32		order.push("released");33	});34	for (let i = 0; i < 100 && order.length === 0; i++) await Bun.sleep(10);35	const synced2 = syncer.syncAll().then(() => order.push("synced"));36	await Bun.sleep(50);37	expect(order).toEqual(["held"]);38	release();39	await Promise.all([held, synced2]);40	expect(order).toEqual(["held", "released", "synced"]);4142	kepr.query("UPDATE repos SET hidden_paths = 'secret.txt' WHERE name = ?").run(fx.repo);43	await syncer.applyHidden([fx.repo]);44	expect(fileAt(mirror(), head, "secret.txt")).toBeNull();45	expect(fileAt(mirror(), head, "src/main.ts")).not.toBeNull();46});4748test("a hidden list edited during a rename reaches the repo under its new name", async () => {49	const fx = await makeKohBucket("before");50	const dataDir = await mkdtemp(join(tmpdir(), "kepr-worker-"));51	const mirrorDir = join(dataDir, "mirror");52	const kepr = openKeprDb(dataDir);53	const syncer = startSyncWorker(dataDir, { kind: "folder", path: fx.bucketDir });54	await syncer.syncAll();55	const head = fx.saveIds[0] as string;56	let edited: Promise<void> = Promise.resolve();57	await syncer.hold(async () => {58		kepr.query("UPDATE repos SET hidden_paths = 'secret.txt' WHERE name = 'before'").run();59		edited = syncer.applyHidden(["before"]);60		// What a rename does under its hold: rows and mirror move to the new name.61		kepr.query("UPDATE repos SET name = 'after' WHERE name = 'before'").run();62		kepr.query("INSERT INTO renamed (old, new) VALUES ('before', 'after')").run();63		closeMirror(mirrorDir, "before");64		for (const suffix of ["", "-wal", "-shm"]) {65			const path = join(mirrorDir, `before.db${suffix}`);66			if (existsSync(path)) renameSync(path, join(mirrorDir, `after.db${suffix}`));67		}68	});69	await edited;70	expect(fileAt(openMirror(mirrorDir, "after"), head, "secret.txt")).toBeNull();71	expect(existsSync(join(mirrorDir, "before.db"))).toBe(false);72});