apigateway / tests /test_base_service.py
jebin2's picture
refactor
bcc8074
"""
Unit tests for base service infrastructure.
Tests:
- BaseService registration and configuration
- ServiceRegistry service management
- ServiceConfig operations
"""
import pytest
from services.base_service import BaseService, ServiceConfig, ServiceRegistry
class TestServiceConfig:
"""Test ServiceConfig container."""
def test_initialization(self):
"""Test config initialization with kwargs."""
config = ServiceConfig(key1="value1", key2=42)
assert config.get("key1") == "value1"
assert config.get("key2") == 42
def test_get_with_default(self):
"""Test get with default value."""
config = ServiceConfig(key1="value1")
assert config.get("key1") == "value1"
assert config.get("missing", "default") == "default"
assert config.get("missing") is None
def test_set_value(self):
"""Test setting values."""
config = ServiceConfig()
config.set("key1", "value1")
assert config.get("key1") == "value1"
def test_dictionary_access(self):
"""Test dictionary-style access."""
config = ServiceConfig(key1="value1")
assert config["key1"] == "value1"
config["key2"] = "value2"
assert config["key2"] == "value2"
def test_contains(self):
"""Test 'in' operator."""
config = ServiceConfig(key1="value1")
assert "key1" in config
assert "missing" not in config
class TestBaseService:
"""Test BaseService abstract class."""
def setup_method(self):
"""Reset service state before each test."""
# Create concrete test service
class TestService(BaseService):
SERVICE_NAME = "test_service"
@classmethod
def register(cls, **config):
super().register(**config)
self.TestService = TestService
# Reset state
self.TestService._registered = False
self.TestService._config = None
def test_registration(self):
"""Test service registration."""
assert not self.TestService.is_registered()
self.TestService.register(key1="value1", key2=42)
assert self.TestService.is_registered()
assert self.TestService.get_config().get("key1") == "value1"
assert self.TestService.get_config().get("key2") == 42
def test_double_registration_fails(self):
"""Test that double registration raises error."""
self.TestService.register(key1="value1")
with pytest.raises(RuntimeError, match="already registered"):
self.TestService.register(key2="value2")
def test_assert_registered(self):
"""Test assert_registered raises when not registered."""
with pytest.raises(RuntimeError, match="not registered"):
self.TestService.assert_registered()
self.TestService.register()
self.TestService.assert_registered() # Should not raise
def test_get_config_before_registration(self):
"""Test get_config raises before registration."""
with pytest.raises(RuntimeError, match="not registered"):
self.TestService.get_config()
def test_get_middleware_default(self):
"""Test default get_middleware returns None."""
assert self.TestService.get_middleware() is None
def test_on_shutdown_default(self):
"""Test default on_shutdown does nothing."""
self.TestService.on_shutdown() # Should not raise
class TestServiceRegistry:
"""Test ServiceRegistry global registry."""
def setup_method(self):
"""Reset registry before each test."""
ServiceRegistry._services = {}
def test_register_service(self):
"""Test registering a service."""
class TestService(BaseService):
SERVICE_NAME = "test_service"
@classmethod
def register(cls, **config):
super().register(**config)
ServiceRegistry.register_service(TestService)
assert ServiceRegistry.get_service("test_service") == TestService
def test_register_multiple_services(self):
"""Test registering multiple services."""
class Service1(BaseService):
SERVICE_NAME = "service1"
@classmethod
def register(cls, **config):
super().register(**config)
class Service2(BaseService):
SERVICE_NAME = "service2"
@classmethod
def register(cls, **config):
super().register(**config)
ServiceRegistry.register_service(Service1)
ServiceRegistry.register_service(Service2)
assert len(ServiceRegistry.get_all_services()) == 2
assert ServiceRegistry.get_service("service1") == Service1
assert ServiceRegistry.get_service("service2") == Service2
def test_get_nonexistent_service(self):
"""Test getting service that doesn't exist."""
assert ServiceRegistry.get_service("nonexistent") is None
def test_overwrite_service(self):
"""Test registering service with same name overwrites."""
class Service1(BaseService):
SERVICE_NAME = "test"
version = 1
@classmethod
def register(cls, **config):
super().register(**config)
class Service2(BaseService):
SERVICE_NAME = "test"
version = 2
@classmethod
def register(cls, **config):
super().register(**config)
ServiceRegistry.register_service(Service1)
ServiceRegistry.register_service(Service2)
service = ServiceRegistry.get_service("test")
assert service.version == 2
def test_get_all_middleware(self):
"""Test getting middleware from all services."""
class MockMiddleware:
pass
class ServiceWithMiddleware(BaseService):
SERVICE_NAME = "with_middleware"
@classmethod
def register(cls, **config):
super().register(**config)
@classmethod
def get_middleware(cls):
return MockMiddleware()
class ServiceWithoutMiddleware(BaseService):
SERVICE_NAME = "without_middleware"
@classmethod
def register(cls, **config):
super().register(**config)
# Register services
ServiceWithMiddleware.register()
ServiceWithoutMiddleware.register()
ServiceRegistry.register_service(ServiceWithMiddleware)
ServiceRegistry.register_service(ServiceWithoutMiddleware)
middleware_list = ServiceRegistry.get_all_middleware()
assert len(middleware_list) == 1
assert isinstance(middleware_list[0], MockMiddleware)
def test_shutdown_all(self):
"""Test calling shutdown on all services."""
shutdown_called = []
class Service1(BaseService):
SERVICE_NAME = "service1"
@classmethod
def register(cls, **config):
super().register(**config)
@classmethod
def on_shutdown(cls):
shutdown_called.append("service1")
class Service2(BaseService):
SERVICE_NAME = "service2"
@classmethod
def register(cls, **config):
super().register(**config)
@classmethod
def on_shutdown(cls):
shutdown_called.append("service2")
ServiceRegistry.register_service(Service1)
ServiceRegistry.register_service(Service2)
ServiceRegistry.shutdown_all()
assert "service1" in shutdown_called
assert "service2" in shutdown_called