mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 03:51:14 +00:00
[AZ-270] [AZ-272] [AZ-279] [AZ-281] [AZ-283] Compose root + FDR schema + 3 Layer-1 helpers
AZ-270: composition root with strategy registry, tier-gated lookup, topo-order construction, all-or-nothing teardown, StrategyNotLinkedError payload. AZ-272: orjson-backed FdrRecord serialise/parse with forward-compat for unknown payload + top-level fields and canonical overrun-record shape. AZ-279: pyproj-backed WGS84/ECEF/ENU + OSM slippy-map tile math with WgsConversionError for shape/range/zoom guards. AZ-281: strict EngineFilenameSchema build/parse/matches_host with anchored regex + enum validation; round-trip identity by construction. AZ-283: dtype-preserving (fp16/fp32) single + batch L2 normaliser with zero-norm safety and descriptor_metric() source-of-truth. pyproject.toml pins pyproj>=3.6 and orjson>=3.9 (named-backend deps per the AZ-272 / AZ-279 contracts). New DTOs LatLonAlt + BoundingBox and EngineCacheKey + HostCapabilities land in _types/ to back the helper contracts. 203 unit tests pass (64 new). Review verdict: PASS_WITH_WARNINGS; findings are perf-NFR deferrals + dep amendment + minor docstring polish. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
"""AZ-281 — EngineFilenameSchema helper AC tests.
|
||||
|
||||
Verifies the contract at ``_docs/02_document/contracts/shared_helpers/engine_filename_schema.md`` v1.0.0.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import random
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from gps_denied_onboard._types.manifests import EngineCacheKey, HostCapabilities
|
||||
from gps_denied_onboard.helpers import EngineFilenameSchema, EngineFilenameSchemaError
|
||||
|
||||
|
||||
def test_ac1_reference_example_builds_exact_string() -> None:
|
||||
assert (
|
||||
EngineFilenameSchema.build("ultravpr", 87, "6.2", "10.3", "fp16")
|
||||
== "ultravpr__sm87_jp6.2_trt10.3_fp16.engine"
|
||||
)
|
||||
|
||||
|
||||
def test_ac2_roundtrip_identity_over_10_random_tuples() -> None:
|
||||
rng = random.Random(2026)
|
||||
for _ in range(10):
|
||||
model = rng.choice(["ultravpr", "netvlad", "megaloc", "selavpr", "salad", "mix_vpr"])
|
||||
sm = rng.choice([72, 86, 87])
|
||||
jp = rng.choice(["5.1", "6.0", "6.2", "6.3"])
|
||||
trt = rng.choice(["8.6", "10.0", "10.3", "10.4"])
|
||||
prec = rng.choice(["fp16", "int8", "mixed"])
|
||||
filename = EngineFilenameSchema.build(model, sm, jp, trt, prec)
|
||||
parsed = EngineFilenameSchema.parse(filename)
|
||||
assert parsed == EngineCacheKey(model, sm, jp, trt, prec)
|
||||
|
||||
|
||||
def test_ac3_matches_host_exact_match() -> None:
|
||||
filename = EngineFilenameSchema.build("ultravpr", 87, "6.2", "10.3", "fp16")
|
||||
host = HostCapabilities(sm=87, jetpack="6.2", trt="10.3")
|
||||
assert EngineFilenameSchema.matches_host(filename, host) is True
|
||||
|
||||
|
||||
def test_ac4_matches_host_tuple_mismatch_returns_false() -> None:
|
||||
filename = EngineFilenameSchema.build("ultravpr", 87, "6.2", "10.3", "fp16")
|
||||
host_mismatch = HostCapabilities(sm=72, jetpack="6.2", trt="10.3")
|
||||
assert EngineFilenameSchema.matches_host(filename, host_mismatch) is False
|
||||
host_mismatch_trt = HostCapabilities(sm=87, jetpack="6.2", trt="10.4")
|
||||
assert EngineFilenameSchema.matches_host(filename, host_mismatch_trt) is False
|
||||
|
||||
|
||||
def test_ac5_precision_enum_strictness() -> None:
|
||||
with pytest.raises(EngineFilenameSchemaError, match=r"precision"):
|
||||
EngineFilenameSchema.build("ultravpr", 87, "6.2", "10.3", "bf16")
|
||||
|
||||
|
||||
def test_ac6_model_name_character_set_rejection() -> None:
|
||||
with pytest.raises(EngineFilenameSchemaError, match=r"a-z0-9_"):
|
||||
EngineFilenameSchema.build("UltraVPR", 87, "6.2", "10.3", "fp16")
|
||||
|
||||
|
||||
def test_ac7_reserved_separator_collision_rejected() -> None:
|
||||
with pytest.raises(EngineFilenameSchemaError, match=r"__"):
|
||||
EngineFilenameSchema.build("ultra__vpr", 87, "6.2", "10.3", "fp16")
|
||||
|
||||
|
||||
def test_ac8_three_segment_version_rejected() -> None:
|
||||
with pytest.raises(EngineFilenameSchemaError, match=r"major.*minor"):
|
||||
EngineFilenameSchema.build("ultravpr", 87, "6.2.1", "10.3", "fp16")
|
||||
|
||||
|
||||
def test_ac9_parse_rejects_malformed_filename() -> None:
|
||||
with pytest.raises(EngineFilenameSchemaError):
|
||||
EngineFilenameSchema.parse("not_an_engine_file.engine")
|
||||
|
||||
|
||||
def test_ac10_parse_requires_engine_suffix() -> None:
|
||||
with pytest.raises(EngineFilenameSchemaError, match=r"\.engine"):
|
||||
EngineFilenameSchema.parse("ultravpr__sm87_jp6.2_trt10.3_fp16")
|
||||
|
||||
|
||||
def test_ac11_no_upward_imports_to_components() -> None:
|
||||
module_path = (
|
||||
Path(__file__).resolve().parents[2]
|
||||
/ "src"
|
||||
/ "gps_denied_onboard"
|
||||
/ "helpers"
|
||||
/ "engine_filename_schema.py"
|
||||
)
|
||||
tree = ast.parse(module_path.read_text(encoding="utf-8"))
|
||||
bad: list[str] = []
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.ImportFrom) and node.module:
|
||||
if node.module.startswith("gps_denied_onboard.components"):
|
||||
bad.append(node.module)
|
||||
elif isinstance(node, ast.Import):
|
||||
for alias in node.names:
|
||||
if alias.name.startswith("gps_denied_onboard.components"):
|
||||
bad.append(alias.name)
|
||||
assert not bad, f"engine_filename_schema must not import components.*; found: {bad}"
|
||||
Reference in New Issue
Block a user