Files
rea/tests/boundary/mcp/nativeUiFinalizationMcp.test.ts
T
morluto d1adc60795 test(contracts): align plist and UI finalization regressions
Update public-boundary expectations after the explicit XML unknown-scalar
and native UI deadline provenance changes. Retain raw malformed literals,
independent exact integers, expanded-year ISO dates, and partial UI reports.
Assert successful cleanup releases its lease and failed cleanup retains it
until close retries. Keep malformed-input and true date-range coverage.

The shared number fixture owns CLI/filesystem/MCP expectations. Native
plutil controls confirm integer entities are invalid plist literals, even
though they are valid XML. No runtime behavior or CI gates change.

Validation: 187 source cases, 138 focused public cases, final 97-case
rerun after fixture typing/group changes, full static/architecture checks,
and test discovery (1591 files).
2026-10-19 06:22:32 +08:00

116 lines
4.0 KiB
TypeScript

import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import { expect, it, vi } from "vitest";
import { AnalysisCleanupLease } from "../../../src/artifacts/AnalysisCleanupLease.js";
import * as runtimes from "../../../src/native/NativeUiHelperRuntime.js";
import { NativeMacOSProvider } from "../../../src/native/NativeMacOSProvider.js";
import { createServer } from "../../../src/server/createServer.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import { NativeFixtureRunner } from "../../fixtures/nativeCommands.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
it.each([false, true])(
"retains native UI reports over MCP when its deadline expires during close (cleanup fails: %s)",
async (fails) => {
const directory = await createTestTempDirectory("rea-native-ui-mcp-");
const path = join(directory, "Inert");
const header = Buffer.alloc(32);
header.writeUInt32LE(0xfeedfacf, 0);
header.writeUInt32LE(0x0100000c, 4);
header.writeUInt32LE(2, 12);
await writeFile(path, header);
const snapshot = {
window: {
pid: 123,
window_id: 456,
executable: path,
launch_time: 1,
title: "Fixture",
},
nodes: [],
screenshot: null,
gaps: [],
truncated: false,
};
const deadline = new AbortController();
let allowClose = !fails;
const cleanupLease = new AnalysisCleanupLease(async () => {
deadline.abort({ phase: "mcp-owned-finalization-deadline" });
if (!allowClose) throw new Error("controlled cleanup failure");
});
const runtime = {
signal: deadline.signal,
cleanupLease,
invoke: async () => ({ ok: true, result: snapshot }),
close: () => cleanupLease.release(),
resources: () => (cleanupLease.released ? [] : ["controlled-ui-runtime"]),
};
const factory = vi
.spyOn(runtimes, "createNativeUiHelperRuntime")
.mockReturnValue(runtime);
const session = createTestBinarySession(
new NativeMacOSProvider({}, new NativeFixtureRunner(), "darwin"),
);
const server = createServer({ kind: "session", session });
const client = new Client({ name: "native-ui-finalization", version: "1" });
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
try {
await server.connect(serverTransport);
await client.connect(clientTransport);
const opened = await client.callTool({
name: "open_binary",
arguments: { path },
});
expect(opened.isError).not.toBe(true);
const result = await client.callTool({
name: "observe_native_ui",
arguments: {
pid: 123,
window_id: 456,
screenshot: false,
accessibility: true,
},
});
expect(parseMcpToolError(result)).toMatchObject({
error: {
code: fails ? "cleanup_incomplete" : "provider_timeout",
details: {
...(fails
? {
cleanup: "incomplete",
execution_failure: "execution_failure",
diagnostics: {
primary_error: { code: "provider_timeout" },
},
resources: ["controlled-ui-runtime"],
}
: {}),
partial_observation: {
initial: snapshot,
steps: [],
restore: "leave-as-is",
},
},
},
});
expect(cleanupLease.released).toBe(!fails);
allowClose = true;
const closed = await client.callTool({
name: "close_binary",
arguments: {},
});
expect(closed.isError).not.toBe(true);
expect(cleanupLease.released).toBe(true);
} finally {
allowClose = true;
await session.close();
await client.close();
await server.close();
factory.mockRestore();
}
},
);