mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 13:02:59 +00:00
fix(test): repair test infrastructure and mock fixtures (#281)
* fix(test): repair test infrastructure and mock fixtures - Add test/__init__.py for proper test collection - Fix ConfigManager instantiation to use config_path parameter - Route schedule config through config_service mock - Update mock to match get_raw_file_content endpoint change Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(test): correct get_main_config assertion per CodeRabbit review The endpoint calls load_config(), not get_raw_file_content('main'). Also set up load_config mock return value in the fixture so the test's data assertions pass correctly. Co-Authored-By: 5ymb01 <noreply@github.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(test): correct plugin config test mock structure and schema returns - Plugin configs live at top-level keys, not under 'plugins' subkey - Mock schema_manager.generate_default_config to return a dict - Mock schema_manager.merge_with_defaults to merge dicts (not MagicMock) - Fixes test_get_plugin_config returning 500 due to non-serializable MagicMock Co-Authored-By: 5ymb01 <noreply@github.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(test): use patch.object for config_service.get_config in schedule tests config_service.get_config is a real method, not a mock — can't set return_value on it directly. Use patch.object context manager instead. Co-Authored-By: 5ymb01 <noreply@github.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: 5ymb01 <5ymb01@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: 5ymb01 <noreply@github.com>
This commit is contained in:
1
test/__init__.py
Normal file
1
test/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Test package
|
||||
@@ -23,6 +23,7 @@ if str(project_root) not in sys.path:
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
from src.config_manager import ConfigManager
|
||||
from src.exceptions import ConfigError
|
||||
from src.plugin_system.schema_manager import SchemaManager
|
||||
|
||||
|
||||
@@ -30,35 +31,31 @@ class TestInvalidJson:
|
||||
"""Test handling of invalid JSON in config files."""
|
||||
|
||||
def test_invalid_json_syntax(self, tmp_path):
|
||||
"""Config with invalid JSON syntax should be handled gracefully."""
|
||||
"""Config with invalid JSON syntax should raise ConfigError."""
|
||||
config_file = tmp_path / "config.json"
|
||||
config_file.write_text("{ invalid json }")
|
||||
|
||||
with patch.object(ConfigManager, '_get_config_path', return_value=str(config_file)):
|
||||
config_manager = ConfigManager(config_dir=str(tmp_path))
|
||||
# Should not raise, should return empty or default config
|
||||
config = config_manager.load_config()
|
||||
assert isinstance(config, dict)
|
||||
config_manager = ConfigManager(config_path=str(config_file))
|
||||
with pytest.raises(ConfigError):
|
||||
config_manager.load_config()
|
||||
|
||||
def test_truncated_json(self, tmp_path):
|
||||
"""Config with truncated JSON should be handled gracefully."""
|
||||
"""Config with truncated JSON should raise ConfigError."""
|
||||
config_file = tmp_path / "config.json"
|
||||
config_file.write_text('{"plugin": {"enabled": true') # Missing closing braces
|
||||
|
||||
with patch.object(ConfigManager, '_get_config_path', return_value=str(config_file)):
|
||||
config_manager = ConfigManager(config_dir=str(tmp_path))
|
||||
config = config_manager.load_config()
|
||||
assert isinstance(config, dict)
|
||||
config_manager = ConfigManager(config_path=str(config_file))
|
||||
with pytest.raises(ConfigError):
|
||||
config_manager.load_config()
|
||||
|
||||
def test_empty_config_file(self, tmp_path):
|
||||
"""Empty config file should be handled gracefully."""
|
||||
"""Empty config file should raise ConfigError."""
|
||||
config_file = tmp_path / "config.json"
|
||||
config_file.write_text("")
|
||||
|
||||
with patch.object(ConfigManager, '_get_config_path', return_value=str(config_file)):
|
||||
config_manager = ConfigManager(config_dir=str(tmp_path))
|
||||
config = config_manager.load_config()
|
||||
assert isinstance(config, dict)
|
||||
config_manager = ConfigManager(config_path=str(config_file))
|
||||
with pytest.raises(ConfigError):
|
||||
config_manager.load_config()
|
||||
|
||||
|
||||
class TestTypeValidation:
|
||||
|
||||
@@ -209,49 +209,47 @@ class TestDisplayControllerSchedule:
|
||||
def test_schedule_disabled(self, test_display_controller):
|
||||
"""Test when schedule is disabled."""
|
||||
controller = test_display_controller
|
||||
controller.config = {"schedule": {"enabled": False}}
|
||||
|
||||
controller._check_schedule()
|
||||
assert controller.is_display_active is True
|
||||
|
||||
schedule_config = {"schedule": {"enabled": False}}
|
||||
with patch.object(controller.config_service, 'get_config', return_value=schedule_config):
|
||||
controller._check_schedule()
|
||||
assert controller.is_display_active is True
|
||||
|
||||
def test_active_hours(self, test_display_controller):
|
||||
"""Test active hours check."""
|
||||
controller = test_display_controller
|
||||
# Mock datetime to be within active hours
|
||||
with patch('src.display_controller.datetime') as mock_datetime:
|
||||
mock_datetime.now.return_value.strftime.return_value.lower.return_value = "monday"
|
||||
mock_datetime.now.return_value.time.return_value = datetime.strptime("12:00", "%H:%M").time()
|
||||
mock_datetime.strptime = datetime.strptime
|
||||
|
||||
controller.config = {
|
||||
|
||||
schedule_config = {
|
||||
"schedule": {
|
||||
"enabled": True,
|
||||
"start_time": "09:00",
|
||||
"end_time": "17:00"
|
||||
}
|
||||
}
|
||||
|
||||
controller._check_schedule()
|
||||
assert controller.is_display_active is True
|
||||
with patch.object(controller.config_service, 'get_config', return_value=schedule_config):
|
||||
controller._check_schedule()
|
||||
assert controller.is_display_active is True
|
||||
|
||||
def test_inactive_hours(self, test_display_controller):
|
||||
"""Test inactive hours check."""
|
||||
controller = test_display_controller
|
||||
# Mock datetime to be outside active hours
|
||||
with patch('src.display_controller.datetime') as mock_datetime:
|
||||
mock_datetime.now.return_value.strftime.return_value.lower.return_value = "monday"
|
||||
mock_datetime.now.return_value.time.return_value = datetime.strptime("20:00", "%H:%M").time()
|
||||
mock_datetime.strptime = datetime.strptime
|
||||
|
||||
controller.config = {
|
||||
|
||||
schedule_config = {
|
||||
"schedule": {
|
||||
"enabled": True,
|
||||
"start_time": "09:00",
|
||||
"end_time": "17:00"
|
||||
}
|
||||
}
|
||||
|
||||
controller._check_schedule()
|
||||
assert controller.is_display_active is False
|
||||
with patch.object(controller.config_service, 'get_config', return_value=schedule_config):
|
||||
controller._check_schedule()
|
||||
assert controller.is_display_active is False
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
@@ -29,7 +29,13 @@ def mock_config_manager():
|
||||
}
|
||||
mock.get_config_path.return_value = 'config/config.json'
|
||||
mock.get_secrets_path.return_value = 'config/config_secrets.json'
|
||||
mock.get_raw_file_content.return_value = {'weather': {'api_key': 'test'}}
|
||||
mock_config = {
|
||||
'display': {'brightness': 50},
|
||||
'plugins': {},
|
||||
'timezone': 'UTC'
|
||||
}
|
||||
mock.load_config.return_value = mock_config
|
||||
mock.get_raw_file_content.return_value = mock_config
|
||||
mock.save_config_atomic.return_value = MagicMock(
|
||||
status=MagicMock(value='success'),
|
||||
message=None
|
||||
@@ -385,17 +391,21 @@ class TestPluginsAPI:
|
||||
|
||||
def test_get_plugin_config(self, client, mock_config_manager):
|
||||
"""Test getting plugin configuration."""
|
||||
# Plugin configs live at top-level keys (not under 'plugins')
|
||||
mock_config_manager.load_config.return_value = {
|
||||
'plugins': {
|
||||
'weather': {
|
||||
'enabled': True,
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
'weather': {
|
||||
'enabled': True,
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Ensure schema manager returns serializable values
|
||||
from web_interface.blueprints.api_v3 import api_v3
|
||||
api_v3.schema_manager.generate_default_config.return_value = {'enabled': False}
|
||||
api_v3.schema_manager.merge_with_defaults.side_effect = lambda config, defaults: {**defaults, **config}
|
||||
|
||||
response = client.get('/api/v3/plugins/config?plugin_id=weather')
|
||||
|
||||
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.data)
|
||||
assert 'enabled' in data or 'config' in data or 'data' in data
|
||||
|
||||
Reference in New Issue
Block a user