
























11import { existsSync, mkdtempSync, readFileSync, rmSync, statSync } from "node:fs";
22import { tmpdir } from "node:os";
33import path from "node:path";
4-import { describe, expect, it } from "vitest";
5-import { createMcpClientTempState } from "../../scripts/e2e/mcp-client-temp-state.js";
4+import { describe, expect, it, vi } from "vitest";
5+import {
6+connectMcpClientWithPairingReconnect,
7+createMcpClientTempState,
8+type McpClientTempState,
9+} from "../../scripts/e2e/mcp-client-temp-state.js";
610711describe("mcp-channels harness", () => {
812it("creates unique client temp state and removes token files on cleanup", () => {
@@ -27,11 +31,69 @@ describe("mcp-channels harness", () => {
2731}
2832});
293330-it("reuses one MCP temp state across the pairing reconnect path", () => {
31-const source = readFileSync("scripts/e2e/mcp-channels-docker-client.ts", "utf8");
34+it("reuses one MCP temp state across the pairing reconnect path", async () => {
35+const tempState = createMcpClientTempState({ gatewayToken: "pairing-token" });
36+const firstHandle = {
37+cleanup: vi.fn(),
38+client: { close: vi.fn(async () => undefined) },
39+transport: { close: vi.fn(async () => undefined) },
40+};
41+const secondHandle = {
42+cleanup: vi.fn(),
43+client: { close: vi.fn(async () => undefined) },
44+transport: { close: vi.fn(async () => undefined) },
45+};
46+const connectCalls: McpClientTempState[] = [];
47+const connect = vi.fn(async (state: McpClientTempState) => {
48+connectCalls.push(state);
49+return connectCalls.length === 1 ? firstHandle : secondHandle;
50+});
325133-expect(source).toContain("const mcpTempState = createMcpClientTempState({ gatewayToken });");
34-expect(source.match(/tempState: mcpTempState/gu)).toHaveLength(2);
35-expect(source).toContain("mcpTempState.cleanup();");
52+try {
53+await expect(
54+connectMcpClientWithPairingReconnect({
55+ connect,
56+maybeApprovePairing: async () => true,
57+ tempState,
58+}),
59+).resolves.toBe(secondHandle);
60+61+expect(connect).toHaveBeenCalledTimes(2);
62+expect(connectCalls).toEqual([tempState, tempState]);
63+expect(firstHandle.client.close).toHaveBeenCalledOnce();
64+expect(firstHandle.transport.close).toHaveBeenCalledOnce();
65+expect(firstHandle.cleanup).toHaveBeenCalledOnce();
66+expect(secondHandle.cleanup).not.toHaveBeenCalled();
67+} finally {
68+tempState.cleanup();
69+}
70+});
71+72+it("cleans up the first MCP client when pairing approval fails", async () => {
73+const tempState = createMcpClientTempState({ gatewayToken: "pairing-token" });
74+const handle = {
75+cleanup: vi.fn(),
76+client: { close: vi.fn(async () => undefined) },
77+transport: { close: vi.fn(async () => undefined) },
78+};
79+const failure = new Error("pairing approval failed");
80+81+try {
82+await expect(
83+connectMcpClientWithPairingReconnect({
84+connect: async () => handle,
85+maybeApprovePairing: async () => {
86+throw failure;
87+},
88+ tempState,
89+}),
90+).rejects.toBe(failure);
91+92+expect(handle.client.close).toHaveBeenCalledOnce();
93+expect(handle.transport.close).toHaveBeenCalledOnce();
94+expect(handle.cleanup).toHaveBeenCalledOnce();
95+} finally {
96+tempState.cleanup();
97+}
3698});
3799});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。