"""Tests for webhook health dashboard generation.""" from __future__ import annotations import importlib.util import json import sys import time from pathlib import Path from unittest.mock import patch PROJECT_ROOT = Path(__file__).parent.parent _spec = importlib.util.spec_from_file_location( "webhook_health_dashboard_test", PROJECT_ROOT / "bin" / "webhook_health_dashboard.py", ) _mod = importlib.util.module_from_spec(_spec) sys.modules["webhook_health_dashboard_test"] = _mod _spec.loader.exec_module(_mod) AgentHealth = _mod.AgentHealth check_agents = _mod.check_agents load_history = _mod.load_history parse_targets = _mod.parse_targets save_history = _mod.save_history sort_key = None to_markdown = _mod.to_markdown write_dashboard = _mod.write_dashboard main = _mod.main class TestParseTargets: def test_defaults_when_none(self): targets = parse_targets(None) assert targets["allegro"].endswith(":8651/health") assert targets["ezra"].endswith(":8652/health") def test_parse_csv_mapping(self): targets = parse_targets("alpha=http://a/health,beta=http://b/health") assert targets == { "alpha": "http://a/health", "beta": "http://b/health", } class TestCheckAgents: @patch("webhook_health_dashboard_test.probe_health") def test_updates_last_success_for_healthy(self, mock_probe): mock_probe.return_value = (True, 200, 42, "HTTP 200") history = {"agents": {}, "runs": []} results = check_agents({"allegro": "http://localhost:8651/health"}, history, timeout=1, stale_after=300) assert len(results) == 1 assert results[0].healthy is True assert history["agents"]["allegro"]["last_success_ts"] is not None @patch("webhook_health_dashboard_test.probe_health") def test_marks_stale_after_threshold(self, mock_probe): mock_probe.return_value = (False, None, 12, "URL error: refused") history = { "agents": { "allegro": { "last_success_ts": time.time() - 301, } }, "runs": [], } results = check_agents({"allegro": "http://localhost:8651/health"}, history, timeout=1, stale_after=300) assert results[0].healthy is False assert results[0].stale is True class TestMarkdown: def test_contains_table_and_icons(self): now = time.time() results = [ AgentHealth("allegro", "http://localhost:8651/health", 200, True, 31, False, now - 5, now, "HTTP 200 — ok"), AgentHealth("ezra", "http://localhost:8652/health", None, False, 14, True, now - 600, now, "URL error: refused"), ] md = to_markdown(results, generated_at=now) assert "| Agent | Status | HTTP |" in md assert "🟢" in md assert "🔴" in md assert "Stale agents" in md assert "ezra" in md class TestFileIO: def test_save_and_load_history(self, tmp_path): path = tmp_path / "history.json" payload = {"agents": {"a": {"last_success_ts": 1}}, "runs": []} save_history(path, payload) loaded = load_history(path) assert loaded == payload def test_write_dashboard(self, tmp_path): out = tmp_path / "dashboard.md" write_dashboard(out, "# Test") assert out.read_text() == "# Test\n" class TestMain: @patch("webhook_health_dashboard_test.probe_health") def test_main_writes_outputs(self, mock_probe, tmp_path): mock_probe.return_value = (True, 200, 10, "HTTP 200") output = tmp_path / "dashboard.md" history = tmp_path / "history.json" rc = main([ "--targets", "allegro=http://localhost:8651/health", "--output", str(output), "--history", str(history), "--timeout", "1", "--stale-after", "300", ]) assert rc == 0 assert output.exists() assert history.exists() assert "allegro" in output.read_text() runs = json.loads(history.read_text())["runs"] assert len(runs) == 1