Files
reverse-engineering-anything/src/process/SharedStartupAttempt.test.ts
T
morluto b655645608 refactor(errors): give caller aborts a typed reason at the adapters (#10633)
* refactor(errors): give caller aborts a typed reason at the adapters

Squashes 908813551f, 87858de4dc (fix(mcp): preserve cancellation reasons in handlers) and fa151dc3f6 (test(server): race handler-entry gates against the triggering tool call) onto main without #10566's pre-squash commits.

* refactor(errors): give owner-initiated aborts a typed reason outside the browser adapters (#10692)

* refactor(errors): give owner-initiated aborts a typed reason outside the browser adapters

* refactor(verify): keep the abort-reason scan receiver-independent

Playwright's route.abort takes a network error code; the one call site now names its default code instead of the guard exempting a variable name.

* refactor(browser): give owner-initiated CDP aborts typed reasons (#10706)

* refactor(browser): give owner-initiated CDP aborts typed reasons

* fix(browser): give the page-side request fetch page-native abort reasons

The request callback runs in the page through page.evaluate and cannot
reach REA's modules. Define its deadline and cleanup reasons as
DOMExceptions inside the callback, and make the test fake evaluate the
callback from its source so module imports are unavailable, as in a page.

* test(process): expect the reader close's typed owner reason

Closing the Darwin run-token reader aborts its compilation with OwnerCancellation.ownerClosed since the owner-abort change in this PR; the boundary test still expected the default DOMException.

* fix(server): report HTTP session replacement and shutdown to pending tools as an owner close
2026-11-15 17:28:05 +08:00

112 lines
3.9 KiB
TypeScript

import { expect, it } from "vitest";
import { createDeferred } from "../../tests/fixtures/binarySession.js";
import { OwnerCancellation } from "../domain/analysisErrorCore.js";
import { SharedStartupAttempt } from "./SharedStartupAttempt.js";
it("keeps shared startup running for an interested peer and returns the departing caller's reason", async () => {
const completed = createDeferred<string>();
const attempt = new SharedStartupAttempt(() => completed.promise);
const controller = new AbortController();
const departing = attempt.wait(controller.signal);
const staying = attempt.wait();
const reason = { caller: "departing" };
controller.abort(reason);
const departed = await departing;
expect(departed).toEqual({ status: "cancelled", reason });
expect(departed.status === "cancelled" ? departed.reason : undefined).toBe(
reason,
);
expect(attempt.signal.aborted).toBe(false);
completed.resolve("ready");
await expect(staying).resolves.toEqual({
status: "completed",
value: "ready",
});
});
it("retains the final cleanup result when all callers cancel together", async () => {
const cleanup = createDeferred<{ cleanupIncomplete: boolean }>();
const attempt = new SharedStartupAttempt(() => cleanup.promise);
const first = new AbortController();
const last = new AbortController();
const waits = [attempt.wait(first.signal), attempt.wait(last.signal)];
const firstReason = new Error("first caller left");
first.abort(firstReason);
last.abort();
await expect(waits[0]).resolves.toEqual({
status: "cancelled",
reason: firstReason,
});
expect(attempt.signal.aborted).toBe(true);
expect(attempt.settled).toBe(false);
const failure = { cleanupIncomplete: true };
cleanup.resolve(failure);
await expect(waits[1]).resolves.toEqual({
status: "stopped",
value: failure,
});
expect(attempt.settled).toBe(true);
});
it("distinguishes provider closure from a caller's cancellation", async () => {
const cleanup = createDeferred<string>();
const attempt = new SharedStartupAttempt(() => cleanup.promise);
const controller = new AbortController();
const waiting = attempt.wait(controller.signal);
attempt.close();
expect(attempt.signal.reason).toBe(OwnerCancellation.startupOwnerClosed);
expect(controller.signal.aborted).toBe(false);
cleanup.resolve("provider stopped");
await expect(waiting).resolves.toEqual({
status: "completed",
value: "provider stopped",
});
});
it("does not lose an unexpected producer rejection after its final caller cancels", async () => {
let reject: ((cause: unknown) => void) | undefined;
const promise = new Promise<never>((_resolve, fail) => {
reject = fail;
});
const attempt = new SharedStartupAttempt(() => promise);
const controller = new AbortController();
const waiting = attempt.wait(controller.signal);
controller.abort();
const cause = new TypeError("Cleanup rejected");
reject?.(cause);
await expect(waiting).rejects.toBe(cause);
});
it.each(["caller", "owner"])(
"preserves %s interruption when owning cancellation and closure occur together",
async (first) => {
const completed = createDeferred<string>();
const controller = new AbortController();
const reason = { caller: "operation owner" };
const attempt = new SharedStartupAttempt(
() => completed.promise,
controller.signal,
);
const waiting = attempt.wait();
if (first === "caller") {
controller.abort(reason);
attempt.close();
} else {
attempt.close();
expect(attempt.signal.aborted).toBe(true);
expect(attempt.signal.reason).toBe(OwnerCancellation.startupOwnerClosed);
controller.abort(reason);
}
expect(attempt.signal.reason).toBe(
first === "caller" ? reason : OwnerCancellation.startupOwnerClosed,
);
expect(attempt.settled).toBe(false);
completed.resolve("finalized");
await expect(waiting).resolves.toEqual({
status: "completed",
value: "finalized",
});
},
);