""" Engine-mode and event-bus-integrity tests. The mock engine must be requested explicitly; a full subscriber queue drops its oldest event but never loses the subscription; history is replayable to late joiners. """ import asyncio import pytest from config import Settings from core.event_bus import EventBus from core.gateway import build_sip_engine from core.media_pipeline import MediaPipeline from core.sip_engine import MockSIPEngine from models.events import EventType, GatewayEvent def _noop(*args, **kwargs): pass class TestEngineMode: def _build(self, settings: Settings): return build_sip_engine( settings, MediaPipeline(sample_rate=16000), on_leg_state_change=_noop, on_device_registered=_noop, on_incoming_call=_noop, ) def test_mock_engine_only_when_asked(self): settings = Settings(use_mock_sip=True) assert isinstance(self._build(settings), MockSIPEngine) def test_unconfigured_trunk_refuses_to_build(self): settings = Settings(use_mock_sip=False) settings.sip_trunk.host = "sip.yourprovider.com" with pytest.raises(RuntimeError, match="not configured"): self._build(settings) def _event(i: int) -> GatewayEvent: return GatewayEvent( type=EventType.CALL_INITIATED, call_id=f"call_{i}", data={}, message=f"event {i}", ) class TestEventBusIntegrity: async def test_overflow_drops_oldest_keeps_subscription(self): bus = EventBus() sub = bus.subscribe(max_size=3) for i in range(5): await bus.publish(_event(i)) assert bus.subscriber_count == 1 # never evicted assert sub.dropped == 2 received = [await asyncio.wait_for(sub.get(), 1.0) for _ in range(3)] assert [e.call_id for e in received] == ["call_2", "call_3", "call_4"] async def test_replay_last_seeds_history(self): bus = EventBus() for i in range(10): await bus.publish(_event(i)) sub = bus.subscribe(replay_last=3) received = [await asyncio.wait_for(sub.get(), 1.0) for _ in range(3)] assert [e.call_id for e in received] == ["call_7", "call_8", "call_9"] async def test_replay_respects_type_filter(self): bus = EventBus() await bus.publish(_event(1)) await bus.publish(GatewayEvent( type=EventType.HUMAN_DETECTED, call_id="call_h", data={}, message="x" )) sub = bus.subscribe( event_types={EventType.HUMAN_DETECTED}, replay_last=5 ) event = await asyncio.wait_for(sub.get(), 1.0) assert event.call_id == "call_h" assert sub._queue.empty()