Newer
Older
vmk-360-data_collector / tests / integration / test_health.py
@Eugene Sukhodolskiy Eugene Sukhodolskiy 1 day ago 4 KB fix: code review critical and high issues
"""Unit tests for health endpoint."""

from contextlib import asynccontextmanager
from typing import Any
from unittest.mock import AsyncMock, MagicMock

import pytest
from fastapi import status
from httpx import AsyncClient

from vmk_data_collector.api.v1 import router_health


def _make_mock_engine(healthy: bool = True) -> Any:
    mock_conn = AsyncMock()
    mock_conn.execute = AsyncMock()

    @asynccontextmanager
    async def connect_cm():
        if not healthy:
            raise RuntimeError("db down")
        yield mock_conn

    engine = MagicMock()
    engine.connect = connect_cm
    return engine


def _make_fake_httpx_client(healthy: bool = True) -> type:
    class FakeClient:
        def __init__(self, *a: Any, **k: Any) -> None:
            pass

        async def __aenter__(self):
            return self

        async def __aexit__(self, *a: Any) -> None:
            pass

        async def get(self, *a: Any, **k: Any) -> Any:
            if not healthy:
                raise RuntimeError("ollama down")
            resp = MagicMock()
            resp.raise_for_status = lambda: None
            return resp

    return FakeClient


class TestHealthCheck:
    @pytest.mark.asyncio
    async def test_all_healthy_returns_200(
        self,
        async_client: AsyncClient,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        monkeypatch.setattr(router_health, "engine", _make_mock_engine(healthy=True))
        monkeypatch.setattr(
            router_health.httpx,
            "AsyncClient",
            _make_fake_httpx_client(healthy=True),
        )
        monkeypatch.setattr(
            router_health.shutil,
            "disk_usage",
            lambda _p: MagicMock(free=500 * 1024 * 1024),
        )

        response = await async_client.get("/api/v1/health")
        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert data["status"] == "healthy"
        for check in data["checks"].values():
            assert check["status"] == "pass"

    @pytest.mark.asyncio
    async def test_db_fails_returns_503(
        self,
        async_client: AsyncClient,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        monkeypatch.setattr(router_health, "engine", _make_mock_engine(healthy=False))
        monkeypatch.setattr(
            router_health.httpx,
            "AsyncClient",
            _make_fake_httpx_client(healthy=True),
        )
        monkeypatch.setattr(
            router_health.shutil,
            "disk_usage",
            lambda _p: MagicMock(free=500 * 1024 * 1024),
        )

        response = await async_client.get("/api/v1/health")
        assert response.status_code == status.HTTP_503_SERVICE_UNAVAILABLE
        data = response.json()
        assert data["status"] == "degraded"
        assert data["checks"]["database"]["status"] == "fail"
        assert data["checks"]["ollama"]["status"] == "pass"

    @pytest.mark.asyncio
    async def test_ollama_fails_returns_503(
        self,
        async_client: AsyncClient,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        monkeypatch.setattr(router_health, "engine", _make_mock_engine(healthy=True))
        monkeypatch.setattr(
            router_health.httpx,
            "AsyncClient",
            _make_fake_httpx_client(healthy=False),
        )
        monkeypatch.setattr(
            router_health.shutil,
            "disk_usage",
            lambda _p: MagicMock(free=500 * 1024 * 1024),
        )

        response = await async_client.get("/api/v1/health")
        assert response.status_code == status.HTTP_503_SERVICE_UNAVAILABLE
        data = response.json()
        assert data["checks"]["ollama"]["status"] == "fail"

    @pytest.mark.asyncio
    async def test_low_disk_returns_503(
        self,
        async_client: AsyncClient,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        monkeypatch.setattr(router_health, "engine", _make_mock_engine(healthy=True))
        monkeypatch.setattr(
            router_health.httpx,
            "AsyncClient",
            _make_fake_httpx_client(healthy=True),
        )
        monkeypatch.setattr(
            router_health.shutil,
            "disk_usage",
            lambda _p: MagicMock(free=10),  # way below 100 MB
        )

        response = await async_client.get("/api/v1/health")
        assert response.status_code == status.HTTP_503_SERVICE_UNAVAILABLE
        data = response.json()
        assert data["checks"]["disk"]["status"] == "fail"