def test_project_validation(self): master = { 'resources': { 'projects': {}, 'groups': {}, 'acls': { 'a1': { 'file': 'fake', } }, 'repos': { 'r1': { 'name': 'sf/r1', 'description': 'This is a GIT repo', 'acl': 'a1' } } } } new = { 'resources': { 'projects': { 'p1': { 'name': 'p1', 'description': 'An awesome project', 'source-repositories': ['r1'], }, }, 'groups': {}, 'repos': { 'r1': { 'name': 'sf/r1', 'description': 'This is a GIT repo', 'acl': 'a1' } }, 'acls': { 'a1': { 'file': 'fake', } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.gitacls.' 'ACLOps.extra_validations') as xv, \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv2: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn('Resource [type: projects, ID: p1] is going to ' 'be created.', logs) self.assertEqual(len(logs), 1) new = { 'resources': { 'projects': { 'p1': { 'name': 'p1', 'description': 'An awesome project', 'source-repositories': ['r1', 'r2'], }, }, 'groups': {}, 'repos': { 'r1': { 'name': 'sf/r1', 'description': 'This is a GIT repo', 'acl': 'a1' } }, 'acls': { 'a1': { 'file': 'fake', } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.gitacls.' 'ACLOps.extra_validations') as xv, \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv2: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) # Project depends on an unknown r2 resource self.assertFalse(valid) self.assertIn('Resource [type: projects, ID: p1] depends on ' 'an unknown resource [type: repos, ID: r2]', logs) self.assertEqual(len(logs), 1) master = { 'resources': { 'projects': { 'p1': { 'name': 'p1', 'description': 'An awesome project', 'source-repositories': ['r1'], }, }, 'groups': {}, 'acls': { 'a1': { 'file': 'fake', } }, 'repos': { 'r1': { 'name': 'sf/r1', 'description': 'This is a GIT repo', 'acl': 'a1' } } } } new = { 'resources': { 'projects': { 'p1': { 'name': 'p1', 'description': 'An awesome project', 'source-repositories': ['r1'], }, }, 'repos': { 'r1': { 'name': 'sf/r1', 'description': 'This is a GIT repo', 'acl': 'a1' } }, 'acls': { 'a1': { 'file': 'fake', 'groups': ['g1'], } }, 'groups': { 'g1': { 'name': 'sf/g1', 'members': [], }, } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.gitacls.' 'ACLOps.extra_validations') as xv, \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv2: l.return_value = (master, new) xv.return_value = [] xv2.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn('Resource [type: acls, ID: a1] is going ' 'to be updated.', logs) self.assertIn('Resource [type: projects, ID: p1] need a ' 'refresh as at least one of its dependencies ' 'has been updated', logs) self.assertIn('Resource [type: groups, ID: g1] is ' 'going to be created.', logs) self.assertIn('Resource [type: repos, ID: r1] need a ' 'refresh as at least one of its dependencies ' 'has been updated', logs) self.assertEqual(len(logs), 4)
def test_gitrepo_validation(self): master = { 'resources': { 'acls': { 'a1': { 'file': 'fake', } }, 'repos': {}, } } new = { 'resources': { 'repos': { 'sf/r1': { 'description': 'This is a GIT repo', 'acl': 'a1' } }, 'acls': { 'a1': { 'file': 'fake', } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.gitacls.' 'ACLOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn('Resource [type: repos, ID: sf/r1] is going to ' 'be created.', logs) self.assertEqual(len(logs), 1) master = { 'resources': { 'repos': { 'sf/r1': { 'description': 'This is a GIT repo', 'acl': 'a1' } }, 'acls': { 'a1': { 'file': 'fake', } }, } } new = { 'resources': { 'repos': { 'sf/r1': { 'description': 'This is a GIT repo', 'acl': 'a1' } }, 'acls': { 'a1': { 'file': 'fake2', } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.gitacls.' 'ACLOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn('Resource [type: acls, ID: a1] is going to ' 'be updated.', logs) self.assertIn('Resource [type: repos, ID: sf/r1] need a refresh ' 'as at least one of its dependencies has been ' 'updated', logs) self.assertEqual(len(logs), 2) master = { 'resources': { 'repos': { 'sf/r1': { 'description': 'This is a GIT repo', 'acl': 'a1' } }, 'acls': { 'a1': { 'file': 'fake', } }, } } new = { 'resources': { 'repos': { 'sf/r1': { 'description': 'This is a GIT repo', 'acl': 'a1' } }, 'acls': {}, } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.gitacls.' 'ACLOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') # GIT repository relie on an unknown ACL valid, logs = eng.validate(None, None, None, None) self.assertFalse(valid) self.assertIn('Resource [type: repos, ID: sf/r1] depends on ' 'an unknown resource [type: acls, ID: a1]', logs) self.assertEqual(len(logs), 1)
def test_group_validation(self): master = { 'resources': { 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } new = { 'resources': { 'groups': { 'sf/g1': { 'description': 'This is a cool group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn( 'Resource [type: groups, ID: sf/g1] is going to be updated.', logs) self.assertEqual(len(logs), 1) master = { 'resources': { 'groups': {} } } new = { 'resources': { 'groups': { 'sf/g1': { 'description': 'This is a cool group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn( 'Resource [type: groups, ID: sf/g1] is going to be created.', logs) self.assertEqual(len(logs), 1) master = { 'resources': { 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } new = { 'resources': { 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', ] } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn( 'Resource [type: groups, ID: sf/g1] is going to be updated.', logs) self.assertEqual(len(logs), 1) master = { 'resources': { 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } new = { 'resources': { 'groups': { 'sf/g2': { 'description': 'This is a group', 'members': [ '*****@*****.**', ] } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn( 'Resource [type: groups, ID: sf/g1] is going to be deleted.', logs) self.assertIn( 'Resource [type: groups, ID: sf/g2] is going to be created.', logs) self.assertEqual(len(logs), 2) master = { 'resources': { 'groups': {}, } } new = { 'resources': { 'groups': { 'sf/g1': { 'description': 'This is a cool group', 'members': [ '*****@*****.**' ] } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = ['Check group members [[email protected] ' 'does not exists]: err API unable to find ' 'the member'] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) # The member is not known self.assertFalse(valid) self.assertIn( "Check group members [[email protected] does not exists]: " "err API unable to find the member", logs) self.assertIn( "Resource [type: groups, ID: sf/g1] extra validations failed", logs) self.assertEqual(len(logs), 2) master = { 'resources': { 'groups': {} } } new = { 'resources': { 'groups': { 'Administrators': { 'description': 'This is the Admin group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.GroupOps.' 'check_account_members') as cam: l.return_value = (master, new) cam.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertFalse(valid) self.assertIn( 'Check group name [Administrators in not managed ' 'by this API]', logs) self.assertIn( 'Resource [type: groups, ID: Administrators] extra ' 'validations failed', logs) self.assertEqual(len(logs), 2)
def test_acls_validation(self): master = { 'resources': { 'acls': {} } } new = { 'resources': { 'acls': { 'a1': { 'file': "this is a\nfake acls", 'groups': ['g1'], } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.gitacls.' 'ACLOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) # The group on which the ACLs depends on is missing self.assertFalse(valid) self.assertIn( 'Resource [type: acls, ID: a1] depends on an unknown ' 'resource [type: groups, ID: g1]', logs) self.assertEqual(len(logs), 1) master = { 'resources': { 'acls': {}, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } new = { 'resources': { 'acls': { 'a1': { 'file': "this is a\nfake acls", 'groups': ['sf/g1'], } }, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.gitacls.' 'ACLOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn( 'Resource [type: acls, ID: a1] is going to be created.', logs) self.assertEqual(len(logs), 1) master = { 'resources': { 'acls': { 'a1': { 'file': "this is a\nfake acls", 'groups': ['g1'], } }, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } new = { 'resources': { 'acls': {}, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.gitacls.' 'ACLOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn( 'Resource [type: acls, ID: a1] is going to be deleted.', logs) self.assertEqual(len(logs), 1) master = { 'resources': { 'acls': { 'a1': { 'file': "this is a\nfake acls", 'groups': ['sf/g1'], } }, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] } } } } new = { 'resources': { 'acls': { 'a1': { 'file': "this is a\nfake acls", 'groups': ['sf/g1'], } }, 'groups': {}, } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) # The group on which the ACLs depends on is missing because # it has been removed between master and new self.assertFalse(valid) self.assertIn( 'Resource [type: acls, ID: a1] depends on an unknown ' 'resource [type: groups, ID: sf/g1]', logs) self.assertEqual(len(logs), 1) master = { 'resources': { 'acls': {}, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] }, } } } new = { 'resources': { 'acls': { 'a1': { 'file': """[project] description = A description [access "refs/*"] read = group sf/g1 owner = group sf/g1 [access "refs/heads/*"] label-Code-Review = -2..+2 group sf/g1 label-Verified = -2..+2 group sf/g1 label-Workflow = -1..+1 group sf/g1 submit = group sf/g1 read = group sf/g1 """, 'groups': ['sf/g1'], } }, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] }, } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) self.assertTrue(valid) self.assertIn( 'Resource [type: acls, ID: a1] is going to be created.', logs) self.assertEqual(len(logs), 1) master = { 'resources': { 'acls': {}, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] }, } } } new = { 'resources': { 'acls': { 'a1': { 'file': """This ACL is wrong ! This string won't be accepted by Gerrit ! """, 'groups': ['sf/g1'], } }, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] }, } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) # The ACLs is not a valid Git Style config file self.assertFalse(valid) self.assertTrue(logs[0].startswith( "File contains no section headers.")) self.assertIn( 'Resource [type: acls, ID: a1] extra validations failed', logs) self.assertEqual(len(logs), 2) master = { 'resources': { 'acls': {}, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] }, } } } new = { 'resources': { 'acls': { 'a1': { 'file': """[project] description = A description [access "refs/*"] read = group sf/g1 owner = group sf/g1 [access "refs/heads/*"] label-Code-Review = -2..+2 group sf/g1 label-Verified = -2..+2 group sf/g1 label-Workflow = -1..+1 group sf/g1 submit = group sf/g2 read = group sf/g1 """, 'groups': ['sf/g1'], } }, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] }, } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) # sf/g2 is not a known group self.assertFalse(valid) self.assertIn('ACLs file section (access "refs/heads/*"), key ' '(submit) relies on an unknown group name: sf/g2', logs) self.assertIn('Resource [type: acls, ID: a1] extra validations ' 'failed', logs) self.assertEqual(len(logs), 2) new = { 'resources': { 'acls': { 'a1': { 'file': """[project] description = A description [access "refs/*"] read = group sf/g1 owner = group sf/g1 [access "refs/heads/*"] label-Code-Review = -2..+2 group sf/g1 label-Verified = -2..+2 group sf/g1 label-Workflow = -1..+1 group sf/g1 submit = group sf/g2 read = group sf/g1 """, 'groups': ['sf/g1', 'others/g2'], } }, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] }, 'others/g2': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] }, } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None) # others/g2 is not a known group self.assertFalse(valid) self.assertIn('ACLs file section (access "refs/heads/*"), key ' '(submit) relies on an unknown group name: sf/g2', logs) self.assertIn('Resource [type: acls, ID: a1] extra validations ' 'failed', logs) new = { 'resources': { 'acls': { 'a1': { 'file': """[project] description = A description [access "refs/*"] read = group sf/g1 owner = group sf/g1 [access "refs/heads/*"] label-Code-Review = -2..+2 group sf/g1 label-Verified = -2..+2 group sf/g1 label-Workflow = -1..+1 group sf/g1 submit = group g2 read = group sf/g1 """, 'groups': ['sf/g1', 'g2'], } }, 'groups': { 'sf/g1': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] }, 'g2': { 'description': 'This is a group', 'members': [ '*****@*****.**', '*****@*****.**', ] }, } } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine._load_resources_data') as l, \ patch('os.path.isdir'), \ patch('os.mkdir'), \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.extra_validations') as xv: l.return_value = (master, new) xv.return_value = [] eng = engine.SFResourceBackendEngine('fake', 'resources') valid, logs = eng.validate(None, None, None, None)
def test_get_missing_resources(self): eng = engine.SFResourceBackendEngine(None, None) current_resources = { 'resources': { 'projects': { 'p1': { 'description': 'An awesome project', 'source-repositories': ['r1'], }, }, 'groups': { 'g1': { 'members': ['*****@*****.**'], }, 'g2': { 'members': ['*****@*****.**'], }, }, 'repos': { 'sf/r1': { 'acl': 'a1', }, 'sf/r2': { 'acl': 'a1', }, }, 'acls': { 'a1': { 'file': 'fake', 'groups': [], } } } } gr_reality = { 'repos': { 'sf/r1': { 'acl': 'hash77', }, 'sf/r2': { 'acl': 'hash77', }, 'sf/r3': { 'acl': 'hash77', }, }, 'acls': { 'hash77': { 'file': 'fake', 'groups': [], }, 'hash78': { 'file': 'fake2', 'groups': [], }, }, } g_reality = { 'groups': { 'g3': { 'members': ['*****@*****.**'], }, }, } expected = { 'resources': { 'groups': { 'g3': { 'members': ['*****@*****.**'] }, }, 'repos': { 'sf/r3': { 'acl': 'a1', } }, 'acls': { 'hash78': { 'groups': [], 'file': 'fake2', } }, } } with patch('managesf.model.yamlbkd.engine.' 'SFResourceBackendEngine.get') as g, \ patch('managesf.model.yamlbkd.resources.gitrepository.' 'GitRepositoryOps.get_all') as gar, \ patch('managesf.model.yamlbkd.resources.group.' 'GroupOps.get_all') as gag: gar.return_value = ([], gr_reality) gag.return_value = ([], g_reality) g.return_value = current_resources logs, tree = eng.get_missing_resources(None, None) self.assertListEqual(logs, []) self.assertDictEqual(tree, expected)