51 lines
4.0 KiB
JavaScript
51 lines
4.0 KiB
JavaScript
const test=require('node:test'),assert=require('node:assert/strict'),m=require('./web/device-model.js');
|
|
const sites=[{id:'floor',name:'一楼'},{id:'bed',name:'卧室',parentId:'floor'},{id:'office',name:'办公室'}];
|
|
const devices=[{id:'lamp',name:'卧室台灯',deviceType:'灯',siteId:'bed',managerName:'乙',ownerName:'甲',tags:['照明','常用']},{id:'desk',name:'办公灯',deviceType:'灯',siteId:'office',managerName:'甲',ownerName:'乙',tags:['照明']},{id:'phone',name:'手机',deviceType:'手机',siteId:'bed',managerName:'乙',ownerName:'乙',tags:[]}];
|
|
test('type then area and area then type reuse the same device identities',()=>{
|
|
const a=m.groups(devices,['type','space'],sites),b=m.groups(devices,['space','type'],sites);
|
|
assert.deepEqual(a.find(g=>g.items.some(x=>x.id==='lamp')).labels,['灯','一楼','卧室']);
|
|
assert.deepEqual(b.find(g=>g.items.some(x=>x.id==='lamp')).labels,['一楼','卧室','灯']);
|
|
assert.equal(a.flatMap(g=>g.items).length,3);assert.equal(b.flatMap(g=>g.items).length,3);
|
|
});
|
|
test('responsible person differs from owner and supports multitag grouping',()=>{
|
|
assert.equal(m.groups(devices,['manager'],sites).find(g=>g.labels[0]==='乙').items.length,2);
|
|
assert.equal(m.groups(devices,['owner'],sites).find(g=>g.labels[0]==='乙').items.length,2);
|
|
assert.equal(m.groups(devices,['tag'],sites).find(g=>g.labels[0]==='照明').items.length,2);
|
|
assert.equal(m.groups(devices,['tag'],sites).find(g=>g.labels[0]==='未标记').items[0].id,'phone');
|
|
});
|
|
test('spaces have no fixed depth and traversal handles corrupt cycles safely',()=>{
|
|
const deep=Array.from({length:2500},(_,i)=>({id:String(i),name:'Area '+i,parentId:i?String(i-1):''}));
|
|
assert.equal(m.path(deep,'2499').length,2500);assert.equal(m.descendants(deep,'0').size,2500);
|
|
assert.equal(m.path([{id:'a',parentId:'b'},{id:'b',parentId:'a'}],'a').length,2);
|
|
assert.equal(m.descendants([{id:'a',parentId:'b'},{id:'b',parentId:'a'}],'a').size,2);
|
|
});
|
|
test('identical area names remain separate groups by stable identifiers',()=>{
|
|
const areas=[{id:'a',name:'卧室'},{id:'b',name:'卧室'}];
|
|
assert.equal(m.groups([{siteId:'a',id:1},{siteId:'b',id:2}],['space'],areas).length,2);
|
|
});
|
|
test('camera recorder and general device records appear in one catalog without mutation',()=>{
|
|
const state={assets:[{id:'a',name:'Camera'}],recorders:[{id:'b',name:'Recorder'}],devices:[{id:'c',deviceType:'冰箱'}]},before=JSON.stringify(state);
|
|
assert.deepEqual(m.catalog(state).map(d=>d.deviceType),['摄像机','录像机','冰箱']);assert.equal(JSON.stringify(state),before);
|
|
assert.equal(m.groups(devices,[],sites).length,1);
|
|
});
|
|
|
|
test('same-name people with different references form separate responsibility groups',()=>{
|
|
const rows=[{id:'a',managerName:'张伟',managerRef:'user:one'},{id:'b',managerName:'张伟',managerRef:'user:two'}];
|
|
assert.equal(m.groups(rows,['manager'],[]).length,2);
|
|
});
|
|
|
|
test('network topology preserves explicit uplinks and remains usable with missing or cyclic parents',()=>{
|
|
const data=[{id:'r'},{id:'c',uplinkId:'r'},{id:'p',uplinkId:'hidden'}];
|
|
const tree=m.topology(data);assert.deepEqual(tree.children.get('r').map(x=>x.id),['c']);assert.equal(tree.parents.get('p'),'');
|
|
assert.equal(m.topology([{id:'a',uplinkId:'b'},{id:'b',uplinkId:'a'}]).children.get('').length,2);
|
|
});
|
|
test('network summary distinguishes recorder stream source from physical camera address',()=>{
|
|
const n=m.network({id:'a',managementHost:'192.168.8.160',networkAccess:'tailscale'},{cameras:[{assetId:'a',host:'192.168.3.135',sourceKind:'recorder',recorderId:'r',archiveSource:'recorder',archiveRecorderId:'r'}]});
|
|
assert.deepEqual(n.hosts,['192.168.8.160']);assert.deepEqual(n.via,['r']);assert.deepEqual(n.archiveVia,['r']);assert.equal(n.access,'tailscale');
|
|
});
|
|
|
|
test('configured camera address overrides an old inventory address and is searchable',()=>{
|
|
const rows=m.catalog({assets:[{id:'a',managementHost:'192.168.1.20'}],cameras:[{assetId:'a',host:'192.168.1.30',sourceKind:'direct'}]});
|
|
assert.deepEqual(rows[0].networkHosts,['192.168.1.30']);assert.equal(m.matches(rows[0],'192.168.1.30',[]),true);
|
|
});
|