Files
rea/tests/boundary/process/verifierCleanup.test.ts
T
morluto 72ba1cd92b fix(verifiers): centralize failure and cleanup ownership
Own operation results and exact rejections in withVerifierCleanup, including
undefined, null and independent cleanup failures. Remove the optional-primary
cleanup contract and migrate every caller, preserving returns, annotations,
signal restoration and dependent cleanup order.

Make Frida/JEB reporters fail on reasonless rejections and retain JEB fixture
files while provider cleanup is incomplete. Own the nested packaged WASM
verifier and expose its composite process/root cleanup capability for retry.
Update runnable docs and isolated fixture dependencies.

Validation: 547 focused cases in 20 files, eight isolated boundary unit checks,
static/build/docs/discovery gates and duplication check (3.58%). Node process,
SDK and descriptor cleanup are exercised; provider and packaging results in
orchestration tests are simulated. Pack/install subprocess ownership remains
with the existing shared package runner outside the nested-command change.
2026-10-24 15:38:35 +08:00

218 lines
6.4 KiB
TypeScript

import { expect, it } from "vitest";
import {
closeVerifierResources,
withVerifierCleanup,
} from "../../../scripts/lib/verifier-cleanup.mjs";
it("attempts every cleanup and reports failures when there is no primary error", async () => {
const attempted: string[] = [];
const tasks = [
async () => {
attempted.push("provider");
throw new Error("provider close failed");
},
async () => {
attempted.push("fixture");
},
];
let failure: unknown;
try {
await closeVerifierResources(tasks);
} catch (cause) {
failure = cause;
}
expect(failure).toBeInstanceOf(AggregateError);
expect(
(failure as AggregateError).errors.map((error) => error.message),
).toEqual(["provider close failed"]);
expect(attempted).toEqual(["provider", "fixture"]);
});
it("retains primary verification and independent cleanup failures", async () => {
const primary = new Error("analysis assertion failed");
const attempted: string[] = [];
const tasks = [
async () => {
attempted.push("provider");
throw new Error("provider close failed");
},
async () => {
attempted.push("fixture");
throw new Error("fixture removal failed");
},
];
let failure: unknown;
try {
await withVerifierCleanup(() => {
throw primary;
}, tasks);
} catch (cause) {
failure = cause;
}
expect(failure).toBeInstanceOf(AggregateError);
expect((failure as AggregateError).cause).toBe(primary);
expect((failure as AggregateError).errors).toEqual([
primary,
expect.objectContaining({ message: "provider close failed" }),
expect.objectContaining({ message: "fixture removal failed" }),
]);
expect(attempted).toEqual(["provider", "fixture"]);
});
it("keeps a parent fixture when any owned child cleanup remains incomplete", async () => {
const primary = new Error("verification failed");
const attempted: string[] = [];
let parentRemoved = false;
let failure: unknown;
try {
await withVerifierCleanup(() => {
throw primary;
}, [
async () => {
await closeVerifierResources([
async () => {
attempted.push("client");
},
async () => {
attempted.push("transport");
throw new Error("transport close failed");
},
async () => {
attempted.push("file-scope");
},
]);
parentRemoved = true;
},
]);
} catch (cause) {
failure = cause;
}
expect(failure).toBeInstanceOf(AggregateError);
expect((failure as AggregateError).errors[0]).toBe(primary);
expect((failure as AggregateError).cause).toBe(primary);
expect((failure as AggregateError).errors[1]).toBeInstanceOf(AggregateError);
expect(attempted).toEqual(["client", "transport", "file-scope"]);
expect(parentRemoved).toBe(false);
});
it.each([undefined, null, new Error("exact operation failure")])(
"preserves an exact operation rejection after successful cleanup: %s",
async (primary) => {
const attempted: string[] = [];
await expect(
withVerifierCleanup(() => {
attempted.push("operation");
throw primary;
}, [
() => {
attempted.push("cleanup");
},
]),
).rejects.toBe(primary);
expect(attempted).toEqual(["operation", "cleanup"]);
},
);
it.each([undefined, null])(
"retains an opaque operation rejection with its independent cleanup failure: %s",
async (primary) => {
const cleanup = new Error("independent cleanup failure");
const outcome = await withVerifierCleanup(async () => {
throw primary;
}, [
() => {
throw cleanup;
},
]).then(
(value) => ({ kind: "fulfilled" as const, value }),
(reason: unknown) => ({ kind: "rejected" as const, reason }),
);
if (outcome.kind !== "rejected")
throw new Error("Expected both operation and cleanup failures");
expect(outcome.reason).toBeInstanceOf(AggregateError);
const error = outcome.reason as AggregateError;
expect(error.errors).toEqual([primary, cleanup]);
expect(error.errors[1]).toBe(cleanup);
expect(Object.hasOwn(error, "cause")).toBe(true);
expect(error.cause).toBe(primary);
},
);
it.each([undefined, { observation: "retained value" }])(
"returns the exact operation value after cleanup: %s",
async (value) => {
const attempted: string[] = [];
const result = await withVerifierCleanup(() => {
attempted.push("operation");
return value;
}, [
async () => {
attempted.push("cleanup");
},
]);
expect(result).toBe(value);
expect(attempted).toEqual(["operation", "cleanup"]);
},
);
it("does not repeat cleanup or invent a primary when cleanup alone fails", async () => {
const attempted: string[] = [];
const cleanup = new Error("cleanup after successful observation failed");
const outcome = await withVerifierCleanup(() => {
attempted.push("operation");
return "completed";
}, [
async () => {
attempted.push("provider");
throw cleanup;
},
() => {
attempted.push("fixture");
throw undefined;
},
() => {
attempted.push("independent resource");
},
]).catch((reason: unknown) => reason);
expect(outcome).toBeInstanceOf(AggregateError);
expect((outcome as AggregateError).errors).toEqual([cleanup, undefined]);
expect((outcome as AggregateError).errors[0]).toBe(cleanup);
expect(Object.hasOwn(outcome as AggregateError, "cause")).toBe(false);
expect(attempted).toEqual([
"operation",
"provider",
"fixture",
"independent resource",
]);
});
it("preserves nested aggregates and independent failures with the same identity", async () => {
const shared = new Error("same reason from independent owners");
const primary = new AggregateError([shared], "nested operation failure");
const nested = new AggregateError([undefined, shared], "nested cleanup");
const outcome = await withVerifierCleanup(() => {
throw primary;
}, [
() => {
throw nested;
},
() => {
throw shared;
},
() => {
throw shared;
},
]).catch((reason: unknown) => reason);
expect(outcome).toBeInstanceOf(AggregateError);
const error = outcome as AggregateError;
expect(error.cause).toBe(primary);
expect(error.errors).toEqual([primary, nested, shared, shared]);
expect(error.errors[0]).toBe(primary);
expect(error.errors[1]).toBe(nested);
expect(error.errors[2]).toBe(shared);
expect(error.errors[3]).toBe(shared);
});