"""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" )