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
193 lines
6.7 KiB
Python
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"
|