feat: add HIL diagnostics and meter health handling

This commit is contained in:
2026-08-17 22:33:04 +02:00
parent bc2ac6e8f6
commit aa25aa2c12
30 changed files with 2108 additions and 236 deletions
+54
View File
@@ -0,0 +1,54 @@
import os
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "tools" / "hil"))
from hil_common import read_events
from report import evaluate
@pytest.mark.hil
def test_captured_baseline_evidence():
artifact_text = os.environ.get("HIL_ARTIFACT", "")
if not artifact_text:
pytest.skip("set HIL_ARTIFACT to a completed artifacts/hil/<timestamp> directory")
artifact = Path(artifact_text)
checks = evaluate(read_events(artifact))
failures = [f"{check.name}: {check.detail}" for check in checks if check.status == "fail"]
assert not failures, "\n".join(failures)
@pytest.mark.hil
def test_captured_fault_recovery_evidence():
artifact_text = os.environ.get("HIL_ARTIFACT", "")
requested_fault = os.environ.get("HIL_FAULT", "")
if not artifact_text or not requested_fault:
pytest.skip("set HIL_ARTIFACT and HIL_FAULT to a completed fault-run artifact")
checks = evaluate(read_events(Path(artifact_text)), requested_fault)
fault_check = next(check for check in checks if check.name == f"fault {requested_fault}")
assert fault_check.status == "pass", fault_check.detail
@pytest.mark.hil
def test_meter_outage_is_counted_once_and_not_published():
artifact_text = os.environ.get("HIL_ARTIFACT", "")
expect_no_meter = os.environ.get("HIL_EXPECT_NO_METER", "") == "1"
if not artifact_text or not expect_no_meter:
pytest.skip("set HIL_ARTIFACT and HIL_EXPECT_NO_METER=1 for a no-meter capture")
events = read_events(Path(artifact_text))
sender = [event for event in events if event.get("source") == "sender"]
samples = [event for event in sender if event.get("event") == "meter_sample"]
active_faults = [event for event in sender
if event.get("event") == "meter_fault" and event.get("state") == "active"]
assert samples, "no meter sample evidence captured"
assert all(event.get("ok") is False and event.get("classification") == "no_data"
for event in samples)
assert len(active_faults) == 1, active_faults
assert not [event for event in sender if event.get("event") == "batch_created"]
assert not [event for event in sender
if event.get("event") == "queue" and event.get("action") == "enqueue"]