"""The Prometheus dashboard widget (#5691): one target drawn by one template, in widget shape, and the dashboard pieces it needs (settings read when the picker opens, a Details link naming the target).""" import asyncio from datetime import timedelta from plugins.prometheus import library from plugins.prometheus.routes import spark_heights from plugins.prometheus.template_format import check from plugins.prometheus.template_view import render from steward.dashboard.routes import detail_url, with_options from tests._templates import render_plugin_template from tests.plugins.prometheus.test_templates import NOW, SERIES, TEMPLATE, T, latest, states from tests.test_style_tokens import hex_colours def test_every_bundled_template_is_a_template(): entries = library.bundled() assert [e.key for e in entries] == ["bundled:fabled_archives"] for e in entries: assert e.template is not None, [str(p) for p in e.problems] assert entries[0].name == "Fabled Archives" and entries[0].template.expects == "fabledarchives_" def test_settings_read_when_the_picker_opens(): async def targets(db): return [{"value": "t1", "label": "Archives"}] async def none(db): return [] widget = {"key": "w", "params": [ {"key": "target", "type": "select", "default": "", "options_from": targets}, {"key": "template", "type": "select", "default": "", "options_from": none, "empty": "No templates yet."}, {"key": "hours", "type": "select", "default": 6, "options": [{"value": 6, "label": "6h"}]}]} filled = asyncio.run(with_options(None, widget)) assert filled["params"][0]["options"] == [{"value": "t1", "label": "Archives"}] assert filled["params"][1]["options"] == [] assert filled["params"][2] is widget["params"][2] assert "options" not in widget["params"][0] # the registry isn't changed plain = {"key": "x", "params": []} assert asyncio.run(with_options(None, plain)) is plain def test_details_names_the_target_or_falls_back_to_the_section(): defn = {"detail_url": "/plugins/prometheus/targets/{target}"} assert detail_url(defn, {"target": "a b/c", "template": "x"}) == "/plugins/prometheus/targets/a%20b%2Fc" assert detail_url(defn, {}) == "/plugins/prometheus/" assert detail_url({"detail_url": "/monitors/"}, {"limit": 5}) == "/monitors/" def test_bars_scale_to_their_own_peak(): assert spark_heights([1.0, 2.0, 4.0]) == [25.0, 50.0, 100.0] assert spark_heights([0.0, 0.0]) == [0.0, 0.0] and spark_heights([]) == [] def _target(reach="up", ok_minutes=1): at = NOW - timedelta(minutes=ok_minutes) return {"id": "t1", "name": T, "reach": reach, "says": "", "ok_at": at, "scraped_at": NOW} async def _page(app, user=True, **ctx): from quart import session async with app.test_request_context("/plugins/prometheus/widget"): if user: session["user_id"] = "u1" session["user_role"] = "viewer" ctx.setdefault("spark_hours", 24) page = await render_plugin_template(app, "prometheus", "prometheus/widget.html", **ctx) return " ".join(page.split()) async def test_the_widget_leads_with_the_verdict_then_problems_first(app): view = render(check(TEMPLATE), T, latest(SERIES), NOW, history={(T, "fa_disk_free_bytes"): [50.0, 100.0]}) page = await _page(app, problem="", view=view, target=_target()) assert page.index("3 need a look. Backup targets: Photos is late.") < page.index("Backup targets") assert 'class="w-verdict tone-warn"' in page # Photos (late) before Steward (fresh) before Old (disabled, quiet). targets = page[page.index("Backup targets"):page.index("Storage")] assert targets.index("Photos") < targets.index("Steward") < targets.index("Old") assert 'is late' in page assert "