| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- import assert from 'node:assert/strict'
- import { createPipeModelBatches } from '../../../src/modules/cockpit/services/pipeModelBatches.js'
- const pending = [], removed = [], changes = []
- const layer = createPipeModelBatches({
- load: async (group, events) => { const model = { key: group.key }; pending.push({ group, events, model }); return model },
- remove: (model) => removed.push(model.key),
- onChange: (state) => changes.push(state),
- })
- const group = { key: 'tile:valve', instances: [{ id: 'component:v' }] }
- await layer.sync([group])
- assert.deepEqual(layer.state().covered, [], 'await load is NOT model ready')
- pending[0].events.ready()
- assert.deepEqual(layer.state().covered, ['component:v'])
- await layer.sync([structuredClone(group)])
- assert.equal(pending.length, 1, 'unchanged input must not reload model')
- pending[0].events.error(new Error('late buffer error'))
- assert.deepEqual(layer.state().covered, [], 'late error restores fallback')
- assert.deepEqual(removed, ['tile:valve'])
- assert.equal(layer.state().failed, 1)
- await layer.sync([])
- assert.equal(layer.state().failed, 0)
- console.log('PASS readiness, immutable diff, late resource failure and clear')
- let finish
- const staleRemoved = []
- const stale = createPipeModelBatches({ load: async (_, events) => {
- await new Promise((resolve) => { finish = resolve })
- events.ready()
- return { id: 'stale' }
- }, remove: (model) => staleRemoved.push(model.id) })
- const waiting = stale.sync([group])
- await stale.clear()
- finish()
- await waiting
- assert.deepEqual(stale.state().covered, [])
- assert.deepEqual(staleRemoved, ['stale'])
- const splitEvents = []
- const split = createPipeModelBatches({ load: async (g, e) => { splitEvents.push(e); return {} }, remove: () => {} })
- await split.sync([{ key:'a', instances:[{id:'pipe:p'}] },{key:'b', instances:[{id:'pipe:p'}]}])
- splitEvents[0].ready()
- assert.deepEqual(split.state().covered, [], 'do not hide fallback until ALL path spans are ready')
- splitEvents[1].ready()
- assert.deepEqual(split.state().covered, ['pipe:p'])
- console.log('PASS stale completions cannot resurrect, split path waits for all spans')
- let clock = 0
- const attempts = []
- const retry = createPipeModelBatches({ now: () => clock, retryMs: 100, load: async (_, events) => {
- attempts.push(events)
- return {}
- }, remove: () => {} })
- await retry.sync([group])
- attempts[0].error()
- await retry.sync([group])
- assert.equal(attempts.length, 1, 'retry must respect cooldown')
- clock = 101
- await retry.sync([group])
- assert.equal(attempts.length, 2, 'same input recovers after temporary failure')
- attempts[1].ready()
- assert.deepEqual(retry.state().covered, ['component:v'])
- const stable = {key:'stable', instances:[{id:'component:s'}]}
- await retry.sync([group, stable])
- assert.equal(attempts.length, 3, 'adding one batch leaves ready batch intact')
- console.log('PASS failed batch retries with cooldown, incremental additions retain ready batches')
|