/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008-2010 Sun Microsystems, Inc. * Portions Copyright 2011 ForgeRock AS */ package org.opends.server.replication.service; import java.io.File; import static org.testng.Assert.*; import java.util.List; import java.util.Map; import java.util.TreeSet; import java.util.concurrent.LinkedBlockingQueue; import java.net.ServerSocket; import java.util.ArrayList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import org.opends.server.TestCaseUtils; import org.opends.server.core.DirectoryServer; import org.opends.server.replication.ReplicationTestCase; import org.opends.server.replication.common.DSInfo; import org.opends.server.replication.common.RSInfo; import org.opends.server.replication.common.ServerState; import org.opends.server.replication.common.ServerStatus; import org.opends.server.replication.protocol.UpdateMsg; import org.opends.server.replication.server.ReplServerFakeConfiguration; import org.opends.server.replication.server.ReplicationServer; import org.opends.server.util.StaticUtils; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Test the Generic Replication Service. */ public class ReplicationDomainTest extends ReplicationTestCase { /** * Create ChangeNumber Data */ @DataProvider(name = "publishAndReceiveData") public Object[][] createpublishAndReceiveData() { return new Object[][] { {1, 2, 3, 4}, {1, 2, 1, 2}, {1, 2, 45891, 45672}, {45610, 45720, 1, 2}, {45610, 45720, 45891, 45672} }; } /** * Test that a ReplicationDomain is able to publish and receive UpdateMsg. * Also test the ReplicationDomain.resetReplicationLog() method. */ @Test(dataProvider = "publishAndReceiveData", enabled=true) public void publishAndReceive( int replServerID1, int replServerID2, int domain1ServerId, int domain2ServerId) throws Exception { String testService = "test"; ReplicationServer replServer1 = null; ReplicationServer replServer2 = null; FakeReplicationDomain domain1 = null; FakeReplicationDomain domain2 = null; try { // find a free port for the replicationServer ServerSocket socket = TestCaseUtils.bindFreePort(); int replServerPort1 = socket.getLocalPort(); socket.close(); socket = TestCaseUtils.bindFreePort(); int replServerPort2 = socket.getLocalPort(); socket.close(); TreeSet<String> replserver1 = new TreeSet<String>(); replserver1.add("localhost:" + replServerPort1); TreeSet<String> replserver2 = new TreeSet<String>(); replserver2.add("localhost:" + replServerPort2); ReplServerFakeConfiguration conf1 = new ReplServerFakeConfiguration( replServerPort1, "ReplicationDomainTestDb1", 0, replServerID1, 0, 100, replserver2); ReplServerFakeConfiguration conf2 = new ReplServerFakeConfiguration( replServerPort2, "ReplicationDomainTestDb2", 0, replServerID2, 0, 100, replserver1); replServer1 = new ReplicationServer(conf1);; replServer2 = new ReplicationServer(conf2); ArrayList<String> servers = new ArrayList<String>(1); servers.add("localhost:" + replServerPort1); BlockingQueue<UpdateMsg> rcvQueue1 = new LinkedBlockingQueue<UpdateMsg>(); domain1 = new FakeReplicationDomain( testService, domain1ServerId, servers, 100, 1000, rcvQueue1); ArrayList<String> servers2 = new ArrayList<String>(1); servers2.add("localhost:" + replServerPort2); BlockingQueue<UpdateMsg> rcvQueue2 = new LinkedBlockingQueue<UpdateMsg>(); domain2 = new FakeReplicationDomain( testService, domain2ServerId, servers2, 100, 1000, rcvQueue2); Thread.sleep(500); /* * Publish a message from domain1, * Check that domain2 receives it shortly after. */ byte[] test = {1, 2, 3 ,4, 0, 1, 2, 3, 4, 5}; domain1.publish(test); UpdateMsg rcvdMsg = rcvQueue2.poll(20, TimeUnit.SECONDS); assertNotNull(rcvdMsg); assertEquals(test, rcvdMsg.getPayload()); /* * Now test the resetReplicationLog() method. */ List<RSInfo> replServers = domain1.getRsList(); for (RSInfo replServerInfo : replServers) { // The generation Id of the remote should be 1 assertEquals(replServerInfo.getGenerationId(), 1, "Unexpected value of generationId in RSInfo for RS=" + replServerInfo.toString()); } for (DSInfo serverInfo : domain1.getReplicasList()) { assertEquals(serverInfo.getStatus(), ServerStatus.NORMAL_STATUS); } domain1.setGenerationID(2); domain1.resetReplicationLog(); Thread.sleep(500); replServers = domain1.getRsList(); for (RSInfo replServerInfo : replServers) { // The generation Id of the remote should now be 2 assertEquals(replServerInfo.getGenerationId(), 2, "Unexpected value of generationId in RSInfo for RS=" + replServerInfo.toString()); } int sleepTime = 50; while (true) { try { for (DSInfo serverInfo : domain1.getReplicasList()) { if (serverInfo.getDsId() == domain2ServerId) assertEquals(serverInfo.getStatus(), ServerStatus.BAD_GEN_ID_STATUS); else { assertTrue(serverInfo.getDsId() == domain1ServerId); assertTrue(serverInfo.getStatus() == ServerStatus.NORMAL_STATUS); } } for (DSInfo serverInfo : domain2.getReplicasList()) { if (serverInfo.getDsId() == domain2ServerId) assertTrue(serverInfo.getStatus() == ServerStatus.BAD_GEN_ID_STATUS); else { assertTrue(serverInfo.getDsId() == domain1ServerId); assertTrue(serverInfo.getStatus() == ServerStatus.NORMAL_STATUS); } } Map<Integer, ServerState> states1 = domain1.getReplicaStates(); ServerState state2 = states1.get(domain2ServerId); assertNotNull(state2, "getReplicaStates is not showing DS2"); Map<Integer, ServerState> states2 = domain2.getReplicaStates(); ServerState state1 = states2.get(domain1ServerId); assertNotNull(state1, "getReplicaStates is not showing DS1"); // if we reach this point all tests are OK break; } catch (AssertionError e) { if (sleepTime < 30000) { Thread.sleep(sleepTime); sleepTime *=2; } else throw e; } } } finally { if (domain1 != null) domain1.stopDomain(); if (domain2 != null) domain2.stopDomain(); if (replServer1 != null) { replServer1.remove(); StaticUtils.recursiveDelete(new File(DirectoryServer.getInstanceRoot(), replServer1.getDbDirName())); } if (replServer2 != null) { replServer2.remove(); StaticUtils.recursiveDelete(new File(DirectoryServer.getInstanceRoot(), replServer2.getDbDirName())); } } } /** * Publish performance test. * The test loops calling the publish methods of the ReplicationDomain. * It should not be enabled by default as it will use a lot of time. * Its call is only to investigate performance issues with the replication. */ @Test(enabled=false) public void publishPerf() throws Exception { String testService = "test"; ReplicationServer replServer1 = null; int replServerID1 = 10; FakeReplicationDomain domain1 = null; int domain1ServerId = 1; try { // find a free port for the replicationServer ServerSocket socket = TestCaseUtils.bindFreePort(); int replServerPort = socket.getLocalPort(); socket.close(); TreeSet<String> replserver = new TreeSet<String>(); replserver.add("localhost:" + replServerPort); ReplServerFakeConfiguration conf1 = new ReplServerFakeConfiguration( replServerPort, "ReplicationDomainTestDb", 0, replServerID1, 0, 100000, replserver); replServer1 = new ReplicationServer(conf1);; ArrayList<String> servers = new ArrayList<String>(1); servers.add("localhost:" + replServerPort); BlockingQueue<UpdateMsg> rcvQueue1 = new LinkedBlockingQueue<UpdateMsg>(); domain1 = new FakeReplicationDomain( testService, domain1ServerId, servers, 1000, 100000, rcvQueue1); /* * Publish a message from domain1, * Check that domain2 receives it shortly after. */ byte[] test = {1, 2, 3 ,4, 0, 1, 2, 3, 4, 5}; long timeStart = System.nanoTime(); for (int i=0; i< 100000; i++) domain1.publish(test); long timeNow = System.nanoTime(); System.out.println(timeNow - timeStart); timeStart = timeNow; for (int i=0; i< 100000; i++) domain1.publish(test); timeNow = System.nanoTime(); System.out.println(timeNow - timeStart); timeStart = timeNow; for (int i=0; i< 100000; i++) domain1.publish(test); timeNow = System.nanoTime(); System.out.println(timeNow - timeStart); timeStart = timeNow; for (int i=0; i< 100000; i++) domain1.publish(test); timeNow = System.nanoTime(); System.out.println(timeNow - timeStart); } finally { if (domain1 != null) domain1.disableService(); if (replServer1 != null) { replServer1.remove(); StaticUtils.recursiveDelete(new File(DirectoryServer.getInstanceRoot(), replServer1.getDbDirName())); } } } @DataProvider(name = "exportAndImportData") public Object[][] createExportAndimportData() { return new Object[][] { {1, 2}, {45610, 45720} }; } /** * Test that a ReplicationDomain is able to export and import its database * When there is only one replication server. */ @Test(dataProvider = "exportAndImportData", enabled=true) public void exportAndImport(int serverId1, int serverId2) throws Exception { final int ENTRYCOUNT=5000; String testService = "test"; ReplicationServer replServer = null; int replServerID = 11; FakeReplicationDomain domain1 = null; FakeReplicationDomain domain2 = null; try { // find a free port for the replicationServer ServerSocket socket = TestCaseUtils.bindFreePort(); int replServerPort = socket.getLocalPort(); socket.close(); ReplServerFakeConfiguration conf = new ReplServerFakeConfiguration( replServerPort, "exportAndImportData", 0, replServerID, 0, 100, null); replServer = new ReplicationServer(conf); ArrayList<String> servers = new ArrayList<String>(1); servers.add("localhost:" + replServerPort); StringBuilder exportedDataBuilder = new StringBuilder(); for (int i =0; i<ENTRYCOUNT; i++) { exportedDataBuilder.append("key : value"+i+"\n\n"); } String exportedData=exportedDataBuilder.toString(); domain1 = new FakeReplicationDomain( testService, serverId1, servers, 100, 0, exportedData, null, ENTRYCOUNT); StringBuilder importedData = new StringBuilder(); domain2 = new FakeReplicationDomain( testService, serverId2, servers, 100, 0, null, importedData, 0); /* * Trigger a total update from domain1 to domain2. * Check that the exported data is correctly received on domain2. */ for (DSInfo remoteDS : domain2.getReplicasList()) { if (remoteDS.getDsId() != domain2.getServerId()) { domain2.initializeFromRemote(remoteDS.getDsId()); break; } } int count = 0; while ((importedData.length() < exportedData.length()) && (count < 500)) { count ++; Thread.sleep(100); } assertTrue(domain2.getLeftEntryCount() == 0, "LeftEntryCount for export is " + domain2.getLeftEntryCount()); assertTrue(domain1.getLeftEntryCount() == 0, "LeftEntryCount for import is " + domain1.getLeftEntryCount()); assertEquals(importedData.length(), exportedData.length()); assertEquals(importedData.toString(), exportedData); } finally { if (domain1 != null) domain1.disableService(); if (domain2 != null) domain2.disableService(); if (replServer != null) { replServer.remove(); StaticUtils.recursiveDelete(new File(DirectoryServer.getInstanceRoot(), replServer.getDbDirName())); } } } /** * Test that a ReplicationDomain is able to export and import its database * across 2 replication servers. */ @Test(enabled=true) public void exportAndImportAcross2ReplServers() throws Exception { final int ENTRYCOUNT=5000; String testService = "test"; ReplicationServer replServer2 = null; ReplicationServer replServer1 = null; int replServerID = 11; int replServerID2 = 12; FakeReplicationDomain domain1 = null; FakeReplicationDomain domain2 = null; try { // find a free port for the replicationServer ServerSocket socket = TestCaseUtils.bindFreePort(); int replServerPort1 = socket.getLocalPort(); socket.close(); socket = TestCaseUtils.bindFreePort(); int replServerPort2 = socket.getLocalPort(); socket.close(); TreeSet<String> replserver1 = new TreeSet<String>(); replserver1.add("localhost:" + replServerPort1); TreeSet<String> replserver2 = new TreeSet<String>(); replserver2.add("localhost:" + replServerPort2); ReplServerFakeConfiguration conf1 = new ReplServerFakeConfiguration( replServerPort1, "exportAndImportservice1", 0, replServerID, 0, 100, null); ReplServerFakeConfiguration conf2 = new ReplServerFakeConfiguration( replServerPort2, "exportAndImportservice2", 0, replServerID2, 0, 100, replserver1); replServer1 = new ReplicationServer(conf1); replServer2 = new ReplicationServer(conf2); ArrayList<String> servers1 = new ArrayList<String>(1); servers1.add("localhost:" + replServerPort1); ArrayList<String> servers2 = new ArrayList<String>(1); servers2.add("localhost:" + replServerPort2); StringBuilder exportedDataBuilder = new StringBuilder(); for (int i =0; i<ENTRYCOUNT; i++) { exportedDataBuilder.append("key : value"+i+"\n\n"); } String exportedData=exportedDataBuilder.toString(); domain1 = new FakeReplicationDomain( testService, 1, servers1, 100, 0, exportedData, null, ENTRYCOUNT); StringBuilder importedData = new StringBuilder(); domain2 = new FakeReplicationDomain( testService, 2, servers2, 100, 0, null, importedData, 0); domain2.initializeFromRemote(1); int count = 0; while ((importedData.length() < exportedData.length()) && (count < 500)) { count ++; Thread.sleep(100); } assertTrue(domain2.getLeftEntryCount() == 0, "LeftEntryCount for export is " + domain2.getLeftEntryCount()); assertTrue(domain1.getLeftEntryCount() == 0, "LeftEntryCount for import is " + domain1.getLeftEntryCount()); assertEquals(importedData.length(), exportedData.length()); assertEquals(importedData.toString(), exportedData); } finally { if (domain1 != null) domain1.disableService(); if (domain2 != null) domain2.disableService(); if (replServer1 != null) { replServer1.remove(); StaticUtils.recursiveDelete(new File(DirectoryServer.getInstanceRoot(), replServer1.getDbDirName())); } if (replServer2 != null) { replServer2.remove(); StaticUtils.recursiveDelete(new File(DirectoryServer.getInstanceRoot(), replServer2.getDbDirName())); } } } /** * Sender side of the Total Update Perf test. * The goal of this test is to measure the performance * of the total update code. * It is not intended to be run as part of the daily unit test but * should only be used manually by developer in need of testing the * performance improvement or non-regression of the total update code. * Use this test in combination with the receiverInitialize() : * - enable the test * - start the senderInitialize first using * ./build.sh \ * -Dorg.opends.test.suppressOutput=false \ * -Dtest.methods=org.opends.server.replication.service.ReplicationDomainTest.senderInitialize test * - start the receiverInitialize second. * - you may want to change HOST1 and HOST2 to use 2 different hosts * if you don't want to do a loopback test. * - don't forget to disable again the tests after running them */ final String HOST1 = "localhost:"; final String HOST2 = "localhost:"; final int SENDERPORT = 10102; final int RECEIVERPORT = 10101; @Test(enabled=false) public void senderInitialize() throws Exception { String testService = "test"; ReplicationServer replServer = null; int replServerID = 12; FakeStressReplicationDomain domain1 = null; try { TreeSet<String> servers = new TreeSet<String>(); servers.add(HOST1 + SENDERPORT); servers.add(HOST2 + RECEIVERPORT); ReplServerFakeConfiguration conf = new ReplServerFakeConfiguration( SENDERPORT, "ReplicationDomainTestDb", 0, replServerID, 0, 100, servers); replServer = new ReplicationServer(conf); BlockingQueue<UpdateMsg> rcvQueue1 = new LinkedBlockingQueue<UpdateMsg>(); domain1 = new FakeStressReplicationDomain( testService, 2, servers, 100, 1000, rcvQueue1); System.out.println("waiting"); Thread.sleep(1000000000); } finally { if (domain1 != null) domain1.disableService(); if (replServer != null) { replServer.remove(); StaticUtils.recursiveDelete(new File(DirectoryServer.getInstanceRoot(), replServer.getDbDirName())); } } } /** * See comments in senderInitialize() above */ @Test(enabled=false) public void receiverInitialize() throws Exception { String testService = "test"; ReplicationServer replServer = null; int replServerID = 11; FakeStressReplicationDomain domain1 = null; try { TreeSet<String> servers = new TreeSet<String>(); servers.add(HOST1 + SENDERPORT); servers.add(HOST2 + RECEIVERPORT); ReplServerFakeConfiguration conf = new ReplServerFakeConfiguration( RECEIVERPORT, "ReplicationDomainTestDb", 0, replServerID, 0, 100, servers); replServer = new ReplicationServer(conf); BlockingQueue<UpdateMsg> rcvQueue1 = new LinkedBlockingQueue<UpdateMsg>(); domain1 = new FakeStressReplicationDomain( testService, 1, servers, 100, 100000, rcvQueue1); /* * Trigger a total update from domain1 to domain2. * Check that the exported data is correctly received on domain2. */ boolean alone = true; while (alone) { for (DSInfo remoteDS : domain1.getReplicasList()) { if (remoteDS.getDsId() != domain1.getServerId()) { alone = false; domain1.initializeFromRemote(remoteDS.getDsId() , null); break; } } if (alone) { System.out.println("trying..."); Thread.sleep(1000); } } System.out.println("waiting"); Thread.sleep(10000000); } finally { if (domain1 != null) domain1.disableService(); if (replServer != null) { replServer.remove(); StaticUtils.recursiveDelete(new File(DirectoryServer.getInstanceRoot(), replServer.getDbDirName())); } } } }