torture: Add tests of rename behaviour to replica_sync.py
[samba.git] / source4 / torture / drs / python / replica_sync.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Tests various schema replication scenarios
5 #
6 # Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21
22 #
23 # Usage:
24 #  export DC1=dc1_dns_name
25 #  export DC2=dc2_dns_name
26 #  export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
27 #  PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN replica_sync -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
28 #
29
30 import drs_base
31 import samba.tests
32
33 from ldb import (
34     SCOPE_BASE)
35
36 class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
37     """Intended as a black box test case for DsReplicaSync
38        implementation. It should test the behavior of this
39        case in cases when inbound replication is disabled"""
40
41     def setUp(self):
42         super(DrsReplicaSyncTestCase, self).setUp()
43
44     def tearDown(self):
45         # re-enable replication
46         self._enable_inbound_repl(self.dnsname_dc1)
47         self._enable_inbound_repl(self.dnsname_dc2)
48         super(DrsReplicaSyncTestCase, self).tearDown()
49
50     def test_ReplEnabled(self):
51         """Tests we can replicate when replication is enabled"""
52         self._enable_inbound_repl(self.dnsname_dc1)
53         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=False)
54
55     def test_ReplDisabled(self):
56         """Tests we cann't replicate when replication is disabled"""
57         self._disable_inbound_repl(self.dnsname_dc1)
58         try:
59             self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=False)
60         except samba.tests.BlackboxProcessError, e:
61             self.assertTrue('WERR_DS_DRA_SINK_DISABLED' in e.stderr)
62         else:
63             self.fail("'drs replicate' command should have failed!")
64
65     def test_ReplDisabledForced(self):
66         """Tests we can force replicate when replication is disabled"""
67         self._disable_inbound_repl(self.dnsname_dc1)
68         out = self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
69
70     def test_ReplLocal(self):
71         """Tests we can replicate direct to the local db"""
72         self._enable_inbound_repl(self.dnsname_dc1)
73         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=False, local=True, full_sync=True)
74
75     def _create_ou(self, samdb, name):
76         ldif = """
77 dn: %s,%s
78 objectClass: organizationalUnit
79 """ % (name, self.domain_dn)
80         samdb.add_ldif(ldif)
81         res = samdb.search(base="%s,%s" % (name, self.domain_dn),
82                            scope=SCOPE_BASE, attrs=["objectGUID"])
83         return self._GUID_string(res[0]["objectGUID"][0])
84
85     def _check_deleted(self, sam_ldb, guid):
86         # search the user by guid as it may be deleted
87         expression = "(objectGUID=%s)" % guid
88         res = sam_ldb.search(base=self.domain_dn,
89                              expression=expression,
90                              controls=["show_deleted:1"],
91                              attrs=["isDeleted", "objectCategory", "ou"])
92         self.assertEquals(len(res), 1)
93         ou_cur = res[0]
94         # Deleted Object base DN
95         dodn = self._deleted_objects_dn(sam_ldb)
96         # now check properties of the user
97         name_cur  = ou_cur["ou"][0]
98         self.assertEquals(ou_cur["isDeleted"][0],"TRUE")
99         self.assertTrue(not("objectCategory" in ou_cur))
100         self.assertTrue(dodn in str(ou_cur["dn"]),
101                         "OU %s is deleted but it is not located under %s!" % (name_cur, dodn))
102
103     def test_ReplConflictsFullSync(self):
104         """Tests that objects created in conflict become conflict DNs (honour full sync override)"""
105         self._disable_inbound_repl(self.dnsname_dc1)
106         self._disable_inbound_repl(self.dnsname_dc2)
107
108         # Create conflicting objects on DC1 and DC2, with DC1 object created first
109         ou1 = self._create_ou(self.ldb_dc1, "OU=Test Full Sync")
110         ou2 = self._create_ou(self.ldb_dc2, "OU=Test Full Sync")
111
112         self._enable_inbound_repl(self.dnsname_dc2)
113         self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, local=True, forced=True, full_sync=True)
114         self._disable_inbound_repl(self.dnsname_dc2)
115
116         # Check that DC2 got the DC1 object, and one or other object was make into conflict
117         res1 = self.ldb_dc2.search(base="<GUID=%s>" % ou1,
118                                   scope=SCOPE_BASE, attrs=["name"])
119         res2 = self.ldb_dc2.search(base="<GUID=%s>" % ou2,
120                                   scope=SCOPE_BASE, attrs=["name"])
121         print res1[0]["name"][0]
122         print res2[0]["name"][0]
123         self.assertTrue('CNF:%s' % ou1 in str(res1[0]["name"][0]) or 'CNF:%s' % ou2 in str(res2[0]["name"][0]))
124         self.assertTrue(self._lost_and_found_dn(self.ldb_dc2, self.domain_dn) not in str(res1[0].dn))
125         self.assertTrue(self._lost_and_found_dn(self.ldb_dc2, self.domain_dn) not in str(res2[0].dn))
126
127         # Delete both objects by GUID on DC1
128
129         self.ldb_dc2.delete('<GUID=%s>' % ou1)
130         self.ldb_dc2.delete('<GUID=%s>' % ou2)
131
132         self._enable_inbound_repl(self.dnsname_dc1)
133         self._enable_inbound_repl(self.dnsname_dc2)
134         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=True)
135
136         self._check_deleted(self.ldb_dc1, ou1)
137         self._check_deleted(self.ldb_dc1, ou2)
138         # Check deleted on DC2
139         self._check_deleted(self.ldb_dc2, ou1)
140         self._check_deleted(self.ldb_dc2, ou2)
141
142     def test_ReplConflictsRemoteWin(self):
143         """Tests that objects created in conflict become conflict DNs"""
144         self._disable_inbound_repl(self.dnsname_dc1)
145         self._disable_inbound_repl(self.dnsname_dc2)
146
147         # Create conflicting objects on DC1 and DC2, with DC1 object created first
148         ou1 = self._create_ou(self.ldb_dc1, "OU=Test Remote Conflict")
149         ou2 = self._create_ou(self.ldb_dc2, "OU=Test Remote Conflict")
150
151         self._enable_inbound_repl(self.dnsname_dc1)
152         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
153         self._disable_inbound_repl(self.dnsname_dc1)
154
155         # Check that DC2 got the DC1 object, and one or other object was make into conflict
156         res1 = self.ldb_dc1.search(base="<GUID=%s>" % ou1,
157                                   scope=SCOPE_BASE, attrs=["name"])
158         res2 = self.ldb_dc1.search(base="<GUID=%s>" % ou2,
159                                   scope=SCOPE_BASE, attrs=["name"])
160         print res1[0]["name"][0]
161         print res2[0]["name"][0]
162         self.assertTrue('CNF:%s' % ou1 in str(res1[0]["name"][0]) or 'CNF:%s' % ou2 in str(res2[0]["name"][0]))
163         self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
164         self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
165
166         # Delete both objects by GUID on DC1
167
168         self.ldb_dc1.delete('<GUID=%s>' % ou1)
169         self.ldb_dc1.delete('<GUID=%s>' % ou2)
170
171         self._enable_inbound_repl(self.dnsname_dc1)
172         self._enable_inbound_repl(self.dnsname_dc2)
173         self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
174
175         self._check_deleted(self.ldb_dc1, ou1)
176         self._check_deleted(self.ldb_dc1, ou2)
177         # Check deleted on DC2
178         self._check_deleted(self.ldb_dc2, ou1)
179         self._check_deleted(self.ldb_dc2, ou2)
180
181     def test_ReplConflictsLocalWin(self):
182         """Tests that objects created in conflict become conflict DNs"""
183         self._disable_inbound_repl(self.dnsname_dc1)
184         self._disable_inbound_repl(self.dnsname_dc2)
185
186         # Create conflicting objects on DC1 and DC2, with DC2 object created first
187         ou2 = self._create_ou(self.ldb_dc2, "OU=Test Local Conflict")
188         ou1 = self._create_ou(self.ldb_dc1, "OU=Test Local Conflict")
189
190         self._enable_inbound_repl(self.dnsname_dc1)
191         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
192         self._disable_inbound_repl(self.dnsname_dc1)
193
194         # Check that DC2 got the DC1 object, and one or other object was make into conflict
195         res1 = self.ldb_dc1.search(base="<GUID=%s>" % ou1,
196                                   scope=SCOPE_BASE, attrs=["name"])
197         res2 = self.ldb_dc1.search(base="<GUID=%s>" % ou2,
198                                   scope=SCOPE_BASE, attrs=["name"])
199         print res1[0]["name"][0]
200         print res2[0]["name"][0]
201         self.assertTrue('CNF:%s' % ou1 in str(res1[0]["name"][0]) or 'CNF:%s' % ou2 in str(res2[0]["name"][0]))
202         self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
203         self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
204
205         # Delete both objects by GUID on DC1
206
207         self.ldb_dc1.delete('<GUID=%s>' % ou1)
208         self.ldb_dc1.delete('<GUID=%s>' % ou2)
209
210         self._enable_inbound_repl(self.dnsname_dc1)
211         self._enable_inbound_repl(self.dnsname_dc2)
212         self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
213
214         self._check_deleted(self.ldb_dc1, ou1)
215         self._check_deleted(self.ldb_dc1, ou2)
216         # Check deleted on DC2
217         self._check_deleted(self.ldb_dc2, ou1)
218         self._check_deleted(self.ldb_dc2, ou2)
219
220     def test_ReplConflictsRenameRemoteWin(self):
221         """Tests that objects created in conflict become conflict DNs"""
222         self._disable_inbound_repl(self.dnsname_dc1)
223         self._disable_inbound_repl(self.dnsname_dc2)
224
225         # Create conflicting objects on DC1 and DC2, with DC1 object created first
226         ou1 = self._create_ou(self.ldb_dc1, "OU=Test Remote Rename Conflict")
227         ou2 = self._create_ou(self.ldb_dc2, "OU=Test Remote Rename Conflict 2")
228
229         self._enable_inbound_repl(self.dnsname_dc1)
230         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
231         self._disable_inbound_repl(self.dnsname_dc1)
232
233         self.ldb_dc1.rename("<GUID=%s>" % ou1, "OU=Test Remote Rename Conflict 3,%s" % self.domain_dn)
234         self.ldb_dc2.rename("<GUID=%s>" % ou2, "OU=Test Remote Rename Conflict 3,%s" % self.domain_dn)
235
236         self._enable_inbound_repl(self.dnsname_dc1)
237         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
238         self._disable_inbound_repl(self.dnsname_dc1)
239
240         # Check that DC2 got the DC1 object, and one or other object was make into conflict
241         res1 = self.ldb_dc1.search(base="<GUID=%s>" % ou1,
242                                   scope=SCOPE_BASE, attrs=["name"])
243         res2 = self.ldb_dc1.search(base="<GUID=%s>" % ou2,
244                                   scope=SCOPE_BASE, attrs=["name"])
245         print res1[0]["name"][0]
246         print res2[0]["name"][0]
247         self.assertTrue('CNF:%s' % ou1 in str(res1[0]["name"][0]) or 'CNF:%s' % ou2 in str(res2[0]["name"][0]))
248         self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
249         self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
250
251         # Delete both objects by GUID on DC1
252
253         self.ldb_dc1.delete('<GUID=%s>' % ou1)
254         self.ldb_dc1.delete('<GUID=%s>' % ou2)
255
256         self._enable_inbound_repl(self.dnsname_dc1)
257         self._enable_inbound_repl(self.dnsname_dc2)
258         self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
259
260         self._check_deleted(self.ldb_dc1, ou1)
261         self._check_deleted(self.ldb_dc1, ou2)
262         # Check deleted on DC2
263         self._check_deleted(self.ldb_dc2, ou1)
264         self._check_deleted(self.ldb_dc2, ou2)
265
266     def test_ReplConflictsRenameLocalWin(self):
267         """Tests that objects created in conflict become conflict DNs"""
268         self._disable_inbound_repl(self.dnsname_dc1)
269         self._disable_inbound_repl(self.dnsname_dc2)
270
271         # Create conflicting objects on DC1 and DC2, with DC1 object created first
272         ou1 = self._create_ou(self.ldb_dc1, "OU=Test Rename Local Conflict")
273         ou2 = self._create_ou(self.ldb_dc2, "OU=Test Rename Local Conflict 2")
274
275         self._enable_inbound_repl(self.dnsname_dc1)
276         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
277         self._disable_inbound_repl(self.dnsname_dc1)
278
279         self.ldb_dc2.rename("<GUID=%s>" % ou2, "OU=Test Rename Local Conflict 3,%s" % self.domain_dn)
280         self.ldb_dc1.rename("<GUID=%s>" % ou1, "OU=Test Rename Local Conflict 3,%s" % self.domain_dn)
281
282         self._enable_inbound_repl(self.dnsname_dc1)
283         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
284         self._disable_inbound_repl(self.dnsname_dc1)
285
286         # Check that DC2 got the DC1 object, and one or other object was make into conflict
287         res1 = self.ldb_dc1.search(base="<GUID=%s>" % ou1,
288                                   scope=SCOPE_BASE, attrs=["name"])
289         res2 = self.ldb_dc1.search(base="<GUID=%s>" % ou2,
290                                   scope=SCOPE_BASE, attrs=["name"])
291         print res1[0]["name"][0]
292         print res2[0]["name"][0]
293         self.assertTrue('CNF:%s' % ou1 in str(res1[0]["name"][0]) or 'CNF:%s' % ou2 in str(res2[0]["name"][0]))
294         self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
295         self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
296
297         # Delete both objects by GUID on DC1
298
299         self.ldb_dc1.delete('<GUID=%s>' % ou1)
300         self.ldb_dc1.delete('<GUID=%s>' % ou2)
301
302         self._enable_inbound_repl(self.dnsname_dc1)
303         self._enable_inbound_repl(self.dnsname_dc2)
304         self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
305
306         self._check_deleted(self.ldb_dc1, ou1)
307         self._check_deleted(self.ldb_dc1, ou2)
308         # Check deleted on DC2
309         self._check_deleted(self.ldb_dc2, ou1)
310         self._check_deleted(self.ldb_dc2, ou2)
311
312     def test_ReplLostAndFound(self):
313         """Tests that objects created under a OU deleted eleswhere end up in lostAndFound"""
314         self._disable_inbound_repl(self.dnsname_dc1)
315         self._disable_inbound_repl(self.dnsname_dc2)
316
317         # Create two OUs on DC2
318         ou1 = self._create_ou(self.ldb_dc2, "OU=Deleted parent")
319         ou2 = self._create_ou(self.ldb_dc2, "OU=Deleted parent 2")
320
321         # replicate them from DC2 to DC1
322         self._enable_inbound_repl(self.dnsname_dc1)
323         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
324         self._disable_inbound_repl(self.dnsname_dc1)
325
326         # Delete both objects by GUID on DC1
327
328         self.ldb_dc1.delete('<GUID=%s>' % ou1)
329         self.ldb_dc1.delete('<GUID=%s>' % ou2)
330
331         # Create children on DC2
332         ou1_child = self._create_ou(self.ldb_dc2, "OU=Test Child,OU=Deleted parent")
333         ou2_child = self._create_ou(self.ldb_dc2, "OU=Test Child,OU=Deleted parent 2")
334
335         # Replicate from DC2
336         self._enable_inbound_repl(self.dnsname_dc1)
337         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
338         self._disable_inbound_repl(self.dnsname_dc1)
339
340         # Check the sub-OUs are now in lostAndFound and the first one is a conflict DN
341
342         # Check that DC2 got the DC1 object, and one or other object was make into conflict
343         res1 = self.ldb_dc1.search(base="<GUID=%s>" % ou1_child,
344                                   scope=SCOPE_BASE, attrs=["name"])
345         res2 = self.ldb_dc1.search(base="<GUID=%s>" % ou2_child,
346                                   scope=SCOPE_BASE, attrs=["name"])
347         print res1[0]["name"][0]
348         print res2[0]["name"][0]
349         self.assertTrue('CNF:%s' % ou1_child in str(res1[0]["name"][0]) or 'CNF:%s' % ou2_child in str(res2[0]["name"][0]))
350         self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) in str(res1[0].dn))
351         self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) in str(res2[0].dn))
352
353         # Delete all objects by GUID on DC1
354
355         self.ldb_dc1.delete('<GUID=%s>' % ou1_child)
356         self.ldb_dc1.delete('<GUID=%s>' % ou2_child)
357
358         self._enable_inbound_repl(self.dnsname_dc1)
359         self._enable_inbound_repl(self.dnsname_dc2)
360         self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
361
362
363         # Check all deleted on DC1
364         self._check_deleted(self.ldb_dc1, ou1)
365         self._check_deleted(self.ldb_dc1, ou2)
366         self._check_deleted(self.ldb_dc1, ou1_child)
367         self._check_deleted(self.ldb_dc1, ou2_child)
368         # Check all deleted on DC2
369         self._check_deleted(self.ldb_dc2, ou1)
370         self._check_deleted(self.ldb_dc2, ou2)
371         self._check_deleted(self.ldb_dc2, ou1_child)
372         self._check_deleted(self.ldb_dc2, ou2_child)
373
374     def test_ReplRenames(self):
375         """Tests that objects created under a OU deleted eleswhere end up in lostAndFound"""
376         self._disable_inbound_repl(self.dnsname_dc1)
377         self._disable_inbound_repl(self.dnsname_dc2)
378
379         # Create two OUs on DC2
380         ou1 = self._create_ou(self.ldb_dc2, "OU=Original parent")
381         ou2 = self._create_ou(self.ldb_dc2, "OU=Original parent 2")
382
383         # replicate them from DC2 to DC1
384         self._enable_inbound_repl(self.dnsname_dc1)
385         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
386         self._disable_inbound_repl(self.dnsname_dc1)
387
388         # Create children on DC1
389         ou1_child = self._create_ou(self.ldb_dc1, "OU=Test Child,OU=Original parent")
390         ou2_child = self._create_ou(self.ldb_dc1, "OU=Test Child 2,OU=Original parent")
391         ou3_child = self._create_ou(self.ldb_dc1, "OU=Test Case Child,OU=Original parent")
392
393         # replicate them from DC1 to DC2
394         self._enable_inbound_repl(self.dnsname_dc2)
395         self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
396         self._disable_inbound_repl(self.dnsname_dc2)
397
398         self.ldb_dc1.rename("<GUID=%s>" % ou2_child, "OU=Test Child 3,OU=Original parent 2,%s" % self.domain_dn)
399         self.ldb_dc1.rename("<GUID=%s>" % ou1_child, "OU=Test Child 2,OU=Original parent 2,%s" % self.domain_dn)
400         self.ldb_dc1.rename("<GUID=%s>" % ou2_child, "OU=Test Child,OU=Original parent 2,%s" % self.domain_dn)
401         self.ldb_dc1.rename("<GUID=%s>" % ou3_child, "OU=Test CASE Child,OU=Original parent,%s" % self.domain_dn)
402         self.ldb_dc2.rename("<GUID=%s>" % ou2, "OU=Original parent 3,%s" % self.domain_dn)
403         self.ldb_dc2.rename("<GUID=%s>" % ou1, "OU=Original parent 2,%s" % self.domain_dn)
404
405         # replicate them from DC1 to DC2
406         self._enable_inbound_repl(self.dnsname_dc2)
407         self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
408         self._disable_inbound_repl(self.dnsname_dc2)
409
410         # Check the sub-OUs are now under Original Parent 3 (original
411         # parent 2 for Test CASE Child), and both have the right names
412
413         # Check that DC2 got the DC1 object, and the renames are all correct
414         res1 = self.ldb_dc2.search(base="<GUID=%s>" % ou1_child,
415                                   scope=SCOPE_BASE, attrs=["name"])
416         res2 = self.ldb_dc2.search(base="<GUID=%s>" % ou2_child,
417                                   scope=SCOPE_BASE, attrs=["name"])
418         res3 = self.ldb_dc2.search(base="<GUID=%s>" % ou3_child,
419                                   scope=SCOPE_BASE, attrs=["name"])
420         print res1[0].dn
421         print res2[0].dn
422         print res3[0].dn
423         self.assertEqual('Test Child 2', res1[0]["name"][0])
424         self.assertEqual('Test Child', res2[0]["name"][0])
425         self.assertEqual('Test CASE Child', res3[0]["name"][0])
426         self.assertEqual(str(res1[0].dn), "OU=Test Child 2,OU=Original parent 3,%s" % self.domain_dn)
427         self.assertEqual(str(res2[0].dn), "OU=Test Child,OU=Original parent 3,%s" % self.domain_dn)
428         self.assertEqual(str(res3[0].dn), "OU=Test CASE Child,OU=Original parent 2,%s" % self.domain_dn)
429
430         # replicate them from DC2 to DC1
431         self._enable_inbound_repl(self.dnsname_dc1)
432         self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
433         self._disable_inbound_repl(self.dnsname_dc1)
434
435         # Check that DC1 got the DC2 object, and the renames are all correct
436         res1 = self.ldb_dc1.search(base="<GUID=%s>" % ou1_child,
437                                   scope=SCOPE_BASE, attrs=["name"])
438         res2 = self.ldb_dc1.search(base="<GUID=%s>" % ou2_child,
439                                   scope=SCOPE_BASE, attrs=["name"])
440         res3 = self.ldb_dc1.search(base="<GUID=%s>" % ou3_child,
441                                   scope=SCOPE_BASE, attrs=["name"])
442         print res1[0].dn
443         print res2[0].dn
444         print res3[0].dn
445         self.assertEqual('Test Child 2', res1[0]["name"][0])
446         self.assertEqual('Test Child', res2[0]["name"][0])
447         self.assertEqual('Test CASE Child', res3[0]["name"][0])
448         self.assertEqual(str(res1[0].dn), "OU=Test Child 2,OU=Original parent 3,%s" % self.domain_dn)
449         self.assertEqual(str(res2[0].dn), "OU=Test Child,OU=Original parent 3,%s" % self.domain_dn)
450         self.assertEqual(str(res3[0].dn), "OU=Test CASE Child,OU=Original parent 2,%s" % self.domain_dn)
451
452         # Delete all objects by GUID on DC1
453
454         self.ldb_dc1.delete('<GUID=%s>' % ou1_child)
455         self.ldb_dc1.delete('<GUID=%s>' % ou2_child)
456         self.ldb_dc1.delete('<GUID=%s>' % ou3_child)
457         self.ldb_dc1.delete('<GUID=%s>' % ou1)
458         self.ldb_dc1.delete('<GUID=%s>' % ou2)
459
460         self._enable_inbound_repl(self.dnsname_dc1)
461         self._enable_inbound_repl(self.dnsname_dc2)
462         self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
463
464
465         # Check all deleted on DC1
466         self._check_deleted(self.ldb_dc1, ou1)
467         self._check_deleted(self.ldb_dc1, ou2)
468         self._check_deleted(self.ldb_dc1, ou1_child)
469         self._check_deleted(self.ldb_dc1, ou2_child)
470         self._check_deleted(self.ldb_dc1, ou3_child)
471         # Check all deleted on DC2
472         self._check_deleted(self.ldb_dc2, ou1)
473         self._check_deleted(self.ldb_dc2, ou2)
474         self._check_deleted(self.ldb_dc2, ou1_child)
475         self._check_deleted(self.ldb_dc2, ou2_child)
476         self._check_deleted(self.ldb_dc2, ou3_child)