"""The dashboard Alerts widget (#5510): a verdict, what is firing or silent with its reading and since when, then what someone has acknowledged, a line when alert email is failing, and the quiet rules counted.""" import re from datetime import datetime, timedelta, timezone from types import SimpleNamespace from quart import render_template, session from steward.alerts.service import widget_view from steward.core.widgets import WIDGET_REGISTRY from steward.models.alerts import AlertOperator from tests.test_style_tokens import hex_colours NOW = datetime.now(timezone.utc) QUIET_EMAIL = {"failed": 0, "retrying": 0, "said": ""} def _rule(rid, name, resource="web-1", metric="cpu_pct", op=">", threshold=90.0, parent_id=None, enabled=True): return SimpleNamespace(id=rid, name=name, resource_name=resource, metric_name=metric, operator=AlertOperator(op), threshold=threshold, parent_id=parent_id, enabled=enabled) def _row(rule, label, value=None, since=None, acked_by=None, acked_at=None): return {"rule": rule, "label": label, "value": value, "since": since, "acked_by": acked_by, "state": SimpleNamespace(acknowledged_at=acked_at)} async def _render(app, view, email=QUIET_EMAIL, role="admin"): async with app.test_request_context("/alerts/widget"): if role: session["user_id"] = "u1" session["user_role"] = role return await render_template("alerts/widget.html", **view, email=email) def test_the_widget_is_registered_and_points_at_alerts(): w = WIDGET_REGISTRY["alerts"] assert w["hx_url"] == "/alerts/widget" and w["detail_url"] == "/alerts/" and w["plugin"] is None def test_a_covering_rule_counts_once_and_is_quiet_only_when_all_its_hosts_are(): cover = _rule("c", "disk on every host", resource="*") kid_a = _rule("c-a", "disk on every host", resource="nas", parent_id="c") kid_b = _rule("c-b", "disk on every host", resource="web-1", parent_id="c") lone = _rule("l", "web up", metric="is_up", op="<", threshold=0.5) off = _rule("o", "old rule", enabled=False) view = widget_view([_row(kid_a, "firing", 91.0, NOW)], [cover, kid_a, kid_b, lone, off]) assert view["total"] == 2 and view["quiet"] == 1 # "web up"; the covering rule is busy assert view["rows"][0]["condition"] == "CPU > 90%" assert widget_view([], [cover, kid_a, kid_b, lone, off])["quiet"] == 2 async def test_firing_and_silent_come_first_then_who_acknowledged(app): hot = _rule("r1", "web-1 CPU high") gone = _rule("r2", "nas agent", resource="nas") taken = _rule("r3", "db disk", resource="db-1:/var", metric="disk_used_pct", op=">=", threshold=85.0) rows = [_row(hot, "firing", 94.0, NOW - timedelta(minutes=12)), _row(gone, "no_data", None, NOW - timedelta(hours=2)), _row(taken, "acknowledged", 88.0, NOW - timedelta(hours=3), acked_by="bryan", acked_at=NOW - timedelta(minutes=40))] page = await _render(app, widget_view(rows, [hot, gone, taken, _rule("r4", "quiet one")])) assert re.search(r'w-verdict tone-crit">\s*1 firing, 1 silent, 1 acknowledged\.', page) assert page.index("web-1 CPU high") < page.index("nas agent") < page.index("db disk") assert 'href="/alerts/history?rule=r1"' in page assert "web-1 · fires on CPU > 90%" in page and ">94%<" in page and ">12m " in page assert "nas · no reading" in page assert "db-1:/var · acknowledged by bryan 40m " in page assert "+1 rule quiet" in page and 'href="/alerts/"' in page assert len(re.findall(r"]", page)) == 3 assert not hex_colours(page), hex_colours(page) async def test_all_quiet_is_the_verdict_alone(app): rules = [_rule("r1", "a"), _rule("r2", "b")] page = await _render(app, widget_view([], rules)) assert re.search(r'w-verdict tone-ok">\s*Nothing firing: all 2 rules are quiet\.', page) assert "