1a9c92b6db
Includes edge-node (FastAPI/MQTT/Discord voice), op25-container (SDR decoder), and icecast (audio streaming).
132 lines
4.2 KiB
Python
132 lines
4.2 KiB
Python
"""
|
|
Unit tests for config_manager — pure file I/O, no external services.
|
|
"""
|
|
import json
|
|
import pytest
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
from app.models import NodeConfig, SystemConfig
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# save / load round-trip
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def test_save_and_load_roundtrip(tmp_path):
|
|
config = NodeConfig(
|
|
node_id="test-node-01",
|
|
node_name="Test Node",
|
|
lat=40.7128,
|
|
lon=-74.0060,
|
|
configured=True,
|
|
assigned_system_id="sys-001",
|
|
)
|
|
|
|
config_file = tmp_path / "node_config.json"
|
|
with patch("app.internal.config_manager._CONFIG_FILE", config_file):
|
|
import app.internal.config_manager as cm
|
|
cm.save_node_config(config)
|
|
loaded = cm.load_node_config()
|
|
|
|
assert loaded.node_id == config.node_id
|
|
assert loaded.node_name == config.node_name
|
|
assert loaded.lat == pytest.approx(config.lat)
|
|
assert loaded.lon == pytest.approx(config.lon)
|
|
assert loaded.configured is True
|
|
assert loaded.assigned_system_id == "sys-001"
|
|
|
|
|
|
def test_save_writes_valid_json(tmp_path):
|
|
config = NodeConfig(
|
|
node_id="node-x",
|
|
node_name="X",
|
|
lat=1.0,
|
|
lon=2.0,
|
|
)
|
|
config_file = tmp_path / "node_config.json"
|
|
with patch("app.internal.config_manager._CONFIG_FILE", config_file):
|
|
import app.internal.config_manager as cm
|
|
cm.save_node_config(config)
|
|
|
|
data = json.loads(config_file.read_text())
|
|
assert data["node_id"] == "node-x"
|
|
assert data["configured"] is False
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# load fallback behaviour
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def test_load_missing_file_returns_defaults(tmp_path):
|
|
config_file = tmp_path / "nonexistent.json"
|
|
with patch("app.internal.config_manager._CONFIG_FILE", config_file):
|
|
import app.internal.config_manager as cm
|
|
result = cm.load_node_config()
|
|
|
|
assert result.configured is False
|
|
|
|
|
|
def test_load_invalid_json_returns_defaults(tmp_path):
|
|
config_file = tmp_path / "node_config.json"
|
|
config_file.write_text("not valid json {{{")
|
|
|
|
with patch("app.internal.config_manager._CONFIG_FILE", config_file):
|
|
import app.internal.config_manager as cm
|
|
result = cm.load_node_config()
|
|
|
|
assert result.configured is False
|
|
|
|
|
|
def test_load_partial_json_returns_defaults(tmp_path):
|
|
"""A truncated file (e.g. mid-write crash) should fall back to defaults."""
|
|
config_file = tmp_path / "node_config.json"
|
|
config_file.write_text('{"node_id": "x"') # truncated
|
|
|
|
with patch("app.internal.config_manager._CONFIG_FILE", config_file):
|
|
import app.internal.config_manager as cm
|
|
result = cm.load_node_config()
|
|
|
|
assert result.configured is False
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# apply_system_config
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def test_apply_system_config_writes_json(tmp_path):
|
|
system = SystemConfig(
|
|
system_id="sys-001",
|
|
name="Test System",
|
|
type="P25",
|
|
config={"freq": 851.0125, "nac": 0x293},
|
|
)
|
|
|
|
with patch("app.internal.config_manager.settings") as mock_settings:
|
|
mock_settings.config_path = str(tmp_path)
|
|
import app.internal.config_manager as cm
|
|
result = cm.apply_system_config(system)
|
|
|
|
assert result is True
|
|
written = json.loads((tmp_path / "active.cfg.json").read_text())
|
|
assert written["freq"] == pytest.approx(851.0125)
|
|
assert written["nac"] == 0x293
|
|
|
|
|
|
def test_apply_system_config_returns_false_on_error(tmp_path):
|
|
system = SystemConfig(
|
|
system_id="sys-001",
|
|
name="Test",
|
|
type="DMR",
|
|
config={},
|
|
)
|
|
|
|
with patch("app.internal.config_manager.settings") as mock_settings:
|
|
# Point at a path that can't be written (a file, not a dir)
|
|
blocker = tmp_path / "blocker"
|
|
blocker.touch()
|
|
mock_settings.config_path = str(blocker)
|
|
import app.internal.config_manager as cm
|
|
result = cm.apply_system_config(system)
|
|
|
|
assert result is False
|