diff --git a/tests/boundary/process/verifierFileResources.test.ts b/tests/boundary/process/verifierFileResources.test.ts index 01d2ab9b9e..fbdb4c480d 100644 --- a/tests/boundary/process/verifierFileResources.test.ts +++ b/tests/boundary/process/verifierFileResources.test.ts @@ -281,16 +281,26 @@ it } satisfies Parameters[0]; const script = String.raw` import assert from 'node:assert/strict'; + import fs from 'node:fs'; + import { syncBuiltinESMExports } from 'node:module'; import { validateVerifierJadxConfiguration } from ${JSON.stringify(new URL("../../../scripts/lib/jadx-configuration-inspection.mjs", import.meta.url).href)}; import { OwnedFileHandle } from ${JSON.stringify(new URL("../../../dist/filesystem/OwnedFileHandle.js", import.meta.url).href)}; import { ArtifactResourceRetryFailure } from ${JSON.stringify(new URL("../../../dist/artifacts/ArtifactResourceScope.js", import.meta.url).href)}; const [serializedConfiguration, mode] = process.argv.slice(1); const configuration = JSON.parse(serializedConfiguration); const handles = new Set(); + const originalOpen = fs.promises.open; + fs.promises.open = async (...args) => { + const handle = await originalOpen(...args); + if (args[0] === configuration.jar) handles.add(handle); + return handle; + }; + syncBuiltinESMExports(); let attempts = 0, denied = true; const originalClose = OwnedFileHandle.prototype.close; OwnedFileHandle.prototype.close = async function () { - handles.add(this.handle); attempts++; + if (!handles.has(this.handle)) return originalClose.call(this); + attempts++; if ((mode === 'retry-close' && attempts === 1) || (mode === 'retained-close' && denied)) throw new Error('controlled archive close refusal'); return originalClose.call(this); }; @@ -317,6 +327,8 @@ it } finally { denied = false; OwnedFileHandle.prototype.close = originalClose; + fs.promises.open = originalOpen; + syncBuiltinESMExports(); for (const handle of handles) await handle.close(); } `; diff --git a/tests/boundary/providers/hopper/bridgeLauncher.test.ts b/tests/boundary/providers/hopper/bridgeLauncher.test.ts index 0e9a9b24b6..a4f9d64457 100644 --- a/tests/boundary/providers/hopper/bridgeLauncher.test.ts +++ b/tests/boundary/providers/hopper/bridgeLauncher.test.ts @@ -1,5 +1,5 @@ import { createHash, randomUUID } from "node:crypto"; -import { execFile } from "node:child_process"; +import { ChildProcess, execFile } from "node:child_process"; import { access, chmod, open, readFile, rm, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { promisify } from "node:util"; @@ -72,6 +72,9 @@ for (const deniedStops of [0, 2]) `retains a timed-out private-display probe through cleanup retry (denied stops=${String(deniedStops)})`, async () => { const directory = await createTestTempDirectory("rea-probe-owner-retry-"); + const helperPath = fileURLToPath( + new URL("../../../fixtures/x11ProbeHang.py", import.meta.url), + ); const originalStop = ProviderProcessSupervisor.prototype.stop; const captured: { current?: ProviderProcessSupervisor } = {}; let attempts = 0; @@ -81,6 +84,11 @@ for (const deniedStops of [0, 2]) this: ProviderProcessSupervisor, settings, ) { + if ( + !(this.launch.process instanceof ChildProcess) || + !this.launch.process.spawnargs.includes(helperPath) + ) + return originalStop.call(this, settings); captured.current = this; attempts += 1; return attempts <= deniedStops @@ -105,9 +113,7 @@ for (const deniedStops of [0, 2]) selectPrivateDisplay: (settings) => selectLinuxPrivateDisplayStrategy({ ...settings, - helperPath: fileURLToPath( - new URL("../../../fixtures/x11ProbeHang.py", import.meta.url), - ), + helperPath, timeoutMs: 75, }), }, @@ -124,7 +130,14 @@ for (const deniedStops of [0, 2]) expect(projectAnalysisError(original).details).toMatchObject({ diagnostics: { reason: "probe_timeout" }, }); - expect(original.cleanupIncomplete).toBe(deniedStops > 0); + const initiallyPending = original.cleanupIncomplete; + if (deniedStops > 0) expect(initiallyPending).toBe(true); + if (initiallyPending) + expect(original.cleanupResources).toEqual( + expect.arrayContaining([ + expect.stringMatching(/^hopper-private-display-probe:/u), + ]), + ); const supervisor = captured.current; if (supervisor === undefined) throw new Error("Expected the real owned probe"); @@ -142,7 +155,9 @@ for (const deniedStops of [0, 2]) supervisor.launch.process.exitCode !== null || supervisor.launch.process.signalCode !== null, ).toBe(true); - expect(attempts).toBe(deniedStops + 1); + const expectedAttempts = + deniedStops === 0 && initiallyPending ? 2 : deniedStops + 1; + expect(attempts).toBe(expectedAttempts); } finally { stop.mockRestore(); if (captured.current !== undefined) diff --git a/tests/boundary/providers/kuna/kunaInstallationLifetime.test.ts b/tests/boundary/providers/kuna/kunaInstallationLifetime.test.ts index aded1b35b9..903b0c9122 100644 --- a/tests/boundary/providers/kuna/kunaInstallationLifetime.test.ts +++ b/tests/boundary/providers/kuna/kunaInstallationLifetime.test.ts @@ -17,6 +17,7 @@ const gates = vi.hoisted(() => { hashClose: createGate(), identityRead: createGate(), opens: 0, + selectedPath: null as string | null, failClose: false, holdHashClose: false, holdIdentityRead: false, @@ -33,6 +34,7 @@ vi.mock("../../../../src/filesystem/RegularFile.js", async (importOriginal) => { openRegularFile: vi.fn( async (...args: Parameters) => { const descriptor = await original.openRegularFile(...args); + if (args[0] !== gates.selectedPath) return descriptor; const { handle } = descriptor; const index = gates.opens++; const read = handle.read.bind(handle); @@ -71,6 +73,7 @@ import { session } from "./kunaSessionFixture.js"; beforeEach(() => { gates.opens = 0; + gates.selectedPath = null; gates.failClose = false; gates.holdHashClose = false; gates.holdIdentityRead = false; @@ -91,6 +94,7 @@ it async (phase) => { const root = await createTestTempDirectory("rea-kuna-inspection-lifetime-"); const executable = await writeFakeKuna(root); + gates.selectedPath = executable; const scope = new ArtifactResourceScope(); const resourceScope: RetainedResourceScope = { retain: (owner, resource) => @@ -157,7 +161,7 @@ it gates.hashClose.release(); gates.identityRead.release(); const fixture = await session("rea-kuna-session-finalization-"); - gates.opens = 0; + gates.selectedPath = fixture.kuna; gates.hashClose = gates.createGate(); gates.identityRead = gates.createGate(); gates.holdHashClose = phase !== "identity-read";