98 lines
2.7 KiB
Python
98 lines
2.7 KiB
Python
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import sys
|
|
from pathlib import Path
|
|
from types import ModuleType
|
|
|
|
import pytest
|
|
|
|
|
|
def _worker_module() -> ModuleType:
|
|
worker_root = Path(__file__).parents[1] / "experiments" / "perception" / "worker"
|
|
path = worker_root / "run_e9_multirate_perception.py"
|
|
sys.path.insert(0, str(worker_root))
|
|
try:
|
|
spec = importlib.util.spec_from_file_location("e9_multirate_worker", path)
|
|
assert spec is not None and spec.loader is not None
|
|
module = importlib.util.module_from_spec(spec)
|
|
sys.modules[spec.name] = module
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
finally:
|
|
sys.path.pop(0)
|
|
|
|
|
|
def _profile_path() -> Path:
|
|
return (
|
|
Path(__file__).parents[1]
|
|
/ "experiments"
|
|
/ "perception"
|
|
/ "worker"
|
|
/ "e9_multirate_perception_profile.json"
|
|
)
|
|
|
|
|
|
def _semantic(worker: ModuleType, *, index: int, session_seconds: float) -> object:
|
|
return worker.SemanticResult(
|
|
frame_index=index,
|
|
source_frame_index=1000 + index,
|
|
session_seconds=session_seconds,
|
|
completed_monotonic=10.0,
|
|
completion_age_ms=180.0,
|
|
mask_sha256="a" * 64,
|
|
class_pixels={"road": 100},
|
|
class_fractions={"road": 0.5},
|
|
)
|
|
|
|
|
|
def test_e9_profile_pins_independent_bounded_rates() -> None:
|
|
worker = _worker_module()
|
|
|
|
profile, digest = worker._read_profile(_profile_path())
|
|
|
|
assert len(digest) == 64
|
|
assert profile["replay"]["detector_queue_capacity"] == 2
|
|
assert profile["replay"]["semantic_queue_capacity"] == 1
|
|
assert profile["replay"]["semantic_sample_every_frames"] == 5
|
|
assert profile["replay"]["semantic_ttl_ms"] == 750.0
|
|
|
|
|
|
def test_e9_semantic_binding_exposes_fresh_stale_and_unavailable() -> None:
|
|
worker = _worker_module()
|
|
semantic = _semantic(worker, index=5, session_seconds=20.0)
|
|
|
|
assert (
|
|
worker._semantic_binding(
|
|
None,
|
|
frame_session_seconds=20.1,
|
|
ttl_ms=750.0,
|
|
)["status"]
|
|
== "unavailable"
|
|
)
|
|
assert (
|
|
worker._semantic_binding(
|
|
semantic,
|
|
frame_session_seconds=20.7,
|
|
ttl_ms=750.0,
|
|
)["status"]
|
|
== "fresh"
|
|
)
|
|
assert (
|
|
worker._semantic_binding(
|
|
semantic,
|
|
frame_session_seconds=20.8,
|
|
ttl_ms=750.0,
|
|
)["status"]
|
|
== "stale"
|
|
)
|
|
|
|
|
|
def test_e9_latest_semantic_rejects_time_reversal() -> None:
|
|
worker = _worker_module()
|
|
latest = worker.LatestSemantic()
|
|
latest.publish(_semantic(worker, index=5, session_seconds=20.0))
|
|
|
|
with pytest.raises(RuntimeError, match="not monotonic"):
|
|
latest.publish(_semantic(worker, index=4, session_seconds=19.9))
|