
























@@ -1,41 +1,148 @@
1-import { describe, expect, it } from "vitest";
1+import fs from "node:fs/promises";
2+import { createServer } from "node:http";
3+import type { AddressInfo } from "node:net";
4+import os from "node:os";
5+import path from "node:path";
6+import { afterEach, describe, expect, it } from "vitest";
7+import { type RawData, WebSocketServer } from "ws";
8+import { loadOrCreateDeviceIdentity } from "../infra/device-identity.js";
29import { connectTestGatewayClient } from "./gateway-cli-backend.live-helpers.js";
3-import { getFreePort, installGatewayTestHooks, startGatewayServer } from "./test-helpers.js";
10+import { PROTOCOL_VERSION } from "./protocol/index.js";
4115-const GATEWAY_CONNECT_TIMEOUT_MS = 10_000;
12+const GATEWAY_CONNECT_TIMEOUT_MS = 5_000;
13+const tempRoots: string[] = [];
14+15+async function createTempDeviceIdentity() {
16+const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gateway-connect-"));
17+tempRoots.push(tempRoot);
18+return loadOrCreateDeviceIdentity(path.join(tempRoot, "device.json"));
19+}
20+21+async function startMinimalGatewayServer(params: { token: string }) {
22+const httpServer = createServer();
23+const wss = new WebSocketServer({ server: httpServer });
24+const requests: string[] = [];
25+26+wss.on("connection", (ws) => {
27+ws.send(
28+JSON.stringify({
29+type: "event",
30+event: "connect.challenge",
31+payload: { nonce: "test-nonce" },
32+}),
33+);
34+ws.on("message", (data) => {
35+const frame = JSON.parse(rawWsDataToString(data)) as {
36+type?: string;
37+id?: string;
38+method?: string;
39+params?: { auth?: { token?: string }; device?: { nonce?: string } };
40+};
41+if (frame.type !== "req" || !frame.id) {
42+return;
43+}
44+requests.push(frame.method ?? "");
45+if (frame.method === "connect") {
46+expect(frame.params?.auth?.token).toBe(params.token);
47+expect(frame.params?.device?.nonce).toBe("test-nonce");
48+ws.send(
49+JSON.stringify({
50+type: "res",
51+id: frame.id,
52+ok: true,
53+payload: {
54+type: "hello-ok",
55+protocol: PROTOCOL_VERSION,
56+server: { version: "test", connId: "conn-1" },
57+features: { methods: ["health"], events: ["connect.challenge"] },
58+snapshot: {
59+presence: [],
60+health: { ok: true },
61+stateVersion: { presence: 0, health: 0 },
62+uptimeMs: 0,
63+},
64+policy: {
65+maxPayload: 1,
66+maxBufferedBytes: 1,
67+tickIntervalMs: 60_000,
68+},
69+},
70+}),
71+);
72+return;
73+}
74+if (frame.method === "health") {
75+ws.send(JSON.stringify({ type: "res", id: frame.id, ok: true, payload: { ok: true } }));
76+}
77+});
78+});
79+80+await new Promise<void>((resolve) => httpServer.listen(0, "127.0.0.1", resolve));
81+const address = httpServer.address() as AddressInfo;
82+return {
83+ requests,
84+url: `ws://127.0.0.1:${address.port}`,
85+close: async () => {
86+for (const client of wss.clients) {
87+client.terminate();
88+}
89+await new Promise<void>((resolve, reject) => {
90+wss.close((error) => (error ? reject(error) : resolve()));
91+});
92+await new Promise<void>((resolve, reject) => {
93+httpServer.close((error) => (error ? reject(error) : resolve()));
94+});
95+},
96+};
97+}
98+99+function rawWsDataToString(data: RawData): string {
100+if (typeof data === "string") {
101+return data;
102+}
103+if (Buffer.isBuffer(data)) {
104+return data.toString("utf8");
105+}
106+if (Array.isArray(data)) {
107+return Buffer.concat(data).toString("utf8");
108+}
109+return Buffer.from(data).toString("utf8");
110+}
61117112describe("gateway cli backend connect", () => {
8-installGatewayTestHooks();
113+afterEach(async () => {
114+await Promise.all(
115+tempRoots.splice(0).map((root) => fs.rm(root, { recursive: true, force: true })),
116+);
117+});
911810119it(
11-"connects a same-process test gateway client in minimal mode",
120+"connects a test gateway client through the live helper",
12121async () => {
13122const token = `test-${Date.now()}`;
14-const port = await getFreePort();
15-const server = await startGatewayServer(port, {
16-bind: "loopback",
17-auth: { mode: "token", token },
18-controlUiEnabled: false,
19-});
123+const deviceIdentity = await createTempDeviceIdentity();
124+const server = await startMinimalGatewayServer({ token });
20125let client: Awaited<ReturnType<typeof connectTestGatewayClient>> | undefined;
2112622127try {
23128client = await connectTestGatewayClient({
24-url: `ws://127.0.0.1:${port}`,
129+url: server.url,
25130 token,
26-timeoutMs: 5_000,
27-maxAttemptTimeoutMs: 5_000,
28-requestTimeoutMs: 5_000,
131+ deviceIdentity,
132+timeoutMs: 1_000,
133+maxAttemptTimeoutMs: 1_000,
134+requestTimeoutMs: 1_000,
29135});
30136const health = await client.request("health", undefined, {
31-timeoutMs: 5_000,
137+timeoutMs: 1_000,
32138});
33139expect(health).toMatchObject({
34140ok: true,
35141});
142+expect(server.requests).toEqual(["connect", "health"]);
36143} finally {
37144await client?.stopAndWait({ timeoutMs: 1_000 }).catch(() => {});
38-await server.close({ reason: "gateway connect regression complete" });
145+await server.close();
39146}
40147},
41148GATEWAY_CONNECT_TIMEOUT_MS,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。