diff --git a/aircox_streamer/controllers/sources.py b/aircox_streamer/controllers/sources.py index 70b9e3b..dc398a6 100755 --- a/aircox_streamer/controllers/sources.py +++ b/aircox_streamer/controllers/sources.py @@ -76,7 +76,7 @@ class PlaylistSource(Source): self.program = program super().__init__(controller, id=id, **kwargs) - self.path = os.path.join(self.station.path, self.id + ".m3u") + self.path = os.path.join(self.station.path, f"{self.id}.m3u") def get_sound_queryset(self): """Get playlist's sounds queryset.""" @@ -115,23 +115,6 @@ class QueueSource(Source): queue = None """Source's queue (excluded on_air request)""" - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def push(self, *paths): - """Add the provided paths to source's play queue.""" - for path in paths: - self.controller.send(self.id, "_queue.push ", path) - - def fetch(self): - super().fetch() - queue = self.controller.send(self.id, "_queue.queue").strip() - if not queue: - self.queue = [] - return - - self.queue = queue.split(" ") - @property def requests(self): """Queue as requests metadata.""" @@ -139,3 +122,20 @@ class QueueSource(Source): for request in requests: request.fetch() return requests + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def push(self, *paths): + """Add the provided paths to source's play queue.""" + for path in paths: + self.controller.send(f"{self.id}_queue.push {path}") + + def fetch(self): + super().fetch() + queue = self.controller.send(f"{self.id}_queue.queue").strip() + if not queue: + self.queue = [] + return + + self.queue = queue.split(" ") diff --git a/aircox_streamer/tests/conftest.py b/aircox_streamer/tests/conftest.py index ffbb5e9..0d01b5b 100644 --- a/aircox_streamer/tests/conftest.py +++ b/aircox_streamer/tests/conftest.py @@ -1,9 +1,9 @@ -from datetime import datetime +from datetime import datetime, time import tzlocal import pytest -from aircox.models import Station, Port +from aircox import models from aircox_streamer import controllers from aircox_streamer.connector import Connector @@ -36,7 +36,7 @@ class FakeSocket: pass def sendall(self, data): - self.sent_data.append(data) + self.sent_data.append(data.decode()) def recv(self, count): if isinstance(self.recv_data, list): @@ -48,36 +48,76 @@ class FakeSocket: data = self.recv_data self.recv_data = self.recv_data[count:] data = data[:count] - return data.encode("utf-8") if isinstance(data, str) else data + return ( + data.encode("utf-8") if isinstance(data, str) else data + ) or b"\nEND" + + def is_sent(self, data): + """Return True if provided data have been sent.""" + # use [:-1] because connector add "\n" at sent data + return any(r for r in self.sent_data if r == data or r[:-1] == data) # -- models @pytest.fixture def station(): - station = Station(name="test", path="/tmp", default=True, active=True) + station = models.Station( + name="test", path="/tmp", default=True, active=True + ) station.save() return station @pytest.fixture def station_ports(station): - ports = [ - Port( + items = [ + models.Port( station=station, - direction=Port.DIRECTION_INPUT, - type=Port.TYPE_HTTP, + direction=models.Port.DIRECTION_INPUT, + type=models.Port.TYPE_HTTP, active=True, ), - Port( + models.Port( station=station, - direction=Port.DIRECTION_OUTPUT, - type=Port.TYPE_FILE, + direction=models.Port.DIRECTION_OUTPUT, + type=models.Port.TYPE_FILE, active=True, ), ] - for port in ports: - port.save() - return ports + models.Port.objects.bulk_create(items) + return items + + +@pytest.fixture +def program(station): + program = models.Program(title="test", station=station) + program.save() + return program + + +@pytest.fixture +def stream(program): + stream = models.Stream( + program=program, begin=time(10, 12), end=time(12, 13) + ) + stream.save() + return stream + + +@pytest.fixture +def sounds(program): + items = [ + models.Sound( + name=f"sound {i}", + program=program, + type=models.Sound.TYPE_ARCHIVE, + position=i, + file=f"sound-{i}.mp3", + ) + for i in range(0, 3) + ] + models.Sound.objects.bulk_create(items) + return items # -- connectors diff --git a/aircox_streamer/tests/test_controllers_sources.py b/aircox_streamer/tests/test_controllers_sources.py index a9d9629..7b5809f 100644 --- a/aircox_streamer/tests/test_controllers_sources.py +++ b/aircox_streamer/tests/test_controllers_sources.py @@ -1,6 +1,13 @@ +import os + import pytest -from aircox_streamer.controllers import Source +from aircox_streamer.controllers import ( + Source, + PlaylistSource, + QueueSource, + Request, +) @pytest.fixture @@ -8,6 +15,16 @@ def source(controller): return Source(controller, 13) +@pytest.fixture +def playlist_source(controller, program): + return PlaylistSource(controller, 14, program) + + +@pytest.fixture +def queue_source(controller): + return QueueSource(controller, 15) + + class TestSource: @pytest.mark.django_db def test_station(self, source, station): @@ -22,60 +39,108 @@ class TestSource: ] source.fetch() - assert f"{source.id}.remaining" in socket.sent_data - assert f"{source.id}.get" in socket.sent_data + assert socket.is_sent(f"{source.id}.remaining") + assert socket.is_sent(f"{source.id}.get") assert source.remaining == remaining - assert source["request_uri"] + assert source.request_status @pytest.mark.django_db def test_skip(self, socket, source): + socket.recv_data = "\nEND" source.skip() - assert f"{source.id}.skip" in socket.sent_data + assert socket.is_sent(f"{source.id}.skip\n") @pytest.mark.django_db def test_restart(self, socket, source): - source.skip() + source.restart() prefix = f"{source.id}.seek" assert any(r for r in socket.sent_data if r.startswith(prefix)) @pytest.mark.django_db def test_seek(self, socket, source): source.seek(10) - assert f"{source.id}.skip 10" in socket.sent_data + assert socket.is_sent(f"{source.id}.seek 10") class TestPlaylistSource: @pytest.mark.django_db - def test_get_sound_queryset(self): - pass + def test_get_sound_queryset(self, playlist_source, sounds): + query = playlist_source.get_sound_queryset() + assert all( + r.program_id == playlist_source.program.pk + and r.type == r.TYPE_ARCHIVE + for r in query + ) @pytest.mark.django_db - def test_get_playlist(self): - pass + def test_get_playlist(self, playlist_source, sounds): + expected = {r.file.path for r in sounds} + query = playlist_source.get_playlist() + assert all(r in expected for r in query) @pytest.mark.django_db - def test_write_playlist(self): - pass + def test_write_playlist(self, playlist_source): + playlist = ["/tmp/a", "/tmp/b"] + playlist_source.write_playlist(playlist) + with open(playlist_source.path, "r") as file: + result = file.read() + os.remove(playlist_source.path) + + assert result == "\n".join(playlist) @pytest.mark.django_db - def test_stream(self): - pass + def test_stream(self, playlist_source, stream): + result = playlist_source.stream() + assert result == { + "begin": stream.begin.strftime("%Hh%M"), + "end": stream.end.strftime("%Hh%M"), + "delay": 0, + } @pytest.mark.django_db - def test_sync(self): - pass + def test_sync(self, playlist_source): + # spoof method + playlist = ["/tmp/a", "/tmp/b"] + written_playlist = [] + playlist_source.get_playlist = lambda: playlist + playlist_source.write_playlist = lambda p: written_playlist.extend(p) + + playlist_source.sync() + assert written_playlist == playlist class TestQueueSource: @pytest.mark.django_db - def test_push(self): - pass + def test_requests(self, queue_source, socket, metadata_string): + queue_source.queue = [13, 14, 15] + socket.recv_data = [ + f"{metadata_string}\nEND" for _ in queue_source.queue + ] + + requests = queue_source.requests + + assert all(isinstance(r, Request) for r in requests) + assert all(r.uri for r in requests) @pytest.mark.django_db - def test_fetch(self): - pass + def test_push(self, queue_source, socket): + paths = ["/tmp/a", "/tmp/b"] + queue_source.push(*paths) + assert all( + socket.is_sent(f"{queue_source.id}_queue.push {path}") + for path in paths + ) @pytest.mark.django_db - def test_requests(self): - pass + def test_fetch(self, queue_source, socket, metadata_string): + queue = ["13", "14", "15"] + socket.recv_data = [ + # Source fetch remaining & metadata + "13 END", + metadata_string, + " ".join(queue) + "\nEND", + ] + queue_source.fetch() + assert queue_source.uri + assert queue_source.queue == queue