Files
Aniworld/tests/unit/test_provider_config_manager.py

430 lines
16 KiB
Python

"""Unit tests for config_manager.py - Configuration loading, validation, defaults."""
import json
import tempfile
from pathlib import Path
import pytest
from src.core.providers.config_manager import (
ProviderConfigManager,
ProviderSettings,
get_config_manager,
)
class TestProviderSettings:
"""Test ProviderSettings dataclass."""
def test_default_values(self):
"""ProviderSettings should have sensible defaults."""
settings = ProviderSettings(name="test_provider")
assert settings.name == "test_provider"
assert settings.enabled is True
assert settings.priority == 0
assert settings.timeout_seconds == 30
assert settings.max_retries == 3
assert settings.retry_delay_seconds == 1.0
assert settings.max_concurrent_downloads == 3
assert settings.bandwidth_limit_mbps is None
assert settings.custom_headers is None
assert settings.custom_params is None
def test_to_dict(self):
"""to_dict should convert settings to dict, excluding None values."""
settings = ProviderSettings(
name="test",
enabled=True,
priority=1,
)
result = settings.to_dict()
assert result["name"] == "test"
assert result["enabled"] is True
assert result["priority"] == 1
# None values should be excluded
assert "bandwidth_limit_mbps" not in result
assert "custom_headers" not in result
def test_to_dict_with_optional_fields(self):
"""to_dict with optional fields set should include them."""
settings = ProviderSettings(
name="test",
bandwidth_limit_mbps=10.0,
custom_headers={"X-Custom": "value"},
)
result = settings.to_dict()
assert result["bandwidth_limit_mbps"] == 10.0
assert result["custom_headers"] == {"X-Custom": "value"}
def test_from_dict(self):
"""from_dict should create settings from fields with defaults."""
# Note: from_dict uses hasattr(cls, k) which only matches fields
# with defaults on the class. The 'name' field has no default,
# so it must be passed explicitly.
data = {
"name": "test_provider",
"enabled": False,
"priority": 5,
"timeout_seconds": 60,
}
# The from_dict filters with hasattr which excludes 'name'
# (no default), so this should raise TypeError
with pytest.raises(TypeError):
ProviderSettings.from_dict(data)
def test_from_dict_with_only_defaults_fields(self):
"""from_dict works when all fields have defaults (except name)."""
# Directly construct to test fields with defaults
data = {
"enabled": False,
"priority": 5,
}
# This will fail because 'name' is required but filtered out
with pytest.raises(TypeError):
ProviderSettings.from_dict(data)
def test_from_dict_ignores_unknown_fields(self):
"""from_dict should ignore fields not in the dataclass."""
data = {
"name": "test",
"unknown_field": "value",
"another_unknown": 42,
}
# name gets filtered by hasattr → TypeError for missing name
with pytest.raises(TypeError):
ProviderSettings.from_dict(data)
def test_from_dict_with_defaults(self):
"""from_dict with only-defaults data loses required 'name'."""
data = {"name": "minimal"}
with pytest.raises(TypeError):
ProviderSettings.from_dict(data)
class TestProviderConfigManager:
"""Test ProviderConfigManager class."""
def test_init_without_config_file(self):
"""Should initialize with empty provider settings."""
manager = ProviderConfigManager()
assert manager._provider_settings == {}
def test_init_with_nonexistent_config_file(self):
"""Should initialize cleanly when config file doesn't exist."""
manager = ProviderConfigManager(
config_file=Path("/nonexistent/config.json")
)
assert manager._provider_settings == {}
def test_global_settings_defaults(self):
"""Should have sensible global defaults."""
manager = ProviderConfigManager()
assert manager.get_global_setting("default_timeout") == 30
assert manager.get_global_setting("default_max_retries") == 3
assert manager.get_global_setting("enable_health_monitoring") is True
assert manager.get_global_setting("enable_failover") is True
def test_get_provider_settings_none_for_unknown(self):
"""Should return None for unknown provider."""
manager = ProviderConfigManager()
assert manager.get_provider_settings("unknown") is None
def test_set_and_get_provider_settings(self):
"""Should store and retrieve provider settings."""
manager = ProviderConfigManager()
settings = ProviderSettings(name="test", priority=1)
manager.set_provider_settings("test", settings)
result = manager.get_provider_settings("test")
assert result is not None
assert result.name == "test"
assert result.priority == 1
def test_update_provider_settings_existing(self):
"""Should update existing provider settings."""
manager = ProviderConfigManager()
settings = ProviderSettings(name="test", priority=1)
manager.set_provider_settings("test", settings)
result = manager.update_provider_settings("test", priority=5)
assert result is True
updated = manager.get_provider_settings("test")
assert updated.priority == 5
def test_update_provider_settings_new(self):
"""Should create new settings when provider doesn't exist."""
manager = ProviderConfigManager()
result = manager.update_provider_settings(
"new_provider", priority=3, timeout_seconds=60
)
assert result is True
settings = manager.get_provider_settings("new_provider")
assert settings is not None
assert settings.priority == 3
assert settings.timeout_seconds == 60
def test_get_all_provider_settings(self):
"""Should return copy of all provider settings."""
manager = ProviderConfigManager()
manager.set_provider_settings(
"p1", ProviderSettings(name="p1")
)
manager.set_provider_settings(
"p2", ProviderSettings(name="p2")
)
all_settings = manager.get_all_provider_settings()
assert len(all_settings) == 2
assert "p1" in all_settings
assert "p2" in all_settings
def test_get_all_returns_copy(self):
"""get_all_provider_settings should return a copy."""
manager = ProviderConfigManager()
manager.set_provider_settings(
"p1", ProviderSettings(name="p1")
)
all_settings = manager.get_all_provider_settings()
all_settings["p2"] = ProviderSettings(name="p2")
assert "p2" not in manager.get_all_provider_settings()
class TestProviderEnableDisable:
"""Test enable/disable provider functionality."""
def test_enable_provider(self):
"""Should enable a disabled provider."""
manager = ProviderConfigManager()
settings = ProviderSettings(name="test", enabled=False)
manager.set_provider_settings("test", settings)
result = manager.enable_provider("test")
assert result is True
assert manager.get_provider_settings("test").enabled is True
def test_disable_provider(self):
"""Should disable an enabled provider."""
manager = ProviderConfigManager()
settings = ProviderSettings(name="test", enabled=True)
manager.set_provider_settings("test", settings)
result = manager.disable_provider("test")
assert result is True
assert manager.get_provider_settings("test").enabled is False
def test_enable_unknown_provider_returns_false(self):
"""Should return False when enabling unknown provider."""
manager = ProviderConfigManager()
assert manager.enable_provider("unknown") is False
def test_disable_unknown_provider_returns_false(self):
"""Should return False when disabling unknown provider."""
manager = ProviderConfigManager()
assert manager.disable_provider("unknown") is False
def test_get_enabled_providers(self):
"""Should return only enabled providers."""
manager = ProviderConfigManager()
manager.set_provider_settings(
"p1", ProviderSettings(name="p1", enabled=True)
)
manager.set_provider_settings(
"p2", ProviderSettings(name="p2", enabled=False)
)
manager.set_provider_settings(
"p3", ProviderSettings(name="p3", enabled=True)
)
enabled = manager.get_enabled_providers()
assert "p1" in enabled
assert "p2" not in enabled
assert "p3" in enabled
class TestProviderPriority:
"""Test provider priority management."""
def test_set_provider_priority(self):
"""Should set priority for a provider."""
manager = ProviderConfigManager()
manager.set_provider_settings(
"test", ProviderSettings(name="test", priority=0)
)
result = manager.set_provider_priority("test", 5)
assert result is True
assert manager.get_provider_settings("test").priority == 5
def test_set_priority_unknown_returns_false(self):
"""Should return False for unknown provider."""
manager = ProviderConfigManager()
assert manager.set_provider_priority("unknown", 1) is False
def test_get_providers_by_priority(self):
"""Should return providers sorted by priority."""
manager = ProviderConfigManager()
manager.set_provider_settings(
"low", ProviderSettings(name="low", priority=10)
)
manager.set_provider_settings(
"high", ProviderSettings(name="high", priority=1)
)
manager.set_provider_settings(
"mid", ProviderSettings(name="mid", priority=5)
)
sorted_providers = manager.get_providers_by_priority()
assert sorted_providers == ["high", "mid", "low"]
class TestGlobalSettings:
"""Test global settings management."""
def test_get_global_setting(self):
"""Should retrieve global setting value."""
manager = ProviderConfigManager()
assert manager.get_global_setting("default_timeout") == 30
def test_get_unknown_global_setting(self):
"""Should return None for unknown global setting."""
manager = ProviderConfigManager()
assert manager.get_global_setting("nonexistent") is None
def test_set_global_setting(self):
"""Should set a global setting."""
manager = ProviderConfigManager()
manager.set_global_setting("custom_key", "custom_value")
assert manager.get_global_setting("custom_key") == "custom_value"
def test_get_all_global_settings(self):
"""Should return all global settings."""
manager = ProviderConfigManager()
all_settings = manager.get_all_global_settings()
assert "default_timeout" in all_settings
assert "enable_failover" in all_settings
def test_get_all_global_returns_copy(self):
"""get_all_global_settings should return a copy."""
manager = ProviderConfigManager()
settings = manager.get_all_global_settings()
settings["new_key"] = "new_value"
assert manager.get_global_setting("new_key") is None
class TestConfigPersistence:
"""Test configuration save/load functionality."""
def test_save_and_load_config(self):
"""Should save and load configuration from file."""
with tempfile.NamedTemporaryFile(
suffix=".json", delete=False, mode="w"
) as f:
config_path = Path(f.name)
try:
manager = ProviderConfigManager(config_file=config_path)
manager.set_provider_settings(
"test_provider",
ProviderSettings(name="test_provider", priority=3),
)
manager.set_global_setting("custom_option", True)
assert manager.save_config() is True
# Verify the file was created and is valid JSON
assert config_path.exists()
with open(config_path, "r") as f:
data = json.load(f)
assert "providers" in data
assert "test_provider" in data["providers"]
assert data["providers"]["test_provider"]["priority"] == 3
assert data["global"]["custom_option"] is True
finally:
config_path.unlink(missing_ok=True)
def test_save_config_no_path(self):
"""Should return False when no path is specified."""
manager = ProviderConfigManager()
assert manager.save_config() is False
def test_load_config_nonexistent_file(self):
"""Should return False when file doesn't exist."""
manager = ProviderConfigManager()
assert manager.load_config(Path("/nonexistent.json")) is False
def test_load_config_invalid_json(self):
"""Should return False for invalid JSON file."""
with tempfile.NamedTemporaryFile(
suffix=".json", delete=False, mode="w"
) as f:
f.write("not valid json{{{")
config_path = Path(f.name)
try:
manager = ProviderConfigManager()
assert manager.load_config(config_path) is False
finally:
config_path.unlink(missing_ok=True)
def test_save_creates_parent_directories(self):
"""save_config should create parent directories if needed."""
with tempfile.TemporaryDirectory() as tmpdir:
config_path = Path(tmpdir) / "subdir" / "config.json"
manager = ProviderConfigManager(config_file=config_path)
manager.set_provider_settings(
"p1", ProviderSettings(name="p1")
)
assert manager.save_config() is True
assert config_path.exists()
class TestResetToDefaults:
"""Test reset functionality."""
def test_reset_clears_providers(self):
"""reset_to_defaults should clear all provider settings."""
manager = ProviderConfigManager()
manager.set_provider_settings(
"p1", ProviderSettings(name="p1")
)
manager.reset_to_defaults()
assert manager.get_all_provider_settings() == {}
def test_reset_restores_global_defaults(self):
"""reset_to_defaults should restore default global settings."""
manager = ProviderConfigManager()
manager.set_global_setting("default_timeout", 999)
manager.set_global_setting("custom_key", "value")
manager.reset_to_defaults()
assert manager.get_global_setting("default_timeout") == 30
assert manager.get_global_setting("custom_key") is None
class TestGetConfigManagerSingleton:
"""Test the get_config_manager singleton function."""
def test_returns_instance(self):
"""get_config_manager should return a ProviderConfigManager."""
# Reset global state for test
import src.core.providers.config_manager as cm
cm._config_manager = None
manager = get_config_manager()
assert isinstance(manager, ProviderConfigManager)
# Cleanup
cm._config_manager = None
def test_returns_same_instance(self):
"""get_config_manager should return same instance on repeated calls."""
import src.core.providers.config_manager as cm
cm._config_manager = None
first = get_config_manager()
second = get_config_manager()
assert first is second
# Cleanup
cm._config_manager = None