mirror of
https://github.com/openclaw/openclaw.git
synced 2026-11-01 13:09:17 +00:00
* test(ci): deslop u0310 tests * test(scripts): deslop u0311 tests * test(scripts): deslop u0312 tests * test(ci): deslop u0309 tests Consolidate shared CI admission, failure-monitoring, diagnostic, and timing scenarios into parameterized cases. Remove redundant path inventories, alias variants, and status cross-products while retaining authority boundaries and recent regressions. Declarations: 90 to 63. Executed cases: 291 to 220. Test LOC including the preceding fixture fix: 3060 to 2888. Testbox tests and check-changed pass; coverage remains 2981 statements, 2884 branches, and 716 functions with no per-file drops. * test(scripts): deslop u0313 tests * test(scripts): deslop u0307 tests * test(ci): deslop u0308 tests * test(scripts): deslop u0314 tests * test(scripts): deslop u0316 tests * test(scripts): deslop u0305 tests * test(scripts): retain distinct campaign regression contracts
92 lines
3 KiB
TypeScript
92 lines
3 KiB
TypeScript
import { expect, it } from "vitest";
|
|
import {
|
|
isCommandCancellation,
|
|
runCancelableCommand,
|
|
} from "../../scripts/lib/cancelable-command.mts";
|
|
import { createDeferred } from "../helpers/promise.js";
|
|
|
|
it.each([
|
|
["SIGINT", 130, "joined"],
|
|
["SIGINT", 130, "abort"],
|
|
["SIGINT", 130, "release failure"],
|
|
["SIGINT", 130, "unjoined"],
|
|
["SIGTERM", 143, "joined"],
|
|
["SIGHUP", 129, "joined"],
|
|
] as const)("owns %s with exit code %s through %s cleanup", async (signal, exitCode, outcome) => {
|
|
const previous = process.listeners(signal);
|
|
const release = createDeferred();
|
|
const failure = Object.assign(
|
|
new Error("cleanup failed", {
|
|
cause: outcome === "unjoined" ? { processTreeState: "indeterminate" } : undefined,
|
|
}),
|
|
{ code: outcome === "unjoined" ? "ABORT_ERR" : "EIO" },
|
|
);
|
|
let aborted = false;
|
|
let settled = false;
|
|
const command = runCancelableCommand(async (abortSignal) => {
|
|
abortSignal.addEventListener(
|
|
"abort",
|
|
() => {
|
|
aborted = true;
|
|
},
|
|
{ once: true },
|
|
);
|
|
await release.promise;
|
|
if (outcome === "abort") {
|
|
abortSignal.throwIfAborted();
|
|
}
|
|
if (outcome === "release failure" || outcome === "unjoined") {
|
|
throw failure;
|
|
}
|
|
return 7;
|
|
});
|
|
const result = command
|
|
.then(
|
|
(value) => ({ value }),
|
|
(error: unknown) => ({ error }),
|
|
)
|
|
.finally(() => {
|
|
settled = true;
|
|
});
|
|
try {
|
|
// Invoke only this operation's listener; never signal the shared test process.
|
|
const handler = process.listeners(signal).find((entry) => !previous.includes(entry))!;
|
|
handler(signal);
|
|
// The leaf sees the original signal before generic abort; ownership stays
|
|
// pending for arbitrary asynchronous cleanup, without a second grace timer.
|
|
expect(aborted).toBe(false);
|
|
await Promise.resolve();
|
|
expect(aborted).toBe(true);
|
|
expect(settled).toBe(false);
|
|
expect(process.listeners(signal)).toContain(handler);
|
|
release.resolve();
|
|
expect(await result).toEqual(
|
|
outcome === "release failure" || outcome === "unjoined"
|
|
? { error: failure }
|
|
: { value: exitCode },
|
|
);
|
|
expect(process.listeners(signal)).toEqual(previous);
|
|
} finally {
|
|
release.resolve();
|
|
await result;
|
|
}
|
|
});
|
|
|
|
it("preserves an ordinary result and an unsolicited cancellation error", async () => {
|
|
expect(await runCancelableCommand(async () => 7)).toBe(7);
|
|
const failure = Object.assign(new Error("external cancellation"), { code: "ABORT_ERR" });
|
|
await expect(
|
|
runCancelableCommand(async () => {
|
|
throw failure;
|
|
}),
|
|
).rejects.toBe(failure);
|
|
});
|
|
|
|
it("does not turn nested uncertain cleanup into successful cancellation", () => {
|
|
const failure = Object.assign(new Error("cancelled"), {
|
|
code: "ABORT_ERR",
|
|
errors: [new Error("cleanup", { cause: { processTreeState: "live" } })],
|
|
});
|
|
expect(isCommandCancellation(failure)).toBe(false);
|
|
expect(isCommandCancellation(new DOMException("cancelled", "AbortError"))).toBe(true);
|
|
});
|