session_config wird nicht mehr über die API/YAML gesendet. parser_config ist jetzt das einzige Config-Format zwischen Odoo und Bridge. Änderungen: - api/models.py: DeviceConfig.session_config → parser_config: dict SessionConfig bleibt als internes Modell für SessionDetector DeviceConfig.to_session_config() extrahiert Werte mit Defaults - config/schema.py: DeviceConfig gleich umgestellt + to_session_config() - config/loader.py: liest parser_config aus YAML, Fallback für legacy session_config (Rückwärtskompatibilität für bestehende config-active.yaml) - core/device_manager.py: device.session_config → device.to_session_config() - core/service_manager.py: session_config Referenzen entfernt - Odoo _build_bridge_config: sendet parser_config direkt (+ heartbeat) - Odoo iot_api.py: gleich umgestellt - Tests: alle SessionConfig-Fixtures → parser_config dicts 63/63 passing
85 lines
2.7 KiB
Python
85 lines
2.7 KiB
Python
"""Unit tests for DeviceManager lifecycle operations."""
|
|
|
|
from unittest.mock import Mock, patch
|
|
|
|
from api.models import BridgeConfig, DeviceConfig
|
|
from core.device_manager import DeviceManager
|
|
|
|
|
|
def _device_config(device_id: str, topic: str) -> DeviceConfig:
|
|
return DeviceConfig(
|
|
device_id=device_id,
|
|
machine_name=f"Machine {device_id}",
|
|
mqtt_topic=topic,
|
|
parser_type="shelly_pm",
|
|
device_status_timeout_s=120,
|
|
parser_config={
|
|
"standby_threshold_w": 20,
|
|
"working_threshold_w": 100,
|
|
"start_debounce_s": 3,
|
|
"stop_debounce_s": 15,
|
|
"message_timeout_s": 20,
|
|
"heartbeat_interval_s": 60,
|
|
},
|
|
)
|
|
|
|
|
|
def test_apply_config_adds_device_and_subscribes() -> None:
|
|
mqtt_client = Mock()
|
|
event_queue = Mock()
|
|
|
|
manager = DeviceManager(mqtt_client=mqtt_client, event_queue=event_queue)
|
|
|
|
config = BridgeConfig(mqtt=None, devices=[_device_config("dev-1", "dev-1/status/pm1:0")], version="1.0")
|
|
manager.apply_config(config)
|
|
|
|
mqtt_client.subscribe.assert_called_once_with("dev-1/status/pm1:0")
|
|
assert "dev-1" in manager.session_detectors
|
|
assert manager.device_map["dev-1/status/pm1:0"] == "dev-1"
|
|
|
|
|
|
def test_apply_config_removes_device_and_unsubscribes() -> None:
|
|
mqtt_client = Mock()
|
|
event_queue = Mock()
|
|
|
|
manager = DeviceManager(mqtt_client=mqtt_client, event_queue=event_queue)
|
|
start_config = BridgeConfig(mqtt=None, devices=[_device_config("dev-1", "dev-1/status/pm1:0")], version="1.0")
|
|
manager.apply_config(start_config)
|
|
|
|
mqtt_client.reset_mock()
|
|
|
|
manager.apply_config(BridgeConfig(mqtt=None, devices=[], version="1.0"))
|
|
|
|
mqtt_client.unsubscribe.assert_called_once_with("dev-1/status/pm1:0")
|
|
assert "dev-1" not in manager.session_detectors
|
|
assert "dev-1/status/pm1:0" not in manager.device_map
|
|
|
|
|
|
def test_route_message_updates_status_monitor_and_processes_power() -> None:
|
|
mqtt_client = Mock()
|
|
event_queue = Mock()
|
|
status_monitor = Mock()
|
|
|
|
mock_parser = Mock()
|
|
mock_parser.parse_message.return_value = {"apower": 123.4}
|
|
|
|
manager = DeviceManager(
|
|
mqtt_client=mqtt_client,
|
|
event_queue=event_queue,
|
|
status_monitor=status_monitor,
|
|
)
|
|
|
|
with patch("core.device_manager.get_parser", return_value=mock_parser):
|
|
manager.apply_config(
|
|
BridgeConfig(
|
|
mqtt=None,
|
|
devices=[_device_config("dev-1", "dev-1/status/pm1:0")],
|
|
version="1.0",
|
|
)
|
|
)
|
|
|
|
manager.route_message("dev-1/status/pm1:0", {"apower": 123.4})
|
|
|
|
status_monitor.update_last_seen.assert_called_once_with("dev-1")
|
|
mock_parser.parse_message.assert_called_once()
|