import assert from 'node:assert/strict'; import {before,after,test} from 'node:test'; import {execFileSync} from 'node:child_process'; import {createServer} from 'vite'; let server,previewFrames,assertRrd,previewFreshness,previewCamera; before(async()=>{ server=await createServer({appType:'custom',logLevel:'silent',server:{middlewareMode:true}}); ({previewCamera}=await server.ssrLoadModule('@xgrids-k1/frontend/sensors/previewCamera.ts')); ({previewFreshness}=await server.ssrLoadModule('@xgrids-k1/frontend/sensors/previewFreshness.ts')); ({previewFrames,assertRrd}=await server.ssrLoadModule('@xgrids-k1/frontend/sensors/previewFrames.ts')); }); after(async()=>{await server?.close();}); const array=bytes=>Uint8Array.from(bytes).buffer; const header=size=>{const value=new Uint8Array(8);value.set([77,67,70,49]);new DataView(value.buffer).setUint32(4,size);return value.buffer;}; test('native RRD crosses many RTC fragments and reaches decoder once, byte-for-byte',()=>{ const payload=execFileSync('../../.venv/bin/python',['-c',`import rerun as rr, numpy as np, sys r=rr.RecordingStream('synthetic-r10-js'); b=r.binary_stream() r.log('points',rr.Points3D(np.random.default_rng(42).random((5000,3)))) sys.stdout.buffer.write(b.read())`]); assert.ok(payload.length>16384); const calls=[]; const receiver=previewFrames(value=>{assertRrd(value);calls.push(value);}); for(let record=0;record<2;record++){ receiver.push(header(payload.length)); for(let offset=0;offset{ let calls=0; const receiver=previewFrames(value=>{assertRrd(value);calls++;}); assert.throws(()=>receiver.push(array([1,2,3]))); assert.throws(()=>receiver.push(header(8*1024*1024+1))); assert.throws(()=>receiver.push(header(0))); receiver.push(header(20));receiver.push(array([1,2]));receiver.close(); assert.equal(calls,0); receiver.push(header(12));assert.throws(()=>receiver.push(array(new Uint8Array(13))));receiver.close(); receiver.push(header(12));assert.throws(()=>receiver.push(array(new Uint8Array(12)))); assert.equal(calls,0); }); test('source age expires even when metadata repeats, old frames never look live',()=>{ let now=10000;const gate=previewFreshness(()=>now); assert.equal(gate.fresh,false); gate.receive({type:'lidar-state',sequence:1,age_ms:250,points:3}); assert.equal(gate.fresh,true);assert.equal(gate.points,3); now+=1800;gate.receive({type:'lidar-state',sequence:1,age_ms:0,points:3}); assert.equal(gate.fresh,false); gate.receive({type:'lidar-state',sequence:2,age_ms:9000,points:3}); assert.equal(gate.fresh,false); gate.receive({type:'lidar-state',sequence:3,age_ms:0,points:4}); assert.equal(gate.fresh,true);assert.equal(gate.points,4); assert.throws(()=>gate.receive({type:'lidar-state',sequence:4,age_ms:-1,points:4})); }); test('onboard camera admits immediate sourceopen and ignores callbacks after close',()=>{ const saved={media:globalThis.MediaSource,create:URL.createObjectURL,revoke:URL.revokeObjectURL}; let source,buffer,appended=0,ready=0,failed=0; class Buffer extends EventTarget {updating=false;buffered={length:0};appendBuffer(){appended++;}} class Media extends EventTarget { readyState='open';static isTypeSupported(){return true;} constructor(){super();source=this;} addSourceBuffer(){buffer=new Buffer();return buffer;} } class Video extends EventTarget {currentTime=0;set src(_){source.dispatchEvent(new Event('sourceopen'));}pause(){}load(){}removeAttribute(){}play(){return Promise.resolve();}} globalThis.MediaSource=Media;URL.createObjectURL=()=> 'blob:synthetic';URL.revokeObjectURL=()=>{}; try{ const video=new Video(),decoder=previewCamera(video,()=>ready++,()=>failed++); decoder.open('video/mp4');decoder.push(new Uint8Array([1,2,3])); assert.equal(appended,1); video.dispatchEvent(new Event('loadeddata'));assert.equal(ready,1); decoder.close();video.dispatchEvent(new Event('loadeddata'));buffer.dispatchEvent(new Event('error')); assert.equal(ready,1);assert.equal(failed,0); }finally{globalThis.MediaSource=saved.media;URL.createObjectURL=saved.create;URL.revokeObjectURL=saved.revoke;} });