100 lines
3.2 KiB
Python
100 lines
3.2 KiB
Python
import asyncio
|
|
import json
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from server.streaming import StreamManager
|
|
|
|
|
|
@pytest.fixture
|
|
def manager():
|
|
return StreamManager()
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_ws():
|
|
ws = AsyncMock()
|
|
ws.send_text = AsyncMock()
|
|
return ws
|
|
|
|
|
|
class TestClientManagement:
|
|
def test_add_client(self, manager, mock_ws):
|
|
"""Adding a client increases count."""
|
|
manager.add_client(mock_ws)
|
|
assert manager.client_count == 1
|
|
|
|
def test_remove_client(self, manager, mock_ws):
|
|
"""Removing a client decreases count."""
|
|
manager.add_client(mock_ws)
|
|
manager.remove_client(mock_ws)
|
|
assert manager.client_count == 0
|
|
|
|
def test_remove_missing_client(self, manager, mock_ws):
|
|
"""Removing a non-existent client doesn't error."""
|
|
manager.remove_client(mock_ws)
|
|
assert manager.client_count == 0
|
|
|
|
|
|
class TestBroadcast:
|
|
@pytest.mark.asyncio
|
|
async def test_broadcast_phase(self, manager, mock_ws):
|
|
"""Phase update is broadcast to all clients."""
|
|
manager.add_client(mock_ws)
|
|
await manager.broadcast_phase(
|
|
intensity=2.4,
|
|
params={"morph_speed": 0.35, "shader_severity": 0.6, "palette": "crimson_void"},
|
|
)
|
|
mock_ws.send_text.assert_called_once()
|
|
msg = json.loads(mock_ws.send_text.call_args[0][0])
|
|
assert msg["type"] == "phase"
|
|
assert msg["intensity"] == 2.4
|
|
assert msg["params"]["morph_speed"] == 0.35
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_broadcast_asset(self, manager, mock_ws):
|
|
"""Asset notification is broadcast."""
|
|
manager.add_client(mock_ws)
|
|
await manager.broadcast_asset(
|
|
url="/assets/img/abc.png",
|
|
severity=1.8,
|
|
transition="melt",
|
|
)
|
|
msg = json.loads(mock_ws.send_text.call_args[0][0])
|
|
assert msg["type"] == "asset"
|
|
assert msg["url"] == "/assets/img/abc.png"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_broadcast_whisper(self, manager, mock_ws):
|
|
"""Whisper notification is broadcast."""
|
|
manager.add_client(mock_ws)
|
|
await manager.broadcast_whisper(
|
|
url="/assets/audio/w01.wav",
|
|
pan=-0.3,
|
|
volume=0.4,
|
|
reverb=0.7,
|
|
)
|
|
msg = json.loads(mock_ws.send_text.call_args[0][0])
|
|
assert msg["type"] == "whisper"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_broadcast_scare(self, manager, mock_ws):
|
|
"""Scare event is broadcast."""
|
|
manager.add_client(mock_ws)
|
|
await manager.broadcast_scare(effect="face_flash", duration_ms=150)
|
|
msg = json.loads(mock_ws.send_text.call_args[0][0])
|
|
assert msg["type"] == "scare"
|
|
assert msg["effect"] == "face_flash"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_dead_client_cleanup(self, manager):
|
|
"""Dead clients are removed on broadcast."""
|
|
dead_ws = AsyncMock()
|
|
dead_ws.send_text = AsyncMock(side_effect=Exception("connection closed"))
|
|
manager.add_client(dead_ws)
|
|
assert manager.client_count == 1
|
|
|
|
await manager.broadcast_phase(intensity=1.0, params={})
|
|
assert manager.client_count == 0
|