Phase 1-4: Audio stack, mixer engine, MIDI, and network API
Lint & Validate / lint (push) Has been cancelled

P2-R1: ALSA + JACK2 low-latency config (scripts, quirks, tuning)
P2-R2: Carla integration (build scripts, 8ch rack config, NAM LV2 support)
P2-R3: Plugin manager, categories, blacklist, NAM model support
P3-R1: Mixer DSP engine (channel strip, routing matrix, bus mgr, automation)
P4-R1: MIDI engine (learn mode, clock sync, HID discovery, mapping store)
P4-R2: Network API (OSC server, FastAPI REST, WebSocket, auth, rate limiter)
P5-R1: Touchscreen UI evaluation + main entry point
docs: Audio stack, Carla integration, MIDI support, UI evaluation
tests: Full test suite (292 passing)
This commit is contained in:
2026-05-19 20:39:17 -04:00
parent 7b123762b5
commit 9cd8292acc
97 changed files with 26545 additions and 5 deletions
+162
View File
@@ -0,0 +1,162 @@
"""Tests for WebSocket manager."""
import asyncio
import json
import pytest
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.testclient import TestClient
from src.network.websocket import WebSocketManager
from src.network.schemas import (
MixerStateSchema,
ChannelSchema,
WSMessage,
WSMessageType,
)
from src.network.auth import APIKeyAuth
from src.network.rate_limiter import RateLimiter
class TestWebSocketManager:
"""Tests for WebSocketManager (unit tests for the manager class)."""
@pytest.fixture
def manager(self):
return WebSocketManager(max_connections=10)
def test_initial_state(self, manager):
assert manager.connected_clients == 0
stats = manager.stats
assert stats["connected_clients"] == 0
assert stats["total_connections"] == 0
assert stats["total_broadcasts"] == 0
def test_set_state_provider(self, manager):
called = []
def get_state():
called.append(True)
return MixerStateSchema(
channels=[ChannelSchema(channel=0)],
)
manager.set_state_provider(get_state)
assert manager._state_provider is not None
def test_set_parameter_handler(self, manager):
calls = []
def handler(pt, v, ch):
calls.append((pt, v, ch))
manager.set_parameter_handler(handler)
assert manager._parameter_handler is not None
def test_set_transport_handler(self, manager):
calls = []
def handler(cmd):
calls.append(cmd)
manager.set_transport_handler(handler)
assert manager._transport_handler is not None
def test_max_connections_property(self, manager):
assert manager._max_connections == 10
class TestWebSocketBroadcast:
"""Tests for WebSocket broadcasting logic."""
@pytest.fixture
def manager(self):
mgr = WebSocketManager(max_connections=10)
return mgr
@pytest.mark.asyncio
async def test_broadcast_no_clients(self, manager):
msg = WSMessage(
type=WSMessageType.PARAMETER_UPDATE,
payload={"param_type": "volume", "value": -3.0, "channel": 0},
)
count = await manager.broadcast(msg)
assert count == 0
@pytest.mark.asyncio
async def test_broadcast_parameter_update_no_clients(self, manager):
count = await manager.broadcast_parameter_update("volume", -3.0, 0)
assert count == 0
@pytest.mark.asyncio
async def test_broadcast_transport_no_clients(self, manager):
count = await manager.broadcast_transport_update({"command": "play"})
assert count == 0
@pytest.mark.asyncio
async def test_client_add_remove(self, manager):
"""Test client bookkeeping (without actual WebSocket)."""
assert manager.connected_clients == 0
# Simulate adding a client
async with manager._lock:
manager._clients["test-client"] = "mock-ws"
manager._total_connections += 1
assert manager.connected_clients == 1
assert manager.stats["total_connections"] == 1
# Remove client
await manager._remove_client("test-client")
assert manager.connected_clients == 0
class TestWebSocketStats:
"""Tests for WebSocket statistics."""
def test_stats_structure(self):
manager = WebSocketManager(max_connections=5)
stats = manager.stats
assert "connected_clients" in stats
assert "total_connections" in stats
assert "total_messages" in stats
assert "total_broadcasts" in stats
assert "uptime_seconds" in stats
assert "max_connections" in stats
assert stats["max_connections"] == 5
def test_uptime_increases(self):
manager = WebSocketManager()
stats1 = manager.stats
# Stats should have a reasonable uptime
assert stats1["uptime_seconds"] >= 0
class TestWebSocketMessageTypes:
"""Tests for WebSocket message type handling."""
def test_ws_message_serialization(self):
msg = WSMessage(
type=WSMessageType.FULL_STATE,
payload={"channels": [], "master": {"volume_db": 0.0}},
)
data = msg.model_dump()
assert data["type"] == "full_state"
def test_all_message_types(self):
for msg_type in WSMessageType:
msg = WSMessage(type=msg_type, payload={})
assert msg.type == msg_type
assert msg.payload == {}
def test_parameter_update_message(self):
msg = WSMessage(
type=WSMessageType.PARAMETER_UPDATE,
payload={
"param_type": "comp_threshold",
"value": -15.0,
"channel": 2,
},
)
assert msg.payload["param_type"] == "comp_threshold"
assert msg.payload["value"] == -15.0