mirror of
https://github.com/samba-team/samba.git
synced 2025-01-26 10:04:02 +03:00
selftest: Windows resolves object conflicts differently to Samba
While testing link conflicts I noticed that Windows resolves conflicts differently to Samba. Samba considers the version number first when resolving the conflict, whereas Windows always takes the latest change. The existing object conflict test cases didn't detect this problem because they were both modifying the object the same number of times (so they had the same version number). I've added new tests that highlight the problem. They are basically the same as the existing rename tests, except that only one DC does the rename. Samba will always pick the renamed object as the winner, whereas Windows picks the most recent change. I've marked this test as a known fail for now. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13039 Signed-off-by: Tim Beale <timbeale@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
This commit is contained in:
parent
1b395f488a
commit
d278f5ea99
7
selftest/knownfail.d/replica_sync
Normal file
7
selftest/knownfail.d/replica_sync
Normal file
@ -0,0 +1,7 @@
|
||||
# Samba currently picks a different winner of object conflicts compared to Windows.
|
||||
# Samba uses the version number whereas Windows always takes the most recent change
|
||||
samba4.drs.replica_sync.python\(vampire_dc\).replica_sync.DrsReplicaSyncTestCase.test_ReplConflictsRenamedVsNewRemoteWin\(vampire_dc:local\)
|
||||
samba4.drs.replica_sync.python\(promoted_dc\).replica_sync.DrsReplicaSyncTestCase.test_ReplConflictsRenamedVsNewRemoteWin\(promoted_dc:local\)
|
||||
samba4.drs.replica_sync.python\(vampire_dc\).replica_sync.DrsReplicaSyncTestCase.test_ReplConflictsRenamedVsNewLocalWin\(vampire_dc:local\)
|
||||
samba4.drs.replica_sync.python\(promoted_dc\).replica_sync.DrsReplicaSyncTestCase.test_ReplConflictsRenamedVsNewLocalWin\(promoted_dc:local\)
|
||||
|
@ -298,6 +298,86 @@ objectClass: organizationalUnit
|
||||
self._check_deleted(self.ldb_dc2, ou1_child)
|
||||
self._check_deleted(self.ldb_dc2, ou2_child)
|
||||
|
||||
def test_ReplConflictsRenamedVsNewRemoteWin(self):
|
||||
"""Tests resolving a DN conflict between a renamed object and a new object"""
|
||||
self._disable_inbound_repl(self.dnsname_dc1)
|
||||
self._disable_inbound_repl(self.dnsname_dc2)
|
||||
|
||||
# Create an OU and rename it on DC1
|
||||
self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Remote Rename Conflict orig")
|
||||
self.ldb_dc1.rename("<GUID=%s>" % self.ou1, "OU=Test Remote Rename Conflict,%s" % self.domain_dn)
|
||||
|
||||
# We have to sleep to ensure that the two objects have different timestamps
|
||||
time.sleep(1)
|
||||
|
||||
# create a conflicting object with the same DN on DC2
|
||||
self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Remote Rename Conflict")
|
||||
|
||||
self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
|
||||
|
||||
# Check that DC2 got the DC1 object, and SELF.OU1 was made into conflict
|
||||
res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
|
||||
scope=SCOPE_BASE, attrs=["name"])
|
||||
res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
|
||||
scope=SCOPE_BASE, attrs=["name"])
|
||||
print res1[0]["name"][0]
|
||||
print res2[0]["name"][0]
|
||||
self.assertTrue('CNF:%s' % self.ou1 in str(res1[0]["name"][0]))
|
||||
self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
|
||||
self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
|
||||
self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
|
||||
self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
|
||||
|
||||
# Delete both objects by GUID on DC1
|
||||
self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
|
||||
self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
|
||||
|
||||
self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
|
||||
|
||||
self._check_deleted(self.ldb_dc1, self.ou1)
|
||||
self._check_deleted(self.ldb_dc1, self.ou2)
|
||||
# Check deleted on DC2
|
||||
self._check_deleted(self.ldb_dc2, self.ou1)
|
||||
self._check_deleted(self.ldb_dc2, self.ou2)
|
||||
|
||||
def test_ReplConflictsRenamedVsNewLocalWin(self):
|
||||
"""Tests resolving a DN conflict between a renamed object and a new object"""
|
||||
self._disable_inbound_repl(self.dnsname_dc1)
|
||||
self._disable_inbound_repl(self.dnsname_dc2)
|
||||
|
||||
# Create conflicting objects on DC1 and DC2, where the DC2 object has been renamed
|
||||
self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Rename Local Conflict orig")
|
||||
self.ldb_dc2.rename("<GUID=%s>" % self.ou2, "OU=Test Rename Local Conflict,%s" % self.domain_dn)
|
||||
# We have to sleep to ensure that the two objects have different timestamps
|
||||
time.sleep(1)
|
||||
self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Rename Local Conflict")
|
||||
|
||||
self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
|
||||
|
||||
# Check that DC2 got the DC1 object, and OU2 was made into conflict
|
||||
res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
|
||||
scope=SCOPE_BASE, attrs=["name"])
|
||||
res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
|
||||
scope=SCOPE_BASE, attrs=["name"])
|
||||
print res1[0]["name"][0]
|
||||
print res2[0]["name"][0]
|
||||
self.assertTrue('CNF:%s' % self.ou2 in str(res2[0]["name"][0]))
|
||||
self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
|
||||
self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
|
||||
self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
|
||||
self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
|
||||
|
||||
# Delete both objects by GUID on DC1
|
||||
self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
|
||||
self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
|
||||
|
||||
self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
|
||||
|
||||
self._check_deleted(self.ldb_dc1, self.ou1)
|
||||
self._check_deleted(self.ldb_dc1, self.ou2)
|
||||
# Check deleted on DC2
|
||||
self._check_deleted(self.ldb_dc2, self.ou1)
|
||||
self._check_deleted(self.ldb_dc2, self.ou2)
|
||||
|
||||
def test_ReplConflictsRenameRemoteWin(self):
|
||||
"""Tests that objects created in conflict become conflict DNs"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user