import asyncio import json import pytest from hass.typing import XiaoAiConfig from hass.xiaoai_bridge import XiaoAiBridge class FakeServer: def __init__(self): self._fns = {} self.shell_calls = [] def register_fn(self, name, fn): self._fns[name] = fn async def run_shell(self, script, timeout): self.shell_calls.append((script, timeout)) return '{"stdout":"ok","stderr":"","exit_code":0}' async def start_server(self): return None @pytest.mark.asyncio async def test_bridge_interrupts_before_dispatch(monkeypatch): fake_server = FakeServer() import hass.xiaoai_bridge as module monkeypatch.setattr(module, "_LOGGER", module._LOGGER) cfg = XiaoAiConfig(interrupt_on_new_input=True, shell_timeout_ms=123) bridge = XiaoAiBridge(cfg) bridge._open_xiaoai_server = fake_server bridge._loop = asyncio.get_running_loop() called = [] async def on_text(input_data): called.append(input_data) bridge.set_on_text(on_text) bridge._ready.set() bridge._register_callbacks() event = { "event": "instruction", "data": { "ClientIP": "192.168.1.101", "NewLine": json.dumps( { "header": {"namespace": "SpeechRecognizer", "name": "RecognizeResult"}, "payload": { "is_final": True, "results": [{"text": "打开客厅灯"}], }, }, ensure_ascii=False, ), }, } fake_server._fns["on_event"](json.dumps(event, ensure_ascii=False)) await asyncio.sleep(0.05) assert len(fake_server.shell_calls) == 1 assert "ubus call mibrain ai_service" in fake_server.shell_calls[0][0] assert len(called) == 1 assert called[0].text == "打开客厅灯" assert called[0].client_ip == "192.168.1.101" @pytest.mark.asyncio async def test_bridge_extracts_missing_ip_as_none(): fake_server = FakeServer() cfg = XiaoAiConfig(interrupt_on_new_input=False) bridge = XiaoAiBridge(cfg) bridge._open_xiaoai_server = fake_server bridge._loop = asyncio.get_running_loop() captured = [] async def on_text(input_data): captured.append(input_data) bridge.set_on_text(on_text) bridge._ready.set() bridge._register_callbacks() event = { "event": "instruction", "data": { "NewLine": json.dumps( { "header": {"namespace": "SpeechRecognizer", "name": "RecognizeResult"}, "payload": { "is_final": True, "results": [{"text": "查询天气"}], }, }, ensure_ascii=False, ), }, } fake_server._fns["on_event"](json.dumps(event, ensure_ascii=False)) await asyncio.sleep(0.05) assert len(captured) == 1 assert captured[0].client_ip is None assert fake_server.shell_calls == []