worker.test.ts

3.3 KB · raw

1// Covers the sync on its own thread (2026-10-02): a real worker syncs a koh3-made bucket, tells the2// app which repos synced, holds 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, 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		// What a rename does under its hold: rows and mirror move to the new name.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});