Files
reverse-engineering-anything/tests/boundary/process/packageVerifierCommandOwnership.test.ts
T
6938696256 test: keep child deadlines that rule out fallback exits
These fixtures' descendants exit on their own after 20 or 30 seconds. The
shorter explicit deadline is what proves cleanup stopped them first.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 13:21:13 +08:00

270 lines
10 KiB
TypeScript

import { readFile, writeFile } from "node:fs/promises";
import { join, resolve } from "node:path";
import { setTimeout as delay } from "node:timers/promises";
import { pathToFileURL } from "node:url";
import { expect } from "vitest";
import { z } from "zod";
import { liveProcesses } from "../../../src/process/ProcessOwnershipProcessTree.js";
import { systemProcessOwnershipHost } from "../../../src/process/ProcessOwnershipObservation.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { processTest } from "../../support/process/processFixture.js";
processTest.skipIf(process.platform === "win32")(
"releases a cold source loader before verifying command cleanup",
async ({ processes }) => {
const commandsModule = pathToFileURL(
resolve("scripts/lib/verify-package-commands.mjs"),
).href;
const verifierModule = pathToFileURL(
resolve("scripts/lib/verifier-run.mjs"),
).href;
const result = await processes.run(
process.execPath,
[
"--input-type=module",
"-e",
`
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { createPackageVerifierCommands } from ${JSON.stringify(commandsModule)};
import { createVerifierRun, completeVerifierRun } from ${JSON.stringify(verifierModule)};
const run = createVerifierRun();
const path = await mkdtemp(join(tmpdir(), "rea-cold-verifier-"));
const commands = await createPackageVerifierCommands({ workspace: { path, close: () => rm(path, { recursive: true, force: true }) } });
try {
await commands.exec(process.execPath, ["-e", "process.stdout.write('ok')"]);
} finally {
await commands.close();
}
console.log(JSON.stringify(await completeVerifierRun(run)));
`,
],
{ env: { ...process.env, TSX_DISABLE_CACHE: "1" }, timeoutMs: 20_000 },
);
expect(result.exitCode, result.stderr).toBe(0);
expect(JSON.parse(result.stdout)).toMatchObject({
process_lineage: { status: "verified", descendants: [] },
});
},
);
const descendantSource = `
import { appendFileSync, existsSync, writeFileSync } from "node:fs";
const record = (entry) => appendFileSync(process.env.OWNER_EVENTS, JSON.stringify(entry) + "\\n");
const finish = (reason) => {
record({ kind: "descendant-exit", reason, rootExists: existsSync(process.env.OWNER_ROOT) });
process.exit(0);
};
process.on("SIGTERM", () => finish("SIGTERM"));
writeFileSync(process.env.OWNER_DESCENDANT, String(process.pid));
process.send({ pid: process.pid });
setInterval(() => {
if (existsSync(process.env.OWNER_RELEASE)) finish("fixture-release");
}, 25);
setTimeout(() => finish("fixture-deadline"), 20000);
`;
const npmSource = `
import { spawn } from "node:child_process";
import { appendFileSync, existsSync, writeFileSync } from "node:fs";
process.once("SIGTERM", () => {
appendFileSync(process.env.OWNER_EVENTS, JSON.stringify({ kind: "leader-exit", rootExists: existsSync(process.env.OWNER_ROOT) }) + "\\n");
process.kill(process.pid, "SIGTERM");
});
const child = spawn(process.execPath, [process.env.OWNER_DESCENDANT_ENTRY], {
stdio: ["ignore", "ignore", "ignore", "ipc"],
});
const ready = await new Promise((resolve, reject) => {
child.once("message", resolve);
child.once("error", reject);
});
writeFileSync(process.env.OWNER_READY, JSON.stringify({ pids: [process.pid, ready.pid] }));
process.stdout.write("npm descendant ready\\n");
process.stderr.write("selected npm diagnostics\\n");
setInterval(() => {}, 1000);
`;
const reportSchema = z.object({
pids: z.array(z.number().int().positive()).length(2),
liveAtRemoval: z.array(z.number().int().positive()),
rootRemoved: z.boolean(),
failure: z.object({
reason: z.literal("timeout"),
stdout: z.string(),
stderr: z.string(),
}),
});
const stopReceiptSchema = z.object({
kind: z.enum(["leader-exit", "descendant-exit"]),
rootExists: z.boolean(),
reason: z.string().optional(),
});
const releaseDescendant = async (release: string, receipt: string) => {
await writeFile(release, "release this authored descendant");
const pid = await readFile(receipt, "utf8").then(Number, (cause: unknown) => {
if (cause instanceof Error && "code" in cause && cause.code === "ENOENT")
return undefined;
throw cause;
});
if (pid === undefined) return;
const deadline = Date.now() + 7_500;
while (
liveProcesses(await systemProcessOwnershipHost.listProcesses()).some(
(entry) => entry.pid === pid,
)
) {
if (Date.now() >= deadline)
throw new Error(
"Authored npm descendant did not consume its release marker",
);
await delay(25);
}
};
// Actual npm-entry/descendant processes and actual scratch removal; no package
// install, native engine, or WABT behavior is simulated or claimed.
processTest.skipIf(process.platform === "win32")(
"joins a timed-out npm entry and its acknowledged descendant before removing the verifier root",
async ({ processes }) => {
const root = await createTestTempDirectory("rea-package-command-owner-");
const scratch = join(root, "scratch");
const entry = join(root, "selected npm entry.mjs");
const descendant = join(root, "descendant.mjs");
const release = join(root, "release-descendant");
const receipt = join(root, "descendant.pid");
const ready = join(root, "ready.json");
const events = join(root, "events.jsonl");
const driver = join(root, "driver.mjs");
await writeFile(entry, npmSource);
await writeFile(descendant, descendantSource);
const commandsModule = pathToFileURL(
resolve("scripts/lib/verify-package-commands.mjs"),
).href;
const cleanup = pathToFileURL(
resolve("scripts/lib/verifier-cleanup.mjs"),
).href;
const observations = pathToFileURL(
resolve("dist/process/ProcessOwnershipObservation.js"),
).href;
const tree = pathToFileURL(
resolve("dist/process/ProcessOwnershipProcessTree.js"),
).href;
await writeFile(
driver,
`
import { existsSync } from "node:fs";
import { mkdir, readFile, rm } from "node:fs/promises";
import { createPackageVerifierCommands } from ${JSON.stringify(commandsModule)};
import { withVerifierCleanup } from ${JSON.stringify(cleanup)};
import { systemProcessOwnershipHost } from ${JSON.stringify(observations)};
import { liveProcesses } from ${JSON.stringify(tree)};
const scratch = process.env.OWNER_ROOT;
await mkdir(scratch);
let commands, recoveryOwner, pids, liveAtRemoval, failure, diagnostics;
const workspace = {
path: scratch,
async close() {
const ready = await readFile(process.env.OWNER_READY, "utf8").then(JSON.parse, cause => {
if (cause.code === "ENOENT") return { pids: [] };
throw cause;
});
pids = ready.pids;
liveAtRemoval = liveProcesses(await systemProcessOwnershipHost.listProcesses()).filter(({ pid }) => pids.includes(pid)).map(({ pid }) => pid);
await rm(scratch, { recursive: true, force: true });
},
};
try {
await withVerifierCleanup(
async () => {
commands = await createPackageVerifierCommands({ workspace });
await commands.execNpm(["pack", "caller value with spaces"], { cwd: scratch, env: process.env, timeout: 1500 });
},
[async () => {
if (commands === undefined) await rm(scratch, { recursive: true, force: true });
else await commands.close();
}],
);
} catch (cause) {
const failures = cause instanceof AggregateError ? cause.errors : [cause];
// Capture exact cleanup authority before projecting facts or making assertions.
recoveryOwner = failures.find(error => typeof error?.cleanupOwner?.close === "function")?.cleanupOwner ?? commands;
const primary = failures.find(error => error?.snapshot !== undefined && typeof error?.reason === "string");
failure = { reason: primary?.reason, stdout: primary?.snapshot?.stdout.text, stderr: primary?.snapshot?.stderr.text };
diagnostics = failures.map(error => ({
name: error?.name ?? typeof error,
message: error?.message ?? String(error),
reason: error?.reason,
snapshotAvailable: error?.snapshot !== undefined && error?.snapshot !== null,
stack: error?.stack,
cleanupFailure: error?.cleanupFailure,
processError: error?.processError?.message,
preparationFailure: error?.preparationFailure?.message,
cause: {
name: error?.cause?.name,
message: error?.cause?.message ?? String(error?.cause),
stack: error?.cause?.stack,
cause: error?.cause?.cause?.message ?? String(error?.cause?.cause),
},
}));
} finally {
if (recoveryOwner !== undefined) await recoveryOwner.close();
else if (commands !== undefined) await commands.close();
else await rm(scratch, { recursive: true, force: true });
}
process.stdout.write(JSON.stringify({ pids, liveAtRemoval, rootRemoved: !existsSync(scratch), failure, diagnostics }));
`,
);
try {
const result = await processes.run(process.execPath, [driver], {
timeoutMs: 20_000,
env: {
...process.env,
npm_execpath: entry,
OWNER_ROOT: scratch,
OWNER_DESCENDANT_ENTRY: descendant,
OWNER_DESCENDANT: receipt,
OWNER_RELEASE: release,
OWNER_READY: ready,
OWNER_EVENTS: events,
},
});
expect(result.exitCode, result.stderr).toBe(0);
expect(result.signal, result.stderr).toBeNull();
const parsed = reportSchema.safeParse(JSON.parse(result.stdout));
expect(parsed.success, result.stdout).toBe(true);
if (!parsed.success) throw parsed.error;
const report = parsed.data;
expect(report.failure).toEqual({
reason: "timeout",
stdout: "npm descendant ready\n",
stderr: "selected npm diagnostics\n",
});
expect(report.liveAtRemoval).toEqual([]);
expect(report.rootRemoved).toBe(true);
const receipts = await readFile(events, "utf8").catch(
(cause: unknown) => {
if (
cause instanceof Error &&
"code" in cause &&
cause.code === "ENOENT"
)
return "";
throw cause;
},
);
const stopped = receipts
.trim()
.split("\n")
.filter((line) => line !== "")
.map((line) => stopReceiptSchema.parse(JSON.parse(line)));
for (const receipt of stopped) expect(receipt.rootExists).toBe(true);
} finally {
await releaseDescendant(release, receipt);
}
},
);