"""Tests for processor manager.""" import asyncio import pytest import respx from httpx import Response from wled_controller.core.processor_manager import ( ProcessorManager, ProcessingSettings, ) from wled_controller.core.calibration import create_default_calibration @pytest.fixture def wled_url(): """Provide test WLED device URL.""" return "http://192.168.1.100" @pytest.fixture def mock_wled_responses(): """Provide mock WLED API responses.""" return { "info": { "name": "Test WLED", "ver": "0.14.0", "leds": {"count": 150}, "brand": "WLED", "product": "FOSS", "mac": "AA:BB:CC:DD:EE:FF", "ip": "192.168.1.100", }, "state": {"on": True, "bri": 255}, } @pytest.fixture def processor_manager(): """Provide processor manager instance.""" return ProcessorManager() def test_processor_manager_init(): """Test processor manager initialization.""" manager = ProcessorManager() assert manager is not None assert manager.get_all_devices() == [] def test_add_device(processor_manager): """Test adding a device.""" processor_manager.add_device( device_id="test_device", device_url="http://192.168.1.100", led_count=150, ) devices = processor_manager.get_all_devices() assert "test_device" in devices def test_add_device_duplicate(processor_manager): """Test adding duplicate device fails.""" processor_manager.add_device( device_id="test_device", device_url="http://192.168.1.100", led_count=150, ) with pytest.raises(ValueError, match="already exists"): processor_manager.add_device( device_id="test_device", device_url="http://192.168.1.100", led_count=150, ) def test_remove_device(processor_manager): """Test removing a device.""" processor_manager.add_device( device_id="test_device", device_url="http://192.168.1.100", led_count=150, ) processor_manager.remove_device("test_device") assert "test_device" not in processor_manager.get_all_devices() def test_remove_device_not_found(processor_manager): """Test removing non-existent device fails.""" with pytest.raises(ValueError, match="not found"): processor_manager.remove_device("nonexistent") def test_update_settings(processor_manager): """Test updating device settings.""" processor_manager.add_device( device_id="test_device", device_url="http://192.168.1.100", led_count=150, ) new_settings = ProcessingSettings( display_index=1, fps=60, border_width=20, ) processor_manager.update_settings("test_device", new_settings) # Verify settings updated state = processor_manager.get_state("test_device") assert state["fps_target"] == 60 def test_update_calibration(processor_manager): """Test updating device calibration.""" processor_manager.add_device( device_id="test_device", device_url="http://192.168.1.100", led_count=150, ) new_calibration = create_default_calibration(150) processor_manager.update_calibration("test_device", new_calibration) def test_update_calibration_led_count_mismatch(processor_manager): """Test updating calibration with mismatched LED count fails.""" processor_manager.add_device( device_id="test_device", device_url="http://192.168.1.100", led_count=150, ) wrong_calibration = create_default_calibration(100) # Wrong count with pytest.raises(ValueError, match="does not match"): processor_manager.update_calibration("test_device", wrong_calibration) @pytest.mark.asyncio @respx.mock async def test_start_processing(processor_manager, wled_url, mock_wled_responses): """Test starting processing.""" respx.get(f"{wled_url}/json/info").mock( return_value=Response(200, json=mock_wled_responses["info"]) ) respx.post(f"{wled_url}/json/state").mock( return_value=Response(200, json={"success": True}) ) processor_manager.add_device( device_id="test_device", device_url=wled_url, led_count=150, settings=ProcessingSettings(fps=5), # Low FPS for testing ) await processor_manager.start_processing("test_device") assert processor_manager.is_processing("test_device") is True # Let it process a few frames await asyncio.sleep(0.5) # Stop processing await processor_manager.stop_processing("test_device") assert processor_manager.is_processing("test_device") is False @pytest.mark.asyncio async def test_start_processing_already_running(processor_manager): """Test starting processing when already running fails.""" # This test would need mocked WLED responses # Skipping actual connection for simplicity pass @pytest.mark.asyncio async def test_stop_processing_not_running(processor_manager): """Test stopping processing when not running.""" processor_manager.add_device( device_id="test_device", device_url="http://192.168.1.100", led_count=150, ) # Should not raise error await processor_manager.stop_processing("test_device") def test_get_state(processor_manager): """Test getting device state.""" processor_manager.add_device( device_id="test_device", device_url="http://192.168.1.100", led_count=150, settings=ProcessingSettings(fps=30, display_index=0), ) state = processor_manager.get_state("test_device") assert state["device_id"] == "test_device" assert state["processing"] is False assert state["fps_target"] == 30 assert state["display_index"] == 0 def test_get_state_not_found(processor_manager): """Test getting state for non-existent device.""" with pytest.raises(ValueError, match="not found"): processor_manager.get_state("nonexistent") def test_get_metrics(processor_manager): """Test getting device metrics.""" processor_manager.add_device( device_id="test_device", device_url="http://192.168.1.100", led_count=150, ) metrics = processor_manager.get_metrics("test_device") assert metrics["device_id"] == "test_device" assert metrics["processing"] is False assert metrics["frames_processed"] == 0 assert metrics["errors_count"] == 0 @pytest.mark.asyncio async def test_stop_all(processor_manager): """Test stopping all processors.""" processor_manager.add_device( device_id="test_device1", device_url="http://192.168.1.100", led_count=150, ) processor_manager.add_device( device_id="test_device2", device_url="http://192.168.1.101", led_count=150, ) await processor_manager.stop_all() assert processor_manager.is_processing("test_device1") is False assert processor_manager.is_processing("test_device2") is False