2721N/A/*
2721N/A * CDDL HEADER START
2721N/A *
2721N/A * The contents of this file are subject to the terms of the
2721N/A * Common Development and Distribution License, Version 1.0 only
2721N/A * (the "License"). You may not use this file except in compliance
2721N/A * with the License.
2721N/A *
2721N/A * You can obtain a copy of the license at
2721N/A * trunk/opends/resource/legal-notices/OpenDS.LICENSE
2721N/A * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
2721N/A * See the License for the specific language governing permissions
2721N/A * and limitations under the License.
2721N/A *
2721N/A * When distributing Covered Code, include this CDDL HEADER in each
2721N/A * file and include the License file at
2721N/A * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
2721N/A * add the following below this CDDL HEADER, with the fields enclosed
2721N/A * by brackets "[]" replaced with your own identifying information:
2721N/A * Portions Copyright [yyyy] [name of copyright owner]
2721N/A *
2721N/A * CDDL HEADER END
2721N/A *
2721N/A *
5205N/A * Copyright 2008-2010 Sun Microsystems, Inc.
5753N/A * Portions Copyright 2011-2012 ForgeRock AS
2721N/A */
2721N/Apackage org.opends.server.replication.plugin;
2721N/A
5414N/Aimport java.io.File;
4908N/Aimport static org.opends.server.TestCaseUtils.TEST_ROOT_DN_STRING;
2721N/Aimport static org.opends.server.loggers.ErrorLogger.logError;
4908N/Aimport static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
2721N/Aimport static org.testng.Assert.assertEquals;
2721N/Aimport static org.testng.Assert.assertTrue;
4908N/Aimport static org.testng.Assert.fail;
2721N/A
4908N/Aimport java.io.IOException;
2721N/Aimport java.net.ServerSocket;
4908N/Aimport java.util.LinkedList;
2721N/Aimport java.util.List;
4908N/Aimport java.util.SortedSet;
4908N/Aimport java.util.TreeSet;
2721N/A
2721N/Aimport org.opends.messages.Category;
2721N/Aimport org.opends.messages.Message;
2721N/Aimport org.opends.messages.Severity;
2721N/Aimport org.opends.server.TestCaseUtils;
4908N/Aimport org.opends.server.admin.std.meta.ReplicationDomainCfgDefn.AssuredType;
4908N/Aimport org.opends.server.config.ConfigException;
2721N/Aimport org.opends.server.core.DirectoryServer;
2721N/Aimport org.opends.server.replication.ReplicationTestCase;
2721N/Aimport org.opends.server.replication.common.ChangeNumber;
4908N/Aimport org.opends.server.replication.protocol.AddMsg;
4908N/Aimport org.opends.server.replication.protocol.DeleteMsg;
4908N/Aimport org.opends.server.replication.protocol.LDAPUpdateMsg;
4908N/Aimport org.opends.server.replication.protocol.ModifyMsg;
4908N/Aimport org.opends.server.replication.protocol.ReplicationMsg;
4908N/Aimport org.opends.server.replication.server.ReplServerFakeConfiguration;
4908N/Aimport org.opends.server.replication.server.ReplicationServer;
4908N/Aimport org.opends.server.replication.service.ReplicationBroker;
2721N/Aimport org.opends.server.types.Attribute;
2721N/Aimport org.opends.server.types.AttributeType;
2721N/Aimport org.opends.server.types.AttributeValue;
2721N/Aimport org.opends.server.types.ByteString;
2721N/Aimport org.opends.server.types.DN;
4908N/Aimport org.opends.server.types.DirectoryException;
2721N/Aimport org.opends.server.types.Entry;
5414N/Aimport org.opends.server.util.StaticUtils;
4908N/Aimport org.opends.server.util.TimeThread;
2721N/Aimport org.testng.annotations.Test;
2721N/A
2721N/A/**
2721N/A * Test the usage of the historical data of the replication.
2721N/A */
2721N/Apublic class HistoricalCsnOrderingTest
4908N/A extends ReplicationTestCase
2721N/A{
4908N/A final int serverId = 123;
2721N/A
4908N/A public class TestBroker extends ReplicationBroker
4908N/A {
4908N/A LinkedList<ReplicationMsg> list = null;
2721N/A
4908N/A public TestBroker(LinkedList<ReplicationMsg> list)
4908N/A {
4908N/A super(null, null, null, 0, 0, (long) 0, (long) 0, null, (byte) 0, (long) 0);
4908N/A this.list = list;
4908N/A }
2721N/A
4908N/A public void publishRecovery(ReplicationMsg msg)
4908N/A {
4908N/A list.add(msg);
4908N/A }
2721N/A
2721N/A
2721N/A }
2721N/A
2721N/A /**
2721N/A * Check the basic comparator on the HistoricalCsnOrderingMatchingRule
2721N/A */
2721N/A @Test()
2721N/A public void basicRuleTest()
2721N/A throws Exception
2721N/A {
2721N/A // Creates a rule
3988N/A HistoricalCsnOrderingMatchingRule r =
2721N/A new HistoricalCsnOrderingMatchingRule();
2721N/A
4802N/A ChangeNumber del1 = new ChangeNumber(1, 0, 1);
4802N/A ChangeNumber del2 = new ChangeNumber(1, 1, 1);
2721N/A
4134N/A ByteString v1 = ByteString.valueOf("a"+":"+del1.toString());
4134N/A ByteString v2 = ByteString.valueOf("a"+":"+del2.toString());
2721N/A
2721N/A int cmp = r.compareValues(v1, v1);
2721N/A assertTrue(cmp == 0);
2721N/A
2721N/A cmp = r.compareValues(v1, v2);
2721N/A assertTrue(cmp == -1);
2721N/A
2721N/A cmp = r.compareValues(v2, v1);
2721N/A assertTrue(cmp == 1);
2721N/A }
2721N/A
2721N/A /**
3988N/A * Test that we can retrieve the entries that were missed by
2721N/A * a replication server and can re-build operations from the historical
2721N/A * informations.
2721N/A */
2721N/A @Test()
4908N/A public void buildAndPublishMissingChangesOneEntryTest()
2721N/A throws Exception
2721N/A {
4908N/A final int serverId = 123;
4908N/A final DN baseDn = DN.decode(TEST_ROOT_DN_STRING);
4908N/A TestCaseUtils.initializeTestBackend(true);
4908N/A ReplicationServer rs = createReplicationServer();
4908N/A // Create Replication Server and Domain
4908N/A LDAPReplicationDomain rd1 = createReplicationDomain(serverId);
4908N/A
4908N/A try
4908N/A {
4908N/A long startTime = TimeThread.getTime();
2721N/A final DN dn1 = DN.decode("cn=test1," + baseDn.toString());
2721N/A final AttributeType histType =
5753N/A DirectoryServer.getAttributeType(EntryHistorical.HISTORICAL_ATTRIBUTE_NAME);
2721N/A
2721N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION,
2721N/A "Starting replication test : changesCmpTest"));
2721N/A
2721N/A // Add the first test entry.
2721N/A TestCaseUtils.addEntry(
2721N/A "dn: cn=test1," + baseDn.toString(),
2721N/A "displayname: Test1",
2721N/A "objectClass: top",
2721N/A "objectClass: person",
2721N/A "objectClass: organizationalPerson",
2721N/A "objectClass: inetOrgPerson",
2721N/A "cn: test1",
2721N/A "sn: test"
2721N/A );
2721N/A
2721N/A // Perform a first modification to update the historical attribute
3853N/A int resultCode = TestCaseUtils.applyModifications(false,
2721N/A "dn: cn=test1," + baseDn.toString(),
2721N/A "changetype: modify",
2721N/A "add: description",
2721N/A "description: foo");
2721N/A assertEquals(resultCode, 0);
2721N/A
2721N/A // Read the entry back to get its historical and included changeNumber
2721N/A Entry entry = DirectoryServer.getEntry(dn1);
2721N/A List<Attribute> attrs1 = entry.getAttribute(histType);
2721N/A
2721N/A assertTrue(attrs1 != null);
2721N/A assertTrue(attrs1.isEmpty() != true);
2721N/A
2721N/A String histValue =
4134N/A attrs1.get(0).iterator().next().getValue().toString();
2721N/A
2721N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION,
2721N/A "First historical value:" + histValue));
2721N/A
3988N/A // Perform a 2nd modification to update the hist attribute with
2721N/A // a second value
3853N/A resultCode = TestCaseUtils.applyModifications(false,
2721N/A "dn: cn=test1," + baseDn.toString(),
2721N/A "changetype: modify",
2721N/A "add: description",
2721N/A "description: bar");
2721N/A assertEquals(resultCode, 0);
2721N/A
2721N/A Entry entry2 = DirectoryServer.getEntry(dn1);
2721N/A List<Attribute> attrs2 = entry2.getAttribute(histType);
2721N/A
2721N/A assertTrue(attrs2 != null);
2721N/A assertTrue(attrs2.isEmpty() != true);
2721N/A
3853N/A for (AttributeValue av : attrs2.get(0)) {
3853N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION,
4134N/A "Second historical value:" + av.getValue().toString()));
2721N/A }
2721N/A
4908N/A LinkedList<ReplicationMsg> opList = new LinkedList<ReplicationMsg>();
4908N/A TestBroker session = new TestBroker(opList);
4908N/A
4908N/A boolean result =
4908N/A rd1.buildAndPublishMissingChanges(
4908N/A new ChangeNumber(startTime, 0, serverId),
4908N/A session);
4908N/A assertTrue(result, "buildAndPublishMissingChanges has failed");
4908N/A assertEquals(opList.size(), 3, "buildAndPublishMissingChanges should return 3 operations");
4908N/A assertTrue(opList.getFirst().getClass().equals(AddMsg.class));
4908N/A
4908N/A
2721N/A // Build a change number from the first modification
2721N/A String hv[] = histValue.split(":");
4908N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION, hv[1]));
4908N/A ChangeNumber fromChangeNumber = new ChangeNumber(hv[1]);
4908N/A
4908N/A opList = new LinkedList<ReplicationMsg>();
4908N/A session = new TestBroker(opList);
4908N/A
4908N/A result =
4908N/A rd1.buildAndPublishMissingChanges(
4908N/A fromChangeNumber,
4908N/A session);
4908N/A assertTrue(result, "buildAndPublishMissingChanges has failed");
4908N/A assertEquals(opList.size(), 1, "buildAndPublishMissingChanges should return 1 operation");
4908N/A assertTrue(opList.getFirst().getClass().equals(ModifyMsg.class));
4908N/A }
4908N/A finally
4908N/A {
4908N/A MultimasterReplication.deleteDomain(baseDn);
4908N/A rs.remove();
5414N/A StaticUtils.recursiveDelete(new File(DirectoryServer.getInstanceRoot(),
5414N/A rs.getDbDirName()));
4908N/A }
4908N/A }
4908N/A
4908N/A /**
4908N/A * Test that we can retrieve the entries that were missed by
4908N/A * a replication server and can re-build operations from the historical
4908N/A * informations.
4908N/A */
4908N/A @Test()
4908N/A public void buildAndPublishMissingChangesSeveralEntriesTest()
4908N/A throws Exception
4908N/A {
4908N/A final DN baseDn = DN.decode(TEST_ROOT_DN_STRING);
4908N/A TestCaseUtils.initializeTestBackend(true);
4908N/A ReplicationServer rs = createReplicationServer();
4908N/A // Create Replication Server and Domain
4908N/A LDAPReplicationDomain rd1 = createReplicationDomain(serverId);
4908N/A long startTime = TimeThread.getTime();
2721N/A
4908N/A try
4908N/A {
4908N/A logError(Message.raw(Category.SYNC, Severity.INFORMATION,
4908N/A "Starting replication test : changesCmpTest"));
2721N/A
4908N/A // Add 3 entries.
4908N/A String dnTest1 = "cn=test1," + baseDn.toString();
4908N/A String dnTest2 = "cn=test2," + baseDn.toString();
4908N/A String dnTest3 = "cn=test3," + baseDn.toString();
4908N/A TestCaseUtils.addEntry(
4908N/A "dn: " + dnTest3,
4908N/A "displayname: Test1",
4908N/A "objectClass: top",
4908N/A "objectClass: person",
4908N/A "objectClass: organizationalPerson",
4908N/A "objectClass: inetOrgPerson",
4908N/A "cn: test1",
4908N/A "sn: test"
4908N/A );
4908N/A TestCaseUtils.addEntry(
4908N/A "dn: " + dnTest1,
4908N/A "displayname: Test1",
4908N/A "objectClass: top",
4908N/A "objectClass: person",
4908N/A "objectClass: organizationalPerson",
4908N/A "objectClass: inetOrgPerson",
4908N/A "cn: test1",
4908N/A "sn: test"
4908N/A );
4908N/A TestCaseUtils.deleteEntry(DN.decode(dnTest3));
4908N/A TestCaseUtils.addEntry(
4908N/A "dn: " + dnTest2,
4908N/A "displayname: Test1",
4908N/A "objectClass: top",
4908N/A "objectClass: person",
4908N/A "objectClass: organizationalPerson",
4908N/A "objectClass: inetOrgPerson",
4908N/A "cn: test1",
4908N/A "sn: test"
4908N/A );
2721N/A
4908N/A // Perform modifications on the 2 entries
4908N/A int resultCode = TestCaseUtils.applyModifications(false,
4908N/A "dn: cn=test2," + baseDn.toString(),
4908N/A "changetype: modify",
4908N/A "add: description",
4908N/A "description: foo");
4908N/A resultCode = TestCaseUtils.applyModifications(false,
4908N/A "dn: cn=test1," + baseDn.toString(),
4908N/A "changetype: modify",
4908N/A "add: description",
4908N/A "description: foo");
4908N/A assertEquals(resultCode, 0);
4908N/A
4908N/A LinkedList<ReplicationMsg> opList = new LinkedList<ReplicationMsg>();
4908N/A TestBroker session = new TestBroker(opList);
4908N/A
4908N/A // Call the buildAndPublishMissingChanges and check that this method
4908N/A // correctly generates the 4 operations in the correct order.
4908N/A boolean result =
4908N/A rd1.buildAndPublishMissingChanges(
4908N/A new ChangeNumber(startTime, 0, serverId),
4908N/A session);
4908N/A assertTrue(result, "buildAndPublishMissingChanges has failed");
4908N/A assertEquals(opList.size(), 5, "buildAndPublishMissingChanges should return 5 operations");
4908N/A ReplicationMsg msg = opList.removeFirst();
4908N/A assertTrue(msg.getClass().equals(AddMsg.class));
4908N/A assertEquals(((LDAPUpdateMsg) msg).getDn(), dnTest1);
4908N/A msg = opList.removeFirst();
4908N/A assertTrue(msg.getClass().equals(DeleteMsg.class));
4908N/A assertEquals(((LDAPUpdateMsg) msg).getDn(), dnTest3);
4908N/A msg = opList.removeFirst();
4908N/A assertTrue(msg.getClass().equals(AddMsg.class));
4908N/A assertEquals(((LDAPUpdateMsg) msg).getDn(), dnTest2);
4908N/A msg = opList.removeFirst();
4908N/A assertTrue(msg.getClass().equals(ModifyMsg.class));
4908N/A assertEquals(((LDAPUpdateMsg) msg).getDn(), dnTest2);
4908N/A msg = opList.removeFirst();
4908N/A assertTrue(msg.getClass().equals(ModifyMsg.class));
4908N/A assertEquals(((LDAPUpdateMsg) msg).getDn(), dnTest1);
4908N/A }
4908N/A finally
2721N/A {
4908N/A MultimasterReplication.deleteDomain(baseDn);
4908N/A rs.remove();
2721N/A }
4908N/A }
4908N/A
4908N/A SortedSet<String> replServers = new TreeSet<String>();
4908N/A private ReplicationServer createReplicationServer() throws ConfigException
4908N/A {
4908N/A int rsPort;
4908N/A try
4908N/A {
4908N/A ServerSocket socket1 = TestCaseUtils.bindFreePort();
4908N/A rsPort = socket1.getLocalPort();
4908N/A socket1.close();
4908N/A replServers.add("localhost:" + rsPort);
4908N/A
4908N/A
4908N/A ReplServerFakeConfiguration conf =
4908N/A new ReplServerFakeConfiguration(rsPort, "HistoricalCsnOrdering",
4908N/A 0, 1, 0, 100, replServers, 1, 1000, 5000);
4908N/A ReplicationServer replicationServer = new ReplicationServer(conf);
4908N/A replicationServer.clearDb();
4908N/A return replicationServer;
4908N/A }
4908N/A catch (IOException e)
4908N/A {
4908N/A fail("Unable to determinate some free ports " +
4908N/A stackTraceToSingleLineString(e));
4908N/A return null;
4908N/A }
4908N/A }
4908N/A
4908N/A private LDAPReplicationDomain createReplicationDomain(int dsId)
4908N/A throws DirectoryException, ConfigException
4908N/A {
4908N/A DN baseDn = DN.decode(TEST_ROOT_DN_STRING);
4908N/A DomainFakeCfg domainConf =
4908N/A new DomainFakeCfg(baseDn, dsId, replServers, AssuredType.NOT_ASSURED,
4908N/A 2, 1, 0, null);
4908N/A LDAPReplicationDomain replicationDomain =
4908N/A MultimasterReplication.createNewDomain(domainConf);
4908N/A replicationDomain.start();
4908N/A
4908N/A return replicationDomain;
2721N/A }
2721N/A}