""" tests/test_risk_dashboard.py — Tests for compute_risk_dashboard. Validates: - Top-N sorting by score desc - Band count aggregation - Critical P0 service detection - Env filtering passed through """ import pytest import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "services" / "router")) from risk_engine import _builtin_defaults, compute_risk_dashboard, _reload_policy @pytest.fixture(autouse=True) def reset_policy_cache(): _reload_policy() yield _reload_policy() @pytest.fixture def policy(): return _builtin_defaults() def _make_report(service, score, band=None, env="prod"): from risk_engine import score_to_band p = _builtin_defaults() b = band or score_to_band(score, p) return { "service": service, "env": env, "score": score, "band": b, "thresholds": {"warn_at": 50, "fail_at": 80}, "components": {}, "reasons": [], "recommendations": [], "updated_at": "2026-02-23T00:00:00", } class TestDashboardSorting: def test_sorted_desc_by_score(self, policy): reports = [ _make_report("a", 30), _make_report("b", 90), _make_report("c", 10), _make_report("d", 55), ] dash = compute_risk_dashboard("prod", top_n=10, service_reports=reports, policy=policy) scores = [s["score"] for s in dash["services"]] assert scores == sorted(scores, reverse=True) def test_top_n_limits_results(self, policy): reports = [_make_report(f"svc{i}", i * 5) for i in range(15)] dash = compute_risk_dashboard("prod", top_n=5, service_reports=reports, policy=policy) assert len(dash["services"]) == 5 def test_top_n_returns_highest(self, policy): reports = [_make_report(f"svc{i}", i * 5) for i in range(10)] dash = compute_risk_dashboard("prod", top_n=3, service_reports=reports, policy=policy) assert all(s["score"] >= 30 for s in dash["services"]) def test_empty_service_reports(self, policy): dash = compute_risk_dashboard("prod", top_n=10, service_reports=[], policy=policy) assert dash["services"] == [] assert dash["total_services"] == 0 class TestBandCounts: def test_band_counts_correct(self, policy): reports = [ _make_report("a", 0, band="low"), _make_report("b", 21, band="medium"), _make_report("c", 51, band="high"), _make_report("d", 81, band="critical"), _make_report("e", 85, band="critical"), ] dash = compute_risk_dashboard("prod", top_n=10, service_reports=reports, policy=policy) bc = dash["band_counts"] assert bc["low"] == 1 assert bc["medium"] == 1 assert bc["high"] == 1 assert bc["critical"] == 2 class TestP0Detection: def test_critical_p0_services_detected(self, policy): """gateway and router are p0_services. critical/high band → flagged.""" reports = [ _make_report("gateway", 85, band="critical"), # p0, critical _make_report("router", 60, band="high"), # p0, high _make_report("memory-service", 90, band="critical"), # not p0 ] dash = compute_risk_dashboard("prod", top_n=10, service_reports=reports, policy=policy) crit_p0 = dash["critical_p0_services"] assert "gateway" in crit_p0 assert "router" in crit_p0 assert "memory-service" not in crit_p0 def test_low_band_p0_not_flagged(self, policy): reports = [_make_report("gateway", 10, band="low")] dash = compute_risk_dashboard("prod", top_n=10, service_reports=reports, policy=policy) assert "gateway" not in dash["critical_p0_services"] class TestDashboardMetadata: def test_env_passed_through(self, policy): dash = compute_risk_dashboard("staging", top_n=5, service_reports=[], policy=policy) assert dash["env"] == "staging" def test_generated_at_present(self, policy): dash = compute_risk_dashboard("prod", service_reports=[], policy=policy) assert "generated_at" in dash assert dash["generated_at"] def test_total_services_count(self, policy): reports = [_make_report(f"s{i}", i * 10) for i in range(4)] dash = compute_risk_dashboard("prod", top_n=10, service_reports=reports, policy=policy) assert dash["total_services"] == 4