Files
Codex Local bf1233d5df
ci / verify (push) Canceled after 0s
feat: expand companion platform, device controls, and memoir workflows
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
2026-10-08 10:06:44 +08:00

81 lines
3.7 KiB
Python

import importlib.util
import json
from pathlib import Path
import sys
import tempfile
import unittest
TOOLS = Path(__file__).resolve().parents[1] / "tools"
sys.path.insert(0, str(TOOLS))
import device_prepare as prepare
class PrepareTests(unittest.TestCase):
def setUp(self):
self.directory = tempfile.TemporaryDirectory()
self.addCleanup(self.directory.cleanup)
self.root = Path(self.directory.name)
self.credential = self.root / "credential.json"
self.value = {"factory_id": "KP01-0123456789AB", "model": "ECHOEAR-S3",
"origin": "https://example.com", "key_version": 1,
"device_key_hex": "01" * 32}
self.save()
def save(self):
self.credential.write_text(json.dumps(self.value), encoding="utf-8-sig")
def test_accepts_actual_web_download(self):
self.assertEqual(prepare.read_credential(self.credential)["device_id"], self.value["factory_id"])
def test_legacy_id(self):
self.value["device_id"] = self.value.pop("factory_id")
self.save()
self.assertEqual(prepare.read_credential(self.credential)["device_id"], self.value["device_id"])
def test_rejects_conflicting_identity(self):
self.value["device_id"] = "KP01-AAAAAAAAAAAA"
self.save()
with self.assertRaises(ValueError):
prepare.read_credential(self.credential)
def test_rejects_bad_configuration(self):
for field, value in [("model", "different-board"), ("key_version", True),
("key_version", 0), ("device_key_hex", "bad"),
("origin", "http://example.com"),
("origin", "https://user:password@example.com"),
("origin", "https://example.com/path"),
("origin", "https://example.com:invalid")]:
original = self.value[field]
self.value[field] = value
self.save()
with self.subTest(field=field, value=value), self.assertRaises(ValueError):
prepare.read_credential(self.credential)
self.value[field] = original
def test_mac_independent_of_factory_id(self):
self.assertEqual(prepare.normalize_mac("B4-3A-45-16-34-A8"), "b4:3a:45:16:34:a8")
@unittest.skipUnless(importlib.util.find_spec("esp_idf_nvs_partition_gen"), "NVS generator unavailable")
def test_real_nvs_generation_and_no_overwrite(self):
output = self.root / "private"
manifest = prepare.prepare(self.credential, output, "B4:3A:45:16:34:A8")
image = (output / "ble_factory.bin").read_bytes()
self.assertEqual(len(image), 0x6000)
self.assertIn(bytes.fromhex(self.value["device_key_hex"]), image)
self.assertEqual(manifest["expected_mac"], "b4:3a:45:16:34:a8")
self.assertNotIn("device_key_hex", json.dumps(manifest))
self.assertNotIn(self.value["device_key_hex"], (output / "setup-label.json").read_text())
if (TOOLS.parent / "build" / "flasher_args.json").is_file():
import device_flash
plan = device_flash.build_plan(TOOLS.parent / "build", output,
identity_only=True, reset_runtime=True,
expect_mac="B4:3A:45:16:34:A8")
self.assertEqual({item.name for item in plan.images}, {"reset-runtime", "ble_factory"})
self.assertEqual(next(item.data for item in plan.images if item.name == "ble_factory"), image)
with self.assertRaises(FileExistsError):
prepare.prepare(self.credential, output, "B4:3A:45:16:34:A8")
if __name__ == "__main__":
unittest.main()