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
208 lines
6.8 KiB
Python
208 lines
6.8 KiB
Python
"""Tests for database insert functions."""
|
|
|
|
import pytest
|
|
|
|
from meshmon.db import (
|
|
get_connection,
|
|
insert_metric,
|
|
insert_metrics,
|
|
)
|
|
|
|
BASE_TS = 1704067200
|
|
|
|
|
|
class TestInsertMetric:
|
|
"""Tests for insert_metric function."""
|
|
|
|
def test_inserts_single_metric(self, initialized_db):
|
|
"""Inserts a single metric successfully."""
|
|
ts = BASE_TS
|
|
|
|
result = insert_metric(ts, "companion", "battery_mv", 3850.0, initialized_db)
|
|
|
|
assert result is True
|
|
|
|
with get_connection(initialized_db, readonly=True) as conn:
|
|
cursor = conn.execute(
|
|
"SELECT value FROM metrics WHERE ts = ? AND role = ? AND metric = ?",
|
|
(ts, "companion", "battery_mv")
|
|
)
|
|
row = cursor.fetchone()
|
|
assert row is not None
|
|
assert row["value"] == 3850.0
|
|
|
|
def test_returns_false_on_duplicate(self, initialized_db):
|
|
"""Returns False for duplicate (ts, role, metric) tuple."""
|
|
ts = BASE_TS
|
|
|
|
# First insert succeeds
|
|
assert insert_metric(ts, "companion", "test", 1.0, initialized_db) is True
|
|
|
|
# Second insert with same key returns False
|
|
assert insert_metric(ts, "companion", "test", 2.0, initialized_db) is False
|
|
|
|
def test_different_roles_not_duplicate(self, initialized_db):
|
|
"""Same ts/metric with different roles are not duplicates."""
|
|
ts = BASE_TS
|
|
|
|
assert insert_metric(ts, "companion", "test", 1.0, initialized_db) is True
|
|
assert insert_metric(ts, "repeater", "test", 2.0, initialized_db) is True
|
|
|
|
def test_different_metrics_not_duplicate(self, initialized_db):
|
|
"""Same ts/role with different metrics are not duplicates."""
|
|
ts = BASE_TS
|
|
|
|
assert insert_metric(ts, "companion", "test1", 1.0, initialized_db) is True
|
|
assert insert_metric(ts, "companion", "test2", 2.0, initialized_db) is True
|
|
|
|
def test_invalid_role_raises(self, initialized_db):
|
|
"""Invalid role raises ValueError."""
|
|
ts = BASE_TS
|
|
|
|
with pytest.raises(ValueError, match="Invalid role"):
|
|
insert_metric(ts, "invalid", "test", 1.0, initialized_db)
|
|
|
|
def test_sql_injection_blocked(self, initialized_db):
|
|
"""SQL injection attempt raises ValueError."""
|
|
ts = BASE_TS
|
|
|
|
with pytest.raises(ValueError, match="Invalid role"):
|
|
insert_metric(ts, "'; DROP TABLE metrics; --", "test", 1.0, initialized_db)
|
|
|
|
|
|
class TestInsertMetrics:
|
|
"""Tests for insert_metrics function (bulk insert)."""
|
|
|
|
def test_inserts_multiple_metrics(self, initialized_db):
|
|
"""Inserts multiple metrics from dict."""
|
|
ts = BASE_TS
|
|
metrics = {
|
|
"battery_mv": 3850.0,
|
|
"contacts": 5,
|
|
"uptime_secs": 86400,
|
|
}
|
|
|
|
count = insert_metrics(ts, "companion", metrics, initialized_db)
|
|
|
|
assert count == 3
|
|
|
|
with get_connection(initialized_db, readonly=True) as conn:
|
|
cursor = conn.execute(
|
|
"SELECT COUNT(*) FROM metrics WHERE ts = ?",
|
|
(ts,)
|
|
)
|
|
assert cursor.fetchone()[0] == 3
|
|
|
|
def test_returns_insert_count(self, initialized_db):
|
|
"""Returns correct count of inserted metrics."""
|
|
ts = BASE_TS
|
|
metrics = {"a": 1.0, "b": 2.0, "c": 3.0}
|
|
|
|
count = insert_metrics(ts, "companion", metrics, initialized_db)
|
|
|
|
assert count == 3
|
|
|
|
def test_skips_non_numeric_values(self, initialized_db):
|
|
"""Non-numeric values are silently skipped."""
|
|
ts = BASE_TS
|
|
metrics = {
|
|
"battery_mv": 3850.0, # Numeric - inserted
|
|
"name": "test", # String - skipped
|
|
"status": None, # None - skipped
|
|
"flags": [1, 2, 3], # List - skipped
|
|
"nested": {"a": 1}, # Dict - skipped
|
|
}
|
|
|
|
count = insert_metrics(ts, "companion", metrics, initialized_db)
|
|
|
|
assert count == 1 # Only battery_mv
|
|
|
|
def test_handles_int_and_float(self, initialized_db):
|
|
"""Both int and float values are inserted."""
|
|
ts = BASE_TS
|
|
metrics = {
|
|
"int_value": 42,
|
|
"float_value": 3.14,
|
|
}
|
|
|
|
count = insert_metrics(ts, "companion", metrics, initialized_db)
|
|
|
|
assert count == 2
|
|
|
|
def test_converts_int_to_float(self, initialized_db):
|
|
"""Integer values are stored as float."""
|
|
ts = BASE_TS
|
|
metrics = {"contacts": 5}
|
|
|
|
insert_metrics(ts, "companion", metrics, initialized_db)
|
|
|
|
with get_connection(initialized_db, readonly=True) as conn:
|
|
cursor = conn.execute(
|
|
"SELECT value FROM metrics WHERE metric = 'contacts'"
|
|
)
|
|
row = cursor.fetchone()
|
|
assert row["value"] == 5.0
|
|
assert isinstance(row["value"], float)
|
|
|
|
def test_empty_dict_returns_zero(self, initialized_db):
|
|
"""Empty dict returns 0."""
|
|
ts = BASE_TS
|
|
|
|
count = insert_metrics(ts, "companion", {}, initialized_db)
|
|
|
|
assert count == 0
|
|
|
|
def test_skips_duplicates_silently(self, initialized_db):
|
|
"""Duplicate metrics are skipped without error."""
|
|
ts = BASE_TS
|
|
metrics = {"test": 1.0}
|
|
|
|
# First insert
|
|
count1 = insert_metrics(ts, "companion", metrics, initialized_db)
|
|
assert count1 == 1
|
|
|
|
# Second insert - same key
|
|
count2 = insert_metrics(ts, "companion", metrics, initialized_db)
|
|
assert count2 == 0 # Duplicate skipped
|
|
|
|
def test_partial_duplicates(self, initialized_db):
|
|
"""Partial duplicates: some inserted, some skipped."""
|
|
ts = BASE_TS
|
|
|
|
# First insert
|
|
insert_metrics(ts, "companion", {"existing": 1.0}, initialized_db)
|
|
|
|
# Second insert with mix
|
|
metrics = {
|
|
"existing": 2.0, # Duplicate - skipped
|
|
"new": 3.0, # New - inserted
|
|
}
|
|
count = insert_metrics(ts, "companion", metrics, initialized_db)
|
|
|
|
assert count == 1 # Only "new" inserted
|
|
|
|
def test_invalid_role_raises(self, initialized_db):
|
|
"""Invalid role raises ValueError."""
|
|
ts = BASE_TS
|
|
|
|
with pytest.raises(ValueError, match="Invalid role"):
|
|
insert_metrics(ts, "invalid", {"test": 1.0}, initialized_db)
|
|
|
|
def test_companion_metrics(self, initialized_db, sample_companion_metrics):
|
|
"""Inserts companion metrics dict."""
|
|
ts = BASE_TS
|
|
|
|
count = insert_metrics(ts, "companion", sample_companion_metrics, initialized_db)
|
|
|
|
# Should insert all numeric fields
|
|
assert count == len(sample_companion_metrics)
|
|
|
|
def test_repeater_metrics(self, initialized_db, sample_repeater_metrics):
|
|
"""Inserts repeater metrics dict."""
|
|
ts = BASE_TS
|
|
|
|
count = insert_metrics(ts, "repeater", sample_repeater_metrics, initialized_db)
|
|
|
|
# Should insert all numeric fields
|
|
assert count == len(sample_repeater_metrics)
|