Files
ledgrab/server/tests/api/routes/test_system_routes.py
T
alexei.dolgolyov 45d12b2811 feat(update-service): SSRF-validated redirects + restart hardening
update_service grows explicit URL validation on the redirect chain so a
hostile mirror can't bounce the updater to a private IP. restart.ps1
gets stricter argument handling and clearer log lines.
default_config.yaml exposes the new toggles. test_system_routes pins
the new behaviour.
2026-05-23 00:49:18 +03:00

95 lines
3.1 KiB
Python

"""Tests for system routes — health, version.
These tests use the FastAPI TestClient against the real app. The health
and version endpoints do NOT require authentication, so we can test them
without setting up the full dependency injection.
"""
import pytest
from fastapi.testclient import TestClient
from ledgrab import __version__
from ledgrab.config import get_config
def _auth_headers() -> dict[str, str]:
"""Resolve the configured API key lazily so test ordering doesn't matter.
Evaluating ``get_config()`` at module import time produced a stale empty
key when other tests mutated the global config before this module ran.
"""
api_key = next(iter(get_config().auth.api_keys.values()), "")
return {"Authorization": f"Bearer {api_key}"} if api_key else {}
@pytest.fixture(scope="module")
def client():
"""Provide a test client for the main app.
The app module initializes stores from the default config on import,
which is acceptable for read-only endpoints tested here.
"""
from ledgrab.main import app
return TestClient(app, raise_server_exceptions=False)
class TestHealthEndpoint:
def test_health_returns_200(self, client):
resp = client.get("/health")
assert resp.status_code == 200
def test_health_response_structure(self, client):
data = client.get("/health").json()
assert data["status"] == "healthy"
assert data["version"] == __version__
assert "timestamp" in data
def test_health_no_auth_required(self, client):
"""Health endpoint should work without Authorization header."""
resp = client.get("/health")
assert resp.status_code == 200
class TestVersionEndpoint:
def test_version_returns_200(self, client):
resp = client.get("/api/v1/version")
assert resp.status_code == 200
def test_version_response_fields(self, client):
data = client.get("/api/v1/version").json()
assert data["version"] == __version__
assert "python_version" in data
assert data["api_version"] == "v1"
assert "demo_mode" in data
class TestOpenAPIEndpoint:
def test_openapi_available(self, client):
resp = client.get("/openapi.json", headers=_auth_headers())
assert resp.status_code == 200
data = resp.json()
assert "info" in data
assert data["info"]["version"] == __version__
def test_swagger_ui(self, client):
resp = client.get("/docs", headers=_auth_headers())
assert resp.status_code == 200
assert "text/html" in resp.headers["content-type"]
def test_openapi_requires_auth(self, client):
"""Without a valid bearer token, the OpenAPI surface is unreachable."""
resp = client.get("/openapi.json")
assert resp.status_code == 401
def test_swagger_requires_auth(self, client):
resp = client.get("/docs")
assert resp.status_code == 401
class TestRootEndpoint:
def test_root_returns_html(self, client):
resp = client.get("/")
assert resp.status_code == 200
assert "text/html" in resp.headers["content-type"]