test(runner): isolate cancellation timing and portable snapshot paths

Paperclip-Task: rich-acp-production
This commit is contained in:
Dotta committed 2026-09-29 13:12:05 -05:00
1 parent ed3a0df1c1
commit ab0696ae9d
2 files changed
+37 -11

No files matched your search

@@ -1926,9 +1926,15 @@ async function expectOutput(
});
const [exitCode] = await once(child, "exit");
expect(exitCode, stderr).toBe(0);
const normalized = process.platform === "darwin"
? stdout.replace(/\/private\/var\/[^"\s]*\/paperclip-acpx-[^/]+\/0/g, "/proc/self/fd/4")
: stdout;
let normalized = stdout;
if (process.platform === "darwin") {
const snapshotPrefix = join(await realpath(tmpdir()), "paperclip-acpx-")
.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
normalized = stdout.replace(
new RegExp(`${snapshotPrefix}[^/"\\s]+/0(?=[/"])`, "g"),
"/proc/self/fd/4",
);
}
expect(normalized).toBe(expected);
}
@@ -186,14 +186,12 @@ describe("runner semantic MCP bridge", () => {
expect(handler).toHaveBeenCalledTimes(2);
});
it("times out calls and honors MCP cancellation", async () => {
const starts: string[] = [];
it("times out calls", async () => {
const bridge = await startRunnerToolBridge({
tools: [tool("documents.read")],
timeoutMs: 20,
handler: ({ callId, signal }) =>
handler: ({ signal }) =>
new Promise((_resolve, reject) => {
starts.push(callId);
signal.addEventListener(
"abort",
() => reject(new Error("handler aborted")),
@@ -217,15 +215,36 @@ describe("runner semantic MCP bridge", () => {
content: [{ text: "Paperclip tool call timed out" }],
},
});
});
it("honors MCP cancellation after the handler starts", async () => {
let markStarted!: () => void;
const started = new Promise<void>((resolve) => {
markStarted = resolve;
});
const aborted = vi.fn();
const bridge = await startRunnerToolBridge({
tools: [tool("documents.read")],
timeoutMs: 60_000,
handler: ({ signal }) => new Promise((_resolve, reject) => {
signal.addEventListener("abort", () => {
aborted();
reject(new Error("handler aborted"));
}, { once: true });
markStarted();
}),
});
bridges.push(bridge);
const pending = rpc(bridge, {
id: "cancel-me",
method: "tools/call",
params: { name: "documents.read", arguments: {} },
});
await vi.waitFor(() => expect(starts).toContain("cancel-me"), {
interval: 1,
timeout: 15,
});
// Observe request arrival without racing the separate timeout behavior.
// Retain the rejection for the assertion while avoiding an unhandled fetch
// rejection if a failed test closes the bridge before the request arrives.
void pending.catch(() => undefined);
await started;
expect(
(
await rpc(bridge, {
@@ -240,6 +259,7 @@ describe("runner semantic MCP bridge", () => {
content: [{ text: "Paperclip tool call cancelled" }],
},
});
expect(aborted).toHaveBeenCalledOnce();
});
it("preserves successful mutation identity when the result is oversized", async () => {