From 3afec595233778f5cd437ff92f62fad59a0a140f Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Fri, 23 Oct 2026 05:03:15 +0800 Subject: [PATCH] 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. --- .../darwinProcessRunTokenReader.test.ts | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/tests/boundary/process/darwinProcessRunTokenReader.test.ts b/tests/boundary/process/darwinProcessRunTokenReader.test.ts index 6e5e264bb3..dcdddc3afa 100644 --- a/tests/boundary/process/darwinProcessRunTokenReader.test.ts +++ b/tests/boundary/process/darwinProcessRunTokenReader.test.ts @@ -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);