feat: expand companion platform, device controls, and memoir workflows
ci / verify (push) Canceled after 0s
ci / verify (push) Canceled after 0s
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.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user