171 lines
5.6 KiB
Python
171 lines
5.6 KiB
Python
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from k1link.sessions.lab_cache import publish_lab_replay_cache
|
|
from k1link.sessions.recording import (
|
|
CACHE_SCHEMA,
|
|
RECORDING_CACHE_FILENAME,
|
|
RECORDING_CACHE_SIDECAR_FILENAME,
|
|
)
|
|
|
|
|
|
def canonical_json(value: object) -> bytes:
|
|
return json.dumps(
|
|
value,
|
|
ensure_ascii=False,
|
|
sort_keys=True,
|
|
separators=(",", ":"),
|
|
allow_nan=False,
|
|
).encode()
|
|
|
|
|
|
def test_publish_lab_replay_cache_hardlinks_rrd_and_rebinds_sidecars(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
data = tmp_path / "mission-core"
|
|
recordings = data / "recordings"
|
|
source = recordings / "source-session"
|
|
source.mkdir(parents=True)
|
|
source_rrd = source / RECORDING_CACHE_FILENAME
|
|
source_rrd.write_bytes(b"RRF2immutable")
|
|
source_sidecar = {
|
|
"schema_version": CACHE_SCHEMA,
|
|
"session_id": source.name,
|
|
"recording_byte_length": source_rrd.stat().st_size,
|
|
"recording_mtime_ns": source_rrd.stat().st_mtime_ns,
|
|
"recording_sha256": hashlib.sha256(source_rrd.read_bytes()).hexdigest(),
|
|
"timeline": "session_time",
|
|
"timeline_start_ns": 0,
|
|
"timeline_end_ns": 1,
|
|
}
|
|
(source / RECORDING_CACHE_SIDECAR_FILENAME).write_text(
|
|
json.dumps(source_sidecar),
|
|
encoding="utf-8",
|
|
)
|
|
media_root = data / "recorded-media-preparations"
|
|
media_root.mkdir()
|
|
media_body = {
|
|
"schema_version": "missioncore.recorded-media-preparation/v1",
|
|
"session_id": source.name,
|
|
"artifact_id": "recorded-video-1",
|
|
"generation": "accepted",
|
|
}
|
|
(media_root / "source.json").write_text(
|
|
json.dumps(
|
|
{
|
|
**media_body,
|
|
"checksum_sha256": hashlib.sha256(canonical_json(media_body)).hexdigest(),
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
publish_lab_replay_cache(
|
|
data,
|
|
source_session_id=source.name,
|
|
lab_session_id="lab-e21-result",
|
|
)
|
|
|
|
lab = recordings / "lab-e21-result"
|
|
lab_rrd = lab / RECORDING_CACHE_FILENAME
|
|
assert lab_rrd.read_bytes() == source_rrd.read_bytes()
|
|
assert lab_rrd.stat().st_ino == source_rrd.stat().st_ino
|
|
assert lab_rrd.stat().st_nlink == 2
|
|
cloned_cache = json.loads(
|
|
(lab / RECORDING_CACHE_SIDECAR_FILENAME).read_text(encoding="utf-8")
|
|
)
|
|
assert cloned_cache["session_id"] == "lab-e21-result"
|
|
cloned_media = [
|
|
json.loads(path.read_text(encoding="utf-8"))
|
|
for path in media_root.iterdir()
|
|
if path.name != "source.json"
|
|
]
|
|
assert len(cloned_media) == 1
|
|
assert cloned_media[0]["session_id"] == "lab-e21-result"
|
|
cloned_checksum = cloned_media[0].pop("checksum_sha256")
|
|
assert cloned_checksum == hashlib.sha256(canonical_json(cloned_media[0])).hexdigest()
|
|
|
|
lab_rrd.unlink()
|
|
assert source_rrd.read_bytes() == b"RRF2immutable"
|
|
|
|
|
|
def test_publish_lab_replay_cache_materializes_exact_bounded_window(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
import numpy as np
|
|
import rerun as rr
|
|
|
|
data = tmp_path / "mission-core"
|
|
recordings = data / "recordings"
|
|
source = recordings / "source-session"
|
|
source.mkdir(parents=True)
|
|
source_rrd = source / RECORDING_CACHE_FILENAME
|
|
recording = rr.RecordingStream(
|
|
"nodedc_mission_core_recorded",
|
|
recording_id=source.name,
|
|
)
|
|
stream = rr.binary_stream(recording)
|
|
try:
|
|
for index, timestamp in enumerate((0, 2_000_000_000, 4_000_000_000, 8_000_000_000)):
|
|
recording.set_time(
|
|
"session_time",
|
|
duration=np.timedelta64(timestamp, "ns"),
|
|
)
|
|
recording.log(
|
|
"/world/points",
|
|
rr.Points3D([[float(index), 0.0, 0.0]]),
|
|
)
|
|
payload = stream.read(flush=True, flush_timeout_sec=5.0)
|
|
finally:
|
|
recording.disconnect()
|
|
assert payload is not None
|
|
source_rrd.write_bytes(payload)
|
|
source_sidecar = {
|
|
"schema_version": CACHE_SCHEMA,
|
|
"session_id": source.name,
|
|
"recording_byte_length": source_rrd.stat().st_size,
|
|
"recording_mtime_ns": source_rrd.stat().st_mtime_ns,
|
|
"recording_sha256": hashlib.sha256(source_rrd.read_bytes()).hexdigest(),
|
|
"timeline": "session_time",
|
|
"timeline_start_ns": 0,
|
|
"timeline_end_ns": 8_000_000_000,
|
|
}
|
|
(source / RECORDING_CACHE_SIDECAR_FILENAME).write_text(
|
|
json.dumps(source_sidecar),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
publish_lab_replay_cache(
|
|
data,
|
|
source_session_id=source.name,
|
|
lab_session_id="lab-e21-bounded",
|
|
timeline_start_ns=2_000_000_000,
|
|
timeline_end_ns=4_000_000_000,
|
|
)
|
|
|
|
lab = recordings / "lab-e21-bounded"
|
|
lab_rrd = lab / RECORDING_CACHE_FILENAME
|
|
assert lab_rrd.stat().st_ino != source_rrd.stat().st_ino
|
|
bounded = json.loads(
|
|
(lab / RECORDING_CACHE_SIDECAR_FILENAME).read_text(encoding="utf-8")
|
|
)
|
|
assert bounded["timeline_start_ns"] == 2_000_000_000
|
|
assert bounded["timeline_end_ns"] == 4_000_000_000
|
|
assert bounded["recording_byte_length"] == lab_rrd.stat().st_size
|
|
assert bounded["recording_sha256"] == hashlib.sha256(lab_rrd.read_bytes()).hexdigest()
|
|
assert "lab_window" not in bounded
|
|
|
|
original_stat = lab_rrd.stat()
|
|
publish_lab_replay_cache(
|
|
data,
|
|
source_session_id=source.name,
|
|
lab_session_id="lab-e21-bounded",
|
|
timeline_start_ns=2_000_000_000,
|
|
timeline_end_ns=4_000_000_000,
|
|
)
|
|
assert lab_rrd.stat().st_ino == original_stat.st_ino
|
|
assert lab_rrd.stat().st_mtime_ns == original_stat.st_mtime_ns
|