Files
reverse-engineering-anything/tests/boundary/mcp/optionalProviderIsolation.test.ts
T
morluto 60149282fc test: strengthen integration oracles and verification (#8295)
* test: strengthen integration oracles and verification

* test: bound lifecycle gates and strengthen workflow checks

* test: verify complete paged and extracted results

* test: preserve bytecode and cancellation evidence

* test: strengthen retained evidence and fixture cleanup

* test: require cross-projection bridge identities

* test: retain fixture owners through cleanup failures

* test: verify graph examples and project selectors

* test: tighten provider and lifecycle regressions

* test: consolidate hex coverage and bound cutter cleanup

* test: bound subprocess output waits and strengthen graph checks

* test: check mcp recovery and preserve cleanup owners

* test: verify structured mcp argument failures

* test: preserve artifact cleanup and gdb limit evidence

* test: preserve evidence identities and bound provider gates

* test: retain browser and comparison cleanup owners

* test: bound startup and strengthen fixture oracles

* test: bound lifecycle gates and verify recovered evidence

* test: verify public outcomes and lifecycle ownership

* test: assert precise evidence and release lifecycle gates

* test: verify selected facts and bound cleanup waits

* test: check retained evidence and decoded records

* test: verify final reports and retain cleanup ownership

* test: bound reviewed startup gates and retain cleanup

* test: verify PE errors and preserve MCP cleanup

* test: preserve MCP fixture cleanup ownership

* test: release provider gates before late startup
2026-11-01 00:15:28 +08:00

298 lines
10 KiB
TypeScript

import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { McpServer } from "@modelcontextprotocol/server";
import { afterAll, expect, it, onTestFinished, vi } from "vitest";
import { z } from "zod";
import type { BinarySessionPort } from "../../../src/application/binary/BinarySessionPort.js";
import {
loadOptionalObservationProviders,
type OptionalObservationFactories,
} from "../../../src/composition/optionalObservationProviders.js";
import {
TOOL_CONTRACTS,
toolContract,
} from "../../../src/contracts/toolContracts.js";
import { expandToolAvailability } from "../../../src/contracts/toolOutputSchemaPrimitives.js";
import { run } from "../../../src/main.js";
import { createServer } from "../../../src/server/createServer.js";
import { optionalObservationFactories } from "../../fixtures/optionalObservationProviders.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { mcpTest } from "../../support/mcp/mcpFixture.js";
import { createMcpSchemaValidation } from "../../fixtures/mcpSchemaValidation.js";
const schemaValidation = createMcpSchemaValidation();
afterAll(() => schemaValidation.clear());
const failedAdapters = [
["browserObservation", "list_browser_targets", "rea-cdp-browser"],
[
"browserScenarioCapture",
"capture_browser_scenario",
"rea-playwright-browser-scenario",
],
["electronObservation", "list_electron_targets", "rea-cdp-electron"],
[
"electronActiveObservation",
"capture_electron_scenario",
"rea-playwright-electron-active",
],
[
"javascriptRuntimeObservation",
"list_javascript_runtime_targets",
"rea-v8-inspector",
],
] as const;
const boot = async (
factories: OptionalObservationFactories,
configureServer?: (server: McpServer) => void,
) => {
const loaded = await loadOptionalObservationProviders(factories);
let server: McpServer | undefined;
let session: BinarySessionPort | undefined;
let shutdown: (() => Promise<void>) | undefined;
const output: string[] = [];
const exitCodes: number[] = [];
expect(
await run({
env: {},
loadOptionalProviders: async () => loaded,
createServer: (source, options) => {
if (source.kind !== "session")
throw new Error("Expected a session-owned server source");
session = source.session;
// A configured policy cannot hide an actual adapter loading failure.
const created = createServer(source, {
...options,
availabilityPolicy: () => ({
processCaptureEnabled: true,
browserObservationEnabled: true,
browserScenarioEnabled: true,
electronObservationEnabled: true,
electronAutomationEnabled: true,
v8InspectorObservationEnabled: true,
}),
});
configureServer?.(created);
return created;
},
serve: (factory) => {
const created = factory({ era: "legacy" });
if (!(created instanceof McpServer))
throw new Error("Expected the production synchronous MCP factory");
server = created;
return { close: () => Promise.resolve() };
},
registerShutdown: () => () => {},
captureShutdown: (close) => {
shutdown = close;
onTestFinished(close);
},
writeStderr: (message) => output.push(message),
setExitCode: (code) => exitCodes.push(code),
}),
).toBe(0);
expect(output).toEqual([]);
if (server === undefined || session === undefined || shutdown === undefined)
throw new Error("Runtime did not construct the MCP server and session");
expect(exitCodes).toEqual([]);
return { server, session, loaded, shutdown };
};
mcpTest.for(failedAdapters)(
"isolates %s and retains successful peers",
async ([port, operation, providerId], { mcp }) => {
const calls: string[] = [];
const failure = `${port} synthetic import failure`;
const factories = optionalObservationFactories(calls);
const connected = await boot({
...factories,
[port]: async () => {
throw new Error(failure);
},
});
expect(connected.loaded.optionalProviderLoadFailures).toEqual({
[port]: { providerId, reason: failure },
});
for (const [peer] of failedAdapters)
expect(connected.loaded[peer] !== undefined).toBe(peer !== port);
const client = await mcp.connect(
connected.server,
undefined,
schemaValidation,
);
const names = (await client.listTools()).tools.map(({ name }) => name);
expect(new Set(names)).toEqual(
new Set(TOOL_CONTRACTS.map(({ name }) => name)),
);
expect(names).toHaveLength(TOOL_CONTRACTS.length);
const example = toolContract(operation).examples[0];
if (example === undefined)
throw new Error(`Missing example for ${operation}`);
const unavailable = await client.callTool({
name: operation,
arguments: example.input,
});
expect(unavailable.isError).toBe(true);
expect(parseMcpToolError(unavailable)).toMatchObject({
error: {
details: {
provider_id: providerId,
operation,
reason: `Adapter could not load: ${failure}`,
},
},
});
const status = await client.callTool({
name: "binary_session",
arguments: {},
});
const sessionStatus = toolContract("binary_session").outputSchema.parse(
status.structuredContent,
);
const availability = expandToolAvailability(
sessionStatus.result.tool_availability,
);
expect(availability).toEqual(
expect.arrayContaining([
expect.objectContaining({
name: operation,
available: false,
reason: "provider_unavailable",
remediation: expect.stringContaining(failure),
}),
expect.objectContaining({
name: "analyze_javascript_application",
available: true,
}),
expect.objectContaining({
name: "reconcile_javascript_runtime",
available: true,
}),
expect.objectContaining({
name:
port === "electronActiveObservation"
? "list_electron_targets"
: "capture_electron_scenario",
available: true,
}),
]),
);
const healthy =
port === "javascriptRuntimeObservation"
? "list_browser_targets"
: "list_javascript_runtime_targets";
const listed = await client.callTool({
name: healthy,
arguments:
healthy === "list_browser_targets"
? { cdp_endpoint: "http://127.0.0.1:9222" }
: { inspector_endpoint: "http://127.0.0.1:9222" },
});
expect(listed.isError).not.toBe(true);
const evidenceId = z
.object({ evidence_id: z.string() })
.parse(listed.structuredContent).evidence_id;
expect(connected.session.evidenceById(evidenceId)?.operation).toBe(healthy);
expect(calls).toEqual([
port === "javascriptRuntimeObservation" ? "browser" : "runtime",
]);
const reconciled = await client.callTool({
name: "reconcile_javascript_runtime",
arguments: toolContract("reconcile_javascript_runtime").examples[0]
?.input,
});
expect(reconciled.isError).not.toBe(true);
if (
port === "electronObservation" ||
port === "electronActiveObservation"
) {
const directory = await createTestTempDirectory("rea-optional-static-");
await writeFile(
join(directory, "package.json"),
JSON.stringify({ name: "optional-isolation", main: "index.js" }),
);
await writeFile(join(directory, "index.js"), "exports.answer = 42;\n");
const analyzed = await client.callTool({
name: "analyze_javascript_application",
arguments: { input_path: directory, format: "directory" },
});
expect(analyzed.isError).not.toBe(true);
expect(analyzed.structuredContent).toMatchObject({
operation: "analyze_javascript_application",
});
}
const malformed = await client.callTool({
name: operation,
arguments: { unexpected: true },
});
expect(malformed.isError).toBe(true);
expect(parseMcpToolError(malformed)).toMatchObject({
error: {
code: "invalid_request",
category: "invalid_input",
retryable: false,
recovery: { kind: "inspect_input_contract", operation },
details: { operation },
},
});
expect(JSON.stringify(malformed)).not.toContain(failure);
},
);
mcpTest(
"starts with every optional adapter failed and creates fresh connection state",
async ({ mcp }) => {
const failed = async (): Promise<never> => {
throw new Error("all optional adapters unavailable");
};
const first = await boot({
browserObservation: failed,
browserScenarioCapture: failed,
electronObservation: failed,
electronActiveObservation: failed,
javascriptRuntimeObservation: failed,
});
const client = await mcp.connect(first.server, undefined, schemaValidation);
expect((await client.listTools()).tools).toHaveLength(
TOOL_CONTRACTS.length,
);
const status = await client.callTool({
name: "binary_session",
arguments: {},
});
expect(status.isError).not.toBe(true);
const second = await boot(optionalObservationFactories([]));
expect(second.loaded.optionalProviderLoadFailures).toEqual({});
expect(second.session.exportEvidenceBundle().records).toEqual([]);
expect(second.loaded.browserObservation).toBeDefined();
},
);
it("reports a server close failure and retries the runtime owner", async () => {
const failure = new Error("controlled close failure");
let denied = true;
let close: ReturnType<typeof vi.fn> | undefined;
const connected = await boot(optionalObservationFactories([]), (server) => {
const realClose = server.close.bind(server);
close = vi.spyOn(server, "close").mockImplementation(async () => {
if (denied) throw failure;
await realClose();
});
});
try {
await expect(connected.shutdown()).rejects.toMatchObject({
errors: [failure],
});
expect(close).toHaveBeenCalledTimes(1);
denied = false;
await connected.shutdown();
await connected.shutdown();
expect(close).toHaveBeenCalledTimes(2);
} finally {
denied = false;
}
});