mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 02:57:27 +00:00
test(voice-call): cover stream disconnect auto-end
This commit is contained in:
100
extensions/voice-call/src/webhook.test.ts
Normal file
100
extensions/voice-call/src/webhook.test.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { CallManager } from "./manager.js";
|
||||
import type { VoiceCallProvider } from "./providers/base.js";
|
||||
import type { CallRecord } from "./types.js";
|
||||
import { VoiceCallConfigSchema, type VoiceCallConfig } from "./config.js";
|
||||
import { VoiceCallWebhookServer } from "./webhook.js";
|
||||
|
||||
const provider: VoiceCallProvider = {
|
||||
name: "mock",
|
||||
verifyWebhook: () => ({ ok: true }),
|
||||
parseWebhookEvent: () => ({ events: [] }),
|
||||
initiateCall: async () => ({ providerCallId: "provider-call" }),
|
||||
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("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();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user