"""Live smoke test against the running bridge (real WS, real auth, mock backends).""" import asyncio import json import sys import httpx import websockets BASE = "http://127.0.0.1:8766" WS = "ws://127.0.0.1:8766/ws/xiaozhi" TOKEN = "8a07643d106f9282a8f2eb1161da4f73657ce99b6602b98df89d011b8caf48a2" results = {} # 1. health results["health"] = httpx.get(f"{BASE}/health", timeout=5).json() # 2. bad token must be rejected async def bad_token(): async with websockets.connect(WS) as ws: await ws.send(json.dumps({ "type": "hello", "device_id": "xiaozhi-main", "authorization": "wrong-token", "audio": {"format": "opus", "sample_rate": 16000, "channels": 1, "frame_duration": 20}, })) return await ws.recv() # 3. unknown device must be rejected async def bad_device(): async with websockets.connect(WS) as ws: await ws.send(json.dumps({ "type": "hello", "device_id": "intruder", "authorization": TOKEN, "audio": {"format": "opus", "sample_rate": 16000, "channels": 1, "frame_duration": 20}, })) return await ws.recv() # 4. real handshake + a spoken turn async def real_turn(): frames = [] audio_bytes = 0 async with websockets.connect(WS) as ws: await ws.send(json.dumps({ "type": "hello", "device_id": "xiaozhi-main", "client_id": "esp32-01", "authorization": TOKEN, "protocol_version": 1, "audio": {"format": "opus", "sample_rate": 16000, "channels": 1, "frame_duration": 20}, })) for _ in range(20): data = await ws.recv() if isinstance(data, bytes): audio_bytes += len(data) frames.append("audio") else: frames.append(json.loads(data).get("type")) if frames[-1] == "hello": # hello reply → session live break # one spoken turn: 4800 bytes of PCM (0.15s @ 16k mono 16-bit) await ws.send(bytes(range(256)) * 19) got_text = False got_audio = False for _ in range(50): data = await ws.recv() if isinstance(data, bytes): got_audio = True audio_bytes += len(data) else: frames.append(json.loads(data).get("type")) if json.loads(data).get("type") == "text": got_text = True break # keep reading TTS audio chunks that follow the text while not got_audio: data = await ws.recv() if isinstance(data, bytes): got_audio = True audio_bytes += len(data) else: frames.append(json.loads(data).get("type")) return {"frames": frames, "audio_bytes": audio_bytes, "got_text": got_text, "got_audio_out": got_audio} results["bad_token"] = asyncio.run(bad_token()) results["bad_device"] = asyncio.run(bad_device()) results["real_turn"] = asyncio.run(real_turn()) ok = ( results["health"].get("status") == "ok" and json.loads(results["bad_token"]).get("type") == "error" and json.loads(results["bad_device"]).get("type") == "error" and results["real_turn"]["got_audio_out"] ) print(json.dumps(results, ensure_ascii=False, indent=2)) print("LIVE SMOKE:", "PASS" if ok else "FAIL") sys.exit(0 if ok else 1)