Files
zzrouter/backend/tests/test_middleware_auth.py
tech d080e67c29 test: add comprehensive test suite with 89% coverage
- Add tests for all backend modules: config, database, models, services,
  routes, middleware, and providers
- Separate dev dependencies using dependency-groups
- Update CLAUDE.md with test commands and project structure
- Add .coverage and .pytest_cache to gitignore

88 tests covering:
- Authentication and authorization
- Model routing and key selection
- Async logging with batch processing
- All API endpoints (chat, openai, anthropic, health)
- LiteLLM wrapper (mocked external calls)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 19:12:57 +08:00

107 lines
3.6 KiB
Python

"""Tests for authentication middleware."""
import pytest
from unittest.mock import patch, AsyncMock, MagicMock
from fastapi import HTTPException
from fastapi.security import HTTPAuthorizationCredentials
from app.middleware.auth import get_current_client, AuthMiddleware
from app.models import ClientKey
class TestGetCurrentClient:
"""Test get_current_client dependency."""
@pytest.mark.asyncio
async def test_missing_credentials(self):
"""Test with missing credentials."""
with pytest.raises(HTTPException) as exc_info:
await get_current_client(None)
assert exc_info.value.status_code == 401
assert "Missing API key" in str(exc_info.value.detail)
@pytest.mark.asyncio
async def test_invalid_key(self, mock_db):
"""Test with invalid API key."""
credentials = HTTPAuthorizationCredentials(
scheme="Bearer",
credentials="invalid-key"
)
with patch("app.middleware.auth.AuthService.validate_key", return_value=None):
with pytest.raises(HTTPException) as exc_info:
await get_current_client(credentials)
assert exc_info.value.status_code == 401
assert "Invalid API key" in str(exc_info.value.detail)
@pytest.mark.asyncio
async def test_disabled_key(self):
"""Test with disabled API key."""
credentials = HTTPAuthorizationCredentials(
scheme="Bearer",
credentials="disabled-key"
)
disabled_client = ClientKey(
id=1,
key="disabled-key",
name="disabled",
is_active=False,
created_at="2024-01-01"
)
with patch("app.middleware.auth.AuthService.validate_key", return_value=disabled_client):
with pytest.raises(HTTPException) as exc_info:
await get_current_client(credentials)
assert exc_info.value.status_code == 403
assert "disabled" in str(exc_info.value.detail).lower()
@pytest.mark.asyncio
async def test_valid_key(self):
"""Test with valid API key."""
credentials = HTTPAuthorizationCredentials(
scheme="Bearer",
credentials="test-api-key"
)
valid_client = ClientKey(
id=1,
key="test-api-key",
name="test-client",
is_active=True,
created_at="2024-01-01"
)
with patch("app.middleware.auth.AuthService.validate_key", return_value=valid_client):
result = await get_current_client(credentials)
assert result == valid_client
assert result.is_active is True
class TestAuthMiddleware:
"""Test AuthMiddleware."""
def test_default_exclude_paths(self):
"""Test default exclude paths."""
middleware = AuthMiddleware()
assert "/health" in middleware.exclude_paths
assert "/docs" in middleware.exclude_paths
assert "/openapi.json" in middleware.exclude_paths
def test_custom_exclude_paths(self):
"""Test custom exclude paths."""
middleware = AuthMiddleware(exclude_paths=["/custom"])
assert "/custom" in middleware.exclude_paths
assert "/health" not in middleware.exclude_paths
@pytest.mark.asyncio
async def test_middleware_calls_next(self):
"""Test middleware calls next handler."""
middleware = AuthMiddleware()
request = MagicMock()
call_next = AsyncMock(return_value=MagicMock())
response = await middleware(request, call_next)
call_next.assert_called_once_with(request)