# -*- coding: utf-8 -*- """ Unit-Tests für trixy_core.service. """ import pytest from unittest.mock import MagicMock, AsyncMock from trixy_core.service.enums import ServicePriority, ServiceGroup, ServiceState from trixy_core.service.iservice import IService from trixy_core.service.service_container import ServiceContainer class TestServiceEnums: """Tests für Service-Enumerationen.""" def test_service_priority_ordering(self): """Testet die Prioritätsreihenfolge.""" assert ServicePriority.CRITICAL < ServicePriority.CORE assert ServicePriority.CORE < ServicePriority.NETWORK assert ServicePriority.NETWORK < ServicePriority.MANAGER assert ServicePriority.MANAGER < ServicePriority.PLUGIN assert ServicePriority.PLUGIN < ServicePriority.OPTIONAL def test_service_priority_values(self): """Testet die Prioritätswerte.""" assert ServicePriority.CRITICAL == 0 assert ServicePriority.CORE == 10 assert ServicePriority.NETWORK == 20 assert ServicePriority.MANAGER == 30 assert ServicePriority.PLUGIN == 40 assert ServicePriority.OPTIONAL == 50 def test_service_group_exists(self): """Testet, dass Service-Gruppen existieren.""" assert hasattr(ServiceGroup, "CRITICAL") assert hasattr(ServiceGroup, "NETWORK") assert hasattr(ServiceGroup, "MANAGER") assert hasattr(ServiceGroup, "AUDIO") assert hasattr(ServiceGroup, "ML") assert hasattr(ServiceGroup, "UTILITY") assert hasattr(ServiceGroup, "PLUGIN") def test_service_state_values(self): """Testet die Service-Zustände.""" assert hasattr(ServiceState, "STOPPED") assert hasattr(ServiceState, "STARTING") assert hasattr(ServiceState, "RUNNING") assert hasattr(ServiceState, "STOPPING") assert hasattr(ServiceState, "FAILED") class ConcreteService(IService): """Konkrete Service-Implementierung für Tests.""" PRIORITY = ServicePriority.CORE GROUP = ServiceGroup.UTILITY DEPENDENCIES = [] NAME = "TestService" def __init__(self, application): super().__init__(application) self.started = False self.stopped = False async def start(self): self.started = True async def stop(self): self.stopped = True class DependentService(IService): """Service mit Abhängigkeit für Tests.""" PRIORITY = ServicePriority.MANAGER GROUP = ServiceGroup.UTILITY DEPENDENCIES = ["TestService"] NAME = "DependentService" async def start(self): pass async def stop(self): pass class TestIService: """Tests für IService-Basisklasse.""" @pytest.fixture def mock_application(self): """Erstellt eine Mock-Anwendung.""" return MagicMock() @pytest.fixture def service(self, mock_application): """Erstellt eine Test-Service-Instanz.""" return ConcreteService(mock_application) def test_service_initialization(self, service, mock_application): """Testet die Service-Initialisierung.""" assert service.application == mock_application assert service.state == ServiceState.STOPPED def test_service_name(self, service): """Testet den Service-Namen.""" assert service.name == "TestService" def test_service_is_running(self, service): """Testet die is_running-Eigenschaft.""" assert service.is_running is False service._set_state(ServiceState.RUNNING) assert service.is_running is True def test_service_priority(self, service): """Testet die Service-Priorität.""" assert service.PRIORITY == ServicePriority.CORE def test_service_group(self, service): """Testet die Service-Gruppe.""" assert service.GROUP == ServiceGroup.UTILITY def test_service_dependencies(self, service): """Testet die Service-Abhängigkeiten.""" assert service.DEPENDENCIES == [] @pytest.mark.asyncio async def test_service_lifecycle_hooks(self, service): """Testet die Lifecycle-Hooks.""" # Hooks sollten ohne Fehler durchlaufen await service.on_pre_start() await service.on_post_start() await service.on_pre_stop() await service.on_post_stop() await service.on_dependency_ready("SomeService") @pytest.mark.asyncio async def test_health_check_default(self, service): """Testet die Standard-Gesundheitsprüfung.""" # Nicht laufend -> False assert await service.health_check() is False # Laufend -> True service._set_state(ServiceState.RUNNING) assert await service.health_check() is True class TestServiceContainer: """Tests für ServiceContainer.""" @pytest.fixture def mock_application(self): """Erstellt eine Mock-Anwendung.""" return MagicMock() @pytest.fixture def container(self, mock_application): """Erstellt einen ServiceContainer.""" return ServiceContainer(mock_application) def test_container_initialization(self, container): """Testet die Container-Initialisierung.""" assert container.services == {} def test_register_service(self, container): """Testet die Service-Registrierung.""" service = container.register(ConcreteService) assert "TestService" in container.services assert isinstance(service, ConcreteService) def test_register_duplicate_raises_error(self, container): """Testet, dass doppelte Registrierung fehlschlägt.""" container.register(ConcreteService) with pytest.raises(ValueError, match="bereits registriert"): container.register(ConcreteService) def test_get_service(self, container): """Testet get_service.""" container.register(ConcreteService) service = container.get_service("TestService") assert service is not None assert isinstance(service, ConcreteService) def test_get_nonexistent_service(self, container): """Testet get_service für nicht existierenden Service.""" assert container.get_service("NonExistent") is None def test_getitem_by_name(self, container): """Testet __getitem__ mit Name.""" container.register(ConcreteService) service = container["TestService"] assert isinstance(service, ConcreteService) def test_getitem_by_class(self, container): """Testet __getitem__ mit Klasse.""" container.register(ConcreteService) service = container[ConcreteService] assert isinstance(service, ConcreteService) def test_getitem_raises_keyerror(self, container): """Testet, dass __getitem__ KeyError wirft.""" with pytest.raises(KeyError): _ = container["NonExistent"] def test_contains(self, container): """Testet __contains__.""" container.register(ConcreteService) assert "TestService" in container assert "NonExistent" not in container assert ConcreteService in container @pytest.mark.asyncio async def test_start_all(self, container): """Testet start_all.""" service = container.register(ConcreteService) await container.start_all() assert service.started is True assert service.state == ServiceState.RUNNING @pytest.mark.asyncio async def test_stop_all(self, container): """Testet stop_all.""" service = container.register(ConcreteService) await container.start_all() await container.stop_all() assert service.stopped is True assert service.state == ServiceState.STOPPED @pytest.mark.asyncio async def test_dependency_order(self, container): """Testet die Abhängigkeitsreihenfolge.""" container.register(ConcreteService) container.register(DependentService) order = container._resolve_start_order() test_idx = order.index("TestService") dependent_idx = order.index("DependentService") assert test_idx < dependent_idx @pytest.mark.asyncio async def test_restart_service(self, container): """Testet den Service-Neustart.""" service = container.register(ConcreteService) await container.start_all() service.started = False service.stopped = False await container.restart_service("TestService") assert service.stopped is True assert service.started is True