Checklist: verify that sensor data reaches InfluxDB

New guided check "Sensor data in the database (InfluxDB)", also the last
step of the Quick check on the green path. It queries InfluxDB (read
token) for the newest point per measurement of the box and tells apart:
sensor data arrives / status arrives without sensor data / offline now /
never seen / check not possible. Polls every 30 s for up to 4 minutes.
With a stopped RTC in the log it concludes that sensor readings are lost
(stamped 1 Jan 2000): box A4:CB:8F:C9:47:3C sent only device_status and
microphone.

- service/influx.py: query, CSV parsing, classification (no new deps)
- guides: new step type "influx" (host answers via influx_result)
- Settings > InfluxDB access (or KOTA_INFLUX_TOKEN); token never logged
- service status mapping for tech.influx.* findings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
KrzyszurandClaude Opus 5.5 committed 2026-10-01 00:06:48 +02:00
1 parent 2b6d43eb45
commit 66cb804102
11 files changed
+676 -15

No files matched your search

+92
View File
@@ -242,3 +242,95 @@ def test_skip_wait_and_report_contains_technician_checks(rig):
assert runner.end.id == "update_slow"
text = engine.report().to_text()
assert "Technician checks:" in text and "Update is taking very long" in text
# ------------------------------------------------------------ InfluxDB check
RTC_STOPPED = [*BOOT, "I (2945) KOTA: rtc running=0 time=2000-01-01T00:00:00"]
@pytest.fixture
def influx_rig(rig):
engine, runner, clock, actions, board, log = rig
return engine, runner, clock, actions, board
def test_influx_ok_ends_healthy(influx_rig):
engine, runner, clock, actions, board = influx_rig
runner.start("influx")
assert actions == ["influx"] and runner.view().waiting
runner.influx_result("ok", "Sensor data arrives in InfluxDB", ["Device status: 1 min ago"])
assert runner.end.id == "data_ok"
assert any("InfluxDB: Sensor data arrives" in t for t in engine.technician)
def test_influx_polls_until_sensors_arrive(influx_rig):
engine, runner, clock, actions, board = influx_rig
runner.start("influx")
runner.influx_result("sensors_missing", "Status arrives, sensor data does not: SEN66")
assert runner.end is None and "Checking again" in runner.view().note
clock.t += 10
runner.tick()
assert actions == ["influx"] # not yet
clock.t += 25
runner.tick()
assert actions == ["influx", "influx"] # polled again after poll_s
runner.tick()
assert actions == ["influx", "influx"] # no second query while one is pending
runner.influx_result("ok", "Sensor data arrives in InfluxDB")
assert runner.end.id == "data_ok"
def test_influx_repeated_answer_is_noted_once(influx_rig):
engine, runner, clock, actions, board = influx_rig
runner.start("influx")
for _ in range(3):
runner.influx_result("silent", "No recent data in InfluxDB")
clock.t += 31
runner.tick()
assert sum("InfluxDB:" in t for t in engine.technician) == 1
def test_influx_sensors_missing_with_stopped_clock(influx_rig):
engine, runner, clock, actions, board = influx_rig
board(*RTC_STOPPED)
runner.start("influx")
runner.influx_result("sensors_missing", "Status arrives, sensor data does not")
clock.t += 300 # past timeout_s
runner.tick()
assert runner.end.id == "sensors_clock"
f = engine.findings["tech.influx.sensors_clock"]
assert f.severity == Severity.ERROR and f.active
def test_influx_sensors_missing_without_log_cause(influx_rig):
engine, runner, clock, actions, board = influx_rig
runner.start("influx")
clock.t += 250
runner.influx_result("sensors_missing", "Status arrives, sensor data does not")
assert runner.end.id == "sensors_missing"
def test_influx_unavailable_and_stale_results(rig):
engine, runner, clock, actions, board, log = rig
runner._on_action = lambda a: False # no token / host cannot query
runner.start("influx")
assert runner.end.id == "unavailable"
runner.influx_result("ok", "late answer") # ignored: step already left
assert runner.end.id == "unavailable"
def test_influx_skip_uses_last_result(influx_rig):
engine, runner, clock, actions, board = influx_rig
runner.start("influx")
runner.influx_result("silent", "No recent data in InfluxDB")
runner.proceed()
assert runner.end.id == "silent"
def test_quick_check_green_ends_with_influx_check(influx_rig):
engine, runner, clock, actions, board = influx_rig
board(*BOOT)
runner.start("quick")
runner.answer("GREEN")
runner.answer("0") # heartbeat blinking
assert runner.guide.id == "influx" and actions == ["influx"]