test(process): publish compiler readiness atomically and verify native identity

Prevent polling readers from observing truncated readiness JSON in compiler fixtures. Retain deterministic cancellation controls and strengthen the real Swift compiler case to run native identity inspection, verify parent/group facts, and check stable identity across reads.

Validated all 32 Darwin tests with the real host toolchain. A delayed write reproduces the old JSON race; delayed atomic publication passes. No CI timeout or retry changes.
This commit is contained in:
morluto committed 2026-10-23 05:03:15 +08:00
1 parent bea6b98e84
commit 3afec59523
1 file changed
+46 -6
@@ -41,12 +41,22 @@ import { electronActiveObservationInputSchema } from "../../../src/domain/javasc
const execFileAsync = promisify(execFile);
const onDarwin = process.platform === "darwin";
// Readiness files are polled by another process; expose only complete JSON.
const publishFixtureStateSource = `
const publishFixtureState = (file, value) => {
const pending = file + "." + process.pid + ".pending";
fs.writeFileSync(pending, JSON.stringify(value));
fs.renameSync(pending, file);
};
`;
const writeBlockingCompiler = async (directory: string) => {
const executable = join(directory, "fake-xcrun");
const statePath = join(directory, "compile-state.json");
const releasePath = join(directory, "release-compiler");
const source = `#!/usr/bin/env node
const fs = process.getBuiltinModule("node:fs");
${publishFixtureStateSource}
const path = process.getBuiltinModule("node:path");
const statePath = ${JSON.stringify(statePath)};
const releasePath = ${JSON.stringify(releasePath)};
@@ -59,7 +69,7 @@ state.output = process.argv[outputIndex + 1];
state.root = path.dirname(state.output);
state.arguments = process.argv.slice(2);
state.releasePath = releasePath;
fs.writeFileSync(statePath, JSON.stringify(state));
publishFixtureState(statePath, state);
if (state.calls === 1) {
const timer = setInterval(() => {
if (!fs.existsSync(releasePath)) return;
@@ -80,9 +90,10 @@ const writeBlockingIdentityCompiler = async (directory: string) => {
const statePath = join(directory, "identity-helper-state.json");
const helperSource = `#!/usr/bin/env node
const fs = process.getBuiltinModule("node:fs");
fs.writeFileSync(${JSON.stringify(statePath)}, JSON.stringify({
${publishFixtureStateSource}
publishFixtureState(${JSON.stringify(statePath)}, {
root: process.getBuiltinModule("node:path").dirname(fs.realpathSync(process.argv[1])),
}));
});
setInterval(() => {}, 1000);
`;
const compilerSource = `#!/usr/bin/env node
@@ -413,13 +424,14 @@ const writeCacheRecordingCompiler = async (directory: string) => {
const statePath = join(directory, "cache-compile-state.json");
const source = `#!/usr/bin/env node
const fs = process.getBuiltinModule("node:fs");
${publishFixtureStateSource}
const path = process.getBuiltinModule("node:path");
const flagIndex = process.argv.indexOf("-module-cache-path");
const cache = flagIndex === -1 ? undefined : process.argv[flagIndex + 1];
fs.writeFileSync(${JSON.stringify(statePath)}, JSON.stringify({
publishFixtureState(${JSON.stringify(statePath)}, {
arguments: process.argv.slice(2),
moduleCacheEnvironment: process.env.CLANG_MODULE_CACHE_PATH ?? null,
}));
});
if (cache !== undefined) {
fs.mkdirSync(cache, { recursive: true });
fs.writeFileSync(path.join(cache, "written-into-cache"), "kept");
@@ -628,6 +640,33 @@ it.skipIf(!onDarwin)(
});
try {
await host.prepare?.(AbortSignal.timeout(180_000));
const current = (await host.listProcesses()).find(
({ pid }) => pid === process.pid,
);
if (current === undefined)
throw new Error("Current process missing from host snapshot");
if (host.processIdentities === undefined)
throw new Error("Darwin host omitted native identity inspection");
const identity = (await host.processIdentities([current])).get(
process.pid,
);
expect(identity).toMatchObject({
state: "readable",
relation: {
state: "observed",
parentPid: process.ppid,
processGroupId: current.processGroupId,
},
});
if (identity?.state !== "readable")
throw new Error("Current native identity unavailable");
expect(identity.identity).not.toBe("");
expect(
(await host.processIdentities([current])).get(process.pid),
).toMatchObject({
state: "readable",
identity: identity.identity,
});
const entries = await readdir(cachePath);
expect(
entries.some(
@@ -705,6 +744,7 @@ const writeTemporaryObjectCompiler = async (directory: string) => {
const statePath = join(directory, "temporary-state.json");
const source = `#!/usr/bin/env node
const fs = process.getBuiltinModule("node:fs");
${publishFixtureStateSource}
const os = process.getBuiltinModule("node:os");
const path = process.getBuiltinModule("node:path");
const { spawn } = process.getBuiltinModule("node:child_process");
@@ -721,7 +761,7 @@ process.on("SIGINT", () => {
process.exit(130);
});
const output = process.argv[process.argv.indexOf("-o") + 1];
fs.writeFileSync(${JSON.stringify(statePath)}, JSON.stringify({ root: path.dirname(output), temporary }));
publishFixtureState(${JSON.stringify(statePath)}, { root: path.dirname(output), temporary });
setInterval(() => {}, 1000);
`;
await writeFile(executable, source);