Files
StarPilot/tools/ci/tests/test_device_preflight.py
T
firestar5683 6d742eb343 CI
Add control trace and platform qualification tools that exercise explicit safety modes and vehicle coverage.

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com>
Co-authored-by: Kacper Rączy <gfw.kra@gmail.com>
Co-authored-by: YassineYousfi <yyousfi1@binghamton.edu>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>

Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>

Co-authored-by: prabhaavp <prabhaav@msu.edu>
2026-10-14 19:56:17 -05:00

107 lines
6.0 KiB
Python

import hashlib
import json
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest
from unittest.mock import patch
from tools.ci import run_device_preflight as preflight
class DevicePreflightTests(unittest.TestCase):
def setUp(self):
self.temporary = tempfile.TemporaryDirectory()
self.addCleanup(self.temporary.cleanup)
self.root = Path(self.temporary.name)
self.fonts = self.root / "fonts"
self.fonts.mkdir()
(self.root / "openpilot/starpilot/ui").mkdir(parents=True)
(self.root / "openpilot/selfdrive/assets/icons").mkdir(parents=True)
(self.root / "launch_env.sh").write_text(' export AGNOS_VERSION="19.8.1"\nexport AGNOS_UPDATE_POLICY="retain"\n')
(self.root / "pyproject.toml").write_text('[project]\nrequires-python = ">= 3.12.3, < 3.13"\n')
self._manifest("bitmap-fonts.json", self.fonts, "Inter.fnt", b"font")
self._manifest("sora-brand-font.json", self.root / preflight.UI / "assets/fonts", "Sora-800.fnt", b"brand")
for name in preflight.MANIFESTS[2:]:
self._manifest(name, self.root / "openpilot/selfdrive/assets", "icons/image.png", b"image")
def _manifest(self, manifest: str, root: Path, filename: str, content: bytes):
path = root / filename
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(content)
(self.root / preflight.UI / manifest).write_text(json.dumps({"files": [{"file": filename, "bytes": len(content),
"sha256": hashlib.sha256(content).hexdigest()}]}))
def _collect(self, **kwargs):
with patch.object(preflight.subprocess, "run", return_value=subprocess.CompletedProcess([], 0, stdout="abc123\n")):
return preflight.collect(self.root, self.fonts, python_version=(3, 12, 3), system="Darwin", machine="arm64",
probe=lambda *_: preflight._check("pass", "fixture import"), **kwargs)
def test_complete_assets_are_checked_without_claiming_desktop_device_readiness(self):
report = self._collect()
self.assertEqual(report["checks"]["source_policy"]["status"], "pass")
self.assertEqual(report["checks"]["bitmap-fonts.json"]["status"], "pass")
self.assertEqual(report["checks"]["sora-brand-font.json"]["status"], "pass")
self.assertEqual(report["checks"]["target_agnos"]["status"], "unavailable")
self.assertEqual(report["prerequisites"], "incomplete")
self.assertEqual(report["device_qualification"], "not_assessed")
self.assertEqual(report["source_files_sha256"]["launch_env.sh"],
hashlib.sha256((self.root / "launch_env.sh").read_bytes()).hexdigest())
def test_bundled_fonts_are_the_default_and_brand_corruption_fails(self):
self._manifest("bitmap-fonts.json", self.root / preflight.UI / "assets/fonts", "Inter.fnt", b"font")
self.assertEqual(preflight._assets(self.root, None)["bitmap-fonts.json"]["status"], "pass")
brand = self.root / preflight.UI / "assets/fonts/Sora-800.fnt"
brand.write_bytes(b"changed")
self.assertEqual(preflight._assets(self.root, None)["sora-brand-font.json"]["status"], "fail")
def test_missing_mismatched_and_symlinked_assets_fail(self):
(self.fonts / "Inter.fnt").write_bytes(b"wrong")
self.assertEqual(self._collect()["checks"]["bitmap-fonts.json"]["status"], "fail")
(self.fonts / "Inter.fnt").unlink()
(self.fonts / "Inter.fnt").symlink_to(self.root / "openpilot/selfdrive/assets/icons/image.png")
self.assertEqual(self._collect()["checks"]["bitmap-fonts.json"]["status"], "fail")
(self.root / "openpilot/selfdrive/assets/icons/image.png").unlink()
self.assertEqual(self._collect()["checks"]["home-assets.json"]["status"], "fail")
def test_wrong_policy_python_and_os_marker(self):
with patch.object(preflight.subprocess, "run", return_value=subprocess.CompletedProcess([], 0, stdout="abc123\n")):
version_file = self.root / "VERSION"
version_file.write_text("19.8\n")
report = preflight.collect(self.root, self.fonts, system="Linux", machine="aarch64",
os_version_file=version_file, python_version=(3, 11, 9),
probe=lambda *_: preflight._check("pass", "fixture import"))
self.assertEqual(report["checks"]["source_policy"]["status"], "pass")
self.assertEqual(report["checks"]["python_version"]["status"], "fail")
self.assertEqual(report["checks"]["target_agnos"]["status"], "fail")
(self.root / "launch_env.sh").write_text('export AGNOS_VERSION="19.8"\nexport AGNOS_UPDATE_POLICY="auto"\n')
self.assertEqual(self._collect()["checks"]["source_policy"]["status"], "fail")
def test_probe_reports_failure_and_timeout_without_child_output(self):
with patch.object(preflight.subprocess, "run", return_value=subprocess.CompletedProcess([], 1, stderr=b"private traceback")):
result = preflight._probe_import(self.root, sys.executable, "pyray")
self.assertEqual(result, {"status": "fail", "detail": "isolated import failed"})
with patch.object(preflight.subprocess, "run", side_effect=subprocess.TimeoutExpired([], 8)):
result = preflight._probe_import(self.root, sys.executable, "pyray")
self.assertEqual(result["detail"], "isolated import timed out")
def test_editable_package_from_another_checkout_is_rejected(self):
foreign = self.root / "second-checkout/tinygrad"
foreign.mkdir(parents=True)
(foreign / "__init__.py").write_text("value = 'wrong checkout'\n")
own_parent = self.root / "tinygrad_repo"
own_parent.mkdir()
(own_parent / "tinygrad").symlink_to(foreign, target_is_directory=True)
result = preflight._probe_import(self.root, sys.executable, "tinygrad")
self.assertEqual(result, {"status": "fail", "detail": "isolated import failed: OriginMismatch"})
(own_parent / "tinygrad").unlink()
own = self.root / "tinygrad_repo/tinygrad"
own.mkdir()
(own / "__init__.py").write_text("value = 'staged checkout'\n")
self.assertEqual(preflight._probe_import(self.root, sys.executable, "tinygrad")["status"], "pass")
if __name__ == "__main__":
unittest.main()