




















11import { beforeEach, describe, expect, it, vi } from "vitest";
22import type { OpenClawConfig } from "../config/config.js";
3+import {
4+GATEWAY_HEALTH_CREDENTIALS_REQUIRED_MESSAGE,
5+GATEWAY_HEALTH_CREDENTIALS_REQUIRED_TITLE,
6+} from "./gateway-health-auth-diagnostic.js";
3748const callGateway = vi.hoisted(() => vi.fn());
9+const isGatewayCredentialsRequiredError = vi.hoisted(() => vi.fn(() => false));
10+const probeGatewayStatus = vi.hoisted(() => vi.fn());
511const note = vi.hoisted(() => vi.fn());
12+const TEST_GATEWAY_URL = "ws://127.0.0.1:18789";
13+const TEST_AUTH_CLOSE_ERROR = "gateway closed (1008):";
14+const TEST_TLS_FINGERPRINT = "sha256:test-doctor-gateway-fingerprint";
615716vi.mock("../gateway/call.js", () => ({
817buildGatewayConnectionDetails: vi.fn(() => ({
9-message: "Gateway target: ws://127.0.0.1:18789",
18+message: `Gateway target: ${TEST_GATEWAY_URL}`,
19+url: TEST_GATEWAY_URL,
20+})),
21+buildGatewayProbeConnectionDetails: vi.fn(() => ({
22+preauthHandshakeTimeoutMs: 4321,
23+tlsFingerprint: TEST_TLS_FINGERPRINT,
24+url: TEST_GATEWAY_URL,
1025})),
1126 callGateway,
27+ isGatewayCredentialsRequiredError,
28+}));
29+30+vi.mock("../cli/daemon-cli/probe.js", () => ({
31+ probeGatewayStatus,
1232}));
13331434vi.mock("../../packages/terminal-core/src/note.js", () => ({
@@ -26,6 +46,9 @@ describe("checkGatewayHealth", () => {
26462747beforeEach(() => {
2848callGateway.mockReset();
49+isGatewayCredentialsRequiredError.mockReset();
50+isGatewayCredentialsRequiredError.mockReturnValue(false);
51+probeGatewayStatus.mockReset();
2952note.mockReset();
3053});
3154@@ -35,7 +58,7 @@ describe("checkGatewayHealth", () => {
35583659await expect(
3760checkGatewayHealth({ runtime: runtime as never, cfg, timeoutMs: 3000 }),
38-).resolves.toEqual({ healthOk: true, status: { ok: true } });
61+).resolves.toEqual({ authenticated: true, healthOk: true, status: { ok: true } });
39624063expect(callGateway).toHaveBeenNthCalledWith(1, {
4164method: "status",
@@ -58,7 +81,11 @@ describe("checkGatewayHealth", () => {
58815982await expect(
6083checkGatewayHealth({ runtime: runtime as never, cfg, timeoutMs: 3000 }),
61-).resolves.toEqual({ healthOk: true, status: { runtimeVersion: "2026.4.23" } });
84+).resolves.toEqual({
85+authenticated: true,
86+healthOk: true,
87+status: { runtimeVersion: "2026.4.23" },
88+});
62896390const mismatchNotes = note.mock.calls
6491.filter(([, title]) => title === "OpenClaw version mismatch")
@@ -78,13 +105,43 @@ describe("checkGatewayHealth", () => {
7810579106await expect(
80107checkGatewayHealth({ runtime: runtime as never, cfg, timeoutMs: 3000 }),
81-).resolves.toEqual({ healthOk: false });
108+).resolves.toEqual({ authenticated: false, healthOk: false, status: undefined });
8210983110expect(callGateway).toHaveBeenCalledTimes(1);
84111expect(runtime.error).toHaveBeenCalledWith(
85112expect.stringContaining("gateway timeout after 3000ms"),
86113);
87114});
115+116+it("reports credentials-required when status RPC auth blocks a reachable gateway", async () => {
117+callGateway.mockRejectedValueOnce(new Error());
118+isGatewayCredentialsRequiredError.mockReturnValueOnce(true);
119+probeGatewayStatus.mockResolvedValueOnce({
120+ok: false,
121+kind: "connect",
122+error: TEST_AUTH_CLOSE_ERROR,
123+});
124+const runtime = { log: vi.fn(), error: vi.fn(), exit: vi.fn() };
125+126+await expect(
127+checkGatewayHealth({ runtime: runtime as never, cfg, timeoutMs: 3000 }),
128+).resolves.toEqual({ authenticated: false, healthOk: true });
129+130+expect(probeGatewayStatus).toHaveBeenCalledWith({
131+url: TEST_GATEWAY_URL,
132+timeoutMs: 3000,
133+tlsFingerprint: TEST_TLS_FINGERPRINT,
134+preauthHandshakeTimeoutMs: 4321,
135+config: cfg,
136+json: true,
137+});
138+expect(runtime.error).not.toHaveBeenCalled();
139+expect(note).toHaveBeenCalledWith(
140+GATEWAY_HEALTH_CREDENTIALS_REQUIRED_MESSAGE,
141+GATEWAY_HEALTH_CREDENTIALS_REQUIRED_TITLE,
142+);
143+expect(callGateway).toHaveBeenCalledTimes(1);
144+});
88145});
8914690147describe("probeGatewayMemoryStatus", () => {
@@ -116,7 +173,7 @@ describe("probeGatewayMemoryStatus", () => {
116173// A transport timeout must NOT be treated as a skipped probe. It is a real
117174// diagnostic signal and the renderer should warn for key-optional providers.
118175callGateway.mockRejectedValue(
119-new Error("gateway timeout after 8000ms\nGateway target: ws://127.0.0.1:18789"),
176+new Error(`gateway timeout after 8000ms\nGateway target: ${TEST_GATEWAY_URL}`),
120177);
121178122179const result = await probeGatewayMemoryStatus({ cfg });
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。