Files
kkallas dd915b5a74 Technician tool v0.7
Imported from the Google Drive folder 004-technician_tool/v0.7.
2026-09-28 19:11:20 +02:00

108 lines
4.1 KiB
Python

"""Service-system hand-off: status mapping, note, and the #kota-report fragment
(decoded exactly as the v1.1.0 service page does: base64url + UTF-8 JSON)."""
import base64
import json
from pathlib import Path
import pytest
from kota_tech.core.logfile import read_log_file
from kota_tech.core.logline import parse_line
from kota_tech.diag.engine import DiagnosticsEngine
from kota_tech.service.report import (
CONNECTIVITY, HARDWARE, OK, decode_fragment, normalize_mac, report_url, service_note, service_status,
)
FIX = Path(__file__).parent / "fixtures"
def bench():
e = DiagnosticsEngine()
for ln in read_log_file(FIX / "live_boot_A4CB8FC946F8_fw1.0.txt"):
e.feed(ln)
return e
def test_engine_reads_mac_from_boot_log():
assert bench().mac == "A4:CB:8F:C9:46:F8"
def test_bench_box_is_a_connectivity_problem():
e = bench()
assert service_status(e.report()) == CONNECTIVITY
note = service_note(e.report())
assert note.startswith("[KOTA Technician Tool")
assert "not commissioned in Matter" in note and "↳ [Error] No Internet" in note
assert "Firmware: v1.0" in note
def test_hardware_and_healthy_statuses():
e = DiagnosticsEngine()
for ln in ["ESP-ROM:esp32s3-20210327", "I (1299) app_init: Project name: kota-sensorboard",
"E (3511) MAIN: Failed to initialize RTC: ESP_ERR_TIMEOUT"]:
e.feed(parse_line(ln))
assert service_status(e.report()) == HARDWARE
ok = DiagnosticsEngine()
for ln in ["ESP-ROM:esp32s3-20210327", "I (1299) app_init: Project name: kota-sensorboard",
"I (31000) INFLUX: HTTP request performed, status code: 204"]:
ok.feed(parse_line(ln))
assert service_status(ok.report()) == OK
def test_url_shape_and_payload_roundtrip():
e = bench()
url = report_url(e.mac, e.report(), "https://service.kota-app.com")
assert url.startswith("https://service.kota-app.com/A4CB8FC946F8#kota-report=")
assert "?" not in url # nothing in the query: the fragment is never sent to a server
data = decode_fragment(url)
assert data["v"] == 1 and data["mac"] == "A4CB8FC946F8" and data["status"] == CONNECTIVITY
def test_fragment_decodes_like_the_service_page():
# Mirror of index.html applyToolPrefill: base64url -> pad -> bytes -> UTF-8 -> JSON
e = bench()
e.note_technician("Zażółć gęślą jaźń -> Purple") # non-ASCII survives
url = report_url("a4:cb:8f:c9:46:f8", e.report())
frag = url.split("#kota-report=")[1]
assert set(frag) <= set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_") # page regex
padded = frag.replace("-", "+").replace("_", "/")
padded += "==="[(len(padded) + 3) % 4:]
data = json.loads(base64.b64decode(padded).decode("utf-8"))
assert "Zażółć gęślą jaźń" in data["note"]
def test_note_is_limited_and_no_secrets():
e = bench()
for i in range(400):
e.note_technician(f"check {i} " + "x" * 50)
note = service_note(e.report(), limit=4000)
assert len(note) <= 4000
assert "INFLUX_TOKEN" not in note
@pytest.mark.parametrize("bad", ["", "A4CB8F", "zz:cb:8f:c9:46:f8"])
def test_invalid_mac_rejected(bad):
with pytest.raises(ValueError):
report_url(bad, bench().report())
def test_normalize_mac():
assert normalize_mac("a4:cb:8f:c9:46:f8") == "A4CB8FC946F8"
def test_note_mirrors_the_diagnosis_panel():
from pathlib import Path
from kota_tech.core.logfile import read_log_file
e = DiagnosticsEngine()
for ln in read_log_file(Path(__file__).parent / "fixtures" / "live_boot_A4CB8FC946F8_fw1.0.16_uncommissioned.txt"):
e.feed(ln)
note = service_note(e.report())
assert len(note) <= 5000
for part in ("Status LED should be: Cyan, breathing", "Box self-report (KOTA lines):",
"✔ I2C: found: AS7341, DS1307, SEN66, BME688", "Start-up progress (current boot):",
"✔ SD card mounted (1.7 s)", "○ Connected to Wi-Fi", "What to do:",
"Seen 12x, first at 21.6 s after start, last at 126.8 s",
"↳ [Error] No Internet: server names cannot be resolved"):
assert part in note, part