import asyncio from queue import Queue from threading import Event, Thread from speech_to_speech.baseHandler import BaseHandler from speech_to_speech.connections.websocket_streamer import WebSocketStreamer from speech_to_speech.pipeline.control import SESSION_END, is_control_message from speech_to_speech.pipeline.messages import PIPELINE_END class EchoHandler(BaseHandler): def setup(self): self.processed = [] self.session_end_calls = 0 def process(self, item): self.processed.append(item) yield item.upper() def on_session_end(self): self.session_end_calls += 1 class FakeWebSocket: def __init__(self, messages): self._messages = iter(messages) def __aiter__(self): return self async def __anext__(self): try: return next(self._messages) except StopIteration as exc: raise StopAsyncIteration from exc def test_base_handler_session_end_resets_without_stopping(): stop_event = Event() queue_in = Queue() queue_out = Queue() handler = EchoHandler(stop_event, queue_in=queue_in, queue_out=queue_out) thread = Thread(target=handler.run) thread.start() queue_in.put(SESSION_END) queue_in.put("hello") queue_in.put(PIPELINE_END) thread.join(timeout=2) assert not thread.is_alive() outputs = [queue_out.get(timeout=1) for _ in range(3)] assert is_control_message(outputs[0], SESSION_END.kind) assert outputs[1] == "HELLO" assert outputs[2] == PIPELINE_END assert handler.processed == ["hello"] assert handler.session_end_calls == 1 def test_websocket_streamer_last_disconnect_queues_session_end(): streamer = WebSocketStreamer( stop_event=Event(), input_queue=Queue(), output_queue=Queue(), should_listen=Event(), ) asyncio.run(streamer._handle_client(FakeWebSocket([]))) queued = streamer.input_queue.get_nowait() assert is_control_message(queued, SESSION_END.kind) assert streamer.should_listen.is_set() def test_websocket_send_loop_ignores_session_end_until_stop(): stop_event = Event() streamer = WebSocketStreamer( stop_event=stop_event, input_queue=Queue(), output_queue=Queue(), should_listen=Event(), ) async def exercise_send_loop(): task = asyncio.create_task(streamer._send_loop()) streamer.output_queue.put(SESSION_END) await asyncio.sleep(0.05) assert not task.done() stop_event.set() await asyncio.wait_for(task, timeout=1) asyncio.run(exercise_send_loop())