0c40e018968aa94587211843e8955648692a1e30
[samba.git] / source4 / dsdb / tests / python / deletetest.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from __future__ import print_function
5 import optparse
6 import sys
7 import os
8
9 sys.path.insert(0, "bin/python")
10 import samba
11
12 from samba.tests.subunitrun import SubunitOptions, TestProgram
13
14 import samba.getopt as options
15
16 from samba.auth import system_session
17 from ldb import SCOPE_BASE, LdbError, Message, MessageElement, Dn, FLAG_MOD_ADD, FLAG_MOD_DELETE, FLAG_MOD_REPLACE
18 from ldb import ERR_NO_SUCH_OBJECT, ERR_NOT_ALLOWED_ON_NON_LEAF, ERR_ENTRY_ALREADY_EXISTS, ERR_ATTRIBUTE_OR_VALUE_EXISTS
19 from ldb import ERR_UNWILLING_TO_PERFORM, ERR_OPERATIONS_ERROR
20 from samba.samdb import SamDB
21 from samba.tests import delete_force
22 from samba import dsdb
23
24 parser = optparse.OptionParser("deletetest.py [options] <host|file>")
25 sambaopts = options.SambaOptions(parser)
26 parser.add_option_group(sambaopts)
27 parser.add_option_group(options.VersionOptions(parser))
28 # use command line creds if available
29 credopts = options.CredentialsOptions(parser)
30 parser.add_option_group(credopts)
31 subunitopts = SubunitOptions(parser)
32 parser.add_option_group(subunitopts)
33 opts, args = parser.parse_args()
34
35 if len(args) < 1:
36     parser.print_usage()
37     sys.exit(1)
38
39 host = args[0]
40
41 lp = sambaopts.get_loadparm()
42 creds = credopts.get_credentials(lp)
43
44
45 class BaseDeleteTests(samba.tests.TestCase):
46
47     def GUID_string(self, guid):
48         return self.ldb.schema_format_value("objectGUID", guid)
49
50     def setUp(self):
51         super(BaseDeleteTests, self).setUp()
52         self.ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp)
53
54         self.base_dn = self.ldb.domain_dn()
55         self.configuration_dn = self.ldb.get_config_basedn().get_linearized()
56
57     def search_guid(self, guid):
58         print("SEARCH by GUID %s" % self.GUID_string(guid))
59
60         res = self.ldb.search(base="<GUID=%s>" % self.GUID_string(guid),
61                               scope=SCOPE_BASE,
62                               controls=["show_deleted:1"],
63                               attrs=["*", "parentGUID"])
64         self.assertEquals(len(res), 1)
65         return res[0]
66
67     def search_dn(self, dn):
68         print("SEARCH by DN %s" % dn)
69
70         res = self.ldb.search(expression="(objectClass=*)",
71                               base=dn,
72                               scope=SCOPE_BASE,
73                               controls=["show_deleted:1"],
74                               attrs=["*", "parentGUID"])
75         self.assertEquals(len(res), 1)
76         return res[0]
77
78
79 class BasicDeleteTests(BaseDeleteTests):
80
81     def setUp(self):
82         super(BasicDeleteTests, self).setUp()
83
84     def del_attr_values(self, delObj):
85         print("Checking attributes for %s" % delObj["dn"])
86
87         self.assertEquals(delObj["isDeleted"][0], "TRUE")
88         self.assertTrue(not("objectCategory" in delObj))
89         self.assertTrue(not("sAMAccountType" in delObj))
90
91     def preserved_attributes_list(self, liveObj, delObj):
92         print("Checking for preserved attributes list")
93
94         preserved_list = ["nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
95                           "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
96                           "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
97                           "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
98                           "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
99                           "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
100                           "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated"]
101
102         for a in liveObj:
103             if a in preserved_list:
104                 self.assertTrue(a in delObj)
105
106     def check_rdn(self, liveObj, delObj, rdnName):
107         print("Checking for correct rDN")
108         rdn = liveObj[rdnName][0]
109         rdn2 = delObj[rdnName][0]
110         name2 = delObj["name"][0]
111         dn_rdn = delObj.dn.get_rdn_value()
112         guid = liveObj["objectGUID"][0]
113         self.assertEquals(rdn2, rdn + "\nDEL:" + self.GUID_string(guid))
114         self.assertEquals(name2, rdn + "\nDEL:" + self.GUID_string(guid))
115         self.assertEquals(name2, dn_rdn)
116
117     def delete_deleted(self, ldb, dn):
118         print("Testing the deletion of the already deleted dn %s" % dn)
119
120         try:
121             ldb.delete(dn)
122             self.fail()
123         except LdbError as e:
124             (num, _) = e.args
125             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
126
127     def test_delete_protection(self):
128         """Delete protection tests"""
129
130         print(self.base_dn)
131
132         delete_force(self.ldb, "cn=entry1,cn=ldaptestcontainer," + self.base_dn)
133         delete_force(self.ldb, "cn=entry2,cn=ldaptestcontainer," + self.base_dn)
134         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
135
136         self.ldb.add({
137             "dn": "cn=ldaptestcontainer," + self.base_dn,
138             "objectclass": "container"})
139         self.ldb.add({
140             "dn": "cn=entry1,cn=ldaptestcontainer," + self.base_dn,
141             "objectclass": "container"})
142         self.ldb.add({
143             "dn": "cn=entry2,cn=ldaptestcontainer," + self.base_dn,
144             "objectclass": "container"})
145
146         try:
147             self.ldb.delete("cn=ldaptestcontainer," + self.base_dn)
148             self.fail()
149         except LdbError as e1:
150             (num, _) = e1.args
151             self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
152
153         self.ldb.delete("cn=ldaptestcontainer," + self.base_dn, ["tree_delete:1"])
154
155         try:
156             res = self.ldb.search("cn=ldaptestcontainer," + self.base_dn,
157                                   scope=SCOPE_BASE, attrs=[])
158             self.fail()
159         except LdbError as e2:
160             (num, _) = e2.args
161             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
162         try:
163             res = self.ldb.search("cn=entry1,cn=ldaptestcontainer," + self.base_dn,
164                                   scope=SCOPE_BASE, attrs=[])
165             self.fail()
166         except LdbError as e3:
167             (num, _) = e3.args
168             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
169         try:
170             res = self.ldb.search("cn=entry2,cn=ldaptestcontainer," + self.base_dn,
171                                   scope=SCOPE_BASE, attrs=[])
172             self.fail()
173         except LdbError as e4:
174             (num, _) = e4.args
175             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
176
177         delete_force(self.ldb, "cn=entry1,cn=ldaptestcontainer," + self.base_dn)
178         delete_force(self.ldb, "cn=entry2,cn=ldaptestcontainer," + self.base_dn)
179         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
180
181         # Performs some protected object delete testing
182
183         res = self.ldb.search(base="", expression="", scope=SCOPE_BASE,
184                               attrs=["dsServiceName", "dNSHostName"])
185         self.assertEquals(len(res), 1)
186
187         # Delete failing since DC's nTDSDSA object is protected
188         try:
189             self.ldb.delete(res[0]["dsServiceName"][0])
190             self.fail()
191         except LdbError as e5:
192             (num, _) = e5.args
193             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
194
195         res = self.ldb.search(self.base_dn, attrs=["rIDSetReferences"],
196                               expression="(&(objectClass=computer)(dNSHostName=" + res[0]["dNSHostName"][0] + "))")
197         self.assertEquals(len(res), 1)
198
199         # Deletes failing since DC's rIDSet object is protected
200         try:
201             self.ldb.delete(res[0]["rIDSetReferences"][0])
202             self.fail()
203         except LdbError as e6:
204             (num, _) = e6.args
205             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
206         try:
207             self.ldb.delete(res[0]["rIDSetReferences"][0], ["tree_delete:1"])
208             self.fail()
209         except LdbError as e7:
210             (num, _) = e7.args
211             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
212
213         # Deletes failing since three main crossRef objects are protected
214
215         try:
216             self.ldb.delete("cn=Enterprise Schema,cn=Partitions," + self.configuration_dn)
217             self.fail()
218         except LdbError as e8:
219             (num, _) = e8.args
220             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
221         try:
222             self.ldb.delete("cn=Enterprise Schema,cn=Partitions," + self.configuration_dn, ["tree_delete:1"])
223             self.fail()
224         except LdbError as e9:
225             (num, _) = e9.args
226             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
227
228         try:
229             self.ldb.delete("cn=Enterprise Configuration,cn=Partitions," + self.configuration_dn)
230             self.fail()
231         except LdbError as e10:
232             (num, _) = e10.args
233             self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
234         try:
235             self.ldb.delete("cn=Enterprise Configuration,cn=Partitions," + self.configuration_dn, ["tree_delete:1"])
236             self.fail()
237         except LdbError as e11:
238             (num, _) = e11.args
239             self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
240
241         res = self.ldb.search("cn=Partitions," + self.configuration_dn, attrs=[],
242                               expression="(nCName=%s)" % self.base_dn)
243         self.assertEquals(len(res), 1)
244
245         try:
246             self.ldb.delete(res[0].dn)
247             self.fail()
248         except LdbError as e12:
249             (num, _) = e12.args
250             self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
251         try:
252             self.ldb.delete(res[0].dn, ["tree_delete:1"])
253             self.fail()
254         except LdbError as e13:
255             (num, _) = e13.args
256             self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
257
258         # Delete failing since "SYSTEM_FLAG_DISALLOW_DELETE"
259         try:
260             self.ldb.delete("CN=Users," + self.base_dn)
261             self.fail()
262         except LdbError as e14:
263             (num, _) = e14.args
264             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
265
266         # Tree-delete failing since "isCriticalSystemObject"
267         try:
268             self.ldb.delete("CN=Computers," + self.base_dn, ["tree_delete:1"])
269             self.fail()
270         except LdbError as e15:
271             (num, _) = e15.args
272             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
273
274
275 class BasicTreeDeleteTests(BasicDeleteTests):
276
277     def setUp(self):
278         super(BasicTreeDeleteTests, self).setUp()
279
280         # user current time in ms to make unique objects
281         import time
282         marker = str(int(round(time.time() * 1000)))
283         usr1_name = "u_" + marker
284         usr2_name = "u2_" + marker
285         grp_name = "g1_" + marker
286         site_name = "s1_" + marker
287
288         self.usr1 = "cn=%s,cn=users,%s" % (usr1_name, self.base_dn)
289         self.usr2 = "cn=%s,cn=users,%s" % (usr2_name, self.base_dn)
290         self.grp1 = "cn=%s,cn=users,%s" % (grp_name, self.base_dn)
291         self.sit1 = "cn=%s,cn=sites,%s" % (site_name, self.configuration_dn)
292         self.ss1 = "cn=NTDS Site Settings,cn=%s,cn=sites,%s" % (site_name, self.configuration_dn)
293         self.srv1 = "cn=Servers,cn=%s,cn=sites,%s" % (site_name, self.configuration_dn)
294         self.srv2 = "cn=TESTSRV,cn=Servers,cn=%s,cn=sites,%s" % (site_name, self.configuration_dn)
295
296         delete_force(self.ldb, self.usr1)
297         delete_force(self.ldb, self.usr2)
298         delete_force(self.ldb, self.grp1)
299         delete_force(self.ldb, self.ss1)
300         delete_force(self.ldb, self.srv2)
301         delete_force(self.ldb, self.srv1)
302         delete_force(self.ldb, self.sit1)
303
304         self.ldb.add({
305             "dn": self.usr1,
306             "objectclass": "user",
307             "description": "test user description",
308             "samaccountname": usr1_name})
309
310         self.ldb.add({
311             "dn": self.usr2,
312             "objectclass": "user",
313             "description": "test user 2 description",
314             "samaccountname": usr2_name})
315
316         self.ldb.add({
317             "dn": self.grp1,
318             "objectclass": "group",
319             "description": "test group",
320             "samaccountname": grp_name,
321             "member": [self.usr1, self.usr2],
322             "isDeleted": "FALSE"})
323
324         self.ldb.add({
325             "dn": self.sit1,
326             "objectclass": "site"})
327
328         self.ldb.add({
329             "dn": self.ss1,
330             "objectclass": ["applicationSiteSettings", "nTDSSiteSettings"]})
331
332         self.ldb.add({
333             "dn": self.srv1,
334             "objectclass": "serversContainer"})
335
336         self.ldb.add({
337             "dn": self.srv2,
338             "objectClass": "server"})
339
340         self.objLive1 = self.search_dn(self.usr1)
341         self.guid1 = self.objLive1["objectGUID"][0]
342
343         self.objLive2 = self.search_dn(self.usr2)
344         self.guid2 = self.objLive2["objectGUID"][0]
345
346         self.objLive3 = self.search_dn(self.grp1)
347         self.guid3 = self.objLive3["objectGUID"][0]
348
349         self.objLive4 = self.search_dn(self.sit1)
350         self.guid4 = self.objLive4["objectGUID"][0]
351
352         self.objLive5 = self.search_dn(self.ss1)
353         self.guid5 = self.objLive5["objectGUID"][0]
354
355         self.objLive6 = self.search_dn(self.srv1)
356         self.guid6 = self.objLive6["objectGUID"][0]
357
358         self.objLive7 = self.search_dn(self.srv2)
359         self.guid7 = self.objLive7["objectGUID"][0]
360
361         self.deleted_objects_config_dn \
362             = self.ldb.get_wellknown_dn(self.ldb.get_config_basedn(),
363                                         dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER)
364         deleted_objects_config_obj \
365             = self.search_dn(self.deleted_objects_config_dn)
366
367         self.deleted_objects_config_guid \
368             = deleted_objects_config_obj["objectGUID"][0]
369
370         self.deleted_objects_domain_dn \
371             = self.ldb.get_wellknown_dn(self.ldb.get_default_basedn(),
372                                         dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER)
373         deleted_objects_domain_obj \
374             = self.search_dn(self.deleted_objects_domain_dn)
375
376         self.deleted_objects_domain_guid \
377             = deleted_objects_domain_obj["objectGUID"][0]
378
379         self.deleted_objects_domain_dn \
380             = self.ldb.get_wellknown_dn(self.ldb.get_default_basedn(),
381                                         dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER)
382         sites_obj = self.search_dn("cn=sites,%s" \
383                                    % self.ldb.get_config_basedn())
384         self.sites_dn = sites_obj.dn
385         self.sites_guid \
386             = sites_obj["objectGUID"][0]
387
388     def test_all(self):
389         """Basic delete tests"""
390
391         self.ldb.delete(self.usr1)
392         self.ldb.delete(self.usr2)
393         self.ldb.delete(self.grp1)
394         self.ldb.delete(self.srv1, ["tree_delete:1"])
395         self.ldb.delete(self.sit1, ["tree_delete:1"])
396
397         self.check_all()
398
399     def test_tree_delete(self):
400         """Basic delete tests,
401            but use just one tree delete for the config records
402         """
403
404         self.ldb.delete(self.usr1)
405         self.ldb.delete(self.usr2)
406         self.ldb.delete(self.grp1)
407         self.ldb.delete(self.sit1, ["tree_delete:1"])
408
409         self.check_all()
410
411     def check_all(self):
412         objDeleted1 = self.search_guid(self.guid1)
413         objDeleted2 = self.search_guid(self.guid2)
414         objDeleted3 = self.search_guid(self.guid3)
415         objDeleted4 = self.search_guid(self.guid4)
416         objDeleted5 = self.search_guid(self.guid5)
417         objDeleted6 = self.search_guid(self.guid6)
418         objDeleted7 = self.search_guid(self.guid7)
419
420         self.del_attr_values(objDeleted1)
421         self.del_attr_values(objDeleted2)
422         self.del_attr_values(objDeleted3)
423         self.del_attr_values(objDeleted4)
424         self.del_attr_values(objDeleted5)
425         self.del_attr_values(objDeleted6)
426         self.del_attr_values(objDeleted7)
427
428         self.preserved_attributes_list(self.objLive1, objDeleted1)
429         self.preserved_attributes_list(self.objLive2, objDeleted2)
430         self.preserved_attributes_list(self.objLive3, objDeleted3)
431         self.preserved_attributes_list(self.objLive4, objDeleted4)
432         self.preserved_attributes_list(self.objLive5, objDeleted5)
433         self.preserved_attributes_list(self.objLive6, objDeleted6)
434         self.preserved_attributes_list(self.objLive7, objDeleted7)
435
436         self.check_rdn(self.objLive1, objDeleted1, "cn")
437         self.check_rdn(self.objLive2, objDeleted2, "cn")
438         self.check_rdn(self.objLive3, objDeleted3, "cn")
439         self.check_rdn(self.objLive4, objDeleted4, "cn")
440         self.check_rdn(self.objLive5, objDeleted5, "cn")
441         self.check_rdn(self.objLive6, objDeleted6, "cn")
442         self.check_rdn(self.objLive7, objDeleted7, "cn")
443
444         self.delete_deleted(self.ldb, self.usr1)
445         self.delete_deleted(self.ldb, self.usr2)
446         self.delete_deleted(self.ldb, self.grp1)
447         self.delete_deleted(self.ldb, self.sit1)
448         self.delete_deleted(self.ldb, self.ss1)
449         self.delete_deleted(self.ldb, self.srv1)
450         self.delete_deleted(self.ldb, self.srv2)
451
452         self.assertTrue("CN=Deleted Objects" in str(objDeleted1.dn))
453         self.assertEqual(objDeleted1.dn.parent(),
454                          self.deleted_objects_domain_dn)
455         self.assertEqual(objDeleted1["parentGUID"][0],
456                          self.deleted_objects_domain_guid)
457
458         self.assertTrue("CN=Deleted Objects" in str(objDeleted2.dn))
459         self.assertEqual(objDeleted2.dn.parent(),
460                          self.deleted_objects_domain_dn)
461         self.assertEqual(objDeleted2["parentGUID"][0],
462                          self.deleted_objects_domain_guid)
463
464         self.assertTrue("CN=Deleted Objects" in str(objDeleted3.dn))
465         self.assertEqual(objDeleted3.dn.parent(),
466                          self.deleted_objects_domain_dn)
467         self.assertEqual(objDeleted3["parentGUID"][0],
468                          self.deleted_objects_domain_guid)
469
470         self.assertFalse("CN=Deleted Objects" in str(objDeleted4.dn))
471         self.assertEqual(objDeleted4.dn.parent(),
472                          self.sites_dn)
473         self.assertEqual(objDeleted4["parentGUID"][0],
474                          self.sites_guid)
475
476         self.assertTrue("CN=Deleted Objects" in str(objDeleted5.dn))
477         self.assertEqual(objDeleted5.dn.parent(),
478                          self.deleted_objects_config_dn)
479         self.assertEqual(objDeleted5["parentGUID"][0],
480                          self.deleted_objects_config_guid)
481
482         self.assertFalse("CN=Deleted Objects" in str(objDeleted6.dn))
483         self.assertEqual(objDeleted6.dn.parent(),
484                          objDeleted4.dn)
485         self.assertEqual(objDeleted6["parentGUID"][0],
486                          objDeleted4["objectGUID"][0])
487
488         self.assertFalse("CN=Deleted Objects" in str(objDeleted7.dn))
489         self.assertEqual(objDeleted7.dn.parent(),
490                          objDeleted6.dn)
491         self.assertEqual(objDeleted7["parentGUID"][0],
492                          objDeleted6["objectGUID"][0])
493
494         objDeleted1 = self.search_guid(self.guid1)
495         objDeleted2 = self.search_guid(self.guid2)
496         objDeleted3 = self.search_guid(self.guid3)
497         objDeleted4 = self.search_guid(self.guid4)
498         objDeleted5 = self.search_guid(self.guid5)
499         objDeleted6 = self.search_guid(self.guid6)
500         objDeleted7 = self.search_guid(self.guid7)
501
502         self.del_attr_values(objDeleted1)
503         self.del_attr_values(objDeleted2)
504         self.del_attr_values(objDeleted3)
505         self.del_attr_values(objDeleted4)
506         self.del_attr_values(objDeleted5)
507         self.del_attr_values(objDeleted6)
508         self.del_attr_values(objDeleted7)
509
510         self.preserved_attributes_list(self.objLive1, objDeleted1)
511         self.preserved_attributes_list(self.objLive2, objDeleted2)
512         self.preserved_attributes_list(self.objLive3, objDeleted3)
513         self.preserved_attributes_list(self.objLive4, objDeleted4)
514         self.preserved_attributes_list(self.objLive5, objDeleted5)
515         self.preserved_attributes_list(self.objLive6, objDeleted6)
516         self.preserved_attributes_list(self.objLive7, objDeleted7)
517
518         self.check_rdn(self.objLive1, objDeleted1, "cn")
519         self.check_rdn(self.objLive2, objDeleted2, "cn")
520         self.check_rdn(self.objLive3, objDeleted3, "cn")
521         self.check_rdn(self.objLive4, objDeleted4, "cn")
522         self.check_rdn(self.objLive5, objDeleted5, "cn")
523         self.check_rdn(self.objLive6, objDeleted6, "cn")
524         self.check_rdn(self.objLive7, objDeleted7, "cn")
525
526         self.delete_deleted(self.ldb, self.usr1)
527         self.delete_deleted(self.ldb, self.usr2)
528         self.delete_deleted(self.ldb, self.grp1)
529         self.delete_deleted(self.ldb, self.sit1)
530         self.delete_deleted(self.ldb, self.ss1)
531         self.delete_deleted(self.ldb, self.srv1)
532         self.delete_deleted(self.ldb, self.srv2)
533
534         self.assertTrue("CN=Deleted Objects" in str(objDeleted1.dn))
535         self.assertEqual(objDeleted1.dn.parent(),
536                          self.deleted_objects_domain_dn)
537         self.assertEqual(objDeleted1["parentGUID"][0],
538                          self.deleted_objects_domain_guid)
539         self.assertTrue("CN=Deleted Objects" in str(objDeleted2.dn))
540         self.assertEqual(objDeleted2.dn.parent(),
541                          self.deleted_objects_domain_dn)
542         self.assertEqual(objDeleted2["parentGUID"][0],
543                          self.deleted_objects_domain_guid)
544         self.assertTrue("CN=Deleted Objects" in str(objDeleted3.dn))
545         self.assertEqual(objDeleted3.dn.parent(),
546                          self.deleted_objects_domain_dn)
547         self.assertEqual(objDeleted3["parentGUID"][0],
548                          self.deleted_objects_domain_guid)
549         self.assertFalse("CN=Deleted Objects" in str(objDeleted4.dn))
550         self.assertTrue("CN=Deleted Objects" in str(objDeleted5.dn))
551         self.assertEqual(objDeleted5.dn.parent(),
552                          self.deleted_objects_config_dn)
553         self.assertEqual(objDeleted5["parentGUID"][0],
554                          self.deleted_objects_config_guid)
555         self.assertFalse("CN=Deleted Objects" in str(objDeleted6.dn))
556         self.assertFalse("CN=Deleted Objects" in str(objDeleted7.dn))
557
558
559 if not "://" in host:
560     if os.path.isfile(host):
561         host = "tdb://%s" % host
562     else:
563         host = "ldap://%s" % host
564
565 TestProgram(module=__name__, opts=subunitopts)