#!/usr/bin/env python3 """Behavioral tests for validate_psp.py.""" import hashlib import json import tempfile from pathlib import Path import validate_psp def main() -> int: with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) psp = root / "psp" (psp / "configs").mkdir(parents=True) (psp / "scripts").mkdir() (psp / "AiPlugin").mkdir() artifact_root = root / "imgs" / "20260902_1" artifact_root.mkdir(parents=True) artifact = artifact_root / "boot.bin" artifact.write_bytes(b"boot") digest = hashlib.sha256(artifact.read_bytes()).hexdigest() kernel = artifact_root / "kernel.bin" kernel.write_bytes(b"kernel") rootfs = artifact_root / "rootfs.bin" rootfs.write_bytes(b"rootfs") (psp / "psp.json").write_text( json.dumps( { "EmxMediaVersion": "EmxMedia-1", "EmxAiPluginVersion": "EmxAiPlugin-1", "EmxResToProduct": [{"src": str(artifact), "dst": "imgs/boot.bin"}], } ), encoding="utf-8", ) (psp / "AiPlugin" / "profile.json").write_text( json.dumps({"EmxSdkVersion": "EmxSdk-1"}), encoding="utf-8" ) (psp / "configs" / "same.json").write_text( json.dumps( { "source": "psp", "tool_cache": "/var/tmp/psp-tool-only", "endpoint": "https://git.example/psp", } ), encoding="utf-8", ) sensor_dir = psp / "configs" / "media" / "sensor" sensor_dir.mkdir(parents=True) (sensor_dir / "sensor_cfg.ini").write_text( "[sensor]\nname = 0X201C3B40\n", encoding="utf-8" ) expected_sensors = [("sensor", "SMS_SC4336P_MIPI_4M_30FPS_10BIT")] (psp / "scripts" / "start.sh").write_text("#!/bin/sh\ntrue\n", encoding="utf-8") app = root / "orgConfigs" app.mkdir() (app / "same.json").write_text('{"source":"app"}', encoding="utf-8") (psp / "metadata").mkdir() (psp / "metadata" / "allowed-overrides.json").write_text( json.dumps( { "schema_version": 1, "overrides": [ { "psp_path": "configs/same.json", "application_path": "orgConfigs/same.json", "winner": "psp", "reason": "board config", "confirmed_by": "PSP owner", "confirmed_at": "2026-09-02T00:00:00+00:00", } ], } ), encoding="utf-8", ) handoff = root / "psp_handoff.json" bsp_project = root / "CV1841CP-NEW_dualos" partition = bsp_project / "configs" / "board" / "partition" / "partition_spinand.xml" partition.parent.mkdir(parents=True) partition.write_text( """ """, encoding="utf-8", ) margin_checks = [] for image in (kernel, rootfs): size = image.stat().st_size margin_checks.append( { "image": image.name, "image_path": str(image), "image_size_bytes": size, "partitions": [ { "label": "BOOT" if image.name == "kernel.bin" else "ROOTFS", "alias": "kernel.A" if image.name == "kernel.bin" else "rootfs.A", "file": image.name, "size_in_kb": 1024, "size_bytes": 1024 * 1024, } ], "effective_partition_size_bytes": 1024 * 1024, "required_margin_bytes": 512 * 1024, "actual_margin_bytes": 1024 * 1024 - size, "passed": True, } ) margin = { "schema_version": 1, "passed": True, "checked_at": "2026-09-02T00:00:00+00:00", "partition_table": str(partition), "partition_table_sha256": hashlib.sha256(partition.read_bytes()).hexdigest(), "required_margin_bytes": 512 * 1024, "checks": margin_checks, } margin_path = bsp_project / "doc" / "bsp_adaptation" / "validation" / "image_partition_margin_20260902_1.json" margin_path.parent.mkdir(parents=True) margin_path.write_text(json.dumps(margin), encoding="utf-8") handoff.write_text( json.dumps( { "schema_version": 1, "handoff_type": "bsp-to-psp", "producer": { "project": "CV1841CP-NEW_dualos", "project_path": str(bsp_project), }, "baseline": { "chip": "CV1841CP", "sdk": "cv184x-v1", "board_build_type": "cv1841cp_wevb_0015a_spinand", "system_form": "dual-os", }, "build": { "version": "20260902_1", "status": "build_passed", "exit_code": 0, "completion_marker_seen": True, "imgs_version_path": str(artifact_root), "image_partition_margin_path": str(margin_path), }, "artifacts": [ { "relative_path": item.name, "absolute_path": str(item), "size": item.stat().st_size, "sha256": hashlib.sha256(item.read_bytes()).hexdigest(), } for item in (artifact, kernel, rootfs) ], "validation": { "image_partition_margin": margin, "hardware": "pending", "owner_acceptance": "pending", "release": "not-authorized", }, } ), encoding="utf-8", ) lock = psp / "metadata" / "bsp.lock.json" result = validate_psp.validate_psp( psp, "NEW", "EmxSdk-1", "EmxMedia-1", "EmxAiPlugin-1", handoff, lock, "CV1841CP-NEW_dualos", "CV1841CP", "cv184x-v1", "cv1841cp_wevb_0015a_spinand", "dual-os", [], [(app, "configs")], formal=False, expected_sensors=expected_sensors, ) assert result["passed"] is True, result assert lock.is_file() lock_payload = json.loads(lock.read_text(encoding="utf-8")) assert lock_payload["image_partition_margin"]["required_margin_bytes"] == 512 * 1024 assert result["checks"]["configuration_overrides"][0]["allowed"] is True assert any("个人或临时目录" in warning for warning in result["warnings"]) assert any( item["source"] == "configs/same.json" for item in result["checks"]["absolute_paths"] ) assert all( "git.example" not in item["path"] for item in result["checks"]["absolute_paths"] ) assert result["checks"]["sensor_baseline"]["sensors"][0]["matched"] is True assert result["checks"]["sensor_baseline"]["enum_header"]["source"] == "bundled" assert result["checks"]["sensor_baseline"]["enum_header"]["path"] == str( validate_psp.bundled_sensor_header("cv184x") ) cv184_items = validate_psp.parse_sensor_enum( validate_psp.bundled_sensor_header("cv184x"), "_SNS_TYPE_E" ) assert len(cv184_items) == 244 assert cv184_items["SMS_SC4336P_MIPI_4M_30FPS_10BIT"] == 0X201C3B40 assert cv184_items["IMGDS_MIS40C1_MIPI_4M_20FPS_1L_10BIT"] == 0X00003A00 assert "BYD_BF2253L_MIPI_1200P_30FPS_10BIT" not in cv184_items formal = validate_psp.validate_psp( psp, "NEW", "EmxSdk-1", "EmxMedia-1", "EmxAiPlugin-1", handoff, None, "CV1841CP-NEW_dualos", "CV1841CP", "cv184x-v1", "cv1841cp_wevb_0015a_spinand", "dual-os", [artifact_root, handoff], [(app, "configs")], formal=True, expected_sensors=expected_sensors, ) assert formal["passed"] is False assert any( "configs/same.json" in error and "个人或临时目录" in error for error in formal["errors"] ) artifact.write_bytes(b"tampered") tampered = validate_psp.validate_psp( psp, "NEW", None, None, None, handoff, None, "CV1841CP-NEW_dualos", "CV1841CP", "cv184x-v1", "cv1841cp_wevb_0015a_spinand", "dual-os", [], [], formal=False, expected_sensors=expected_sensors, ) assert tampered["passed"] is False assert any("BSP handoff" in error for error in tampered["errors"]) missing_identity = validate_psp.validate_psp( psp, "NEW", None, None, None, handoff, None, None, None, None, None, None, [], [], formal=False, expected_sensors=expected_sensors, ) assert missing_identity["passed"] is False assert any("必需身份字段" in error for error in missing_identity["errors"]) (sensor_dir / "sensor_cfg.ini").write_text( "[sensor]\nname = SMS_SC4336P_MIPI_4M_30FPS_10BIT\n", encoding="utf-8" ) sensor_errors: list[str] = [] validate_psp.validate_sensor_baseline( psp, "CV1841CP", None, expected_sensors, sensor_errors, ) assert any("必须填写" in error and "枚举值" in error for error in sensor_errors) cv181_psp = root / "cv181-psp" cv181_sensor_dir = cv181_psp / "configs" / "media" / "isp" cv181_sensor_dir.mkdir(parents=True) (cv181_sensor_dir / "sensor_cfg.ini").write_text( "[sensor]\nname = SMS_SC4336P_MIPI_4M_30FPS_10BIT\n", encoding="utf-8" ) cv181_errors: list[str] = [] cv181_result = validate_psp.validate_sensor_baseline( cv181_psp, "CV1815J", None, expected_sensors, cv181_errors, ) assert cv181_errors == [], cv181_errors assert cv181_result["sensors"][0]["matched"] is True assert cv181_result["enum_header"]["source"] == "bundled" cv181_items = validate_psp.parse_sensor_enum( validate_psp.bundled_sensor_header("cv181x"), "_SAMPLE_SNS_TYPE_E" ) assert len(cv181_items) == 213 assert "SMS_SC4336P_MIPI_4M_30FPS_10BIT" in cv181_items print("PSP validator tests passed") return 0 if __name__ == "__main__": raise SystemExit(main())