class GroupCacherTest(StoreTestCase): @inlineCallbacks def setUp(self): yield super(GroupCacherTest, self).setUp() self.groupCacher = GroupCacher(self.directory) @inlineCallbacks def test_multipleCalls(self): """ Ensure multiple calls to groupByUID() don't raise an exception """ store = self.storeUnderTest() txn = store.newTransaction() record = yield self.directory.recordWithUID(u"__top_group_1__") yield txn.groupByUID(record.uid) yield txn.groupByUID(record.uid) yield txn.commit() @inlineCallbacks def test_refreshGroup(self): """ Verify refreshGroup() adds a group to the Groups table with the expected membership hash value and members """ store = self.storeUnderTest() txn = store.newTransaction() record = yield self.directory.recordWithUID(u"__top_group_1__") yield self.groupCacher.refreshGroup(txn, record.uid) group = (yield txn.groupByUID(record.uid)) self.assertEquals(group.extant, True) self.assertEquals(group.membershipHash, "553eb54e3bbb26582198ee04541dbee4") group = yield txn.groupByID(group.groupID) self.assertEquals(group.groupUID, record.uid) self.assertEquals(group.name, u"Top Group 1") self.assertEquals(group.membershipHash, "553eb54e3bbb26582198ee04541dbee4") self.assertEquals(group.extant, True) members = (yield txn.groupMemberUIDs(group.groupID)) self.assertEquals( set([ u'__cdaboo1__', u'__glyph1__', u'__sagen1__', u'__wsanchez1__' ]), members) records = (yield self.groupCacher.cachedMembers(txn, group.groupID)) self.assertEquals( set([r.uid for r in records]), set([ u'__cdaboo1__', u'__glyph1__', u'__sagen1__', u'__wsanchez1__' ])) # sagen is in the top group, even though it's actually one level # removed record = yield self.directory.recordWithUID(u"__sagen1__") groups = (yield self.groupCacher.cachedGroupsFor(txn, record.uid)) self.assertEquals(set([u"__top_group_1__"]), groups) yield txn.commit() @inlineCallbacks def test_synchronizeMembers(self): """ After loading in a group via refreshGroup(), pass new member sets to synchronizeMembers() and verify members are added and removed as expected """ store = self.storeUnderTest() txn = store.newTransaction() # Refresh the group so it's assigned a group_id uid = u"__top_group_1__" yield self.groupCacher.refreshGroup(txn, uid) group = yield txn.groupByUID(uid) # Remove two members, and add one member newSet = set() for name in (u"wsanchez1", u"cdaboo1", u"dre1"): record = (yield self.directory.recordWithShortName( RecordType.user, name)) newSet.add(record.uid) added, removed = (yield self.groupCacher.synchronizeMembers( txn, group.groupID, newSet)) self.assertEquals(added, set([ "__dre1__", ])) self.assertEquals(removed, set([ "__glyph1__", "__sagen1__", ])) records = (yield self.groupCacher.cachedMembers(txn, group.groupID)) self.assertEquals(set([r.shortNames[0] for r in records]), set(["wsanchez1", "cdaboo1", "dre1"])) # Remove all members added, removed = (yield self.groupCacher.synchronizeMembers( txn, group.groupID, set())) self.assertEquals(added, set()) self.assertEquals(removed, set([ "__wsanchez1__", "__cdaboo1__", "__dre1__", ])) records = (yield self.groupCacher.cachedMembers(txn, group.groupID)) self.assertEquals(len(records), 0) yield txn.commit() @inlineCallbacks def test_groupByID(self): store = self.storeUnderTest() txn = store.newTransaction() # Non-existent groupID yield self.failUnlessFailure(txn.groupByID(42), NotFoundError) uid = u"__top_group_1__" hash = "553eb54e3bbb26582198ee04541dbee4" yield self.groupCacher.refreshGroup(txn, uid) group = yield txn.groupByUID(uid) group = yield txn.groupByID(group.groupID) self.assertEqual(group.groupUID, uid) self.assertEqual(group.name, u"Top Group 1") self.assertEqual(group.membershipHash, hash) self.assertEqual(group.extant, True) yield txn.commit() @inlineCallbacks def test_externalAssignments(self): store = self.storeUnderTest() txn = store.newTransaction() oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals(oldExternalAssignments, {}) newAssignments = {u"__wsanchez1__": (None, u"__top_group_1__")} yield self.groupCacher.scheduleExternalAssignments(txn, newAssignments, immediately=True) oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals(oldExternalAssignments, {u"__wsanchez1__": (None, u"__top_group_1__")}) newAssignments = { u"__cdaboo1__": (u"__sub_group_1__", None), u"__wsanchez1__": (u"__sub_group_1__", u"__top_group_1__"), } yield self.groupCacher.scheduleExternalAssignments(txn, newAssignments, immediately=True) oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals( oldExternalAssignments, { u"__wsanchez1__": (u"__sub_group_1__", u"__top_group_1__"), u"__cdaboo1__": (u"__sub_group_1__", None) }) allGroupDelegates = (yield txn.allGroupDelegates()) self.assertEquals(allGroupDelegates, set([u"__top_group_1__", u"__sub_group_1__"])) # Fault in the read-only group yield self.groupCacher.refreshGroup(txn, u"__sub_group_1__") # Wilfredo should have Sagen and Daboo as read-only delegates delegates = (yield txn.delegates(u"__wsanchez1__", False, expanded=True)) self.assertEquals(delegates, set([u"__sagen1__", u"__cdaboo1__"])) # Fault in the read-write group yield self.groupCacher.refreshGroup(txn, u"__top_group_1__") # Wilfredo should have 4 users as read-write delegates delegates = (yield txn.delegates(u"__wsanchez1__", True, expanded=True)) self.assertEquals(delegates, set([u"__sagen1__", u"__cdaboo1__", u"__glyph1__"])) # # Now, remove some external assignments # newAssignments = { u"__wsanchez1__": (u"__sub_group_1__", None), } yield self.groupCacher.scheduleExternalAssignments(txn, newAssignments, immediately=True) oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals(oldExternalAssignments, { u"__wsanchez1__": (u"__sub_group_1__", None), }) allGroupDelegates = (yield txn.allGroupDelegates()) self.assertEquals(allGroupDelegates, set([u"__sub_group_1__"])) # Wilfredo should have Sagen and Daboo as read-only delegates delegates = (yield txn.delegates(u"__wsanchez1__", False, expanded=True)) self.assertEquals(delegates, set([u"__sagen1__", u"__cdaboo1__"])) # Wilfredo should have no read-write delegates delegates = (yield txn.delegates(u"__wsanchez1__", True, expanded=True)) self.assertEquals(delegates, set([])) # Only 1 group as delegate now: allGroupDelegates = (yield txn.allGroupDelegates()) self.assertEquals(allGroupDelegates, set([u"__sub_group_1__"])) # # Say somebody messed up and stuck a non-existent group UID in # as a delegate # newAssignments = { u"__wsanchez1__": ( u"__sub_group_1__", u"__non_existent_group__", ), } yield self.groupCacher.scheduleExternalAssignments(txn, newAssignments, immediately=True) oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals( oldExternalAssignments, { u"__wsanchez1__": ( u"__sub_group_1__", None # <--- (not __non_existent_group__) ), }) yield txn.commit() def test_diffAssignments(self): """ Ensure external proxy assignment diffing works """ self.assertEquals( ( # changed [], # removed [], ), diffAssignments( # old {}, # new {})) self.assertEquals( ( # changed [], # removed [], ), diffAssignments( # old {"B": ("1", "2")}, # new {"B": ("1", "2")}, )) self.assertEquals( map( set, ( # changed [("A", ("1", "2")), ("B", ("3", "4"))], # removed [], )), map( set, diffAssignments( # old {}, # new { "A": ("1", "2"), "B": ("3", "4") }))) self.assertEquals( map( set, ( # changed [], # removed ["A", "B"], )), map( set, diffAssignments( # old { "A": ("1", "2"), "B": ("3", "4") }, # new {}, ))) self.assertEquals( map( set, ( # changed [('C', ('4', '5')), ('D', ('7', '8'))], # removed ["B"], )), map( set, diffAssignments( # old { "A": ("1", "2"), "B": ("3", "4"), "C": ("5", "6") }, # new { "D": ("7", "8"), "C": ("4", "5"), "A": ("1", "2") }, ))) @inlineCallbacks def test_recursiveGroup(self): """ Verify refreshGroup() adds a group to the Groups table with the expected membership hash value and members """ store = self.storeUnderTest() txn = store.newTransaction() record = yield self.directory.recordWithUID(u"recursive1_coasts") members = yield record.expandedMembers() self.assertEquals( set([r.uid for r in members]), set([ u'6423F94A-6B76-4A3A-815B-D52CFD77935D', u'5A985493-EE2C-4665-94CF-4DFEA3A89500' ])) yield txn.commit() @inlineCallbacks def test_groupChangeCacheNotificationRefreshGroup(self): """ Verify refreshGroup() triggers a cache notification for the group and all members that are added or removed """ class TestNotifier(object): changedTokens = [] def changed(self, token): self.changedTokens.append(token) self.groupCacher.cacheNotifier = TestNotifier() # No change yield self.groupCacher.refreshGroup(self.transactionUnderTest(), "__top_group_1__") yield self.groupCacher.refreshGroup(self.transactionUnderTest(), "__sub_group_1__") yield self.commit() self.assertEqual(TestNotifier.changedTokens, []) # Add member to group record = yield self.directory.recordWithUID(u"__top_group_1__") addrecord = yield self.directory.recordWithUID(u"__dre1__") yield record.addMembers([ addrecord, ]) yield self.groupCacher.refreshGroup(self.transactionUnderTest(), "__top_group_1__") yield self.commit() self.assertEqual(TestNotifier.changedTokens, [ "__top_group_1__", "__dre1__", ]) TestNotifier.changedTokens = [] # Remove member from group record = yield self.directory.recordWithUID(u"__top_group_1__") addrecord = yield self.directory.recordWithUID(u"__dre1__") yield record.removeMembers([ addrecord, ]) yield self.groupCacher.refreshGroup(self.transactionUnderTest(), "__top_group_1__") yield self.commit() self.assertEqual(TestNotifier.changedTokens, [ "__top_group_1__", "__dre1__", ]) TestNotifier.changedTokens = [] # Add member to sub-group record = yield self.directory.recordWithUID(u"__sub_group_1__") addrecord = yield self.directory.recordWithUID(u"__dre1__") yield record.addMembers([ addrecord, ]) yield self.groupCacher.refreshGroup(self.transactionUnderTest(), "__top_group_1__") yield self.commit() self.assertEqual(TestNotifier.changedTokens, [ "__top_group_1__", "__dre1__", ]) TestNotifier.changedTokens = [] yield self.groupCacher.refreshGroup(self.transactionUnderTest(), "__sub_group_1__") yield self.commit() self.assertEqual(TestNotifier.changedTokens, [ "__sub_group_1__", "__dre1__", ]) TestNotifier.changedTokens = [] # Remove member from sub-group record = yield self.directory.recordWithUID(u"__sub_group_1__") addrecord = yield self.directory.recordWithUID(u"__dre1__") yield record.removeMembers([ addrecord, ]) yield self.groupCacher.refreshGroup(self.transactionUnderTest(), "__top_group_1__") yield self.commit() self.assertEqual(TestNotifier.changedTokens, [ "__top_group_1__", "__dre1__", ]) TestNotifier.changedTokens = [] yield self.groupCacher.refreshGroup(self.transactionUnderTest(), "__sub_group_1__") yield self.commit() self.assertEqual(TestNotifier.changedTokens, [ "__sub_group_1__", "__dre1__", ]) TestNotifier.changedTokens = [] # Remove sub-group member from group record = yield self.directory.recordWithUID(u"__top_group_1__") addrecord = yield self.directory.recordWithUID(u"__sub_group_1__") yield record.removeMembers([ addrecord, ]) yield self.groupCacher.refreshGroup(self.transactionUnderTest(), "__top_group_1__") yield self.commit() self.assertEqual( set(TestNotifier.changedTokens), set([ "__top_group_1__", "__sagen1__", "__cdaboo1__", ])) TestNotifier.changedTokens = [] # Add sub-group member to group record = yield self.directory.recordWithUID(u"__top_group_1__") addrecord = yield self.directory.recordWithUID(u"__sub_group_1__") yield record.addMembers([ addrecord, ]) yield self.groupCacher.refreshGroup(self.transactionUnderTest(), "__top_group_1__") yield self.commit() self.assertEqual( set(TestNotifier.changedTokens), set([ "__top_group_1__", "__sagen1__", "__cdaboo1__", ])) TestNotifier.changedTokens = [] @inlineCallbacks def test_groupChangeCacheNotificationApplyExternalAssignments(self): """ Verify applyExternalAssignments() triggers a cache notification for the delegator and delegates """ class TestNotifier(object): changedTokens = [] def changed(self, token): self.changedTokens.append(token) self.groupCacher.cacheNotifier = TestNotifier() yield self.groupCacher.applyExternalAssignments( self.transactionUnderTest(), "__dre1__", None, None) yield self.commit() self.assertEqual(TestNotifier.changedTokens, ["__dre1__"]) TestNotifier.changedTokens = [] yield self.groupCacher.applyExternalAssignments( self.transactionUnderTest(), "__dre1__", "__top_group_1__", "__sub_group_1__") yield self.commit() self.assertEqual(TestNotifier.changedTokens, ["__dre1__", "__top_group_1__", "__sub_group_1__"]) TestNotifier.changedTokens = []
def test_directoryBasedDelegationChanges(self): groupCacher = GroupCacher(self.directory) delegator = yield self.directory.recordWithUID(u"__wsanchez1__") groupRecord1 = yield self.directory.recordWithUID(u"__top_group_1__") group1 = yield self.transactionUnderTest().groupByUID("__top_group_1__") groupRecord2 = yield self.directory.recordWithUID(u"__sub_group_1__") group2 = yield self.transactionUnderTest().groupByUID("__sub_group_1__") groupRecord3 = yield self.directory.recordWithUID(u"left_coast") group3 = yield self.transactionUnderTest().groupByUID("left_coast") delegate = yield self.directory.recordWithUID(u"__sagen1__") # No delegates delegates = yield Delegates.delegatesOf(self.transactionUnderTest(), delegator, False) self.assertEquals(len(delegates), 0) # No delegators to this group delegators = yield self.transactionUnderTest().delegatorsToGroup(group1.groupID, False) self.assertEquals(len(delegators), 0) # User is not a delegate delegators = yield Delegates.delegatedTo(self.transactionUnderTest(), delegate, True) self.assertEquals(len(delegators), 0) # Apply an external read-only assignment yield groupCacher.applyExternalAssignments( self.transactionUnderTest(), delegator.uid, groupRecord1.uid, None ) # Now there is a read-only delegate delegates = yield Delegates.delegatesOf(self.transactionUnderTest(), delegator, False) self.assertEquals(len(delegates), 1) # Now this group is read-only delegated to delegators = yield self.transactionUnderTest().delegatorsToGroup(group1.groupID, False) self.assertEquals(len(delegators), 1) # Apply an external read-write assignment yield groupCacher.applyExternalAssignments( self.transactionUnderTest(), delegator.uid, groupRecord1.uid, groupRecord2.uid ) # Now there are read-only and read-write delegates delegates = yield Delegates.delegatesOf(self.transactionUnderTest(), delegator, False) self.assertEquals(len(delegates), 1) self.assertEquals(delegates[0].uid, "__top_group_1__") delegates = yield Delegates.delegatesOf(self.transactionUnderTest(), delegator, True) self.assertEquals(len(delegates), 1) self.assertEquals(delegates[0].uid, "__sub_group_1__") # Now both groups are delegated to delegators = yield self.transactionUnderTest().delegatorsToGroup(group1.groupID, False) self.assertEquals(len(delegators), 1) delegators = yield self.transactionUnderTest().delegatorsToGroup(group2.groupID, True) self.assertEquals(len(delegators), 1) # User is now a delegate (cache must have been invalidated properly) delegators = yield Delegates.delegatedTo(self.transactionUnderTest(), delegate, True) self.assertEquals(len(delegators), 1) # Change read-write assignment yield groupCacher.applyExternalAssignments( self.transactionUnderTest(), delegator.uid, groupRecord1.uid, groupRecord3.uid ) # Now this group is not delegated to delegators = yield self.transactionUnderTest().delegatorsToGroup(group2.groupID, True) self.assertEquals(len(delegators), 0) # ..but this group is delegated to delegators = yield self.transactionUnderTest().delegatorsToGroup(group3.groupID, True) self.assertEquals(len(delegators), 1) # Remove external read-write assignment yield groupCacher.applyExternalAssignments( self.transactionUnderTest(), delegator.uid, groupRecord1.uid, None ) # Now there is only a read-only delegate delegates = yield Delegates.delegatesOf(self.transactionUnderTest(), delegator, False) self.assertEquals(len(delegates), 1) self.assertEquals(delegates[0].uid, "__top_group_1__") delegates = yield Delegates.delegatesOf(self.transactionUnderTest(), delegator, True) self.assertEquals(len(delegates), 0) # Now this group is read-only delegated to delegators = yield self.transactionUnderTest().delegatorsToGroup(group1.groupID, False) self.assertEquals(len(delegators), 1) # Now this group is not delegated to delegators = yield self.transactionUnderTest().delegatorsToGroup(group3.groupID, True) self.assertEquals(len(delegators), 0) # User is not a delegate anymore (cache must have been invalidated properly) delegators = yield Delegates.delegatedTo(self.transactionUnderTest(), delegate, True) self.assertEquals(len(delegators), 0) # Remove external assignments altogether yield groupCacher.applyExternalAssignments( self.transactionUnderTest(), delegator.uid, None, None ) # Now there are no delegates delegates = yield Delegates.delegatesOf(self.transactionUnderTest(), delegator, False) self.assertEquals(len(delegates), 0) # No groups are delegated to delegators = yield self.transactionUnderTest().delegatorsToGroup(group1.groupID, False) self.assertEquals(len(delegators), 0) delegators = yield self.transactionUnderTest().delegatorsToGroup(group2.groupID, True) self.assertEquals(len(delegators), 0) delegators = yield self.transactionUnderTest().delegatorsToGroup(group3.groupID, True) self.assertEquals(len(delegators), 0)
class GroupCacherTest(StoreTestCase): @inlineCallbacks def setUp(self): yield super(GroupCacherTest, self).setUp() self.groupCacher = GroupCacher(self.directory) @inlineCallbacks def test_multipleCalls(self): """ Ensure multiple calls to groupByUID() don't raise an exception """ store = self.storeUnderTest() txn = store.newTransaction() record = yield self.directory.recordWithUID(u"__top_group_1__") yield txn.groupByUID(record.uid) yield txn.groupByUID(record.uid) yield txn.commit() @inlineCallbacks def test_refreshGroup(self): """ Verify refreshGroup() adds a group to the Groups table with the expected membership hash value and members """ store = self.storeUnderTest() txn = store.newTransaction() record = yield self.directory.recordWithUID(u"__top_group_1__") yield self.groupCacher.refreshGroup(txn, record.uid) (groupID, _ignore_name, membershipHash, _ignore_modified, extant) = (yield txn.groupByUID(record.uid)) self.assertEquals(extant, True) self.assertEquals(membershipHash, "553eb54e3bbb26582198ee04541dbee4") groupUID, name, membershipHash, extant = (yield txn.groupByID(groupID)) self.assertEquals(groupUID, record.uid) self.assertEquals(name, u"Top Group 1") self.assertEquals(membershipHash, "553eb54e3bbb26582198ee04541dbee4") self.assertEquals(extant, True) members = (yield txn.membersOfGroup(groupID)) self.assertEquals( set([ u'__cdaboo1__', u'__glyph1__', u'__sagen1__', u'__wsanchez1__' ]), members) records = (yield self.groupCacher.cachedMembers(txn, groupID)) self.assertEquals( set([r.uid for r in records]), set([ u'__cdaboo1__', u'__glyph1__', u'__sagen1__', u'__wsanchez1__' ])) # sagen is in the top group, even though it's actually one level # removed record = yield self.directory.recordWithUID(u"__sagen1__") groups = (yield self.groupCacher.cachedGroupsFor(txn, record.uid)) self.assertEquals(set([u"__top_group_1__"]), groups) yield txn.commit() @inlineCallbacks def test_synchronizeMembers(self): """ After loading in a group via refreshGroup(), pass new member sets to synchronizeMembers() and verify members are added and removed as expected """ store = self.storeUnderTest() txn = store.newTransaction() # Refresh the group so it's assigned a group_id uid = u"__top_group_1__" yield self.groupCacher.refreshGroup(txn, uid) (groupID, name, _ignore_membershipHash, _ignore_modified, _ignore_extant) = yield txn.groupByUID(uid) # Remove two members, and add one member newSet = set() for name in (u"wsanchez1", u"cdaboo1", u"dre1"): record = (yield self.directory.recordWithShortName( RecordType.user, name)) newSet.add(record.uid) numAdded, numRemoved = (yield self.groupCacher.synchronizeMembers( txn, groupID, newSet)) self.assertEquals(numAdded, 1) self.assertEquals(numRemoved, 2) records = (yield self.groupCacher.cachedMembers(txn, groupID)) self.assertEquals(set([r.shortNames[0] for r in records]), set(["wsanchez1", "cdaboo1", "dre1"])) # Remove all members numAdded, numRemoved = (yield self.groupCacher.synchronizeMembers( txn, groupID, set())) self.assertEquals(numAdded, 0) self.assertEquals(numRemoved, 3) records = (yield self.groupCacher.cachedMembers(txn, groupID)) self.assertEquals(len(records), 0) yield txn.commit() @inlineCallbacks def test_groupByID(self): store = self.storeUnderTest() txn = store.newTransaction() # Non-existent groupID self.failUnlessFailure(txn.groupByID(42), NotFoundError) uid = u"__top_group_1__" hash = "553eb54e3bbb26582198ee04541dbee4" yield self.groupCacher.refreshGroup(txn, uid) (groupID, _ignore_name, _ignore_membershipHash, _ignore_modified, extant) = yield txn.groupByUID(uid) results = yield txn.groupByID(groupID) self.assertEquals((uid, u"Top Group 1", hash, True), results) yield txn.commit() @inlineCallbacks def test_externalAssignments(self): store = self.storeUnderTest() txn = store.newTransaction() oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals(oldExternalAssignments, {}) newAssignments = {u"__wsanchez1__": (None, u"__top_group_1__")} yield self.groupCacher.applyExternalAssignments(txn, newAssignments) oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals(oldExternalAssignments, {u"__wsanchez1__": (None, u"__top_group_1__")}) newAssignments = { u"__cdaboo1__": (u"__sub_group_1__", None), u"__wsanchez1__": (u"__sub_group_1__", u"__top_group_1__"), } yield self.groupCacher.applyExternalAssignments(txn, newAssignments) oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals( oldExternalAssignments, { u"__wsanchez1__": (u"__sub_group_1__", u"__top_group_1__"), u"__cdaboo1__": (u"__sub_group_1__", None) }) allGroupDelegates = (yield txn.allGroupDelegates()) self.assertEquals(allGroupDelegates, set([u"__top_group_1__", u"__sub_group_1__"])) # Fault in the read-only group yield self.groupCacher.refreshGroup(txn, u"__sub_group_1__") # Wilfredo should have Sagen and Daboo as read-only delegates delegates = (yield txn.delegates(u"__wsanchez1__", False, expanded=True)) self.assertEquals(delegates, set([u"__sagen1__", u"__cdaboo1__"])) # Fault in the read-write group yield self.groupCacher.refreshGroup(txn, u"__top_group_1__") # Wilfredo should have 4 users as read-write delegates delegates = (yield txn.delegates(u"__wsanchez1__", True, expanded=True)) self.assertEquals( delegates, set([ u"__wsanchez1__", u"__sagen1__", u"__cdaboo1__", u"__glyph1__" ])) # # Now, remove some external assignments # newAssignments = { u"__wsanchez1__": (u"__sub_group_1__", None), } yield self.groupCacher.applyExternalAssignments(txn, newAssignments) oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals(oldExternalAssignments, { u"__wsanchez1__": (u"__sub_group_1__", None), }) allGroupDelegates = (yield txn.allGroupDelegates()) self.assertEquals(allGroupDelegates, set([u"__sub_group_1__"])) # Wilfredo should have Sagen and Daboo as read-only delegates delegates = (yield txn.delegates(u"__wsanchez1__", False, expanded=True)) self.assertEquals(delegates, set([u"__sagen1__", u"__cdaboo1__"])) # Wilfredo should have no read-write delegates delegates = (yield txn.delegates(u"__wsanchez1__", True, expanded=True)) self.assertEquals(delegates, set([])) # Only 1 group as delegate now: allGroupDelegates = (yield txn.allGroupDelegates()) self.assertEquals(allGroupDelegates, set([u"__sub_group_1__"])) yield txn.commit() def test_diffAssignments(self): """ Ensure external proxy assignment diffing works """ self.assertEquals( ( # changed [], # removed [], ), diffAssignments( # old {}, # new {})) self.assertEquals( ( # changed [], # removed [], ), diffAssignments( # old {"B": ("1", "2")}, # new {"B": ("1", "2")}, )) self.assertEquals( ( # changed [("A", ("1", "2")), ("B", ("3", "4"))], # removed [], ), diffAssignments( # old {}, # new { "A": ("1", "2"), "B": ("3", "4") })) self.assertEquals( ( # changed [], # removed ["A", "B"], ), diffAssignments( # old { "A": ("1", "2"), "B": ("3", "4") }, # new {}, )) self.assertEquals( ( # changed [('C', ('4', '5')), ('D', ('7', '8'))], # removed ["B"], ), diffAssignments( # old { "A": ("1", "2"), "B": ("3", "4"), "C": ("5", "6") }, # new { "D": ("7", "8"), "C": ("4", "5"), "A": ("1", "2") }, ))
class GroupCacherTest(StoreTestCase): @inlineCallbacks def setUp(self): yield super(GroupCacherTest, self).setUp() self.groupCacher = GroupCacher(self.directory) @inlineCallbacks def test_multipleCalls(self): """ Ensure multiple calls to groupByUID() don't raise an exception """ store = self.storeUnderTest() txn = store.newTransaction() record = yield self.directory.recordWithUID(u"__top_group_1__") yield txn.groupByUID(record.uid) yield txn.groupByUID(record.uid) yield txn.commit() @inlineCallbacks def test_refreshGroup(self): """ Verify refreshGroup() adds a group to the Groups table with the expected membership hash value and members """ store = self.storeUnderTest() txn = store.newTransaction() record = yield self.directory.recordWithUID(u"__top_group_1__") yield self.groupCacher.refreshGroup(txn, record.uid) ( groupID, _ignore_name, membershipHash, _ignore_modified, extant ) = (yield txn.groupByUID(record.uid)) self.assertEquals(extant, True) self.assertEquals(membershipHash, "553eb54e3bbb26582198ee04541dbee4") groupUID, name, membershipHash, extant = (yield txn.groupByID(groupID)) self.assertEquals(groupUID, record.uid) self.assertEquals(name, u"Top Group 1") self.assertEquals(membershipHash, "553eb54e3bbb26582198ee04541dbee4") self.assertEquals(extant, True) members = (yield txn.membersOfGroup(groupID)) self.assertEquals( set([u'__cdaboo1__', u'__glyph1__', u'__sagen1__', u'__wsanchez1__']), members ) records = (yield self.groupCacher.cachedMembers(txn, groupID)) self.assertEquals( set([r.uid for r in records]), set([u'__cdaboo1__', u'__glyph1__', u'__sagen1__', u'__wsanchez1__']) ) # sagen is in the top group, even though it's actually one level # removed record = yield self.directory.recordWithUID(u"__sagen1__") groups = (yield self.groupCacher.cachedGroupsFor(txn, record.uid)) self.assertEquals(set([u"__top_group_1__"]), groups) yield txn.commit() @inlineCallbacks def test_synchronizeMembers(self): """ After loading in a group via refreshGroup(), pass new member sets to synchronizeMembers() and verify members are added and removed as expected """ store = self.storeUnderTest() txn = store.newTransaction() # Refresh the group so it's assigned a group_id uid = u"__top_group_1__" yield self.groupCacher.refreshGroup(txn, uid) ( groupID, name, _ignore_membershipHash, _ignore_modified, _ignore_extant ) = yield txn.groupByUID(uid) # Remove two members, and add one member newSet = set() for name in (u"wsanchez1", u"cdaboo1", u"dre1"): record = ( yield self.directory.recordWithShortName( RecordType.user, name ) ) newSet.add(record.uid) numAdded, numRemoved = ( yield self.groupCacher.synchronizeMembers( txn, groupID, newSet ) ) self.assertEquals(numAdded, 1) self.assertEquals(numRemoved, 2) records = (yield self.groupCacher.cachedMembers(txn, groupID)) self.assertEquals( set([r.shortNames[0] for r in records]), set(["wsanchez1", "cdaboo1", "dre1"]) ) # Remove all members numAdded, numRemoved = ( yield self.groupCacher.synchronizeMembers(txn, groupID, set()) ) self.assertEquals(numAdded, 0) self.assertEquals(numRemoved, 3) records = (yield self.groupCacher.cachedMembers(txn, groupID)) self.assertEquals(len(records), 0) yield txn.commit() @inlineCallbacks def test_groupByID(self): store = self.storeUnderTest() txn = store.newTransaction() # Non-existent groupID self.failUnlessFailure(txn.groupByID(42), NotFoundError) uid = u"__top_group_1__" hash = "553eb54e3bbb26582198ee04541dbee4" yield self.groupCacher.refreshGroup(txn, uid) ( groupID, _ignore_name, _ignore_membershipHash, _ignore_modified, extant ) = yield txn.groupByUID(uid) results = yield txn.groupByID(groupID) self.assertEquals((uid, u"Top Group 1", hash, True), results) yield txn.commit() @inlineCallbacks def test_externalAssignments(self): store = self.storeUnderTest() txn = store.newTransaction() oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals(oldExternalAssignments, {}) newAssignments = { u"__wsanchez1__": (None, u"__top_group_1__") } yield self.groupCacher.applyExternalAssignments(txn, newAssignments) oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals( oldExternalAssignments, { u"__wsanchez1__": ( None, u"__top_group_1__" ) } ) newAssignments = { u"__cdaboo1__": ( u"__sub_group_1__", None ), u"__wsanchez1__": ( u"__sub_group_1__", u"__top_group_1__" ), } yield self.groupCacher.applyExternalAssignments(txn, newAssignments) oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals( oldExternalAssignments, { u"__wsanchez1__": ( u"__sub_group_1__", u"__top_group_1__" ), u"__cdaboo1__": ( u"__sub_group_1__", None ) } ) allGroupDelegates = (yield txn.allGroupDelegates()) self.assertEquals( allGroupDelegates, set( [ u"__top_group_1__", u"__sub_group_1__" ] ) ) # Fault in the read-only group yield self.groupCacher.refreshGroup(txn, u"__sub_group_1__") # Wilfredo should have Sagen and Daboo as read-only delegates delegates = (yield txn.delegates( u"__wsanchez1__", False, expanded=True) ) self.assertEquals( delegates, set( [ u"__sagen1__", u"__cdaboo1__" ] ) ) # Fault in the read-write group yield self.groupCacher.refreshGroup(txn, u"__top_group_1__") # Wilfredo should have 4 users as read-write delegates delegates = (yield txn.delegates( u"__wsanchez1__", True, expanded=True) ) self.assertEquals( delegates, set( [ u"__wsanchez1__", u"__sagen1__", u"__cdaboo1__", u"__glyph1__" ] ) ) # # Now, remove some external assignments # newAssignments = { u"__wsanchez1__": ( u"__sub_group_1__", None ), } yield self.groupCacher.applyExternalAssignments(txn, newAssignments) oldExternalAssignments = (yield txn.externalDelegates()) self.assertEquals( oldExternalAssignments, { u"__wsanchez1__": ( u"__sub_group_1__", None ), } ) allGroupDelegates = (yield txn.allGroupDelegates()) self.assertEquals( allGroupDelegates, set( [ u"__sub_group_1__" ] ) ) # Wilfredo should have Sagen and Daboo as read-only delegates delegates = (yield txn.delegates( u"__wsanchez1__", False, expanded=True) ) self.assertEquals( delegates, set( [ u"__sagen1__", u"__cdaboo1__" ] ) ) # Wilfredo should have no read-write delegates delegates = (yield txn.delegates( u"__wsanchez1__", True, expanded=True) ) self.assertEquals( delegates, set([]) ) # Only 1 group as delegate now: allGroupDelegates = (yield txn.allGroupDelegates()) self.assertEquals( allGroupDelegates, set( [ u"__sub_group_1__" ] ) ) yield txn.commit() def test_diffAssignments(self): """ Ensure external proxy assignment diffing works """ self.assertEquals( ( # changed [], # removed [], ), diffAssignments( # old {}, # new {} ) ) self.assertEquals( ( # changed [], # removed [], ), diffAssignments( # old {"B": ("1", "2")}, # new {"B": ("1", "2")}, ) ) self.assertEquals( ( # changed [("A", ("1", "2")), ("B", ("3", "4"))], # removed [], ), diffAssignments( # old {}, # new {"A": ("1", "2"), "B": ("3", "4")} ) ) self.assertEquals( ( # changed [], # removed ["A", "B"], ), diffAssignments( # old {"A": ("1", "2"), "B": ("3", "4")}, # new {}, ) ) self.assertEquals( ( # changed [('C', ('4', '5')), ('D', ('7', '8'))], # removed ["B"], ), diffAssignments( # old {"A": ("1", "2"), "B": ("3", "4"), "C": ("5", "6")}, # new {"D": ("7", "8"), "C": ("4", "5"), "A": ("1", "2")}, ) )