Files
rea/tests/process-global/firmwareFileLifetime.test.ts
T
morluto 2d163c12b1 fix(firmware): own file access through publication and cleanup retry
Refs #4475.

Share descriptor scopes across firmware inspection and publication. Preserve primary failures, exact cancellation reasons, and unresolved resources through finalization.
2026-10-17 00:44:02 +08:00

816 lines
28 KiB
TypeScript

import { execFile } from "node:child_process";
import { createHash } from "node:crypto";
import {
access,
mkdir,
rm,
writeFile,
type FileHandle,
} from "node:fs/promises";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { promisify } from "node:util";
import { afterEach, beforeEach, expect, it, vi } from "vitest";
const fault = vi.hoisted(() => ({
selected: "",
handles: [] as FileHandle[],
blocked: new Set<FileHandle>(),
onClose: undefined as (() => Promise<void>) | undefined,
malformed: false,
onSync: undefined as (() => void) | undefined,
}));
vi.mock("node:fs/promises", async (importOriginal) => {
const original = await importOriginal<typeof import("node:fs/promises")>();
return {
...original,
open: async (...args: Parameters<typeof original.open>) => {
const handle = await original.open(...args);
if (
!fault.selected ||
!String(args[0]).endsWith(fault.selected) ||
typeof args[1] !== "number"
)
return handle;
const close = handle.close.bind(handle);
const sync = handle.sync.bind(handle);
handle.sync = async () => {
await sync();
fault.onSync?.();
};
fault.handles.push(handle);
fault.blocked.add(handle);
handle.close = async () => {
await fault.onClose?.();
if (fault.blocked.has(handle))
throw new Error("controlled firmware descriptor close failure");
await close();
};
return handle;
},
};
});
// Only host/tool admission and producer execution are simulated. File IO,
// normalization, provider finalization and cleanup ownership remain production code.
vi.mock("../../src/firmware/FirmwareCommand.js", async (importOriginal) => {
const original =
await importOriginal<
typeof import("../../src/firmware/FirmwareCommand.js")
>();
return {
...original,
resolveFirmwareCommand: async () => ({
command: "/fixture/binwalk",
limiter: "/fixture/prlimit",
sha256: "0".repeat(64),
}),
runFirmwareCommand: async (
context: Parameters<typeof original.runFirmwareCommand>[0],
) => {
const version = context.args[0] === "--version";
if (!version) {
const report = context.args[context.args.indexOf("--log") + 1];
if (report === undefined)
throw new Error("Missing fixture report path");
await writeFile(
report,
fault.malformed
? "{"
: JSON.stringify([
{
Analysis: {
file_path: context.args.at(-1),
file_map: [],
extractions: {},
},
},
]),
);
}
const text = version ? "binwalk 3.1.0" : "";
return {
stdout: { text, bytes: Buffer.byteLength(text), truncated: false },
stderr: { text: "", bytes: 0, truncated: false },
exit_code: 0,
signal: null,
command: context.command,
args: context.args,
resource_limiter: context.limiter,
};
},
};
});
import { FirmwareFileAccess } from "../../src/firmware/FirmwareFiles.js";
import { publishFirmwareExtraction } from "../../src/firmware/FirmwarePublication.js";
import { normalizeUnblobReport } from "../../src/firmware/FirmwareReports.js";
import { SafeOutputTree } from "../../src/artifacts/SafeOutputTree.js";
import { AnalysisCleanupLease } from "../../src/artifacts/AnalysisCleanupLease.js";
import { ArtifactReaderFailure } from "../../src/artifacts/ArtifactReader.js";
import { FirmwareProvider } from "../../src/firmware/FirmwareProvider.js";
import { firmwareFailure } from "../../src/firmware/FirmwareFailures.js";
import { ArtifactFileCleanupFailure } from "../../src/artifacts/ArtifactFileOperation.js";
import { AnalysisError } from "../../src/domain/analysisErrorBase.js";
import { AnalysisCancelledError } from "../../src/domain/analysisErrorCore.js";
import { PrivateRuntimeRoot } from "../../src/process/PrivateRuntimeRoot.js";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
const providers: FirmwareProvider[] = [];
beforeEach(() => {
fault.selected = "";
fault.handles = [];
fault.blocked.clear();
fault.onClose = undefined;
fault.malformed = false;
fault.onSync = undefined;
});
afterEach(async () => {
fault.blocked.clear();
fault.onClose = undefined;
vi.restoreAllMocks();
for (const handle of fault.handles) await handle.close();
await Promise.all(providers.splice(0).map((provider) => provider.close()));
});
it.skipIf(process.platform === "win32")(
"rejects writerless FIFO input, hash and report through the compiled reader",
async () => {
const root = await createTestTempDirectory("rea-firmware-fifo-");
const fifo = join(root, "input.fifo");
const work = join(root, "work");
await mkdir(work);
await promisify(execFile)("mkfifo", [fifo]);
const module = pathToFileURL(
join(process.cwd(), "dist/firmware/FirmwareFiles.js"),
).href;
const script = `import { FirmwareFileAccess } from ${JSON.stringify(module)};
const files = new FirmwareFileAccess();
const outcomes = [];
for (const run of [() => files.hash(process.argv[1]), () => files.report(process.argv[1], 'inspect_firmware_regions'), () => files.snapshot({ operation: 'inspect_firmware_regions', input: { path: process.argv[1] } }, process.argv[2], new AbortController().signal)]) {
try { await run(); outcomes.push('unexpected-success'); } catch (error) { outcomes.push(error._tag ?? error.name); }
}
await files.close(); console.log(JSON.stringify(outcomes));`;
const { stdout } = await promisify(execFile)(
process.execPath,
["--input-type=module", "-e", script, fifo, work],
{ timeout: 3000 },
);
expect(JSON.parse(stdout)).toEqual([
"NonRegularFileReadError",
"AnalysisOutputError",
"AnalysisInputError",
]);
},
);
it.each(["hash", "report"] as const)(
"retains completed %s and exact owner across rejected retry",
async (kind) => {
const root = await createTestTempDirectory("rea-firmware-read-owner-");
const path = join(root, "selected.bin");
await writeFile(path, '{"value":"固件"}');
fault.selected = path;
const files = new FirmwareFileAccess();
const raw = await (
kind === "hash"
? files.hash(path)
: files.report(path, "inspect_firmware_regions")
).catch((cause: unknown) => cause);
expect(raw).toBeInstanceOf(ArtifactFileCleanupFailure);
if (!(raw instanceof ArtifactFileCleanupFailure))
throw new Error("Missing physical file outcome");
expect(raw.fileCleanupFailure.outcome).toEqual({
kind: "completed",
value:
kind === "hash"
? createHash("sha256").update('{"value":"固件"}').digest("hex")
: { value: "固件" },
});
const original = firmwareFailure(
raw,
"binwalk",
"inspect_firmware_regions",
);
const retry = await files
.retryCleanup()
.catch((cause: unknown) =>
firmwareFailure(cause, "binwalk", "inspect_firmware_regions"),
);
expect(retry).toBeInstanceOf(AnalysisError);
expect(fault.handles).toHaveLength(1);
const handle = fault.handles[0];
if (handle === undefined) throw new Error("Missing exact descriptor");
expect(handle.fd).toBeGreaterThanOrEqual(0);
fault.blocked.delete(handle);
await files.close();
expect(handle.fd).toBe(-1);
expect(original.cleanupIncomplete).toBe(false);
if (retry instanceof AnalysisError)
expect(retry.cleanupIncomplete).toBe(false);
},
);
it("preserves malformed-report failure when cancellation arrives during failed close", async () => {
const root = await createTestTempDirectory("rea-firmware-primary-");
const path = join(root, "report.json");
await writeFile(path, "{");
fault.selected = path;
const controller = new AbortController();
fault.onClose = async () => controller.abort("late close cancellation");
const files = new FirmwareFileAccess();
const raw = await files
.report(path, "inspect_firmware_regions", controller.signal)
.catch((cause: unknown) => cause);
const error = firmwareFailure(raw, "binwalk", "inspect_firmware_regions");
expect(error.diagnostics?.primary_error).toMatchObject({
code: "unreadable_output",
});
fault.blocked.clear();
await files.close();
expect(error.cleanupIncomplete).toBe(false);
});
it.each([null, "caller cancellation", new Error("caller cancellation")])(
"preserves exact cancellation during final close: %s",
async (reason) => {
const root = await createTestTempDirectory("rea-firmware-final-cancel-");
const path = join(root, "report.json");
await writeFile(path, "{}");
fault.selected = path;
const controller = new AbortController();
fault.onClose = async () => {
controller.abort(reason);
fault.blocked.clear();
};
const files = new FirmwareFileAccess();
const raw = await files
.report(path, "inspect_firmware_regions", controller.signal)
.catch((cause: unknown) => cause);
const error = firmwareFailure(raw, "binwalk", "inspect_firmware_regions");
expect(error).toBeInstanceOf(AnalysisCancelledError);
expect(error.cause).toBe(reason);
await files.close();
},
);
it.each(["descriptor-first", "workspace-first"])(
"keeps provider mixed-owner cleanup incomplete until both release: %s",
async (order) => {
const root = await createTestTempDirectory("rea-firmware-mixed-owner-");
const path = join(root, "input.bin");
await writeFile(path, "firmware bytes");
fault.selected = "report.json";
let workspaceBlocked = true;
let workspacePath = "";
const close = PrivateRuntimeRoot.prototype.close;
vi.spyOn(PrivateRuntimeRoot.prototype, "close").mockImplementation(
async function (this: PrivateRuntimeRoot) {
workspacePath = this.path;
if (workspaceBlocked)
throw new Error("controlled workspace cleanup failure");
await close.call(this);
},
);
const provider = new FirmwareProvider({});
providers.push(provider);
const result = await provider.execute({
operation: "inspect_firmware_regions",
input: { path },
});
if (result.ok) throw new Error("Expected descriptor and workspace failure");
expect(result.error.cleanupIncomplete).toBe(true);
expect(result.error.cleanupResources).toContain(workspacePath);
expect(fault.handles).toHaveLength(1);
const blocked = await provider.execute({
operation: "inspect_firmware_regions",
input: { path },
});
expect(blocked).toMatchObject({
ok: false,
error: { cleanupIncomplete: true },
});
expect(fault.handles).toHaveLength(1);
if (order === "descriptor-first") fault.blocked.clear();
else workspaceBlocked = false;
const retry = await provider.close().catch((cause: unknown) => cause);
expect(retry).toBeInstanceOf(AnalysisError);
expect(result.error.cleanupIncomplete).toBe(true);
if (order === "workspace-first")
await expect(access(workspacePath)).rejects.toMatchObject({
code: "ENOENT",
});
else expect(fault.handles[0]?.fd).toBe(-1);
fault.blocked.clear();
workspaceBlocked = false;
await provider.close();
expect(result.error.cleanupIncomplete).toBe(false);
if (retry instanceof AnalysisError)
expect(retry.cleanupIncomplete).toBe(false);
if (!blocked.ok) expect(blocked.error.cleanupIncomplete).toBe(false);
},
);
it("retains completed firmware observation when cancellation arrives during workspace close", async () => {
const root = await createTestTempDirectory("rea-firmware-workspace-cancel-");
const path = join(root, "input.bin");
await writeFile(path, "firmware bytes");
const controller = new AbortController();
const close = PrivateRuntimeRoot.prototype.close;
vi.spyOn(PrivateRuntimeRoot.prototype, "close").mockImplementation(
async function (this: PrivateRuntimeRoot) {
controller.abort(null);
await close.call(this);
},
);
const provider = new FirmwareProvider({});
providers.push(provider);
const result = await provider.execute(
{ operation: "inspect_firmware_regions", input: { path } },
{ signal: controller.signal },
);
expect(result).toMatchObject({
ok: false,
error: {
_tag: "AnalysisCancelledError",
cause: null,
partialObservation: { kind: "firmware" },
},
});
});
it.skipIf(process.platform === "win32").each(["snapshot", "report"] as const)(
"retains typed %s admission failure when rejecting a directory also fails close",
async (kind) => {
const root = await createTestTempDirectory(
"rea-firmware-rejected-admission-",
);
const path = join(root, "selected");
const work = join(root, "work");
await mkdir(path);
await mkdir(work);
fault.selected = path;
const files = new FirmwareFileAccess();
const raw = await (
kind === "snapshot"
? files.snapshot(
{ operation: "inspect_firmware_regions", input: { path } },
work,
new AbortController().signal,
)
: files.report(path, "inspect_firmware_regions")
).catch((cause: unknown) => cause);
const error = firmwareFailure(raw, "binwalk", "inspect_firmware_regions");
expect(error.diagnostics?.primary_error).toMatchObject({
code: kind === "snapshot" ? "invalid_request" : "unreadable_output",
});
expect(error.cleanupIncomplete).toBe(true);
fault.blocked.clear();
await files.close();
expect(error.cleanupIncomplete).toBe(false);
},
);
it.each([false, true])(
"retains timeout during workspace finalization (close fails: %s)",
async (closeFails) => {
const root = await createTestTempDirectory("rea-firmware-final-timeout-");
const path = join(root, "input.bin");
await writeFile(path, "firmware bytes");
const deadline = new AbortController();
vi.spyOn(AbortSignal, "timeout").mockReturnValue(deadline.signal);
let blocked = closeFails;
const close = PrivateRuntimeRoot.prototype.close;
vi.spyOn(PrivateRuntimeRoot.prototype, "close").mockImplementation(
async function (this: PrivateRuntimeRoot) {
deadline.abort(new DOMException("controlled deadline", "TimeoutError"));
if (blocked)
throw new Error("controlled final workspace close failure");
await close.call(this);
},
);
const provider = new FirmwareProvider({});
providers.push(provider);
const result = await provider.execute({
operation: "inspect_firmware_regions",
input: { path },
});
if (result.ok) throw new Error("Expected timeout");
expect(result.error.partialObservation).toMatchObject({ kind: "firmware" });
if (closeFails) {
expect(result.error.diagnostics?.primary_error).toMatchObject({
code: "provider_timeout",
});
expect(result.error.cleanupIncomplete).toBe(true);
blocked = false;
await provider.close();
expect(result.error.cleanupIncomplete).toBe(false);
} else
expect(result.error).toMatchObject({
_tag: "AnalysisTimeoutError",
cause: deadline.signal.reason,
});
},
);
it("classifies a deadline before composing failed descriptor cleanup", async () => {
const root = await createTestTempDirectory("rea-firmware-file-timeout-");
const path = join(root, "report.json");
await writeFile(path, "{}");
fault.selected = path;
const deadline = new AbortController();
fault.onClose = async () =>
deadline.abort(new DOMException("controlled deadline", "TimeoutError"));
const files = new FirmwareFileAccess();
const raw = await files
.report(path, "inspect_firmware_regions", deadline.signal)
.catch((cause: unknown) => cause);
const error = firmwareFailure(
raw,
"binwalk",
"inspect_firmware_regions",
deadline.signal,
);
expect(error.diagnostics?.primary_error).toMatchObject({
code: "provider_timeout",
});
fault.blocked.clear();
await files.close();
expect(error.cleanupIncomplete).toBe(false);
});
const publication = async (
signal: AbortSignal,
deadline = new AbortController().signal,
) => {
const root = await createTestTempDirectory(
"rea-firmware-publication-lifetime-",
);
const inputPath = join(root, "input.bin");
const outputRoot = join(root, "extracted");
const sha256 = "0".repeat(64);
const normalized = normalizeUnblobReport(
[
{
task: {
path: inputPath,
depth: 0,
blob_id: "root",
is_multi_file: false,
},
reports: [
{ __typename__: "HashReport", sha256 },
{
__typename__: "StatReport",
path: inputPath,
size: 8,
is_dir: false,
is_file: true,
is_link: false,
link_target: null,
},
],
subtasks: [],
},
],
{ inputPath, outputRoot, sha256, length: 8, offset: 0, maxDepth: 3 },
);
const retained: AnalysisCleanupLease[] = [];
const workspacePath = join(root, "private");
await mkdir(workspacePath);
const context = {
files: new FirmwareFileAccess(),
workspacePath,
deadline,
outputDirectory: join(root, "published"),
entries: [],
normalized,
selection: { offset: 0, length: 8, sha256 },
maxDepth: 3,
engine: {
name: "unblob",
version: "26.6.4",
executable_path: "/fixture/unblob",
executable_sha256: sha256,
source_revision: null,
worker_count: 1 as const,
},
signal,
retainCleanup: (
_tree: SafeOutputTree,
lease: AnalysisCleanupLease,
failure: AnalysisError,
) => {
const workspace = new AnalysisCleanupLease(() =>
rm(workspacePath, { recursive: true, force: true }),
);
workspace.bindCleanupError(failure);
retained.push(
new AnalysisCleanupLease(async () => {
await lease.release();
await workspace.release();
}),
);
},
};
return { context, retained };
};
it("preserves primitive cancellation before publication commit and rolls back the output", async () => {
const controller = new AbortController();
const fixture = await publication(controller.signal);
const create = SafeOutputTree.create;
vi.spyOn(SafeOutputTree, "create").mockImplementation(async (...args) => {
const tree = await create(...args);
controller.abort(null);
return tree;
});
const error = await publishFirmwareExtraction(fixture.context).catch(
(cause: unknown) => cause,
);
expect(error).toBeInstanceOf(AnalysisCancelledError);
if (error instanceof AnalysisCancelledError) expect(error.cause).toBeNull();
await expect(access(fixture.context.outputDirectory)).rejects.toMatchObject({
code: "ENOENT",
});
expect(fixture.retained).toHaveLength(0);
await fixture.context.files.close();
});
it.each(["caller", "deadline"])(
"preserves %s cancellation during directory sync plus failed close and rollback",
async (kind) => {
const controller = new AbortController();
const reason =
kind === "caller"
? null
: new DOMException("controlled deadline", "TimeoutError");
const fixture = await publication(
controller.signal,
kind === "deadline" ? controller.signal : undefined,
);
const create = SafeOutputTree.create;
vi.spyOn(SafeOutputTree, "create").mockImplementation(async (...args) => {
const tree = await create(...args);
fault.selected = tree.outputRoot;
fault.onSync = () => controller.abort(reason);
return tree;
});
const error = await publishFirmwareExtraction(fixture.context).catch(
(cause: unknown) => cause,
);
if (!(error instanceof AnalysisError))
throw new Error("Expected typed tree failure");
expect(error.cleanupIncomplete).toBe(true);
expect(error.diagnostics?.primary_error).toMatchObject({
code: "cleanup_incomplete",
details: {
diagnostics: {
primary_error: {
code: kind === "caller" ? "cancelled" : "provider_timeout",
},
},
},
});
const aggregate = error.cause;
if (!(aggregate instanceof AggregateError))
throw new Error("Expected primary and cleanup causes");
const primary = aggregate.errors[0] as AnalysisError;
const inner = primary.cause;
if (!(inner instanceof AggregateError))
throw new Error("Expected primary cancellation plus commit cleanup");
expect((inner.errors[0] as AnalysisError).cause).toBe(reason);
expect(fixture.retained).toHaveLength(1);
fault.blocked.clear();
await Promise.all(fixture.retained.map((lease) => lease.release()));
expect(error.cleanupIncomplete).toBe(false);
await expect(access(fixture.context.outputDirectory)).rejects.toMatchObject(
{ code: "ENOENT" },
);
await fixture.context.files.close();
},
);
it("retains a completed published observation when commit cleanup and rollback both fail", async () => {
const fixture = await publication(new AbortController().signal);
const commit = SafeOutputTree.prototype.commit;
vi.spyOn(SafeOutputTree.prototype, "commit").mockImplementation(
async function (this: SafeOutputTree, signal) {
await commit.call(this, signal);
throw ArtifactReaderFailure.withCleanup(
new Error("controlled published commit cleanup failure"),
{
reason: "controlled pending directory close",
resources: [this.outputRoot],
},
);
},
);
const rollback = SafeOutputTree.prototype.rollback;
let blocked = true;
vi.spyOn(SafeOutputTree.prototype, "rollback").mockImplementation(
async function (this: SafeOutputTree) {
if (blocked) throw new Error("controlled rollback failure");
return rollback.call(this);
},
);
const error = await publishFirmwareExtraction(fixture.context).catch(
(cause: unknown) => cause,
);
if (!(error instanceof AnalysisError))
throw new Error("Expected typed publication cleanup failure");
expect(error.partialObservation).toMatchObject({
kind: "firmware",
result: { output_directory: fixture.context.outputDirectory, files: [] },
});
expect(error.cleanupIncomplete).toBe(true);
blocked = false;
await Promise.all(fixture.retained.map((lease) => lease.release()));
expect(error.cleanupIncomplete).toBe(false);
await expect(
access(fixture.context.outputDirectory),
).resolves.toBeUndefined();
await fixture.context.files.close();
});
it("waits through selected-range snapshot finalization when shutdown starts during source close", async () => {
const root = await createTestTempDirectory("rea-firmware-selected-close-");
const path = join(root, "input.bin");
const work = join(root, "work");
await mkdir(work);
await writeFile(path, "firmware bytes");
fault.selected = path;
let enter!: () => void;
let release!: () => void;
const entered = new Promise<void>((resolve) => {
enter = resolve;
});
const gate = new Promise<void>((resolve) => {
release = resolve;
});
fault.onClose = async () => {
fault.blocked.clear();
enter();
await gate;
};
const files = new FirmwareFileAccess();
const pending = files.snapshot(
{
operation: "extract_firmware",
input: {
path,
output_directory: join(root, "unused"),
max_depth: 3,
max_output_bytes: 1024,
max_output_files: 10,
range: { offset: 1, length: 4 },
},
},
work,
new AbortController().signal,
);
try {
await entered;
let closed = false;
const closing = files.close().then(() => {
closed = true;
});
await new Promise<void>((resolve) => setImmediate(resolve));
expect(closed).toBe(false);
release();
const snapshot = await pending;
await closing;
expect(snapshot.selection).toMatchObject({
offset: 1,
length: 4,
sha256: createHash("sha256").update("irmw").digest("hex"),
});
expect(fault.handles.every((handle) => handle.fd === -1)).toBe(true);
} finally {
release();
await pending.catch(() => {});
await files.close();
}
});
it("retains the exact publication source descriptor when its final close fails", async () => {
const fixture = await publication(new AbortController().signal);
const path = join(fixture.context.workspacePath, "source.bin");
const bytes = Buffer.from("published bytes");
await writeFile(path, bytes);
const tree = await SafeOutputTree.create(fixture.context.outputDirectory);
fault.selected = path;
const raw = await fixture.context.files
.publish(
{
path,
relativePath: "file.bin",
size: bytes.length,
kind: "file",
linkTarget: null,
},
createHash("sha256").update(bytes).digest("hex"),
tree,
fixture.context.signal,
)
.catch((cause: unknown) => cause);
expect(raw).toBeInstanceOf(ArtifactFileCleanupFailure);
const error = firmwareFailure(raw, "unblob", "extract_firmware");
expect(error.cleanupResources).toContain(path);
await tree.rollback();
expect(error.cleanupIncomplete).toBe(true);
fault.blocked.clear();
await fixture.context.files.close();
expect(error.cleanupIncomplete).toBe(false);
expect(fault.handles[0]?.fd).toBe(-1);
});
it.each(["source-first", "tree-first"])(
"keeps nested source and destination cleanup bound to their exact owners: %s",
async (order) => {
const fixture = await publication(new AbortController().signal);
const path = join(fixture.context.workspacePath, "payload.bin");
const bytes = Buffer.from("published bytes");
await writeFile(path, bytes);
const hash = fixture.context.files.hash.bind(fixture.context.files);
vi.spyOn(fixture.context.files, "hash").mockImplementation(
async (...args) => {
const digest = await hash(...args);
fault.selected = "payload.bin";
return digest;
},
);
const error = await publishFirmwareExtraction({
...fixture.context,
entries: [
{
path,
relativePath: "payload.bin",
size: bytes.length,
kind: "file",
linkTarget: null,
},
],
}).catch((cause: unknown) => cause);
if (!(error instanceof AnalysisError))
throw new Error("Expected nested file and tree cleanup failure");
expect(error.cleanupIncomplete).toBe(true);
expect(fault.handles.length).toBeGreaterThanOrEqual(2);
expect(fixture.retained).toHaveLength(1);
fault.blocked.clear();
if (order === "source-first") await fixture.context.files.close();
else await Promise.all(fixture.retained.map((lease) => lease.release()));
expect(error.cleanupIncomplete).toBe(true);
await fixture.context.files.close();
await Promise.all(fixture.retained.map((lease) => lease.release()));
expect(error.cleanupIncomplete).toBe(false);
expect(fault.handles.every((handle) => handle.fd === -1)).toBe(true);
},
);
it("shares one workspace cleanup attempt across concurrent shutdown callers", async () => {
const root = await createTestTempDirectory("rea-firmware-concurrent-close-");
const path = join(root, "input.bin");
await writeFile(path, "firmware bytes");
let blocked = true;
let attempts = 0;
let enter!: () => void;
let release!: () => void;
const entered = new Promise<void>((resolve) => {
enter = resolve;
});
const gate = new Promise<void>((resolve) => {
release = resolve;
});
const close = PrivateRuntimeRoot.prototype.close;
vi.spyOn(PrivateRuntimeRoot.prototype, "close").mockImplementation(
async function (this: PrivateRuntimeRoot) {
attempts++;
if (blocked) throw new Error("controlled first workspace close failure");
enter();
await gate;
await close.call(this);
},
);
const provider = new FirmwareProvider({});
providers.push(provider);
const result = await provider.execute({
operation: "inspect_firmware_regions",
input: { path },
});
if (result.ok) throw new Error("Expected retained workspace cleanup");
blocked = false;
const first = provider.close();
try {
await entered;
const second = provider.close();
expect(second).toBe(first);
expect(attempts).toBe(2);
release();
await Promise.all([first, second]);
expect(result.error.cleanupIncomplete).toBe(false);
} finally {
release();
await first;
}
});