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) <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
"tags": ["finanzen"],
|
"tags": ["finanzen"],
|
||||||
"time": {
|
"time": {
|
||||||
"from": "now-1y",
|
"from": "now-1y",
|
||||||
"to": "now"
|
"to": "now+19M"
|
||||||
},
|
},
|
||||||
"refresh": "",
|
"refresh": "",
|
||||||
"panels": [
|
"panels": [
|
||||||
|
|||||||
51
finance/tests/test_grafana_dashboard.py
Normal file
51
finance/tests/test_grafana_dashboard.py
Normal file
@@ -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"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user