import test from "node:test"; import assert from "node:assert/strict"; import { mkdtemp, rm } from "node:fs/promises"; import path from "node:path"; import os from "node:os"; import { spawn } from "node:child_process"; import { once } from "node:events"; import { withFileLock } from "../src/capability-language/file-lock.js"; test("authoring lock excludes concurrent mutations and survives owner death", async (context) => { const root = await mkdtemp(path.join(os.tmpdir(), "qx-lock-test-")); context.after(() => rm(root, { recursive: true, force: true })); const filename = path.join(root, "lock"); const events: string[] = []; let queued: Promise; await withFileLock(filename, async () => { queued = withFileLock(filename, async () => { events.push("second"); }); events.push("first"); }); await queued!; assert.deepEqual(events, ["first", "second"]); const module = new URL("../src/capability-language/file-lock.js", import.meta.url).href; const owner = spawn( process.execPath, [ "--input-type=module", "-e", `import {withFileLock} from ${JSON.stringify(module)}; await withFileLock(${JSON.stringify(filename)}, async () => {process.stdout.write('ready'); await new Promise(() => {});});`, ], { stdio: ["ignore", "pipe", "pipe"] }, ); context.after(() => owner.kill("SIGKILL")); await once(owner.stdout, "data"); const exited = once(owner, "exit"); owner.kill("SIGKILL"); await exited; let acquired = false; await withFileLock(filename, async () => { acquired = true; }); assert.equal(acquired, true); });