from __future__ import annotations import asyncio import tempfile import threading import unittest from pathlib import Path from unittest.mock import patch from restream_playout import PlayoutEngine from restream_playout.rtmp import RTMP_AUDIO, RTMP_DATA_AMF0, RTMP_VIDEO from .mp4_builder import write_test_mp4 class _FakeSession: messages: list[tuple[int, int, bytes]] = [] def __init__(self, rtmp_url: str, *, stop_event: asyncio.Event, state_callback: object, **kwargs: object) -> None: self.stop_event = stop_event self.state_callback = state_callback self.generation = 1 self._announced = False async def ensure_connected(self) -> int: if not self._announced: self._announced = True await self.state_callback(True) return self.generation async def send_message( self, message_type: int, timestamp: int, payload: bytes, *, chunk_stream_id: int = 5, ) -> None: self.messages.append((message_type, timestamp, payload)) async def close(self) -> None: if self._announced: await self.state_callback(False) class EngineTests(unittest.TestCase): def test_dynamic_insertion_switches_from_filler_and_finishes_clip(self) -> None: with tempfile.TemporaryDirectory() as directory: clip_path = Path(directory, "dynamic.mp4") write_test_mp4(clip_path) started = threading.Event() finished = threading.Event() connected = threading.Event() _FakeSession.messages = [] with patch("restream_playout.engine.StreamSession", _FakeSession): engine = PlayoutEngine("rtmp://localhost/live/key") engine.on_clip_started(lambda path: started.set()) engine.on_clip_finished(lambda path: finished.set()) engine.on_stream_connected(lambda: connected.set()) engine.start() self.assertTrue(connected.wait(2)) engine.enqueue(clip_path) self.assertTrue(started.wait(2)) self.assertTrue(finished.wait(2)) engine.stop() message_types = {message_type for message_type, _, _ in _FakeSession.messages} self.assertEqual(message_types, {RTMP_AUDIO, RTMP_DATA_AMF0, RTMP_VIDEO}) timestamps = [timestamp for _, timestamp, _ in _FakeSession.messages] self.assertEqual(timestamps, sorted(timestamps))