"""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()