mirror of
https://github.com/jorijn/meshcore-stats.git
synced 2026-03-28 17:42:55 +01:00
* tests: cache integration/report fixtures to speed up tests * fix: speed up yearly aggregation and refresh timings report * chore: remove the report * fix: unrecognized named-value: 'runner'. Located at position 1 within expression: runner.temp * fix: ruff linting error * test: strengthen assertions and stabilize tests * test(integration): expand rendered chart metrics
202 lines
6.6 KiB
Python
202 lines
6.6 KiB
Python
"""Tests for chart statistics I/O functions."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from meshmon.charts import (
|
|
load_chart_stats,
|
|
save_chart_stats,
|
|
)
|
|
|
|
|
|
class TestSaveChartStats:
|
|
"""Tests for save_chart_stats function."""
|
|
|
|
def test_saves_stats_to_file(self, configured_env):
|
|
"""Saves stats dict to JSON file."""
|
|
stats = {
|
|
"bat": {
|
|
"day": {"min": 3.5, "avg": 3.7, "max": 3.9, "current": 3.85},
|
|
"week": {"min": 3.4, "avg": 3.65, "max": 3.95, "current": 3.85},
|
|
}
|
|
}
|
|
|
|
path = save_chart_stats("repeater", stats)
|
|
|
|
assert path.exists()
|
|
with open(path) as f:
|
|
loaded = json.load(f)
|
|
assert loaded == stats
|
|
|
|
def test_creates_directories(self, configured_env):
|
|
"""Creates parent directories if needed."""
|
|
stats = {"test": {"day": {"min": 1.0}}}
|
|
|
|
path = save_chart_stats("repeater", stats)
|
|
|
|
assert path.parent.exists()
|
|
assert path.parent.name == "repeater"
|
|
|
|
def test_returns_path(self, configured_env):
|
|
"""Returns path to saved file."""
|
|
stats = {"test": {"day": {}}}
|
|
|
|
path = save_chart_stats("companion", stats)
|
|
|
|
assert isinstance(path, Path)
|
|
assert path.name == "chart_stats.json"
|
|
assert "companion" in str(path)
|
|
|
|
def test_overwrites_existing(self, configured_env):
|
|
"""Overwrites existing stats file."""
|
|
stats1 = {"metric1": {"day": {"min": 1.0}}}
|
|
stats2 = {"metric2": {"day": {"min": 2.0}}}
|
|
|
|
path1 = save_chart_stats("repeater", stats1)
|
|
path2 = save_chart_stats("repeater", stats2)
|
|
|
|
assert path1 == path2
|
|
with open(path2) as f:
|
|
loaded = json.load(f)
|
|
assert loaded == stats2
|
|
|
|
def test_empty_stats(self, configured_env):
|
|
"""Saves empty stats dict."""
|
|
stats = {}
|
|
|
|
path = save_chart_stats("repeater", stats)
|
|
|
|
with open(path) as f:
|
|
loaded = json.load(f)
|
|
assert loaded == {}
|
|
|
|
def test_nested_stats_structure(self, configured_env):
|
|
"""Preserves nested structure of stats."""
|
|
stats = {
|
|
"bat": {
|
|
"day": {"min": 3.5, "avg": 3.7, "max": 3.9, "current": 3.85},
|
|
"week": {"min": 3.4, "avg": 3.65, "max": 3.95, "current": None},
|
|
},
|
|
"nb_recv": {
|
|
"day": {"min": 0, "avg": 50.5, "max": 100, "current": 75},
|
|
}
|
|
}
|
|
|
|
path = save_chart_stats("repeater", stats)
|
|
|
|
with open(path) as f:
|
|
loaded = json.load(f)
|
|
assert loaded["bat"]["week"]["current"] is None
|
|
assert loaded["nb_recv"]["day"]["avg"] == 50.5
|
|
|
|
|
|
class TestLoadChartStats:
|
|
"""Tests for load_chart_stats function."""
|
|
|
|
def test_loads_existing_stats(self, configured_env):
|
|
"""Loads stats from existing file."""
|
|
stats = {
|
|
"bat": {
|
|
"day": {"min": 3.5, "avg": 3.7, "max": 3.9, "current": 3.85},
|
|
}
|
|
}
|
|
save_chart_stats("repeater", stats)
|
|
|
|
loaded = load_chart_stats("repeater")
|
|
|
|
assert loaded == stats
|
|
|
|
def test_returns_empty_when_missing(self, configured_env):
|
|
"""Returns empty dict when file doesn't exist."""
|
|
loaded = load_chart_stats("repeater")
|
|
|
|
assert loaded == {}
|
|
|
|
def test_returns_empty_on_invalid_json(self, configured_env):
|
|
"""Returns empty dict on invalid JSON."""
|
|
stats_path = configured_env["out_dir"] / "assets" / "repeater" / "chart_stats.json"
|
|
stats_path.parent.mkdir(parents=True, exist_ok=True)
|
|
stats_path.write_text("not valid json {{{", encoding="utf-8")
|
|
|
|
loaded = load_chart_stats("repeater")
|
|
|
|
assert loaded == {}
|
|
|
|
def test_preserves_none_values(self, configured_env):
|
|
"""None values are preserved through save/load cycle."""
|
|
stats = {
|
|
"bat": {
|
|
"day": {"min": None, "avg": None, "max": None, "current": None},
|
|
}
|
|
}
|
|
save_chart_stats("repeater", stats)
|
|
|
|
loaded = load_chart_stats("repeater")
|
|
|
|
assert loaded["bat"]["day"]["min"] is None
|
|
assert loaded["bat"]["day"]["avg"] is None
|
|
|
|
def test_loads_different_roles(self, configured_env):
|
|
"""Loads correct file for each role."""
|
|
companion_stats = {"battery_mv": {"day": {"min": 3.5}}}
|
|
repeater_stats = {"bat": {"day": {"min": 3.6}}}
|
|
|
|
save_chart_stats("companion", companion_stats)
|
|
save_chart_stats("repeater", repeater_stats)
|
|
|
|
assert load_chart_stats("companion") == companion_stats
|
|
assert load_chart_stats("repeater") == repeater_stats
|
|
|
|
|
|
class TestStatsRoundTrip:
|
|
"""Tests for complete save/load round trips."""
|
|
|
|
def test_complex_stats_roundtrip(self, configured_env):
|
|
"""Complex stats survive round trip unchanged."""
|
|
stats = {
|
|
"bat": {
|
|
"day": {"min": 3.5, "avg": 3.7, "max": 3.9, "current": 3.85},
|
|
"week": {"min": 3.4, "avg": 3.65, "max": 3.95, "current": 3.8},
|
|
"month": {"min": 3.3, "avg": 3.6, "max": 4.0, "current": 3.75},
|
|
"year": {"min": 3.2, "avg": 3.55, "max": 4.1, "current": 3.7},
|
|
},
|
|
"bat_pct": {
|
|
"day": {"min": 50.0, "avg": 70.0, "max": 90.0, "current": 85.0},
|
|
"week": {"min": 45.0, "avg": 65.0, "max": 95.0, "current": 80.0},
|
|
"month": {"min": 40.0, "avg": 60.0, "max": 100.0, "current": 75.0},
|
|
"year": {"min": 30.0, "avg": 55.0, "max": 100.0, "current": 70.0},
|
|
},
|
|
"nb_recv": {
|
|
"day": {"min": 0, "avg": 50.5, "max": 100, "current": 75},
|
|
"week": {"min": 0, "avg": 48.2, "max": 150, "current": 60},
|
|
"month": {"min": 0, "avg": 45.8, "max": 200, "current": 55},
|
|
"year": {"min": 0, "avg": 42.1, "max": 250, "current": 50},
|
|
},
|
|
}
|
|
|
|
save_chart_stats("repeater", stats)
|
|
loaded = load_chart_stats("repeater")
|
|
|
|
assert loaded == stats
|
|
|
|
def test_float_precision_preserved(self, configured_env):
|
|
"""Float precision is preserved in round trip."""
|
|
stats = {
|
|
"test": {
|
|
"day": {
|
|
"min": 3.141592653589793,
|
|
"avg": 2.718281828459045,
|
|
"max": 1.4142135623730951,
|
|
"current": 0.0001234567890123,
|
|
}
|
|
}
|
|
}
|
|
|
|
save_chart_stats("repeater", stats)
|
|
loaded = load_chart_stats("repeater")
|
|
|
|
assert loaded["test"]["day"]["min"] == pytest.approx(3.141592653589793)
|
|
assert loaded["test"]["day"]["avg"] == pytest.approx(2.718281828459045)
|