generated from personal-projects/leo-claude-mktplace
- Move tests from src/gitea_mcp_remote/tests/ to tests/ (top-level) - Update pytest.ini to point to new test location - All imports already use absolute paths (gitea_mcp_remote.*) - Tests run successfully from new location (28/30 pass, 2 pre-existing failures) This improves project structure by following standard Python conventions where tests live at the repository root level rather than inside the source package. Closes #21 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
163 lines
5.8 KiB
Python
163 lines
5.8 KiB
Python
"""Tests for HTTP authentication middleware."""
|
|
|
|
import pytest
|
|
from starlette.applications import Starlette
|
|
from starlette.responses import JSONResponse
|
|
from starlette.routing import Route
|
|
from starlette.testclient import TestClient
|
|
|
|
from gitea_mcp_remote.middleware import (
|
|
BearerAuthMiddleware,
|
|
HealthCheckBypassMiddleware,
|
|
)
|
|
|
|
|
|
# Test application endpoint
|
|
async def test_endpoint(request):
|
|
return JSONResponse({"message": "success"})
|
|
|
|
|
|
class TestBearerAuthMiddleware:
|
|
"""Test BearerAuthMiddleware."""
|
|
|
|
def test_no_auth_configured(self):
|
|
"""Test that requests pass through when no auth token is configured."""
|
|
app = Starlette(routes=[Route("/test", test_endpoint)])
|
|
app.add_middleware(BearerAuthMiddleware, auth_token=None)
|
|
|
|
client = TestClient(app)
|
|
response = client.get("/test")
|
|
|
|
assert response.status_code == 200
|
|
assert response.json()["message"] == "success"
|
|
|
|
def test_auth_configured_valid_token(self):
|
|
"""Test successful authentication with valid token."""
|
|
app = Starlette(routes=[Route("/test", test_endpoint)])
|
|
app.add_middleware(BearerAuthMiddleware, auth_token="secret_token")
|
|
|
|
client = TestClient(app)
|
|
response = client.get("/test", headers={"Authorization": "Bearer secret_token"})
|
|
|
|
assert response.status_code == 200
|
|
assert response.json()["message"] == "success"
|
|
|
|
def test_auth_configured_missing_header(self):
|
|
"""Test rejection when Authorization header is missing."""
|
|
app = Starlette(routes=[Route("/test", test_endpoint)])
|
|
app.add_middleware(BearerAuthMiddleware, auth_token="secret_token")
|
|
|
|
client = TestClient(app)
|
|
response = client.get("/test")
|
|
|
|
assert response.status_code == 401
|
|
assert "Missing Authorization header" in response.json()["message"]
|
|
|
|
def test_auth_configured_invalid_format(self):
|
|
"""Test rejection when Authorization header has wrong format."""
|
|
app = Starlette(routes=[Route("/test", test_endpoint)])
|
|
app.add_middleware(BearerAuthMiddleware, auth_token="secret_token")
|
|
|
|
client = TestClient(app)
|
|
|
|
# Test with wrong scheme
|
|
response = client.get("/test", headers={"Authorization": "Basic secret_token"})
|
|
assert response.status_code == 401
|
|
assert "Bearer scheme" in response.json()["message"]
|
|
|
|
# Test with no scheme
|
|
response = client.get("/test", headers={"Authorization": "secret_token"})
|
|
assert response.status_code == 401
|
|
|
|
def test_auth_configured_invalid_token(self):
|
|
"""Test rejection when token is invalid."""
|
|
app = Starlette(routes=[Route("/test", test_endpoint)])
|
|
app.add_middleware(BearerAuthMiddleware, auth_token="secret_token")
|
|
|
|
client = TestClient(app)
|
|
response = client.get("/test", headers={"Authorization": "Bearer wrong_token"})
|
|
|
|
assert response.status_code == 403
|
|
assert "Invalid authentication token" in response.json()["message"]
|
|
|
|
def test_auth_case_sensitive_token(self):
|
|
"""Test that token comparison is case-sensitive."""
|
|
app = Starlette(routes=[Route("/test", test_endpoint)])
|
|
app.add_middleware(BearerAuthMiddleware, auth_token="Secret_Token")
|
|
|
|
client = TestClient(app)
|
|
|
|
# Correct case
|
|
response = client.get("/test", headers={"Authorization": "Bearer Secret_Token"})
|
|
assert response.status_code == 200
|
|
|
|
# Wrong case
|
|
response = client.get("/test", headers={"Authorization": "Bearer secret_token"})
|
|
assert response.status_code == 403
|
|
|
|
|
|
class TestHealthCheckBypassMiddleware:
|
|
"""Test HealthCheckBypassMiddleware."""
|
|
|
|
def test_default_health_check_paths(self):
|
|
"""Test that default health check paths bypass auth."""
|
|
app = Starlette(
|
|
routes=[
|
|
Route("/health", test_endpoint),
|
|
Route("/healthz", test_endpoint),
|
|
Route("/ping", test_endpoint),
|
|
Route("/test", test_endpoint),
|
|
]
|
|
)
|
|
app.add_middleware(BearerAuthMiddleware, auth_token="secret_token")
|
|
app.add_middleware(HealthCheckBypassMiddleware)
|
|
|
|
client = TestClient(app)
|
|
|
|
# Health checks should work without auth
|
|
assert client.get("/health").status_code == 200
|
|
assert client.get("/healthz").status_code == 200
|
|
assert client.get("/ping").status_code == 200
|
|
|
|
# Regular endpoint should require auth
|
|
assert client.get("/test").status_code == 401
|
|
|
|
def test_custom_health_check_paths(self):
|
|
"""Test custom health check paths."""
|
|
app = Starlette(
|
|
routes=[
|
|
Route("/custom-health", test_endpoint),
|
|
Route("/test", test_endpoint),
|
|
]
|
|
)
|
|
app.add_middleware(BearerAuthMiddleware, auth_token="secret_token")
|
|
app.add_middleware(
|
|
HealthCheckBypassMiddleware,
|
|
health_check_paths=["/custom-health"],
|
|
)
|
|
|
|
client = TestClient(app)
|
|
|
|
# Custom health check should work without auth
|
|
assert client.get("/custom-health").status_code == 200
|
|
|
|
# Regular endpoint should require auth
|
|
assert client.get("/test").status_code == 401
|
|
|
|
def test_middleware_order(self):
|
|
"""Test that middleware order is correct."""
|
|
# HealthCheckBypass should be added BEFORE BearerAuth
|
|
# so it can bypass the auth check
|
|
|
|
app = Starlette(routes=[Route("/health", test_endpoint)])
|
|
|
|
# Correct order: HealthCheck bypass first, then Auth
|
|
app.add_middleware(BearerAuthMiddleware, auth_token="secret_token")
|
|
app.add_middleware(HealthCheckBypassMiddleware)
|
|
|
|
client = TestClient(app)
|
|
response = client.get("/health")
|
|
|
|
# Should succeed without auth
|
|
assert response.status_code == 200
|