import io import threading from pathlib import Path from time import sleep from unittest.mock import MagicMock import pytest import shout from croaker import playlist, streamer @pytest.fixture(scope="session") def silence_bytes(): # return (Path(streamer.__file__).parent / "silence.mp3").read_bytes() return (Path(__file__).parent / "fixtures" / "transcoded_silence.mp3").read_bytes() @pytest.fixture def output_stream(): return io.BytesIO() @pytest.fixture def mock_shout(output_stream, monkeypatch): def handle_send(buf): print(f"buffering {len(buf)} bytes to output_stream.") output_stream.write(buf) mm = MagicMock(spec=shout.Shout, **{"return_value.send.side_effect": handle_send}) monkeypatch.setattr("shout.Shout", mm) return mm @pytest.fixture def audio_streamer(monkeypatch, mock_shout): return streamer.AudioStreamer() @pytest.fixture def thread(audio_streamer): thread = threading.Thread(target=audio_streamer.run) thread.daemon = True yield thread audio_streamer.shutdown_requested.set() thread.join() def wait_for(condition, timeout=2.0): elapsed = 0.0 while not condition() and elapsed < 2.0: elapsed += 0.01 sleep(0.01) return elapsed <= timeout def wait_for_not(condition, timeout=2.0): return wait_for(lambda: not condition(), timeout=timeout) def test_streamer_clear(audio_streamer, thread): # enqueue some tracks pl = playlist.Playlist(name="test_playlist") for track in pl.tracks: audio_streamer.queue.put(bytes(track)) assert not audio_streamer.queue.empty() # start the server and send it a clear request thread.start() audio_streamer.clear_requested.set() assert wait_for(audio_streamer.queue.empty) assert wait_for_not(audio_streamer.clear_requested.is_set) def test_streamer_shutdown(audio_streamer, thread): thread.start() audio_streamer.shutdown_requested.set() assert wait_for_not(audio_streamer.shutdown_requested.is_set) def test_streamer_skip(audio_streamer, thread): thread.start() audio_streamer.skip_requested.set() assert wait_for_not(audio_streamer.skip_requested.is_set) def test_streamer_defaults_to_silence(audio_streamer, thread, output_stream, silence_bytes): thread.start() thread.join(timeout=1) output_stream.seek(0, 0) out = output_stream.read() assert silence_bytes in out