From becf36cba38a762b3d9ee0b9d014c9db7330ebee Mon Sep 17 00:00:00 2001
From: ludovicp <ludovicp@localhost>
Date: Mon, 31 May 2010 09:49:21 +0000
Subject: [PATCH] Fix issue #3891 - Handle replication conflict when adding child entry and parent is deleted
---
opendj-sdk/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java | 27 +--
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java | 21 ++
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java | 18 +
opendj-sdk/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java | 63 ++++++++
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java | 281 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 374 insertions(+), 36 deletions(-)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index e472a43..f887c0a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -77,7 +77,6 @@
import org.opends.server.backends.jeb.BackendImpl;
import org.opends.server.backends.task.Task;
import org.opends.server.config.ConfigException;
-import org.opends.server.controls.SubtreeDeleteControl;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
@@ -2564,11 +2563,10 @@
/*
* Create a new operation as the ConflictResolution
* different operation.
+ * Note: When msg is a DeleteMsg, the DeleteOperation is properly
+ * created with subtreeDelete request control when needed.
*/
op = msg.createOperation(conn);
- if (op instanceof DeleteOperation) {
- op.addRequestControl(new SubtreeDeleteControl(false));
- }
}
}
else
@@ -3189,21 +3187,14 @@
for (SearchResultEntry entry : entries)
{
/*
- * Check the ADD and ModRDN date of the child entry. If it is after
- * the delete date then keep the entry as a conflicting entry,
- * otherwise delete the entry with the operation.
+ * Check the ADD and ModRDN date of the child entry (All of them,
+ * not only the one that are newer than the DEL op)
+ * and keep the entry as a conflicting entry,
*/
- if (cn != null)
- {
- Historical hist = Historical.load(entry);
- if (hist.AddedOrRenamedAfter(cn))
- {
- conflict = true;
- markConflictEntry(conflictOp, entry.getDN(), entryDN);
- renameConflictEntry(conflictOp, entry.getDN(),
- Historical.getEntryUuid(entry));
- }
- }
+ conflict = true;
+ markConflictEntry(conflictOp, entry.getDN(), entryDN);
+ renameConflictEntry(conflictOp, entry.getDN(),
+ Historical.getEntryUuid(entry));
}
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java b/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java
index 4068db1..7e8c1cf 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2006-2009 Sun Microsystems, Inc.
+ * Copyright 2006-2010 Sun Microsystems, Inc.
*/
package org.opends.server.replication.protocol;
@@ -31,6 +31,7 @@
import java.io.UnsupportedEncodingException;
import java.util.zip.DataFormatException;
+import org.opends.server.controls.SubtreeDeleteControl;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.common.ChangeNumber;
@@ -43,7 +44,10 @@
*/
public class DeleteMsg extends LDAPUpdateMsg
{
- String initiatorsName;
+ private String initiatorsName;
+
+ // whether the DEL operation is a subtree DEL
+ private boolean isSubtreeDelete = false;
/**
* Creates a new delete message.
@@ -54,15 +58,23 @@
{
super((OperationContext) operation.getAttachment(SYNCHROCONTEXT),
operation.getRawEntryDN().toString());
+ try
+ {
+ if (operation.getRequestControl(SubtreeDeleteControl.DECODER) != null)
+ isSubtreeDelete = true;
+ }
+ catch(Exception e)
+ {}
+
}
/**
* Creates a new delete message.
*
- * @param dn The dn with which the message must be created.
+ * @param dn The dn with which the message must be created.
* @param changeNumber The change number with which the message must be
* created.
- * @param uid The unique id with which the message must be created.
+ * @param uid The unique id with which the message must be created.
*/
public DeleteMsg(String dn, ChangeNumber changeNumber, String uid)
{
@@ -87,6 +99,12 @@
// protocol version has been read as part of the header
if (protocolVersion >= 4)
decodeBody_V4(in, pos);
+ else
+ {
+ // Keep the previous protocol version behavior - when we don't know the
+ // truth, we assume 'subtree'
+ isSubtreeDelete = true;
+ }
}
@@ -101,6 +119,10 @@
InternalClientConnection.nextOperationID(),
InternalClientConnection.nextMessageID(), null,
ByteString.valueOf(newDn));
+
+ if (isSubtreeDelete)
+ del.addRequestControl(new SubtreeDeleteControl(false));
+
DeleteContext ctx = new DeleteContext(getChangeNumber(), getUniqueId());
del.setAttachment(SYNCHROCONTEXT, ctx);
return del;
@@ -152,6 +174,8 @@
{
bodyLength++;
}
+ // subtree flag
+ bodyLength++;
/* encode the header in a byte[] large enough to also contain the mods */
byte [] encodedMsg = encodeHeader(MSG_TYPE_DELETE, bodyLength,
@@ -163,6 +187,9 @@
encodedMsg[pos++] = 0;
pos = addByteArray(byteEntryAttrLen, encodedMsg, pos);
pos = addByteArray(encodedEclIncludes, encodedMsg, pos);
+
+ encodedMsg[pos++] = (isSubtreeDelete ? (byte) 1 : (byte) 0);
+
return encodedMsg;
}
@@ -173,7 +200,6 @@
private void decodeBody_V4(byte[] in, int pos)
throws DataFormatException, UnsupportedEncodingException
{
- // Read ecl attr len
int length = getNextLength(in, pos);
if (length != 0)
{
@@ -185,15 +211,21 @@
initiatorsName = null;
pos += 1;
}
+
+ // Read ecl attr len
length = getNextLength(in, pos);
int eclAttrLen = Integer.valueOf(new String(in, pos, length,"UTF-8"));
+ // Skip the length
pos += length + 1;
// Read/Don't decode entry attributes
encodedEclIncludes = new byte[eclAttrLen];
try
{
+ // Copy ecl attr
System.arraycopy(in, pos, encodedEclIncludes, 0, eclAttrLen);
+ // Skip the attrs
+ pos += eclAttrLen +1;
} catch (IndexOutOfBoundsException e)
{
throw new DataFormatException(e.getMessage());
@@ -204,6 +236,10 @@
{
throw new DataFormatException(e.getMessage());
}
+
+ // subtree flag
+ isSubtreeDelete = (in[pos] == 1);
+
}
/**
@@ -263,4 +299,21 @@
return initiatorsName;
}
+ /**
+ * Set the subtree flag.
+ * @param subtreeDelete the subtree flag.
+ */
+ public void setSubtreeDelete(boolean subtreeDelete)
+ {
+ this.isSubtreeDelete = subtreeDelete;
+ }
+
+ /**
+ * Get the subtree flag.
+ * @return the subtree flag.
+ */
+ public boolean isSubtreeDelete()
+ {
+ return this.isSubtreeDelete;
+ }
}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
index e98164b..b26d5ca 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2006-2009 Sun Microsystems, Inc.
+ * Copyright 2006-2010 Sun Microsystems, Inc.
*/
package org.opends.server.replication;
@@ -1194,12 +1194,18 @@
assertNull(getEntry(DN.decode(domain1dn), 10000, false),
"The DELETE replication message was not replayed");
- // check that domain2 and domain3 have not been renamed as conflicting
- assertNull(getEntry(conflictDomain2dn, 10000, true),
- "The conflicting entries were created");
- assertNull(getEntry(conflictDomain3dn, 10000, true),
- "The conflicting entries were created");
+ // check that domain2 and domain3 have been renamed as conflicting
+ String confDomain2dn = "entryuuid="+domain2uid+"+dc=domain2,ou=people,"+TEST_ROOT_DN_STRING;
+ String confDomain3dn = "entryuuid="+domain3uid+"+dc=domain3,ou=people,"+TEST_ROOT_DN_STRING;
+ assertTrue(DirectoryServer.entryExists(DN.decode(confDomain2dn)),
+ "The conflicting entry exist for domain2" + confDomain2dn);
+ assertTrue(DirectoryServer.entryExists(DN.decode(confDomain3dn)),
+ "The conflicting entry exist for domain3" + confDomain3dn);
+ // check that unresolved conflict count has been incremented
+ assertEquals(getMonitorDelta(), 1);
+ delEntry(DN.decode(confDomain2dn));
+ delEntry(DN.decode(confDomain3dn));
//
// Check that when an entry is added on one master below an entry
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java
index be76ec6..1977ed7 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java
@@ -22,12 +22,13 @@
* CDDL HEADER END
*
*
- * Copyright 2009 Sun Microsystems, Inc.
+ * Copyright 2009-2010 Sun Microsystems, Inc.
*/
package org.opends.server.replication.plugin;
import static org.opends.server.TestCaseUtils.TEST_ROOT_DN_STRING;
+import java.util.ArrayList;
import java.util.TreeSet;
import org.opends.server.TestCaseUtils;
@@ -36,7 +37,10 @@
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
+import org.opends.server.replication.protocol.AddMsg;
import org.opends.server.replication.protocol.ModifyDNMsg;
+import org.opends.server.replication.protocol.DeleteMsg;
+import org.opends.server.types.Attribute;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.testng.annotations.Test;
@@ -113,7 +117,10 @@
TEST_ROOT_DN_STRING,
"uid=simultaneous2");
+ // Put the message in the replay queue
domain.processUpdate(modDnMsg);
+
+ // Make the domain replay the change from the replay queue
domain.replay(queue.take().getUpdateMessage());
// This MODIFY DN uses an older DN and should therefore be cancelled
@@ -124,9 +131,14 @@
TEST_ROOT_DN_STRING,
"uid=simulatneouswrong");
+ // Put the message in the replay queue
domain.processUpdate(modDnMsg);
+
+ // Make the domain replay the change from the replay queue
+ // and resolve conflict
domain.replay(queue.take().getUpdateMessage());
+ // Expect the conflict resolution
assertFalse(DirectoryServer.entryExists(entry.getDN()),
"The modDN conflict was not resolved as expected.");
}
@@ -135,4 +147,271 @@
MultimasterReplication.deleteDomain(baseDn);
}
}
+
+ /**
+ * Tests for issue 3891
+ * S1 S2
+ * ADD uid=xx,ou=parent,... [SUBTREE] DEL ou=parent, ...
+ *
+ * 1/ removeParentConflict1 (on S1)
+ * - t1(cn1) ADD uid=xx,ou=parent,...
+ * - t2(cn2) replay SUBTREE DEL ou=parent, ....
+ * => No conflict : expect the parent entry & subtree to be deleted
+ *
+ * 2/ removeParentConflict2 (on S1)
+ * - t1(cn1) ADD uid=xx,ou=parent,...
+ * - replay t2(cn2) DEL ou=parent, ....
+ * => Conflict and no automatic resolution: expect
+ * - the child entry to be renamed under root entry
+ * - the parent entry to be deleted
+ *
+ * 3/ removeParentConflict3 (on S2)
+ * - t2(cn2) DEL or SUBTREE DEL ou=parent, ....
+ * - t1(cn1) replay ADD uid=xx,ou=parent,...
+ * => Conflict and no automatic resolution: expect
+ * - the child entry to be renamed under root entry
+ *
+ */
+ @Test(enabled=true)
+ public void removeParentConflict1() throws Exception
+ {
+ TestCaseUtils.initializeTestBackend(true);
+
+ final DN baseDn = DN.decode(TEST_ROOT_DN_STRING);
+
+ TestSynchronousReplayQueue queue = new TestSynchronousReplayQueue();
+ DomainFakeCfg conf = new DomainFakeCfg(baseDn, 1, new TreeSet<String>());
+ conf.setIsolationPolicy(IsolationPolicy.ACCEPT_ALL_UPDATES);
+
+ LDAPReplicationDomain domain =
+ MultimasterReplication.createNewDomain(conf, queue);
+ domain.start();
+
+ try
+ {
+ /*
+ * Create a Change number generator to generate new ChangeNumbers
+ * when we need to send operations messages to the replicationServer.
+ */
+ ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
+
+ Entry parentEntry = TestCaseUtils.entryFromLdifString(
+ "dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
+ + "objectClass: top\n"
+ + "objectClass: organizationalUnit\n");
+
+ Entry childEntry = TestCaseUtils.entryFromLdifString(
+ "dn: cn=child, ou=rpConflict,"+ TEST_ROOT_DN_STRING + "\n"
+ + "objectClass: top\n"
+ + "objectClass: person\n"
+ + "objectClass: organizationalPerson\n"
+ + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
+ + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
+ + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
+ + "$Rockford, NC 85762\n" + "mail: user.1@example.com\n"
+ + "cn: Aaccf Amar\n" + "l: Rockford\n"
+ + "street: 17984 Thirteenth Street\n"
+ + "employeeNumber: 1\n"
+ + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
+ + "userPassword: password\n" + "initials: AA\n");
+
+ TestCaseUtils.addEntry(parentEntry);
+ TestCaseUtils.addEntry(childEntry);
+
+ String parentUUID = getEntryUUID(parentEntry.getDN());
+ String childUUID = getEntryUUID(childEntry.getDN());
+
+ ChangeNumber cn2 = gen.newChangeNumber();
+
+ DeleteMsg delMsg = new DeleteMsg(
+ parentEntry.getDN().toNormalizedString(),
+ cn2,
+ parentUUID);
+ delMsg.setSubtreeDelete(true);
+
+ // Put the message in the replay queue
+ domain.processUpdate(delMsg);
+ // Make the domain replay the change from the replay queue
+ domain.replay(queue.take().getUpdateMessage());
+
+ // Expect the subtree to be deleted and no conflict entry created
+ assertFalse(DirectoryServer.entryExists(parentEntry.getDN()),
+ "DEL subtree on parent was not processed as expected.");
+ assertFalse(DirectoryServer.entryExists(parentEntry.getDN()),
+ "DEL subtree on parent was not processed as expected.");
+ }
+ finally
+ {
+ MultimasterReplication.deleteDomain(baseDn);
+ }
+ }
+
+ @Test(enabled=true)
+ public void removeParentConflict2() throws Exception
+ {
+ TestCaseUtils.initializeTestBackend(true);
+
+ final DN baseDn = DN.decode(TEST_ROOT_DN_STRING);
+
+ TestSynchronousReplayQueue queue = new TestSynchronousReplayQueue();
+ DomainFakeCfg conf = new DomainFakeCfg(baseDn, 1, new TreeSet<String>());
+ conf.setIsolationPolicy(IsolationPolicy.ACCEPT_ALL_UPDATES);
+
+ LDAPReplicationDomain domain =
+ MultimasterReplication.createNewDomain(conf, queue);
+ domain.start();
+
+ try
+ {
+ /*
+ * Create a Change number generator to generate new ChangeNumbers
+ * when we need to send operations messages to the replicationServer.
+ */
+ ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
+
+ Entry parentEntry = TestCaseUtils.entryFromLdifString(
+ "dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
+ + "objectClass: top\n"
+ + "objectClass: organizationalUnit\n");
+
+ Entry childEntry = TestCaseUtils.entryFromLdifString(
+ "dn: cn=child, ou=rpConflict,"+ TEST_ROOT_DN_STRING + "\n"
+ + "objectClass: top\n"
+ + "objectClass: person\n"
+ + "objectClass: organizationalPerson\n"
+ + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
+ + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
+ + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
+ + "$Rockford, NC 85762\n" + "mail: user.1@example.com\n"
+ + "cn: Aaccf Amar\n" + "l: Rockford\n"
+ + "street: 17984 Thirteenth Street\n"
+ + "employeeNumber: 1\n"
+ + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
+ + "userPassword: password\n" + "initials: AA\n");
+
+ TestCaseUtils.addEntry(parentEntry);
+ TestCaseUtils.addEntry(childEntry);
+
+ assertTrue(DirectoryServer.entryExists(parentEntry.getDN()),
+ "Parent entry expected to exist.");
+ assertTrue(DirectoryServer.entryExists(childEntry.getDN()),
+ "Child entry expected to be exist.");
+
+ String parentUUID = getEntryUUID(parentEntry.getDN());
+ String childUUID = getEntryUUID(childEntry.getDN());
+
+ ChangeNumber cn2 = gen.newChangeNumber();
+
+ DeleteMsg delMsg = new DeleteMsg(
+ parentEntry.getDN().toNormalizedString(),
+ cn2,
+ parentUUID);
+ // NOT SUBTREE
+
+ // Put the message in the replay queue
+ domain.processUpdate(delMsg);
+ // Make the domain replay the change from the replay queue
+ domain.replay(queue.take().getUpdateMessage());
+
+ // Expect the parent entry to be deleted
+ assertTrue(!DirectoryServer.entryExists(parentEntry.getDN()),
+ "Parent entry expected to be deleted : " + parentEntry.getDN());
+
+ // Expect the child entry to be moved as conflict entry under the root
+ // entry of the suffix
+ DN childDN = DN.decode("entryuuid="+childUUID+
+ "+cn=child,o=test");
+ assertTrue(DirectoryServer.entryExists(childDN),
+ "Child entry conflict exist with DN="+childDN);
+
+ }
+ finally
+ {
+ MultimasterReplication.deleteDomain(baseDn);
+ }
+ }
+
+ @Test(enabled=true)
+ public void removeParentConflict3() throws Exception
+ {
+ TestCaseUtils.initializeTestBackend(true);
+
+ final DN baseDn = DN.decode(TEST_ROOT_DN_STRING);
+
+ TestSynchronousReplayQueue queue = new TestSynchronousReplayQueue();
+ DomainFakeCfg conf = new DomainFakeCfg(baseDn, 1, new TreeSet<String>());
+ conf.setIsolationPolicy(IsolationPolicy.ACCEPT_ALL_UPDATES);
+
+ LDAPReplicationDomain domain =
+ MultimasterReplication.createNewDomain(conf, queue);
+ domain.start();
+
+ try
+ {
+ /*
+ * Create a Change number generator to generate new ChangeNumbers
+ * when we need to send operations messages to the replicationServer.
+ */
+ ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
+
+ Entry parentEntry = TestCaseUtils.entryFromLdifString(
+ "dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
+ + "objectClass: top\n"
+ + "objectClass: organizationalUnit\n");
+
+ Entry childEntry = TestCaseUtils.entryFromLdifString(
+ "dn: cn=child, ou=rpConflict,"+ TEST_ROOT_DN_STRING + "\n"
+ + "objectClass: top\n"
+ + "objectClass: person\n"
+ + "objectClass: organizationalPerson\n"
+ + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
+ + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
+ + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
+ + "$Rockford, NC 85762\n" + "mail: user.1@example.com\n"
+ + "cn: Aaccf Amar\n" + "l: Rockford\n"
+ + "street: 17984 Thirteenth Street\n"
+ + "employeeNumber: 1\n"
+ + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
+ + "userPassword: password\n" + "initials: AA\n");
+
+
+ TestCaseUtils.addEntry(parentEntry);
+ String parentUUID = getEntryUUID(parentEntry.getDN());
+ TestCaseUtils.deleteEntry(parentEntry);
+
+ ChangeNumber cn1 = gen.newChangeNumber();
+
+ // Create and publish an update message to add the child entry.
+ String childUUID = "44444444-4444-4444-4444-444444444444";
+ AddMsg addMsg = new AddMsg(
+ cn1,
+ childEntry.getDN().toString(),
+ childUUID,
+ parentUUID,
+ childEntry.getObjectClassAttribute(),
+ childEntry.getAttributes(),
+ new ArrayList<Attribute>());
+
+ // Put the message in the replay queue
+ domain.processUpdate(addMsg);
+ // Make the domain replay the change from the replay queue
+ domain.replay(queue.take().getUpdateMessage());
+
+ // Expect the parent entry to be deleted
+ assertFalse(DirectoryServer.entryExists(parentEntry.getDN()),
+ "Parent entry exists ");
+
+ // Expect the child entry to be moved as conflict entry under the root
+ // entry of the suffix
+ DN childDN = DN.decode("entryuuid="+childUUID+
+ "+cn=child,o=test");
+ assertTrue(DirectoryServer.entryExists(childDN),
+ "Child entry conflict exist with DN="+childDN);
+
+ }
+ finally
+ {
+ MultimasterReplication.deleteDomain(baseDn);
+ }
+ }
}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java
index 669f017..ef8fa71 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java
@@ -79,7 +79,7 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
-
+import org.opends.server.controls.SubtreeDeleteControl;
/**
* Test the constructors, encoders and decoders of the replication protocol
* PDUs classes (message classes)
@@ -321,8 +321,8 @@
entryAttrList.add(eattr2);
return new Object[][] {
- {"dc=com", entryAttrList},
- {"dc=delete,dc=an,dc=entry,dc=with,dc=a,dc=long dn", null},
+ {"dc=com", entryAttrList, false},
+ {"dc=delete,dc=an,dc=entry,dc=with,dc=a,dc=long dn", null, true},
};
}
@@ -333,18 +333,23 @@
* Finally test that both Msg matches.
*/
@Test(enabled=true,dataProvider = "createDeleteData")
- public void deleteMsgTest(String rawDN, List<Attribute> entryAttrList)
+ public void deleteMsgTest(String rawDN, List<Attribute> entryAttrList,
+ boolean subtree)
throws Exception
{
InternalClientConnection connection =
InternalClientConnection.getRootConnection();
DeleteOperationBasis opBasis =
new DeleteOperationBasis(connection, 1, 1,null, DN.decode(rawDN));
+ if (subtree)
+ {
+ opBasis.addRequestControl(new SubtreeDeleteControl(false));
+ }
LocalBackendDeleteOperation op = new LocalBackendDeleteOperation(opBasis);
ChangeNumber cn = new ChangeNumber(TimeThread.getTime(),123, 45);
op.setAttachment(SYNCHROCONTEXT, new DeleteContext(cn, "uniqueid"));
DeleteMsg msg = new DeleteMsg(op);
-
+ assertTrue((msg.isSubtreeDelete()==subtree));
// Set ECL entry attributes
if (entryAttrList != null)
{
@@ -356,8 +361,8 @@
assertEquals(msg.toString(), generatedMsg.toString());
assertEquals(msg.getInitiatorsName(), generatedMsg.getInitiatorsName());
-
assertEquals(msg.getChangeNumber(), generatedMsg.getChangeNumber());
+ assertEquals(generatedMsg.isSubtreeDelete(), subtree);
// Get ECL entry attributes
ArrayList<RawAttribute> genAttrList = generatedMsg.getEclIncludes();
@@ -379,6 +384,9 @@
Operation generatedOperation = generatedMsg.createOperation(connection);
assertEquals(generatedOperation.getClass(), DeleteOperationBasis.class);
+ assertTrue(
+ (subtree?(generatedOperation.getRequestControl(SubtreeDeleteControl.DECODER)!=null):
+ (generatedOperation.getRequestControl(SubtreeDeleteControl.DECODER)==null)));
DeleteOperationBasis mod2 = (DeleteOperationBasis) generatedOperation;
@@ -387,6 +395,7 @@
// Create an update message from this op
DeleteMsg updateMsg = (DeleteMsg) LDAPUpdateMsg.generateMsg(op);
assertEquals(msg.getChangeNumber(), updateMsg.getChangeNumber());
+ assertEquals(msg.isSubtreeDelete(), updateMsg.isSubtreeDelete());
}
@DataProvider(name = "createModifyDnData")
--
Gitblit v1.10.0