Files
openrouter-watcher/tests/unit/services/test_openrouter.py
Luca Sacchi Ricciardi 3824ce5169 feat(openrouter): T28 implement API key validation service
- 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
2026-04-07 14:44:15 +02:00

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