"""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 "-> 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"