110 lines
4.1 KiB
Python
110 lines
4.1 KiB
Python
"""Tests for the AI health check script (scripts/ai_health_check.py)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
# Add scripts dir to path
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts"))
|
|
|
|
|
|
def test_enumerate_routes_returns_api_routes():
|
|
"""enumerate_routes should return only /api/ routes with methods."""
|
|
from ai_health_check import enumerate_routes
|
|
|
|
routes = enumerate_routes()
|
|
assert isinstance(routes, list)
|
|
assert len(routes) > 0
|
|
for route in routes:
|
|
assert route["path"].startswith("/api/")
|
|
assert isinstance(route["methods"], list)
|
|
assert len(route["methods"]) > 0
|
|
|
|
|
|
def test_enumerate_routes_excludes_non_api():
|
|
"""enumerate_routes should not include non-API paths like /docs or /openapi.json."""
|
|
from ai_health_check import enumerate_routes
|
|
|
|
routes = enumerate_routes()
|
|
paths = [r["path"] for r in routes]
|
|
assert not any(p.startswith("/docs") for p in paths)
|
|
assert not any(p.startswith("/openapi") for p in paths)
|
|
|
|
|
|
def test_format_json_report_structure():
|
|
"""JSON report should have summary and endpoints keys."""
|
|
from ai_health_check import format_json_report
|
|
|
|
results = [
|
|
{"endpoint": "/api/v1/health", "method": "GET", "status": 200, "response_time_ms": 5.0, "healthy": True, "tags": ["health"], "note": ""},
|
|
{"endpoint": "/api/v1/users", "method": "POST", "status": "skipped", "response_time_ms": 0, "healthy": True, "tags": ["users"], "note": "Non-GET method — documented only"},
|
|
]
|
|
report = json.loads(format_json_report(results))
|
|
assert "summary" in report
|
|
assert "endpoints" in report
|
|
assert report["summary"]["total_endpoints"] == 2
|
|
assert report["summary"]["healthy"] == 1
|
|
assert report["summary"]["skipped"] == 1
|
|
assert report["summary"]["all_healthy"] is True
|
|
|
|
|
|
def test_format_json_report_with_failures():
|
|
"""JSON report should mark all_healthy=False when failures exist."""
|
|
from ai_health_check import format_json_report
|
|
|
|
results = [
|
|
{"endpoint": "/api/v1/health", "method": "GET", "status": 200, "response_time_ms": 5.0, "healthy": True, "tags": [], "note": ""},
|
|
{"endpoint": "/api/v1/broken", "method": "GET", "status": 500, "response_time_ms": 10.0, "healthy": False, "tags": [], "note": "HTTP 500"},
|
|
]
|
|
report = json.loads(format_json_report(results))
|
|
assert report["summary"]["failed"] == 1
|
|
assert report["summary"]["all_healthy"] is False
|
|
|
|
|
|
def test_format_csv_report_has_header():
|
|
"""CSV report should have a header row with expected columns."""
|
|
from ai_health_check import format_csv_report
|
|
|
|
results = [
|
|
{"endpoint": "/api/v1/health", "method": "GET", "status": 200, "response_time_ms": 5.0, "healthy": True, "tags": ["health"], "note": ""},
|
|
]
|
|
csv_output = format_csv_report(results)
|
|
lines = csv_output.strip().split("\n")
|
|
assert "endpoint" in lines[0]
|
|
assert "method" in lines[0]
|
|
assert "status" in lines[0]
|
|
assert "/api/v1/health" in lines[1]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_probe_all_endpoints_skips_non_get():
|
|
"""probe_all_endpoints should skip POST/PUT/DELETE methods."""
|
|
from ai_health_check import probe_all_endpoints
|
|
|
|
routes = [
|
|
{"path": "/api/v1/users", "methods": ["POST"], "tags": ["users"]},
|
|
]
|
|
results = await probe_all_endpoints("http://localhost:8000", "fake-token", routes)
|
|
assert len(results) == 1
|
|
assert results[0]["status"] == "skipped"
|
|
assert results[0]["healthy"] is True
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_probe_all_endpoints_handles_connection_error():
|
|
"""probe_all_endpoints should handle connection errors gracefully."""
|
|
from ai_health_check import probe_all_endpoints
|
|
|
|
routes = [
|
|
{"path": "/api/v1/health", "methods": ["GET"], "tags": ["health"]},
|
|
]
|
|
results = await probe_all_endpoints("http://nonexistent-host:9999", "fake-token", routes)
|
|
assert len(results) == 1
|
|
assert results[0]["healthy"] is False
|
|
assert results[0]["status"] in ("connection_error", "error")
|