feat(control-station): add atomic recorded-session playback
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { after, before, test } from "node:test";
|
||||
|
||||
import { createServer } from "vite";
|
||||
|
||||
let server;
|
||||
let createRecordedOpenWatchdog;
|
||||
let recordedOpenWatchdogTimeoutMs;
|
||||
let rerunViewerInitialSource;
|
||||
let resolveRecordedViewerSourceUrl;
|
||||
|
||||
before(async () => {
|
||||
server = await createServer({
|
||||
appType: "custom",
|
||||
logLevel: "silent",
|
||||
server: { middlewareMode: true },
|
||||
});
|
||||
({
|
||||
createRecordedOpenWatchdog,
|
||||
recordedOpenWatchdogTimeoutMs,
|
||||
rerunViewerInitialSource,
|
||||
resolveRecordedViewerSourceUrl,
|
||||
} = await server.ssrLoadModule("/src/components/RerunViewport.tsx"));
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await server?.close();
|
||||
});
|
||||
|
||||
const sourceUrl = "/api/v1/observation-sessions/session-atomic/recording.rrd";
|
||||
const sha256 = "a".repeat(64);
|
||||
const viewerSourceUrl = `${sourceUrl}?generation=${sha256}`;
|
||||
|
||||
test("only the canonical digest-bound generation URL reaches the native Rerun receiver", () => {
|
||||
const descriptor = {
|
||||
sourceUrl,
|
||||
viewerSourceUrl,
|
||||
byteLength: 246_331_680,
|
||||
sha256,
|
||||
};
|
||||
const resolved = resolveRecordedViewerSourceUrl(descriptor, "http://mission-core.test");
|
||||
assert.equal(resolved, `http://mission-core.test${viewerSourceUrl}`);
|
||||
assert.equal(rerunViewerInitialSource(resolved), resolved);
|
||||
|
||||
for (const unsafeViewerSourceUrl of [
|
||||
sourceUrl,
|
||||
`${sourceUrl}?generation=${"b".repeat(64)}`,
|
||||
`${viewerSourceUrl}&extra=true`,
|
||||
`https://foreign.test${viewerSourceUrl}`,
|
||||
]) {
|
||||
assert.throws(
|
||||
() => resolveRecordedViewerSourceUrl({
|
||||
...descriptor,
|
||||
viewerSourceUrl: unsafeViewerSourceUrl,
|
||||
}, "http://mission-core.test"),
|
||||
/Unsafe recorded RRD viewer descriptor/,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("recorded admission watchdog is size-aware and exits an incomplete load", () => {
|
||||
const smallDelay = recordedOpenWatchdogTimeoutMs(4);
|
||||
const currentDelay = recordedOpenWatchdogTimeoutMs(246_331_680);
|
||||
const largeDelay = recordedOpenWatchdogTimeoutMs(805_687_122);
|
||||
assert.ok(smallDelay >= 120_000);
|
||||
assert.ok(currentDelay >= smallDelay);
|
||||
assert.ok(largeDelay > currentDelay);
|
||||
assert.ok(largeDelay <= 1_800_000);
|
||||
assert.ok(largeDelay > 12_000);
|
||||
|
||||
let scheduledCallback;
|
||||
let scheduledDelay;
|
||||
let timeoutCount = 0;
|
||||
const cancelled = [];
|
||||
const watchdog = createRecordedOpenWatchdog({
|
||||
byteLength: 246_331_680,
|
||||
schedule(callback, timeoutMs) {
|
||||
scheduledCallback = callback;
|
||||
scheduledDelay = timeoutMs;
|
||||
return 17;
|
||||
},
|
||||
cancel(handle) {
|
||||
cancelled.push(handle);
|
||||
},
|
||||
onTimeout() {
|
||||
timeoutCount += 1;
|
||||
},
|
||||
});
|
||||
watchdog.arm();
|
||||
assert.equal(watchdog.pending(), true);
|
||||
assert.equal(scheduledDelay, currentDelay);
|
||||
scheduledCallback();
|
||||
assert.equal(timeoutCount, 1);
|
||||
assert.equal(watchdog.pending(), false);
|
||||
assert.deepEqual(cancelled, []);
|
||||
});
|
||||
|
||||
test("complete recorded admission clears its watchdog", () => {
|
||||
let timeoutCount = 0;
|
||||
const cancelled = [];
|
||||
const watchdog = createRecordedOpenWatchdog({
|
||||
byteLength: 805_687_122,
|
||||
schedule() {
|
||||
return 23;
|
||||
},
|
||||
cancel(handle) {
|
||||
cancelled.push(handle);
|
||||
},
|
||||
onTimeout() {
|
||||
timeoutCount += 1;
|
||||
},
|
||||
});
|
||||
watchdog.arm();
|
||||
watchdog.clear();
|
||||
assert.equal(watchdog.pending(), false);
|
||||
assert.equal(timeoutCount, 0);
|
||||
assert.deepEqual(cancelled, [23]);
|
||||
});
|
||||
|
||||
test("recorded RRD bytes are never split across LogChannel.send_rrd calls", async () => {
|
||||
const source = await readFile(
|
||||
new URL("../src/components/RerunViewport.tsx", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
assert.doesNotMatch(source, /streamVerifiedRecordedRrd/);
|
||||
assert.doesNotMatch(source, /missioncore\/recorded-recording/);
|
||||
assert.doesNotMatch(source, /recordedChannel/);
|
||||
assert.match(source, /viewer\.start\(\s*rerunViewerInitialSource\(resolvedSource\)/s);
|
||||
assert.match(
|
||||
source,
|
||||
/recordingOpened = true;[\s\S]*if \(!isRecordedSource\) clearLiveRecordingOpenTimer\(\);/,
|
||||
);
|
||||
assert.match(
|
||||
source,
|
||||
/viewerStartResolved = true;\s*if \(isRecordedSource && !recordedSceneAdmitted\) recordedOpenWatchdog\?\.arm\(\);/,
|
||||
);
|
||||
assert.match(
|
||||
source,
|
||||
/if \(readyToRender && !readyPublished\)[\s\S]*clearRecordedAdmissionWatchdog\(\);/,
|
||||
);
|
||||
});
|
||||
|
||||
test("the complete vendor canvas host is hidden during partial and failed admission", async () => {
|
||||
const css = await readFile(new URL("../src/styles/spatial.css", import.meta.url), "utf8");
|
||||
assert.match(
|
||||
css,
|
||||
/\.rerun-viewport:is\(\[data-status="loading"\], \[data-status="error"\]\)\s+\.rerun-viewport__canvas\s*\{[^}]*visibility:\s*hidden;[^}]*pointer-events:\s*none;/s,
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
css,
|
||||
/data-status="loading"[^}]*\.rerun-viewport__canvas\s*>\s*div/s,
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user