From 2ceafbafccae0de8a13d2b4213b292dcaf11e894 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 7 Apr 2026 08:31:33 +0100 Subject: [PATCH] test(gateway): cover minimal connect startup --- .../gateway-cli-backend.connect.test.ts | 98 +++++++++++++++++++ .../gateway-cli-backend.live-helpers.test.ts | 8 ++ .../gateway-cli-backend.live-helpers.ts | 9 ++ 3 files changed, 115 insertions(+) create mode 100644 src/gateway/gateway-cli-backend.connect.test.ts diff --git a/src/gateway/gateway-cli-backend.connect.test.ts b/src/gateway/gateway-cli-backend.connect.test.ts new file mode 100644 index 00000000000..2e3b49a4d8d --- /dev/null +++ b/src/gateway/gateway-cli-backend.connect.test.ts @@ -0,0 +1,98 @@ +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { afterEach, describe, expect, it } from "vitest"; +import { clearConfigCache, clearRuntimeConfigSnapshot } from "../config/config.js"; +import { clearSessionStoreCacheForTest } from "../config/sessions/store.js"; +import { captureEnv } from "../test-utils/env.js"; +import { + connectTestGatewayClient, + ensurePairedTestGatewayClientIdentity, + getFreeGatewayPort, +} from "./gateway-cli-backend.live-helpers.js"; +import { startGatewayServer } from "./server.js"; + +const GATEWAY_CONNECT_TIMEOUT_MS = 90_000; + +describe("gateway cli backend connect", () => { + afterEach(() => { + clearRuntimeConfigSnapshot(); + clearConfigCache(); + clearSessionStoreCacheForTest(); + }); + + it( + "connects a same-process test gateway client in minimal mode", + async () => { + const envSnapshot = captureEnv([ + "HOME", + "OPENCLAW_STATE_DIR", + "OPENCLAW_CONFIG_PATH", + "OPENCLAW_GATEWAY_TOKEN", + "OPENCLAW_SKIP_CHANNELS", + "OPENCLAW_SKIP_PROVIDERS", + "OPENCLAW_SKIP_GMAIL_WATCHER", + "OPENCLAW_SKIP_CRON", + "OPENCLAW_SKIP_CANVAS_HOST", + "OPENCLAW_SKIP_BROWSER_CONTROL_SERVER", + "OPENCLAW_BUNDLED_PLUGINS_DIR", + "OPENCLAW_TEST_MINIMAL_GATEWAY", + ]); + + const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gateway-connect-home-")); + const configPath = path.join(tempHome, ".openclaw", "openclaw.json"); + const bundledPluginsDir = path.join(tempHome, "openclaw-test-no-bundled-extensions"); + const token = `test-${Date.now()}`; + process.env.HOME = tempHome; + process.env.OPENCLAW_STATE_DIR = path.join(tempHome, ".openclaw"); + process.env.OPENCLAW_CONFIG_PATH = configPath; + process.env.OPENCLAW_GATEWAY_TOKEN = token; + process.env.OPENCLAW_SKIP_CHANNELS = "1"; + process.env.OPENCLAW_SKIP_PROVIDERS = "1"; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; + process.env.OPENCLAW_SKIP_CRON = "1"; + process.env.OPENCLAW_SKIP_CANVAS_HOST = "1"; + process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = "1"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledPluginsDir; + process.env.OPENCLAW_TEST_MINIMAL_GATEWAY = "1"; + await fs.mkdir(path.dirname(configPath), { recursive: true }); + await fs.mkdir(bundledPluginsDir, { recursive: true }); + await fs.writeFile( + configPath, + `${JSON.stringify({ gateway: { auth: { mode: "token", token } } }, null, 2)}\n`, + ); + clearRuntimeConfigSnapshot(); + clearConfigCache(); + clearSessionStoreCacheForTest(); + + const deviceIdentity = await ensurePairedTestGatewayClientIdentity(); + const port = await getFreeGatewayPort(); + const server = await startGatewayServer(port, { + bind: "loopback", + auth: { mode: "token", token }, + controlUiEnabled: false, + }); + let client: Awaited> | undefined; + + try { + client = await connectTestGatewayClient({ + url: `ws://127.0.0.1:${port}`, + token, + deviceIdentity, + }); + const health = await client.request<{ ok?: boolean }>("health", undefined, { + timeoutMs: 5_000, + }); + expect(health).toMatchObject({ + ok: true, + }); + } finally { + await client?.stopAndWait({ timeoutMs: 1_000 }).catch(() => {}); + await server.close({ reason: "gateway connect regression complete" }); + await fs.rm(tempHome, { recursive: true, force: true }); + envSnapshot.restore(); + } + }, + GATEWAY_CONNECT_TIMEOUT_MS, + ); +}); diff --git a/src/gateway/gateway-cli-backend.live-helpers.test.ts b/src/gateway/gateway-cli-backend.live-helpers.test.ts index 5e762bd0f32..e0487d007d5 100644 --- a/src/gateway/gateway-cli-backend.live-helpers.test.ts +++ b/src/gateway/gateway-cli-backend.live-helpers.test.ts @@ -26,10 +26,12 @@ describe("gateway cli backend live helpers", () => { afterEach(() => { gatewayClientState.lastOptions = undefined; delete process.env.OPENCLAW_SKIP_CHANNELS; + delete process.env.OPENCLAW_SKIP_PROVIDERS; delete process.env.OPENCLAW_SKIP_GMAIL_WATCHER; delete process.env.OPENCLAW_SKIP_CRON; delete process.env.OPENCLAW_SKIP_CANVAS_HOST; delete process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER; + delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR; delete process.env.OPENCLAW_TEST_MINIMAL_GATEWAY; delete process.env.ANTHROPIC_API_KEY; delete process.env.ANTHROPIC_API_KEY_OLD; @@ -40,10 +42,12 @@ describe("gateway cli backend live helpers", () => { await import("./gateway-cli-backend.live-helpers.js"); process.env.OPENCLAW_SKIP_CHANNELS = "old-channels"; + process.env.OPENCLAW_SKIP_PROVIDERS = "old-providers"; process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "old-gmail"; process.env.OPENCLAW_SKIP_CRON = "old-cron"; process.env.OPENCLAW_SKIP_CANVAS_HOST = "old-canvas"; process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = "old-browser"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "old-bundled"; process.env.OPENCLAW_TEST_MINIMAL_GATEWAY = "old-minimal"; process.env.ANTHROPIC_API_KEY = "old-anthropic"; process.env.ANTHROPIC_API_KEY_OLD = "old-anthropic-old"; @@ -52,10 +56,12 @@ describe("gateway cli backend live helpers", () => { applyCliBackendLiveEnv(new Set()); expect(process.env.OPENCLAW_SKIP_CHANNELS).toBe("1"); + expect(process.env.OPENCLAW_SKIP_PROVIDERS).toBe("1"); expect(process.env.OPENCLAW_SKIP_GMAIL_WATCHER).toBe("1"); expect(process.env.OPENCLAW_SKIP_CRON).toBe("1"); expect(process.env.OPENCLAW_SKIP_CANVAS_HOST).toBe("1"); expect(process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER).toBe("1"); + expect(process.env.OPENCLAW_BUNDLED_PLUGINS_DIR).toBe("old-bundled"); expect(process.env.OPENCLAW_TEST_MINIMAL_GATEWAY).toBe("1"); expect(process.env.ANTHROPIC_API_KEY).toBeUndefined(); expect(process.env.ANTHROPIC_API_KEY_OLD).toBeUndefined(); @@ -63,10 +69,12 @@ describe("gateway cli backend live helpers", () => { restoreCliBackendLiveEnv(snapshot); expect(process.env.OPENCLAW_SKIP_CHANNELS).toBe("old-channels"); + expect(process.env.OPENCLAW_SKIP_PROVIDERS).toBe("old-providers"); expect(process.env.OPENCLAW_SKIP_GMAIL_WATCHER).toBe("old-gmail"); expect(process.env.OPENCLAW_SKIP_CRON).toBe("old-cron"); expect(process.env.OPENCLAW_SKIP_CANVAS_HOST).toBe("old-canvas"); expect(process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER).toBe("old-browser"); + expect(process.env.OPENCLAW_BUNDLED_PLUGINS_DIR).toBe("old-bundled"); expect(process.env.OPENCLAW_TEST_MINIMAL_GATEWAY).toBe("old-minimal"); expect(process.env.ANTHROPIC_API_KEY).toBe("old-anthropic"); expect(process.env.ANTHROPIC_API_KEY_OLD).toBe("old-anthropic-old"); diff --git a/src/gateway/gateway-cli-backend.live-helpers.ts b/src/gateway/gateway-cli-backend.live-helpers.ts index 054484dbae7..a3e10f78d04 100644 --- a/src/gateway/gateway-cli-backend.live-helpers.ts +++ b/src/gateway/gateway-cli-backend.live-helpers.ts @@ -96,10 +96,12 @@ export type CliBackendLiveEnvSnapshot = { stateDir?: string; token?: string; skipChannels?: string; + skipProviders?: string; skipGmail?: string; skipCron?: string; skipCanvas?: string; skipBrowserControl?: string; + bundledPluginsDir?: string; minimalGateway?: string; anthropicApiKey?: string; anthropicApiKeyOld?: string; @@ -338,10 +340,12 @@ export function snapshotCliBackendLiveEnv(): CliBackendLiveEnvSnapshot { stateDir: process.env.OPENCLAW_STATE_DIR, token: process.env.OPENCLAW_GATEWAY_TOKEN, skipChannels: process.env.OPENCLAW_SKIP_CHANNELS, + skipProviders: process.env.OPENCLAW_SKIP_PROVIDERS, skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER, skipCron: process.env.OPENCLAW_SKIP_CRON, skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST, skipBrowserControl: process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER, + bundledPluginsDir: process.env.OPENCLAW_BUNDLED_PLUGINS_DIR, minimalGateway: process.env.OPENCLAW_TEST_MINIMAL_GATEWAY, anthropicApiKey: process.env.ANTHROPIC_API_KEY, anthropicApiKeyOld: process.env.ANTHROPIC_API_KEY_OLD, @@ -350,10 +354,13 @@ export function snapshotCliBackendLiveEnv(): CliBackendLiveEnvSnapshot { export function applyCliBackendLiveEnv(preservedEnv: ReadonlySet): void { process.env.OPENCLAW_SKIP_CHANNELS = "1"; + process.env.OPENCLAW_SKIP_PROVIDERS = "1"; process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; process.env.OPENCLAW_SKIP_CRON = "1"; process.env.OPENCLAW_SKIP_CANVAS_HOST = "1"; process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = "1"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR ?? "openclaw-live-test-no-bundled-extensions"; process.env.OPENCLAW_TEST_MINIMAL_GATEWAY = "1"; if (!preservedEnv.has("ANTHROPIC_API_KEY")) { delete process.env.ANTHROPIC_API_KEY; @@ -368,10 +375,12 @@ export function restoreCliBackendLiveEnv(snapshot: CliBackendLiveEnvSnapshot): v restoreEnvVar("OPENCLAW_STATE_DIR", snapshot.stateDir); restoreEnvVar("OPENCLAW_GATEWAY_TOKEN", snapshot.token); restoreEnvVar("OPENCLAW_SKIP_CHANNELS", snapshot.skipChannels); + restoreEnvVar("OPENCLAW_SKIP_PROVIDERS", snapshot.skipProviders); restoreEnvVar("OPENCLAW_SKIP_GMAIL_WATCHER", snapshot.skipGmail); restoreEnvVar("OPENCLAW_SKIP_CRON", snapshot.skipCron); restoreEnvVar("OPENCLAW_SKIP_CANVAS_HOST", snapshot.skipCanvas); restoreEnvVar("OPENCLAW_SKIP_BROWSER_CONTROL_SERVER", snapshot.skipBrowserControl); + restoreEnvVar("OPENCLAW_BUNDLED_PLUGINS_DIR", snapshot.bundledPluginsDir); restoreEnvVar("OPENCLAW_TEST_MINIMAL_GATEWAY", snapshot.minimalGateway); restoreEnvVar("ANTHROPIC_API_KEY", snapshot.anthropicApiKey); restoreEnvVar("ANTHROPIC_API_KEY_OLD", snapshot.anthropicApiKeyOld);