Files
group_fqcd_jr/tests/unit/service/test_health_service.py
T

107 lines
3.7 KiB
Python
Raw Normal View History

"""就绪探针(B3)单元测试:Milvus 可用/不可用/客户端缺失/探测超时。"""
import asyncio
from typing import Any
2026-09-09 23:40:35 +08:00
import pytest
from app.service import health_service
2026-09-09 23:40:35 +08:00
from app.service.health_service import HealthService
class FakeMilvusClient:
def __init__(self, *, version: Any = "pkg/v2.5.4", error: Exception | None = None,
delay: float = 0.0) -> None:
self._version = version
self._error = error
self._delay = delay
self.closed = False
async def get_server_version(self) -> Any:
if self._delay:
await asyncio.sleep(self._delay)
if self._error is not None:
raise self._error
return self._version
async def close(self) -> None:
self.closed = True
def patch_client(monkeypatch: pytest.MonkeyPatch, client: Any) -> None:
monkeypatch.setattr(health_service, "_create_milvus_client", lambda uri, token: client)
async def test_available_milvus_reports_ok(monkeypatch: pytest.MonkeyPatch) -> None:
client = FakeMilvusClient()
patch_client(monkeypatch, client)
ready, state = await HealthService()._milvus_ready()
assert (ready, state) == (True, "ok")
assert client.closed is True
@pytest.mark.parametrize("error", [ConnectionError("refused"), RuntimeError("grpc down")])
async def test_unavailable_milvus_reports_unavailable(
monkeypatch: pytest.MonkeyPatch, error: Exception
) -> None:
client = FakeMilvusClient(error=error)
patch_client(monkeypatch, client)
ready, state = await HealthService()._milvus_ready()
assert (ready, state) == (False, "unavailable")
assert client.closed is True
async def test_missing_pymilvus_reports_client_missing(monkeypatch: pytest.MonkeyPatch) -> None:
def missing(uri: str, token: str) -> Any:
raise ImportError("No module named 'pymilvus'")
monkeypatch.setattr(health_service, "_create_milvus_client", missing)
ready, state = await HealthService()._milvus_ready()
assert (ready, state) == (False, "client_missing")
async def test_probe_timeout_is_bounded(monkeypatch: pytest.MonkeyPatch) -> None:
client = FakeMilvusClient(delay=5.0)
patch_client(monkeypatch, client)
ready, state = await HealthService(milvus_timeout_seconds=0.05)._milvus_ready()
assert (ready, state) == (False, "timeout")
async def test_ready_reflects_real_milvus_probe(monkeypatch: pytest.MonkeyPatch) -> None:
client = FakeMilvusClient(error=ConnectionError("milvus stopped"))
patch_client(monkeypatch, client)
async def redis_ok(_self: HealthService) -> bool:
return True
monkeypatch.setattr(HealthService, "_redis_ready", redis_ok)
result = await HealthService().ready()
assert result["checks"]["milvus"] is False
assert result["probes"]["milvus"] == "unavailable"
assert result["status"] == "degraded"
async def test_ready_is_ready_when_all_probes_pass(monkeypatch: pytest.MonkeyPatch) -> None:
patch_client(monkeypatch, FakeMilvusClient())
async def redis_ok(_self: HealthService) -> bool:
return True
monkeypatch.setattr(HealthService, "_redis_ready", redis_ok)
result = await HealthService().ready()
assert result["checks"]["milvus"] is True
assert result["probes"]["milvus"] == "ok"
assert result["checks"]["mysql"] is True
2026-09-09 23:40:35 +08:00
async def test_redis_failure_marks_readiness_degraded(monkeypatch: pytest.MonkeyPatch) -> None:
async def unavailable(self: HealthService) -> bool:
return False
monkeypatch.setattr(HealthService, "_redis_ready", unavailable)
patch_client(monkeypatch, FakeMilvusClient())
2026-09-09 23:40:35 +08:00
service = HealthService()
result = await service.ready()
assert result["checks"]["redis"] is False
assert result["status"] == "degraded"