mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
72ba1cd92b
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.
218 lines
6.4 KiB
TypeScript
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);
|
|
});
|