test(process): bind cleanup fixtures to selected resources

This commit is contained in:
morluto committed 2026-11-09 14:58:35 +08:00
1 parent 5d5fe72218
commit 95382c2ba0
3 files changed
+39 -8

No files matched your search

@@ -281,16 +281,26 @@ it
} satisfies Parameters<typeof validateVerifierJadxConfiguration>[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();
}
`;
@@ -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)
@@ -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<typeof original.openRegularFile>) => {
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";