Spaces:
Running
Running
| """Unit tests for app-level helpers (no hardware, no network).""" | |
| import queue | |
| import threading | |
| import time | |
| import numpy as np | |
| from yrobot.config import Settings | |
| from yrobot.main import Conversation, UplinkPacket | |
| from yrobot.realtime import Delta | |
| from yrobot.turn import QUIET_S, TurnGate | |
| def test_urgent_uplink_discards_stale_backlog(): | |
| packets: queue.Queue[UplinkPacket] = queue.Queue(maxsize=4) | |
| old = np.zeros(16_000, np.float32) | |
| for captured_at in (1.0, 2.0, 3.0): | |
| packets.put( | |
| UplinkPacket( | |
| old, | |
| force_listen=False, | |
| captured_at=captured_at, | |
| input_id=f"old-{captured_at}", | |
| ) | |
| ) | |
| urgent = UplinkPacket( | |
| np.ones(16_000, np.float32), | |
| force_listen=True, | |
| captured_at=4.0, | |
| input_id="forced", | |
| ) | |
| Conversation._enqueue_packet(packets, urgent, flush_backlog=True) | |
| assert packets.qsize() == 1 | |
| assert packets.get_nowait() is urgent | |
| def test_slow_websocket_sender_does_not_block_packet_producer(): | |
| entered = threading.Event() | |
| release = threading.Event() | |
| class SlowClient: | |
| def send_chunk(self, audio, jpeg, force_listen, input_id): | |
| entered.set() | |
| release.wait(2.0) | |
| conversation = object.__new__(Conversation) | |
| conversation._session_dead = threading.Event() | |
| conversation._video_kv_est = 0.0 | |
| conversation._turn_lock = threading.Lock() | |
| conversation._gate = TurnGate() | |
| packets: queue.Queue[UplinkPacket] = queue.Queue(maxsize=4) | |
| halt = threading.Event() | |
| packets.put( | |
| UplinkPacket( | |
| np.zeros(16_000, np.float32), | |
| False, | |
| time.monotonic(), | |
| "normal-1", | |
| ) | |
| ) | |
| sender = threading.Thread( | |
| target=conversation._send_loop, | |
| args=(SlowClient(), packets, halt, None), | |
| ) | |
| sender.start() | |
| try: | |
| assert entered.wait(1.0) | |
| started = time.monotonic() | |
| Conversation._enqueue_packet( | |
| packets, | |
| UplinkPacket( | |
| np.ones(16_000, np.float32), | |
| False, | |
| time.monotonic(), | |
| "normal-2", | |
| ), | |
| ) | |
| assert time.monotonic() - started < 0.05 | |
| finally: | |
| halt.set() | |
| release.set() | |
| sender.join(timeout=2) | |
| def _conversation_without_hardware() -> Conversation: | |
| class FakeMedia: | |
| pass | |
| class FakeMini: | |
| media = FakeMedia() | |
| return Conversation( | |
| Settings(head_tracking_weight=0.0), | |
| FakeMini(), | |
| threading.Event(), | |
| ) | |
| def test_barge_candidate_hard_stops_and_latches_force(): | |
| conversation = _conversation_without_hardware() | |
| started = time.monotonic() | |
| old_epoch = conversation._speaker.epoch | |
| conversation._begin_barge(started) | |
| assert conversation._speaker.epoch == old_epoch + 1 | |
| assert conversation._speaker._flush_event.is_set() | |
| assert conversation._gate.latched | |
| with conversation._turn_lock: | |
| assert conversation._gate.chunk_force_listen(started + 0.01) | |
| def test_interrupted_multi_branch_output_waits_for_force_listen_boundary(): | |
| conversation = _conversation_without_hardware() | |
| pcm = np.ones(2400, np.float32) | |
| conversation._on_delta(Delta(kind="audio", audio=pcm, response_id="old")) | |
| conversation._speaker._q.get_nowait() | |
| started = time.monotonic() | |
| conversation._begin_barge(started) | |
| conversation._on_delta( | |
| Delta(kind="audio", audio=pcm, response_id="old-branch-2", received_at=started + 0.04) | |
| ) | |
| conversation._on_delta( | |
| Delta(kind="audio", audio=pcm, response_id="old-branch-3", received_at=started + 0.06) | |
| ) | |
| assert conversation._speaker._q.empty() | |
| with conversation._turn_lock: | |
| assert conversation._gate.chunk_force_listen(started + 0.08) | |
| conversation._gate.force_sent("forced-input", started + 0.08) | |
| conversation._on_delta(Delta(kind="listen", input_id="wrong-input", received_at=started + 0.09)) | |
| assert conversation._gate.latched | |
| conversation._on_delta( | |
| Delta(kind="listen", input_id="forced-input", received_at=started + 0.10) | |
| ) | |
| conversation._on_delta( | |
| Delta( | |
| kind="audio", | |
| audio=pcm, | |
| response_id="new-answer", | |
| received_at=started + QUIET_S + 0.10, | |
| ) | |
| ) | |
| epoch, queued = conversation._speaker._q.get_nowait() | |
| assert epoch == conversation._speaker.epoch | |
| assert queued is pcm | |
| def test_late_callbacks_from_rotated_session_cannot_poison_current_session(): | |
| conversation = _conversation_without_hardware() | |
| conversation._session_sequence = 2 | |
| pcm = np.ones(2400, np.float32) | |
| conversation._on_delta(Delta(kind="audio", audio=pcm), session_sequence=1) | |
| conversation._on_closed("late-close", session_sequence=1) | |
| assert conversation._speaker._q.empty() | |
| assert not conversation._session_dead.is_set() | |