Files
OmniRoute/tests/unit/chatcore-telemetry-helpers.test.ts
Septianata Rizky Pratama 45310f202d fix: auto-start WS server in-process and change default port to 20132 (#6072)
* feat: change default LIVE_WS_PORT from 20129 to 20132

Update the default WebSocket port for the live dashboard server from 20129 to 20132 across all configuration files, documentation, code comments, and tests. Also consolidate OMNIROUTE_DISABLE_LIVE_WS and OMNIROUTE_ENABLE_LIVE_WS into a single OMNIROUTE_ENABLE_LIVE_WS flag. Wire the live WebSocket server to start in-process via instrumentation-node.ts.

* feat: clarify NEXT_PUBLIC_LIVE_WS_PUBLIC_URL path usage and derive upgrade path from URL

Update .env.example and ENVIRONMENT.md to document that the pathname portion of NEXT_PUBLIC_LIVE_WS_PUBLIC_URL (e.g. /live-ws) is used as the WebSocket upgrade path by the dev proxy, handshake response, and client connection logic.

Extract deriveLiveWsPath() into shared/utils/wsPath.ts and wire it through:
- src/app/api/v1/ws/route.ts — handshake response path field
- src/hooks/useLiveDashboard.ts — build

* fix: use the standard URL API to safely parse and update the effectiveWsUrl

* build(docker): expose live WebSocket server port and configure CORS origins

Add LIVE_WS_PORT (20132), LIVE_WS_HOST (0.0.0.0), and LIVE_WS_ALLOWED_ORIGINS environment variables to all Docker Compose profiles and expose the WebSocket port mapping. Prevent infinite self-loop in standalone-server-ws.mjs by skipping proxy when the server itself is running on the LiveWS port.

* docs(env): fix comment formatting for HOST and HOSTNAME variables

---------

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-11 01:01:27 -03:00

173 lines
5.9 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// Isolated DATA_DIR set BEFORE importing anything that may touch the DB
// (maybeSyncClaudeExtraUsageState -> fetchLiveProviderLimits -> getProviderConnectionById).
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-telemetry-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const { forwardDashboardEventToLiveWs, maybeSyncClaudeExtraUsageState } =
await import("../../open-sse/handlers/chatCore/telemetryHelpers.ts");
const core = await import("../../src/lib/db/core.ts");
const originalFetch = globalThis.fetch;
const originalLiveWsPort = process.env.LIVE_WS_PORT;
test.afterEach(() => {
globalThis.fetch = originalFetch;
if (originalLiveWsPort === undefined) {
delete process.env.LIVE_WS_PORT;
} else {
process.env.LIVE_WS_PORT = originalLiveWsPort;
}
});
test.after(() => {
globalThis.fetch = originalFetch;
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
// ─── forwardDashboardEventToLiveWs ───────────────────────────────────────────
test("forwardDashboardEventToLiveWs POSTs event+payload+timestamp as JSON to the default port", async () => {
delete process.env.LIVE_WS_PORT;
let capturedUrl: string | undefined;
let capturedInit: RequestInit | undefined;
globalThis.fetch = (async (url: string, init: RequestInit) => {
capturedUrl = url;
capturedInit = init;
return new Response("ok", { status: 200 });
}) as typeof fetch;
const before = Date.now();
await forwardDashboardEventToLiveWs("my-event", { foo: "bar" });
const after = Date.now();
// Default port is 20132 when LIVE_WS_PORT is unset.
assert.equal(capturedUrl, "http://127.0.0.1:20132/__omniroute_event");
assert.equal(capturedInit?.method, "POST");
assert.equal(
(capturedInit?.headers as Record<string, string>)["content-type"],
"application/json"
);
assert.ok(capturedInit?.signal, "an AbortSignal is attached for the 1.5s timeout");
const parsed = JSON.parse(capturedInit?.body as string);
assert.equal(parsed.event, "my-event");
assert.deepEqual(parsed.payload, { foo: "bar" });
assert.equal(typeof parsed.timestamp, "number");
assert.ok(
parsed.timestamp >= before && parsed.timestamp <= after,
"timestamp is Date.now() captured at call time"
);
});
test("forwardDashboardEventToLiveWs honors LIVE_WS_PORT override", async () => {
process.env.LIVE_WS_PORT = "31337";
let capturedUrl: string | undefined;
globalThis.fetch = (async (url: string) => {
capturedUrl = url;
return new Response("ok", { status: 200 });
}) as typeof fetch;
await forwardDashboardEventToLiveWs("e", null);
assert.equal(capturedUrl, "http://127.0.0.1:31337/__omniroute_event");
});
test("forwardDashboardEventToLiveWs swallows fetch rejection and still resolves", async () => {
globalThis.fetch = (async () => {
throw new Error("sidecar down");
}) as typeof fetch;
// Must not throw — best-effort sidecar bridge; the catch swallows.
await assert.doesNotReject(forwardDashboardEventToLiveWs("e", { a: 1 }));
});
// ─── maybeSyncClaudeExtraUsageState ──────────────────────────────────────────
test("maybeSyncClaudeExtraUsageState returns early when connectionId is falsy (no fetch)", async () => {
let fetchCalled = false;
globalThis.fetch = (async () => {
fetchCalled = true;
return new Response("", { status: 200 });
}) as typeof fetch;
await maybeSyncClaudeExtraUsageState({
provider: "claude",
connectionId: null,
providerSpecificData: {},
log: null,
});
assert.equal(fetchCalled, false, "guard short-circuits before any network/DB work");
});
test("maybeSyncClaudeExtraUsageState returns early for non-claude provider (block disabled)", async () => {
let fetchCalled = false;
globalThis.fetch = (async () => {
fetchCalled = true;
return new Response("", { status: 200 });
}) as typeof fetch;
await maybeSyncClaudeExtraUsageState({
provider: "openai",
connectionId: "some-conn",
providerSpecificData: {},
log: null,
});
assert.equal(fetchCalled, false, "isClaudeExtraUsageBlockEnabled is false for non-claude");
});
test("maybeSyncClaudeExtraUsageState returns early for claude with blockExtraUsage:false", async () => {
let fetchCalled = false;
globalThis.fetch = (async () => {
fetchCalled = true;
return new Response("", { status: 200 });
}) as typeof fetch;
await maybeSyncClaudeExtraUsageState({
provider: "claude",
connectionId: "some-conn",
providerSpecificData: { blockExtraUsage: false },
log: null,
});
assert.equal(fetchCalled, false, "explicit blockExtraUsage:false disables the block");
});
test("maybeSyncClaudeExtraUsageState enters the try for claude+enabled, swallows the error, and logs via log.debug", async () => {
// provider=claude, providerSpecificData={} (blockExtraUsage !== false), connectionId set
// -> passes the guard -> calls the REAL fetchLiveProviderLimits("bogus-conn") which
// looks the connection up in the (empty) DB, finds nothing, throws "Connection not found",
// and the function's internal try/catch swallows it while logging to log.debug.
const calls: unknown[][] = [];
const log = {
debug: (...args: unknown[]) => {
calls.push(args);
},
};
await assert.doesNotReject(
maybeSyncClaudeExtraUsageState({
provider: "claude",
connectionId: "bogus-conn-id",
providerSpecificData: {},
log,
})
);
assert.equal(calls.length, 1, "the swallowed error path logs exactly once");
assert.equal(calls[0][0], "CLAUDE_USAGE");
assert.match(
String(calls[0][1]),
/Failed to sync Claude extra-usage state:/,
"logs the sync-failure message with the underlying error text"
);
});