Files
ThothII/backend/scripts/p11-manual-acceptance.test.mjs

92 lines
4.0 KiB
JavaScript

import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { access, lstat, readFile, rm } from "node:fs/promises";
import { join } from "node:path";
import test from "node:test";
import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path";
import {
cleanupManual,
prepareManual,
readManualOwnership,
serveManual,
stopManual,
} from "./p11-manual-acceptance.mjs";
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
const fixedRoot = join(repoRoot, ".artifacts", "manual-acceptance", "p11");
async function safeCleanup() {
try {
const owned = await readManualOwnership({ repositoryRoot: repoRoot });
if (owned.status === "RUNNING") await stopManual({ repositoryRoot: repoRoot }).catch(() => {});
await cleanupManual({ repositoryRoot: repoRoot }).catch(() => {});
} catch {
await rm(fixedRoot, { recursive: true, force: true }).catch(() => {});
}
}
test.beforeEach(async () => {
await safeCleanup();
});
test.afterEach(async () => {
await safeCleanup();
});
test("prepare creates an independent pending lab without verdict", { concurrency: false }, async () => {
const root = await prepareManual({ repositoryRoot: repoRoot });
assert.equal(root, fixedRoot);
const owned = await readManualOwnership({ repositoryRoot: repoRoot });
assert.equal(owned.kind, "p11-manual-acceptance");
assert.equal(owned.status, "PENDING");
await access(join(root, "GUIDE.md"));
await access(join(root, "author", "thoth-workspaces.yaml"));
await access(join(root, "author", "p11-filesystem", "evidence", "guide.md"));
await access(join(root, "requests", "validate-p11-filesystem.json"));
await access(join(root, "commands", "http-01-status.sh"));
await access(join(root, "commands", "render-1.sh"));
await assert.rejects(access(join(root, "VERDICT.md")));
const guide = await readFile(join(root, "GUIDE.md"), "utf8");
assert.match(guide, /VERDICT\.md/);
assert.match(guide, /read-only/);
});
test("serve, stop, and cleanup manage the owned backend and frontend listeners", { concurrency: false }, async () => {
await prepareManual({ repositoryRoot: repoRoot });
const running = await serveManual({ repositoryRoot: repoRoot });
assert.equal(running.status, "RUNNING");
assert.equal(typeof running.backend.pid, "number");
assert.equal(typeof running.frontend.pid, "number");
const status = await fetch("http://127.0.0.1:8791/workspace-registry/status");
assert.equal(status.status, 200);
const frontend = await fetch("http://127.0.0.1:8792/");
assert.equal(frontend.status, 200);
await assert.rejects(cleanupManual({ repositoryRoot: repoRoot }), /still live/);
const stopped = await stopManual({ repositoryRoot: repoRoot });
assert.equal(stopped.status, "STOPPED");
await cleanupManual({ repositoryRoot: repoRoot });
await assert.rejects(lstat(fixedRoot));
});
test("stop fails closed when ownership is tampered", { concurrency: false }, async () => {
await prepareManual({ repositoryRoot: repoRoot });
const running = await serveManual({ repositoryRoot: repoRoot });
const ownershipPath = join(fixedRoot, "ownership.json");
const digestPath = join(fixedRoot, "ownership.sha256");
const original = JSON.parse(await readFile(ownershipPath, "utf8"));
const tampered = { ...original, backend: { ...original.backend, pid: original.backend.pid + 1 } };
await rm(ownershipPath);
await readFile(join(fixedRoot, "logs", "backend.log"));
await import("node:fs/promises").then(({ writeFile }) => writeFile(ownershipPath, `${JSON.stringify(tampered, null, 2)}
`));
await assert.rejects(stopManual({ repositoryRoot: repoRoot }), /manual ownership digest mismatch/);
const restored = `${JSON.stringify(running, null, 2)}
`;
const restoredDigest = `${createHash("sha256").update(restored).digest("hex")}
`;
await import("node:fs/promises").then(({ writeFile }) => Promise.all([writeFile(ownershipPath, restored), writeFile(digestPath, restoredDigest)]));
await stopManual({ repositoryRoot: repoRoot });
});