io-v2-events.test.mjs (2880B)
1 import test from 'node:test'; 2 import assert from 'node:assert/strict'; 3 import {Events} from '../dist/io-v2-events.js'; 4 test('invalid/stale/wrong-kind replies preserve the live read',async()=>{ 5 const e=new Events('1'),c=new AbortController(),pending=e.read(3,c.signal); 6 assert.equal(e.reply({run:'1',id:1,kind:'read',bytes:[1],eof:false}),false); 7 const event=e.take()[0]; 8 for(const change of [{run:'2'},{id:2},{kind:'write',count:1},{bytes:[0,1,2,3]},{bytes:[256]},{bytes:[],eof:false},{bytes:[1],eof:true},{kind:'cancelled'}]) 9 assert.equal(e.reply({...event,bytes:[1],eof:false,...change}),false); 10 assert.equal(e.counts.pending,1);assert(e.reply({...event,bytes:[1,2],eof:false}));assert.deepEqual(await pending,{kind:'read',bytes:[1,2],eof:false}); 11 assert.equal(e.reply({...event,bytes:[1],eof:false}),false);assert.deepEqual(e.counts,{pending:0,queued:0}); 12 }); 13 test('cancellation before dispatch has no host effect; delivered cancellation waits for acknowledgement',async()=>{ 14 const e=new Events('1'),a=new AbortController(),p=e.read(4,a.signal);a.abort();assert.deepEqual(e.take(),[]);assert.deepEqual(await p,{kind:'cancelled'}); 15 const b=new AbortController(),q=e.read(4,b.signal),event=e.take()[0];let settled=false;q.then(()=>{settled=true;}); 16 b.abort();b.abort();await Promise.resolve();assert(!settled);assert.deepEqual(e.take(),[{run:'1',id:event.id,kind:'cancel',operation:'read'}]); 17 assert(e.reply({...event,kind:'cancelled'}));assert.deepEqual(await q,{kind:'cancelled'});assert.deepEqual(e.counts,{pending:0,queued:0}); 18 }); 19 test('normal completion racing abort acknowledges cleanup but discards its data',async()=>{ 20 const e=new Events('1'),c=new AbortController(),p=e.write('output',[1,2],c.signal),event=e.take()[0];c.abort(); 21 assert(e.reply({...event,kind:'write',count:1}));assert.deepEqual(await p,{kind:'cancelled'});assert.deepEqual(e.take(),[]); 22 }); 23 test('output snapshots cannot mutate validation; partial progress is explicit',async()=>{ 24 const e=new Events('1'),bytes=[1,2],c=new AbortController(),p=e.write('error',bytes,c.signal);bytes.push(3); 25 const event=e.take()[0];event.bytes.push(4);event.kind='read'; 26 assert(!e.reply({run:'1',id:1,kind:'write',count:3}));assert(e.reply({run:'1',id:1,kind:'write',count:1})); 27 assert.deepEqual(await p,{kind:'write',count:1}); 28 }); 29 test('identity exhaustion cannot prevent cancellation or retirement; repeated operations retain no history',async()=>{ 30 const e=new Events('1',1),c=new AbortController(),p=e.read(1,c.signal),event=e.take()[0]; 31 assert.throws(()=>e.read(1,c.signal),/exhausted/);c.abort();assert(e.reply({...event,kind:'cancelled'}));await p; 32 const many=new Events('2');for(let i=0;i<1000;i++){const pending=many.read(1,new AbortController().signal),ev=many.take()[0];assert(many.reply({...ev,bytes:[],eof:true}));await pending;assert.deepEqual(many.counts,{pending:0,queued:0});} 33 });