fix(lab): сжать и адресовать RAV004 overlay
This commit is contained in:
@@ -14,6 +14,7 @@ from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from PIL import Image
|
||||
|
||||
import k1link.laboratory.canonical_rerun_overlay as canonical_overlay_module
|
||||
import k1link.laboratory.vegetation_policy_review as policy_review_module
|
||||
import k1link.laboratory.vegetation_policy_video as policy_video_module
|
||||
import k1link.laboratory.vegetation_shadow_lab as vegetation_lab_module
|
||||
@@ -22,6 +23,9 @@ from k1link.laboratory import LaboratoryEvidenceRegistry
|
||||
from k1link.laboratory.canonical_rerun_overlay import (
|
||||
CanonicalLabOverlayArtifact,
|
||||
_artifact_is_regular,
|
||||
_encoded_semantic_png,
|
||||
_optimize_overlay,
|
||||
_semantic_palette,
|
||||
_video_reference_timestamps,
|
||||
)
|
||||
from k1link.laboratory.evidence_report import verify_laboratory_evidence_result
|
||||
@@ -90,6 +94,64 @@ def test_canonical_overlay_memory_cache_rejects_same_size_tampering(
|
||||
assert not _artifact_is_regular(artifact)
|
||||
|
||||
|
||||
def test_canonical_overlay_keeps_semantics_as_palette_encoded_png() -> None:
|
||||
mask = np.zeros((600, 800), dtype=np.uint8)
|
||||
mask[120:420, 200:600] = 7
|
||||
palette = _semantic_palette(
|
||||
[
|
||||
{"class_id": 0, "color_rgb": [0, 0, 0]},
|
||||
{"class_id": 7, "color_rgb": [255, 47, 128]},
|
||||
]
|
||||
)
|
||||
|
||||
encoded = _encoded_semantic_png(mask, palette)
|
||||
|
||||
assert len(encoded) < mask.nbytes // 20
|
||||
with Image.open(io.BytesIO(encoded)) as image:
|
||||
assert image.mode == "P"
|
||||
assert image.getpixel((0, 0)) == 0
|
||||
assert image.getpixel((300, 300)) == 7
|
||||
assert image.getpalette()[7 * 3 : 7 * 3 + 3] == [255, 47, 128]
|
||||
|
||||
|
||||
def test_canonical_overlay_compacts_chunks_before_cache_publication(
|
||||
tmp_path: Path,
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
source = tmp_path / "source.rrd"
|
||||
source.write_bytes(b"RRF2-source")
|
||||
|
||||
def optimize(command: list[str], **options: object) -> SimpleNamespace:
|
||||
assert command[:4] == [
|
||||
canonical_overlay_module.sys.executable,
|
||||
"-m",
|
||||
"rerun",
|
||||
"rrd",
|
||||
]
|
||||
assert command[4:13] == [
|
||||
"optimize",
|
||||
"--profile",
|
||||
"object-store",
|
||||
"--max-size",
|
||||
"4MiB",
|
||||
"--max-rows",
|
||||
"512",
|
||||
"--num-pass",
|
||||
"20",
|
||||
]
|
||||
assert command[13] == str(source)
|
||||
assert command[14] == "-o"
|
||||
Path(command[15]).write_bytes(b"RRF2-optimized")
|
||||
assert options == {"check": False, "capture_output": True, "timeout": 120}
|
||||
return SimpleNamespace(returncode=0, stderr=b"")
|
||||
|
||||
monkeypatch.setattr(canonical_overlay_module.subprocess, "run", optimize)
|
||||
|
||||
_optimize_overlay(source)
|
||||
|
||||
assert source.read_bytes() == b"RRF2-optimized"
|
||||
|
||||
|
||||
def test_canonical_overlay_get_is_generation_bound_and_range_streamable(
|
||||
tmp_path: Path,
|
||||
monkeypatch,
|
||||
@@ -148,12 +210,28 @@ def test_canonical_overlay_get_is_generation_bound_and_range_streamable(
|
||||
)
|
||||
client = TestClient(app)
|
||||
endpoint = f"/api/v1/laboratory/vegetation-shadow/{result_id}/canonical-overlay.rrd"
|
||||
descriptor = client.head(
|
||||
endpoint,
|
||||
params={
|
||||
"application_id": "nodedc_mission_core_recorded",
|
||||
"recording_id": recording_id,
|
||||
"generation": generation,
|
||||
},
|
||||
)
|
||||
assert descriptor.status_code == 200
|
||||
assert descriptor.content == b""
|
||||
assert descriptor.headers["content-length"] == str(artifact.byte_length)
|
||||
assert descriptor.headers["etag"] == f'"{artifact.sha256}"'
|
||||
assert descriptor.headers["x-rerun-format"] == "RRF2"
|
||||
assert descriptor.headers["cache-control"] == "private, no-store"
|
||||
|
||||
response = client.get(
|
||||
endpoint,
|
||||
params={
|
||||
"application_id": "nodedc_mission_core_recorded",
|
||||
"recording_id": recording_id,
|
||||
"generation": generation,
|
||||
"overlay_generation": artifact.sha256,
|
||||
},
|
||||
headers={"Range": "bytes=0-3"},
|
||||
)
|
||||
@@ -163,7 +241,7 @@ def test_canonical_overlay_get_is_generation_bound_and_range_streamable(
|
||||
assert response.headers["etag"] == f'"{artifact.sha256}"'
|
||||
assert response.headers["cache-control"].endswith("immutable")
|
||||
|
||||
stale = client.get(
|
||||
stale = client.head(
|
||||
endpoint,
|
||||
params={
|
||||
"application_id": "nodedc_mission_core_recorded",
|
||||
@@ -173,6 +251,17 @@ def test_canonical_overlay_get_is_generation_bound_and_range_streamable(
|
||||
)
|
||||
assert stale.status_code == 412
|
||||
|
||||
stale_overlay = client.get(
|
||||
endpoint,
|
||||
params={
|
||||
"application_id": "nodedc_mission_core_recorded",
|
||||
"recording_id": recording_id,
|
||||
"generation": generation,
|
||||
"overlay_generation": "d" * 64,
|
||||
},
|
||||
)
|
||||
assert stale_overlay.status_code == 412
|
||||
|
||||
|
||||
def test_route_playback_chunk_descriptor_seals_only_requested_binary_window() -> None:
|
||||
points = np.arange(18, dtype="<f4").reshape(6, 3)
|
||||
|
||||
Reference in New Issue
Block a user