- Add validate_api_key() function for OpenRouter key validation - Add get_key_info() function to retrieve key metadata - Implement proper error handling (timeout, network errors) - Use httpx with 10s timeout - Export from services/__init__.py - 92% coverage on openrouter module (13 tests) Refs: T28
195 lines
7.0 KiB
Python
195 lines
7.0 KiB
Python
"""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
|