76 lines
2.0 KiB
Python
76 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from k1link.compute.multirate_perception_qualification import (
|
|
MERGED_FRAME_SCHEMA,
|
|
_validate_merged_rows,
|
|
)
|
|
from k1link.sessions import SessionIntegrityError
|
|
|
|
|
|
def _merged(index: int, semantic: dict[str, object]) -> dict[str, object]:
|
|
return {
|
|
"schema_version": MERGED_FRAME_SCHEMA,
|
|
"frame_index": index,
|
|
"source_frame_index": 1000 + index,
|
|
"session_seconds": 20.0 + index * 0.1,
|
|
"detector_result_age_ms": 80.0,
|
|
"tracks": [],
|
|
"semantic": semantic,
|
|
}
|
|
|
|
|
|
def test_merged_rows_allow_explicit_unavailable_then_fresh(tmp_path: Path) -> None:
|
|
path = tmp_path / "merged-frames.jsonl"
|
|
unavailable = {
|
|
"status": "unavailable",
|
|
"source_frame_index": None,
|
|
"source_age_ms": None,
|
|
"completion_age_ms": None,
|
|
"mask_sha256": None,
|
|
}
|
|
fresh = {
|
|
"status": "fresh",
|
|
"source_frame_index": 1000,
|
|
"source_age_ms": 200.0,
|
|
"completion_age_ms": 210.0,
|
|
"mask_sha256": "a" * 64,
|
|
}
|
|
path.write_text(
|
|
json.dumps(_merged(0, unavailable)) + "\n" + json.dumps(_merged(2, fresh)) + "\n",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
_validate_merged_rows(
|
|
path,
|
|
tmp_path,
|
|
expected_indices=(0, 2),
|
|
source_start=1000,
|
|
semantic_indices={0},
|
|
)
|
|
|
|
|
|
def test_merged_rows_reject_future_semantic_binding(tmp_path: Path) -> None:
|
|
path = tmp_path / "merged-frames.jsonl"
|
|
future = {
|
|
"status": "fresh",
|
|
"source_frame_index": 1005,
|
|
"source_age_ms": 0.0,
|
|
"completion_age_ms": 200.0,
|
|
"mask_sha256": "a" * 64,
|
|
}
|
|
path.write_text(json.dumps(_merged(2, future)) + "\n", encoding="utf-8")
|
|
|
|
with pytest.raises(SessionIntegrityError, match="binding"):
|
|
_validate_merged_rows(
|
|
path,
|
|
tmp_path,
|
|
expected_indices=(2,),
|
|
source_start=1000,
|
|
semantic_indices={5},
|
|
)
|