Skip to content

Commit 5cf01ac

Browse files
committed
test: keep gateway suites minimal
1 parent e493d1d commit 5cf01ac

7 files changed

Lines changed: 113 additions & 79 deletions

src/gateway/server-runtime-services.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { OpenClawConfig } from "../config/types.openclaw.js";
2+
import { isVitestRuntimeEnv } from "../infra/env.js";
23
import { startHeartbeatRunner, type HeartbeatRunner } from "../infra/heartbeat-runner.js";
34
import type { ChannelHealthMonitor } from "./channel-health-monitor.js";
45
import { startChannelHealthMonitor } from "./channel-health-monitor.js";
@@ -87,7 +88,7 @@ export function startGatewayRuntimeServices(params: {
8788
heartbeatRunner: createNoopHeartbeatRunner(),
8889
channelHealthMonitor,
8990
stopModelPricingRefresh:
90-
!params.minimalTestGateway && process.env.VITEST !== "1"
91+
!params.minimalTestGateway && !isVitestRuntimeEnv()
9192
? startGatewayModelPricingRefresh({ config: params.cfgAtStart })
9293
: () => {},
9394
};

src/gateway/server-runtime-subscriptions.ts

Lines changed: 30 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
} from "./server-session-events.js";
1616

1717
export function startGatewayEventSubscriptions(params: {
18-
minimalTestGateway: boolean;
1918
broadcast: (event: string, payload: unknown, opts?: { dropIfSlow?: boolean }) => void;
2019
broadcastToConnIds: (
2120
event: string,
@@ -33,47 +32,39 @@ export function startGatewayEventSubscriptions(params: {
3332
sessionMessageSubscribers: SessionMessageSubscriberRegistry;
3433
chatAbortControllers: Map<string, unknown>;
3534
}) {
36-
const agentUnsub = params.minimalTestGateway
37-
? null
38-
: onAgentEvent(
39-
createAgentEventHandler({
40-
broadcast: params.broadcast,
41-
broadcastToConnIds: params.broadcastToConnIds,
42-
nodeSendToSession: params.nodeSendToSession,
43-
agentRunSeq: params.agentRunSeq,
44-
chatRunState: params.chatRunState,
45-
resolveSessionKeyForRun: params.resolveSessionKeyForRun,
46-
clearAgentRunContext: params.clearAgentRunContext,
47-
toolEventRecipients: params.toolEventRecipients,
48-
sessionEventSubscribers: params.sessionEventSubscribers,
49-
isChatSendRunActive: (runId) => params.chatAbortControllers.has(runId),
50-
}),
51-
);
35+
const agentUnsub = onAgentEvent(
36+
createAgentEventHandler({
37+
broadcast: params.broadcast,
38+
broadcastToConnIds: params.broadcastToConnIds,
39+
nodeSendToSession: params.nodeSendToSession,
40+
agentRunSeq: params.agentRunSeq,
41+
chatRunState: params.chatRunState,
42+
resolveSessionKeyForRun: params.resolveSessionKeyForRun,
43+
clearAgentRunContext: params.clearAgentRunContext,
44+
toolEventRecipients: params.toolEventRecipients,
45+
sessionEventSubscribers: params.sessionEventSubscribers,
46+
isChatSendRunActive: (runId) => params.chatAbortControllers.has(runId),
47+
}),
48+
);
5249

53-
const heartbeatUnsub = params.minimalTestGateway
54-
? null
55-
: onHeartbeatEvent((evt) => {
56-
params.broadcast("heartbeat", evt, { dropIfSlow: true });
57-
});
50+
const heartbeatUnsub = onHeartbeatEvent((evt) => {
51+
params.broadcast("heartbeat", evt, { dropIfSlow: true });
52+
});
5853

59-
const transcriptUnsub = params.minimalTestGateway
60-
? null
61-
: onSessionTranscriptUpdate(
62-
createTranscriptUpdateBroadcastHandler({
63-
broadcastToConnIds: params.broadcastToConnIds,
64-
sessionEventSubscribers: params.sessionEventSubscribers,
65-
sessionMessageSubscribers: params.sessionMessageSubscribers,
66-
}),
67-
);
54+
const transcriptUnsub = onSessionTranscriptUpdate(
55+
createTranscriptUpdateBroadcastHandler({
56+
broadcastToConnIds: params.broadcastToConnIds,
57+
sessionEventSubscribers: params.sessionEventSubscribers,
58+
sessionMessageSubscribers: params.sessionMessageSubscribers,
59+
}),
60+
);
6861

69-
const lifecycleUnsub = params.minimalTestGateway
70-
? null
71-
: onSessionLifecycleEvent(
72-
createLifecycleEventBroadcastHandler({
73-
broadcastToConnIds: params.broadcastToConnIds,
74-
sessionEventSubscribers: params.sessionEventSubscribers,
75-
}),
76-
);
62+
const lifecycleUnsub = onSessionLifecycleEvent(
63+
createLifecycleEventBroadcastHandler({
64+
broadcastToConnIds: params.broadcastToConnIds,
65+
sessionEventSubscribers: params.sessionEventSubscribers,
66+
}),
67+
);
7768

7869
return {
7970
agentUnsub,

src/gateway/server.auth.control-ui.suite.ts

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -310,33 +310,36 @@ export function registerControlUiAndPairingSuite(): void {
310310
});
311311
});
312312

313-
test("allows localhost control ui without device identity when insecure auth is enabled", async () => {
313+
test("allows localhost ui clients without device identity when insecure auth is enabled", async () => {
314314
testState.gatewayControlUi = { allowInsecureAuth: true };
315-
const { server, ws, prevToken } = await startControlUiServerWithClient("secret", {
315+
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret", {
316316
wsHeaders: { origin: "http://127.0.0.1" },
317317
});
318-
await connectControlUiWithoutDeviceAndExpectOk({ ws, token: "secret" });
319-
ws.close();
320-
await server.close();
321-
restoreGatewayToken(prevToken);
322-
});
318+
let tuiWs: WebSocket | undefined;
319+
try {
320+
await connectControlUiWithoutDeviceAndExpectOk({ ws, token: "secret" });
323321

324-
test("allows localhost tui without device identity when insecure auth is enabled", async () => {
325-
testState.gatewayControlUi = { allowInsecureAuth: true };
326-
const { server, ws, prevToken } = await startControlUiServerWithClient("secret");
327-
await connectControlUiWithoutDeviceAndExpectOk({
328-
ws,
329-
token: "secret",
330-
client: {
331-
id: GATEWAY_CLIENT_NAMES.TUI,
332-
version: "1.0.0",
333-
platform: "darwin",
334-
mode: GATEWAY_CLIENT_MODES.UI,
335-
},
336-
});
337-
ws.close();
338-
await server.close();
339-
restoreGatewayToken(prevToken);
322+
tuiWs = await openWs(port);
323+
await connectControlUiWithoutDeviceAndExpectOk({
324+
ws: tuiWs,
325+
token: "secret",
326+
client: {
327+
id: GATEWAY_CLIENT_NAMES.TUI,
328+
version: "1.0.0",
329+
platform: "darwin",
330+
mode: GATEWAY_CLIENT_MODES.UI,
331+
},
332+
});
333+
} finally {
334+
ws.close();
335+
tuiWs?.close();
336+
await Promise.all([
337+
waitForWsClose(ws, 1_000),
338+
...(tuiWs ? [waitForWsClose(tuiWs, 1_000)] : []),
339+
]);
340+
await server.close();
341+
restoreGatewayToken(prevToken);
342+
}
340343
});
341344

342345
test("allows control ui password-only auth on localhost when insecure auth is enabled", async () => {
@@ -1322,16 +1325,35 @@ export function registerControlUiAndPairingSuite(): void {
13221325
}
13231326
});
13241327

1325-
test("allows local gateway backend shared-auth connections without device pairing", async () => {
1326-
const { server, ws, prevToken } = await startControlUiServerWithClient("secret");
1328+
test("allows gateway backend loopback shared-auth connections without device pairing", async () => {
1329+
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
1330+
const sockets = [ws];
13271331
try {
1328-
const localBackend = await connectReq(ws, {
1329-
token: "secret",
1330-
client: BACKEND_GATEWAY_CLIENT,
1331-
});
1332-
expect(localBackend.ok).toBe(true);
1332+
const backendCases: Array<{
1333+
name: string;
1334+
headers?: Record<string, string>;
1335+
socket?: WebSocket;
1336+
}> = [
1337+
{ name: "default host", socket: ws },
1338+
{ name: "remote-looking host", headers: { host: "gateway.example" } },
1339+
{ name: "private host", headers: { host: "172.17.0.2:18789" } },
1340+
];
1341+
1342+
for (const backendCase of backendCases) {
1343+
const socket = backendCase.socket ?? (await openWs(port, backendCase.headers));
1344+
if (!backendCase.socket) {
1345+
sockets.push(socket);
1346+
}
1347+
const backendConnect = await connectReq(socket, {
1348+
token: "secret",
1349+
client: BACKEND_GATEWAY_CLIENT,
1350+
});
1351+
expect(backendConnect.ok, backendCase.name).toBe(true);
1352+
}
13331353
} finally {
1334-
ws.close();
1354+
for (const socket of sockets) {
1355+
socket.close();
1356+
}
13351357
await server.close();
13361358
restoreGatewayToken(prevToken);
13371359
}

src/gateway/server.impl.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
1818
import { resolveMainSessionKey } from "../config/sessions.js";
1919
import { clearAgentRunContext } from "../infra/agent-events.js";
2020
import { isDiagnosticsEnabled } from "../infra/diagnostic-events.js";
21-
import { logAcceptedEnvOption } from "../infra/env.js";
21+
import { isVitestRuntimeEnv, logAcceptedEnvOption } from "../infra/env.js";
2222
import { ensureOpenClawCliOnPath } from "../infra/path-env.js";
2323
import { setGatewaySigusr1RestartPolicy, setPreRestartDeferralCheck } from "../infra/restart.js";
2424
import { enqueueSystemEvent } from "../infra/system-events.js";
@@ -208,7 +208,7 @@ export async function startGatewayServer(
208208
opts: GatewayServerOptions = {},
209209
): Promise<GatewayServer> {
210210
const minimalTestGateway =
211-
process.env.VITEST === "1" && process.env.OPENCLAW_TEST_MINIMAL_GATEWAY === "1";
211+
isVitestRuntimeEnv() && process.env.OPENCLAW_TEST_MINIMAL_GATEWAY === "1";
212212

213213
// Ensure all default port derivations (browser/canvas) see the actual runtime port.
214214
process.env.OPENCLAW_GATEWAY_PORT = String(port);
@@ -599,7 +599,6 @@ export async function startGatewayServer(
599599
Object.assign(
600600
runtimeState,
601601
startGatewayEventSubscriptions({
602-
minimalTestGateway,
603602
broadcast,
604603
broadcastToConnIds,
605604
nodeSendToSession,

src/gateway/server.models-voicewake-misc.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -542,9 +542,11 @@ describe("gateway server misc", () => {
542542
"utf-8",
543543
);
544544

545-
const autoPort = await getFreePort();
546-
const autoServer = await startGatewayServer(autoPort);
547-
await autoServer.close();
545+
await withEnvAsync({ OPENCLAW_TEST_MINIMAL_GATEWAY: undefined }, async () => {
546+
const autoPort = await getFreePort();
547+
const autoServer = await startGatewayServer(autoPort);
548+
await autoServer.close();
549+
});
548550

549551
const updated = JSON.parse(await fs.readFile(configPath, "utf-8")) as Record<string, unknown>;
550552
const channels = updated.channels as Record<string, unknown> | undefined;

src/gateway/server.reload.test.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
44
import { WebSocket } from "ws";
55
import { resolveMainSessionKeyFromConfig } from "../config/sessions.js";
66
import { drainSystemEvents } from "../infra/system-events.js";
7+
import { withEnvAsync } from "../test-utils/env.js";
78
import {
89
TALK_TEST_PROVIDER_API_KEY_PATH,
910
TALK_TEST_PROVIDER_ID,
@@ -369,8 +370,16 @@ describe("gateway hot reload", () => {
369370
);
370371
}
371372

373+
async function withNonMinimalGatewayServer(
374+
fn: Parameters<typeof withGatewayServer>[0],
375+
): ReturnType<typeof withGatewayServer> {
376+
return await withEnvAsync({ OPENCLAW_TEST_MINIMAL_GATEWAY: undefined }, async () =>
377+
withGatewayServer(fn),
378+
);
379+
}
380+
372381
it("applies hot reload actions and emits restart signal", async () => {
373-
await withGatewayServer(async () => {
382+
await withNonMinimalGatewayServer(async () => {
374383
const onHotReload = hoisted.getOnHotReload();
375384
expect(onHotReload).toBeTypeOf("function");
376385

@@ -473,7 +482,7 @@ describe("gateway hot reload", () => {
473482
await writeEnvRefConfig();
474483
process.env.OPENAI_API_KEY = "sk-startup"; // pragma: allowlist secret
475484

476-
await withGatewayServer(async () => {
485+
await withNonMinimalGatewayServer(async () => {
477486
const onHotReload = hoisted.getOnHotReload();
478487
expect(onHotReload).toBeTypeOf("function");
479488
const sessionKey = resolveMainSessionKeyFromConfig();

src/infra/env.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ export function isTruthyEnvValue(value?: string): boolean {
6767
}
6868
}
6969

70+
export function isVitestRuntimeEnv(env: NodeJS.ProcessEnv = process.env): boolean {
71+
return (
72+
env.VITEST === "true" ||
73+
env.VITEST === "1" ||
74+
env.VITEST_POOL_ID !== undefined ||
75+
env.VITEST_WORKER_ID !== undefined ||
76+
env.NODE_ENV === "test"
77+
);
78+
}
79+
7080
export function normalizeEnv(): void {
7181
normalizeZaiEnv();
7282
}

0 commit comments

Comments
 (0)