ria-toolkit-oss/tests/agent/test_integration.py
2026-04-13 11:48:15 -04:00

101 lines
3.7 KiB
Python
Raw RIA Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""End-to-end: local websockets server drives a Streamer with a MockSDR."""
from __future__ import annotations
import asyncio
import json
import websockets
from ria_toolkit_oss.agent.streamer import Streamer
from ria_toolkit_oss.agent.ws_client import WsClient
from ria_toolkit_oss.sdr.mock import MockSDR
def test_server_start_stream_stop_cycle_over_real_ws():
async def scenario():
control_frames: list[dict] = []
binary_frames: list[bytes] = []
ready = asyncio.Event()
stopped = asyncio.Event()
async def server_handler(ws):
# Agent will open the connection; wait for heartbeat first.
try:
first = await asyncio.wait_for(ws.recv(), timeout=2.0)
control_frames.append(json.loads(first))
await ws.send(
json.dumps(
{
"type": "start",
"app_id": "app-1",
"radio_config": {
"device": "mock",
"buffer_size": 32,
"sample_rate": 1_000_000,
"center_frequency": 2.45e9,
},
}
)
)
while len(binary_frames) < 3:
msg = await asyncio.wait_for(ws.recv(), timeout=2.0)
if isinstance(msg, bytes):
binary_frames.append(msg)
else:
control_frames.append(json.loads(msg))
ready.set()
await ws.send(json.dumps({"type": "stop", "app_id": "app-1"}))
# Drain final status frame.
try:
while True:
msg = await asyncio.wait_for(ws.recv(), timeout=0.5)
if isinstance(msg, bytes):
binary_frames.append(msg)
else:
control_frames.append(json.loads(msg))
except (asyncio.TimeoutError, Exception):
pass
stopped.set()
except Exception:
stopped.set()
server = await websockets.serve(server_handler, "127.0.0.1", 0)
port = server.sockets[0].getsockname()[1]
try:
client = WsClient(
f"ws://127.0.0.1:{port}",
token="",
heartbeat_interval=10.0,
reconnect_pause=0.05,
)
streamer = Streamer(ws=client, sdr_factory=lambda d, i: MockSDR(buffer_size=32, seed=0))
task = asyncio.create_task(
client.run(on_message=streamer.on_message, heartbeat=streamer.build_heartbeat)
)
await asyncio.wait_for(ready.wait(), timeout=3.0)
await asyncio.wait_for(stopped.wait(), timeout=3.0)
client.stop()
task.cancel()
try:
await task
except (asyncio.CancelledError, Exception):
pass
finally:
server.close()
await server.wait_closed()
return control_frames, binary_frames
controls, binaries = asyncio.run(scenario())
# Heartbeat reached the server.
assert any(f.get("type") == "heartbeat" for f in controls)
# Status transitioned idle -> streaming -> idle.
statuses = [f["status"] for f in controls if f.get("type") == "status"]
assert "streaming" in statuses
assert statuses[-1] == "idle"
# Three binary IQ frames of 32 samples × 2 floats × 4 bytes.
assert len(binaries) >= 3
for b in binaries[:3]:
assert len(b) == 32 * 2 * 4