"""Unit tests for bootstrap configuration loading behavior.""" import importlib from pathlib import Path from unittest.mock import Mock import yaml from config.schema import ( BridgeConfig, DeviceStatusConfig, EventQueueConfig, LoggingConfig, MQTTConfig, OdooConfig, ) from core.bootstrap import get_mqtt_config, load_bridge_config from exceptions import ConfigurationError def _base_config() -> BridgeConfig: return BridgeConfig( mqtt=MQTTConfig(broker="yaml-broker", port=1883, client_id="bridge"), odoo=OdooConfig(use_mock=True), logging=LoggingConfig(), event_queue=EventQueueConfig(), device_status=DeviceStatusConfig(), devices=[], ) def test_load_bridge_config_returns_none_on_missing_main_config(monkeypatch): bootstrap_module = importlib.import_module("core.bootstrap") def fail_load_config(_path): raise ConfigurationError("missing") monkeypatch.setattr(bootstrap_module, "load_config", fail_load_config) config = load_bridge_config("missing.yaml", Path("/tmp/no-active.yaml"), logger=None) assert config is None def test_load_bridge_config_merges_persisted_mqtt_and_devices(monkeypatch, tmp_path): bootstrap_module = importlib.import_module("core.bootstrap") active_path = tmp_path / "config-active.yaml" active_path.write_text( yaml.safe_dump( { "mqtt": { "broker": "persisted-broker", "port": 1884, "username": "mqtt-user", "password": "secret", "client_id": "persisted-client", "keepalive": 30, "use_tls": True, }, "devices": [ { "device_id": "dev-1", "mqtt_topic": "shelly/dev-1/status", "parser_type": "shelly_pm", "machine_name": "Machine 1", "session_config": { "standby_threshold_w": 5, "working_threshold_w": 20, "start_debounce_s": 3, "stop_debounce_s": 15, "message_timeout_s": 20, "heartbeat_interval_s": 60, }, } ], } ) ) expected_devices = [Mock(device_id="dev-1")] monkeypatch.setattr(bootstrap_module, "load_config", lambda _path: _base_config()) monkeypatch.setattr( bootstrap_module, "load_devices_from_config", lambda _path: expected_devices, ) config = load_bridge_config("config.yaml", active_path, logger=None) assert config is not None assert config.devices == expected_devices assert config.mqtt.broker == "persisted-broker" assert config.mqtt.port == 1884 assert config.mqtt.use_tls is True def test_get_mqtt_config_falls_back_to_environment(monkeypatch): monkeypatch.setenv("MQTT_BROKER", "env-broker") monkeypatch.setenv("MQTT_PORT", "1999") monkeypatch.setenv("MQTT_USERNAME", "env-user") monkeypatch.setenv("MQTT_PASSWORD", "env-password") monkeypatch.setenv("MQTT_CLIENT_ID", "env-client") monkeypatch.setenv("MQTT_USE_TLS", "true") mqtt_config = get_mqtt_config(config=None) assert mqtt_config.broker == "env-broker" assert mqtt_config.port == 1999 assert mqtt_config.username == "env-user" assert mqtt_config.password == "env-password" assert mqtt_config.client_id == "env-client" assert mqtt_config.use_tls is True