import assert from "node:assert/strict"; import { after, before, test } from "node:test"; import { createElement } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { createServer } from "vite"; let server; let xgridsK1Manifest; let xgridsK1ObservationSources; let openObservationSource; let shouldRestartObservationSource; let consumeCameraLeaseRetry; let resetCameraLeaseRetryBudget; let initialObservationWindowRect; let ObservationTimeline; let shouldCaptureWorkspacePointer; let normalizeTimelineRange; let timelineOffsetSeconds; let formatTimelineDuration; let normalizeAccumulationSeconds; let formatAccumulationDuration; let resolveRerunSourceUrl; let resolveRecordedBlueprintUrl; let fetchRecordedBlueprintRrd; let isRecordedPlaybackFullyBuffered; let recordedObservationSources; let selectRecordedMediaEpoch; let recordedMediaLocalTime; before(async () => { server = await createServer({ appType: "custom", logLevel: "silent", server: { middlewareMode: true }, }); ({ xgridsK1Manifest } = await server.ssrLoadModule( "@xgrids-k1/frontend/manifest.ts", )); ({ xgridsK1ObservationSources } = await server.ssrLoadModule( "@xgrids-k1/frontend/observationSources.ts", )); ({ openObservationSource, shouldRestartObservationSource } = await server.ssrLoadModule( "/src/core/observation/layoutPolicy.ts", )); ({ consumeCameraLeaseRetry, resetCameraLeaseRetryBudget } = await server.ssrLoadModule( "/src/components/MseFmp4WebSocketPlayer.tsx", )); ({ initialObservationWindowRect, shouldCaptureWorkspacePointer } = await server.ssrLoadModule( "/src/components/FloatingObservationWindow.tsx", )); ({ ObservationTimeline, normalizeTimelineRange, timelineOffsetSeconds, formatTimelineDuration, normalizeAccumulationSeconds, formatAccumulationDuration, } = await server.ssrLoadModule("/src/components/ObservationTimeline.tsx")); ({ resolveRerunSourceUrl, resolveRecordedBlueprintUrl, fetchRecordedBlueprintRrd, isRecordedPlaybackFullyBuffered, } = await server.ssrLoadModule( "/src/components/RerunViewport.tsx", )); ({ recordedObservationSources } = await server.ssrLoadModule( "/src/core/observation/recordedObservationSources.ts", )); ({ selectRecordedMediaEpoch, recordedMediaLocalTime } = await server.ssrLoadModule( "/src/components/RecordedFmp4Player.tsx", )); }); test("observation camera windows tile from the bottom-right above the live timeline", () => { const bounds = { width: 1280, height: 720 }; const left = initialObservationWindowRect(0, 2, bounds); const right = initialObservationWindowRect(1, 2, bounds); assert.equal(left.y, right.y); assert.ok(left.x + left.width < right.x); assert.equal(right.x + right.width, bounds.width - 18); assert.ok(right.y + right.height <= bounds.height - 64); }); test("observation camera windows stack without overlap when the viewport is narrow", () => { const bounds = { width: 420, height: 700 }; const lower = initialObservationWindowRect(0, 2, bounds); const upper = initialObservationWindowRect(1, 2, bounds); assert.equal(lower.x, upper.x); assert.ok(upper.y + upper.height < lower.y); for (const rect of [lower, upper]) { assert.ok(rect.x >= 0 && rect.y >= 0); assert.ok(rect.x + rect.width <= bounds.width); assert.ok(rect.y + rect.height <= bounds.height - 64); } }); test("observation camera tiling remains in bounds on a constrained viewport", () => { const bounds = { width: 260, height: 280 }; const rects = Array.from({ length: 2 }, (_, index) => ( initialObservationWindowRect(index, 2, bounds) )); for (const rect of rects) { assert.ok(rect.width > 0 && rect.height > 0); assert.ok(rect.x >= 0 && rect.y >= 0); assert.ok(rect.x + rect.width <= bounds.width); assert.ok(rect.y + rect.height <= bounds.height - 64); } assert.ok(rects[1].y + rects[1].height <= rects[0].y); }); test("floating observation interaction captures resize and movable header pointers", () => { const target = (matches) => ({ closest: (selector) => matches.includes(selector) }); assert.equal( shouldCaptureWorkspacePointer(0, target([".nodedc-workspace-window__resize"])), true, ); assert.equal( shouldCaptureWorkspacePointer(0, target([".nodedc-workspace-window__head"])), true, ); assert.equal( shouldCaptureWorkspacePointer( 0, target([".nodedc-workspace-window__head", "button, input, select, textarea, a"]), ), false, ); assert.equal( shouldCaptureWorkspacePointer(2, target([".nodedc-workspace-window__resize"])), false, ); }); test("recorded observation timeline clamps relative seek time without epoch precision in the UI", () => { const range = normalizeTimelineRange({ min: 0, max: 12_500_000_000, }); assert.ok(range); assert.equal(timelineOffsetSeconds(range, range.min + 2_250_000_000), 2.25); assert.equal(timelineOffsetSeconds(range, range.min - 1), 0); assert.equal(timelineOffsetSeconds(range, range.max + 1), 12.5); assert.equal(formatTimelineDuration(62.125), "01:02.125"); }); test("recorded observation timeline rejects empty and non-finite ranges", () => { assert.equal(normalizeTimelineRange(null), null); assert.equal(normalizeTimelineRange({ min: 10, max: 10 }), null); assert.equal(normalizeTimelineRange({ min: Number.NaN, max: 10 }), null); }); test("accumulation control normalizes UI values and distinguishes a single frame", () => { assert.equal(normalizeAccumulationSeconds(-3), 0); assert.equal(normalizeAccumulationSeconds(12.6), 13); assert.equal(normalizeAccumulationSeconds(999), 120); assert.equal(normalizeAccumulationSeconds(Number.NaN), 0); assert.equal(formatAccumulationDuration(0), "Кадр"); assert.equal(formatAccumulationDuration(12), "12 с"); }); test("spatial timeline renders synchronized accumulation and playback controls", () => { const markup = renderToStaticMarkup(createElement(ObservationTimeline, { active: true, sourceCount: 2, mode: "recorded", seekable: true, rangeNs: { min: 0, max: 20_000_000_000 }, currentNs: 5_000_000_000, accumulationSeconds: 12, onAccumulationChange: () => undefined, onAccumulationCommit: () => undefined, onSeek: () => undefined, })); assert.match(markup, /data-accumulation="true"/); assert.match(markup, /Накопление/); assert.match(markup, /aria-label="Окно накопления облака точек"/); assert.match(markup, /aria-valuetext="12 с"/); assert.match(markup, /aria-label="Позиция воспроизведения"/); assert.equal((markup.match(/type="range"/g) ?? []).length, 2); }); test("Rerun expands only root-relative session recordings onto the current origin", () => { assert.equal( resolveRerunSourceUrl( " /api/v1/observation-sessions/session-1/recording.rrd ", "http://127.0.0.1:5174", ), "http://127.0.0.1:5174/api/v1/observation-sessions/session-1/recording.rrd", ); assert.equal( resolveRerunSourceUrl("rerun+http://127.0.0.1:9877/proxy", "http://127.0.0.1:5174"), "rerun+http://127.0.0.1:9877/proxy", ); assert.equal( resolveRerunSourceUrl("//different-authority.invalid/session.rrd", "http://127.0.0.1:5174"), "//different-authority.invalid/session.rrd", ); }); test("recorded blueprint endpoint is derived only from canonical same-origin RRD sources", () => { assert.equal( resolveRecordedBlueprintUrl( "/api/v1/observation-sessions/session-1/recording.rrd", "http://127.0.0.1:5174", ), "http://127.0.0.1:5174/api/v1/observation-sessions/session-1/blueprint.rrd", ); assert.equal( resolveRecordedBlueprintUrl( "https://outside.invalid/api/v1/observation-sessions/session-1/recording.rrd", "http://127.0.0.1:5174", ), null, ); assert.equal( resolveRecordedBlueprintUrl( "/api/v1/observation-sessions/../recording.rrd", "http://127.0.0.1:5174", ), null, ); }); test("recorded replay becomes ready only after the complete declared timeline is buffered", () => { assert.equal(isRecordedPlaybackFullyBuffered(null, 20), false); assert.equal( isRecordedPlaybackFullyBuffered({ min: 0, max: 19_500_000_000 }, 20), false, ); assert.equal( isRecordedPlaybackFullyBuffered({ min: 0, max: 19_999_500_000 }, 20), true, ); assert.equal( isRecordedPlaybackFullyBuffered({ min: 0, max: 1 }, undefined), true, ); assert.equal( isRecordedPlaybackFullyBuffered({ min: 0, max: 20_000_000_000 }, Number.NaN), false, ); }); test("recorded blueprint fetch is bounded, strict and sends only display settings", async () => { const calls = []; const payload = Uint8Array.from([0x52, 0x52, 0x46, 0x32, 0x01]); const result = await fetchRecordedBlueprintRrd( "http://127.0.0.1:5174/api/v1/observation-sessions/session-1/blueprint.rrd", { accumulationSeconds: 24, showGrid: false, showPoints: true, showTrajectory: false, pointSize: 4.5, palette: "custom", customColor: "#35d7c1", }, { applicationId: "nodedc_mission_core_recorded", recordingId: "recording-001" }, { origin: "http://127.0.0.1:5174", fetcher: async (input, init) => { calls.push({ input: String(input), init, body: JSON.parse(String(init.body)) }); return new Response(payload, { status: 200, headers: { "Content-Type": "application/vnd.rerun.rrd" }, }); }, }, ); assert.deepEqual([...result], [...payload]); assert.equal(calls[0].init.method, "POST"); assert.equal(calls[0].init.credentials, "same-origin"); assert.deepEqual(calls[0].body, { application_id: "nodedc_mission_core_recorded", recording_id: "recording-001", accumulation_seconds: 24, show_grid: false, show_points: true, show_trajectory: false, point_size: 4.5, palette: "custom", custom_color: "#35d7c1", }); await assert.rejects( fetchRecordedBlueprintRrd( "https://outside.invalid/api/v1/observation-sessions/session-1/blueprint.rrd", { accumulationSeconds: 24, showGrid: false, showPoints: true, showTrajectory: false, pointSize: 4.5, palette: "custom", customColor: "#35d7c1", }, { applicationId: "nodedc_mission_core_recorded", recordingId: "recording-001" }, { origin: "http://127.0.0.1:5174", fetcher: async () => new Response(payload) }, ), /Unsafe recorded blueprint request/, ); }); test("recorded replay creates an isolated source catalog without live device bindings", () => { const sources = recordedObservationSources({ kind: "rerun-recording", sessionId: "session-1", sourceUrl: "/api/v1/observation-sessions/session-1/recording.rrd", viewerSourceUrl: `/api/v1/observation-sessions/session-1/recording.rrd?generation=${"a".repeat(64)}`, mediaType: "application/vnd.rerun.rrd", timeline: "session_time", timelineStartSeconds: 0, timelineEndSeconds: 20, seekable: true, byteLength: 123, sha256: "a".repeat(64), playback: { speed: 1, loop: false }, mediaSources: [{ id: "recorded.camera.abc123", label: "Записанная камера 1", modality: "video", manifestUrl: "/api/v1/observation-sessions/session-1/media/recorded-video-abc123/manifest", manifestGenerationSha256: "c".repeat(64), byteLength: 1_024, mediaType: "video/mp4", timelineStartSeconds: 0.25, timelineEndSeconds: 20, seekable: true, synchronization: "host-arrival-best-effort", }], }); assert.deepEqual(sources.map(({ modality }) => modality), ["point-cloud", "video"]); assert.equal(sources[1].delivery.kind, "recorded-fmp4-manifest"); assert.equal(sources[1].delivery.manifestGenerationSha256, "c".repeat(64)); assert.deepEqual(sources[1].binding, {}); assert.equal(sources.some(({ provider }) => provider.pluginId.includes("xgrids")), false); assert.equal(JSON.stringify(sources).includes("192.168"), false); }); test("recorded camera epoch selection and shared-clock offset are deterministic", () => { const epochs = [ { ordinal: 1, timelineStartSeconds: 0.25, timelineEndSeconds: 9 }, { ordinal: 2, timelineStartSeconds: 10, timelineEndSeconds: 20 }, ]; assert.equal(selectRecordedMediaEpoch(epochs, 0), null); assert.equal(selectRecordedMediaEpoch(epochs, 0.25).ordinal, 1); assert.equal(selectRecordedMediaEpoch(epochs, 9), epochs[0]); assert.equal(selectRecordedMediaEpoch(epochs, 9.9), null); assert.equal(selectRecordedMediaEpoch(epochs, 10).ordinal, 2); assert.equal(recordedMediaLocalTime(10, 12.5), 2.5); assert.equal(recordedMediaLocalTime(10, 8), 0); assert.equal(recordedMediaLocalTime(10, 30, 4), 4); }); after(async () => { await server?.close(); }); function model() { const activeModel = xgridsK1Manifest.spec.models[0]; assert.ok(activeModel, "XGRIDS plugin must declare at least one model"); return activeModel; } function cameraRow(sourceId, label) { return { stream_id: `camera.preview.${sourceId.split(".").at(-1)}`, source_id: sourceId, semantic_channel_id: "camera.preview.live", label, sensor_kind: "camera", modality: "encoded-video", availability: "available", endpoint_label: "MSE · fMP4", activation: { group_id: "camera.preview.decoder", max_active: 1, selected: false, controllable: true, }, delivery: null, }; } function declaredState(cameraRows = [ cameraRow("sensor.camera.left", "K1 · камера слева"), cameraRow("sensor.camera.right", "K1 · камера справа"), ]) { const activeModel = model(); return { phase: "connected", source_mode: "idle", k1_ip: "192.168.7.10", foxglove_ws_url: "ws://192.168.7.10:8765", foxglove_viewer_url: "http://192.168.7.10:8765/vendor-viewer", compatibility: { profile_id: "xgrids.lixelkity-k1.fw-3.0.2.local-network.v2", camera_preview: "rtsp://192.168.7.10:8554/vendor-preview", }, device_ref: { device_id: "device-k1-001", model_id: activeModel.id, identity_stability: "stable", identity_basis: "hardware-identifier", }, device_session: { device_session_id: "device-session-001", device_id: "device-k1-001", compatibility_profile_id: "xgrids.lixelkity-k1.fw-3.0.2.local-network.v2", connectivity: "connected", }, sensor_catalog: { schema_version: "missioncore.sensor-catalog/v1alpha2", revision: "test-profile", streams: [ { stream_id: "spatial.point-cloud.live", modality: "point-cloud", availability: "observed" }, ...cameraRows, ], }, camera_preview: { phase: "idle", revision: 1, generation: 0, active_source_id: null, delivery: null, }, }; } function pointCloudStreamingState() { return { ...declaredState(), phase: "streaming", source_mode: "live", rerun_grpc_url: "rerun+http://127.0.0.1:9877/proxy", acquisition: { acquisition_id: "acquisition-001", device_id: "device-k1-001", device_session_id: "device-session-001", compatibility_profile_id: "xgrids.lixelkity-k1.fw-3.0.2.local-network.v2", control_mode: "operator-manual", requested_streams: ["spatial.point-cloud.live"], target_host: "127.0.0.1", duration_seconds: 0, evidence_policy: "required", state: "acquiring", state_revision: 3, }, }; } function cameraStreamingState(sourceId) { const state = pointCloudStreamingState(); const delivery = { id: `preview-generation-7:${sourceId}`, kind: "mse-fmp4-websocket", url: "/api/v1/device-plugins/xgrids-k1/camera-preview/ws?generation=7", media_type: 'video/mp4; codecs="avc1.640028"', }; state.sensor_catalog = { ...state.sensor_catalog, streams: state.sensor_catalog.streams.map((stream) => stream.source_id === sourceId ? { ...stream, availability: "streaming", activation: { ...stream.activation, selected: true }, delivery, } : stream), }; state.camera_preview = { phase: "streaming", revision: 4, generation: 7, active_source_id: sourceId, delivery, }; return state; } function collectUrlLikeStrings(value, found = []) { if (typeof value === "string") { if (value.includes("://")) found.push(value); return found; } if (Array.isArray(value)) { for (const item of value) collectUrlLikeStrings(item, found); return found; } if (value && typeof value === "object") { for (const item of Object.values(value)) collectUrlLikeStrings(item, found); } return found; } test("K1 maps zero, one or N catalog cameras without model-specific source ids", () => { const zero = xgridsK1ObservationSources(declaredState([]), model()); const one = xgridsK1ObservationSources( declaredState([cameraRow("rig.front", "Передняя камера")]), model(), ); const many = xgridsK1ObservationSources(declaredState(), model()); assert.deepEqual(zero.map(({ modality }) => modality), ["point-cloud"]); assert.deepEqual(one.map(({ sourceId }) => sourceId), ["sensor.lidar.primary", "rig.front"]); assert.deepEqual(many.map(({ sourceId }) => sourceId), [ "sensor.lidar.primary", "sensor.camera.left", "sensor.camera.right", ]); assert.equal(new Set(many.map(({ id }) => id)).size, many.length); assert.ok(many.every(({ provider }) => provider.pluginId && provider.modelId)); assert.ok(many.every(({ binding }) => binding.deviceId === "device-k1-001")); }); test("descriptor ids remain stable while point cloud and selected camera start streaming", () => { const declared = xgridsK1ObservationSources(declaredState(), model()); const streaming = xgridsK1ObservationSources( cameraStreamingState("sensor.camera.left"), model(), ); assert.deepEqual(streaming.map(({ id }) => id), declared.map(({ id }) => id)); assert.equal(declared[0].availability, "available"); assert.equal(streaming[0].availability, "streaming"); assert.equal(streaming[0].previewUrl, "rerun+http://127.0.0.1:9877/proxy"); }); test("only the authoritative selected camera receives browser delivery", () => { const sources = xgridsK1ObservationSources( cameraStreamingState("sensor.camera.left"), model(), ); const cameras = sources.filter(({ modality }) => modality === "video"); const [left, right] = cameras; assert.equal(cameras.length, 2); assert.equal(left.activation.selected, true); assert.equal(left.activation.maxActive, 1); assert.equal(left.availability, "streaming"); assert.equal(left.delivery.kind, "mse-fmp4-websocket"); assert.equal(left.transport, "websocket"); assert.equal(right.activation.selected, false); assert.equal(right.availability, "available"); assert.equal(right.delivery, null); assert.equal(left.activation.groupId, right.activation.groupId); assert.match(left.activation.groupId, /device-session-001/); }); test("switching left to right keeps ids stable and never exposes both deliveries", () => { const left = xgridsK1ObservationSources( cameraStreamingState("sensor.camera.left"), model(), ).filter(({ modality }) => modality === "video"); const right = xgridsK1ObservationSources( cameraStreamingState("sensor.camera.right"), model(), ).filter(({ modality }) => modality === "video"); assert.deepEqual(right.map(({ id }) => id), left.map(({ id }) => id)); assert.deepEqual(left.filter(({ delivery }) => delivery).map(({ sourceId }) => sourceId), [ "sensor.camera.left", ]); assert.deepEqual(right.filter(({ delivery }) => delivery).map(({ sourceId }) => sourceId), [ "sensor.camera.right", ]); }); test("camera descriptors never leak vendor RTSP endpoints or device IP addresses", () => { const sources = xgridsK1ObservationSources( cameraStreamingState("sensor.camera.left"), model(), ); const cameras = sources.filter(({ modality }) => modality === "video"); assert.ok(cameras.every(({ previewUrl }) => previewUrl === null)); assert.deepEqual(collectUrlLikeStrings(sources), [ "rerun+http://127.0.0.1:9877/proxy", ]); const serialized = JSON.stringify(cameras); assert.doesNotMatch(serialized, /rtsp:\/\//i); assert.doesNotMatch(serialized, /192\.168\.7\.10/); assert.doesNotMatch(serialized, /vendor-(?:preview|viewer)/); }); test("unattested, duplicate and unsafe camera entries fail closed", () => { const duplicate = cameraRow("sensor.camera.left", "Duplicate"); const state = cameraStreamingState("sensor.camera.left"); state.compatibility.profile_id = null; state.device_session.compatibility_profile_id = null; state.sensor_catalog.streams.push(duplicate); state.camera_preview.delivery = { ...state.camera_preview.delivery, url: "ws://192.168.7.10:9000/leak", }; const cameras = xgridsK1ObservationSources(state, model()).filter( ({ modality }) => modality === "video", ); assert.deepEqual(cameras.map(({ sourceId }) => sourceId), ["sensor.camera.right"]); assert.equal(cameras[0].availability, "unverified"); assert.equal(cameras[0].activation.controllable, false); assert.equal(cameras[0].delivery, null); }); test("camera delivery rejects literal and encoded endpoint or credential leaks", () => { const unsafeUrls = [ "/api/preview?upstream=rtsp://camera.local/live", "/api/preview?upstream=rtsp%3A%2F%2Fcamera.local%2Flive", "/api/preview?upstream=rtsp%253A%252F%252Fcamera.local%252Flive", "/api/preview?endpoint=192.168.68.52:8554", "/api/preview?endpoint=192%2E168%2E68%2E52", "/api/preview?password=not-for-the-browser", "/api/preview?%70%61%73%73%77%6f%72%64=not-for-the-browser", "/api/preview/camera:secret@device", "/%2f%2fevil.example/preview", ]; for (const url of unsafeUrls) { const state = cameraStreamingState("sensor.camera.left"); state.camera_preview.delivery = { ...state.camera_preview.delivery, url }; state.sensor_catalog.streams = state.sensor_catalog.streams.map((stream) => stream.source_id === "sensor.camera.left" ? { ...stream, delivery: { ...stream.delivery, url } } : stream, ); const left = xgridsK1ObservationSources(state, model()).find( ({ sourceId }) => sourceId === "sensor.camera.left", ); assert.ok(left, `left camera descriptor missing for ${url}`); assert.equal(left.delivery, null, `unsafe delivery escaped for ${url}`); } }); test("manual camera reconnect restores an exhausted lease retry budget", () => { let budget = resetCameraLeaseRetryBudget("delivery-7"); for (const expectedDelay of [400, 1_000, 2_000]) { const retry = consumeCameraLeaseRetry(budget, "delivery-7"); assert.equal(retry.delay, expectedDelay); budget = retry.budget; } assert.equal(consumeCameraLeaseRetry(budget, "delivery-7").delay, null); budget = resetCameraLeaseRetryBudget("delivery-7"); const retryAfterManualReset = consumeCameraLeaseRetry(budget, "delivery-7"); assert.equal(retryAfterManualReset.delay, 400); assert.equal(retryAfterManualReset.budget.count, 1); }); test("layout policy evicts only exclusive camera peers", () => { const sources = xgridsK1ObservationSources( cameraStreamingState("sensor.camera.left"), model(), ); const left = sources.find(({ sourceId }) => sourceId === "sensor.camera.left"); const right = sources.find(({ sourceId }) => sourceId === "sensor.camera.right"); const pointCloud = sources.find(({ modality }) => modality === "point-cloud"); assert.ok(left && right && pointCloud); const change = openObservationSource( [pointCloud.id, left.id], right.id, sources, ); assert.deepEqual(change.visibleIds, [pointCloud.id, right.id]); assert.deepEqual(change.removedIds, [left.id]); }); test("selected camera without delivery is explicitly restartable", () => { const state = cameraStreamingState("sensor.camera.left"); state.camera_preview = { ...state.camera_preview, phase: "error", delivery: null, }; state.sensor_catalog.streams = state.sensor_catalog.streams.map((stream) => stream.source_id === "sensor.camera.left" ? { ...stream, availability: "error", delivery: null } : stream, ); const sources = xgridsK1ObservationSources(state, model()); const left = sources.find(({ sourceId }) => sourceId === "sensor.camera.left"); const right = sources.find(({ sourceId }) => sourceId === "sensor.camera.right"); assert.ok(left && right); assert.equal(left.activation.selected, true); assert.equal(left.delivery, null); assert.equal(left.availability, "error"); assert.equal(shouldRestartObservationSource(left), true); assert.equal(shouldRestartObservationSource(right), false); });