from __future__ import annotations import importlib.util import json from pathlib import Path SCRIPT = Path(__file__).parents[1] / "scripts" / "pi_doctor_collector.py" SPEC = importlib.util.spec_from_file_location("pi_doctor_collector", SCRIPT) collector = importlib.util.module_from_spec(SPEC) assert SPEC and SPEC.loader SPEC.loader.exec_module(collector) def snapshot(**overrides): value = { "system": {"timestamp": "2026-10-28T12:00:00+00:00", "cpu_percent": 10, "memory_percent": 20, "temperature_c": 50}, "storage": {"root_percent": 30, "mounts": []}, "docker": {"available": True, "containers": []}, "services": {"codexpi": {"configured": True, "available": True}, "jellyfin": {"configured": False}}, } for section, values in overrides.items(): value[section].update(values) return value def test_detects_thresholds_mounts_and_services_without_repairing(): value = snapshot( system={"cpu_percent": 99, "temperature_c": 80}, storage={"root_percent": 96, "mounts": [{"path": "/mnt/nas", "state": "unavailable", "error": "timeout"}]}, services={"codexpi": {"configured": True, "available": False}, "jellyfin": {"configured": False}}, ) incidents = collector.detect_incidents(value) assert {item["fingerprint"] for item in incidents} == { "cpu-high", "root-disk-high", "temperature-high", "mount:/mnt/nas", "service:codexpi", } assert next(item for item in incidents if item["fingerprint"] == "cpu-high")["severity"] == "critical" assert not hasattr(collector, "repair") def test_spool_survives_failure_then_flushes_in_order(tmp_path, monkeypatch): first = collector.enqueue(tmp_path, snapshot()) second_value = snapshot(system={"timestamp": "2026-10-28T12:01:00+00:00"}) second = collector.enqueue(tmp_path, second_value) delivered = [] monkeypatch.setattr(collector, "deliver", lambda url, token, value: delivered.append(value["system"]["timestamp"])) assert first.exists() and second.exists() assert collector.flush(tmp_path, "https://codexpi.test", "token") == 2 assert delivered == ["2026-10-28T12:00:00+00:00", "2026-10-28T12:01:00+00:00"] assert list(tmp_path.glob("*.json")) == [] def test_delivery_posts_snapshot_then_real_detected_incidents(monkeypatch): requests = [] monkeypatch.setattr(collector, "_post", lambda url, token, payload: requests.append((url, token, payload))) value = snapshot(system={"memory_percent": 98}) collector.deliver("https://codexpi.test/", "secret-token", value) assert requests[0][0].endswith("/api/pi-doctor/snapshots/import") assert requests[0][2] == {"snapshot": value} assert requests[1][0].endswith("/api/pi-doctor/incidents/import") assert requests[1][2]["incidents"][0]["fingerprint"] == "memory-high" assert {request[1] for request in requests} == {"secret-token"}