117 lines
3.8 KiB
Python
117 lines
3.8 KiB
Python
"""Tests for EPUB search health and readiness routes."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from fastapi.testclient import TestClient
|
|
from sqlalchemy import create_engine
|
|
|
|
from python.ebook_search.api.main import create_app
|
|
from python.ebook_search.config import EbookSearchConfig, RerankConfig
|
|
|
|
HEALTH_MODULE = "python.ebook_search.api.routes.health"
|
|
|
|
|
|
def fake_get_postgres_engine(**_kwargs):
|
|
"""Return an in-memory engine for route tests."""
|
|
return create_engine("sqlite+pysqlite:///:memory:", future=True)
|
|
|
|
|
|
def patch_app_runtime(monkeypatch):
|
|
monkeypatch.setattr("python.ebook_search.api.main.get_postgres_engine", fake_get_postgres_engine)
|
|
monkeypatch.setattr("python.ebook_search.api.main.ensure_bm25_corpus", lambda _session, _config: None)
|
|
|
|
|
|
def patch_dependencies(monkeypatch, *, database=True, embedding=True, chat=True, bm25="ok"):
|
|
monkeypatch.setattr(f"{HEALTH_MODULE}.check_database", lambda _session: database)
|
|
monkeypatch.setattr(f"{HEALTH_MODULE}.check_embedding_endpoint", lambda _config: embedding)
|
|
monkeypatch.setattr(f"{HEALTH_MODULE}.check_chat_endpoint", lambda _config: chat)
|
|
monkeypatch.setattr(f"{HEALTH_MODULE}.check_bm25_status", lambda _config: bm25)
|
|
|
|
|
|
def build_client(monkeypatch, config=None):
|
|
patch_app_runtime(monkeypatch)
|
|
app = create_app()
|
|
app.state.config = config or EbookSearchConfig(rerank=RerankConfig(enabled=False))
|
|
return TestClient(app)
|
|
|
|
|
|
def test_health_returns_ok(monkeypatch) -> None:
|
|
with build_client(monkeypatch) as client:
|
|
response = client.get("/health")
|
|
|
|
assert response.status_code == 200
|
|
assert response.json() == {"status": "ok"}
|
|
|
|
|
|
def test_ready_all_dependencies_ok(monkeypatch) -> None:
|
|
patch_dependencies(monkeypatch)
|
|
|
|
with build_client(monkeypatch) as client:
|
|
response = client.get("/ready")
|
|
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert body["status"] == "ready"
|
|
assert body["checks"] == {"database": "ok", "embedding": "ok", "chat": "ok", "bm25": "ok"}
|
|
|
|
|
|
def test_ready_embedding_down_is_degraded(monkeypatch) -> None:
|
|
patch_dependencies(monkeypatch, embedding=False)
|
|
|
|
with build_client(monkeypatch) as client:
|
|
response = client.get("/ready")
|
|
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert body["status"] == "degraded"
|
|
assert body["checks"]["embedding"] == "fail"
|
|
|
|
|
|
def test_ready_chat_down_is_degraded(monkeypatch) -> None:
|
|
patch_dependencies(monkeypatch, chat=False)
|
|
|
|
with build_client(monkeypatch) as client:
|
|
response = client.get("/ready")
|
|
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert body["status"] == "degraded"
|
|
assert body["checks"]["chat"] == "fail"
|
|
|
|
|
|
def test_ready_chat_disabled_when_answers_off(monkeypatch) -> None:
|
|
patch_dependencies(monkeypatch)
|
|
config = EbookSearchConfig(rerank=RerankConfig(enabled=False), answer_enabled=False)
|
|
|
|
with build_client(monkeypatch, config) as client:
|
|
response = client.get("/ready")
|
|
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert body["status"] == "ready"
|
|
assert body["checks"]["chat"] == "disabled"
|
|
|
|
|
|
def test_ready_database_down_is_unavailable(monkeypatch) -> None:
|
|
patch_dependencies(monkeypatch, database=False)
|
|
|
|
with build_client(monkeypatch) as client:
|
|
response = client.get("/ready")
|
|
|
|
assert response.status_code == 503
|
|
body = response.json()
|
|
assert body["status"] == "unavailable"
|
|
assert body["checks"]["database"] == "fail"
|
|
|
|
|
|
def test_ready_bm25_missing_is_degraded(monkeypatch) -> None:
|
|
patch_dependencies(monkeypatch, bm25="missing")
|
|
|
|
with build_client(monkeypatch) as client:
|
|
response = client.get("/ready")
|
|
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert body["status"] == "degraded"
|
|
assert body["checks"]["bm25"] == "missing"
|