3 # Unit tests for dirsync control
4 # Copyright (C) Matthieu Patou <mat@matws.net> 2011
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 sys.path.insert(0, "bin/python")
25 samba.ensure_external_module("testtools", "testtools")
26 samba.ensure_external_module("subunit", "subunit/python")
28 import samba.getopt as options
31 from ldb import LdbError, SCOPE_BASE
32 from ldb import Message, MessageElement, Dn
33 from ldb import FLAG_MOD_ADD, FLAG_MOD_DELETE
34 from samba.dcerpc import security, misc, drsblobs
35 from samba.ndr import ndr_unpack, ndr_pack
37 from samba.auth import system_session
38 from samba import gensec, sd_utils
39 from samba.samdb import SamDB
40 from samba.credentials import Credentials
42 from samba.tests import delete_force
43 from subunit.run import SubunitTestRunner
46 parser = optparse.OptionParser("dirsync.py [options] <host>")
47 sambaopts = options.SambaOptions(parser)
48 parser.add_option_group(sambaopts)
49 parser.add_option_group(options.VersionOptions(parser))
51 # use command line creds if available
52 credopts = options.CredentialsOptions(parser)
53 parser.add_option_group(credopts)
54 opts, args = parser.parse_args()
62 ldaphost = "ldap://%s" % host
63 ldapshost = "ldaps://%s" % host
66 start = host.rindex("://")
67 host = host.lstrip(start+3)
69 lp = sambaopts.get_loadparm()
70 creds = credopts.get_credentials(lp)
76 class DirsyncBaseTests(samba.tests.TestCase):
79 super(DirsyncBaseTests, self).setUp()
81 self.base_dn = ldb.domain_dn()
82 self.domain_sid = security.dom_sid(ldb.get_domain_sid())
83 self.user_pass = "samba123@AAA"
84 self.configuration_dn = self.ldb_admin.get_config_basedn().get_linearized()
85 self.sd_utils = sd_utils.SDUtils(ldb)
86 #used for anonymous login
87 print "baseDN: %s" % self.base_dn
89 def get_user_dn(self, name):
90 return "CN=%s,CN=Users,%s" % (name, self.base_dn)
92 def get_ldb_connection(self, target_username, target_password):
93 creds_tmp = Credentials()
94 creds_tmp.set_username(target_username)
95 creds_tmp.set_password(target_password)
96 creds_tmp.set_domain(creds.get_domain())
97 creds_tmp.set_realm(creds.get_realm())
98 creds_tmp.set_workstation(creds.get_workstation())
99 creds_tmp.set_gensec_features(creds_tmp.get_gensec_features()
100 | gensec.FEATURE_SEAL)
101 ldb_target = SamDB(url=ldaphost, credentials=creds_tmp, lp=lp)
105 #tests on ldap add operations
106 class SimpleDirsyncTests(DirsyncBaseTests):
109 super(SimpleDirsyncTests, self).setUp()
111 self.dirsync_user = "test_dirsync_user"
112 self.simple_user = "test_simple_user"
113 self.admin_user = "test_admin_user"
116 self.ldb_admin.newuser(self.dirsync_user, self.user_pass)
117 self.ldb_admin.newuser(self.simple_user, self.user_pass)
118 self.ldb_admin.newuser(self.admin_user, self.user_pass)
119 self.desc_sddl = self.sd_utils.get_sd_as_sddl(self.base_dn)
121 user_sid = self.sd_utils.get_object_sid(self.get_user_dn(self.dirsync_user))
122 mod = "(A;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;%s)" % str(user_sid)
123 self.sd_utils.dacl_add_ace(self.base_dn, mod)
125 # add admins to the Domain Admins group
126 self.ldb_admin.add_remove_group_members("Domain Admins", self.admin_user,
127 add_members_operation=True)
130 super(SimpleDirsyncTests, self).tearDown()
131 delete_force(self.ldb_admin, self.get_user_dn(self.dirsync_user))
132 delete_force(self.ldb_admin, self.get_user_dn(self.simple_user))
133 delete_force(self.ldb_admin, self.get_user_dn(self.admin_user))
135 delete_force(self.ldb_admin, self.ouname)
136 self.sd_utils.modify_sd_on_dn(self.base_dn, self.desc_sddl)
138 self.ldb_admin.deletegroup("testgroup")
142 #def test_dirsync_errors(self):
145 def test_dirsync_supported(self):
146 """Test the basic of the dirsync is supported"""
147 self.ldb_dirsync = self.get_ldb_connection(self.dirsync_user, self.user_pass)
148 self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass)
149 res = self.ldb_admin.search(self.base_dn, expression="samaccountname=*", controls=["dirsync:1:0:1"])
150 res = self.ldb_dirsync.search(self.base_dn, expression="samaccountname=*", controls=["dirsync:1:0:1"])
152 self.ldb_simple.search(self.base_dn,
153 expression="samaccountname=*",
154 controls=["dirsync:1:0:1"])
156 self.assertTrue(str(l).find("LDAP_INSUFFICIENT_ACCESS_RIGHTS") != -1)
158 def test_parentGUID_referrals(self):
159 res2 = self.ldb_admin.search(self.base_dn, scope=SCOPE_BASE, attrs=["objectGUID"])
161 res = self.ldb_admin.search(self.base_dn,
162 expression="name=Configuration",
163 controls=["dirsync:1:0:1"])
164 self.assertEqual(res2[0].get("objectGUID"), res[0].get("parentGUID"))
166 def test_ok_not_rootdc(self):
167 """Test if it's ok to do dirsync on another NC that is not the root DC"""
169 res = self.ldb_admin.search(self.ldb_admin.get_config_basedn(),
170 expression="samaccountname=*",
171 controls=["dirsync:1:0:1"])
173 self.assertTrue(False)
175 def test_dirsync_errors(self):
176 """Test if dirsync returns the correct LDAP errors in case of pb"""
177 self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass)
178 self.ldb_dirsync = self.get_ldb_connection(self.dirsync_user, self.user_pass)
180 self.ldb_simple.search(self.base_dn,
181 expression="samaccountname=*",
182 controls=["dirsync:1:0:1"])
185 self.assertTrue(str(l).find("LDAP_INSUFFICIENT_ACCESS_RIGHTS") != -1)
188 self.ldb_simple.search("CN=Users,%s" % self.base_dn,
189 expression="samaccountname=*",
190 controls=["dirsync:1:0:1"])
193 self.assertTrue(str(l).find("LDAP_INSUFFICIENT_ACCESS_RIGHTS") != -1)
196 self.ldb_simple.search("CN=Users,%s" % self.base_dn,
197 expression="samaccountname=*",
198 controls=["dirsync:1:1:1"])
201 self.assertTrue(str(l).find("LDAP_UNWILLING_TO_PERFORM") != -1)
204 self.ldb_dirsync.search("CN=Users,%s" % self.base_dn,
205 expression="samaccountname=*",
206 controls=["dirsync:1:0:1"])
209 self.assertTrue(str(l).find("LDAP_INSUFFICIENT_ACCESS_RIGHTS") != -1)
212 self.ldb_admin.search("CN=Users,%s" % self.base_dn,
213 expression="samaccountname=*",
214 controls=["dirsync:1:0:1"])
217 self.assertTrue(str(l).find("LDAP_INSUFFICIENT_ACCESS_RIGHTS") != -1)
220 self.ldb_admin.search("CN=Users,%s" % self.base_dn,
221 expression="samaccountname=*",
222 controls=["dirsync:1:1:1"])
225 self.assertTrue(str(l).find("LDAP_UNWILLING_TO_PERFORM") != -1)
230 def test_dirsync_attributes(self):
231 """Check behavior with some attributes """
232 res = self.ldb_admin.search(self.base_dn,
233 expression="samaccountname=*",
234 controls=["dirsync:1:0:1"])
235 # Check that nTSecurityDescriptor is returned as it's the case when doing dirsync
236 self.assertTrue(res.msgs[0].get("ntsecuritydescriptor") != None)
237 # Check that non replicated attributes are not returned
238 self.assertTrue(res.msgs[0].get("badPwdCount") == None)
239 # Check that non forward link are not returned
240 self.assertTrue(res.msgs[0].get("memberof") == None)
242 # Asking for instanceType will return also objectGUID
243 res = self.ldb_admin.search(self.base_dn,
244 expression="samaccountname=Administrator",
245 attrs=["instanceType"],
246 controls=["dirsync:1:0:1"])
247 self.assertTrue(res.msgs[0].get("objectGUID") != None)
248 self.assertTrue(res.msgs[0].get("instanceType") != None)
250 # We don't return an entry if asked for objectGUID
251 res = self.ldb_admin.search(self.base_dn,
252 expression="dn=%s" % self.base_dn,
253 attrs=["objectGUID"],
254 controls=["dirsync:1:0:1"])
255 self.assertEquals(len(res.msgs), 0)
257 # a request on the root of a NC didn't return parentGUID
258 res = self.ldb_admin.search(self.base_dn,
259 expression="dn=%s" % self.base_dn,
261 controls=["dirsync:1:0:1"])
262 self.assertTrue(res.msgs[0].get("objectGUID") != None)
263 self.assertTrue(res.msgs[0].get("name") != None)
264 self.assertTrue(res.msgs[0].get("parentGUID") == None)
265 self.assertTrue(res.msgs[0].get("instanceType") != None)
267 # Asking for name will return also objectGUID and parentGUID
268 # and instanceType and of course name
269 res = self.ldb_admin.search(self.base_dn,
270 expression="samaccountname=Administrator",
272 controls=["dirsync:1:0:1"])
273 self.assertTrue(res.msgs[0].get("objectGUID") != None)
274 self.assertTrue(res.msgs[0].get("name") != None)
275 self.assertTrue(res.msgs[0].get("parentGUID") != None)
276 self.assertTrue(res.msgs[0].get("instanceType") != None)
278 # Asking for dn will not return not only DN but more like if attrs=*
279 # parentGUID should be returned
280 res = self.ldb_admin.search(self.base_dn,
281 expression="samaccountname=Administrator",
283 controls=["dirsync:1:0:1"])
284 count = len(res.msgs[0])
285 res2 = self.ldb_admin.search(self.base_dn,
286 expression="samaccountname=Administrator",
287 controls=["dirsync:1:0:1"])
288 count2 = len(res2.msgs[0])
289 self.assertEqual(count, count2)
291 # Asking for cn will return nothing on objects that have CN as RDN
292 res = self.ldb_admin.search(self.base_dn,
293 expression="samaccountname=Administrator",
295 controls=["dirsync:1:0:1"])
296 self.assertEqual(len(res.msgs), 0)
297 # Asking for parentGUID will return nothing too
298 res = self.ldb_admin.search(self.base_dn,
299 expression="samaccountname=Administrator",
300 attrs=["parentGUID"],
301 controls=["dirsync:1:0:1"])
302 self.assertEqual(len(res.msgs), 0)
303 ouname="OU=testou,%s" % self.base_dn
305 self.ldb_admin.create_ou(ouname)
307 delta.dn = Dn(self.ldb_admin, str(ouname))
308 delta["cn"] = MessageElement("test ou",
311 self.ldb_admin.modify(delta)
312 res = self.ldb_admin.search(self.base_dn,
313 expression="name=testou",
315 controls=["dirsync:1:0:1"])
317 self.assertEqual(len(res.msgs), 1)
318 self.assertEqual(len(res.msgs[0]), 3)
319 delete_force(self.ldb_admin, ouname)
321 def test_dirsync_with_controls(self):
322 """Check that dirsync return correct informations when dealing with the NC"""
323 res = self.ldb_admin.search(self.base_dn,
324 expression="(dn=%s)" % str(self.base_dn),
326 controls=["dirsync:1:0:10000", "extended_dn:1", "show_deleted:1"])
328 def test_dirsync_basenc(self):
329 """Check that dirsync return correct informations when dealing with the NC"""
330 res = self.ldb_admin.search(self.base_dn,
331 expression="(dn=%s)" % str(self.base_dn),
333 controls=["dirsync:1:0:10000"])
334 self.assertEqual(len(res.msgs), 1)
335 self.assertEqual(len(res.msgs[0]), 3)
337 res = self.ldb_admin.search(self.base_dn,
338 expression="(dn=%s)" % str(self.base_dn),
339 attrs=["ntSecurityDescriptor"],
340 controls=["dirsync:1:0:10000"])
341 self.assertEqual(len(res.msgs), 1)
342 self.assertEqual(len(res.msgs[0]), 3)
344 def test_dirsync_othernc(self):
345 """Check that dirsync return information for entries that are normaly referrals (ie. other NCs)"""
346 res = self.ldb_admin.search(self.base_dn,
347 expression="(objectclass=configuration)",
349 controls=["dirsync:1:0:10000"])
350 self.assertEqual(len(res.msgs), 1)
351 self.assertEqual(len(res.msgs[0]), 4)
353 res = self.ldb_admin.search(self.base_dn,
354 expression="(objectclass=configuration)",
355 attrs=["ntSecurityDescriptor"],
356 controls=["dirsync:1:0:10000"])
357 self.assertEqual(len(res.msgs), 1)
358 self.assertEqual(len(res.msgs[0]), 3)
360 res = self.ldb_admin.search(self.base_dn,
361 expression="(objectclass=domaindns)",
362 attrs=["ntSecurityDescriptor"],
363 controls=["dirsync:1:0:10000"])
366 # only sub nc returns a result when asked for objectGUID
367 res = self.ldb_admin.search(self.base_dn,
368 expression="(objectclass=domaindns)",
369 attrs=["objectGUID"],
370 controls=["dirsync:1:0:0"])
371 self.assertEqual(len(res.msgs), nb - 1)
373 self.assertTrue(res.msgs[0].get("objectGUID") != None)
375 res = self.ldb_admin.search(self.base_dn,
376 expression="(objectclass=configuration)",
377 attrs=["objectGUID"],
378 controls=["dirsync:1:0:0"])
381 def test_dirsync_send_delta(self):
382 """Check that dirsync return correct delta when sending the last cookie"""
383 res = self.ldb_admin.search(self.base_dn,
384 expression="(&(samaccountname=test*)(!(isDeleted=*)))",
385 controls=["dirsync:1:0:10000"])
386 ctl = str(res.controls[0]).split(":")
390 control = str(":".join(ctl))
391 res = self.ldb_admin.search(self.base_dn,
392 expression="(&(samaccountname=test*)(!(isDeleted=*)))",
394 self.assertEqual(len(res), 0)
396 res = self.ldb_admin.search(self.base_dn,
397 expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))",
398 controls=["dirsync:1:0:100000"])
400 ctl = str(res.controls[0]).split(":")
404 control2 = str(":".join(ctl))
407 ouname="OU=testou2,%s" % self.base_dn
409 self.ldb_admin.create_ou(ouname)
410 res = self.ldb_admin.search(self.base_dn,
411 expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))",
413 self.assertEqual(len(res), 1)
414 ctl = str(res.controls[0]).split(":")
418 control3 = str(":".join(ctl))
421 delta.dn = Dn(self.ldb_admin, str(ouname))
423 delta["cn"] = MessageElement("test ou",
426 self.ldb_admin.modify(delta)
427 res = self.ldb_admin.search(self.base_dn,
428 expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))",
431 self.assertEqual(len(res.msgs), 1)
432 # 3 attributes: instanceType, cn and objectGUID
433 self.assertEqual(len(res.msgs[0]), 3)
436 delta.dn = Dn(self.ldb_admin, str(ouname))
437 delta["cn"] = MessageElement([],
440 self.ldb_admin.modify(delta)
441 res = self.ldb_admin.search(self.base_dn,
442 expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))",
445 self.assertEqual(len(res.msgs), 1)
446 # So we won't have much attribute returned but instanceType and GUID
448 # 3 attributes: instanceType and objectGUID and cn but empty
449 self.assertEqual(len(res.msgs[0]), 3)
450 ouname = "OU=newouname,%s" % self.base_dn
451 self.ldb_admin.rename(str(res[0].dn), str(Dn(self.ldb_admin, ouname)))
453 ctl = str(res.controls[0]).split(":")
457 control4 = str(":".join(ctl))
458 res = self.ldb_admin.search(self.base_dn,
459 expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))",
462 self.assertTrue(res[0].get("parentGUID") != None)
463 self.assertTrue(res[0].get("name") != None)
464 delete_force(self.ldb_admin, ouname)
466 def test_dirsync_linkedattributes(self):
467 """Check that dirsync returnd deleted objects too"""
468 # Let's search for members
469 self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass)
470 res = self.ldb_simple.search(self.base_dn,
471 expression="(name=Administrators)",
472 controls=["dirsync:1:1:1"])
474 self.assertTrue(len(res[0].get("member")) > 0)
475 size = len(res[0].get("member"))
477 ctl = str(res.controls[0]).split(":")
481 control1 = str(":".join(ctl))
482 self.ldb_admin.add_remove_group_members("Administrators", self.simple_user,
483 add_members_operation=True)
485 res = self.ldb_simple.search(self.base_dn,
486 expression="(name=Administrators)",
489 self.assertEqual(len(res[0].get("member")), size + 1)
490 ctl = str(res.controls[0]).split(":")
494 control1 = str(":".join(ctl))
496 # remove the user from the group
497 self.ldb_admin.add_remove_group_members("Administrators", self.simple_user,
498 add_members_operation=False)
500 res = self.ldb_simple.search(self.base_dn,
501 expression="(name=Administrators)",
504 self.assertEqual(len(res[0].get("member")), size )
506 self.ldb_admin.newgroup("testgroup")
507 self.ldb_admin.add_remove_group_members("testgroup", self.simple_user,
508 add_members_operation=True)
510 res = self.ldb_admin.search(self.base_dn,
511 expression="(name=testgroup)",
512 controls=["dirsync:1:0:1"])
514 self.assertEqual(len(res[0].get("member")), 1)
515 self.assertTrue(res[0].get("member") != "" )
517 ctl = str(res.controls[0]).split(":")
521 control1 = str(":".join(ctl))
523 # Check that reasking the same question but with an updated cookie
524 # didn't return any results.
526 res = self.ldb_admin.search(self.base_dn,
527 expression="(name=testgroup)",
529 self.assertEqual(len(res), 0)
531 ctl = str(res.controls[0]).split(":")
535 control1 = str(":".join(ctl))
537 self.ldb_admin.add_remove_group_members("testgroup", self.simple_user,
538 add_members_operation=False)
540 res = self.ldb_admin.search(self.base_dn,
541 expression="(name=testgroup)",
545 self.ldb_admin.deletegroup("testgroup")
546 self.assertEqual(len(res[0].get("member")), 0)
550 def test_dirsync_deleted_items(self):
551 """Check that dirsync returnd deleted objects too"""
553 ouname="OU=testou3,%s" % self.base_dn
555 self.ldb_admin.create_ou(ouname)
556 res = self.ldb_admin.search(self.base_dn,
557 expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))",
558 controls=["dirsync:1:0:1"])
561 if str(e["name"]) == "testou3":
562 guid = str(ndr_unpack(misc.GUID,e.get("objectGUID")[0]))
564 ctl = str(res.controls[0]).split(":")
568 control1 = str(":".join(ctl))
570 # So now delete the object and check that
571 # we can see the object but deleted when admin
572 delete_force(self.ldb_admin, ouname)
574 res = self.ldb_admin.search(self.base_dn,
575 expression="(objectClass=organizationalUnit)",
577 self.assertEqual(len(res), 1)
578 guid2 = str(ndr_unpack(misc.GUID,res[0].get("objectGUID")[0]))
579 self.assertEqual(guid2, guid)
580 self.assertTrue(res[0].get("isDeleted"))
581 self.assertTrue(res[0].get("name") != None)
583 def test_cookie_from_others(self):
584 res = self.ldb_admin.search(self.base_dn,
585 expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))",
586 controls=["dirsync:1:0:1"])
587 ctl = str(res.controls[0]).split(":")
588 cookie = ndr_unpack(drsblobs.ldapControlDirSyncCookie, base64.b64decode(str(ctl[4])))
589 cookie.blob.guid1 = misc.GUID("128a99bf-abcd-1234-abcd-1fb625e530db")
590 controls=["dirsync:1:0:0:%s" % base64.b64encode(ndr_pack(cookie))]
591 res = self.ldb_admin.search(self.base_dn,
592 expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))",
595 class ExtendedDirsyncTests(SimpleDirsyncTests):
596 def test_dirsync_linkedattributes(self):
597 flag_incr_linked = 2147483648
598 self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass)
599 res = self.ldb_admin.search(self.base_dn,
601 expression="(name=Administrators)",
602 controls=["dirsync:1:%d:1" % flag_incr_linked])
604 self.assertTrue(res[0].get("member;range=1-1") != None )
605 self.assertTrue(len(res[0].get("member;range=1-1")) > 0)
606 size = len(res[0].get("member;range=1-1"))
608 ctl = str(res.controls[0]).split(":")
610 ctl[2] = "%d" % flag_incr_linked
612 control1 = str(":".join(ctl))
613 self.ldb_admin.add_remove_group_members("Administrators", self.simple_user,
614 add_members_operation=True)
615 self.ldb_admin.add_remove_group_members("Administrators", self.dirsync_user,
616 add_members_operation=True)
619 res = self.ldb_admin.search(self.base_dn,
620 expression="(name=Administrators)",
623 self.assertEqual(len(res[0].get("member;range=1-1")), 2)
624 ctl = str(res.controls[0]).split(":")
626 ctl[2] = "%d" % flag_incr_linked
628 control1 = str(":".join(ctl))
630 # remove the user from the group
631 self.ldb_admin.add_remove_group_members("Administrators", self.simple_user,
632 add_members_operation=False)
634 res = self.ldb_admin.search(self.base_dn,
635 expression="(name=Administrators)",
638 self.assertEqual(res[0].get("member;range=1-1"), None )
639 self.assertEqual(len(res[0].get("member;range=0-0")), 1)
641 ctl = str(res.controls[0]).split(":")
643 ctl[2] = "%d" % flag_incr_linked
645 control2 = str(":".join(ctl))
647 self.ldb_admin.add_remove_group_members("Administrators", self.dirsync_user,
648 add_members_operation=False)
650 res = self.ldb_admin.search(self.base_dn,
651 expression="(name=Administrators)",
654 self.assertEqual(res[0].get("member;range=1-1"), None )
655 self.assertEqual(len(res[0].get("member;range=0-0")), 1)
657 res = self.ldb_admin.search(self.base_dn,
658 expression="(name=Administrators)",
661 self.assertEqual(res[0].get("member;range=1-1"), None )
662 self.assertEqual(len(res[0].get("member;range=0-0")), 2)
664 def test_dirsync_deleted_items(self):
665 """Check that dirsync returnd deleted objects too"""
667 self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass)
668 ouname="OU=testou3,%s" % self.base_dn
670 self.ldb_admin.create_ou(ouname)
672 # Specify LDAP_DIRSYNC_OBJECT_SECURITY
673 res = self.ldb_simple.search(self.base_dn,
674 expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))",
675 controls=["dirsync:1:1:1"])
679 if str(e["name"]) == "testou3":
680 guid = str(ndr_unpack(misc.GUID,e.get("objectGUID")[0]))
682 self.assertTrue(guid != None)
683 ctl = str(res.controls[0]).split(":")
687 control1 = str(":".join(ctl))
689 # So now delete the object and check that
690 # we can see the object but deleted when admin
691 # we just see the objectGUID when simple user
692 delete_force(self.ldb_admin, ouname)
694 res = self.ldb_simple.search(self.base_dn,
695 expression="(objectClass=organizationalUnit)",
697 self.assertEqual(len(res), 1)
698 guid2 = str(ndr_unpack(misc.GUID,res[0].get("objectGUID")[0]))
699 self.assertEqual(guid2, guid)
700 self.assertEqual(str(res[0].dn), "")
703 ldb = SamDB(ldapshost, credentials=creds, session_info=system_session(lp), lp=lp)
705 runner = SubunitTestRunner()
708 if not runner.run(unittest.makeSuite(SimpleDirsyncTests)).wasSuccessful():
710 if not runner.run(unittest.makeSuite(ExtendedDirsyncTests)).wasSuccessful():