import { readFileSync } from "node:fs"; import { afterAll, afterEach, beforeEach, describe, expect, mock, test, } from "bun:test"; import { CURRENT_POLICY_EPOCH } from "../auth/policy.js"; import { initSigningKey, mintToken } from "../auth/token-service.js"; import type { GatewayConfig } from "../config.js"; import type { LiveVoiceSocketData } from "../http/routes/live-voice-websocket.js"; import { setVelayBridgeAuthHeader } from "../velay/bridge-auth.js"; // The bound-guardian platform user id, shared by the velay mock and the velay // tests (their attested caller must match it to authenticate). const VELAY_USER_ID = "11111111-1111-1111-1111-111111111111"; // The live-voice upgrade pins actor tokens to the bound guardian. Mock the // binding lookup (set BEFORE importing the module under test) so the actor // path is testable without gateway DB state; the default binding matches // `mintEdgeToken`'s default principal. let mockFindVellumGuardian = mock( async (): Promise<{ principalId: string } | null> => ({ principalId: "test-user", }), ); mock.module("../auth/guardian-bootstrap.js", () => ({ findVellumGuardian: () => mockFindVellumGuardian(), })); // The managed/velay path cross-checks the attested caller against the stored // `platform_user_id`. Default the credential to `VELAY_USER_ID` so the velay // success cases match; negative cases override this mock. let mockReadCredential = mock( async (_key: string): Promise => VELAY_USER_ID, ); mock.module("../credential-reader.js", () => ({ readCredential: (key: string) => mockReadCredential(key), })); const { createLiveVoiceWebsocketHandler, getLiveVoiceWebsocketHandlers } = await import("../http/routes/live-voice-websocket.js"); const TEST_SIGNING_KEY = Buffer.from("test-signing-key-at-least-32-bytes-long"); initSigningKey(TEST_SIGNING_KEY); const WS_CONNECTING = WebSocket.CONNECTING; const WS_OPEN = WebSocket.OPEN; const WS_CLOSED = WebSocket.CLOSED; function mintEdgeToken(actorPrincipalId: string = "test-user"): string { return mintToken({ aud: "vellum-gateway", sub: `actor:test-assistant:${actorPrincipalId}`, scope_profile: "actor_client_v1", policy_epoch: CURRENT_POLICY_EPOCH, ttlSeconds: 300, }); } function mintServiceEdgeToken(): string { return mintToken({ aud: "vellum-gateway", sub: "svc:gateway:self", scope_profile: "gateway_service_v1", policy_epoch: CURRENT_POLICY_EPOCH, ttlSeconds: 300, }); } function makeConfig(overrides: Partial = {}): GatewayConfig { return { assistantRuntimeBaseUrl: "http://localhost:7821", routingEntries: [], defaultAssistantId: undefined, unmappedPolicy: "reject", port: 7830, runtimeProxyRequireAuth: true, shutdownDrainMs: 5000, runtimeTimeoutMs: 30000, runtimeMaxRetries: 2, runtimeInitialBackoffMs: 500, maxWebhookPayloadBytes: 1048576, logFile: { dir: undefined, retentionDays: 30 }, maxAttachmentBytes: { telegram: 50 * 1024 * 1024, slack: 100 * 1024 * 1024, whatsapp: 16 * 1024 * 1024, default: 50 * 1024 * 1024, }, maxAttachmentConcurrency: 3, gatewayInternalBaseUrl: "http://127.0.0.1:7830", trustProxy: false, ...overrides, }; } function makeFakeServer(upgradeResult: boolean = true) { return { requestIP: mock(() => ({ address: "127.0.0.1", family: "IPv4", port: 54000, })), upgrade: mock(() => upgradeResult), } as unknown as import("bun").Server; } function createFakeDownstreamWs(data: LiveVoiceSocketData) { const sent: (string | Uint8Array)[] = []; const closes: { code: number; reason: string }[] = []; return { data, sent, closes, send: mock((msg: string | Uint8Array) => { sent.push(msg); }), close: mock((code?: number, reason?: string) => { closes.push({ code: code ?? 1000, reason: reason ?? "" }); }), }; } function createFakeUpstreamWs() { const listeners: Record void)[]> = {}; const sent: unknown[] = []; const closes: { code?: number; reason?: string }[] = []; return { readyState: WS_CONNECTING as number, sent, closes, addEventListener: mock( (event: string, cb: (...args: unknown[]) => void) => { (listeners[event] ??= []).push(cb); }, ), send: mock((msg: unknown) => { sent.push(msg); }), close: mock((code?: number, reason?: string) => { closes.push({ code, reason }); }), emit(event: string, detail: unknown = {}) { for (const cb of listeners[event] ?? []) { cb(detail); } }, }; } // Reset both mocks to their success defaults — file-scoped so per-test // overrides never leak into later describes. beforeEach(() => { mockFindVellumGuardian = mock(async () => ({ principalId: "test-user" })); mockReadCredential = mock(async () => VELAY_USER_ID); }); describe("createLiveVoiceWebsocketHandler", () => { const TEST_TOKEN = mintEdgeToken(); test("upgrades when token query parameter is a valid actor edge token", async () => { const config = makeConfig(); const handler = createLiveVoiceWebsocketHandler(config); const req = new Request( `http://localhost:7830/v1/live-voice?token=${TEST_TOKEN}`, { headers: { upgrade: "websocket" } }, ); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeUndefined(); expect(server.upgrade).toHaveBeenCalledTimes(1); const call = (server.upgrade as ReturnType).mock .calls[0] as unknown[]; expect(call[0]).toBe(req); expect((call[1] as { data: LiveVoiceSocketData }).data).toEqual({ wsType: "live-voice", config, }); }); test("upgrades when Authorization header is a valid actor edge token", async () => { const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request("http://localhost:7830/v1/live-voice", { headers: { upgrade: "websocket", authorization: `Bearer ${TEST_TOKEN}`, }, }); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeUndefined(); expect(server.upgrade).toHaveBeenCalledTimes(1); }); test("returns 401 when auth is required and no token is provided", async () => { const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request("http://localhost:7830/v1/live-voice", { headers: { upgrade: "websocket" }, }); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(401); expect(server.upgrade).not.toHaveBeenCalled(); }); test("returns 401 when token is invalid", async () => { const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request( "http://localhost:7830/v1/live-voice?token=bad-token", { headers: { upgrade: "websocket" } }, ); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(401); expect(server.upgrade).not.toHaveBeenCalled(); }); test("returns 401 when token lacks an actor principal", async () => { const serviceToken = mintServiceEdgeToken(); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request( `http://localhost:7830/v1/live-voice?token=${serviceToken}`, { headers: { upgrade: "websocket" } }, ); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(401); expect(server.upgrade).not.toHaveBeenCalled(); }); test("allows unauthenticated upgrade when runtime proxy auth is disabled", async () => { const config = makeConfig({ runtimeProxyRequireAuth: false }); const handler = createLiveVoiceWebsocketHandler(config); const req = new Request("http://localhost:7830/v1/live-voice", { headers: { upgrade: "websocket" }, }); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeUndefined(); expect(server.upgrade).toHaveBeenCalledTimes(1); }); test("returns 426 when upgrade header is not websocket", async () => { const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request( `http://localhost:7830/v1/live-voice?token=${TEST_TOKEN}`, ); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(426); expect(server.upgrade).not.toHaveBeenCalled(); }); test("returns 500 when Bun.serve upgrade fails", async () => { const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request( `http://localhost:7830/v1/live-voice?token=${TEST_TOKEN}`, { headers: { upgrade: "websocket" } }, ); const server = makeFakeServer(false); const res = await handler(req, server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(500); }); // Guardian pinning: live voice is a guardian-only surface (the daemon stamps // each voice turn with the guardian's trust context on that basis), so a // valid actor token whose principal is not the bound guardian must not // upgrade. test("returns 403 when the actor token is valid but not the bound guardian", async () => { mockFindVellumGuardian = mock(async () => ({ principalId: "someone-else", })); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request( `http://localhost:7830/v1/live-voice?token=${TEST_TOKEN}`, { headers: { upgrade: "websocket" } }, ); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(403); expect(server.upgrade).not.toHaveBeenCalled(); }); test("returns 403 when no guardian binding exists", async () => { mockFindVellumGuardian = mock(async () => null); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request( `http://localhost:7830/v1/live-voice?token=${TEST_TOKEN}`, { headers: { upgrade: "websocket" } }, ); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(403); expect(server.upgrade).not.toHaveBeenCalled(); }); test("returns 503 when the guardian binding lookup fails", async () => { mockFindVellumGuardian = mock(async () => { throw new Error("gateway db unavailable"); }); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request( `http://localhost:7830/v1/live-voice?token=${TEST_TOKEN}`, { headers: { upgrade: "websocket" } }, ); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(503); expect(server.upgrade).not.toHaveBeenCalled(); }); }); describe("createLiveVoiceWebsocketHandler — velay-attested managed auth", () => { const TEST_TOKEN = mintEdgeToken(); // VELAY_USER_ID is declared at module scope (shared with the credential mock). const VELAY_ORG_ID = "22222222-2222-2222-2222-222222222222"; const originalIsPlatform = process.env.IS_PLATFORM; function setPlatform(on: boolean) { if (on) { process.env.IS_PLATFORM = "true"; } else { delete process.env.IS_PLATFORM; } } function makeVelayReq( headers: Record = { "x-velay-user-id": VELAY_USER_ID, "x-velay-org-id": VELAY_ORG_ID, "x-velay-actor": "user", }, opts: { bridgeAuth?: boolean } = {}, ) { const requestHeaders = new Headers({ upgrade: "websocket", ...headers }); if (opts.bridgeAuth !== false) { setVelayBridgeAuthHeader(requestHeaders); } return new Request("http://localhost:7830/v1/live-voice", { headers: requestHeaders, }); } afterEach(() => { if (originalIsPlatform === undefined) { delete process.env.IS_PLATFORM; } else { process.env.IS_PLATFORM = originalIsPlatform; } }); test("managed mode + valid X-Velay-* headers with bridge proof authorizes the upgrade", async () => { setPlatform(true); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const server = makeFakeServer(); const res = await handler(makeVelayReq(), server); expect(res).toBeUndefined(); expect(server.upgrade).toHaveBeenCalledTimes(1); }); // Guardian pinning on the velay path: the attested caller must match the // stored platform_user_id, or the daemon's guardian stamp would be unbacked. test("managed mode + bridge proof but velay user is not the bound guardian is rejected", async () => { setPlatform(true); mockReadCredential = mock( async () => "99999999-9999-9999-9999-999999999999", ); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const server = makeFakeServer(); const res = await handler(makeVelayReq(), server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(403); expect(server.upgrade).not.toHaveBeenCalled(); }); test("managed mode + bridge proof but no platform_user_id stored is rejected", async () => { setPlatform(true); mockReadCredential = mock(async () => undefined); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const server = makeFakeServer(); const res = await handler(makeVelayReq(), server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(403); expect(server.upgrade).not.toHaveBeenCalled(); }); test("managed mode + bridge proof but platform_user_id lookup fails returns 503", async () => { setPlatform(true); mockReadCredential = mock(async () => { throw new Error("credential store unavailable"); }); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const server = makeFakeServer(); const res = await handler(makeVelayReq(), server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(503); expect(server.upgrade).not.toHaveBeenCalled(); }); test("managed mode + spoofed X-Velay-* headers without bridge proof is rejected", async () => { setPlatform(true); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const server = makeFakeServer(); const res = await handler( makeVelayReq(undefined, { bridgeAuth: false }), server, ); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(401); expect(server.upgrade).not.toHaveBeenCalled(); }); test("managed mode without velay headers and without actor JWT is rejected", async () => { setPlatform(true); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request("http://localhost:7830/v1/live-voice", { headers: { upgrade: "websocket" }, }); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(401); expect(server.upgrade).not.toHaveBeenCalled(); }); test("managed mode with X-Velay-Actor other than 'user' is rejected", async () => { setPlatform(true); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const server = makeFakeServer(); const res = await handler( makeVelayReq({ "x-velay-user-id": VELAY_USER_ID, "x-velay-org-id": VELAY_ORG_ID, "x-velay-actor": "service", }), server, ); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(401); expect(server.upgrade).not.toHaveBeenCalled(); }); test("managed mode missing org id falls through and is rejected", async () => { setPlatform(true); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const server = makeFakeServer(); const res = await handler( makeVelayReq({ "x-velay-user-id": VELAY_USER_ID, "x-velay-actor": "user", }), server, ); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(401); expect(server.upgrade).not.toHaveBeenCalled(); }); test("local mode does NOT trust X-Velay-* headers even with bridge proof", async () => { setPlatform(false); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const server = makeFakeServer(); const res = await handler(makeVelayReq(), server); expect(res).toBeInstanceOf(Response); expect(res!.status).toBe(401); expect(server.upgrade).not.toHaveBeenCalled(); }); test("managed mode still accepts a valid actor edge JWT (no velay headers)", async () => { setPlatform(true); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const req = new Request( `http://localhost:7830/v1/live-voice?token=${TEST_TOKEN}`, { headers: { upgrade: "websocket" } }, ); const server = makeFakeServer(); const res = await handler(req, server); expect(res).toBeUndefined(); expect(server.upgrade).toHaveBeenCalledTimes(1); }); }); describe("getLiveVoiceWebsocketHandlers", () => { const OriginalWebSocket = globalThis.WebSocket; let fakeUpstream: ReturnType; let handlers: ReturnType; beforeEach(() => { fakeUpstream = createFakeUpstreamWs(); const MockWS = mock(() => fakeUpstream); Object.assign(MockWS, { CONNECTING: WS_CONNECTING, OPEN: WS_OPEN, CLOSING: 2, CLOSED: WS_CLOSED, }); globalThis.WebSocket = MockWS as unknown as typeof WebSocket; handlers = getLiveVoiceWebsocketHandlers(); }); afterAll(() => { globalThis.WebSocket = OriginalWebSocket; }); test("open targets the runtime live voice websocket with a service token", async () => { const ws = createFakeDownstreamWs({ wsType: "live-voice", config: makeConfig({ assistantRuntimeBaseUrl: "http://runtime.internal:7821", }), }); handlers.open(ws as never); const MockWS = globalThis.WebSocket as unknown as ReturnType; const calledUrl = (MockWS.mock.calls[0] as unknown[])[0] as string; const parsed = new URL(calledUrl); expect(parsed.protocol).toBe("ws:"); expect(parsed.host).toBe("runtime.internal:7821"); expect(parsed.pathname).toBe("/v1/live-voice"); expect(parsed.searchParams.get("token")).toMatch(/^ey/); }); test("buffers downstream text and binary messages before upstream opens", async () => { const ws = createFakeDownstreamWs({ wsType: "live-voice", config: makeConfig(), }); const binaryFrame = new Uint8Array([1, 2, 3]); handlers.open(ws as never); handlers.message(ws as never, '{"type":"start"}'); handlers.message(ws as never, binaryFrame); expect(ws.data.pendingMessages).toEqual(['{"type":"start"}', binaryFrame]); expect(fakeUpstream.sent).toEqual([]); }); test("flushes buffered messages on upstream open", async () => { const ws = createFakeDownstreamWs({ wsType: "live-voice", config: makeConfig(), }); const binaryFrame = new Uint8Array([4, 5, 6]); handlers.open(ws as never); handlers.message(ws as never, '{"type":"start"}'); handlers.message(ws as never, binaryFrame); fakeUpstream.readyState = WS_OPEN; fakeUpstream.emit("open"); expect(fakeUpstream.sent).toEqual(['{"type":"start"}', binaryFrame]); expect(ws.data.pendingMessages).toBeUndefined(); }); test("forwards downstream binary audio frames without JSON conversion", async () => { const ws = createFakeDownstreamWs({ wsType: "live-voice", config: makeConfig(), }); const binaryFrame = new Uint8Array([9, 8, 7]); handlers.open(ws as never); fakeUpstream.readyState = WS_OPEN; fakeUpstream.emit("open"); handlers.message(ws as never, binaryFrame); expect(fakeUpstream.sent).toEqual([binaryFrame]); expect(fakeUpstream.sent[0]).toBe(binaryFrame); }); test("forwards upstream text and binary frames to the downstream socket", async () => { const ws = createFakeDownstreamWs({ wsType: "live-voice", config: makeConfig(), }); handlers.open(ws as never); fakeUpstream.emit("message", { data: '{"type":"ready"}' }); fakeUpstream.emit("message", { data: new Uint8Array([5, 6]).buffer }); expect(ws.sent[0]).toBe('{"type":"ready"}'); expect(ws.sent[1]).toBeInstanceOf(Uint8Array); expect(Array.from(ws.sent[1] as Uint8Array)).toEqual([5, 6]); }); test("closes downstream with 1008 on pending buffer overflow", async () => { const ws = createFakeDownstreamWs({ wsType: "live-voice", config: makeConfig(), }); handlers.open(ws as never); for (let i = 0; i < 100; i++) { handlers.message(ws as never, `msg-${i}`); } handlers.message(ws as never, "overflow"); expect(ws.closes).toEqual([{ code: 1008, reason: "Buffer overflow" }]); }); test("downstream close clears pending messages and closes connecting upstream", async () => { const ws = createFakeDownstreamWs({ wsType: "live-voice", config: makeConfig(), }); handlers.open(ws as never); handlers.message(ws as never, "pending"); handlers.close(ws as never, 1000, "client closed"); expect(ws.data.pendingMessages).toBeUndefined(); expect(fakeUpstream.closes).toEqual([ { code: 1000, reason: "client closed" }, ]); }); test("upstream close and error events close the downstream socket", async () => { const ws = createFakeDownstreamWs({ wsType: "live-voice", config: makeConfig(), }); handlers.open(ws as never); fakeUpstream.emit("close", { code: 1001, reason: "going away" }); fakeUpstream.emit("error", new Event("error")); expect(ws.closes).toEqual([ { code: 1001, reason: "going away" }, { code: 1011, reason: "Upstream error" }, ]); }); }); describe("live voice gateway boundary", () => { test("handler does not import assistant package files", async () => { const source = readFileSync( new URL("../http/routes/live-voice-websocket.ts", import.meta.url), "utf8", ); expect(source).not.toMatch(/from\s+["'](?:\.\.\/)+assistant\//); expect(source).not.toContain('from "assistant/'); }); test("gateway index routes live voice websocket upgrades before the runtime proxy", async () => { const source = readFileSync( new URL("../index.ts", import.meta.url), "utf8", ); expect(source).toContain("createLiveVoiceWebsocketHandler"); expect(source).toContain("getLiveVoiceWebsocketHandlers"); expect(source).toContain("type LiveVoiceSocketData"); expect(source).toContain("function isLiveVoiceSocketData"); expect(source).toContain("const handleLiveVoiceWs"); expect(source).toContain("const liveVoiceWebsocketHandlers"); const liveVoiceRouteIndex = source.indexOf( 'url.pathname === "/v1/live-voice"', ); const runtimeProxyDispatchIndex = source.indexOf( "const response = await router(req, url, resolveClientIp, svr);", ); expect(liveVoiceRouteIndex).toBeGreaterThan(-1); expect(runtimeProxyDispatchIndex).toBeGreaterThan(-1); expect(liveVoiceRouteIndex).toBeLessThan(runtimeProxyDispatchIndex); expect(source).toContain("handleLiveVoiceWs(req, server)"); expect(source).toContain('url.pathname === "/v1/stt/stream"'); expect(source).toContain("handleSttStreamWs(req, server)"); }); test("gateway websocket lifecycle dispatches live voice socket data", async () => { const source = readFileSync( new URL("../index.ts", import.meta.url), "utf8", ); expect(source).toMatch( /if \(isLiveVoiceSocketData\(ws\.data\)\) \{\s+liveVoiceWebsocketHandlers\.open\(ws as never\);\s+return;\s+\}/, ); expect(source).toMatch( /if \(isLiveVoiceSocketData\(ws\.data\)\) \{\s+liveVoiceWebsocketHandlers\.message\(ws as never, message\);\s+return;\s+\}/, ); expect(source).toMatch( /if \(isLiveVoiceSocketData\(ws\.data\)\) \{\s+liveVoiceWebsocketHandlers\.close\(ws as never, code, reason\);\s+return;\s+\}/, ); }); }); describe("createLiveVoiceWebsocketHandler — revocation", () => { // These tests exercise the gateway DB, so set it up per-test. (The other // suites run without a DB; the revocation check is fail-open when the DB is // absent, so they upgrade as before.) let testRoot: string; beforeEach(async () => { const { mkdtempSync, mkdirSync } = await import("node:fs"); const { tmpdir } = await import("node:os"); const { join } = await import("node:path"); testRoot = mkdtempSync(join(tmpdir(), "live-voice-revocation-")); mkdirSync(join(testRoot, "protected"), { recursive: true }); process.env.GATEWAY_SECURITY_DIR = join(testRoot, "protected"); const { initGatewayDb } = await import("../db/connection.js"); await initGatewayDb(); }); afterEach(async () => { const { resetGatewayDb } = await import("../db/connection.js"); resetGatewayDb(); delete process.env.GATEWAY_SECURITY_DIR; const { rmSync } = await import("node:fs"); try { rmSync(testRoot, { recursive: true, force: true }); } catch { /* best effort */ } }); test("returns 401 when the actor token has been revoked", async () => { const { getGatewayDb } = await import("../db/connection.js"); const { actorTokenRecords } = await import("../db/schema.js"); const { createHash } = await import("node:crypto"); const jwt = mintEdgeToken(); const now = Date.now(); getGatewayDb() .insert(actorTokenRecords) .values({ id: "id-revoked", tokenHash: createHash("sha256").update(jwt).digest("hex"), guardianPrincipalId: "guardian-001", hashedDeviceId: createHash("sha256").update("device").digest("hex"), platform: "web", status: "revoked", issuedAt: now, expiresAt: now + 300_000, createdAt: now, updatedAt: now, }) .run(); const handler = createLiveVoiceWebsocketHandler(makeConfig()); const server = makeFakeServer(); const res = await handler( new Request(`http://127.0.0.1:7830/v1/live-voice?token=${jwt}`, { headers: { upgrade: "websocket" }, }), server, ); expect(res).not.toBeNull(); expect(res!.status).toBe(401); expect(server.upgrade).not.toHaveBeenCalled(); }); });