""" Tests for the ProviderRegistry singleton. """ import pytest import threading from services.providers.registry import ProviderRegistry, get_registry from services.providers.base import TranslationProvider from services.providers.schemas import TranslationRequest, TranslationResponse class MockProvider(TranslationProvider): """Mock provider for testing.""" def __init__(self, name: str, available: bool = True): self._name = name self._available = available def translate_text(self, request: TranslationRequest) -> TranslationResponse: return TranslationResponse( translated_text=f"[{self._name}] {request.text}", provider_name=self._name, from_cache=False, ) def get_name(self) -> str: return self._name def is_available(self) -> bool: return self._available class TestProviderRegistry: """Tests for the ProviderRegistry class.""" @pytest.fixture(autouse=True) def setup_registry(self): """Clear registry before each test.""" registry = get_registry() registry.clear() yield registry.clear() def test_singleton_pattern(self): """Test that ProviderRegistry is a singleton.""" registry1 = ProviderRegistry() registry2 = ProviderRegistry() assert registry1 is registry2 def test_get_registry_function(self): """Test get_registry returns the singleton.""" registry1 = get_registry() registry2 = get_registry() assert registry1 is registry2 def test_register_and_get(self): """Test registering and retrieving a provider.""" registry = get_registry() provider = MockProvider("test") registry.register("test", provider) retrieved = registry.get("test") assert retrieved is provider assert retrieved.get_name() == "test" def test_get_nonexistent_provider(self): """Test getting a provider that doesn't exist.""" registry = get_registry() result = registry.get("nonexistent") assert result is None def test_unregister(self): """Test unregistering a provider.""" registry = get_registry() provider = MockProvider("test") registry.register("test", provider) assert registry.get("test") is not None result = registry.unregister("test") assert result is True assert registry.get("test") is None def test_unregister_nonexistent(self): """Test unregistering a provider that doesn't exist.""" registry = get_registry() result = registry.unregister("nonexistent") assert result is False def test_list_all(self): """Test listing all registered providers.""" registry = get_registry() registry.register("google", MockProvider("google")) registry.register("deepl", MockProvider("deepl")) registry.register("openai", MockProvider("openai")) names = registry.list_all() assert len(names) == 3 assert "google" in names assert "deepl" in names assert "openai" in names def test_list_available(self): """Test listing only available providers.""" registry = get_registry() registry.register("available1", MockProvider("available1", available=True)) registry.register("available2", MockProvider("available2", available=True)) registry.register("unavailable", MockProvider("unavailable", available=False)) names = registry.list_available() assert len(names) == 2 assert "available1" in names assert "available2" in names assert "unavailable" not in names def test_get_first_available(self): """Test getting first available provider from a list.""" registry = get_registry() registry.register("google", MockProvider("google", available=True)) registry.register("deepl", MockProvider("deepl", available=True)) registry.register("openai", MockProvider("openai", available=False)) provider = registry.get_first_available(["openai", "deepl", "google"]) assert provider is not None assert provider.get_name() == "deepl" def test_get_first_available_all_unavailable(self): """Test getting first available when all are unavailable.""" registry = get_registry() registry.register("google", MockProvider("google", available=False)) registry.register("deepl", MockProvider("deepl", available=False)) provider = registry.get_first_available(["google", "deepl"]) assert provider is None def test_get_first_available_not_registered(self): """Test getting first available when provider not registered.""" registry = get_registry() provider = registry.get_first_available(["google", "deepl"]) assert provider is None def test_clear(self): """Test clearing all providers.""" registry = get_registry() registry.register("google", MockProvider("google")) registry.register("deepl", MockProvider("deepl")) registry.clear() assert len(registry) == 0 assert registry.list_all() == [] def test_len(self): """Test __len__ method.""" registry = get_registry() assert len(registry) == 0 registry.register("google", MockProvider("google")) assert len(registry) == 1 registry.register("deepl", MockProvider("deepl")) assert len(registry) == 2 def test_contains(self): """Test __contains__ method.""" registry = get_registry() registry.register("google", MockProvider("google")) assert "google" in registry assert "deepl" not in registry def test_thread_safety(self): """Test that registry operations are thread-safe.""" registry = get_registry() registry.clear() errors = [] def register_providers(prefix: str, count: int): try: for i in range(count): registry.register(f"{prefix}_{i}", MockProvider(f"{prefix}_{i}")) except Exception as e: errors.append(e) threads = [ threading.Thread(target=register_providers, args=(f"thread_{t}", 10)) for t in range(5) ] for t in threads: t.start() for t in threads: t.join() assert len(errors) == 0 assert len(registry) == 50 def test_overwrite_registration(self): """Test that registering with same name overwrites.""" registry = get_registry() provider1 = MockProvider("test1") provider2 = MockProvider("test2") registry.register("test", provider1) assert registry.get("test").get_name() == "test1" registry.register("test", provider2) assert registry.get("test").get_name() == "test2"