61 lines
3.1 KiB
Python
61 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Verify real OTA cold allocations, host DATA cache ownership and streaming proofs.
|
|
|
|
The fixture uses controlled host representations, encoder/decoder callbacks and
|
|
radio admission. It validates manager bytes/hashes/proofs under sanitizers, not
|
|
the DEFLATE codec or physical USB/BLE/radio transport.
|
|
"""
|
|
|
|
from pathlib import Path
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
|
|
from test_serial_wifi_sessions import SANITIZER_FLAGS
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
FIXTURE = ROOT / "test/fixtures/ota_cold_buffers/test.cpp"
|
|
HOST_MARKERS = (
|
|
"host compression needs leaves only; allocation denial and invalid-output fallback",
|
|
"host short tail and maximum leaf capacity retain original source bounds",
|
|
"host bytes stay pinned through DATA/PROOF backpressure and raw/compressed switches",
|
|
"host DATA reloads after successful interleaved inbound decoding",
|
|
"partial failed inbound decoder cannot leak into pinned host DATA",
|
|
"host DATA survives interleaved source growth, failure and rollover",
|
|
"caller-owned self-source encoder output remains separate and unallocated",
|
|
)
|
|
|
|
|
|
class OtaColdBufferTests(unittest.TestCase):
|
|
def test_proofs_allocation_failures_and_transfer_lifetimes(self):
|
|
compiler = os.environ.get("CXX") or shutil.which("g++") or shutil.which("clang++")
|
|
if not compiler:
|
|
self.skipTest("a host C++17 compiler is required")
|
|
for platform in ((), ("-DNRF52_PLATFORM=1",),
|
|
("-DNRF52_PLATFORM=1", "-DOTA_SD_STORE=1"),
|
|
("-DESP32_PLATFORM=1",)):
|
|
with self.subTest(platform=platform), tempfile.TemporaryDirectory(prefix="ota-cold-") as directory:
|
|
binary = Path(directory) / "cold-buffers"
|
|
sources = ("OtaManager.cpp", "OtaProtocol.cpp", "MotaContainer.cpp", "MerkleTree.cpp")
|
|
built = subprocess.run([
|
|
compiler, "-std=c++17", "-O1", "-Wall", "-Wextra", "-Werror",
|
|
"-Wno-unused-parameter", "-Wno-sign-compare", *SANITIZER_FLAGS, *platform,
|
|
"-I", str(ROOT / "src"), "-I", str(ROOT / "test/mocks"),
|
|
str(FIXTURE), *[str(ROOT / "src/helpers/ota" / name) for name in sources],
|
|
str(ROOT / "src/Utils.cpp"), "-Wl,--wrap=malloc", "-Wl,--wrap=free",
|
|
"-o", str(binary),
|
|
], capture_output=True, text=True, timeout=60)
|
|
self.assertEqual(built.returncode, 0, built.stdout + built.stderr)
|
|
checked = subprocess.run([str(binary)], capture_output=True, text=True, timeout=60)
|
|
self.assertEqual(checked.returncode, 0, checked.stdout + checked.stderr)
|
|
for marker in HOST_MARKERS:
|
|
self.assertEqual(checked.stdout.count("PASS: " + marker), 1, checked.stdout)
|
|
self.assertIn("PASS: streaming proofs and OTA cold-buffer lifetimes", checked.stdout)
|
|
print(f"\n[OTA cold buffers: {platform or 'portable'}]\n{checked.stdout}", flush=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|