/*
* 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 legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* 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 legal-notices/CDDLv1_0.txt.
* 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-2015 ForgeRock AS
*/
package org.opends.server.replication.plugin;
import static org.opends.server.TestCaseUtils.*;
import static org.testng.Assert.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.std.meta.ReplicationDomainCfgDefn.AssuredType;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.AssuredMode;
import org.opends.server.replication.common.DSInfo;
import org.opends.server.replication.common.RSInfo;
import org.opends.server.replication.common.ServerStatus;
import org.opends.server.replication.protocol.ProtocolVersion;
import org.opends.server.replication.server.ReplServerFakeConfiguration;
import org.opends.server.replication.server.ReplicationServer;
import org.opends.server.types.DN;
import org.opends.server.types.HostPort;
import org.testng.annotations.Test;
/**
* Some tests to know if at any time the view DSs and RSs have of the current
* topology is accurate, even after some connections, disconnections and
* re-connections events.
*/
public class TopologyViewTest extends ReplicationTestCase
{
/** Server id definitions. */
private static final int DS1_ID = 1;
private static final int DS2_ID = 2;
private static final int DS3_ID = 3;
private static final int DS4_ID = 4;
private static final int DS5_ID = 5;
private static final int DS6_ID = 6;
private static final int RS1_ID = 51;
private static final int RS2_ID = 52;
private static final int RS3_ID = 53;
/** Group id definitions. */
private static final int DS1_GID = 1;
private static final int DS2_GID = 1;
private static final int DS3_GID = 2;
private static final int DS4_GID = 2;
private static final int DS5_GID = 3;
private static final int DS6_GID = 3;
private static final int RS1_GID = 1;
private static final int RS2_GID = 2;
private static final int RS3_GID = 3;
/** Assured conf definitions. */
private static final AssuredType DS1_AT = AssuredType.NOT_ASSURED;
private static final int DS1_SDL = -1;
private static SortedSet<String> DS1_RU = new TreeSet<>();
private static final AssuredType DS2_AT = AssuredType.SAFE_READ;
private static final int DS2_SDL = -1;
private static SortedSet<String> DS2_RU = new TreeSet<>();
private static final AssuredType DS3_AT = AssuredType.SAFE_DATA;
private static final int DS3_SDL = 1;
private static SortedSet<String> DS3_RU = new TreeSet<>();
private static final AssuredType DS4_AT = AssuredType.SAFE_READ;
private static final int DS4_SDL = -1;
private static SortedSet<String> DS4_RU = new TreeSet<>();
private static final AssuredType DS5_AT = AssuredType.SAFE_DATA;
private static final int DS5_SDL = 2;
private static SortedSet<String> DS5_RU = new TreeSet<>();
private static final AssuredType DS6_AT = AssuredType.SAFE_READ;
private static final int DS6_SDL = -1;
private static SortedSet<String> DS6_RU = new TreeSet<>();
private static String LOCAL_HOST_NAME;
static
{
DS2_RU.add("ldap://fake_url_for_ds2");
DS6_RU.add("ldap://fake_url_for_ds6_A");
DS6_RU.add("ldap://fake_url_for_ds6_B");
try
{
LOCAL_HOST_NAME = InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e)
{
fail("Unable to resolve local host name", e);
}
}
private int rs1Port = -1;
private int rs2Port = -1;
private int rs3Port = -1;
private LDAPReplicationDomain rd1;
private LDAPReplicationDomain rd2;
private LDAPReplicationDomain rd3;
private LDAPReplicationDomain rd4;
private LDAPReplicationDomain rd5;
private LDAPReplicationDomain rd6;
private ReplicationServer rs1;
private ReplicationServer rs2;
private ReplicationServer rs3;
/** The tracer object for the debug logger. */
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
private void debugInfo(String s)
{
logger.error(LocalizableMessage.raw(s));
if (logger.isTraceEnabled())
{
logger.trace("** TEST **" + s);
}
}
private void initTest() throws Exception
{
rs1Port = -1;
rs2Port = -1;
rs3Port = -1;
rd1 = null;
rd2 = null;
rd3 = null;
rd4 = null;
rd5 = null;
rd6 = null;
rs1 = null;
rs2 = null;
rs3 = null;
findFreePorts();
}
private void endTest() throws Exception
{
if (rd1 != null)
{
rd1.shutdown();
rd1 = null;
}
if (rd2 != null)
{
rd2.shutdown();
rd2 = null;
}
if (rd3 != null)
{
rd3.shutdown();
rd3 = null;
}
if (rd4 != null)
{
rd4.shutdown();
rd4 = null;
}
if (rd5 != null)
{
rd5.shutdown();
rd5 = null;
}
if (rd6 != null)
{
rd6.shutdown();
rd6 = null;
}
// Clear any reference to a domain in synchro plugin
MultimasterReplication.deleteDomain(DN.valueOf(TEST_ROOT_DN_STRING));
remove(rs1, rs2, rs3);
rs1 = rs2 = rs3 = null;
rs1Port = rs2Port = rs3Port = -1;
}
/**
* Check connection of the provided replication domain to the provided
* replication server. Waits for connection to be ok up to secTimeout seconds
* before failing.
*/
private void checkConnection(int secTimeout, int dsId, int rsId)
throws Exception
{
int rsPort = -1;
LDAPReplicationDomain rd = null;
switch (dsId)
{
case DS1_ID:
rd = rd1;
break;
case DS2_ID:
rd = rd2;
break;
case DS3_ID:
rd = rd3;
break;
case DS4_ID:
rd = rd4;
break;
case DS5_ID:
rd = rd5;
break;
case DS6_ID:
rd = rd6;
break;
default:
fail("Unknown replication domain server id.");
}
switch (rsId)
{
case RS1_ID:
rsPort = rs1Port;
break;
case RS2_ID:
rsPort = rs2Port;
break;
case RS3_ID:
rsPort = rs3Port;
break;
default:
fail("Unknown replication server id.");
}
int nSec = 0;
// Go out of the loop only if connection is verified or if timeout occurs
while (true)
{
// Test connection
boolean connected = rd.isConnected();
int rdPort = -1;
boolean rightPort = false;
if (connected)
{
String serverStr = rd.getReplicationServer();
rdPort = HostPort.valueOf(serverStr).getPort();
if (rdPort == rsPort)
{
rightPort = true;
}
}
if (connected && rightPort)
{
// Connection verified
debugInfo("checkConnection: connection from domain " + dsId + " to" +
" replication server " + rsId + " obtained after "
+ nSec + " seconds.");
return;
}
// Sleep 1 second
Thread.sleep(1000);
nSec++;
if (nSec > secTimeout)
{
// Timeout reached, end with error
fail("checkConnection: could not verify connection from domain " + dsId
+ " to replication server " + rsId + " after " + secTimeout + " seconds."
+ " Domain connected: " + connected + ", connection port: " + rdPort
+ " (should be: " + rsPort + ")");
}
}
}
/**
* Find needed free TCP ports.
*/
private void findFreePorts() throws Exception
{
int[] ports = TestCaseUtils.findFreePorts(3);
int i = 0;
rs1Port = ports[i++];
rs2Port = ports[i++];
rs3Port = ports[i++];
}
/**
* Creates the list of servers to represent the RS topology excluding the
* RS whose id is passed.
*/
private SortedSet<String> createRSListExceptOne(int rsIdToExclude)
{
SortedSet<String> replServers = new TreeSet<>();
if (rsIdToExclude != RS1_ID)
{
replServers.add(getHostPort(rs1Port));
}
if (rsIdToExclude != RS2_ID)
{
replServers.add(getHostPort(rs2Port));
}
if (rsIdToExclude != RS3_ID)
{
replServers.add(getHostPort(rs3Port));
}
return replServers;
}
/**
* Creates a new ReplicationServer.
*/
private ReplicationServer createReplicationServer(int rsId, String testCase)
throws ConfigException
{
SortedSet<String> replServers = createRSListExceptOne(rsId);
int rsPort = -1;
int groupId = -1;
switch (rsId)
{
case RS1_ID:
rsPort = rs1Port;
groupId = RS1_GID;
break;
case RS2_ID:
rsPort = rs2Port;
groupId = RS2_GID;
break;
case RS3_ID:
rsPort = rs3Port;
groupId = RS3_GID;
break;
default:
fail("Unknown replication server id.");
}
String dir = "topologyViewTest" + rsId + testCase + "Db";
ReplServerFakeConfiguration conf =
new ReplServerFakeConfiguration(rsPort, dir, 0, rsId, 0,
100, replServers, groupId, 1000, 5000);
return new ReplicationServer(conf);
}
/**
* Creates and starts a new ReplicationDomain with the correct list of
* know RSs according to DS id.
*/
private LDAPReplicationDomain createReplicationDomain(int dsId)
throws Exception
{
SortedSet<String> replServers = new TreeSet<>();
int groupId = -1;
AssuredType assuredType = null;
int assuredSdLevel = -100;
SortedSet<String> refUrls = null;
// Fill rs list according to defined scenario (see testTopologyChanges
// comment)
switch (dsId)
{
case DS1_ID:
replServers.add(getHostPort(rs1Port));
replServers.add(getHostPort(rs2Port));
replServers.add(getHostPort(rs3Port));
groupId = DS1_GID;
assuredType = DS1_AT;
assuredSdLevel = DS1_SDL;
refUrls = DS1_RU;
break;
case DS2_ID:
replServers.add(getHostPort(rs1Port));
replServers.add(getHostPort(rs2Port));
replServers.add(getHostPort(rs3Port));
groupId = DS2_GID;
assuredType = DS2_AT;
assuredSdLevel = DS2_SDL;
refUrls = DS2_RU;
break;
case DS3_ID:
replServers.add(getHostPort(rs2Port));
groupId = DS3_GID;
assuredType = DS3_AT;
assuredSdLevel = DS3_SDL;
refUrls = DS3_RU;
break;
case DS4_ID:
replServers.add(getHostPort(rs2Port));
groupId = DS4_GID;
assuredType = DS4_AT;
assuredSdLevel = DS4_SDL;
refUrls = DS4_RU;
break;
case DS5_ID:
replServers.add(getHostPort(rs2Port));
replServers.add(getHostPort(rs3Port));
groupId = DS5_GID;
assuredType = DS5_AT;
assuredSdLevel = DS5_SDL;
refUrls = DS5_RU;
break;
case DS6_ID:
replServers.add(getHostPort(rs2Port));
replServers.add(getHostPort(rs3Port));
groupId = DS6_GID;
assuredType = DS6_AT;
assuredSdLevel = DS6_SDL;
refUrls = DS6_RU;
break;
default:
fail("Unknown replication domain server id.");
}
DN baseDn = DN.valueOf(TEST_ROOT_DN_STRING);
DomainFakeCfg domainConf =
new DomainFakeCfg(baseDn, dsId, replServers, assuredType,
assuredSdLevel, groupId, 0, refUrls);
LDAPReplicationDomain replicationDomain =
MultimasterReplication.createNewDomain(domainConf);
replicationDomain.start();
return replicationDomain;
}
/** Definitions of steps for the test case. */
private static final int STEP_1 = 1;
private static final int STEP_2 = 2;
private static final int STEP_3 = 3;
private static final int STEP_4 = 4;
private static final int STEP_5 = 5;
private static final int STEP_6 = 6;
private static final int STEP_7 = 7;
private static final int STEP_8 = 8;
private static final int STEP_9 = 9;
private static final int STEP_10 = 10;
private static final int STEP_11 = 11;
private static final int STEP_12 = 12;
private static final int STEP_13 = 13;
/**
* Perform connections/disconnections of DS/RS. Uses various config parameters
* that are embedded in topo info to check if they are well transported.
* This tests:
* - if topo msgs are exchanged when needed and reflect topo reality (who is
* connected to who)
* - if topo msgs transport config params in terms of assured replication,
* group id... that reflect what is configured in the DSs.
*
* Full topo is:
* (GID=group id, A=assured, NA=not assured, SR=safe read, SD=safe data,
* SDL=safe data level, RUF=ref urls filled, RUE=ref urls empty)
* Except if otherwise stated, RSs and DSs are aware of every others existence
* - RS1 with GID=1
* - RS2 with GID=2
* - RS3 with GID=3
* - DS1 with GID=1, NA
* - DS2 with GID=1, A, SR, RUF
* - DS3 with GID=2, A, SD, SDL=1 (DS3 does not know RS1 and RS3)
* - DS4 with GID=2, A, SR, RUE (DS4 does not know RS1 and RS3)
* - DS5 with GID=3, A, SD, SDL=2 (DS5 does not know RS1)
* - DS6 with GID=3, A, SR, RUF (DS6 does not know RS1)
* Scenario is:
* - RS1 starts
* - DS1 starts and connects to RS1 (check topo view in DS1)
* - DS2 starts and connects to RS1 (check topo view in DS1,DS2)
* - RS2 starts (check topo view in DS1,DS2)
* - DS3 starts and connects to RS2 (check topo view in DS1,DS2,DS3)
* - DS4 starts and connects to RS2 (check topo view in DS1,DS2,DS3,DS4)
* - DS5 starts and connects to RS2 (check topo view in DS1,DS2,DS3,DS4,DS5)
* - RS3 starts (check topo view in DS1,DS2,DS3,DS4,DS5)
* - DS6 starts and connects to RS3. DS5 should reconnect to RS3 (as RS with
* same GID becomes available) (check topo view in DS1,DS2,DS3,DS4,DS5,DS6)
* - DS6 stops (check topo view in DS1,DS2,DS3,DS4,DS5)
* - DS6 starts and connects to RS3 (check topo view in DS1,DS2,DS3,DS4,DS5,
* DS6)
* - RS3 stops. DS5 and DS6 should failover to RS2 as do not know RS1 (check
* topo view in DS1,DS2,DS3,DS4,DS5,DS6)
* - RS3 starts. DS5 and DS6 should reconnect to RS3 (as RS with same GID
* becomes available) (check topo view in DS1,DS2,DS3,DS4,DS5,DS6)
* - RS2 stops. DS3 and DS4 do not reconnect to any RS as do not know RS1 and
* RS3. This emulates a full RS with his connected DSs crash. (check topo view
* in DS1,DS2,DS5,DS6)
* @throws Exception If a problem occurred
*/
@Test(enabled = true, groups = "slow")
public void testTopologyChanges() throws Exception
{
String testCase = "testTopologyChanges";
debugInfo("Starting " + testCase);
initTest();
TopoView theoricalTopoView = null;
try
{
/**
* RS1 starts
*/
debugInfo("*** STEP 0 ***");
rs1 = createReplicationServer(RS1_ID, testCase);
/**
* DS1 starts and connects to RS1 (check topo view in DS1)
*/
debugInfo("*** STEP 1 ***");
rd1 = createReplicationDomain(DS1_ID);
checkConnection(30, DS1_ID, RS1_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_1);
checkTopoView(new int[] {DS1_ID}, theoricalTopoView);
/**
* DS2 starts and connects to RS1 (check topo view in DS1,DS2)
*/
debugInfo("*** STEP 2 ***");
rd2 = createReplicationDomain(DS2_ID);
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_2);
checkTopoView(new int[] {DS1_ID, DS2_ID}, theoricalTopoView);
/**
* RS2 starts (check topo view in DS1,DS2)
*/
debugInfo("*** STEP 3 ***");
rs2 = createReplicationServer(RS2_ID, testCase);
Thread.sleep(1000); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_3);
checkTopoView(new int[] {DS1_ID, DS2_ID}, theoricalTopoView);
/**
* DS3 starts and connects to RS2 (check topo view in DS1,DS2,DS3)
*/
debugInfo("*** STEP 4 ***");
rd3 = createReplicationDomain(DS3_ID);
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
checkConnection(30, DS3_ID, RS2_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_4);
checkTopoView(new int[] {DS1_ID, DS2_ID, DS3_ID}, theoricalTopoView);
/**
* DS4 starts and connects to RS2 (check topo view in DS1,DS2,DS3,DS4)
*/
debugInfo("*** STEP 5 ***");
rd4 = createReplicationDomain(DS4_ID);
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
checkConnection(30, DS3_ID, RS2_ID);
checkConnection(30, DS4_ID, RS2_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_5);
checkTopoView(new int[] {DS1_ID, DS2_ID, DS3_ID, DS4_ID},
theoricalTopoView);
/**
* DS5 starts and connects to RS2 (check topo view in DS1,DS2,DS3,DS4,DS5)
*/
debugInfo("*** STEP 6 ***");
rd5 = createReplicationDomain(DS5_ID);
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
checkConnection(30, DS3_ID, RS2_ID);
checkConnection(30, DS4_ID, RS2_ID);
checkConnection(30, DS5_ID, RS2_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_6);
checkTopoView(new int[] {DS1_ID, DS2_ID, DS3_ID, DS4_ID, DS5_ID},
theoricalTopoView);
/**
* RS3 starts. DS5 should reconnect to RS3 (as RS with
* same GID becomes available) (check topo view in DS1,DS2,DS3,DS4,DS5)
*/
debugInfo("*** STEP 7 ***");
rs3 = createReplicationServer(RS3_ID, testCase);
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
checkConnection(30, DS3_ID, RS2_ID);
checkConnection(30, DS4_ID, RS2_ID);
checkConnection(30, DS5_ID, RS3_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_7);
checkTopoView(new int[] {DS1_ID, DS2_ID, DS3_ID, DS4_ID, DS5_ID},
theoricalTopoView);
/**
* DS6 starts and connects to RS3 (check topo view in DS1,DS2,DS3,DS4,DS5,
* DS6)
*/
debugInfo("*** STEP 8 ***");
rd6 = createReplicationDomain(DS6_ID);
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
checkConnection(30, DS3_ID, RS2_ID);
checkConnection(30, DS4_ID, RS2_ID);
checkConnection(30, DS5_ID, RS3_ID);
checkConnection(30, DS6_ID, RS3_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_8);
checkTopoView(new int[] {DS1_ID, DS2_ID, DS3_ID, DS4_ID, DS5_ID, DS6_ID},
theoricalTopoView);
/**
* DS6 stops (check topo view in DS1,DS2,DS3,DS4,DS5)
*/
debugInfo("*** STEP 9 ***");
rd6.disable();
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
checkConnection(30, DS3_ID, RS2_ID);
checkConnection(30, DS4_ID, RS2_ID);
checkConnection(30, DS5_ID, RS3_ID);
assertFalse(rd6.isConnected());
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_9);
checkTopoView(new int[] {DS1_ID, DS2_ID, DS3_ID, DS4_ID, DS5_ID},
theoricalTopoView);
/**
* DS6 starts and connects to RS3 (check topo view in DS1,DS2,DS3,DS4,DS5,
* DS6)
*/
debugInfo("*** STEP 10 ***");
rd6.enable();
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
checkConnection(30, DS3_ID, RS2_ID);
checkConnection(30, DS4_ID, RS2_ID);
checkConnection(30, DS5_ID, RS3_ID);
checkConnection(30, DS6_ID, RS3_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_10);
checkTopoView(new int[] {DS1_ID, DS2_ID, DS3_ID, DS4_ID, DS5_ID, DS6_ID},
theoricalTopoView);
/**
* RS3 stops. DS5 and DS6 should failover to RS2 as do not know RS1 (check
* topo view in DS1,DS2,DS3,DS4,DS5,DS6)
*/
debugInfo("*** STEP 11 ***");
rs3.remove();
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
checkConnection(30, DS3_ID, RS2_ID);
checkConnection(30, DS4_ID, RS2_ID);
checkConnection(30, DS5_ID, RS2_ID);
checkConnection(30, DS6_ID, RS2_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_11);
checkTopoView(new int[] {DS1_ID, DS2_ID, DS3_ID, DS4_ID, DS5_ID, DS6_ID},
theoricalTopoView);
/**
* RS3 starts. DS5 and DS6 should reconnect to RS3 (as RS with same GID
* becomes available) (check topo view in DS1,DS2,DS3,DS4,DS5,DS6)
*/
debugInfo("*** STEP 12 ***");
rs3 = createReplicationServer(RS3_ID, testCase);
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
checkConnection(30, DS3_ID, RS2_ID);
checkConnection(30, DS4_ID, RS2_ID);
checkConnection(30, DS5_ID, RS3_ID);
checkConnection(30, DS6_ID, RS3_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_12);
checkTopoView(new int[] {DS1_ID, DS2_ID, DS3_ID, DS4_ID, DS5_ID, DS6_ID},
theoricalTopoView);
/**
* RS2 stops. DS3 and DS4 do not reconnect to any RS as do not know RS1 and
* RS3. This emulates a full RS with his connected DSs crash. (check topo
* view in DS1,DS2,DS5,DS6)
*/
debugInfo("*** STEP 13 ***");
rs2.remove();
Thread.sleep(500); // Let time to topo msgs being propagated through the network
checkConnection(30, DS1_ID, RS1_ID);
checkConnection(30, DS2_ID, RS1_ID);
checkConnection(30, DS5_ID, RS3_ID);
checkConnection(30, DS6_ID, RS3_ID);
theoricalTopoView = createTheoreticalTopoViewForStep(STEP_13);
checkTopoView(new int[] {DS1_ID, DS2_ID, DS5_ID, DS6_ID},
theoricalTopoView);
} finally
{
endTest();
}
}
/**
* Creates RSInfo for the passed RS.
*/
private RSInfo createRSInfo(int rsId)
{
int groupId = -1;
String serverUrl = null;
switch (rsId)
{
case RS1_ID:
groupId = RS1_GID;
serverUrl = getHostPort(rs1Port);
break;
case RS2_ID:
groupId = RS2_GID;
serverUrl = getHostPort(rs2Port);
break;
case RS3_ID:
groupId = RS3_GID;
serverUrl = getHostPort(rs3Port);
break;
default:
fail("Unknown replication server id.");
}
return new RSInfo(rsId, serverUrl, TEST_DN_WITH_ROOT_ENTRY_GENID, (byte)groupId, 1);
}
/**
* Creates DSInfo for the passed DS, connected to the passed RS.
*/
private DSInfo createDSInfo(int dsId, int rsId)
{
ServerStatus status = ServerStatus.NORMAL_STATUS;
byte groupId = -1;
AssuredType assuredType = null;
int assuredSdLevel = -100;
SortedSet<String> refUrls = null;
Set<String> eclIncludes = new HashSet<>();
short protocolVersion = ProtocolVersion.getCurrentVersion();
switch (dsId)
{
case DS1_ID:
groupId = DS1_GID;
assuredType = DS1_AT;
assuredSdLevel = DS1_SDL;
refUrls = DS1_RU;
break;
case DS2_ID:
groupId = DS2_GID;
assuredType = DS2_AT;
assuredSdLevel = DS2_SDL;
refUrls = DS2_RU;
break;
case DS3_ID:
groupId = DS3_GID;
assuredType = DS3_AT;
assuredSdLevel = DS3_SDL;
refUrls = DS3_RU;
break;
case DS4_ID:
groupId = DS4_GID;
assuredType = DS4_AT;
assuredSdLevel = DS4_SDL;
refUrls = DS4_RU;
break;
case DS5_ID:
groupId = DS5_GID;
assuredType = DS5_AT;
assuredSdLevel = DS5_SDL;
refUrls = DS5_RU;
break;
case DS6_ID:
groupId = DS6_GID;
assuredType = DS6_AT;
assuredSdLevel = DS6_SDL;
refUrls = DS6_RU;
break;
default:
fail("Unknown replication domain server id.");
}
// Perform necessary conversions
boolean assuredFlag = assuredType != AssuredType.NOT_ASSURED;
AssuredMode assMode = assuredType == AssuredType.SAFE_READ
? AssuredMode.SAFE_READ_MODE
: AssuredMode.SAFE_DATA_MODE;
return new DSInfo(dsId, "dummy:1234", rsId, TEST_DN_WITH_ROOT_ENTRY_GENID, status, assuredFlag, assMode,
(byte)assuredSdLevel, groupId, refUrls, eclIncludes, eclIncludes, protocolVersion);
}
/**
* Creates the topo view to be checked at each step of the test (view that
* every concerned DS should have).
*/
private TopoView createTheoreticalTopoViewForStep(int step)
{
List<DSInfo> dsList = new ArrayList<>();
List<RSInfo> rsList = new ArrayList<>();
switch (step)
{
case STEP_1:
rsList.add(createRSInfo(RS1_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
break;
case STEP_2:
rsList.add(createRSInfo(RS1_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
break;
case STEP_3:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS2_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
break;
case STEP_4:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS2_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
dsList.add(createDSInfo(DS3_ID, RS2_ID));
break;
case STEP_5:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS2_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
dsList.add(createDSInfo(DS3_ID, RS2_ID));
dsList.add(createDSInfo(DS4_ID, RS2_ID));
break;
case STEP_6:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS2_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
dsList.add(createDSInfo(DS3_ID, RS2_ID));
dsList.add(createDSInfo(DS4_ID, RS2_ID));
dsList.add(createDSInfo(DS5_ID, RS2_ID));
break;
case STEP_7:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS2_ID));
rsList.add(createRSInfo(RS3_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
dsList.add(createDSInfo(DS3_ID, RS2_ID));
dsList.add(createDSInfo(DS4_ID, RS2_ID));
dsList.add(createDSInfo(DS5_ID, RS3_ID));
break;
case STEP_8:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS2_ID));
rsList.add(createRSInfo(RS3_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
dsList.add(createDSInfo(DS3_ID, RS2_ID));
dsList.add(createDSInfo(DS4_ID, RS2_ID));
dsList.add(createDSInfo(DS5_ID, RS3_ID));
dsList.add(createDSInfo(DS6_ID, RS3_ID));
break;
case STEP_9:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS2_ID));
rsList.add(createRSInfo(RS3_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
dsList.add(createDSInfo(DS3_ID, RS2_ID));
dsList.add(createDSInfo(DS4_ID, RS2_ID));
dsList.add(createDSInfo(DS5_ID, RS3_ID));
break;
case STEP_10:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS2_ID));
rsList.add(createRSInfo(RS3_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
dsList.add(createDSInfo(DS3_ID, RS2_ID));
dsList.add(createDSInfo(DS4_ID, RS2_ID));
dsList.add(createDSInfo(DS5_ID, RS3_ID));
dsList.add(createDSInfo(DS6_ID, RS3_ID));
break;
case STEP_11:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS2_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
dsList.add(createDSInfo(DS3_ID, RS2_ID));
dsList.add(createDSInfo(DS4_ID, RS2_ID));
dsList.add(createDSInfo(DS5_ID, RS2_ID));
dsList.add(createDSInfo(DS6_ID, RS2_ID));
break;
case STEP_12:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS2_ID));
rsList.add(createRSInfo(RS3_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
dsList.add(createDSInfo(DS3_ID, RS2_ID));
dsList.add(createDSInfo(DS4_ID, RS2_ID));
dsList.add(createDSInfo(DS5_ID, RS3_ID));
dsList.add(createDSInfo(DS6_ID, RS3_ID));
break;
case STEP_13:
rsList.add(createRSInfo(RS1_ID));
rsList.add(createRSInfo(RS3_ID));
dsList.add(createDSInfo(DS1_ID, RS1_ID));
dsList.add(createDSInfo(DS2_ID, RS1_ID));
dsList.add(createDSInfo(DS5_ID, RS3_ID));
dsList.add(createDSInfo(DS6_ID, RS3_ID));
break;
default:
fail("Unknown test step: " + step);
}
return new TopoView(dsList, rsList);
}
/**
* Get the topo view each DS in the provided ds list has and compares it
* with the theoretical topology view that every body should have at the time
* this method is called.
*/
private void checkTopoView(int[] dsIdList, TopoView theoricalTopoView)
throws Exception
{
Thread.sleep(500);
for(int currentDsId : dsIdList)
{
LDAPReplicationDomain rd = null;
switch (currentDsId)
{
case DS1_ID:
rd = rd1;
break;
case DS2_ID:
rd = rd2;
break;
case DS3_ID:
rd = rd3;
break;
case DS4_ID:
rd = rd4;
break;
case DS5_ID:
rd = rd5;
break;
case DS6_ID:
rd = rd6;
break;
default:
fail("Unknown replication domain server id.");
}
/**
* Get the topo view of the current analyzed DS
*/
// Add info for DS itself:
// we need to clone the list as we don't want to modify the list kept
// inside the DS.
final DSInfo dsInfo = new DSInfo(rd.getServerId(), "dummy:1234", rd.getRsServerId(),
TEST_DN_WITH_ROOT_ENTRY_GENID,
rd.getStatus(),
rd.isAssured(), rd.getAssuredMode(), rd.getAssuredSdLevel(),
rd.getGroupId(), rd.getRefUrls(),
rd.getEclIncludes(), rd.getEclIncludesForDeletes(),
ProtocolVersion.getCurrentVersion());
final List<DSInfo> dsList = new ArrayList<>(rd.getReplicaInfos().values());
dsList.add(dsInfo);
TopoView dsTopoView = new TopoView(dsList, rd.getRsInfos());
assertEquals(dsTopoView, theoricalTopoView, " in DSid=" + currentDsId);
}
}
/**
* Bag class representing a view of the topology at a given time
* (who is connected to who, what are the config parameters...)
*/
private class TopoView
{
private List<DSInfo> dsList;
private List<RSInfo> rsList;
public TopoView(List<DSInfo> dsList, List<RSInfo> rsList)
{
assertNotNull(dsList);
assertNotNull(rsList);
this.dsList = dsList;
this.rsList = rsList;
}
@Override
public boolean equals(Object obj)
{
if (obj == null || getClass() != obj.getClass())
{
return false;
}
TopoView other = (TopoView) obj;
return checkLists(dsList, other.dsList)
&& checkLists(rsList, other.rsList);
}
private boolean checkLists(List<?> list, List<?> otherList)
{
if (otherList.size() != list.size())
{
return false;
}
for (Object otherObj : otherList)
{
int found = 0;
for (Object thisObj : list)
{
if (thisObj.equals(otherObj))
{
found++;
}
}
// Not found
if (found == 0)
{
return false;
}
// Should never see twice as dsInfo structure in a dsList
assertFalse(found > 1);
// Ok, found exactly once in the list, examine next structure
}
return true;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder("TopoView:");
sb.append("\n----------------------------\n");
sb.append("CONNECTED DS SERVERS:\n");
for (DSInfo dsInfo : dsList)
{
sb.append(dsInfo).append("\n----------------------------\n");
}
sb.append("CONNECTED RS SERVERS:\n");
for (RSInfo rsInfo : rsList)
{
sb.append(rsInfo).append("\n----------------------------\n");
}
return sb.toString();
}
private TopologyViewTest getOuterType()
{
return TopologyViewTest.this;
}
}
private String getHostPort(int port)
{
return LOCAL_HOST_NAME + ":" + port;
}
}