188N/A/*
188N/A * CDDL HEADER START
188N/A *
188N/A * The contents of this file are subject to the terms of the
188N/A * Common Development and Distribution License, Version 1.0 only
188N/A * (the "License"). You may not use this file except in compliance
188N/A * with the License.
188N/A *
188N/A * You can obtain a copy of the license at
188N/A * trunk/opends/resource/legal-notices/OpenDS.LICENSE
188N/A * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
188N/A * See the License for the specific language governing permissions
188N/A * and limitations under the License.
188N/A *
188N/A * When distributing Covered Code, include this CDDL HEADER in each
188N/A * file and include the License file at
188N/A * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
188N/A * add the following below this CDDL HEADER, with the fields enclosed
873N/A * by brackets "[]" replaced with your own identifying information:
188N/A * Portions Copyright [yyyy] [name of copyright owner]
188N/A *
188N/A * CDDL HEADER END
188N/A *
188N/A *
5129N/A * Copyright 2006-2010 Sun Microsystems, Inc.
5529N/A * Portions Copyright 2011 ForgeRock AS
188N/A */
188N/A
1182N/Apackage org.opends.server.replication;
188N/A
1280N/Aimport static org.opends.server.loggers.ErrorLogger.logError;
1689N/Aimport static org.testng.Assert.assertEquals;
1689N/Aimport static org.testng.Assert.assertFalse;
1689N/Aimport static org.testng.Assert.assertNotNull;
1689N/Aimport static org.testng.Assert.assertNull;
1689N/Aimport static org.testng.Assert.assertTrue;
1689N/Aimport static org.testng.Assert.fail;
385N/A
1204N/Aimport java.net.ServerSocket;
188N/Aimport java.util.ArrayList;
188N/Aimport java.util.List;
188N/A
188N/Aimport org.opends.server.TestCaseUtils;
2086N/Aimport org.opends.messages.Message;
2086N/Aimport org.opends.messages.Category;
2086N/Aimport org.opends.messages.Severity;
1689N/Aimport org.opends.server.core.AddOperationBasis;
1689N/Aimport org.opends.server.core.DeleteOperationBasis;
1689N/Aimport org.opends.server.core.DirectoryServer;
1858N/Aimport org.opends.server.core.ModifyDNOperationBasis;
1689N/Aimport org.opends.server.core.ModifyOperation;
1689N/Aimport org.opends.server.core.ModifyOperationBasis;
2181N/Aimport org.opends.server.extensions.DummyAlertHandler;
442N/Aimport org.opends.server.plugins.ShortCircuitPlugin;
1689N/Aimport org.opends.server.protocols.internal.InternalClientConnection;
1689N/Aimport org.opends.server.protocols.ldap.LDAPAttribute;
1689N/Aimport org.opends.server.protocols.ldap.LDAPModification;
1423N/Aimport org.opends.server.replication.common.ChangeNumber;
1182N/Aimport org.opends.server.replication.common.ChangeNumberGenerator;
3988N/Aimport org.opends.server.replication.service.ReplicationBroker;
3988N/Aimport org.opends.server.replication.plugin.LDAPReplicationDomain;
1182N/Aimport org.opends.server.replication.protocol.AddMsg;
1182N/Aimport org.opends.server.replication.protocol.DeleteMsg;
1182N/Aimport org.opends.server.replication.protocol.HeartbeatThread;
1182N/Aimport org.opends.server.replication.protocol.ModifyDNMsg;
1182N/Aimport org.opends.server.replication.protocol.ModifyMsg;
4088N/Aimport org.opends.server.replication.protocol.OperationContext;
3853N/Aimport org.opends.server.replication.protocol.ReplicationMsg;
442N/Aimport org.opends.server.schema.DirectoryStringSyntax;
4134N/Aimport org.opends.server.types.*;
4890N/Aimport org.opends.server.util.StaticUtils;
385N/Aimport org.testng.annotations.BeforeClass;
398N/Aimport org.testng.annotations.DataProvider;
385N/Aimport org.testng.annotations.Test;
3853N/Aimport static org.opends.server.TestCaseUtils.*;
5238N/Aimport org.opends.server.util.TimeThread;
5238N/A
188N/A
188N/A/**
1183N/A * Test synchronization of update operations on the directory server and through
1183N/A * the replication server broker interface.
188N/A */
2342N/Apublic class UpdateOperationTest extends ReplicationTestCase
188N/A{
188N/A /**
385N/A * An entry with a entryUUID
385N/A */
385N/A private Entry personWithUUIDEntry;
385N/A private Entry personWithSecondUniqueID;
385N/A
3324N/A private Entry user3Entry;
3324N/A private String user3dn;
3324N/A private String user3UUID;
3324N/A
385N/A private String baseUUID;
385N/A
385N/A private String user1dn;
385N/A
385N/A private String user1entrysecondUUID;
385N/A
385N/A private String user1entryUUID;
704N/A
583N/A /**
583N/A * A "person" entry
583N/A */
583N/A protected Entry personEntry;
1204N/A private int replServerPort;
1523N/A private String domain1uid;
1523N/A private String domain2uid;
1523N/A private String domain3uid;
1523N/A private String domain1dn;
1523N/A private String domain2dn;
1523N/A private String domain3dn;
1523N/A private Entry domain1;
1523N/A private Entry domain2;
1523N/A private Entry domain3;
3853N/A
4802N/A int domainSid = 55;
258N/A
188N/A /**
188N/A * Set up the environment for performing the tests in this Class.
338N/A *
188N/A * @throws Exception
385N/A * If the environment could not be set up.
188N/A */
188N/A @BeforeClass
188N/A @Override
188N/A public void setUp() throws Exception
188N/A {
3853N/A super.setUp();
338N/A
3853N/A // Create necessary backend top level entry
3853N/A String topEntry = "dn: ou=People," + TEST_ROOT_DN_STRING + "\n"
3853N/A + "objectClass: top\n"
385N/A + "objectClass: organizationalUnit\n"
385N/A + "entryUUID: 11111111-1111-1111-1111-111111111111\n";
3853N/A addEntry(TestCaseUtils.entryFromLdifString(topEntry));
188N/A
3853N/A baseUUID = getEntryUUID(DN.decode("ou=People," + TEST_ROOT_DN_STRING));
338N/A
1204N/A // find a free port for the replicationServer
1204N/A ServerSocket socket = TestCaseUtils.bindFreePort();
1204N/A replServerPort = socket.getLocalPort();
1204N/A socket.close();
1291N/A
1204N/A // replication server
1204N/A String replServerLdif =
3853N/A "dn: cn=Replication Server, " + SYNCHRO_PLUGIN_DN + "\n"
188N/A + "objectClass: top\n"
2624N/A + "objectClass: ds-cfg-replication-server\n"
1204N/A + "cn: Replication Server\n"
2624N/A + "ds-cfg-replication-port: " + replServerPort + "\n"
3988N/A + "ds-cfg-replication-db-directory: UpdateOperationTest\n"
3853N/A + "ds-cfg-replication-server-id: 107\n";
1204N/A replServerEntry = TestCaseUtils.entryFromLdifString(replServerLdif);
188N/A
188N/A // suffix synchronized
3853N/A String testName = "updateOperationTest";
1204N/A String synchroServerLdif =
3853N/A "dn: cn=" + testName + ", cn=domains, " + SYNCHRO_PLUGIN_DN + "\n"
188N/A + "objectClass: top\n"
2624N/A + "objectClass: ds-cfg-replication-domain\n"
3853N/A + "cn: " + testName + "\n"
3853N/A + "ds-cfg-base-dn: ou=People," + TEST_ROOT_DN_STRING + "\n"
1204N/A + "ds-cfg-replication-server: localhost:" + replServerPort + "\n"
3853N/A + "ds-cfg-server-id: "+ domainSid +"\n"
3324N/A + "ds-cfg-receive-status: true\n";
188N/A synchroServerEntry = TestCaseUtils.entryFromLdifString(synchroServerLdif);
188N/A
3853N/A String personLdif = "dn: uid=user.1,ou=People," + TEST_ROOT_DN_STRING + "\n"
188N/A + "objectClass: top\n" + "objectClass: person\n"
188N/A + "objectClass: organizationalPerson\n"
188N/A + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
188N/A + "homePhone: 951-245-7634\n"
385N/A + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
385N/A + "mobile: 027-085-0537\n"
188N/A + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
188N/A + "$Rockford, NC 85762\n" + "mail: user.1@example.com\n"
188N/A + "cn: Aaccf Amar\n" + "l: Rockford\n" + "pager: 508-763-4246\n"
188N/A + "street: 17984 Thirteenth Street\n"
188N/A + "telephoneNumber: 216-564-6748\n" + "employeeNumber: 1\n"
188N/A + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
188N/A + "userPassword: password\n" + "initials: AA\n";
188N/A personEntry = TestCaseUtils.entryFromLdifString(personLdif);
385N/A
385N/A /*
385N/A * The 2 entries defined in the following code are used for the naming
385N/A * conflict resolution test (called namingConflicts)
385N/A * They must have the same DN but different entryUUID.
385N/A */
385N/A user1entryUUID = "33333333-3333-3333-3333-333333333333";
385N/A user1entrysecondUUID = "22222222-2222-2222-2222-222222222222";
3853N/A user1dn = "uid=user1,ou=People," + TEST_ROOT_DN_STRING;
385N/A String entryWithUUIDldif = "dn: "+ user1dn + "\n"
385N/A + "objectClass: top\n" + "objectClass: person\n"
385N/A + "objectClass: organizationalPerson\n"
385N/A + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
385N/A + "homePhone: 951-245-7634\n"
385N/A + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
385N/A + "mobile: 027-085-0537\n"
385N/A + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
385N/A + "$Rockford, NC 85762\n" + "mail: user.1@example.com\n"
385N/A + "cn: Aaccf Amar\n" + "l: Rockford\n" + "pager: 508-763-4246\n"
385N/A + "street: 17984 Thirteenth Street\n"
385N/A + "telephoneNumber: 216-564-6748\n" + "employeeNumber: 1\n"
385N/A + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
385N/A + "userPassword: password\n" + "initials: AA\n"
385N/A + "entryUUID: " + user1entryUUID + "\n";
385N/A personWithUUIDEntry = TestCaseUtils.entryFromLdifString(entryWithUUIDldif);
385N/A
385N/A String entryWithSecondUUID = "dn: "+ user1dn + "\n"
385N/A + "objectClass: top\n" + "objectClass: person\n"
385N/A + "objectClass: organizationalPerson\n"
385N/A + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
385N/A + "homePhone: 951-245-7634\n"
385N/A + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
385N/A + "mobile: 027-085-0537\n"
385N/A + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
385N/A + "$Rockford, NC 85762\n" + "mail: user.1@example.com\n"
385N/A + "cn: Aaccf Amar\n" + "l: Rockford\n" + "pager: 508-763-4246\n"
385N/A + "street: 17984 Thirteenth Street\n"
385N/A + "telephoneNumber: 216-564-6748\n" + "employeeNumber: 1\n"
385N/A + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
385N/A + "userPassword: password\n" + "initials: AA\n"
385N/A + "entryUUID: "+ user1entrysecondUUID + "\n";
385N/A personWithSecondUniqueID =
385N/A TestCaseUtils.entryFromLdifString(entryWithSecondUUID);
3853N/A
3324N/A user3UUID = "44444444-4444-4444-4444-444444444444";
3853N/A user3dn = "uid=user3,ou=People," + TEST_ROOT_DN_STRING;
3324N/A String user3LDIFEntry = "dn: "+ user3dn + "\n"
3324N/A + "objectClass: top\n" + "objectClass: person\n"
3324N/A + "objectClass: organizationalPerson\n"
3324N/A + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
3324N/A + "homePhone: 951-245-7634\n"
3324N/A + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
3324N/A + "mobile: 027-085-0537\n"
3324N/A + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
3324N/A + "$Rockford, NC 85762\n" + "mail: user.3@example.com\n"
3324N/A + "cn: Aaccf Amar\n" + "l: Rockford\n" + "pager: 508-763-4246\n"
3324N/A + "street: 17984 Thirteenth Street\n"
3324N/A + "telephoneNumber: 216-564-6748\n" + "employeeNumber: 1\n"
3324N/A + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
3324N/A + "userPassword: password\n" + "initials: AA\n"
3324N/A + "entryUUID: " + user3UUID + "\n";
3324N/A user3Entry = TestCaseUtils.entryFromLdifString(user3LDIFEntry);
3324N/A
3853N/A domain1dn = "dc=domain1,ou=People," + TEST_ROOT_DN_STRING;
3853N/A domain2dn = "dc=domain2,dc=domain1,ou=People," + TEST_ROOT_DN_STRING;
3853N/A domain3dn = "dc=domain3,dc=domain1,ou=People," + TEST_ROOT_DN_STRING;
1523N/A domain1 = TestCaseUtils.entryFromLdifString(
3853N/A "dn:" + domain1dn + "\n"
1523N/A + "objectClass:domain\n"
1523N/A + "dc:domain1");
1523N/A domain2 = TestCaseUtils.entryFromLdifString(
3853N/A "dn:" + domain2dn + "\n"
1523N/A + "objectClass:domain\n"
1523N/A + "dc:domain2");
1523N/A domain3 = TestCaseUtils.entryFromLdifString(
3853N/A "dn:" + domain3dn + "\n"
1523N/A + "objectClass:domain\n"
1523N/A + "dc:domain3");
385N/A
1183N/A configureReplication();
188N/A }
188N/A
188N/A /**
3853N/A * Add an entry in the database
1523N/A *
1523N/A */
4088N/A private ChangeNumber addEntry(Entry entry) throws Exception
1523N/A {
1689N/A AddOperationBasis addOp = new AddOperationBasis(connection,
1523N/A InternalClientConnection.nextOperationID(), InternalClientConnection
1523N/A .nextMessageID(), null, entry.getDN(), entry.getObjectClasses(),
1523N/A entry.getUserAttributes(), entry.getOperationalAttributes());
1523N/A addOp.setInternalOperation(true);
1523N/A addOp.run();
3853N/A
3853N/A assertEquals(addOp.getResultCode(), ResultCode.SUCCESS);
1523N/A assertNotNull(getEntry(entry.getDN(), 1000, true));
4088N/A return OperationContext.getChangeNumber((Operation) addOp);
1523N/A }
3853N/A
1523N/A /**
3853N/A * Delete an entry in the database
1523N/A *
1523N/A */
1523N/A private void delEntry(DN dn) throws Exception
1523N/A {
1523N/A connection.processDelete(dn);
1523N/A assertNull(getEntry(dn, 1000, true));
1523N/A }
1523N/A
1523N/A /**
707N/A * Tests whether the synchronization provider receive status can be disabled
707N/A * then re-enabled.
707N/A * FIXME Enable this test when broker suspend/resume receive are implemented.
707N/A * @throws Exception
707N/A */
707N/A @Test(enabled=false)
707N/A public void toggleReceiveStatus() throws Exception
707N/A {
2089N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION,
2089N/A "Starting synchronization test : toggleReceiveStatus"));
707N/A
4890N/A // Clean replication server database from previous run
4890N/A cleanUpReplicationServersDB();
4890N/A
3853N/A final DN baseDn = DN.decode("ou=People," + TEST_ROOT_DN_STRING);
707N/A
707N/A /*
1191N/A * Open a session to the replicationServer using the broker API.
707N/A * This must use a different serverId to that of the directory server.
707N/A */
1191N/A ReplicationBroker broker =
4802N/A openReplicationSession(baseDn, 2, 100, replServerPort, 1000, true);
707N/A
707N/A
5529N/A try
5529N/A {
5529N/A /*
5529N/A * Create a Change number generator to generate new changenumbers
5529N/A * when we need to send operation messages to the replicationServer.
5529N/A */
5529N/A ChangeNumberGenerator gen = new ChangeNumberGenerator(2, 0);
707N/A
707N/A
5529N/A // Disable the directory server receive status.
5529N/A setReceiveStatus(synchroServerEntry.getDN().toString(), false);
707N/A
707N/A
5529N/A // Create and publish an update message to add an entry.
5529N/A AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
5529N/A personWithUUIDEntry.getDN().toString(),
5529N/A user1entryUUID,
5529N/A baseUUID,
5529N/A personWithUUIDEntry.getObjectClassAttribute(),
5529N/A personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
5529N/A broker.publish(addMsg);
707N/A
5529N/A Entry resultEntry;
707N/A
5529N/A // Check that the entry has not been created in the directory server.
5529N/A resultEntry = getEntry(personWithUUIDEntry.getDN(), 1000, true);
5529N/A assertNull(resultEntry,
5529N/A "The replication message was replayed while the server "
5529N/A + "receive status was disabled");
707N/A
5529N/A // Enable the directory server receive status.
5529N/A setReceiveStatus(synchroServerEntry.getDN().toString(), true);
707N/A
5529N/A // Create and publish another update message to add an entry.
5529N/A addMsg = new AddMsg(gen.newChangeNumber(),
5529N/A personWithUUIDEntry.getDN().toString(),
5529N/A user1entryUUID,
5529N/A baseUUID,
5529N/A personWithUUIDEntry.getObjectClassAttribute(),
5529N/A personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
5529N/A broker.publish(addMsg);
5529N/A
5529N/A // Check that the entry has been created in the directory server.
5529N/A resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, true);
5529N/A assertNotNull(resultEntry,
5529N/A "The replication message was not replayed after the server "
5529N/A + "receive status was enabled");
707N/A
5529N/A // Delete the entries to clean the database.
5529N/A DeleteMsg delMsg =
5529N/A new DeleteMsg(personWithUUIDEntry.getDN().toString(),
5529N/A gen.newChangeNumber(), user1entryUUID);
5529N/A broker.publish(delMsg);
5529N/A resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, false);
707N/A
5529N/A // Check that the delete operation has been applied.
5529N/A assertNull(resultEntry,
5529N/A "The DELETE replication message was not replayed");
5529N/A }
5529N/A finally
5529N/A {
5529N/A broker.stop();
5529N/A }
707N/A }
707N/A
707N/A /**
759N/A * Tests whether the synchronization provider fails over when it loses
1183N/A * the heartbeat from the replication server.
759N/A */
759N/A @Test(groups = "slow")
759N/A public void lostHeartbeatFailover() throws Exception
759N/A {
2089N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION,
2089N/A "Starting replication test : lostHeartbeatFailover"));
775N/A
4890N/A // Clean replication server database from previous run
4890N/A cleanUpReplicationServersDB();
4890N/A
3853N/A final DN baseDn = DN.decode("ou=People," + TEST_ROOT_DN_STRING);
759N/A
759N/A /*
1191N/A * Open a session to the replicationServer using the broker API.
759N/A * This must use a different serverId to that of the directory server.
759N/A */
1191N/A ReplicationBroker broker =
4802N/A openReplicationSession(baseDn, 2, 100, replServerPort, 1000, true);
759N/A
5529N/A try
5529N/A {
5529N/A /*
5529N/A * Create a Change number generator to generate new changenumbers
5529N/A * when we need to send operation messages to the replicationServer.
5529N/A */
5529N/A ChangeNumberGenerator gen = new ChangeNumberGenerator(2, 0);
759N/A
759N/A
5529N/A // Create and publish an update message to add an entry.
5529N/A AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
5529N/A personWithUUIDEntry.getDN().toString(),
5529N/A user1entryUUID,
5529N/A baseUUID,
5529N/A personWithUUIDEntry.getObjectClassAttribute(),
5529N/A personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
5529N/A broker.publish(addMsg);
759N/A
5529N/A Entry resultEntry;
759N/A
5529N/A // Check that the entry has been created in the directory server.
5529N/A resultEntry = getEntry(personWithUUIDEntry.getDN(), 30000, true);
5529N/A assertNotNull(resultEntry,
5529N/A "The ADD replication message was not replayed");
759N/A
5529N/A // Send a first modify operation message.
5529N/A List<Modification> mods = generatemods("telephonenumber", "01 02 45");
5529N/A ModifyMsg modMsg = new ModifyMsg(gen.newChangeNumber(),
5529N/A personWithUUIDEntry.getDN(), mods,
5529N/A user1entryUUID);
5529N/A broker.publish(modMsg);
759N/A
5529N/A // Check that the modify has been replayed.
5529N/A boolean found = checkEntryHasAttribute(personWithUUIDEntry.getDN(),
5529N/A "telephonenumber", "01 02 45", 10000, true);
5529N/A if (!found)
5529N/A {
5529N/A fail("The first modification was not replayed.");
5529N/A }
759N/A
5529N/A // Simulate loss of heartbeats.
5529N/A HeartbeatThread.setHeartbeatsDisabled(true);
5529N/A Thread.sleep(3000);
5529N/A HeartbeatThread.setHeartbeatsDisabled(false);
759N/A
5529N/A // Send a second modify operation message.
5529N/A mods = generatemods("description", "Description was changed");
5529N/A modMsg = new ModifyMsg(gen.newChangeNumber(),
5529N/A personWithUUIDEntry.getDN(), mods,
5529N/A user1entryUUID);
5529N/A broker.publish(modMsg);
759N/A
5529N/A // Check that the modify has been replayed.
5529N/A found = checkEntryHasAttribute(personWithUUIDEntry.getDN(),
5529N/A "description", "Description was changed",
5529N/A 10000, true);
5529N/A if (!found)
5529N/A {
5529N/A fail("The second modification was not replayed.");
5529N/A }
759N/A
5529N/A // Delete the entries to clean the database.
5529N/A DeleteMsg delMsg =
5529N/A new DeleteMsg(personWithUUIDEntry.getDN().toString(),
1367N/A gen.newChangeNumber(), user1entryUUID);
5529N/A broker.publish(delMsg);
5529N/A resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, false);
759N/A
5529N/A // Check that the delete operation has been applied.
5529N/A assertNull(resultEntry,
5529N/A "The DELETE replication message was not replayed");
5529N/A }
5529N/A finally
5529N/A {
5529N/A broker.stop();
5529N/A }
759N/A }
759N/A
759N/A /**
1423N/A * Tests the modify conflict resolution code.
1423N/A * In this test, the local server acts both as an LDAP server and
1423N/A * a replicationServer that are inter-connected.
1423N/A *
1423N/A * The test creates an other session to the replicationServer using
1423N/A * directly the ReplicationBroker API.
1423N/A * It then uses this session to simulate conflicts and therefore
1423N/A * test the modify conflict resolution code.
1423N/A */
1423N/A @Test(enabled=true, groups="slow")
1423N/A public void modifyConflicts()
1423N/A throws Exception
1423N/A {
3853N/A final DN baseDn = DN.decode("ou=People," + TEST_ROOT_DN_STRING);
1423N/A final DN dn1 = DN.decode("cn=test1," + baseDn.toString());
1423N/A final AttributeType attrType =
1423N/A DirectoryServer.getAttributeType("displayname");
1423N/A final AttributeType entryuuidType =
1423N/A DirectoryServer.getAttributeType("entryuuid");
1423N/A String monitorAttr = "resolved-modify-conflicts";
1423N/A
4890N/A // Clean replication server database from previous run
4890N/A cleanUpReplicationServersDB();
4890N/A
1423N/A /*
1423N/A * Open a session to the replicationServer using the broker API.
1423N/A * This must use a different serverId to that of the directory server.
1423N/A */
1423N/A ReplicationBroker broker =
5529N/A openReplicationSession(baseDn, 2, 100, replServerPort, 1000, true);
1423N/A
5529N/A try
5529N/A {
5529N/A // Add the first test entry.
5529N/A TestCaseUtils.addEntry(
5529N/A "dn: cn=test1," + baseDn.toString(),
5529N/A "displayname: Test1",
5529N/A "objectClass: top",
5529N/A "objectClass: person",
5529N/A "objectClass: organizationalPerson",
5529N/A "objectClass: inetOrgPerson",
5529N/A "cn: test1",
5529N/A "sn: test");
1423N/A
5529N/A // Read the entry back to get its UUID.
5529N/A Entry entry = DirectoryServer.getEntry(dn1);
5529N/A List<Attribute> attrs = entry.getAttribute(entryuuidType);
5529N/A String entryuuid =
5529N/A attrs.get(0).iterator().next().getValue().toString();
1423N/A
5529N/A // A change on a first server.
5529N/A long changeTime = TimeThread.getTime();
5529N/A ChangeNumber t1 = new ChangeNumber(changeTime, 0, 3);
1423N/A
5529N/A // A change on a second server.
5529N/A changeTime++;
5529N/A ChangeNumber t2 = new ChangeNumber(changeTime, 0, 4);
1423N/A
5529N/A // Simulate the ordering t2:replace:B followed by t1:add:A that
5529N/A updateMonitorCount(baseDn, monitorAttr);
1523N/A
5529N/A // Replay a replace of a value B at time t2 on a second server.
5529N/A Attribute attr = Attributes.create(attrType, "B");
5529N/A Modification mod = new Modification(ModificationType.REPLACE, attr);
5529N/A List<Modification> mods = new ArrayList<Modification>(1);
5529N/A mods.add(mod);
5529N/A ModifyMsg modMsg = new ModifyMsg(t2, dn1, mods, entryuuid);
5529N/A broker.publish(modMsg);
1423N/A
5529N/A Thread.sleep(2000);
1423N/A
5529N/A // Replay an add of a value A at time t1 on a first server.
5529N/A attr = Attributes.create(attrType, "A");
5529N/A mod = new Modification(ModificationType.ADD, attr);
5529N/A mods = new ArrayList<Modification>(1);
5529N/A mods.add(mod);
5529N/A modMsg = new ModifyMsg(t1, dn1, mods, entryuuid);
5529N/A broker.publish(modMsg);
1423N/A
5529N/A Thread.sleep(2000);
1423N/A
5529N/A // Read the entry to see how the conflict was resolved.
5529N/A entry = DirectoryServer.getEntry(dn1);
5529N/A attrs = entry.getAttribute(attrType);
5529N/A String attrValue1 =
5529N/A attrs.get(0).iterator().next().getValue().toString();
1423N/A
5529N/A // the value should be the last (time t2) value added
5529N/A assertEquals(attrValue1, "B");
5529N/A assertEquals(getMonitorDelta(), 1);
1523N/A
5529N/A // Simulate the ordering t2:delete:displayname followed by
5529N/A // t1:replace:displayname
5529N/A // A change on a first server.
5529N/A changeTime++;
5529N/A t1 = new ChangeNumber(changeTime, 0, 3);
1423N/A
5529N/A // A change on a second server.
5529N/A changeTime++;
5529N/A t2 = new ChangeNumber(changeTime, 0, 4);
1423N/A
5529N/A // Simulate the ordering t2:delete:displayname followed by t1:replace:A
5529N/A updateMonitorCount(baseDn, monitorAttr);
1523N/A
5529N/A // Replay an delete of attribute displayname at time t2 on a second server.
5529N/A attr = Attributes.empty(attrType);
5529N/A mod = new Modification(ModificationType.DELETE, attr);
5529N/A mods = new ArrayList<Modification>(1);
5529N/A mods.add(mod);
5529N/A modMsg = new ModifyMsg(t2, dn1, mods, entryuuid);
5529N/A broker.publish(modMsg);
1423N/A
5529N/A Thread.sleep(2000);
1423N/A
5529N/A // Replay a replace of a value A at time t1 on a first server.
5529N/A attr = Attributes.create(attrType, "A");
5529N/A mod = new Modification(ModificationType.REPLACE, attr);
5529N/A mods = new ArrayList<Modification>(1);
5529N/A mods.add(mod);
5529N/A modMsg = new ModifyMsg(t1, dn1, mods, entryuuid);
5529N/A broker.publish(modMsg);
1423N/A
5529N/A Thread.sleep(2000);
1423N/A
5529N/A // Read the entry to see how the conflict was resolved.
5529N/A entry = DirectoryServer.getEntry(dn1);
5529N/A attrs = entry.getAttribute(attrType);
1423N/A
5529N/A // there should not be a value (delete at time t2)
5529N/A assertNull(attrs);
5529N/A assertEquals(getMonitorDelta(), 1);
5529N/A }
5529N/A finally
5529N/A {
5529N/A broker.stop();
5529N/A }
1423N/A }
1423N/A
4246N/A
1423N/A /**
385N/A * Tests the naming conflict resolution code.
385N/A * In this test, the local server act both as an LDAP server and
1191N/A * a replicationServer that are inter-connected.
385N/A *
1191N/A * The test creates an other session to the replicationServer using
1191N/A * directly the ReplicationBroker API.
3853N/A * It then uses this session to simulate conflicts and therefore
385N/A * test the naming conflict resolution code.
385N/A */
1423N/A @Test(enabled=true, groups="slow")
385N/A public void namingConflicts() throws Exception
385N/A {
2089N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION,
2089N/A "Starting replication test : namingConflicts"));
544N/A
3853N/A final DN baseDn = DN.decode("ou=People," + TEST_ROOT_DN_STRING);
1523N/A String resolvedMonitorAttr = "resolved-naming-conflicts";
1523N/A String unresolvedMonitorAttr = "unresolved-naming-conflicts";
385N/A
4890N/A // Clean replication server database from previous run
4890N/A cleanUpReplicationServersDB();
4890N/A
385N/A /*
1191N/A * Open a session to the replicationServer using the ReplicationServer broker API.
385N/A * This must use a serverId different from the LDAP server ID
385N/A */
1191N/A ReplicationBroker broker =
4802N/A openReplicationSession(baseDn, 2, 100, replServerPort, 1000, true);
385N/A
5529N/A try
5529N/A {
385N/A /*
385N/A * Create a Change number generator to generate new changenumbers
1191N/A * when we need to send operations messages to the replicationServer.
385N/A */
4802N/A ChangeNumberGenerator gen = new ChangeNumberGenerator( 2, 0);
385N/A
385N/A /*
385N/A * Test that the conflict resolution code is able to find entries
385N/A * that have been renamed by an other master.
442N/A * To simulate this, create an entry with a given UUID and a given DN
385N/A * then send a modify operation using another DN but the same UUID.
385N/A * Finally check that the modify operation has been applied.
385N/A */
385N/A // create the entry with a given DN
1367N/A AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
385N/A personWithUUIDEntry.getDN().toString(),
385N/A user1entryUUID,
385N/A baseUUID,
385N/A personWithUUIDEntry.getObjectClassAttribute(),
385N/A personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
385N/A broker.publish(addMsg);
385N/A
385N/A // Check that the entry has been created in the local DS.
544N/A Entry resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, true);
385N/A assertNotNull(resultEntry,
1183N/A "The send ADD replication message was not applied");
385N/A
385N/A // send a modify operation with the correct unique ID but another DN
385N/A List<Modification> mods = generatemods("telephonenumber", "01 02 45");
1367N/A ModifyMsg modMsg = new ModifyMsg(gen.newChangeNumber(),
3853N/A DN.decode("cn=something,ou=People," + TEST_ROOT_DN_STRING), mods,
385N/A user1entryUUID);
1523N/A updateMonitorCount(baseDn, resolvedMonitorAttr);
2181N/A int AlertCount = DummyAlertHandler.getAlertCount();
385N/A broker.publish(modMsg);
385N/A
385N/A // check that the modify has been applied as if the entry had been renamed.
385N/A boolean found = checkEntryHasAttribute(personWithUUIDEntry.getDN(),
544N/A "telephonenumber", "01 02 45", 10000, true);
385N/A if (found == false)
385N/A fail("The modification has not been correctly replayed.");
1523N/A assertEquals(getMonitorDelta(), 1);
3853N/A
2181N/A // check that there was no administrative alert generated
2181N/A // because the conflict has been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount,
2181N/A "An alert was incorrectly generated when resolving conflicts");
3988N/A
3853N/A /*
3988N/A * Test that modify conflict resolution is able to detect that
3853N/A * because there is a conflict between a MODIFYDN and a MODIFY,
3853N/A * when a MODIFY is replayed the attribute that is being modified is
3853N/A * now the RDN of the entry and therefore should not be deleted.
3853N/A */
3988N/A // send a modify operation attempting to replace the RDN entry
3853N/A // with a new value
3853N/A mods = generatemods("uid", "AnotherUid");
3853N/A modMsg = new ModifyMsg(gen.newChangeNumber(),
3853N/A personWithUUIDEntry.getDN(), mods,
3853N/A user1entryUUID);
3988N/A
3853N/A updateMonitorCount(baseDn, resolvedMonitorAttr);
3853N/A AlertCount = DummyAlertHandler.getAlertCount();
3853N/A broker.publish(modMsg);
3988N/A
3853N/A // check that the modify has been applied.
3853N/A found = checkEntryHasAttribute(personWithUUIDEntry.getDN(),
3853N/A "uid", "AnotherUid", 10000, true);
3988N/A
3853N/A if (found == false)
3853N/A fail("The modification has not been correctly replayed.");
3853N/A assertEquals(getMonitorDelta(), 1);
3988N/A
385N/A /*
385N/A * Test that the conflict resolution code is able to detect
3853N/A * that an entry has been renamed and that a new entry has
385N/A * been created with the same DN but another entry UUID
385N/A * To simulate this, create and entry with a given UUID and a given DN
385N/A * then send a modify operation using the same DN but another UUID.
385N/A * Finally check that the modify operation has not been applied to the
385N/A * entry with the given DN.
385N/A */
385N/A
385N/A // create the entry with a given DN and unique ID
1367N/A addMsg = new AddMsg(gen.newChangeNumber(),
385N/A personWithUUIDEntry.getDN().toString(),
385N/A user1entryUUID, baseUUID,
385N/A personWithUUIDEntry.getObjectClassAttribute(),
385N/A personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
385N/A broker.publish(addMsg);
385N/A
385N/A // Check that the entry has been created in the local DS.
544N/A resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, true);
385N/A assertNotNull(resultEntry,
1183N/A "The ADD replication message was not applied");
385N/A
385N/A // send a modify operation with a wrong unique ID but the same DN
385N/A mods = generatemods("telephonenumber", "02 01 03 05");
1367N/A modMsg = new ModifyMsg(gen.newChangeNumber(),
392N/A DN.decode(user1dn), mods, "10000000-9abc-def0-1234-1234567890ab");
1523N/A updateMonitorCount(baseDn, resolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
385N/A broker.publish(modMsg);
385N/A
385N/A // check that the modify has not been applied
3105N/A Thread.sleep(2000);
385N/A found = checkEntryHasAttribute(personWithUUIDEntry.getDN(),
544N/A "telephonenumber", "02 01 03 05", 10000, false);
385N/A if (found == true)
385N/A fail("The modification has been replayed while it should not.");
1423N/A assertEquals(getMonitorDelta(), 1);
3853N/A
2181N/A // Check that there was no administrative alert generated
2181N/A // because the conflict has been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount,
2181N/A "An alert was incorrectly generated when resolving conflicts");
2181N/A
385N/A
385N/A
385N/A /*
385N/A * Test that the conflict resolution code is able to find entries
385N/A * that have been renamed by an other master.
385N/A * To simulate this, send a delete operation using another DN but
385N/A * the same UUID has the entry that has been used in the tests above.
385N/A * Finally check that the delete operation has been applied.
385N/A */
392N/A // send a delete operation with a wrong dn but the unique ID of the entry
385N/A // used above
385N/A DeleteMsg delMsg =
3853N/A new DeleteMsg("cn=anotherdn,ou=People," + TEST_ROOT_DN_STRING,
1367N/A gen.newChangeNumber(), user1entryUUID);
1523N/A updateMonitorCount(baseDn, resolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
385N/A broker.publish(delMsg);
398N/A
385N/A // check that the delete operation has been applied
544N/A resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, false);
385N/A
385N/A assertNull(resultEntry,
1183N/A "The DELETE replication message was not replayed");
1423N/A assertEquals(getMonitorDelta(), 1);
2181N/A // Check that there was no administrative alert generated
2181N/A // because the conflict has been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount,
2181N/A "An alert was incorrectly generated when resolving conflicts");
385N/A
385N/A /*
385N/A * Test that two adds with the same DN but a different unique ID result
385N/A * cause a conflict and result in the second entry to be renamed.
385N/A */
385N/A
385N/A // create an entry with a given DN and unique ID
1367N/A addMsg = new AddMsg(gen.newChangeNumber(),
385N/A personWithUUIDEntry.getDN().toString(),
385N/A user1entryUUID, baseUUID,
385N/A personWithUUIDEntry.getObjectClassAttribute(),
385N/A personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
385N/A broker.publish(addMsg);
385N/A
385N/A // Check that the entry has been created in the local DS.
544N/A resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, true);
385N/A assertNotNull(resultEntry,
1183N/A "The ADD replication message was not applied");
385N/A
385N/A // create an entry with the same DN and another unique ID
1367N/A addMsg = new AddMsg(gen.newChangeNumber(),
385N/A personWithSecondUniqueID.getDN().toString(),
385N/A user1entrysecondUUID, baseUUID,
385N/A personWithSecondUniqueID.getObjectClassAttribute(),
385N/A personWithSecondUniqueID.getAttributes(), new ArrayList<Attribute>());
1523N/A updateMonitorCount(baseDn, unresolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
385N/A broker.publish(addMsg);
385N/A
385N/A // Check that the entry has been renamed and created in the local DS.
385N/A resultEntry = getEntry(
392N/A DN.decode("entryuuid=" + user1entrysecondUUID +" + " + user1dn),
544N/A 10000, true);
385N/A assertNotNull(resultEntry,
1183N/A "The ADD replication message was not applied");
1523N/A assertEquals(getMonitorDelta(), 1);
1523N/A assertConflictAttribute(resultEntry);
2181N/A // Check that there was an administrative alert generated
2181N/A // because the conflict has not been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount+1,
2181N/A "An alert was not generated when resolving conflicts");
2181N/A
385N/A
385N/A // delete the entries to clean the database.
385N/A delMsg =
385N/A new DeleteMsg(personWithUUIDEntry.getDN().toString(),
1367N/A gen.newChangeNumber(), user1entryUUID);
385N/A broker.publish(delMsg);
385N/A delMsg =
385N/A new DeleteMsg(personWithSecondUniqueID.getDN().toString(),
1367N/A gen.newChangeNumber(), user1entrysecondUUID);
385N/A broker.publish(delMsg);
544N/A resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, false);
2606N/A resultEntry = getEntry(personWithSecondUniqueID.getDN(), 10000, false);
385N/A
385N/A // check that the delete operation has been applied
385N/A assertNull(resultEntry,
1183N/A "The DELETE replication message was not replayed");
385N/A /*
385N/A * Check that and added entry is correctly added below it's
385N/A * parent entry when this parent entry has been renamed.
385N/A *
385N/A * Simulate this by trying to add an entry below a DN that does not
385N/A * exist but with a parent ID that exist.
385N/A */
1367N/A addMsg = new AddMsg(gen.newChangeNumber(),
3853N/A "uid=new person,o=nothere,o=below,ou=People," + TEST_ROOT_DN_STRING,
385N/A user1entryUUID,
385N/A baseUUID,
385N/A personWithUUIDEntry.getObjectClassAttribute(),
385N/A personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
1523N/A updateMonitorCount(baseDn, resolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
385N/A broker.publish(addMsg);
385N/A
3853N/A // Check that the entry has been created in the local DS.
385N/A resultEntry = getEntry(
3853N/A DN.decode("uid=new person,ou=People," + TEST_ROOT_DN_STRING), 10000, true);
385N/A assertNotNull(resultEntry,
1183N/A "The ADD replication message was not applied");
1423N/A assertEquals(getMonitorDelta(), 1);
2181N/A // Check that there was no administrative alert generated
2181N/A // because the conflict has been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount,
2181N/A "An alert was incorrectly generated when resolving conflicts");
2181N/A
385N/A
385N/A /*
385N/A * Check that when replaying delete the naming conflict code
385N/A * verify that the unique ID op the replayed operation is
385N/A * the same as the unique ID of the entry with the given DN
385N/A *
385N/A * To achieve this send a delete operation with a correct DN
385N/A * but a wrong unique ID.
385N/A */
398N/A
385N/A delMsg =
3853N/A new DeleteMsg("uid=new person,ou=People," + TEST_ROOT_DN_STRING,
1367N/A gen.newChangeNumber(), "11111111-9abc-def0-1234-1234567890ab");
1523N/A updateMonitorCount(baseDn, resolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
385N/A broker.publish(delMsg);
385N/A resultEntry = getEntry(
3853N/A DN.decode("uid=new person,ou=People," + TEST_ROOT_DN_STRING), 10000, true);
385N/A
385N/A // check that the delete operation has not been applied
385N/A assertNotNull(resultEntry,
1183N/A "The DELETE replication message was replayed when it should not");
1423N/A assertEquals(getMonitorDelta(), 1);
3853N/A
2181N/A // Check that there was no administrative alert generated
2181N/A // because the conflict has been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount,
2181N/A "An alert was incorrectly generated when resolving conflicts");
385N/A
398N/A
392N/A /*
392N/A * Check that when replaying modify dn operations, the conflict
392N/A * resolution code is able to find the new DN of the parent entry
392N/A * if it has been renamed on another master.
398N/A *
392N/A * To simulate this try to rename an entry below an entry that does
392N/A * not exist but giving the unique ID of an existing entry.
392N/A */
398N/A
392N/A ModifyDNMsg modDnMsg = new ModifyDNMsg(
3853N/A "uid=new person,ou=People," + TEST_ROOT_DN_STRING, gen.newChangeNumber(),
392N/A user1entryUUID, baseUUID, false,
3853N/A "uid=wrong, ou=people," + TEST_ROOT_DN_STRING,
392N/A "uid=newrdn");
1523N/A updateMonitorCount(baseDn, resolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
392N/A broker.publish(modDnMsg);
398N/A
392N/A resultEntry = getEntry(
3853N/A DN.decode("uid=newrdn,ou=People," + TEST_ROOT_DN_STRING), 10000, true);
392N/A
392N/A // check that the operation has been correctly relayed
392N/A assertNotNull(resultEntry,
392N/A "The modify dn was not or badly replayed");
1423N/A assertEquals(getMonitorDelta(), 1);
3853N/A
2181N/A // Check that there was no administrative alert generated
2181N/A // because the conflict has been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount,
2181N/A "An alert was incorrectly generated when resolving conflicts");
2181N/A
398N/A
392N/A /*
398N/A * same test but by giving a bad entry DN
392N/A */
398N/A
392N/A modDnMsg = new ModifyDNMsg(
3853N/A "uid=wrong,ou=People," + TEST_ROOT_DN_STRING, gen.newChangeNumber(),
3853N/A user1entryUUID, null, false, null, "uid=reallynewrdn");
1523N/A updateMonitorCount(baseDn, resolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
392N/A broker.publish(modDnMsg);
398N/A
392N/A resultEntry = getEntry(
3853N/A DN.decode("uid=reallynewrdn,ou=People," + TEST_ROOT_DN_STRING), 10000, true);
392N/A
392N/A // check that the operation has been correctly relayed
392N/A assertNotNull(resultEntry,
392N/A "The modify dn was not or badly replayed");
1423N/A assertEquals(getMonitorDelta(), 1);
3853N/A
2181N/A // Check that there was no administrative alert generated
2181N/A // because the conflict has been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount,
2181N/A "An alert was incorrectly generated when resolving conflicts");
2181N/A
398N/A
392N/A /*
398N/A * Check that conflicting entries are renamed when a
392N/A * modifyDN is done with the same DN as an entry added on another server.
392N/A */
398N/A
392N/A // add a second entry
1367N/A addMsg = new AddMsg(gen.newChangeNumber(),
392N/A user1dn,
392N/A user1entrysecondUUID,
392N/A baseUUID,
392N/A personWithSecondUniqueID.getObjectClassAttribute(),
398N/A personWithSecondUniqueID.getAttributes(), new ArrayList<Attribute>());
392N/A broker.publish(addMsg);
398N/A
392N/A // check that the second entry has been added
544N/A resultEntry = getEntry(DN.decode(user1dn), 10000, true);
398N/A
392N/A // check that the add operation has been applied
392N/A assertNotNull(resultEntry, "The add operation was not replayed");
398N/A
392N/A // try to rename the first entry
1367N/A modDnMsg = new ModifyDNMsg(user1dn, gen.newChangeNumber(),
392N/A user1entrysecondUUID, baseUUID, false,
392N/A baseDn.toString(), "uid=reallynewrdn");
1523N/A updateMonitorCount(baseDn, unresolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
392N/A broker.publish(modDnMsg);
398N/A
392N/A // check that the second entry has been renamed
392N/A resultEntry = getEntry(
392N/A DN.decode("entryUUID = " + user1entrysecondUUID + "+uid=reallynewrdn," +
3853N/A "ou=People," + TEST_ROOT_DN_STRING), 10000, true);
392N/A assertNotNull(resultEntry, "The modifyDN was not or incorrectly replayed");
1423N/A assertEquals(getMonitorDelta(), 1);
1523N/A assertConflictAttribute(resultEntry);
3853N/A
2181N/A // Check that there was no administrative alert generated
2181N/A // because the conflict has been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount+1,
2181N/A "An alert was not generated when resolving conflicts");
2181N/A
398N/A
392N/A // delete the entries to clean the database
385N/A delMsg =
398N/A new DeleteMsg("entryUUID = " + user1entrysecondUUID + "+" +
392N/A DN.decode(user1dn).getRDN().toString() +
3853N/A ",ou=People," + TEST_ROOT_DN_STRING,
1367N/A gen.newChangeNumber(), user1entrysecondUUID);
392N/A broker.publish(delMsg);
392N/A resultEntry = getEntry(
398N/A DN.decode("entryUUID = " + user1entrysecondUUID + "+" +
392N/A DN.decode(user1dn).getRDN().toString() +
3853N/A ",ou=People," + TEST_ROOT_DN_STRING), 10000, false);
398N/A
385N/A // check that the delete operation has been applied
385N/A assertNull(resultEntry,
1183N/A "The DELETE replication message was not replayed");
702N/A
5163N/A delMsg =
5163N/A new DeleteMsg("uid=reallynewrdn,ou=People," + TEST_ROOT_DN_STRING,
5163N/A gen.newChangeNumber(), user1entryUUID);
5163N/A broker.publish(delMsg);
5163N/A resultEntry = getEntry(
5163N/A DN.decode("uid=reallynewrdn,ou=People," + TEST_ROOT_DN_STRING), 10000, false);
5163N/A
5163N/A // check that the delete operation has been applied
5163N/A assertNull(resultEntry,
5163N/A "The DELETE replication message was not replayed");
5163N/A
702N/A /*
702N/A * When replaying add operations it is possible that the parent entry has
702N/A * been renamed before and that another entry have taken the former dn of
1183N/A * the parent entry. In such case the replication replay code should
702N/A * detect that the parent has been renamed and should add the entry below
707N/A * the new dn of the parent (thus changing the original dn with which the
702N/A * entry had been created)
702N/A *
702N/A * Steps
702N/A * - create parent entry 1 with baseDn1
702N/A * - create Add Msg for user1 with parent entry 1 UUID
702N/A * - MODDN parent entry 1 to baseDn2 in the LDAP server
702N/A * - add new parent entry 2 with baseDn1
702N/A * - publish msg
707N/A * - check that the Dn has been changed to baseDn2 in the msg received
702N/A */
702N/A
702N/A // - create parent entry 1 with baseDn1
702N/A String[] topEntries = new String[1];
702N/A topEntries[0] = "dn: ou=baseDn1,"+baseDn+"\n" + "objectClass: top\n"
702N/A + "objectClass: organizationalUnit\n"
702N/A + "entryUUID: 55555555-5555-5555-5555-555555555555\n";
702N/A Entry entry;
775N/A for (String entryStr : topEntries)
702N/A {
775N/A entry = TestCaseUtils.entryFromLdifString(entryStr);
1689N/A AddOperationBasis addOp = new AddOperationBasis(connection,
702N/A InternalClientConnection.nextOperationID(), InternalClientConnection
702N/A .nextMessageID(), null, entry.getDN(), entry.getObjectClasses(),
702N/A entry.getUserAttributes(), entry.getOperationalAttributes());
702N/A addOp.setInternalOperation(true);
702N/A addOp.run();
702N/A }
702N/A resultEntry = getEntry(
702N/A DN.decode("ou=baseDn1,"+baseDn), 10000, true);
702N/A assertNotNull(resultEntry,
702N/A "Entry not added: ou=baseDn1,"+baseDn);
702N/A
702N/A // - create Add Msg for user1 with parent entry 1 UUID
1367N/A addMsg = new AddMsg(gen.newChangeNumber(),
702N/A "uid=new person,ou=baseDn1,"+baseDn,
702N/A user1entryUUID,
702N/A getEntryUUID(DN.decode("ou=baseDn1,"+baseDn)),
702N/A personWithUUIDEntry.getObjectClassAttribute(),
702N/A personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
702N/A
702N/A // - MODDN parent entry 1 to baseDn2 in the LDAP server
1858N/A ModifyDNOperationBasis modDNOp = new ModifyDNOperationBasis(connection,
702N/A InternalClientConnection.nextOperationID(), InternalClientConnection
707N/A .nextMessageID(), null,
702N/A DN.decode("ou=baseDn1,"+baseDn),
707N/A RDN.decode("ou=baseDn2"), true,
702N/A baseDn);
702N/A modDNOp.run();
702N/A
702N/A resultEntry = getEntry(
702N/A DN.decode("ou=baseDn2,"+baseDn), 10000, true);
702N/A assertNotNull(resultEntry,
702N/A "Entry not moved from ou=baseDn1,"+baseDn+" to ou=baseDn2,"+baseDn);
702N/A
702N/A // - add new parent entry 2 with baseDn1
775N/A String p2 = "dn: ou=baseDn1,"+baseDn+"\n" + "objectClass: top\n"
775N/A + "objectClass: organizationalUnit\n"
775N/A + "entryUUID: 66666666-6666-6666-6666-666666666666\n";
702N/A entry = TestCaseUtils.entryFromLdifString(p2);
1689N/A AddOperationBasis addOp = new AddOperationBasis(connection,
702N/A InternalClientConnection.nextOperationID(), InternalClientConnection
702N/A .nextMessageID(), null, entry.getDN(), entry.getObjectClasses(),
702N/A entry.getUserAttributes(), entry.getOperationalAttributes());
702N/A addOp.setInternalOperation(true);
702N/A addOp.run();
702N/A
702N/A
702N/A // - publish msg
1523N/A updateMonitorCount(baseDn, resolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
702N/A broker.publish(addMsg);
702N/A
3853N/A // - check that the DN has been changed to baseDn2
702N/A resultEntry = getEntry(
715N/A DN.decode("uid=new person,ou=baseDn1,"+baseDn), 10000, false);
702N/A assertNull(resultEntry,
1183N/A "The ADD replication message was applied under ou=baseDn1,"+baseDn);
702N/A
702N/A resultEntry = getEntry(
702N/A DN.decode("uid=new person,ou=baseDn2,"+baseDn), 10000, true);
702N/A assertNotNull(resultEntry,
1183N/A "The ADD replication message was NOT applied under ou=baseDn2,"+baseDn);
1423N/A assertEquals(getMonitorDelta(), 1);
3988N/A
2181N/A // Check that there was no administrative alert generated
2181N/A // because the conflict has been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount,
2181N/A "An alert was incorrectly generated when resolving conflicts");
2181N/A
3988N/A
1523N/A //
1523N/A // Check that when a delete is conflicting with Add of some entries
1523N/A // below the deleted entries, the child entry that have been added
1523N/A // before the deleted is replayed gets renamed correctly.
1523N/A //
3988N/A
3853N/A // add domain1 entry with 2 children : domain2 and domain3
1523N/A addEntry(domain1);
4072N/A ChangeNumber olderCn = gen.newChangeNumber();
4072N/A Thread.sleep(1000);
1523N/A domain1uid = getEntryUUID(DN.decode(domain1dn));
1523N/A addEntry(domain2);
1523N/A domain2uid = getEntryUUID(DN.decode(domain2dn));
1523N/A addEntry(domain3);
1523N/A domain3uid = getEntryUUID(DN.decode(domain3dn));
1523N/A DN conflictDomain2dn = DN.decode(
3853N/A "entryUUID = " + domain2uid + "+dc=domain2,ou=people," + TEST_ROOT_DN_STRING);
1523N/A DN conflictDomain3dn = DN.decode(
3853N/A "entryUUID = " + domain3uid + "+dc=domain3,ou=people," + TEST_ROOT_DN_STRING);
3988N/A
1523N/A updateMonitorCount(baseDn, unresolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
3988N/A
1523N/A // delete domain1
4072N/A delMsg = new DeleteMsg(domain1dn, olderCn, domain1uid);
1523N/A broker.publish(delMsg);
702N/A
1523N/A // check that the domain1 has correctly been deleted
1523N/A assertNull(getEntry(DN.decode(domain1dn), 10000, false),
1523N/A "The DELETE replication message was not replayed");
3988N/A
1523N/A // check that domain2 and domain3 have been renamed
1523N/A assertNotNull(getEntry(conflictDomain2dn, 1000, true),
1523N/A "The conflicting entries were not created");
1523N/A assertNotNull(getEntry(conflictDomain3dn, 1000, true),
1523N/A "The conflicting entries were not created");
702N/A
1523N/A // check that the 2 conflicting entries have been correctly marked
1523N/A assertTrue(checkEntryHasAttribute(conflictDomain2dn,
5163N/A LDAPReplicationDomain.DS_SYNC_CONFLICT, domain2dn, 1000, true));
1523N/A assertTrue(checkEntryHasAttribute(conflictDomain3dn,
5163N/A LDAPReplicationDomain.DS_SYNC_CONFLICT, domain3dn, 1000, true));
3988N/A
1523N/A // check that unresolved conflict count has been incremented
1523N/A assertEquals(getMonitorDelta(), 1);
3988N/A
2181N/A // Check that an administrative alert was generated
2181N/A // because the conflict has not been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount+2,
2181N/A "An alert was incorrectly generated when resolving conflicts");
2181N/A
3988N/A
1523N/A // delete the resulting entries for the next test
1523N/A delEntry(conflictDomain2dn);
1523N/A delEntry(conflictDomain3dn);
3988N/A
4088N/A
1523N/A //
4072N/A // Check that when a delete is replayed over an entry which has child
4072N/A // those child are also deleted
4072N/A //
4072N/A // add domain1 entry with 2 children : domain2 and domain3
4072N/A addEntry(domain1);
4072N/A domain1uid = getEntryUUID(DN.decode(domain1dn));
4072N/A addEntry(domain2);
4072N/A domain2uid = getEntryUUID(DN.decode(domain2dn));
4088N/A ChangeNumber addCn = addEntry(domain3);
4088N/A gen.adjust(addCn);
4072N/A domain3uid = getEntryUUID(DN.decode(domain3dn));
4072N/A
4072N/A updateMonitorCount(baseDn, unresolvedMonitorAttr);
4072N/A AlertCount = DummyAlertHandler.getAlertCount();
4072N/A
4072N/A // delete domain1
4072N/A delMsg = new DeleteMsg(domain1dn, gen.newChangeNumber(), domain1uid);
4072N/A broker.publish(delMsg);
4072N/A
4072N/A // check that the domain1 has correctly been deleted
4072N/A assertNull(getEntry(DN.decode(domain1dn), 10000, false),
4072N/A "The DELETE replication message was not replayed");
4072N/A
5129N/A // check that domain2 and domain3 have been renamed as conflicting
5129N/A String confDomain2dn = "entryuuid="+domain2uid+"+dc=domain2,ou=people,"+TEST_ROOT_DN_STRING;
5129N/A String confDomain3dn = "entryuuid="+domain3uid+"+dc=domain3,ou=people,"+TEST_ROOT_DN_STRING;
5129N/A assertTrue(DirectoryServer.entryExists(DN.decode(confDomain2dn)),
5129N/A "The conflicting entry exist for domain2" + confDomain2dn);
5129N/A assertTrue(DirectoryServer.entryExists(DN.decode(confDomain3dn)),
5129N/A "The conflicting entry exist for domain3" + confDomain3dn);
5129N/A // check that unresolved conflict count has been incremented
5129N/A assertEquals(getMonitorDelta(), 1);
4072N/A
5129N/A delEntry(DN.decode(confDomain2dn));
5129N/A delEntry(DN.decode(confDomain3dn));
4072N/A
4072N/A //
1523N/A // Check that when an entry is added on one master below an entry
1523N/A // that is currently deleted on another master, the replay of the
1523N/A // add on the second master cause the added entry to be renamed
1523N/A //
1523N/A addMsg = new AddMsg(gen.newChangeNumber(), domain2dn, domain2uid,
1523N/A domain1uid,
1523N/A domain2.getObjectClassAttribute(),
1523N/A domain2.getAttributes(), new ArrayList<Attribute>());
1523N/A broker.publish(addMsg);
3988N/A
1523N/A // check that conflict entry was created
1523N/A assertNotNull(getEntry(conflictDomain2dn, 1000, true),
1523N/A "The conflicting entries were not created");
3988N/A
1523N/A // check that the entry have been correctly marked as conflicting.
1523N/A assertTrue(checkEntryHasAttribute(conflictDomain2dn,
3988N/A LDAPReplicationDomain.DS_SYNC_CONFLICT, domain2dn, 1000, true));
3988N/A
1523N/A // check that unresolved conflict count has been incremented
1523N/A assertEquals(getMonitorDelta(), 1);
3988N/A
1730N/A // Check that when an entry is deleted on a first master and
1730N/A // renamed on a second master and the rename is replayed last
1730N/A // this is correctly detected as a resolved conflict.
1730N/A // To simulate this simply try a modifyDN on a non existent uid.
1730N/A modDnMsg = new ModifyDNMsg(
3853N/A "uid=new person,ou=People," + TEST_ROOT_DN_STRING, gen.newChangeNumber(),
1730N/A "33343333-3533-3633-3373-333333833333", baseUUID, false,
3853N/A "uid=wrong, ou=people," + TEST_ROOT_DN_STRING,
1730N/A "uid=newrdn");
1730N/A updateMonitorCount(baseDn, resolvedMonitorAttr);
2181N/A AlertCount = DummyAlertHandler.getAlertCount();
1730N/A broker.publish(modDnMsg);
1730N/A // unfortunately it is difficult to check that the operation
1730N/A // did not do anything.
2606N/A // The only thing we can check is that resolved naming conflict counter
1730N/A // has correctly been incremented.
2606N/A int count = 0;
2606N/A while ((count<2000) && getMonitorDelta() == 0)
2606N/A {
2606N/A // it is possible that the update has not yet been applied
2606N/A // wait a short time and try again.
2606N/A Thread.sleep(100);
2606N/A count++;
2606N/A }
2606N/A // if the monitor counter did not get incremented after 200sec
2606N/A // then something got wrong.
2606N/A assertTrue(count < 200);
3988N/A
2181N/A // Check that there was no administrative alert generated
2181N/A // because the conflict has been automatically resolved.
2181N/A assertEquals(DummyAlertHandler.getAlertCount(), AlertCount,
2181N/A "An alert was incorrectly generated when resolving conflicts");
2181N/A
2903N/A /*
3988N/A * Check that a conflict is detected when an entry is
2903N/A * moved below an entry that does not exist.
2903N/A */
2903N/A updateMonitorCount(baseDn, unresolvedMonitorAttr);
2903N/A AlertCount = DummyAlertHandler.getAlertCount();
2903N/A modDnMsg = new ModifyDNMsg(
3853N/A "uid=new person,ou=People," + TEST_ROOT_DN_STRING, gen.newChangeNumber(),
2903N/A "33333333-3333-3333-3333-333333333333",
2903N/A "12343333-3533-3633-3333-333333833333" , false,
3853N/A "uid=wrong, ou=people," + TEST_ROOT_DN_STRING,
2903N/A "uid=newrdn");
2903N/A broker.publish(modDnMsg);
3988N/A
2903N/A count = 0;
2903N/A while ((count<2000) && getMonitorDelta() == 0)
2903N/A {
2903N/A // it is possible that the update has not yet been applied
2903N/A // wait a short time and try again.
2903N/A Thread.sleep(100);
2903N/A count++;
2903N/A }
2903N/A // if the monitor counter did not get incremented after 200sec
2903N/A // then something got wrong.
2903N/A assertTrue(count < 200);
3988N/A
2903N/A // check that the entry have been correctly marked as conflicting.
2903N/A assertTrue(checkEntryHasAttribute(
2903N/A DN.decode("uid=new person,ou=baseDn2,"+baseDn),
3988N/A LDAPReplicationDomain.DS_SYNC_CONFLICT,
3853N/A "uid=newrdn,ou=baseDn2,ou=People," + TEST_ROOT_DN_STRING, 1000, true));
5529N/A }
5529N/A finally
5529N/A {
5529N/A broker.stop();
5529N/A }
385N/A }
385N/A
1523N/A /**
1523N/A * Check that the given entry does contain the attribute that mark the
1523N/A * entry as conflicting.
1523N/A *
1523N/A * @param entry The entry that needs to be asserted.
1523N/A *
1523N/A * @return A boolean indicating if the entry is correctly marked.
1523N/A */
1523N/A private boolean assertConflictAttribute(Entry entry)
1523N/A {
1523N/A List<Attribute> attrs = entry.getAttribute("ds-sync-confict");
1523N/A
1523N/A if (attrs == null)
1523N/A return false;
1523N/A else
1523N/A return true;
1523N/A }
1523N/A
398N/A @DataProvider(name="assured")
398N/A public Object[][] getAssuredFlag()
398N/A {
398N/A return new Object[][] { { false }, {true} };
398N/A }
864N/A
4890N/A private void cleanupTest() {
4890N/A try
4890N/A {
4890N/A classCleanUp();
4890N/A setUp();
4890N/A } catch (Exception e)
4890N/A {
4890N/A fail("Test cleanup failed: " + e.getClass().getName() + " : " +
4890N/A e.getMessage() + " : " + StaticUtils.stackTraceToSingleLineString(e));
4890N/A }
4890N/A }
4890N/A
385N/A /**
1191N/A * Tests done using directly the ReplicationBroker interface.
188N/A */
3028N/A @Test(enabled=true, dataProvider="assured")
398N/A public void updateOperations(boolean assured) throws Exception
188N/A {
2086N/A logError(Message.raw(
2089N/A Category.SYNC, Severity.INFORMATION,
2089N/A "Starting replication test : updateOperations " + assured));
544N/A
4890N/A // Cleanup from previous run
4890N/A cleanupTest();
4890N/A
3853N/A final DN baseDn = DN.decode("ou=People," + TEST_ROOT_DN_STRING);
544N/A
1191N/A ReplicationBroker broker =
4802N/A openReplicationSession(baseDn, 27, 100, replServerPort, 2000, true);
4802N/A
535N/A try {
4802N/A ChangeNumberGenerator gen = new ChangeNumberGenerator( 27, 0);
385N/A
535N/A /*
535N/A * Test that operations done on this server are sent to the
1191N/A * replicationServer and forwarded to our replicationServer broker session.
535N/A */
385N/A
535N/A // Create an Entry (add operation)
1057N/A Entry tmp = personEntry.duplicate(false);
1689N/A AddOperationBasis addOp = new AddOperationBasis(connection,
535N/A InternalClientConnection.nextOperationID(), InternalClientConnection
535N/A .nextMessageID(), null, tmp.getDN(),
535N/A tmp.getObjectClasses(), tmp.getUserAttributes(),
535N/A tmp.getOperationalAttributes());
535N/A addOp.run();
582N/A assertTrue(DirectoryServer.entryExists(personEntry.getDN()),
385N/A "The Add Entry operation failed");
385N/A
904N/A if (ResultCode.SUCCESS.equals(addOp.getResultCode()))
904N/A {
904N/A // Check if the client has received the msg
3853N/A ReplicationMsg msg = broker.receive();
904N/A assertTrue(msg instanceof AddMsg,
4890N/A "The received replication message is not an ADD msg : " + msg);
904N/A AddMsg addMsg = (AddMsg) msg;
385N/A
904N/A Operation receivedOp = addMsg.createOperation(connection);
904N/A assertTrue(OperationType.ADD.compareTo(receivedOp.getOperationType()) == 0,
4890N/A "The received replication message is not an ADD msg : " + addMsg);
385N/A
904N/A assertEquals(DN.decode(addMsg.getDn()),personEntry.getDN(),
4890N/A "The received ADD replication message is not for the excepted DN : " + addMsg);
904N/A }
385N/A
535N/A // Modify the entry
535N/A List<Modification> mods = generatemods("telephonenumber", "01 02 45");
385N/A
1689N/A ModifyOperationBasis modOp = new ModifyOperationBasis(connection,
535N/A InternalClientConnection.nextOperationID(), InternalClientConnection
535N/A .nextMessageID(), null, personEntry.getDN(), mods);
535N/A modOp.setInternalOperation(true);
535N/A modOp.run();
385N/A
535N/A // See if the client has received the msg
3853N/A ReplicationMsg msg = broker.receive();
535N/A assertTrue(msg instanceof ModifyMsg,
4890N/A "The received replication message is not a MODIFY msg : " + msg);
535N/A ModifyMsg modMsg = (ModifyMsg) msg;
385N/A
1162N/A modMsg.createOperation(connection);
535N/A assertTrue(DN.decode(modMsg.getDn()).compareTo(personEntry.getDN()) == 0,
4890N/A "The received MODIFY replication message is not for the excepted DN : " + modMsg);
385N/A
535N/A // Modify the entry DN
3853N/A DN newDN = DN.decode("uid= new person,ou=People," + TEST_ROOT_DN_STRING) ;
1858N/A ModifyDNOperationBasis modDNOp = new ModifyDNOperationBasis(connection,
535N/A InternalClientConnection.nextOperationID(), InternalClientConnection
535N/A .nextMessageID(), null, personEntry.getDN(), RDN
535N/A .decode("uid=new person"), true, DN
3853N/A .decode("ou=People," + TEST_ROOT_DN_STRING));
535N/A modDNOp.run();
582N/A assertTrue(DirectoryServer.entryExists(newDN),
535N/A "The MOD_DN operation didn't create the new person entry");
582N/A assertFalse(DirectoryServer.entryExists(personEntry.getDN()),
535N/A "The MOD_DN operation didn't delete the old person entry");
385N/A
535N/A // See if the client has received the msg
535N/A msg = broker.receive();
535N/A assertTrue(msg instanceof ModifyDNMsg,
4890N/A "The received replication message is not a MODIFY DN msg : " + msg);
535N/A ModifyDNMsg moddnMsg = (ModifyDNMsg) msg;
1162N/A moddnMsg.createOperation(connection);
385N/A
535N/A assertTrue(DN.decode(moddnMsg.getDn()).compareTo(personEntry.getDN()) == 0,
4890N/A "The received MODIFY_DN message is not for the excepted DN : " + moddnMsg);
385N/A
535N/A // Delete the entry
1689N/A DeleteOperationBasis delOp = new DeleteOperationBasis(connection,
535N/A InternalClientConnection.nextOperationID(), InternalClientConnection
535N/A .nextMessageID(), null, DN
3853N/A .decode("uid= new person,ou=People," + TEST_ROOT_DN_STRING));
535N/A delOp.run();
582N/A assertFalse(DirectoryServer.entryExists(newDN),
535N/A "Unable to delete the new person Entry");
385N/A
535N/A // See if the client has received the msg
535N/A msg = broker.receive();
535N/A assertTrue(msg instanceof DeleteMsg,
4890N/A "The received replication message is not a MODIFY DN msg : " + msg);
535N/A DeleteMsg delMsg = (DeleteMsg) msg;
1162N/A delMsg.createOperation(connection);
535N/A assertTrue(DN.decode(delMsg.getDn()).compareTo(DN
3853N/A .decode("uid= new person,ou=People," + TEST_ROOT_DN_STRING)) == 0,
4890N/A "The received DELETE message is not for the excepted DN : " + delMsg);
385N/A
535N/A /*
1191N/A * Now check that when we send message to the ReplicationServer
535N/A * and that they are received and correctly replayed by the server.
535N/A *
535N/A * Start by testing the Add message reception
535N/A */
1367N/A AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
535N/A personWithUUIDEntry.getDN().toString(),
535N/A user1entryUUID, baseUUID,
535N/A personWithUUIDEntry.getObjectClassAttribute(),
535N/A personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
535N/A if (assured)
3853N/A addMsg.setAssured(true);
535N/A broker.publish(addMsg);
385N/A
535N/A /*
535N/A * Check that the entry has been created in the local DS.
535N/A */
544N/A Entry resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, true);
535N/A assertNotNull(resultEntry,
1183N/A "The send ADD replication message was not applied for "+personWithUUIDEntry.getDN().toString());
385N/A
535N/A /*
535N/A * Test the reception of Modify Msg
535N/A */
1367N/A modMsg = new ModifyMsg(gen.newChangeNumber(), personWithUUIDEntry.getDN(),
535N/A mods, user1entryUUID);
535N/A if (assured)
3853N/A modMsg.setAssured(true);
535N/A broker.publish(modMsg);
385N/A
535N/A boolean found = checkEntryHasAttribute(personWithUUIDEntry.getDN(),
544N/A "telephonenumber", "01 02 45", 10000, true);
385N/A
535N/A if (found == false)
535N/A fail("The modification has not been correctly replayed.");
3988N/A
1737N/A // Test that replication is able to add attribute that do
1737N/A // not exist in the schema.
1737N/A List<Modification> invalidMods = generatemods("badattribute", "value");
1737N/A modMsg = new ModifyMsg(gen.newChangeNumber(), personWithUUIDEntry.getDN(),
1737N/A invalidMods, user1entryUUID);
1737N/A if (assured)
3853N/A modMsg.setAssured(true);
1737N/A broker.publish(modMsg);
1737N/A
1737N/A found = checkEntryHasAttribute(
1737N/A personWithUUIDEntry.getDN(), "badattribute", "value", 10000, true);
1737N/A if (found == false)
1737N/A fail("The modification has not been correctly replayed.");
385N/A
535N/A /*
535N/A * Test the Reception of Modify Dn Msg
535N/A */
535N/A moddnMsg = new ModifyDNMsg(personWithUUIDEntry.getDN().toString(),
1367N/A gen.newChangeNumber(),
535N/A user1entryUUID, null,
535N/A true, null, "uid= new person");
535N/A if (assured)
3853N/A moddnMsg.setAssured(true);
535N/A broker.publish(moddnMsg);
385N/A
535N/A resultEntry = getEntry(
3853N/A DN.decode("uid= new person,ou=People," + TEST_ROOT_DN_STRING), 10000, true);
385N/A
535N/A assertNotNull(resultEntry,
1183N/A "The modify DN replication message was not applied");
385N/A
535N/A /*
535N/A * Test the Reception of Delete Msg
535N/A */
3853N/A delMsg = new DeleteMsg("uid= new person,ou=People," + TEST_ROOT_DN_STRING,
1367N/A gen.newChangeNumber(), user1entryUUID);
535N/A if (assured)
3853N/A delMsg.setAssured(true);
535N/A broker.publish(delMsg);
535N/A resultEntry = getEntry(
3853N/A DN.decode("uid= new person,ou=People," + TEST_ROOT_DN_STRING), 10000, false);
385N/A
535N/A assertNull(resultEntry,
1183N/A "The DELETE replication message was not replayed");
535N/A }
535N/A finally
535N/A {
535N/A broker.stop();
535N/A }
385N/A }
385N/A
385N/A
385N/A /**
437N/A * Test case for
437N/A * [Issue 635] NullPointerException when trying to access non existing entry.
437N/A */
437N/A @Test(enabled=true)
437N/A public void deleteNoSuchObject() throws Exception
437N/A {
2089N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION,
2089N/A "Starting replication test : deleteNoSuchObject"));
544N/A
4890N/A // Clean replication server database from previous run
4890N/A cleanUpReplicationServersDB();
4890N/A
3853N/A DN dn = DN.decode("cn=No Such Object,ou=People," + TEST_ROOT_DN_STRING);
1689N/A DeleteOperationBasis op =
1689N/A new DeleteOperationBasis(connection,
437N/A InternalClientConnection.nextOperationID(),
437N/A InternalClientConnection.nextMessageID(), null,
437N/A dn);
437N/A op.run();
437N/A assertEquals(op.getResultCode(), ResultCode.NO_SUCH_OBJECT);
437N/A }
442N/A
442N/A /**
442N/A * Test case for
442N/A * [Issue 798] break infinite loop when problems with naming resolution
442N/A * conflict.
442N/A */
3031N/A @Test(enabled=true)
442N/A public void infiniteReplayLoop() throws Exception
442N/A {
2089N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION,
2089N/A "Starting replication test : infiniteReplayLoop"));
544N/A
3853N/A final DN baseDn = DN.decode("ou=People," + TEST_ROOT_DN_STRING);
3988N/A
4890N/A // Clean replication server database from previous run
4890N/A cleanUpReplicationServersDB();
4890N/A
535N/A Thread.sleep(2000);
1191N/A ReplicationBroker broker =
4802N/A openReplicationSession(baseDn, 11, 100, replServerPort, 1000, true);
442N/A try
442N/A {
4802N/A ChangeNumberGenerator gen = new ChangeNumberGenerator( 11, 0);
442N/A
442N/A // Create a test entry.
3853N/A String personLdif = "dn: uid=user.2,ou=People," + TEST_ROOT_DN_STRING + "\n"
442N/A + "objectClass: top\n" + "objectClass: person\n"
442N/A + "objectClass: organizationalPerson\n"
442N/A + "objectClass: inetOrgPerson\n" + "uid: user.2\n"
442N/A + "homePhone: 951-245-7634\n"
442N/A + "description: This is the description for Aaccf Amar.\n"
442N/A + "st: NC\n"
442N/A + "mobile: 027-085-0537\n"
442N/A + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
442N/A + "$Rockford, NC 85762\n" + "mail: user.1@example.com\n"
442N/A + "cn: Aaccf Amar\n" + "l: Rockford\n" + "pager: 508-763-4246\n"
442N/A + "street: 17984 Thirteenth Street\n"
442N/A + "telephoneNumber: 216-564-6748\n" + "employeeNumber: 1\n"
442N/A + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
442N/A + "userPassword: password\n" + "initials: AA\n";
442N/A Entry tmp = TestCaseUtils.entryFromLdifString(personLdif);
1689N/A AddOperationBasis addOp =
1689N/A new AddOperationBasis(connection,
442N/A InternalClientConnection.nextOperationID(),
442N/A InternalClientConnection.nextMessageID(),
442N/A null, tmp.getDN(), tmp.getObjectClasses(),
442N/A tmp.getUserAttributes(),
442N/A tmp.getOperationalAttributes());
442N/A addOp.run();
442N/A assertEquals(addOp.getResultCode(), ResultCode.SUCCESS);
442N/A
1423N/A long initialCount = getMonitorAttrValue(baseDn, "replayed-updates");
442N/A
442N/A // Get the UUID of the test entry.
582N/A Entry resultEntry = getEntry(tmp.getDN(), 1, true);
442N/A AttributeType uuidType = DirectoryServer.getAttributeType("entryuuid");
442N/A String uuid =
442N/A resultEntry.getAttributeValue(uuidType,
442N/A DirectoryStringSyntax.DECODER);
442N/A
442N/A // Register a short circuit that will fake a no-such-object result code
1183N/A // on a delete. This will cause a replication replay loop.
442N/A ShortCircuitPlugin.registerShortCircuit(OperationType.DELETE,
442N/A "PreParse", 32);
442N/A try
442N/A {
442N/A // Publish a delete message for this test entry.
442N/A DeleteMsg delMsg = new DeleteMsg(tmp.getDN().toString(),
1367N/A gen.newChangeNumber(),
442N/A uuid);
442N/A broker.publish(delMsg);
442N/A
442N/A // Wait for the operation to be replayed.
442N/A long endTime = System.currentTimeMillis() + 5000;
1423N/A while (getMonitorAttrValue(baseDn, "replayed-updates") == initialCount &&
442N/A System.currentTimeMillis() < endTime)
442N/A {
442N/A Thread.sleep(100);
442N/A }
442N/A }
442N/A finally
442N/A {
442N/A ShortCircuitPlugin.deregisterShortCircuit(OperationType.DELETE,
442N/A "PreParse");
442N/A }
442N/A
1183N/A // If the replication replay loop was detected and broken then the
442N/A // counter will still be updated even though the replay was unsuccessful.
1423N/A if (getMonitorAttrValue(baseDn, "replayed-updates") == initialCount)
442N/A {
1183N/A fail("Operation was not replayed");
442N/A }
442N/A }
442N/A finally
442N/A {
442N/A broker.stop();
442N/A }
442N/A }
442N/A
442N/A /**
707N/A * Enable or disable the receive status of a synchronization provider.
707N/A *
707N/A * @param syncConfigDN The DN of the synchronization provider configuration
707N/A * entry.
707N/A * @param enable Specifies whether the receive status should be enabled
707N/A * or disabled.
707N/A */
707N/A private static void setReceiveStatus(String syncConfigDN, boolean enable)
707N/A {
4134N/A ArrayList<ByteString> valueList = new ArrayList<ByteString>(1);
707N/A if (enable)
707N/A {
4134N/A valueList.add(ByteString.valueOf("TRUE"));
707N/A }
707N/A else
707N/A {
4134N/A valueList.add(ByteString.valueOf("FALSE"));
707N/A }
707N/A LDAPAttribute a = new LDAPAttribute("ds-cfg-receive-status", valueList);
707N/A
707N/A LDAPModification m = new LDAPModification(ModificationType.REPLACE, a);
707N/A
1177N/A ArrayList<RawModification> modList = new ArrayList<RawModification>(1);
707N/A modList.add(m);
707N/A
707N/A InternalClientConnection conn =
707N/A InternalClientConnection.getRootConnection();
4134N/A ByteString rawEntryDN =
4134N/A ByteString.valueOf(syncConfigDN);
707N/A ModifyOperation internalModify = conn.processModify(rawEntryDN, modList);
707N/A
707N/A ResultCode resultCode = internalModify.getResultCode();
707N/A if (resultCode != ResultCode.SUCCESS)
707N/A {
707N/A throw new RuntimeException("Cannot set receive status");
707N/A }
707N/A }
3324N/A /**
3324N/A * Test that the ReplicationDomain (plugin inside LDAP server) adjust
3324N/A * its internal change number generator to the last change number
3324N/A * received. Steps:
3324N/A * - create a domain with the current date in the CN generator
3324N/A * - make it receive an update with a CN in the future
3324N/A * - do a local operation replicated on that domain
3324N/A * - check that the update generated for that operation has a CN in the
3853N/A * future.
3324N/A * @throws Exception
3324N/A */
3324N/A @Test(enabled=true)
3324N/A public void CNGeneratorAdjust() throws Exception
3324N/A {
4802N/A int serverId = 88;
3324N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION,
3324N/A "Starting synchronization test : CNGeneratorAdjust"));
3324N/A
3853N/A final DN baseDn = DN.decode("ou=People," + TEST_ROOT_DN_STRING);
3988N/A
4890N/A // Clean replication server database from previous run
4890N/A cleanUpReplicationServersDB();
4890N/A
3324N/A /*
3324N/A * Open a session to the replicationServer using the broker API.
3324N/A * This must use a different serverId to that of the directory server.
3324N/A */
3324N/A ReplicationBroker broker =
3324N/A openReplicationSession(baseDn, serverId, 100, replServerPort, 1000, true);
3324N/A
5529N/A try
5529N/A {
5529N/A /*
5529N/A * Create a Change number generator to generate new changenumbers
5529N/A * when we need to send operation messages to the replicationServer.
5529N/A */
5529N/A long inTheFutur = System.currentTimeMillis() + (3600 * 1000);
5529N/A ChangeNumberGenerator gen = new ChangeNumberGenerator(serverId, inTheFutur);
3324N/A
5529N/A // Create and publish an update message to add an entry.
5529N/A AddMsg addMsg = new AddMsg(
5529N/A gen.newChangeNumber(),
5529N/A user3dn.toString(),
5529N/A user3UUID,
5529N/A baseUUID,
5529N/A user3Entry.getObjectClassAttribute(),
5529N/A user3Entry.getAttributes(),
5529N/A new ArrayList<Attribute>());
5529N/A broker.publish(addMsg);
3324N/A
5529N/A Entry resultEntry;
3324N/A
5529N/A // Check that the entry has not been created in the directory server.
5529N/A resultEntry = getEntry(user3Entry.getDN(), 1000, true);
5529N/A assertNotNull(resultEntry, "The entry has not been created");
3324N/A
5529N/A // Modify the entry
5529N/A List<Modification> mods = generatemods("telephonenumber", "01 02 45");
5529N/A ModifyOperationBasis modOp = new ModifyOperationBasis(
5529N/A connection,
5529N/A InternalClientConnection.nextOperationID(),
5529N/A InternalClientConnection.nextMessageID(),
5529N/A null,
5529N/A user3Entry.getDN(),
5529N/A mods);
5529N/A modOp.setInternalOperation(true);
5529N/A modOp.run();
3988N/A
5529N/A // See if the client has received the msg
5529N/A ReplicationMsg msg = broker.receive();
5529N/A assertTrue(msg instanceof ModifyMsg,
5529N/A "The received replication message is not a MODIFY msg");
5529N/A ModifyMsg modMsg = (ModifyMsg) msg;
5529N/A assertEquals(addMsg.getChangeNumber().getTimeSec(),
5529N/A modMsg.getChangeNumber().getTimeSec(),
5529N/A "The MOD timestamp should have been adjusted to the ADD one");
5529N/A
5529N/A // Delete the entries to clean the database.
5529N/A DeleteMsg delMsg =
5529N/A new DeleteMsg(
3324N/A user3Entry.getDN().toString(),
3324N/A gen.newChangeNumber(),
3324N/A user3UUID);
5529N/A broker.publish(delMsg);
3324N/A
5529N/A // Check that the delete operation has been applied.
5529N/A resultEntry = getEntry(user3Entry.getDN(), 10000, false);
5529N/A assertNull(resultEntry,
5529N/A "The DELETE replication message was not replayed");
5529N/A }
5529N/A finally
5529N/A {
5529N/A broker.stop();
5529N/A }
3324N/A }
188N/A}