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