/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyright [year] [name of copyright owner]".
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
*/
package org.opends.server.replication.server;
import static java.util.Arrays.*;
import static org.assertj.core.api.Assertions.*;
import static org.opends.server.TestCaseUtils.*;
import static org.opends.server.util.CollectionUtils.*;
import static org.testng.Assert.*;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
import org.assertj.core.api.SoftAssertions;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.server.config.meta.ReplicationDomainCfgDefn.AssuredType;
import org.forgerock.opendj.server.config.server.ReplicationDomainCfg;
import org.opends.server.TestCaseUtils;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.AssuredMode;
import org.opends.server.replication.common.CSNGenerator;
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.plugin.DomainFakeCfg;
import org.opends.server.replication.plugin.MultimasterReplication;
import org.opends.server.replication.protocol.AckMsg;
import org.opends.server.replication.protocol.DeleteMsg;
import org.opends.server.replication.protocol.ErrorMsg;
import org.opends.server.replication.protocol.ReplServerStartMsg;
import org.opends.server.replication.protocol.ReplSessionSecurity;
import org.opends.server.replication.protocol.ReplicationMsg;
import org.opends.server.replication.protocol.Session;
import org.opends.server.replication.protocol.TopologyMsg;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.service.ReplicationDomain;
import org.opends.server.types.DirectoryException;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* Test Server part of the assured feature in both safe data and
* safe read modes.
*/
@SuppressWarnings("javadoc")
public class AssuredReplicationServerTest
extends ReplicationTestCase
{
private String testName = this.getClass().getSimpleName();
/** The tracer object for the debug logger. */
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
private int[] rsPorts;
private static final int FDS1_ID = 1;
private static final int FDS2_ID = 2;
private static final int FDS3_ID = 3;
private static final int FDS4_ID = 4;
private static final int FDS5_ID = 5;
private static final int FDS6_ID = 6;
private static final int FDS7_ID = 7;
private static final int FDS8_ID = 8;
private static final int FDS9_ID = 9;
private static final int FDS10_ID = 10;
private static final int FDS11_ID = 11;
private static final int FDS12_ID = 12;
private static final int FRS1_ID = 51;
private static final int FRS2_ID = 52;
private static final int FRS3_ID = 53;
private static final int DS_FRS2_ID = FRS2_ID + 10;
private static final int RS1_ID = 101;
private static final int RS2_ID = 102;
private static final int RS3_ID = 103;
private static final int RS4_ID = 104;
/**
* We don't use index 0 to stay consistent with what old code was doing
* fakeRd1 == fakeRDs[1], etc.
*/
private FakeReplicationDomain[] fakeRDs;
private FakeReplicationServer fakeRs1;
private FakeReplicationServer fakeRs2;
private FakeReplicationServer fakeRs3;
private ReplicationServer rs1;
private ReplicationServer rs2;
private ReplicationServer rs3;
private ReplicationServer rs4;
/**
* Small assured timeout value (timeout to be used in first RS receiving an
* assured update from a DS).
*/
private static final int SMALL_TIMEOUT = 3000;
/**
* Long assured timeout value (timeout to use in DS when sending an assured
* update).
*/
private static final int LONG_TIMEOUT = 5000;
/**
* Expected max time for sending an assured update and receive its ack
* (without errors).
*/
private static final int MAX_SEND_UPDATE_TIME = 2000;
/** Default group id. */
private static final int DEFAULT_GID = 1;
/** Other group ids. */
private static final int OTHER_GID = 2;
private static final int OTHER_GID_BIS = 3;
/** Default generation id. */
private static final long DEFAULT_GENID = EMPTY_DN_GENID;
/** Other generation id. */
private static final long OTHER_GENID = 500L;
/*
* Definitions for the scenario of the fake DS
*/
/** DS receives updates and replies acks with no errors to every updates. */
private static final int REPLY_OK_DS_SCENARIO = 1;
/** DS receives updates but does not respond (makes timeouts). */
private static final int TIMEOUT_DS_SCENARIO = 2;
/** DS receives updates and replies ack with replay error flags. */
private static final int REPLAY_ERROR_DS_SCENARIO = 3;
/*
* Definitions for the scenario of the fake RS
*/
/** RS receives updates and replies acks with no errors to every updates. */
private static final int REPLY_OK_RS_SCENARIO = 11;
/** RS receives updates but does not respond (makes timeouts). */
private static final int TIMEOUT_RS_SCENARIO = 12;
/**
* RS is used for sending updates (with sendNewFakeUpdate()) and receive acks,
* synchronously.
*/
private static final int SENDER_RS_SCENARIO = 13;
// Scenarios only used in safe read tests:
/**
* RS receives updates and replies ack error as if a DS was connected to it
* and timed out.
*/
private static final int DS_TIMEOUT_RS_SCENARIO_SAFE_READ = 14;
/**
* RS receives updates and replies ack error as if a DS was connected to it
* and was wrong status.
*/
private static final int DS_WRONG_STATUS_RS_SCENARIO_SAFE_READ = 15;
/**
* RS receives updates and replies ack error as if a DS was connected to it
* and had a replay error.
*/
private static final int DS_REPLAY_ERROR_RS_SCENARIO_SAFE_READ = 16;
private void debugInfo(String s)
{
logger.error(LocalizableMessage.raw(s));
if (logger.isTraceEnabled())
{
logger.trace("** TEST **" + s);
}
}
/**
* Before starting the tests configure some stuff.
*/
@BeforeClass
@Override
public void setUp() throws Exception
{
super.setUp();
rsPorts = TestCaseUtils.findFreePorts(4);
}
private void initTest()
{
fakeRDs = new FakeReplicationDomain[13];
fakeRs1 = fakeRs2 = fakeRs3 = null;
rs1 = rs2 = rs3 = rs4 = null;
}
private void endTest() throws Exception
{
disableService(fakeRDs);
Arrays.fill(fakeRDs, null);
shutdown(fakeRs1, fakeRs2, fakeRs3);
fakeRs1 = fakeRs2 = fakeRs3 = null;
remove(rs1, rs2, rs3, rs4);
rs1 = rs2 = rs3 = rs4 = null;
}
private void disableService(FakeReplicationDomain... fakeRDs)
{
for (FakeReplicationDomain fakeRd : fakeRDs)
{
if (fakeRd != null)
{
fakeRd.disableService();
}
}
}
private void shutdown(FakeReplicationServer... fakeRSs)
{
for (FakeReplicationServer fakeRs : fakeRSs)
{
if (fakeRs != null)
{
fakeRs.shutdown();
}
}
}
/**
* Creates and connects a new fake replication domain, using the passed scenario
* (no server state constructor version).
*/
private FakeReplicationDomain createFakeReplicationDomain(int serverId,
int groupId, int rsId, long generationId, AssuredMode assuredMode,
int safeDataLevel, long assuredTimeout, int scenario) throws Exception
{
return createFakeReplicationDomain(serverId, groupId, rsId, generationId,
assuredMode, safeDataLevel, assuredTimeout, scenario,
new ServerState(), true);
}
private int getRsPort(int rsId)
{
return rsPorts[rsId - 101];
}
/**
* Creates a new fake replication domain, using the passed scenario.
*
* @param groupId
* The group ID for the replication domain.
* @param rsId
* The replication server ID.
* @param generationId
* The generationID associated with data in the domain.
* @param assured
* Is this domain using assured replication.
* @param assuredMode
* The mode if assured replication is enabled.
* @param safeDataLevel
* The
* @param assuredTimeout
* The timeout for acks in assured mode.
* @param scenario
* The scenario identifier
* @param serverState
* The state of the server to start with
* @param startListen
* If true, we start the listen service. In all cases, the publish
* service gets started.
* @return
* The FakeReplicationDomain, a mock-up of a Replication Domain
* for tests
* @throws Exception
*/
private FakeReplicationDomain createFakeReplicationDomain(
int serverId, int groupId, int rsId, long generationId,
AssuredMode assuredMode, int safeDataLevel,
long assuredTimeout, int scenario, ServerState serverState,
boolean startListen) throws Exception
{
final DomainFakeCfg config = newDomainConfig(serverId, groupId, rsId,
assuredMode, safeDataLevel, assuredTimeout);
return createFakeReplicationDomain(config, rsId, generationId, scenario,
serverState, startListen);
}
private FakeReplicationDomain createFakeReplicationDomain(
ReplicationDomainCfg config, int rsId, long generationId, int scenario,
ServerState serverState, boolean startListen) throws Exception
{
FakeReplicationDomain fakeReplicationDomain =
new FakeReplicationDomain(config, generationId, scenario, serverState);
fakeReplicationDomain.startPublishService();
if (startListen)
{
fakeReplicationDomain.startListenService();
}
assertTrue(fakeReplicationDomain.isConnected());
assertEquals(fakeReplicationDomain.getReplicationServer().getPort(), getRsPort(rsId));
return fakeReplicationDomain;
}
private DomainFakeCfg newDomainConfig(int serverId, int groupId, int rsId,
AssuredMode assuredMode, int safeDataLevel, long assuredTimeout)
throws DirectoryException
{
final int rsPort = getRsPort(rsId);
final DomainFakeCfg fakeCfg = new DomainFakeCfg(
DN.valueOf(TEST_ROOT_DN_STRING), serverId, newTreeSet("localhost:" + rsPort),
getAssuredType(assuredMode),
safeDataLevel, groupId, assuredTimeout, new TreeSet());
fakeCfg.setHeartbeatInterval(1000);
fakeCfg.setChangetimeHeartbeatInterval(500);
return fakeCfg;
}
private AssuredType getAssuredType(AssuredMode assuredMode)
{
if (assuredMode == null)
{
return AssuredType.NOT_ASSURED;
}
switch (assuredMode)
{
case SAFE_READ_MODE:
return AssuredType.SAFE_READ;
case SAFE_DATA_MODE:
return AssuredType.SAFE_DATA;
}
throw new RuntimeException("Not implemented for " + assuredMode);
}
private FakeReplicationServer createFakeReplicationServer(int serverId,
int groupId, long generationId, boolean assured,
AssuredMode assuredMode, int safeDataLevel, int scenario)
throws Exception
{
return createFakeReplicationServer(serverId, groupId, RS1_ID, generationId,
assured, assuredMode, safeDataLevel, new ServerState(), scenario);
}
/**
* Creates and connects a new fake replication server, using the passed scenario.
*/
private FakeReplicationServer createFakeReplicationServer(int serverId,
int groupId, int rsId, long generationId, boolean assured,
AssuredMode assuredMode, int safeDataLevel, ServerState serverState,
int scenario) throws Exception
{
// Set port to right real RS according to its id
int rsPort = getRsPort(rsId);
FakeReplicationServer fakeReplicationServer = new FakeReplicationServer(
rsPort, serverId, assured, assuredMode, safeDataLevel, groupId,
DN.valueOf(TEST_ROOT_DN_STRING), generationId);
// Connect fake RS to the real RS
fakeReplicationServer.connect(serverState);
// Start wished scenario
fakeReplicationServer.start(scenario);
return fakeReplicationServer;
}
/**
* Creates a new real replication server (one which is to be tested).
*/
private ReplicationServer createReplicationServer(int serverId, int groupId,
long assuredTimeout, String testCase, int nbRS) throws ConfigException
{
int port = getRsPort(serverId);
SortedSet otherRsUrls =
generateOtherReplicationServerUrls(port, nbRS);
String dir = testName + serverId + testCase + "Db";
ReplServerFakeConfiguration conf =
new ReplServerFakeConfiguration(port, dir, 0, serverId, 0,
100, otherRsUrls, groupId, assuredTimeout, 5000);
// No monitoring publisher to not interfere with some SocketTimeoutException
// expected at some points in these tests
conf.setMonitoringPeriod(0L);
return new ReplicationServer(conf);
}
/**
* Returns a Set containing the URLs for the real Replication Servers
* (RS for short) for the specified number of RSs excluding the URL for the
* excludedRsPort. The returned Set size is nbRS - 1 (for the excluded port).
*
* @param excludedRsPort
* the RS port to exclude
* @param totalNbRS
* the total number of real RSs that will be part of the topology.
* @return a SortedSet containing the RS URLs.
*/
private SortedSet generateOtherReplicationServerUrls(
int excludedRsPort, int totalNbRS)
{
SortedSet replServers = new TreeSet<>();
if (totalNbRS >= 2)
{
addIfNotSame(replServers, rsPorts[0], excludedRsPort);
addIfNotSame(replServers, rsPorts[1], excludedRsPort);
if (totalNbRS >= 3)
{
addIfNotSame(replServers, rsPorts[2], excludedRsPort);
if (totalNbRS >= 4)
{
addIfNotSame(replServers, rsPorts[3], excludedRsPort);
}
}
}
return replServers;
}
private void addIfNotSame(Set replServers, int rsPort,
int excludedRsPort)
{
if (rsPort != excludedRsPort)
{
replServers.add("localhost:" + rsPort);
}
}
/**
* Fake replication domain implementation to test the replication server
* regarding the assured feature.
* According to the configured scenario, it will answer to updates with acks
* as the scenario is requesting.
*/
private class FakeReplicationDomain extends ReplicationDomain
{
/** The scenario this DS is expecting. */
private final int scenario;
private final CSNGenerator gen;
/** Number of received updates. */
private int nReceivedUpdates;
private int nWrongReceivedUpdates;
/**
* Creates a fake replication domain (DS)
* @param baseDN The base dn used at connection to RS
* @param serverID our server id
* @param generationId the generation id we use at connection to real RS
* @param groupId our group id
* @param assured do we expect incoming assured updates (also used for outgoing updates)
* @param assuredMode the expected assured mode of the incoming updates (also used for outgoing updates)
* @param safeDataLevel the expected safe data level of the incoming updates (also used for outgoing updates)
* @param assuredTimeout the assured timeout used when sending updates
* @param scenario the scenario we are creating for (implies particular
* behavior upon reception of updates)
* @throws org.opends.server.config.ConfigException
*/
private FakeReplicationDomain(ReplicationDomainCfg config,
long generationId, int scenario, ServerState serverState)
throws ConfigException
{
super(config, generationId, serverState);
this.scenario = scenario;
gen = new CSNGenerator(config.getServerId(), 0L);
}
@Override
public long countEntries() throws DirectoryException
{
// Not needed for this test
return -1;
}
@Override
protected void exportBackend(OutputStream output) throws DirectoryException
{
// Not needed for this test
}
@Override
protected void importBackend(InputStream input) throws DirectoryException
{
// Not needed for this test
}
@Override
public boolean processUpdate(UpdateMsg updateMsg)
{
checkUpdateAssuredParameters(updateMsg);
nReceivedUpdates++;
// Now execute the requested scenario
switch (scenario)
{
case TIMEOUT_DS_SCENARIO:
// Let timeout occur
break;
case REPLY_OK_DS_SCENARIO:
// Send the ack without errors
// Call processUpdateDone and update the server state is what needs to
// be done when using asynchronous process update mechanism
// (see processUpdate javadoc)
processUpdateDone(updateMsg, null);
getServerState().update(updateMsg.getCSN());
break;
case REPLAY_ERROR_DS_SCENARIO:
// Send the ack with replay error
// Call processUpdateDone and update the server state is what needs to
// be done when using asynchronous process update mechanism
// (see processUpdate javadoc)
processUpdateDone(updateMsg, "This is the replay error message generated from fake DS " +
getServerId() + " for update with CSN " + updateMsg.getCSN());
getServerState().update(updateMsg.getCSN());
break;
default:
Assert.fail("Unknown scenario: " + scenario);
}
// IMPORTANT: return false so that we use the asynchronous processUpdate mechanism
// (see processUpdate javadoc)
return false;
}
/**
* Check that received update assured parameters are as defined at DS start.
*/
private void checkUpdateAssuredParameters(UpdateMsg updateMsg)
{
boolean ok = true;
if (updateMsg.isAssured() != isAssured())
{
debugInfo("Fake DS " + getServerId() + " received update assured flag is wrong: " + updateMsg);
ok = false;
}
if (isAssured() && updateMsg.getAssuredMode() != getAssuredMode())
{ // it is meaningless to have different assured mode when UpdateMsg is not assured
debugInfo("Fake DS " + getServerId() + " received update assured mode is wrong: " + updateMsg);
ok = false;
}
if (updateMsg.getSafeDataLevel() != getAssuredSdLevel())
{
debugInfo("Fake DS " + getServerId() + " received update assured sd level is wrong: " + updateMsg);
ok = false;
}
if (ok)
{
debugInfo("Fake DS " + getServerId() + " received update assured parameters are ok: " + updateMsg);
}
else
{
nWrongReceivedUpdates++;
}
}
/**
* Sends a new update from this DS.
* @throws TimeoutException If timeout waiting for an assured ack
*/
private void sendNewFakeUpdate() throws TimeoutException
{
// Create a new delete update message (the simplest to create)
DeleteMsg delMsg = new DeleteMsg(getBaseDN(), gen.newCSN(), UUID.randomUUID().toString());
// Send it (this uses the defined assured conf at constructor time)
prepareWaitForAckIfAssuredEnabled(delMsg);
publish(delMsg);
waitForAckIfAssuredEnabled(delMsg);
}
private void assertReceivedWrongUpdates(int expectedNbUpdates, int expectedNbWrongUpdates)
{
final SoftAssertions softly = new SoftAssertions();
softly.assertThat(nReceivedUpdates).as("receivedUpdates").isEqualTo(expectedNbUpdates);
softly.assertThat(nWrongReceivedUpdates).as("wrongReceivedUpdates").isEqualTo(expectedNbWrongUpdates);
softly.assertAll();
}
private void assertReceivedUpdates(int expectedNbUpdates)
{
assertReceivedWrongUpdates(expectedNbUpdates, 0);
}
public SafeReadAssertions newSafeReadAssertions()
{
return new SafeReadAssertions(this);
}
}
private static class SafeReadAssertions
{
private ReplicationDomain domain;
private int sentUpdates;
private int acknowledgedUpdates;
private int notAcknowledgedUpdates;
private int timeoutUpdates;
private int wrongStatusUpdates;
private int replayErrorUpdates;
private final Map serverNotAcknowledgedUpdates = new HashMap<>();
private int receivedUpdates;
private int receivedUpdatesAcked;
private int receivedUpdatesNotAcked;
public SafeReadAssertions(FakeReplicationDomain domain)
{
this.domain = domain;
}
public void runAsserts()
{
final SoftAssertions softly = new SoftAssertions();
softly.assertThat(domain.getAssuredSrSentUpdates())
.as("sentUpdates").isEqualTo(sentUpdates);
softly.assertThat(domain.getAssuredSrAcknowledgedUpdates())
.as("acknowledgedUpdates").isEqualTo(acknowledgedUpdates);
softly.assertThat(domain.getAssuredSrNotAcknowledgedUpdates())
.as("notAcknowledgedUpdates").isEqualTo(notAcknowledgedUpdates);
softly.assertThat(domain.getAssuredSrTimeoutUpdates())
.as("timeoutUpdates").isEqualTo(timeoutUpdates);
softly.assertThat(domain.getAssuredSrWrongStatusUpdates())
.as("wrongStatusUpdates").isEqualTo(wrongStatusUpdates);
softly.assertThat(domain.getAssuredSrReplayErrorUpdates())
.as("replayErrorUpdates").isEqualTo(replayErrorUpdates);
softly.assertThat(domain.getAssuredSrServerNotAcknowledgedUpdates())
.as("serverNotAcknowledgedUpdates").isEqualTo(serverNotAcknowledgedUpdates);
softly.assertThat(domain.getAssuredSrReceivedUpdates())
.as("receivedUpdates").isEqualTo(receivedUpdates);
softly.assertThat(domain.getAssuredSrReceivedUpdatesAcked())
.as("receivedUpdatesAcked").isEqualTo(receivedUpdatesAcked);
softly.assertThat(domain.getAssuredSrReceivedUpdatesNotAcked())
.as("receivedUpdatesNotAcked").isEqualTo(receivedUpdatesNotAcked);
softly.assertAll();
}
public SafeReadAssertions sentUpdates(int value)
{
sentUpdates = value;
return this;
}
public SafeReadAssertions acknowledgedUpdates(int value)
{
acknowledgedUpdates = value;
return this;
}
public SafeReadAssertions notAcknowledgedUpdates(int value)
{
notAcknowledgedUpdates = value;
return this;
}
public SafeReadAssertions timeoutUpdates(int value)
{
timeoutUpdates = value;
return this;
}
public SafeReadAssertions wrongStatusUpdates(int value)
{
wrongStatusUpdates = value;
return this;
}
public SafeReadAssertions replayErrorUpdates(int value)
{
replayErrorUpdates = value;
return this;
}
public SafeReadAssertions serverNotAcknowledgedUpdates(int key, int value)
{
serverNotAcknowledgedUpdates.put(key, value);
return this;
}
public SafeReadAssertions receivedUpdates(int value)
{
receivedUpdates = value;
return this;
}
public SafeReadAssertions receivedUpdatesAcked(int value)
{
receivedUpdatesAcked = value;
return this;
}
public SafeReadAssertions receivedUpdatesNotAcked(int value)
{
receivedUpdatesNotAcked = value;
return this;
}
}
/**
* The fake replication server used to emulate RS behavior the way we want
* for assured features test.
* This fake replication server is able to receive another RS connection only.
* According to the configured scenario, it will answer to updates with acks
* as the scenario is requesting.
*/
private static int fakePort;
private class FakeReplicationServer extends Thread
{
private boolean shutdown;
private Session session;
/** Parameters given at constructor time. */
private int port;
private int serverId = -1;
/** Default value for config. */
private boolean isAssured;
/** Default value for config. */
private AssuredMode assuredMode = AssuredMode.SAFE_DATA_MODE;
/** Default value for config. */
private byte safeDataLevel = 1;
private DN baseDN;
private long generationId = -1L;
private byte groupId = -1;
private boolean sslEncryption;
/** The scenario this RS is expecting. */
private int scenario = -1;
private CSNGenerator gen;
/** False if a received update had assured parameters not as expected. */
private boolean everyUpdatesAreOk = true;
/** Number of received updates. */
private int nReceivedUpdates;
/**
* True if an ack has been replied to a received assured update (in assured
* mode of course) used in reply scenario.
*/
private boolean ackReplied;
/**
* Creates a fake replication server.
* @param port port of the real RS we will connect to
* @param serverId our server id
* @param assured do we expect incoming assured updates (also used for outgoing updates)
* @param assuredMode the expected assured mode of the incoming updates (also used for outgoing updates)
* @param safeDataLevel the expected safe data level of the incoming updates (also used for outgoing updates)
* @param groupId our group id
* @param baseDN the baseDN we connect with, to the real RS
* @param generationId the generation id we use at connection to real RS
*/
public FakeReplicationServer(int port, int serverId, boolean assured,
AssuredMode assuredMode, int safeDataLevel,
int groupId, DN baseDN, long generationId)
{
this.port = port;
this.serverId = serverId;
this.baseDN = baseDN;
this.generationId = generationId;
this.groupId = (byte) groupId;
this.isAssured = assured;
this.assuredMode = assuredMode;
this.safeDataLevel = (byte) safeDataLevel;
gen = new CSNGenerator(serverId + 10, 0L);
}
/**
* Make the RS send an assured message and return the ack message it
* receives from the RS.
*/
public AckMsg sendNewFakeUpdate() throws Exception
{
// Create a new delete update message (the simplest to create)
DeleteMsg delMsg = new DeleteMsg(baseDN, gen.newCSN(),
UUID.randomUUID().toString());
// Send del message in assured mode
delMsg.setAssured(isAssured);
delMsg.setAssuredMode(assuredMode);
delMsg.setSafeDataLevel(safeDataLevel);
session.publish(delMsg);
// Read and return matching ack
ReplicationMsg replMsg = session.receive();
if (replMsg instanceof ErrorMsg)
{
// Support for connection done with bad gen id : we receive an error
// message that we must throw away before reading our ack.
replMsg = session.receive();
}
return (AckMsg)replMsg;
}
/**
* Connect to RS.
*/
public void connect(ServerState serverState) throws Exception
{
// Create and connect socket
InetSocketAddress serverAddr =
new InetSocketAddress("localhost", port);
Socket socket = new Socket();
socket.setReuseAddress(true);
socket.setTcpNoDelay(true);
int timeoutMS = MultimasterReplication.getConnectionTimeoutMS();
socket.connect(serverAddr, timeoutMS);
// Create client session
fakePort++;
String fakeUrl = "localhost:" + fakePort;
ReplSessionSecurity replSessionSecurity = new ReplSessionSecurity();
session = replSessionSecurity.createClientSession(socket, timeoutMS);
// Send our repl server start msg
ReplServerStartMsg replServerStartMsg = new ReplServerStartMsg(serverId,
fakeUrl, baseDN, 100, serverState,
generationId, sslEncryption, groupId, 5000);
session.publish(replServerStartMsg);
// Read repl server start msg
ReplServerStartMsg inReplServerStartMsg = (ReplServerStartMsg) session.
receive();
sslEncryption = inReplServerStartMsg.getSSLEncryption();
if (!sslEncryption)
{
session.stopEncryption();
}
// Send our topo mesg
RSInfo rsInfo = new RSInfo(serverId, fakeUrl, generationId, groupId, 1);
session.publish(new TopologyMsg(null, newArrayList(rsInfo)));
// Read topo msg
TopologyMsg inTopoMsg = (TopologyMsg) session.receive();
debugInfo("Fake RS " + serverId + " handshake received the following info:" + inTopoMsg);
}
/**
* Starts the fake RS, expecting and testing the passed scenario.
*/
public void start(int scenario)
{
// Store expected test case
this.scenario = scenario;
if (scenario == SENDER_RS_SCENARIO)
{
// Do not start the listening thread and let the main thread receive
// receive acks in sendNewFakeUpdate()
return;
}
// Start listening
start();
}
/**
* Wait for DS connections.
*/
@Override
public void run()
{
try
{
// Loop receiving and treating updates
while (!shutdown)
{
try
{
ReplicationMsg replicationMsg = session.receive();
if (!(replicationMsg instanceof UpdateMsg))
{
debugInfo("Fake RS " + serverId + " received non update message: " +
replicationMsg);
continue;
}
UpdateMsg updateMsg = (UpdateMsg) replicationMsg;
checkUpdateAssuredParameters(updateMsg);
nReceivedUpdates++;
// Now execute the requested scenario
switch (scenario)
{
case REPLY_OK_RS_SCENARIO:
if (updateMsg.isAssured())
{
// Send the ack without errors
AckMsg ackMsg = new AckMsg(updateMsg.getCSN());
session.publish(ackMsg);
ackReplied = true;
}
break;
case TIMEOUT_RS_SCENARIO:
// Let timeout occur
break;
case DS_TIMEOUT_RS_SCENARIO_SAFE_READ:
if (updateMsg.isAssured())
{
// Emulate RS waiting for virtual DS ack
sleep(MAX_SEND_UPDATE_TIME);
// Send the ack with timeout error from a virtual DS with id (ours + 10)
AckMsg ackMsg = new AckMsg(updateMsg.getCSN());
ackMsg.setHasTimeout(true);
ackMsg.setFailedServers(newArrayList(serverId + 10));
session.publish(ackMsg);
ackReplied = true;
}
break;
case DS_WRONG_STATUS_RS_SCENARIO_SAFE_READ:
if (updateMsg.isAssured())
{
// Send the ack with wrong status error from a virtual DS with id (ours + 10)
AckMsg ackMsg = new AckMsg(updateMsg.getCSN());
ackMsg.setHasWrongStatus(true);
ackMsg.setFailedServers(newArrayList(serverId + 10));
session.publish(ackMsg);
ackReplied = true;
}
break;
case DS_REPLAY_ERROR_RS_SCENARIO_SAFE_READ:
if (updateMsg.isAssured())
{
// Send the ack with replay error from a virtual DS with id (ours + 10)
AckMsg ackMsg = new AckMsg(updateMsg.getCSN());
ackMsg.setHasReplayError(true);
ackMsg.setFailedServers(newArrayList(serverId + 10));
session.publish(ackMsg);
ackReplied = true;
}
break;
default:
Assert.fail("Unknown scenario: " + scenario);
}
} catch (SocketTimeoutException toe)
{
// We may timeout reading, in this case just re-read
debugInfo("Fake RS " + serverId + " : " + toe.
getMessage() + " (this is normal)");
}
}
} catch (Throwable th)
{
debugInfo("Terminating thread of fake RS " + serverId + " :" + th.
getMessage());
// Probably thread closure from main thread
}
}
/**
* Shutdown the Replication Server service and all its connections.
*/
public void shutdown()
{
if (shutdown)
{
return;
}
shutdown = true;
// Shutdown any current client handling code
if (session != null)
{
session.close();
}
try
{
join();
} catch (InterruptedException ignored)
{
}
}
/**
* Check that received update assured parameters are as defined at RS start.
*/
private void checkUpdateAssuredParameters(UpdateMsg updateMsg)
{
boolean ok = true;
if (updateMsg.isAssured() != isAssured)
{
debugInfo("Fake RS " + serverId + " received update assured flag is wrong: " + updateMsg);
ok = false;
}
if (updateMsg.getAssuredMode() != assuredMode)
{
debugInfo("Fake RS " + serverId + " received update assured mode is wrong: " + updateMsg);
ok = false;
}
if (updateMsg.getSafeDataLevel() != safeDataLevel)
{
debugInfo("Fake RS " + serverId + " received update assured sd level is wrong: " + updateMsg);
ok = false;
}
if (ok)
{
debugInfo("Fake RS " + serverId + " received update assured parameters are ok: " + updateMsg);
}
else
{
everyUpdatesAreOk = false;
}
}
/**
* Test if the last received updates was acknowledged (ack sent with or
* without errors).
*
* WARNING: this must be called once per update as it also immediately
* resets the status for a new test for the next update
*
*
* @return True if acknowledged
*/
public boolean ackReplied()
{
boolean result = ackReplied;
// reset ack replied status
ackReplied = false;
return result;
}
private void assertReceivedUpdates(int expectedNbUpdates)
{
assertEquals(nReceivedUpdates, expectedNbUpdates);
assertTrue(everyUpdatesAreOk);
}
private void assertReceivedAckedUpdates(final int expectedNbUpdates,
final boolean expectingAckReplied)
{
assertReceivedUpdates(expectedNbUpdates);
assertEquals(ackReplied(), expectingAckReplied);
}
}
/**
* See testSafeDataLevelOne comment.
* This is a facility to run the testSafeDataLevelOne in precommit in simplest
* case, so that precommit run test something and is not long.
* testSafeDataLevelOne will run in nightly tests (groups = "slow")
*/
@Test(enabled = true)
public void testSafeDataLevelOnePrecommit() throws Exception
{
testSafeDataLevelOne(DEFAULT_GID, false, false, DEFAULT_GID, DEFAULT_GID);
}
/**
* Returns possible combinations of parameters for testSafeDataLevelOne test.
*/
@DataProvider(name = "testSafeDataLevelOneProvider")
private Object[][] testSafeDataLevelOneProvider()
{
return new Object[][]
{
{ DEFAULT_GID, false, false, DEFAULT_GID, DEFAULT_GID},
{ DEFAULT_GID, false, false, OTHER_GID, DEFAULT_GID},
{ DEFAULT_GID, false, false, DEFAULT_GID, OTHER_GID},
{ DEFAULT_GID, false, false, OTHER_GID, OTHER_GID},
{ DEFAULT_GID, true, false, DEFAULT_GID, DEFAULT_GID},
{ DEFAULT_GID, true, false, OTHER_GID, DEFAULT_GID},
{ DEFAULT_GID, true, false, DEFAULT_GID, OTHER_GID},
{ DEFAULT_GID, true, false, OTHER_GID, OTHER_GID},
{ DEFAULT_GID, false, true, DEFAULT_GID, DEFAULT_GID},
{ DEFAULT_GID, false, true, OTHER_GID, DEFAULT_GID},
{ DEFAULT_GID, false, true, DEFAULT_GID, OTHER_GID},
{ DEFAULT_GID, false, true, OTHER_GID, OTHER_GID},
{ DEFAULT_GID, true, true, DEFAULT_GID, DEFAULT_GID},
{ DEFAULT_GID, true, true, OTHER_GID, DEFAULT_GID},
{ DEFAULT_GID, true, true, DEFAULT_GID, OTHER_GID},
{ DEFAULT_GID, true, true, OTHER_GID, OTHER_GID},
{ OTHER_GID, false, false, DEFAULT_GID, DEFAULT_GID},
{ OTHER_GID, false, false, OTHER_GID, DEFAULT_GID},
{ OTHER_GID, false, false, DEFAULT_GID, OTHER_GID},
{ OTHER_GID, false, false, OTHER_GID, OTHER_GID},
{ OTHER_GID, true, false, DEFAULT_GID, DEFAULT_GID},
{ OTHER_GID, true, false, OTHER_GID, DEFAULT_GID},
{ OTHER_GID, true, false, DEFAULT_GID, OTHER_GID},
{ OTHER_GID, true, false, OTHER_GID, OTHER_GID},
{ OTHER_GID, false, true, DEFAULT_GID, DEFAULT_GID},
{ OTHER_GID, false, true, OTHER_GID, DEFAULT_GID},
{ OTHER_GID, false, true, DEFAULT_GID, OTHER_GID},
{ OTHER_GID, false, true, OTHER_GID, OTHER_GID},
{ OTHER_GID, true, true, DEFAULT_GID, DEFAULT_GID},
{ OTHER_GID, true, true, OTHER_GID, DEFAULT_GID},
{ OTHER_GID, true, true, DEFAULT_GID, OTHER_GID},
{ OTHER_GID, true, true, OTHER_GID, OTHER_GID}
};
}
/**
* Test that the RS is able to acknowledge SD updates sent by SD, with level 1.
* - 1 main fake DS connected to 1 RS, with same GID as RS or not
* - 1 optional other fake DS connected to RS, with same GID as RS or not
* - 1 optional other fake RS connected to RS, with same GID as RS or not
* All possible combinations tested thanks to the provider
*/
@Test(dataProvider = "testSafeDataLevelOneProvider",
groups = { "slow", "opendj-256" },
enabled = true)
public void testSafeDataLevelOne(
int mainDsGid, boolean otherFakeDS, boolean fakeRS,
int otherFakeDsGid, int fakeRsGid) throws Exception
{
String testCase = "testSafeDataLevelOne";
debugInfo("Starting " + testCase);
initTest();
try
{
/*
* Start real RS (the one to be tested)
*/
// Create real RS 1
rs1 = createReplicationServer(RS1_ID, DEFAULT_GID, SMALL_TIMEOUT, testCase, 0);
/*
* Start main DS (the one which sends updates)
*/
// Create and connect fake domain 1 to RS 1
// Assured mode: SD, level 1
fakeRDs[1] = createFakeReplicationDomain(FDS1_ID, mainDsGid, RS1_ID,
DEFAULT_GENID, AssuredMode.SAFE_DATA_MODE, 1, LONG_TIMEOUT, TIMEOUT_DS_SCENARIO);
/*
* Start one other fake DS
*/
// Put another fake domain connected to real RS ?
if (otherFakeDS)
{
// Assured set to false as RS should forward change without assured requested
// Timeout scenario used so that no reply is made if however the real RS
// by mistake sends an assured error and expects an ack from this DS:
// this would timeout. If main DS group id is not the same as the real RS one,
// the update will even not come to real RS as assured
fakeRDs[2] = createFakeReplicationDomain(FDS2_ID, otherFakeDsGid, RS1_ID,
DEFAULT_GENID, null, 1, LONG_TIMEOUT, TIMEOUT_DS_SCENARIO);
}
/*
* Start 1 fake Rs
*/
// Put a fake RS connected to real RS ?
if (fakeRS)
{
// Assured set to false as RS should forward change without assured requested
// Timeout scenario used so that no reply is made if however the real RS
// by mistake sends an assured error and expects an ack from this fake RS:
// this would timeout. If main DS group id is not the same as the real RS one,
// the update will even not come to real RS as assured
fakeRs1 = createFakeReplicationServer(FRS1_ID, fakeRsGid, DEFAULT_GENID,
false, AssuredMode.SAFE_DATA_MODE, 1, TIMEOUT_RS_SCENARIO);
}
// Send update from DS 1
final FakeReplicationDomain fakeRd1 = fakeRDs[1];
long startTime = System.currentTimeMillis();
fakeRd1.sendNewFakeUpdate();
// Check call time (should have last a lot less than long timeout)
// (ack received if group id of DS and real RS are the same, no ack requested
// otherwise)
long sendUpdateTime = System.currentTimeMillis() - startTime;
assertThat(sendUpdateTime).isLessThan(MAX_SEND_UPDATE_TIME);
sleepWhileUpdatePropagates(500);
if (mainDsGid == DEFAULT_GID)
{
// Check monitoring values (check that ack has been correctly received)
assertEquals(fakeRd1.getAssuredSdSentUpdates(), 1);
assertEquals(fakeRd1.getAssuredSdAcknowledgedUpdates(), 1);
}
else
{
// Check monitoring values (DS group id (OTHER_GID) is not the same as RS one
// (DEFAULT_GID) so update should have been sent in normal mode
assertEquals(fakeRd1.getAssuredSdSentUpdates(), 0);
assertEquals(fakeRd1.getAssuredSdAcknowledgedUpdates(), 0);
}
assertEquals(fakeRd1.getAssuredSdTimeoutUpdates(), 0);
assertEquals(fakeRd1.getAssuredSdServerTimeoutUpdates().size(), 0);
// Sanity check
sleepWhileUpdatePropagates(500);
fakeRd1.assertReceivedUpdates(0);
if (otherFakeDS)
{
fakeRDs[2].assertReceivedUpdates(1);
}
if (fakeRS)
{
fakeRs1.assertReceivedUpdates(1);
}
} finally
{
endTest();
}
}
/**
* Returns possible combinations of parameters for testSafeDataLevelHighPrecommit test.
*/
@DataProvider(name = "testSafeDataLevelHighPrecommitProvider")
private Object[][] testSafeDataLevelHighPrecommitProvider()
{
return new Object[][]
{
{ 2, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
OTHER_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, OTHER_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
OTHER_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, OTHER_GENID, REPLY_OK_RS_SCENARIO,
DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO}
};
}
/**
* See testSafeDataLevelHigh comment.
*/
@Test(dataProvider = "testSafeDataLevelHighPrecommitProvider", groups = "slow", enabled = true)
public void testSafeDataLevelHighPrecommit(int sdLevel,
boolean otherFakeDS, int otherFakeDsGid, long otherFakeDsGenId,
int fakeRs1Gid, long fakeRs1GenId, int fakeRs1Scen,
int fakeRs2Gid, long fakeRs2GenId, int fakeRs2Scen,
int fakeRs3Gid, long fakeRs3GenId, int fakeRs3Scen) throws Exception
{
testSafeDataLevelHigh(sdLevel, otherFakeDS, otherFakeDsGid, otherFakeDsGenId,
fakeRs1Gid, fakeRs1GenId, fakeRs1Scen, fakeRs2Gid, fakeRs2GenId, fakeRs2Scen,
fakeRs3Gid, fakeRs3GenId, fakeRs3Scen);
}
/**
* Returns possible combinations of parameters for testSafeDataLevelHighNightly test.
*/
@DataProvider(name = "testSafeDataLevelHighNightlyProvider")
private Object[][] testSafeDataLevelHighNightlyProvider()
{
return new Object[][]
{
{ 2, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, TIMEOUT_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, TIMEOUT_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
OTHER_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, OTHER_GENID, TIMEOUT_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO, OTHER_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, OTHER_GENID, REPLY_OK_RS_SCENARIO, OTHER_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO, OTHER_GID,
OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO, OTHER_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, OTHER_GENID, TIMEOUT_RS_SCENARIO, OTHER_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 2, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, TIMEOUT_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, TIMEOUT_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
OTHER_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, OTHER_GENID, TIMEOUT_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO, OTHER_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, OTHER_GENID, REPLY_OK_RS_SCENARIO, OTHER_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, REPLY_OK_RS_SCENARIO, OTHER_GID,
OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, DEFAULT_GENID, TIMEOUT_RS_SCENARIO, OTHER_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, OTHER_GID, OTHER_GENID, TIMEOUT_RS_SCENARIO, OTHER_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO},
{ 3, true, DEFAULT_GID, DEFAULT_GENID, DEFAULT_GID, OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
OTHER_GENID, REPLY_OK_RS_SCENARIO, DEFAULT_GID,
DEFAULT_GENID, REPLY_OK_RS_SCENARIO}
};
}
/**
* See testSafeDataLevelHigh comment.
*/
@Test(dataProvider = "testSafeDataLevelHighNightlyProvider", groups = "slow", enabled = true)
public void testSafeDataLevelHighNightly(int sdLevel,
boolean otherFakeDS, int otherFakeDsGid, long otherFakeDsGenId,
int fakeRs1Gid, long fakeRs1GenId, int fakeRs1Scen,
int fakeRs2Gid, long fakeRs2GenId, int fakeRs2Scen,
int fakeRs3Gid, long fakeRs3GenId, int fakeRs3Scen) throws Exception
{
testSafeDataLevelHigh(sdLevel, otherFakeDS, otherFakeDsGid, otherFakeDsGenId,
fakeRs1Gid, fakeRs1GenId, fakeRs1Scen, fakeRs2Gid, fakeRs2GenId, fakeRs2Scen,
fakeRs3Gid, fakeRs3GenId, fakeRs3Scen);
}
/**
* Returns possible combinations of parameters for testSafeDataLevelHigh test.
*/
@DataProvider(name = "testSafeDataLevelHighProvider")
private Object[][] testSafeDataLevelHighProvider()
{
// Construct all possible combinations of parameters
List> objectArrayList = new ArrayList<>();
// Safe Data Level
objectArrayList = addPossibleParameters(objectArrayList, 2, 3);
// Other fake DS
objectArrayList = addPossibleParameters(objectArrayList, true, false);
// Other fake DS group id
objectArrayList = addPossibleParameters(objectArrayList, DEFAULT_GID, OTHER_GID);
// Other fake DS generation id
objectArrayList = addPossibleParameters(objectArrayList, DEFAULT_GENID, OTHER_GENID);
// Fake RS 1 group id
objectArrayList = addPossibleParameters(objectArrayList, DEFAULT_GID, OTHER_GID);
// Fake RS 1 generation id
objectArrayList = addPossibleParameters(objectArrayList, DEFAULT_GENID, OTHER_GENID);
// Fake RS 1 scenario
objectArrayList = addPossibleParameters(objectArrayList, REPLY_OK_RS_SCENARIO, TIMEOUT_RS_SCENARIO);
// Fake RS 2 group id
objectArrayList = addPossibleParameters(objectArrayList, DEFAULT_GID, OTHER_GID);
// Fake RS 2 generation id
objectArrayList = addPossibleParameters(objectArrayList, DEFAULT_GENID, OTHER_GENID);
// Fake RS 2 scenario
objectArrayList = addPossibleParameters(objectArrayList, REPLY_OK_RS_SCENARIO, TIMEOUT_RS_SCENARIO);
// Fake RS 3 group id
objectArrayList = addPossibleParameters(objectArrayList, DEFAULT_GID, OTHER_GID);
// Fake RS 3 generation id
objectArrayList = addPossibleParameters(objectArrayList, DEFAULT_GENID, OTHER_GENID);
// Fake RS 3 scenario
objectArrayList = addPossibleParameters(objectArrayList, REPLY_OK_RS_SCENARIO, TIMEOUT_RS_SCENARIO);
debugInfo("testSafeDataLevelHighProvider: number of possible parameter combinations : "
+ objectArrayList.size());
return toDataProvider(objectArrayList);
}
/**
* Helper for providers: Modify the passed object array list adding to each
* already contained object array each passed possible values.
*
* Example: to create all possible parameter combinations for a test method
* which has 2 parameters: one boolean then an integer, with both 2 possible
* values: {true|false} and {10|100}:
*
*
* List<List<Object>> objectArrayList = new ArrayList<List<Object>>();
* // Possible boolean values
* objectArrayList = addPossibleParameters(objectArrayList, true, false);
* // Possible integer values
* objectArrayList = addPossibleParameters(objectArrayList, 10, 100);
* Object[][] result = new Object[objectArrayList.size()][];
* int i = 0;
* for (List<Object> objectArray : objectArrayList)
* {
* result[i] = objectArray.toArray();
* i++;
* }
* return result;
*
*
* The provider will return the equivalent following Object[][]:
*
*
*/
private List> addPossibleParameters(List> objectArrayList, Object... possibleParameters)
{
List> newObjectArrayList = new ArrayList<>();
if (objectArrayList.isEmpty())
{
// First time we add some parameters, create first object arrays
// Add each possible parameter as initial parameter lists
for (Object possibleParameter : possibleParameters)
{
newObjectArrayList.add(newArrayList(possibleParameter));
}
return newObjectArrayList;
}
for (List