Files
meshcore-stats/tests/html/test_metrics_builders.py
Jorijn Schrijvershof ca13e31aae test: stabilize suite and broaden integration coverage (#32)
* 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
2026-01-08 21:20:34 +01:00

193 lines
6.7 KiB
Python

"""Tests for metrics builder functions."""
from meshmon.html import (
_build_traffic_table_rows,
build_companion_metrics,
build_node_details,
build_radio_config,
build_repeater_metrics,
)
class TestBuildRepeaterMetrics:
"""Tests for build_repeater_metrics function."""
def test_returns_dict(self, sample_repeater_metrics):
"""Returns a dictionary."""
# build_repeater_metrics takes a row dict (firmware field names)
result = build_repeater_metrics(sample_repeater_metrics)
assert isinstance(result, dict)
def test_returns_dict_structure(self, sample_repeater_metrics):
"""Returns dict with expected keys."""
result = build_repeater_metrics(sample_repeater_metrics)
# Should have critical_metrics, secondary_metrics, traffic_metrics
assert "critical_metrics" in result
assert "secondary_metrics" in result
assert "traffic_metrics" in result
def test_critical_metrics_is_list(self, sample_repeater_metrics):
"""Critical metrics is a list."""
result = build_repeater_metrics(sample_repeater_metrics)
assert isinstance(result["critical_metrics"], list)
def test_handles_none(self):
"""Handles None row."""
result = build_repeater_metrics(None)
assert isinstance(result, dict)
assert result["critical_metrics"] == []
def test_handles_empty_dict(self):
"""Handles empty dict."""
result = build_repeater_metrics({})
assert isinstance(result, dict)
class TestBuildCompanionMetrics:
"""Tests for build_companion_metrics function."""
def test_returns_dict(self, sample_companion_metrics):
"""Returns a dictionary."""
result = build_companion_metrics(sample_companion_metrics)
assert isinstance(result, dict)
def test_returns_dict_structure(self, sample_companion_metrics):
"""Returns dict with expected keys."""
result = build_companion_metrics(sample_companion_metrics)
assert "critical_metrics" in result
assert "secondary_metrics" in result
assert "traffic_metrics" in result
def test_handles_none(self):
"""Handles None row."""
result = build_companion_metrics(None)
assert isinstance(result, dict)
assert result["critical_metrics"] == []
def test_handles_empty_dict(self):
"""Handles empty dict."""
result = build_companion_metrics({})
assert isinstance(result, dict)
class TestBuildNodeDetails:
"""Tests for build_node_details function."""
def test_returns_list(self, configured_env):
"""Returns a list of detail items."""
result = build_node_details("repeater")
assert isinstance(result, list)
def test_items_have_label_value(self, configured_env):
"""Each item has label and value."""
result = build_node_details("repeater")
for item in result:
assert isinstance(item, dict)
assert "label" in item
assert "value" in item
def test_includes_hardware_info(self, configured_env, monkeypatch):
"""Includes hardware model info."""
monkeypatch.setenv("REPEATER_HARDWARE", "Test LoRa Device")
import meshmon.env
meshmon.env._config = None
result = build_node_details("repeater")
# Should have hardware in one of the items
hardware = next(item for item in result if item.get("label") == "Hardware")
assert hardware["value"] == "Test LoRa Device"
def test_different_roles(self, configured_env):
"""Different roles return details."""
repeater_details = build_node_details("repeater")
companion_details = build_node_details("companion")
assert isinstance(repeater_details, list)
assert isinstance(companion_details, list)
class TestBuildRadioConfig:
"""Tests for build_radio_config function."""
def test_returns_list(self, configured_env):
"""Returns a list of config items."""
result = build_radio_config()
assert isinstance(result, list)
def test_items_have_label_value(self, configured_env):
"""Each item has label and value."""
result = build_radio_config()
for item in result:
assert isinstance(item, dict)
assert "label" in item
assert "value" in item
def test_includes_frequency_when_set(self, configured_env, monkeypatch):
"""Includes frequency when configured."""
monkeypatch.setenv("RADIO_FREQUENCY", "869.618 MHz")
import meshmon.env
meshmon.env._config = None
result = build_radio_config()
freq = next(item for item in result if item.get("label") == "Frequency")
assert freq["value"] == "869.618 MHz"
def test_handles_missing_config(self, configured_env):
"""Returns list even with default config."""
result = build_radio_config()
assert isinstance(result, list)
class TestBuildTrafficTableRows:
"""Tests for _build_traffic_table_rows function."""
def test_returns_list(self):
"""Returns a list of rows."""
# Input is list of traffic metric dicts
traffic_metrics = [
{"label": "RX", "value": "100", "raw_value": 100, "unit": "/min"},
{"label": "TX", "value": "50", "raw_value": 50, "unit": "/min"},
]
rows = _build_traffic_table_rows(traffic_metrics)
assert isinstance(rows, list)
def test_rows_have_structure(self):
"""Each row has expected structure."""
traffic_metrics = [
{"label": "RX", "value": "100", "raw_value": 100, "unit": "/min"},
{"label": "TX", "value": "50", "raw_value": 50, "unit": "/min"},
]
rows = _build_traffic_table_rows(traffic_metrics)
for row in rows:
assert isinstance(row, dict)
assert "label" in row
assert "rx" in row
assert "tx" in row
assert "rx_raw" in row
assert "tx_raw" in row
assert "unit" in row
def test_handles_empty_list(self):
"""Handles empty traffic metrics list."""
rows = _build_traffic_table_rows([])
assert isinstance(rows, list)
assert len(rows) == 0
def test_combines_rx_tx_pairs(self):
"""Combines RX and TX into single row."""
traffic_metrics = [
{"label": "Flood RX", "value": "100", "raw_value": 100, "unit": "/min"},
{"label": "Flood TX", "value": "50", "raw_value": 50, "unit": "/min"},
]
rows = _build_traffic_table_rows(traffic_metrics)
# Should have one "Flood" row with both rx and tx
assert len(rows) == 1
assert rows[0]["label"] == "Flood"
assert rows[0]["rx"] == "100"
assert rows[0]["tx"] == "50"