From 224baba326e9bd0ffe1925444384d024d31a054cf0fbc056812ecb4bd40068a7 Mon Sep 17 00:00:00 2001 From: wlfb Date: Fri, 24 Jul 2026 20:39:23 +0200 Subject: [PATCH] fix: Grafana-Zeitfenster deckt Projektionshorizont ab (Szenario-Vergleich sichtbar) Das Szenario-Vergleich-Panel zeichnet die Projektion (Zukunft, horizon_days ab heute). Kein Panel nutzt $__timeFilter, daher begrenzt allein das Dashboard-Zeitfenster die Anzeige. Mit time.to='now' wurde die gesamte Kurve ab morgen abgeschnitten (nur ~4 Tage <= heute sichtbar, Y-Achse auf deren schmalen Bereich fixiert). Fix: time.to='now+19M' deckt den 548-Tage-Horizont ab. Regressionstest tests/test_grafana_dashboard.py haelt die Invariante fest. Co-Authored-By: Claude Opus 4.8 (1M context) --- finance/grafana/dashboards/finanzen.json | 2 +- finance/tests/test_grafana_dashboard.py | 51 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 finance/tests/test_grafana_dashboard.py diff --git a/finance/grafana/dashboards/finanzen.json b/finance/grafana/dashboards/finanzen.json index 7780d07..c0c8f54 100644 --- a/finance/grafana/dashboards/finanzen.json +++ b/finance/grafana/dashboards/finanzen.json @@ -8,7 +8,7 @@ "tags": ["finanzen"], "time": { "from": "now-1y", - "to": "now" + "to": "now+19M" }, "refresh": "", "panels": [ diff --git a/finance/tests/test_grafana_dashboard.py b/finance/tests/test_grafana_dashboard.py new file mode 100644 index 0000000..3580e8b --- /dev/null +++ b/finance/tests/test_grafana_dashboard.py @@ -0,0 +1,51 @@ +"""Regressionstests fuer das provisionierte Grafana-Dashboard finanzen.json. + +Hintergrund: Kein Panel nutzt $__timeFilter, jedes liefert alle Zeilen und +Grafana beschneidet auf das Dashboard-Zeitfenster. Das Szenario-Vergleich-Panel +zeichnet die Projektion (Zukunft, horizon_days ab heute). Steht 'to' auf 'now', +wird die gesamte Kurve ab morgen abgeschnitten (nur die ~4 Tage <= heute +sichtbar, Y-Achse auf deren schmalen Bereich fixiert). Dieser Test haelt fest, +dass 'to' weit genug in die Zukunft reicht. +""" +import json +import re +from pathlib import Path + +from app.config import get_settings + +DASHBOARD = Path(__file__).resolve().parent.parent / "grafana" / "dashboards" / "finanzen.json" + +_UNIT_DAYS = {"y": 365, "M": 30, "w": 7, "d": 1, "h": 1 / 24} + + +def _relative_to_days(expr: str) -> float: + """Grafana-Relativausdruck ('now', 'now+19M', 'now-1y') -> vorzeichen- + behafteter Tages-Offset relativ zu 'now' (Zukunft positiv).""" + expr = expr.strip() + if expr == "now": + return 0.0 + m = re.fullmatch(r"now([+-])(\d+)([yMwdh])", expr) + if not m: + raise ValueError(f"Unerwarteter Grafana-Zeitausdruck: {expr!r}") + sign = 1 if m.group(1) == "+" else -1 + return sign * int(m.group(2)) * _UNIT_DAYS[m.group(3)] + + +def _load() -> dict: + return json.loads(DASHBOARD.read_text()) + + +def test_dashboard_has_szenario_panel(): + titles = [p.get("title") for p in _load().get("panels", [])] + assert "Szenario-Vergleich" in titles + + +def test_time_window_covers_projection_horizon(): + d = _load() + horizon = get_settings().horizon_days + to_days = _relative_to_days(d["time"]["to"]) + assert to_days >= horizon, ( + f"time.to reicht nur {to_days} Tage in die Zukunft, deckt aber den " + f"Projektionshorizont von {horizon} Tagen nicht ab -> Projektionskurve " + f"wird abgeschnitten" + )