import { test, expect } from "vitest"; import { existsSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { MaintenanceBarrier } from "../src/runtime/maintenance-gate.js"; test("activation waits for an in-flight admission lease and rejects later admissions", async () => { const gate = new MaintenanceBarrier(); const release = gate.acquire(); expect(release).toBeTypeOf("function"); let acknowledged = false; const activation = gate.activate().then(() => { acknowledged = true; }); await Promise.resolve(); expect(acknowledged).toBe(false); expect(gate.acquire()).toBeUndefined(); release?.(); await activation; expect(acknowledged).toBe(true); expect(gate.status()).toEqual({ active: true, admissions: 0 }); gate.deactivate(); expect(gate.acquire()).toBeTypeOf("function"); }); test("durable activation survives recreation and deactivation removes the marker first", async () => { const directory = mkdtempSync(join(tmpdir(), "tht-maintenance-gate-")); const marker = join(directory, "maintenance.json"); try { const first = new MaintenanceBarrier(marker); const release = first.acquire(); expect(release).toBeTypeOf("function"); const activation = first.activate(); expect(existsSync(marker)).toBe(true); expect(first.acquire()).toBeUndefined(); expect(first.status()).toEqual({ active: true, admissions: 1 }); release?.(); await activation; expect(first.status()).toEqual({ active: true, admissions: 0 }); const recreated = new MaintenanceBarrier(marker); expect(recreated.status()).toEqual({ active: true, admissions: 0 }); recreated.deactivate(); expect(existsSync(marker)).toBe(false); expect(recreated.status()).toEqual({ active: false, admissions: 0 }); } finally { rmSync(directory, { recursive: true, force: true }); } }); test("activation reconciles active state when directory fsync fails after marker rename", async () => { const directory = mkdtempSync(join(tmpdir(), "tht-maintenance-activate-fsync-")); const marker = join(directory, "maintenance.json"); try { const gate = new MaintenanceBarrier(marker, { syncDirectory() { throw new Error("injected post-rename fsync failure"); }, }); await expect(gate.activate()).rejects.toThrow(/post-rename fsync failure/); expect(existsSync(marker)).toBe(true); expect(gate.status()).toEqual({ active: true, admissions: 0, recoveryRequired: true }); expect(gate.acquire()).toBeUndefined(); const recovered = new MaintenanceBarrier(marker); expect(recovered.status()).toEqual({ active: true, admissions: 0 }); expect(recovered.acquire()).toBeUndefined(); } finally { rmSync(directory, { recursive: true, force: true }); } }); test.each(["write", "fsync"] as const)( "activation cleans its marker temp file after a pre-rename %s failure", async (failure) => { const directory = mkdtempSync(join(tmpdir(), "tht-maintenance-temp-cleanup-")); const marker = join(directory, "maintenance.json"); try { const gate = new MaintenanceBarrier(marker, { writeFile(descriptor, contents) { if (failure === "write") throw new Error("injected marker write failure"); writeFileSync(descriptor, contents, "utf8"); }, syncFile() { if (failure === "fsync") throw new Error("injected marker fsync failure"); }, syncDirectory() {}, }); await expect(gate.activate()).rejects.toThrow(`injected marker ${failure} failure`); expect(existsSync(marker)).toBe(false); expect(readdirSync(directory).filter((entry) => entry.includes(".tmp-"))).toEqual([]); expect(gate.status()).toEqual({ active: false, admissions: 0, recoveryRequired: true }); } finally { rmSync(directory, { recursive: true, force: true }); } }, ); test("deactivation reconciles inactive state when directory fsync fails after marker removal", async () => { const directory = mkdtempSync(join(tmpdir(), "tht-maintenance-deactivate-fsync-")); const marker = join(directory, "maintenance.json"); let failSync = false; try { const gate = new MaintenanceBarrier(marker, { syncDirectory() { if (failSync) throw new Error("injected post-remove fsync failure"); }, }); await gate.activate(); failSync = true; expect(() => gate.deactivate()).toThrow(/post-remove fsync failure/); expect(existsSync(marker)).toBe(true); expect(gate.status()).toEqual({ active: true, admissions: 0, recoveryRequired: true }); expect(gate.acquire()).toBeUndefined(); } finally { rmSync(directory, { recursive: true, force: true }); } }); test("status and admission recover from a persistent marker even when memory started inactive", () => { const directory = mkdtempSync(join(tmpdir(), "tht-maintenance-reconcile-")); const marker = join(directory, "maintenance.json"); try { const gate = new MaintenanceBarrier(marker); expect(gate.status().active).toBe(false); writeFileSync(marker, '{"version":1,"active":true}\n', { mode: 0o600 }); expect(gate.status()).toEqual({ active: true, admissions: 0 }); expect(gate.acquire()).toBeUndefined(); } finally { rmSync(directory, { recursive: true, force: true }); } });