"""Tests for OpenRouter service. T28: Test API key validation with OpenRouter API. """ import pytest from unittest.mock import AsyncMock, MagicMock, patch import httpx class TestValidateApiKey: """Tests for validate_api_key function.""" @pytest.mark.asyncio async def test_validate_api_key_success(self): """Test successful API key validation.""" from openrouter_monitor.services.openrouter import validate_api_key # Mock successful response mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = { "data": { "label": "Test Key", "usage": 0, "limit": 100, "is_free_tier": True } } with patch('httpx.AsyncClient.get', return_value=mock_response): result = await validate_api_key("sk-or-v1-test-key") assert result is True @pytest.mark.asyncio async def test_validate_api_key_invalid(self): """Test invalid API key returns False.""" from openrouter_monitor.services.openrouter import validate_api_key # Mock 401 Unauthorized response mock_response = MagicMock() mock_response.status_code = 401 mock_response.text = "Unauthorized" with patch('httpx.AsyncClient.get', return_value=mock_response): result = await validate_api_key("sk-or-v1-invalid-key") assert result is False @pytest.mark.asyncio async def test_validate_api_key_timeout(self): """Test timeout returns False.""" from openrouter_monitor.services.openrouter import validate_api_key with patch('httpx.AsyncClient.get', side_effect=httpx.TimeoutException("Connection timed out")): result = await validate_api_key("sk-or-v1-test-key") assert result is False @pytest.mark.asyncio async def test_validate_api_key_network_error(self): """Test network error returns False.""" from openrouter_monitor.services.openrouter import validate_api_key with patch('httpx.AsyncClient.get', side_effect=httpx.NetworkError("Connection failed")): result = await validate_api_key("sk-or-v1-test-key") assert result is False @pytest.mark.asyncio async def test_validate_api_key_uses_correct_headers(self): """Test that correct headers are sent to OpenRouter.""" from openrouter_monitor.services.openrouter import validate_api_key, OPENROUTER_AUTH_URL mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"data": {"usage": 0}} with patch('httpx.AsyncClient.get', return_value=mock_response) as mock_get: await validate_api_key("sk-or-v1-test-key") # Verify correct URL and headers mock_get.assert_called_once() call_args = mock_get.call_args assert call_args[0][0] == OPENROUTER_AUTH_URL assert "Authorization" in call_args[1]["headers"] assert call_args[1]["headers"]["Authorization"] == "Bearer sk-or-v1-test-key" @pytest.mark.asyncio async def test_validate_api_key_uses_10s_timeout(self): """Test that request uses 10 second timeout.""" from openrouter_monitor.services.openrouter import validate_api_key mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"data": {"usage": 0}} with patch('httpx.AsyncClient.get', return_value=mock_response) as mock_get: await validate_api_key("sk-or-v1-test-key") # Verify timeout is set to 10 seconds call_kwargs = mock_get.call_args[1] assert call_kwargs.get("timeout") == 10.0 class TestGetKeyInfo: """Tests for get_key_info function.""" @pytest.mark.asyncio async def test_get_key_info_success(self): """Test successful key info retrieval.""" from openrouter_monitor.services.openrouter import get_key_info expected_data = { "data": { "label": "Test Key", "usage": 50, "limit": 100, "is_free_tier": False } } mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = expected_data with patch('httpx.AsyncClient.get', return_value=mock_response): result = await get_key_info("sk-or-v1-test-key") assert result == expected_data["data"] @pytest.mark.asyncio async def test_get_key_info_invalid_key(self): """Test invalid key returns None.""" from openrouter_monitor.services.openrouter import get_key_info mock_response = MagicMock() mock_response.status_code = 401 mock_response.text = "Unauthorized" with patch('httpx.AsyncClient.get', return_value=mock_response): result = await get_key_info("sk-or-v1-invalid-key") assert result is None @pytest.mark.asyncio async def test_get_key_info_timeout(self): """Test timeout returns None.""" from openrouter_monitor.services.openrouter import get_key_info with patch('httpx.AsyncClient.get', side_effect=httpx.TimeoutException("Connection timed out")): result = await get_key_info("sk-or-v1-test-key") assert result is None @pytest.mark.asyncio async def test_get_key_info_network_error(self): """Test network error returns None.""" from openrouter_monitor.services.openrouter import get_key_info with patch('httpx.AsyncClient.get', side_effect=httpx.NetworkError("Connection failed")): result = await get_key_info("sk-or-v1-test-key") assert result is None @pytest.mark.asyncio async def test_get_key_info_malformed_response(self): """Test malformed JSON response returns None.""" from openrouter_monitor.services.openrouter import get_key_info mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.side_effect = ValueError("Invalid JSON") with patch('httpx.AsyncClient.get', return_value=mock_response): result = await get_key_info("sk-or-v1-test-key") assert result is None class TestOpenRouterConstants: """Tests for OpenRouter constants.""" def test_openrouter_auth_url_defined(self): """Test that OPENROUTER_AUTH_URL is defined.""" from openrouter_monitor.services.openrouter import OPENROUTER_AUTH_URL assert OPENROUTER_AUTH_URL == "https://openrouter.ai/api/v1/auth/key" def test_openrouter_timeout_defined(self): """Test that TIMEOUT_SECONDS is defined.""" from openrouter_monitor.services.openrouter import TIMEOUT_SECONDS assert TIMEOUT_SECONDS == 10.0