Rebuild audio streamer event handlers
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
@@ -14,3 +15,7 @@ def mock_env(monkeypatch):
|
||||
monkeypatch.setenv("ICECAST_PORT", "6523")
|
||||
monkeypatch.setenv("ICECAST_PASSWORD", "password")
|
||||
monkeypatch.setenv("DEBUG", "1")
|
||||
|
||||
logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.DEBUG)
|
||||
# logging.getLogger('transcoder').setLevel(logging.INFO)
|
||||
# logging.getLogger('root').setLevel(logging.INFO)
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+44
-84
@@ -1,7 +1,7 @@
|
||||
import io
|
||||
import queue
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from time import sleep
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
@@ -10,13 +10,10 @@ import shout
|
||||
from croaker import playlist, streamer
|
||||
|
||||
|
||||
def get_stream_output(stream):
|
||||
return stream.read()
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def silence_bytes():
|
||||
return (Path(streamer.__file__).parent / "silence.mp3").read_bytes()
|
||||
# return (Path(streamer.__file__).parent / "silence.mp3").read_bytes()
|
||||
return (Path(__file__).parent / "fixtures" / "transcoded_silence.mp3").read_bytes()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -27,6 +24,7 @@ def output_stream():
|
||||
@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})
|
||||
@@ -35,98 +33,60 @@ def mock_shout(output_stream, monkeypatch):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def input_queue():
|
||||
return queue.Queue()
|
||||
def audio_streamer(monkeypatch, mock_shout):
|
||||
return streamer.AudioStreamer()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def skip_event():
|
||||
return threading.Event()
|
||||
def thread(audio_streamer):
|
||||
thread = threading.Thread(target=audio_streamer.run)
|
||||
thread.daemon = True
|
||||
yield thread
|
||||
audio_streamer.shutdown_requested.set()
|
||||
thread.join()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def stop_event():
|
||||
return threading.Event()
|
||||
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
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def load_event():
|
||||
return threading.Event()
|
||||
def wait_for_not(condition, timeout=2.0):
|
||||
return wait_for(lambda: not condition(), timeout=timeout)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def audio_streamer(mock_shout, input_queue, skip_event, stop_event, load_event):
|
||||
return streamer.AudioStreamer(input_queue, skip_event, stop_event, load_event)
|
||||
|
||||
|
||||
def test_streamer_stop(audio_streamer, stop_event, output_stream):
|
||||
stop_event.set()
|
||||
audio_streamer.stream_queued_audio()
|
||||
assert not stop_event.is_set()
|
||||
|
||||
|
||||
def test_streamer_skip(audio_streamer, skip_event, output_stream):
|
||||
skip_event.set()
|
||||
audio_streamer.stream_queued_audio()
|
||||
assert not skip_event.is_set()
|
||||
|
||||
|
||||
def test_streamer_load(audio_streamer, load_event, output_stream):
|
||||
load_event.set()
|
||||
audio_streamer.stream_queued_audio()
|
||||
assert not load_event.is_set()
|
||||
|
||||
|
||||
def test_clear_queue(audio_streamer, input_queue):
|
||||
def test_streamer_clear(audio_streamer, thread):
|
||||
# enqueue some tracks
|
||||
pl = playlist.Playlist(name="test_playlist")
|
||||
for track in pl.tracks:
|
||||
input_queue.put(bytes(track))
|
||||
assert input_queue.not_empty
|
||||
audio_streamer.clear_queue()
|
||||
assert input_queue.empty
|
||||
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)
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_streamer_defaults_to_silence(audio_streamer, input_queue, output_stream, silence_bytes):
|
||||
audio_streamer.stream_queued_audio()
|
||||
track = playlist.Playlist(name="test_playlist").tracks[0]
|
||||
input_queue.put(bytes(track))
|
||||
audio_streamer.stream_queued_audio()
|
||||
audio_streamer.stream_queued_audio()
|
||||
assert get_stream_output(output_stream) == silence_bytes + track.read_bytes() + silence_bytes
|
||||
def test_streamer_shutdown(audio_streamer, thread):
|
||||
thread.start()
|
||||
audio_streamer.shutdown_requested.set()
|
||||
assert wait_for_not(audio_streamer.shutdown_requested.is_set)
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_streamer_plays_silence_on_error(monkeypatch, audio_streamer, input_queue, output_stream, silence_bytes):
|
||||
monkeypatch.setattr(audio_streamer.queue, "get", MagicMock(side_effect=Exception))
|
||||
track = playlist.Playlist(name="test_playlist").tracks[0]
|
||||
input_queue.put(bytes(track))
|
||||
audio_streamer.stream_queued_audio()
|
||||
assert get_stream_output(output_stream) == silence_bytes
|
||||
def test_streamer_skip(audio_streamer, thread):
|
||||
thread.start()
|
||||
audio_streamer.skip_requested.set()
|
||||
assert wait_for_not(audio_streamer.skip_requested.is_set)
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_streamer_plays_from_queue(audio_streamer, input_queue, output_stream):
|
||||
pl = playlist.Playlist(name="test_playlist")
|
||||
expected = b""
|
||||
for track in pl.tracks:
|
||||
input_queue.put(bytes(track))
|
||||
expected += track.read_bytes()
|
||||
while not input_queue.empty():
|
||||
audio_streamer.stream_queued_audio()
|
||||
assert get_stream_output(output_stream) == expected
|
||||
|
||||
|
||||
def test_streamer_handles_stop_interrupt(audio_streamer, output_stream, stop_event):
|
||||
stop_event.set()
|
||||
audio_streamer.stream_queued_audio()
|
||||
assert get_stream_output(output_stream) == b""
|
||||
|
||||
|
||||
def test_streamer_handles_load_interrupt(audio_streamer, input_queue, output_stream, load_event):
|
||||
pl = playlist.Playlist(name="test_playlist")
|
||||
input_queue.put(bytes(pl.tracks[0]))
|
||||
load_event.set()
|
||||
audio_streamer.stream_queued_audio()
|
||||
assert get_stream_output(output_stream) == b""
|
||||
assert input_queue.empty
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user