Files
gps-denied-onboard/test_f17_configuration_manager.py
T
Denys Zaitsev d7e1066c60 Initial commit
2026-04-03 23:25:54 +03:00

157 lines
5.5 KiB
Python

import pytest
import os
import yaml
import tempfile
from unittest.mock import Mock
from f02_1_flight_lifecycle_manager import CameraParameters
from f17_configuration_manager import (
ConfigurationManager, SystemConfig, OperationalArea,
ModelPaths, FlightConfig
)
@pytest.fixture
def valid_yaml_content():
return """
camera:
focal_length_mm: 35.0
sensor_width_mm: 36.0
resolution:
width: 3840
height: 2160
operational_area:
name: "Test Area"
min_lat: 40.0
max_lat: 45.0
min_lon: -10.0
max_lon: 10.0
"""
@pytest.fixture
def temp_config_file(valid_yaml_content):
fd, path = tempfile.mkstemp(suffix=".yaml")
with os.fdopen(fd, 'w') as f:
f.write(valid_yaml_content)
yield path
os.remove(path)
@pytest.fixture
def mock_db():
db = Mock()
flight_mock = Mock()
flight_mock.camera_params = CameraParameters(focal_length_mm=25, sensor_width_mm=36, resolution={"width": 1920, "height": 1080})
flight_mock.altitude_m = 400.0
db.get_flight_by_id.return_value = flight_mock
return db
@pytest.fixture
def cm(mock_db):
return ConfigurationManager(f03_database=mock_db)
class TestConfigurationManager:
# --- 17.01 Feature: System Configuration ---
def test_load_config_valid_yaml(self, cm, temp_config_file):
config = cm.load_config(temp_config_file)
assert isinstance(config, SystemConfig)
assert config.camera.focal_length_mm == 35.0
assert config.operational_area.name == "Test Area"
def test_load_config_missing_file_uses_defaults(self, cm):
config = cm.load_config("nonexistent_file.yaml")
assert config.camera.focal_length_mm == 25.0 # Default value
assert config.operational_area.name == "Eastern Ukraine"
def test_load_config_invalid_yaml_raises_error(self, cm):
fd, path = tempfile.mkstemp(suffix=".yaml")
with os.fdopen(fd, 'w') as f:
f.write("invalid: yaml: : syntax")
with pytest.raises(ValueError, match="Malformed YAML"):
cm.load_config(path)
os.remove(path)
def test_load_config_partial_uses_defaults(self, cm):
fd, path = tempfile.mkstemp(suffix=".yaml")
with os.fdopen(fd, 'w') as f:
f.write("camera:\n focal_length_mm: 50.0\n")
config = cm.load_config(path)
assert config.camera.focal_length_mm == 50.0
assert config.camera.sensor_width_mm == 36.0 # Kept default
assert config.database.url == "sqlite:///flights.db" # Default database
os.remove(path)
def test_validate_config_valid(self, cm):
config = cm._apply_defaults({})
val = cm.validate_config(config)
assert val.is_valid is True
def test_validate_config_invalid_focal_length(self, cm):
config = cm._apply_defaults({})
config.camera.focal_length_mm = -10.0
val = cm.validate_config(config)
assert val.is_valid is False
assert any("Focal length" in e for e in val.errors)
def test_validate_config_invalid_operational_area(self, cm):
config = cm._apply_defaults({})
config.operational_area.min_lat = 100.0 # Invalid lat
val = cm.validate_config(config)
assert val.is_valid is False
assert any("latitude bounds" in e for e in val.errors)
def test_get_camera_params_default(self, cm, temp_config_file):
cm.load_config(temp_config_file)
params = cm.get_camera_params()
assert params.focal_length_mm == 35.0
assert params.resolution["width"] == 3840
def test_update_config_valid_key(self, cm, temp_config_file):
cm.load_config(temp_config_file)
assert cm.update_config("operational_area", "name", "Western Ukraine") is True
assert cm._system_config.operational_area.name == "Western Ukraine"
def test_update_config_invalid_section(self, cm, temp_config_file):
cm.load_config(temp_config_file)
assert cm.update_config("nonexistent", "key", "value") is False
# --- 17.02 Feature: Flight Configuration ---
def test_get_flight_config_existing_via_db(self, cm):
# Should use mock_db to fetch the config
config = cm.get_flight_config("flight_123")
assert isinstance(config, FlightConfig)
assert config.altitude == 400.0
assert config.camera_params.focal_length_mm == 25.0
def test_get_flight_config_nonexistent(self, cm):
cm.db.get_flight_by_id.return_value = None
with pytest.raises(ValueError, match="not found"):
cm.get_flight_config("missing_flight")
def test_save_flight_config_valid(self, cm):
config = FlightConfig(
camera_params=CameraParameters(focal_length_mm=50, sensor_width_mm=36, resolution={"width": 100, "height": 100}),
altitude=300.0
)
assert cm.save_flight_config("flight_saved", config) is True
# Verify retrieval via cache instead of DB
retrieved = cm.get_flight_config("flight_saved")
assert retrieved.altitude == 300.0
def test_save_flight_config_invalid_flight_id(self, cm):
assert cm.save_flight_config("", None) is False
def test_get_operational_altitude_existing(self, cm):
assert cm.get_operational_altitude("flight_123") == 400.0
def test_get_frame_spacing_existing(self, cm):
assert cm.get_frame_spacing("flight_123") == 100.0
def test_get_frame_spacing_default(self, cm):
cm.db.get_flight_by_id.return_value = None
# Should fallback to default 100.0 on error
assert cm.get_frame_spacing("missing_flight") == 100.0