"""SdrDisconnectedError translation + streamer handling.""" from __future__ import annotations import asyncio from ria_toolkit_oss.agent.streamer import Streamer from ria_toolkit_oss.sdr import SdrDisconnectedError from ria_toolkit_oss.sdr.sdr import translate_disconnect def test_translate_disconnect_usb_message(): exc = RuntimeError("libiio: Input/output error (errno 5)") out = translate_disconnect(exc) assert isinstance(out, SdrDisconnectedError) def test_translate_disconnect_enodev_oserror(): exc = OSError(19, "No such device") assert isinstance(translate_disconnect(exc), SdrDisconnectedError) def test_translate_disconnect_passes_through_unrelated(): exc = ValueError("bad sample rate") assert translate_disconnect(exc) is exc def test_translate_disconnect_preserves_sdr_disconnected(): original = SdrDisconnectedError("already typed") assert translate_disconnect(original) is original class _FlakySdr: """SDR that raises SdrDisconnectedError on the first rx() call.""" def __init__(self) -> None: self.closed = False def rx(self, n): # noqa: D401 - trivial raise SdrDisconnectedError("usb gone") def close(self): self.closed = True class _Ws: def __init__(self): self.json_sent = [] self.bytes_sent = [] async def send_json(self, p): self.json_sent.append(p) async def send_bytes(self, b): self.bytes_sent.append(b) def test_streamer_reports_disconnected_and_ends_capture(): async def scenario(): ws = _Ws() sdr = _FlakySdr() streamer = Streamer(ws=ws, sdr_factory=lambda d, i: sdr) await streamer.on_message( { "type": "start", "app_id": "a", "radio_config": {"device": "fake", "buffer_size": 8}, } ) # Wait for the capture loop to emit its error frame and tear down the session. for _ in range(100): if any(m.get("type") == "error" for m in ws.json_sent) and streamer._rx is None: break await asyncio.sleep(0.01) return ws, sdr, streamer ws, sdr, streamer = asyncio.run(scenario()) assert sdr.closed errors = [m for m in ws.json_sent if m.get("type") == "error"] assert errors, "expected an error frame" assert "disconnected" in errors[-1]["message"].lower() # Session handle cleared so future starts can proceed. assert streamer._rx is None