UNPKG

@gguf/claw

Version:

Multi-channel AI gateway with extensible messaging integrations

119 lines (101 loc) 3.47 kB
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { VoiceCallConfigSchema, type VoiceCallConfig } from "./config.js"; import type { CallManager } from "./manager.js"; import type { VoiceCallProvider } from "./providers/base.js"; import type { CallRecord } from "./types.js"; import { VoiceCallWebhookServer } from "./webhook.js"; const provider: VoiceCallProvider = { name: "mock", verifyWebhook: () => ({ ok: true }), parseWebhookEvent: () => ({ events: [] }), initiateCall: async () => ({ providerCallId: "provider-call", status: "initiated" }), hangupCall: async () => {}, playTts: async () => {}, startListening: async () => {}, stopListening: async () => {}, }; const createConfig = (overrides: Partial<VoiceCallConfig> = {}): VoiceCallConfig => { const base = VoiceCallConfigSchema.parse({}); base.serve.port = 0; return { ...base, ...overrides, serve: { ...base.serve, ...(overrides.serve ?? {}), }, }; }; const createCall = (startedAt: number): CallRecord => ({ callId: "call-1", providerCallId: "provider-call-1", provider: "mock", direction: "outbound", state: "initiated", from: "+15550001234", to: "+15550005678", startedAt, transcript: [], processedEventIds: [], }); const createManager = (calls: CallRecord[]) => { const endCall = vi.fn(async () => ({ success: true })); const manager = { getActiveCalls: () => calls, endCall, } as unknown as CallManager; return { manager, endCall }; }; describe("VoiceCallWebhookServer stale call reaper", () => { beforeEach(() => { vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); }); it("ends calls older than staleCallReaperSeconds", async () => { const now = new Date("2026-02-16T00:00:00Z"); vi.setSystemTime(now); const call = createCall(now.getTime() - 120_000); const { manager, endCall } = createManager([call]); const config = createConfig({ staleCallReaperSeconds: 60 }); const server = new VoiceCallWebhookServer(config, manager, provider); try { await server.start(); await vi.advanceTimersByTimeAsync(30_000); expect(endCall).toHaveBeenCalledWith(call.callId); } finally { await server.stop(); } }); it("skips calls that are younger than the threshold", async () => { const now = new Date("2026-02-16T00:00:00Z"); vi.setSystemTime(now); const call = createCall(now.getTime() - 10_000); const { manager, endCall } = createManager([call]); const config = createConfig({ staleCallReaperSeconds: 60 }); const server = new VoiceCallWebhookServer(config, manager, provider); try { await server.start(); await vi.advanceTimersByTimeAsync(30_000); expect(endCall).not.toHaveBeenCalled(); } finally { await server.stop(); } }); it("does not run when staleCallReaperSeconds is disabled", async () => { const now = new Date("2026-02-16T00:00:00Z"); vi.setSystemTime(now); const call = createCall(now.getTime() - 120_000); const { manager, endCall } = createManager([call]); const config = createConfig({ staleCallReaperSeconds: 0 }); const server = new VoiceCallWebhookServer(config, manager, provider); try { await server.start(); await vi.advanceTimersByTimeAsync(60_000); expect(endCall).not.toHaveBeenCalled(); } finally { await server.stop(); } }); });