"""Tests for key selector service.""" import pytest from unittest.mock import patch from app.services.key_selector import KeySelector from app.models import ProviderKey class TestKeySelector: """Test KeySelector.""" @pytest.mark.asyncio async def test_get_next_key_single_key(self, mock_db): """Test getting next key with single key configured.""" selector = KeySelector() with patch("app.services.key_selector.db_connection", mock_db): # First call key1 = await selector.get_next_key(1) assert key1 is not None assert isinstance(key1, ProviderKey) @pytest.mark.asyncio async def test_get_next_key_round_robin(self, mock_db): """Test round-robin key selection.""" selector = KeySelector() selector.reset_index(1) # Reset to start fresh with patch("app.services.key_selector.db_connection", mock_db): keys = [] for _ in range(4): # More calls than keys (2 keys) key = await selector.get_next_key(1) if key: keys.append(key.key) # Should cycle through keys assert len(keys) == 4 # First and third should be same, second and fourth should be same assert keys[0] == keys[2] assert keys[1] == keys[3] assert keys[0] != keys[1] @pytest.mark.asyncio async def test_get_next_key_no_keys_configured(self, mock_db): """Test when no keys are configured for provider.""" selector = KeySelector() with patch("app.services.key_selector.db_connection", mock_db): key = await selector.get_next_key(999) # Non-existent provider assert key is None @pytest.mark.asyncio async def test_reset_index(self, mock_db): """Test resetting round-robin index.""" selector = KeySelector() selector._indices[1] = 5 selector.reset_index(1) assert 1 not in selector._indices @pytest.mark.asyncio async def test_reset_index_nonexistent(self): """Test resetting index for non-existent provider.""" selector = KeySelector() selector.reset_index(999) # Should not raise assert 999 not in selector._indices @pytest.mark.asyncio async def test_concurrent_access(self, mock_db): """Test thread-safe concurrent access.""" import asyncio selector = KeySelector() selector.reset_index(1) with patch("app.services.key_selector.db_connection", mock_db): # Run multiple concurrent requests tasks = [selector.get_next_key(1) for _ in range(5)] results = await asyncio.gather(*tasks) # All should return valid keys assert all(r is not None for r in results) @pytest.mark.asyncio async def test_different_providers_independent(self, mock_db): """Test that different providers have independent indices.""" selector = KeySelector() with patch("app.services.key_selector.db_connection", mock_db): key1 = await selector.get_next_key(1) key2 = await selector.get_next_key(2) # Both should return valid keys from different providers assert key1 is not None assert key2 is not None assert key1.provider_id == 1 assert key2.provider_id == 2