| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- import assert from 'node:assert/strict'
- import { readFile } from 'node:fs/promises'
- import { register } from 'node:module'
- register('./t32-adapter-io-loader.mjs',import.meta.url)
- const { createCesiumPipeModels }=await import('../../../src/modules/cockpit/services/cesiumPipeModels.js')
- globalThis.t32Models=[]
- globalThis.t32TerrainFails=false
- globalThis.window={location:{href:'http://localhost:8002/cockpit/',origin:'http://localhost:8002'}}
- const originalFetch=globalThis.fetch
- let missing=false
- const requested=[]
- globalThis.fetch=async(input,options)=>{
- const url=String(input)
- if(url.startsWith('blob:')) return originalFetch(input,options)
- requested.push(url)
- if(missing) return new Response('missing',{status:404})
- const name=url.split('/').at(-1)
- const json=await readFile(new URL('../../../public/cockpit/models/pipes/'+name,import.meta.url),'utf8')
- return new Response(json,{status:200})
- }
- const source={entities:{values:[]}}
- const added=[],removed=[]
- const viewer={terrainProvider:{},isDestroyed:()=>false,scene:{requestRender(){},primitives:{
- add(model){added.push(model)},remove(model){removed.push(model);model.destroy()},
- }}}
- const states=[]
- let adapter=createCesiumPipeModels(viewer,{source,onChange:state=>states.push(state),base:'/'})
- const pipe=(code,lon)=>({code,industry:'GAS',diameter:400,positions:[[lon,28.44],[lon+.00004,28.44]]})
- const network={pipes:[pipe('east',110.391),pipe('west',110.411)],components:[]}
- source.entities.values=network.pipes.map(row=>({id:'pipe:'+row.code,show:true}))
- await adapter.sync(network)
- assert.equal(added.length,2)
- assert.equal(states.at(-1).pending,2)
- assert.ok(source.entities.values.every(e=>e.show),'load promise does not remove fallback')
- for(const model of added) model.readyEvent.raiseEvent()
- assert.ok(source.entities.values.every(e=>!e.show),'ready switches complete pipes to models')
- assert.equal(requested.filter(url=>url.endsWith('spline.gltf')).length,1)
- assert.equal(added[0].gltf.buffers[0].uri,added[1].gltf.buffers[0].uri)
- assert.equal(added[0].gltf.buffers[0].uri,'http://localhost:8002/cockpit/models/pipes/spline.bin')
- await adapter.sync({...network,pipes:network.pipes.map(row=>({...row,name:'changed metadata'}))})
- assert.equal(added.length,2,'metadata-only change does not rebuild GPU batches')
- await adapter.sync({...network,pipes:[{...network.pipes[0],diameter:600},network.pipes[1]]})
- assert.equal(added.length,3,'only changed tile recreated')
- assert.equal(removed.length,1)
- assert.equal(source.entities.values[0].show,true)
- assert.equal(source.entities.values[1].show,false)
- added[2].readyEvent.raiseEvent()
- added[2].errorEvent.raiseEvent(new Error('late buffer failure'))
- assert.equal(source.entities.values[0].show,true)
- assert.equal(states.at(-1).failed,1)
- adapter.destroy()
- assert.ok(added.every(model=>model.destroyed))
- console.log('PASS real adapter readiness, shared URL, stable metadata, selective update, late error and cleanup')
- const terrainStates=[]
- globalThis.t32TerrainFails=true
- source.entities.values=[{id:'pipe:terrain',show:true}]
- adapter=createCesiumPipeModels(viewer,{source,onChange:state=>terrainStates.push(state),base:'/'})
- await adapter.sync({pipes:[pipe('terrain',110.431)],components:[]})
- assert.equal(terrainStates.at(-1).terrainFailed,true)
- assert.equal(terrainStates.at(-1).fallback,1)
- assert.equal(source.entities.values[0].show,true)
- adapter.destroy()
- console.log('PASS terrain failure preserves fallback and publishes reason')
- globalThis.t32TerrainFails=false
- missing=true
- const assetStates=[]
- source.entities.values=[{id:'component:404',show:true}]
- adapter=createCesiumPipeModels(viewer,{source,onChange:state=>assetStates.push(state),base:'missing-base/'})
- await adapter.sync({pipes:[],components:[{code:'404',kind:'valve',industry:'GAS',position:[110.431,28.44]}]})
- assert.equal(assetStates.at(-1).failed,1)
- assert.equal(assetStates.at(-1).fallback,1)
- assert.equal(source.entities.values[0].show,true)
- adapter.destroy()
- globalThis.fetch=originalFetch
- console.log('PASS template 404 reaches real adapter failure path and keeps symbol')
|