Files
OmniRoute/tests/unit/executor-devin-cli-12517-double-close.test.ts
Diego Rodrigues de Sa e Souza 0bdbe48de2 fix(providers): stop devin-cli spawn error from double-closing SSE controller (#12517) (#13261)
Merged as part of the 39-PR owner batch of 2026-09-11, validated as a unit.

Boarded into one consolidated worktree cut from `release/v3.8.51` with the other 38 — zero conflicts between them.

- ESLint over every changed file: no errors (the only finding was one suppression entry the batch emptied, pruned on #13243)
- `typecheck:core` clean; `check:dashboard-typecheck` OK (206 pre-existing, within baseline); `check:changelog-integrity` OK
- complexity 2821 / baseline 3218 and cognitive-complexity 1272 / baseline 1437 — both under baseline
- 256 assertions green: 246 under node:test and 10 under vitest, which is where `tests/unit/**/*.test.tsx` actually runs
- `check-file-size`: `chatCore.ts` rebaselined 6144 → 6146 for #13278 and #13276, annotated and landed on #13243

⚠️ base-red inherited: #12732 — the provider count (356 in the docs vs the 358 the modules define) and `open-sse/utils/stream.ts` at 3115 > frozen 3098 both reproduce on the pure tip with zero contribution from this batch.
2026-09-11 22:06:26 -03:00

56 lines
1.9 KiB
TypeScript

import { describe, it, after } from "node:test";
import assert from "node:assert/strict";
const mod = await import("../../open-sse/executors/devin-cli.ts");
describe("DevinCliExecutor — #12517 spawn error must not double-close SSE controller", () => {
it("surfaces a sanitized SSE error and never fires uncaughtException on ENOENT spawn", async () => {
const previousBin = process.env.CLI_DEVIN_BIN;
process.env.CLI_DEVIN_BIN = "/nonexistent/absolute/path/to/devin-bin-12517";
let caught: unknown = null;
const onUncaught = (err: unknown) => {
caught = err;
};
process.on("uncaughtException", onUncaught);
try {
const executor = new mod.DevinCliExecutor();
const { response } = await executor.execute({
model: "devin-cli",
body: { messages: [{ role: "user", content: "hi" }] },
stream: true,
credentials: {},
signal: undefined,
log: undefined,
} as never);
const reader = response.body!.getReader();
const decoder = new TextDecoder();
let payload = "";
for (;;) {
const { done, value } = await reader.read();
if (done) break;
payload += decoder.decode(value);
}
assert.match(payload, /Devin CLI not found/);
assert.match(payload, /data: \[DONE\]/);
// Give the child's async "close" event (which fires after "error" for a
// failed spawn) room to run before asserting no uncaughtException fired.
await new Promise((resolve) => setTimeout(resolve, 300));
assert.equal(caught, null, `expected no uncaughtException, got: ${String(caught)}`);
} finally {
process.removeListener("uncaughtException", onUncaught);
if (previousBin === undefined) delete process.env.CLI_DEVIN_BIN;
else process.env.CLI_DEVIN_BIN = previousBin;
}
});
after(() => {
delete process.env.CLI_DEVIN_BIN;
});
});