"""The Status page says what is wrong, and since when, before anything else (#5120).""" from datetime import datetime, timedelta, timezone from types import SimpleNamespace import pytest from quart import render_template from steward.core.status import StatusEntry, streak_start from tests.test_style_tokens import hex_colours T0 = datetime(2026, 10, 6, 18, 0, tzinfo=timezone.utc) def _checks(*ups): return [SimpleNamespace(is_up=up, checked_at=T0 + timedelta(minutes=i)) for i, up in enumerate(ups)] @pytest.mark.parametrize("ups, since, at_least", [ ((), None, False), ((True,), 0, True), ((False, False, False), 0, True), # down for every check we have ((True, True, False, False), 2, False), # went down at the third check ((False, True, True, False), 3, False), ]) def test_streak_start(ups, since, at_least): checks = _checks(*ups) assert streak_start(checks) == ((checks[since].checked_at if since is not None else None), at_least) async def _rows(app, entries, alerts): async with app.test_request_context("/status/rows"): return await render_template( "status/rows.html", entries=entries, alerts=alerts, problems=[e for e in entries if e.status == "down"], up=sum(e.status == "up" for e in entries), down=sum(e.status == "down" for e in entries), pending=0) async def test_the_problems_come_first_and_say_since_when(app): now = datetime.now(timezone.utc) entries = [ StatusEntry(kind="http", key="1", name="shop-api", target="https://shop/x", status="down", since=now - timedelta(minutes=12), uptime={"24h": 93.0}, tls_days=2.0), StatusEntry(kind="icmp", key="2", name="nas", target="10.0.0.5", status="up", since=now - timedelta(days=3), since_at_least=True, uptime={"24h": 100.0}), ] state = SimpleNamespace(state=SimpleNamespace(value="firing"), no_data_since=None, last_transition_at=now - timedelta(minutes=4)) rule = SimpleNamespace(id="r1", name="CPU high", resource_name="web01", metric_name="cpu_pct", operator=SimpleNamespace(value=">"), threshold=90) page = await _rows(app, entries, [(state, rule)]) attention = page.index("Needs attention") assert attention < page.index("Recent checks") # before the full list problem_card = page[attention:page.index("")] assert "shop-api" in problem_card and "nas" not in problem_card assert "down since 12m ago" in problem_card assert "CPU high" in problem_card and "cpu_pct > 90" in problem_card and ">4m ago" in problem_card assert 'Firing' in problem_card # Uptime and TLS coloured by Settings → Thresholds, not by literals. assert '93.00%' in page and '100.00%' in page assert 'class="tone-crit" title="TLS certificate expires in 2 days">2d' in page assert not hex_colours(page), hex_colours(page) async def test_a_quiet_board_has_no_problem_card(app): entries = [StatusEntry(kind="icmp", key="2", name="nas", target="10.0.0.5", status="up")] page = await _rows(app, entries, []) assert "Needs attention" not in page and "nas" in page assert "No monitors yet" in await _rows(app, [], [])