mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 11:13:21 +00:00
The owned transport is the doctor's only cleanup owner, and Client.close only delegates to it. Close it once and report its typed failure instead of aggregating a duplicate SDK close and clearing that failure after a retry. Pass the filtered caller environment as the launcher's base only, and name the doctor operation in transport cleanup errors. Cover a descendant in its own session, which only the token sweep can reach, and a late cleanup denial that keeps the startup diagnostic and reports the retained run. Bound the fixture descendant's lifetime so a failing run cannot leak it. Document the doctor's process-family ownership and output bound. Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
60 lines
1.9 KiB
TypeScript
60 lines
1.9 KiB
TypeScript
import { resolve } from "node:path";
|
|
|
|
import { expect, it, vi } from "vitest";
|
|
|
|
const cleanupDenial = vi.hoisted(() => ({
|
|
reason: undefined as string | undefined,
|
|
}));
|
|
|
|
// Keep real process-group cleanup, then report the selected denial so the
|
|
// doctor's late cleanup failure is observed without leaking the fixture.
|
|
vi.mock("./process/ProcessOwnership.js", async (importOriginal) => {
|
|
const original =
|
|
await importOriginal<typeof import("./process/ProcessOwnership.js")>();
|
|
return {
|
|
...original,
|
|
cleanupOwnedProcessGroup: async (
|
|
...parameters: Parameters<typeof original.cleanupOwnedProcessGroup>
|
|
) => {
|
|
const released = await original.cleanupOwnedProcessGroup(...parameters);
|
|
return cleanupDenial.reason === undefined
|
|
? released
|
|
: { cleaned: false as const, reason: cleanupDenial.reason };
|
|
},
|
|
};
|
|
});
|
|
|
|
import { runProductionMcpDoctor } from "./mcpDoctor.js";
|
|
|
|
it("keeps the startup diagnostic and reports retained resources when cleanup fails", async () => {
|
|
cleanupDenial.reason = "fixture process group remained alive";
|
|
try {
|
|
const result = await runProductionMcpDoctor({
|
|
command: process.execPath,
|
|
args: [resolve("tests/fixtures/mcpDoctorExit.mjs")],
|
|
cwd: process.cwd(),
|
|
environment: { ...process.env, REA_MCP_DOCTOR_DEADLINE_MS: "5000" },
|
|
});
|
|
|
|
expect(result).toMatchObject({
|
|
healthy: false,
|
|
checks: [
|
|
{ name: "transport", ok: false },
|
|
{
|
|
name: "cleanup",
|
|
ok: false,
|
|
detail: expect.stringMatching(
|
|
/^MCP stdio cleanup failed: Provider mcp-doctor adapter failed during mcp_doctor \(fixture process group remained alive\); retained resources: [0-9a-f-]{36}$/u,
|
|
),
|
|
},
|
|
],
|
|
diagnostics: {
|
|
stderr: "fixture MCP startup exit\n",
|
|
stderr_truncated: false,
|
|
},
|
|
});
|
|
} finally {
|
|
cleanupDenial.reason = undefined;
|
|
}
|
|
});
|