def test_sort_behaviour_ncchanges(self): """Testing sorting behaviour on a group of objects.""" user1_dn = "cn=test_user1,%s" % self.ou group_dn = "cn=test_group,%s" % self.ou self.ldb_dc1.add({"dn": user1_dn, "objectclass": "user"}) self.ldb_dc1.add({"dn": group_dn, "objectclass": "group"}) self.add_linked_attribute(group_dn, user1_dn, attr='member') dc_guid_1 = self.ldb_dc1.get_invocation_id() drs, drs_handle = self._ds_bind(self.dnsname_dc1) # Make sure the max objects count is high enough req8 = self._exop_req8(dest_dsa=None, invocation_id=dc_guid_1, nc_dn_str=self.base_dn, replica_flags=0, max_objects=100, exop=drsuapi.DRSUAPI_EXOP_NONE) # Loop until we get linked attributes, or we get to the end. # Samba sends linked attributes at the end, unlike Windows. while True: (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8) if ctr.more_data == 0 or ctr.linked_attributes_count != 0: break req8.highwatermark = ctr.new_highwatermark self.assertTrue(ctr.linked_attributes_count != 0) no_inactive = [] for link in ctr.linked_attributes: try: target_guid = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3, link.value.blob).guid except: target_guid = ndr_unpack( drsuapi.DsReplicaObjectIdentifier3Binary, link.value.blob).guid no_inactive.append((link, target_guid)) no_inactive.sort(key=cmp_to_key_fn(_linked_attribute_compare)) # assert the two arrays are the same self.assertEqual([x[0] for x in no_inactive], ctr.linked_attributes)
def _test_server_sort_different_attr(self): def cmp_locale(a, b): return locale.strcoll(a[0], b[0]) def cmp_binary(a, b): return cmp_fn(a[0], b[0]) def cmp_numeric(a, b): return cmp_fn(int(a[0]), int(b[0])) # For testing simplicity, the attributes in here need to be # unique for each user. Otherwise there are multiple possible # valid answers. sort_functions = { 'cn': cmp_binary, "employeeNumber": cmp_locale, "accountExpires": cmp_numeric, "msTSExpireDate4": cmp_binary } attrs = list(sort_functions.keys()) attr_pairs = zip(attrs, attrs[1:] + attrs[:1]) for sort_attr, result_attr in attr_pairs: forward = sorted(((norm(x[sort_attr]), norm(x[result_attr])) for x in self.users), key=cmp_to_key_fn(sort_functions[sort_attr])) reverse = list(reversed(forward)) for rev in (0, 1): res = self.ldb.search( self.ou, scope=ldb.SCOPE_ONELEVEL, attrs=[result_attr], controls=["server_sort:1:%d:%s" % (rev, sort_attr)]) self.assertEqual(len(res), len(self.users)) pairs = (forward, reverse)[rev] expected_order = [x[1] for x in pairs] received_order = [norm(x[result_attr][0]) for x in res] if expected_order != received_order: print(sort_attr, result_attr, ['forward', 'reverse'][rev]) print("expected", expected_order) print("received", received_order) print("unnormalised:", [x[result_attr][0] for x in res]) print("unnormalised: «%s»" % '» «'.join(str(x[result_attr][0]) for x in res)) print("pairs:", pairs) # There are bugs in Windows that we don't want (or # know how) to replicate regarding timestamp sorting. # Let's remind ourselves. if result_attr == "msTSExpireDate4": print('-' * 72) print("This test fails against Windows with the " "default number of elements (33).") print("Try with --elements=27 (or similar).") print('-' * 72) self.assertEquals(expected_order, received_order) for x in res: if sort_attr in x: self.fail('the search for %s should not return %s' % (result_attr, sort_attr))
def test_sort_behaviour_single_object(self): """Testing sorting behaviour on single objects""" user1_dn = "cn=test_user1,%s" % self.ou user2_dn = "cn=test_user2,%s" % self.ou user3_dn = "cn=test_user3,%s" % self.ou group_dn = "cn=test_group,%s" % self.ou self.ldb_dc1.add({"dn": user1_dn, "objectclass": "user"}) self.ldb_dc1.add({"dn": user2_dn, "objectclass": "user"}) self.ldb_dc1.add({"dn": user3_dn, "objectclass": "user"}) self.ldb_dc1.add({"dn": group_dn, "objectclass": "group"}) u1_guid = misc.GUID( self.ldb_dc1.search(base=user1_dn, attrs=["objectGUID"])[0]['objectGUID'][0]) u2_guid = misc.GUID( self.ldb_dc1.search(base=user2_dn, attrs=["objectGUID"])[0]['objectGUID'][0]) u3_guid = misc.GUID( self.ldb_dc1.search(base=user3_dn, attrs=["objectGUID"])[0]['objectGUID'][0]) g_guid = misc.GUID( self.ldb_dc1.search(base=group_dn, attrs=["objectGUID"])[0]['objectGUID'][0]) self.add_linked_attribute(group_dn, user1_dn, attr='member') self.add_linked_attribute(group_dn, user2_dn, attr='member') self.add_linked_attribute(group_dn, user3_dn, attr='member') self.add_linked_attribute(group_dn, user1_dn, attr='managedby') self.add_linked_attribute(group_dn, user2_dn, attr='nonSecurityMember') self.add_linked_attribute(group_dn, user3_dn, attr='nonSecurityMember') set_inactive = AbstractLink( drsuapi.DRSUAPI_ATTID_nonSecurityMember, drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE, g_guid, u3_guid) expected_links = set([ set_inactive, AbstractLink(drsuapi.DRSUAPI_ATTID_member, drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE, g_guid, u1_guid), AbstractLink(drsuapi.DRSUAPI_ATTID_member, drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE, g_guid, u2_guid), AbstractLink(drsuapi.DRSUAPI_ATTID_member, drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE, g_guid, u3_guid), AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy, drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE, g_guid, u1_guid), AbstractLink(drsuapi.DRSUAPI_ATTID_nonSecurityMember, drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE, g_guid, u2_guid), ]) dc_guid_1 = self.ldb_dc1.get_invocation_id() drs, drs_handle = self._ds_bind(self.dnsname_dc1) req8 = self._exop_req8(dest_dsa=None, invocation_id=dc_guid_1, nc_dn_str=group_dn, exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ) (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8) no_inactive = [] for link in ctr.linked_attributes: target_guid = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3, link.value.blob).guid no_inactive.append((link, target_guid)) self.assertTrue( AbstractLink(link.attid, link.flags, link.identifier.guid, target_guid) in expected_links) no_inactive.sort(key=cmp_to_key_fn(_linked_attribute_compare)) # assert the two arrays are the same self.assertEqual(len(expected_links), ctr.linked_attributes_count) self.assertEqual([x[0] for x in no_inactive], ctr.linked_attributes) self.remove_linked_attribute(group_dn, user3_dn, attr='nonSecurityMember') # Set the link inactive expected_links.remove(set_inactive) set_inactive.flags = 0 expected_links.add(set_inactive) has_inactive = [] (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8) for link in ctr.linked_attributes: target_guid = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3, link.value.blob).guid has_inactive.append((link, target_guid)) self.assertTrue( AbstractLink(link.attid, link.flags, link.identifier.guid, target_guid) in expected_links) has_inactive.sort(key=cmp_to_key_fn(_linked_attribute_compare)) # assert the two arrays are the same self.assertEqual(len(expected_links), ctr.linked_attributes_count) self.assertEqual([x[0] for x in has_inactive], ctr.linked_attributes)