Skip to main content
Glama
test_health.py15 kB
"""Tests for health check system.""" from autodoc_mcp.health import HealthCheck, HealthChecker, HealthStatus class TestHealthCheck: """Test HealthCheck dataclass.""" def test_health_check_creation(self): """Test creating a health check.""" check = HealthCheck( name="test_check", status=HealthStatus.HEALTHY, message="All good", response_time_ms=150.0, timestamp=1234567890.0, ) assert check.name == "test_check" assert check.status == HealthStatus.HEALTHY assert check.message == "All good" assert check.response_time_ms == 150.0 assert check.timestamp == 1234567890.0 class TestHealthChecker: """Test HealthChecker functionality.""" def setup_method(self): """Set up test fixtures.""" self.health_checker = HealthChecker() async def test_check_cache_manager_not_initialized(self, mocker): """Test cache manager health when not initialized.""" mocker.patch("autodoc_mcp.main.cache_manager", None) result = await self.health_checker.check_cache_manager() assert result.name == "cache_manager" assert result.status == HealthStatus.UNHEALTHY assert "not initialized" in result.message.lower() async def test_check_cache_manager_healthy(self, mocker): """Test cache manager health when working.""" mock_cache_manager = mocker.AsyncMock() mock_cache_manager.get_cache_stats.return_value = {"total_entries": 5} mock_cache_manager.invalidate.return_value = None mocker.patch("autodoc_mcp.main.cache_manager", mock_cache_manager) result = await self.health_checker.check_cache_manager() assert result.name == "cache_manager" assert result.status == HealthStatus.HEALTHY assert "working" in result.message.lower() assert result.response_time_ms > 0 async def test_check_cache_manager_error(self, mocker): """Test cache manager health when erroring.""" mock_cache_manager = mocker.AsyncMock() mock_cache_manager.get_cache_stats.side_effect = Exception("Cache error") mocker.patch("autodoc_mcp.main.cache_manager", mock_cache_manager) result = await self.health_checker.check_cache_manager() assert result.name == "cache_manager" assert result.status == HealthStatus.UNHEALTHY assert "Cache error" in result.message async def test_check_pypi_connectivity_healthy(self, mocker): """Test PyPI connectivity when working.""" mock_client = mocker.AsyncMock() mock_client.__aenter__.return_value = mock_client mock_client.__aexit__.return_value = None mock_client.get_with_retry.return_value = {} mock_class = mocker.patch( "autodoc_mcp.core.network_resilience.NetworkResilientClient" ) mock_class.return_value = mock_client result = await self.health_checker.check_pypi_connectivity() assert result.name == "pypi_connectivity" assert result.status == HealthStatus.HEALTHY assert "accessible" in result.message.lower() async def test_check_pypi_connectivity_404_is_healthy(self, mocker): """Test that 404 from PyPI is considered healthy (PyPI is working).""" mock_client = mocker.AsyncMock() mock_client.__aenter__.return_value = mock_client mock_client.__aexit__.return_value = None mock_client.get_with_retry.side_effect = Exception("404 not found") mock_class = mocker.patch( "autodoc_mcp.core.network_resilience.NetworkResilientClient" ) mock_class.return_value = mock_client result = await self.health_checker.check_pypi_connectivity() assert result.name == "pypi_connectivity" assert result.status == HealthStatus.HEALTHY assert "expected error" in result.message async def test_check_pypi_connectivity_network_error(self, mocker): """Test PyPI connectivity with network error.""" mock_client = mocker.AsyncMock() mock_client.__aenter__.return_value = mock_client mock_client.__aexit__.return_value = None mock_client.get_with_retry.side_effect = Exception("Connection timeout") mock_class = mocker.patch( "autodoc_mcp.core.network_resilience.NetworkResilientClient" ) mock_class.return_value = mock_client result = await self.health_checker.check_pypi_connectivity() assert result.name == "pypi_connectivity" assert result.status == HealthStatus.UNHEALTHY assert "Connection timeout" in result.message async def test_check_dependencies_not_initialized(self, mocker): """Test dependency parser when not initialized.""" mocker.patch("autodoc_mcp.main.parser", None) result = await self.health_checker.check_dependencies() assert result.name == "dependency_parser" assert result.status == HealthStatus.UNHEALTHY assert "not initialized" in result.message.lower() async def test_check_dependencies_healthy(self, mocker): """Test dependency parser when working.""" mock_parser = mocker.AsyncMock() mock_result = mocker.MagicMock() mock_result.successful_deps = 1 mock_parser.parse_project.return_value = mock_result mocker.patch("autodoc_mcp.main.parser", mock_parser) result = await self.health_checker.check_dependencies() assert result.name == "dependency_parser" assert result.status == HealthStatus.HEALTHY assert "found 1 dependencies" in result.message async def test_check_dependencies_no_deps_found(self, mocker): """Test dependency parser when no dependencies found.""" mock_parser = mocker.AsyncMock() mock_result = mocker.MagicMock() mock_result.successful_deps = 0 mock_parser.parse_project.return_value = mock_result mocker.patch("autodoc_mcp.main.parser", mock_parser) result = await self.health_checker.check_dependencies() assert result.name == "dependency_parser" assert result.status == HealthStatus.DEGRADED assert "found no dependencies" in result.message async def test_check_dependencies_error(self, mocker): """Test dependency parser when erroring.""" mock_parser = mocker.AsyncMock() mock_parser.parse_project.side_effect = Exception("Parse error") mocker.patch("autodoc_mcp.main.parser", mock_parser) result = await self.health_checker.check_dependencies() assert result.name == "dependency_parser" assert result.status == HealthStatus.UNHEALTHY assert "Parse error" in result.message async def test_check_context_fetcher_not_initialized(self, mocker): """Test context fetcher when not initialized.""" mocker.patch("autodoc_mcp.main.context_fetcher", None) result = await self.health_checker.check_context_fetcher() assert result.name == "context_fetcher" assert result.status == HealthStatus.UNHEALTHY assert "not initialized" in result.message.lower() async def test_check_context_fetcher_healthy(self, mocker): """Test context fetcher when healthy.""" mock_context_fetcher = mocker.MagicMock() mock_context_fetcher.cache_manager = mocker.MagicMock() mock_context_fetcher.dependency_resolver = mocker.MagicMock() mock_context_fetcher.formatter = mocker.MagicMock() mocker.patch("autodoc_mcp.main.context_fetcher", mock_context_fetcher) result = await self.health_checker.check_context_fetcher() assert result.name == "context_fetcher" assert result.status == HealthStatus.HEALTHY assert "all components" in result.message async def test_check_context_fetcher_partially_initialized(self, mocker): """Test context fetcher when partially initialized.""" mock_context_fetcher = mocker.MagicMock() mock_context_fetcher.cache_manager = None mock_context_fetcher.dependency_resolver = mocker.MagicMock() mock_context_fetcher.formatter = mocker.MagicMock() mocker.patch("autodoc_mcp.main.context_fetcher", mock_context_fetcher) result = await self.health_checker.check_context_fetcher() assert result.name == "context_fetcher" assert result.status == HealthStatus.DEGRADED assert "partially initialized" in result.message async def test_get_overall_health_all_healthy(self, mocker): """Test overall health when all checks are healthy.""" mock_cache = mocker.patch.object(self.health_checker, "check_cache_manager") mock_pypi = mocker.patch.object(self.health_checker, "check_pypi_connectivity") mock_deps = mocker.patch.object(self.health_checker, "check_dependencies") mock_context = mocker.patch.object(self.health_checker, "check_context_fetcher") mock_cache.return_value = HealthCheck( "cache", HealthStatus.HEALTHY, "ok", 10.0, 123.0 ) mock_pypi.return_value = HealthCheck( "pypi", HealthStatus.HEALTHY, "ok", 20.0, 124.0 ) mock_deps.return_value = HealthCheck( "deps", HealthStatus.HEALTHY, "ok", 15.0, 125.0 ) mock_context.return_value = HealthCheck( "context", HealthStatus.HEALTHY, "ok", 5.0, 126.0 ) result = await self.health_checker.get_overall_health() assert result["status"] == "healthy" assert result["summary"]["healthy"] == 4 assert result["summary"]["degraded"] == 0 assert result["summary"]["unhealthy"] == 0 assert result["summary"]["total"] == 4 async def test_get_overall_health_with_degraded(self, mocker): """Test overall health with degraded components.""" mock_cache = mocker.patch.object(self.health_checker, "check_cache_manager") mock_pypi = mocker.patch.object(self.health_checker, "check_pypi_connectivity") mock_deps = mocker.patch.object(self.health_checker, "check_dependencies") mock_context = mocker.patch.object(self.health_checker, "check_context_fetcher") mock_cache.return_value = HealthCheck( "cache", HealthStatus.HEALTHY, "ok", 10.0, 123.0 ) mock_pypi.return_value = HealthCheck( "pypi", HealthStatus.DEGRADED, "slow", 100.0, 124.0 ) mock_deps.return_value = HealthCheck( "deps", HealthStatus.HEALTHY, "ok", 15.0, 125.0 ) mock_context.return_value = HealthCheck( "context", HealthStatus.HEALTHY, "ok", 5.0, 126.0 ) result = await self.health_checker.get_overall_health() assert result["status"] == "degraded" assert result["summary"]["healthy"] == 3 assert result["summary"]["degraded"] == 1 assert result["summary"]["unhealthy"] == 0 async def test_get_overall_health_with_unhealthy(self, mocker): """Test overall health with unhealthy components.""" mock_cache = mocker.patch.object(self.health_checker, "check_cache_manager") mock_pypi = mocker.patch.object(self.health_checker, "check_pypi_connectivity") mock_deps = mocker.patch.object(self.health_checker, "check_dependencies") mock_context = mocker.patch.object(self.health_checker, "check_context_fetcher") mock_cache.return_value = HealthCheck( "cache", HealthStatus.UNHEALTHY, "down", 0.0, 123.0 ) mock_pypi.return_value = HealthCheck( "pypi", HealthStatus.HEALTHY, "ok", 20.0, 124.0 ) mock_deps.return_value = HealthCheck( "deps", HealthStatus.HEALTHY, "ok", 15.0, 125.0 ) mock_context.return_value = HealthCheck( "context", HealthStatus.HEALTHY, "ok", 5.0, 126.0 ) result = await self.health_checker.get_overall_health() assert result["status"] == "unhealthy" assert result["summary"]["healthy"] == 3 assert result["summary"]["degraded"] == 0 assert result["summary"]["unhealthy"] == 1 async def test_get_overall_health_with_exception(self, mocker): """Test overall health handling of exceptions.""" mock_cache = mocker.patch.object(self.health_checker, "check_cache_manager") mock_pypi = mocker.patch.object(self.health_checker, "check_pypi_connectivity") mock_deps = mocker.patch.object(self.health_checker, "check_dependencies") mock_context = mocker.patch.object(self.health_checker, "check_context_fetcher") mock_cache.side_effect = Exception("Check failed") mock_pypi.return_value = HealthCheck( "pypi", HealthStatus.HEALTHY, "ok", 20.0, 124.0 ) mock_deps.return_value = HealthCheck( "deps", HealthStatus.HEALTHY, "ok", 15.0, 125.0 ) mock_context.return_value = HealthCheck( "context", HealthStatus.HEALTHY, "ok", 5.0, 126.0 ) result = await self.health_checker.get_overall_health() assert result["status"] == "unhealthy" assert result["summary"]["healthy"] == 3 assert result["summary"]["unhealthy"] == 1 assert "unknown_error" in result["checks"] async def test_get_readiness_status_ready(self, mocker): """Test readiness check when all services ready.""" mocker.patch("autodoc_mcp.main.parser", mocker.MagicMock()) mocker.patch("autodoc_mcp.main.cache_manager", mocker.MagicMock()) mocker.patch("autodoc_mcp.main.version_resolver", mocker.MagicMock()) mocker.patch("autodoc_mcp.main.context_fetcher", mocker.MagicMock()) result = await self.health_checker.get_readiness_status() assert result["ready"] is True assert "timestamp" in result async def test_get_readiness_status_not_ready(self, mocker): """Test readiness check when services not ready.""" mocker.patch("autodoc_mcp.main.parser", None) mocker.patch("autodoc_mcp.main.cache_manager", mocker.MagicMock()) mocker.patch("autodoc_mcp.main.version_resolver", mocker.MagicMock()) mocker.patch("autodoc_mcp.main.context_fetcher", mocker.MagicMock()) result = await self.health_checker.get_readiness_status() assert result["ready"] is False assert "parser" in result["reason"] assert "timestamp" in result async def test_get_readiness_status_exception(self, mocker): """Test readiness check handling exceptions.""" mocker.patch("autodoc_mcp.main.parser", None) result = await self.health_checker.get_readiness_status() assert result["ready"] is False assert "Services not initialized" in result["reason"] assert "parser" in result["reason"]

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bradleyfay/autodoc-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server