"""Health endpoint contract tests (handbook 10-platform/health.md)."""
from unittest.mock import AsyncMock
import pytest
from fastapi.testclient import TestClient
import navi.api.routes.health as health_mod
from navi.config import Settings
@pytest.fixture
def health_client(monkeypatch):
new_settings = Settings(_env_file=None, navi_persona_file="", hive_url="")
monkeypatch.setattr(health_mod, "settings", new_settings)
from navi.main import app
return TestClient(app)
@pytest.fixture(autouse=True)
def _fresh_embed_cache():
health_mod._embed_cache["checked_at"] = 0.0
health_mod._embed_cache["result"] = None
yield
def test_health_ok_when_all_checks_pass(health_client, monkeypatch):
monkeypatch.setattr(
health_mod, "_check_embed",
AsyncMock(return_value={"ok": True, "backend": "ollama:11434", "error": None}),
)
resp = health_client.get("/health")
assert resp.status_code == 200
body = resp.json()
assert body["status"] == "ok"
assert body["service"] == "navi"
assert body["checks"]["embed"]["status"] == "ok"
assert body["checks"]["hive"]["status"] == "ok"
def test_health_degraded_when_embed_fails(health_client, monkeypatch):
monkeypatch.setattr(
health_mod, "_check_embed",
AsyncMock(return_value={"ok": False, "backend": "none", "error": "connection refused"}),
)
body = health_client.get("/health").json()
assert body["status"] == "degraded"
assert body["checks"]["embed"]["status"] == "degraded"
assert body["checks"]["embed"]["detail"] == "connection refused"
def test_health_keeps_legacy_embed_payload(health_client, monkeypatch):
"""The pre-contract top-level `embed` dict must survive for existing tooling."""
monkeypatch.setattr(
health_mod, "_check_embed",
AsyncMock(return_value={"ok": True, "backend": "ollama:11434", "error": None}),
)
body = health_client.get("/health").json()
assert body["embed"]["ok"] is True
assert body["embed"]["backend"] == "ollama:11434"
def test_embed_check_is_cached(health_client, monkeypatch):
check = AsyncMock(return_value={"ok": True, "backend": "x", "error": None})
monkeypatch.setattr(health_mod, "_check_embed", check)
first = health_client.get("/health").json()
second = health_client.get("/health").json()
assert check.await_count == 1 # second poll was served from cache
assert first["checks"]["embed"] == second["checks"]["embed"]
assert isinstance(first["checks"]["embed"]["ms"], int)