""" WebSocket event-stream tests. The socket is refused (4401) without the bearer token, and an authorized client immediately receives the synthetic trunk-status event followed by the replayed recent history. """ import asyncio import pytest from pydantic import SecretStr from starlette.testclient import TestClient from starlette.websockets import WebSocketDisconnect import main from config import Settings, get_settings from core.gateway import AIPSTNGateway from models.events import EventType, GatewayEvent @pytest.fixture def ws_app(monkeypatch): monkeypatch.setattr(get_settings(), "api_token", SecretStr("tok")) gateway = AIPSTNGateway(settings=Settings()) main.app.state.gateway = gateway yield gateway del main.app.state.gateway def _publish(gateway, call_id: str) -> None: asyncio.run(gateway.event_bus.publish(GatewayEvent( type=EventType.CALL_INITIATED, call_id=call_id, data={}, message=f"call {call_id}", ))) class TestEventStream: def test_refused_without_token(self, ws_app): client = TestClient(main.app) with pytest.raises(WebSocketDisconnect) as exc: with client.websocket_connect("/ws/events"): pass assert exc.value.code == 4401 def test_trunk_status_then_replayed_history(self, ws_app): _publish(ws_app, "call_ws1") _publish(ws_app, "call_ws2") client = TestClient(main.app) with client.websocket_connect("/ws/events?token=tok") as ws: first = ws.receive_json() assert first["type"] == EventType.SIP_TRUNK_REGISTRATION_FAILED.value replayed = [ws.receive_json() for _ in range(2)] assert [m["call_id"] for m in replayed] == ["call_ws1", "call_ws2"] def test_per_call_stream_filters(self, ws_app): client = TestClient(main.app) with client.websocket_connect( "/ws/calls/call_target/events?token=tok" ) as ws: _publish(ws_app, "call_other") _publish(ws_app, "call_target") msg = ws.receive_json() assert msg["call_id"] == "call_target"