The health check endpoint now properly indicates service unavailability: - Returns HTTP 200 when fail2ban is online - Returns HTTP 503 when fail2ban is offline This allows Docker and other orchestration tools to correctly detect when fail2ban is unreachable and automatically restart the backend container, preventing the situation where Docker treats the container as healthy despite fail2ban being down. Changes: - Update GET /api/health to return 503 on fail2ban offline - Return appropriate JSON response bodies for each state - Update tests to verify both online (200) and offline (503) scenarios - Update Dockerfile HEALTHCHECK documentation - Add Health Checks section to Deployment.md documentation All tests pass with 100% coverage on health.py. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
51 lines
2.0 KiB
Python
51 lines
2.0 KiB
Python
"""Tests for the health check router."""
|
|
|
|
import pytest
|
|
from httpx import AsyncClient
|
|
|
|
from app.models.server import ServerStatus
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_health_check_returns_200_when_online(client: AsyncClient) -> None:
|
|
"""``GET /api/health`` must return HTTP 200 when fail2ban is online."""
|
|
client._transport.app.state.server_status = ServerStatus(online=True)
|
|
response = await client.get("/api/health")
|
|
assert response.status_code == 200
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_health_check_returns_503_when_offline(client: AsyncClient) -> None:
|
|
"""``GET /api/health`` must return HTTP 503 when fail2ban is offline."""
|
|
client._transport.app.state.server_status = ServerStatus(online=False)
|
|
response = await client.get("/api/health")
|
|
assert response.status_code == 503
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_health_check_returns_ok_status_when_online(client: AsyncClient) -> None:
|
|
"""``GET /api/health`` must contain ``status: ok`` when fail2ban is online."""
|
|
client._transport.app.state.server_status = ServerStatus(online=True)
|
|
response = await client.get("/api/health")
|
|
data: dict[str, str] = response.json()
|
|
assert data["status"] == "ok"
|
|
assert data["fail2ban"] == "online"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_health_check_returns_unavailable_when_offline(client: AsyncClient) -> None:
|
|
"""``GET /api/health`` must contain ``status: unavailable`` when fail2ban is offline."""
|
|
client._transport.app.state.server_status = ServerStatus(online=False)
|
|
response = await client.get("/api/health")
|
|
data: dict[str, str] = response.json()
|
|
assert data["status"] == "unavailable"
|
|
assert data["fail2ban"] == "offline"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_health_check_content_type_is_json(client: AsyncClient) -> None:
|
|
"""``GET /api/health`` must set the ``Content-Type`` header to JSON."""
|
|
response = await client.get("/api/health")
|
|
assert "application/json" in response.headers.get("content-type", "")
|
|
|