89 lines
6.3 KiB
Python
89 lines
6.3 KiB
Python
|
|
"""Responsibility references and personal household layout regressions."""
|
||
|
|
import unittest
|
||
|
|
from test_app import app
|
||
|
|
import test_households as fixture
|
||
|
|
|
||
|
|
|
||
|
|
class InventoryTests(unittest.TestCase):
|
||
|
|
setUp = fixture.HouseholdTests.setUp
|
||
|
|
stop_server = fixture.HouseholdTests.stop_server
|
||
|
|
request = fixture.HouseholdTests.request
|
||
|
|
|
||
|
|
def test_candidates_are_scoped_minimal_and_support_current_superadmin(self):
|
||
|
|
options = self.request('/api/state')[1]['responsibilityOptions']
|
||
|
|
refs = {p['ref'] for p in options}
|
||
|
|
self.assertIn('user:'+self.members[self.aid]['id'], refs)
|
||
|
|
self.assertNotIn('user:'+self.members[self.bid]['id'], refs)
|
||
|
|
self.assertTrue(all(set(p)=={'ref','name','label','kind'} for p in options))
|
||
|
|
root_options = app.INVENTORY.candidates(self.roots[self.bid])
|
||
|
|
self.assertIn('user:'+self.root['id'], {p['ref'] for p in root_options})
|
||
|
|
self.assertNotIn('responsibilityOptions', self.request('/api/state', self.members[self.aid])[1])
|
||
|
|
|
||
|
|
def test_reference_names_are_authoritative_and_cannot_cross_households(self):
|
||
|
|
member = self.members[self.aid]
|
||
|
|
data = dict(self.assets[self.aid],ownerRef='user:'+member['id'],ownerName='spoofed')
|
||
|
|
code, saved = self.request('/api/assets',data=data)
|
||
|
|
self.assertEqual(code,200);self.assertEqual(saved['ownerName'],member['name'])
|
||
|
|
data['managerRef']='user:'+self.members[self.bid]['id']
|
||
|
|
self.assertEqual(self.request('/api/assets',data=data)[0],400)
|
||
|
|
app.ACCOUNTS.save(dict(app.get_object('users',member['id']),name='更新名字'),self.roots[self.aid])
|
||
|
|
shown=self.request('/api/state')[1]['assets'][0]
|
||
|
|
self.assertEqual(shown['ownerName'],'更新名字');self.assertEqual(shown['ownerRef'],saved['ownerRef'])
|
||
|
|
self.assertEqual(self.request('/api/assets',data=dict(saved,ownerRef='',ownerName='共有单位'))[1]['ownerName'],'共有单位')
|
||
|
|
|
||
|
|
def test_archived_or_disabled_links_are_preserved_but_not_newly_assigned(self):
|
||
|
|
member=self.members[self.aid]
|
||
|
|
saved=app.INVENTORY.save(dict(name='测试灯',deviceType='灯',managerRef='user:'+member['id']),self.owner)
|
||
|
|
app.ACCOUNTS.save(dict(app.get_object('users',member['id']),disabled=True),self.roots[self.aid])
|
||
|
|
self.assertEqual(app.INVENTORY.save(saved,self.owner)['managerRef'],saved['managerRef'])
|
||
|
|
with self.assertRaises(app.Problem):app.INVENTORY.save(dict(name='新灯',deviceType='灯',managerRef=saved['managerRef']),self.owner)
|
||
|
|
|
||
|
|
def test_people_and_all_device_types_share_references_without_granting_access(self):
|
||
|
|
person=dict(id='e'*16,name='家庭成员',familyId=self.aid,archived=False)
|
||
|
|
app.save_object('people',person)
|
||
|
|
ref='person:'+person['id'];self.assertIn(ref,{p['ref'] for p in app.INVENTORY.candidates(self.owner)})
|
||
|
|
before=app.objects('users')
|
||
|
|
rows=[app.save_asset(dict(self.assets[self.aid],managerRef=ref),self.owner),
|
||
|
|
app.save_recorder(dict(name='录像机',siteId=self.sites[self.aid]['id'],host='192.168.9.50',managerRef=ref),self.owner),
|
||
|
|
app.INVENTORY.save(dict(name='灯',deviceType='灯',managerRef=ref),self.owner)]
|
||
|
|
self.assertTrue(all(r['managerName']=='家庭成员' for r in rows));self.assertEqual(before,app.objects('users'))
|
||
|
|
|
||
|
|
def test_layout_persists_per_account_and_rejects_conflicts_and_cross_scope(self):
|
||
|
|
data=dict(revision=0,columns=3,rows=2,groupCity=False,order=[self.bid,self.aid])
|
||
|
|
code,saved=self.request('/api/households/layout',self.root,data)
|
||
|
|
self.assertEqual(code,200);self.assertEqual(saved['order'],data['order'])
|
||
|
|
self.assertEqual(self.request('/api/state',self.root)[1]['householdLayout']['columns'],3)
|
||
|
|
self.assertEqual(app.HOUSEHOLDS.layout(self.owner)['columns'],2)
|
||
|
|
self.assertEqual(self.request('/api/households/layout',self.root,data)[0],409)
|
||
|
|
self.assertEqual(self.request('/api/households/layout',self.owner,data)[0],400)
|
||
|
|
for bad in [dict(data,revision=1,columns=0),dict(data,revision=1,rows=True),dict(data,revision=1,order=[self.aid,self.aid]),dict(data,revision=1,userId=self.owner['id'])]:
|
||
|
|
self.assertEqual(self.request('/api/households/layout',self.root,bad)[0],400)
|
||
|
|
member=self.members[self.aid]
|
||
|
|
self.assertEqual(self.request('/api/households/layout',member,dict(data,order=[self.aid]))[0],200)
|
||
|
|
|
||
|
|
def test_topology_references_and_network_fields_validate_without_opening_access(self):
|
||
|
|
gateway=app.INVENTORY.save(dict(name='网关',deviceType='路由器',managementHost='192.168.8.1',tailscaleHost='gateway.example.ts.net',networkCidr='192.168.8.0/24',networkAccess='tailscale'),self.owner)
|
||
|
|
camera=app.save_asset(dict(self.assets[self.aid],uplinkId=gateway['id'],connectionType='wired'),self.owner)
|
||
|
|
with self.assertRaises(app.Problem):app.INVENTORY.save(dict(gateway,uplinkId=camera['id']),self.owner)
|
||
|
|
with self.assertRaises(app.Problem):app.INVENTORY.save(dict(gateway,uplinkId=gateway['id']),self.owner)
|
||
|
|
with self.assertRaises(app.Problem):app.save_asset(dict(camera,uplinkId=self.assets[self.bid]['id']),self.owner)
|
||
|
|
for bad in [dict(networkCidr='192.168.8.160/24'),dict(managementHost='http://user:secret@example.com'),dict(networkAccess='all'),dict(connectionType='anything')]:
|
||
|
|
with self.assertRaises(app.Problem):app.INVENTORY.save(dict(gateway,**bad),self.owner)
|
||
|
|
self.assertEqual(self.request('/api/state',self.other)[1]['devices'],[])
|
||
|
|
self.assertEqual(app.INVENTORY.save(dict(gateway,networkAccess='public',managementHost='example.org'),self.owner)['managementHost'],'example.org')
|
||
|
|
|
||
|
|
def test_global_topology_summaries_count_only_authorized_devices(self):
|
||
|
|
app.INVENTORY.save(dict(name='未授权区域的设备',deviceType='路由器',networkAccess='tailscale'),self.owner)
|
||
|
|
own=self.request('/api/state',self.members[self.aid])[1]['households']
|
||
|
|
self.assertEqual(len(own),1)
|
||
|
|
self.assertEqual(own[0]['deviceCount'],1)
|
||
|
|
self.assertNotIn('tailscale',own[0]['networkAccesses'])
|
||
|
|
managed=self.request('/api/state',self.owner)[1]['households'][0]
|
||
|
|
self.assertEqual(managed['deviceCount'],2)
|
||
|
|
self.assertIn('tailscale',managed['networkAccesses'])
|
||
|
|
overall=self.request('/api/state',self.root)[1]['households']
|
||
|
|
self.assertEqual({h['id']:h['deviceCount'] for h in overall},{self.aid:2,self.bid:1})
|
||
|
|
|
||
|
|
|
||
|
|
if __name__=='__main__':unittest.main()
|