import asyncio import time import pytest from runtime.history.bridge import SessionHistoryBridge class _FakeHistoryWriter: def __init__(self, *, add_delay_s: float = 0.0, add_result: bool = True): self.add_delay_s = add_delay_s self.add_result = add_result self.created_call_ids = [] self.transcripts = [] self.finalize_calls = 0 self.finalize_statuses = [] self.finalize_at = None self.last_transcript_at = None async def create_call_record(self, *, user_id: int, assistant_id: str | None, source: str = "debug"): _ = (user_id, assistant_id, source) call_id = "call_test_1" self.created_call_ids.append(call_id) return call_id async def add_transcript( self, *, call_id: str, turn_index: int, speaker: str, content: str, start_ms: int, end_ms: int, confidence: float | None = None, duration_ms: int | None = None, ) -> bool: _ = confidence if self.add_delay_s > 0: await asyncio.sleep(self.add_delay_s) self.transcripts.append( { "call_id": call_id, "turn_index": turn_index, "speaker": speaker, "content": content, "start_ms": start_ms, "end_ms": end_ms, "duration_ms": duration_ms, } ) self.last_transcript_at = time.monotonic() return self.add_result async def finalize_call_record(self, *, call_id: str, status: str, duration_seconds: int) -> bool: _ = (call_id, duration_seconds) self.finalize_calls += 1 self.finalize_statuses.append(status) self.finalize_at = time.monotonic() return True @pytest.mark.asyncio async def test_slow_backend_does_not_block_enqueue(): writer = _FakeHistoryWriter(add_delay_s=0.15, add_result=True) bridge = SessionHistoryBridge( history_writer=writer, enabled=True, queue_max_size=32, retry_max_attempts=0, retry_backoff_sec=0.01, finalize_drain_timeout_sec=1.0, ) try: call_id = await bridge.start_call(user_id=1, assistant_id="assistant_1", source="debug") assert call_id == "call_test_1" t0 = time.perf_counter() queued = bridge.enqueue_turn(role="user", text="hello world") elapsed_s = time.perf_counter() - t0 assert queued is True assert elapsed_s < 0.02 await bridge.finalize(status="connected") assert len(writer.transcripts) == 1 assert writer.finalize_calls == 1 finally: await bridge.shutdown() @pytest.mark.asyncio async def test_failing_backend_retries_but_enqueue_remains_non_blocking(): writer = _FakeHistoryWriter(add_delay_s=0.01, add_result=False) bridge = SessionHistoryBridge( history_writer=writer, enabled=True, queue_max_size=32, retry_max_attempts=2, retry_backoff_sec=0.01, finalize_drain_timeout_sec=0.5, ) try: await bridge.start_call(user_id=1, assistant_id="assistant_1", source="debug") t0 = time.perf_counter() assert bridge.enqueue_turn(role="assistant", text="retry me") elapsed_s = time.perf_counter() - t0 assert elapsed_s < 0.02 await bridge.finalize(status="connected") # Initial try + 2 retries assert len(writer.transcripts) == 3 assert writer.finalize_calls == 1 finally: await bridge.shutdown() @pytest.mark.asyncio async def test_finalize_is_idempotent_and_waits_for_queue_drain(): writer = _FakeHistoryWriter(add_delay_s=0.05, add_result=True) bridge = SessionHistoryBridge( history_writer=writer, enabled=True, queue_max_size=32, retry_max_attempts=0, retry_backoff_sec=0.01, finalize_drain_timeout_sec=1.0, ) try: await bridge.start_call(user_id=1, assistant_id="assistant_1", source="debug") assert bridge.enqueue_turn(role="user", text="first") ok_1 = await bridge.finalize(status="connected") ok_2 = await bridge.finalize(status="connected") assert ok_1 is True assert ok_2 is True assert len(writer.transcripts) == 1 assert writer.finalize_calls == 1 assert writer.last_transcript_at is not None assert writer.finalize_at is not None assert writer.finalize_at >= writer.last_transcript_at finally: await bridge.shutdown()