/*
* 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 2013-2015 ForgeRock AS.
*/
package org.opends.server.replication.service;
import java.util.*;
import java.util.Map.Entry;
import org.assertj.core.api.Assertions;
import org.assertj.core.data.MapEntry;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.RSInfo;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.protocol.ReplServerStartMsg;
import org.opends.server.replication.server.ReplicationServer;
import org.opends.server.replication.service.ReplicationBroker.RSEvaluations;
import org.opends.server.replication.service.ReplicationBroker.ReplicationServerInfo;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.util.Collections.*;
import static org.assertj.core.data.MapEntry.*;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.replication.service.ReplicationBroker.*;
import static org.opends.server.util.CollectionUtils.*;
import static org.testng.Assert.*;
/**
* Test the algorithm for finding the best replication server among the
* configured ones.
*/
@SuppressWarnings("javadoc")
public class ComputeBestServerTest extends ReplicationTestCase
{
/** The tracer object for the debug logger. */
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
// definitions for server ids
private static final int myId1 = 1;
private static final int myId2 = 2;
private static final int myId3 = 3;
// definitions for server names
private static final String WINNER = "winner:389";
private static final String LOOSER1 = "looser1:389";
private static final String LOOSER2 = "looser2:389";
private void debugInfo(String s)
{
logger.error(LocalizableMessage.raw(s));
if (logger.isTraceEnabled())
{
logger.trace("** TEST **" + s);
}
}
private ServerState newServerState(CSN... csns)
{
ServerState result = new ServerState();
for (CSN csn : csns)
{
result.update(csn);
}
return result;
}
/**
* Test with one replication server, nobody has a CSN (simulates) very first
* connection.
*/
@Test
public void testNullCSNBoth() throws Exception
{
String testCase = "testNullCSNBoth";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState();
ServerState aState = newServerState();
Map<Integer, ReplicationServerInfo> rsInfos =
newRSInfos(newRSInfo(11, WINNER, aState, 0, 1));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte)1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(), entry(11, NOTE_BEST_RS.ordinal()));
}
private Map<Integer, ReplicationServerInfo> newRSInfos(
ReplicationServerInfo... rsInfos)
{
Map<Integer, ReplicationServerInfo> results = new HashMap<>();
for (ReplicationServerInfo rsInfo : rsInfos)
{
results.put(rsInfo.getServerId(), rsInfo);
}
return results;
}
private ReplicationServerInfo newRSInfo(int serverId, String serverURL,
ServerState state, long genId, int groupId)
{
return ReplicationServerInfo.newInstance(new ReplServerStartMsg(serverId,
serverURL, null, 0, state, genId, false, (byte) groupId, 0));
}
/**
* Test with one replication server, only replication server has a non null
* CSN for ds server id.
*/
@Test
public void testNullCSNDS() throws Exception
{
String testCase = "testNullCSNDS";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState();
ServerState aState = newServerState(new CSN(0, 0, myId1));
Map<Integer, ReplicationServerInfo> rsInfos =
newRSInfos(newRSInfo(11, WINNER, aState, 0, 1));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte)1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(), entry(11, NOTE_BEST_RS.ordinal()));
}
/**
* Test with one replication server, only ds server has a non null CSN for ds
* server id but rs has a null one.
*/
@Test
public void testNullCSNRS() throws Exception
{
String testCase = "testNullCSNRS";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState(new CSN(1, 0, myId1));
ServerState aState = newServerState();
Map<Integer, ReplicationServerInfo> rsInfos =
newRSInfos(newRSInfo(11, WINNER, aState, 0, 1));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte)1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(), entry(11, NOTE_BEST_RS.ordinal()));
}
/**
* Test with one replication server, up to date.
*/
@Test
public void test1ServerUp() throws Exception
{
String testCase = "test1ServerUp";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState(new CSN(1, 0, myId1));
ServerState aState = newServerState(new CSN(1, 0, myId1));
Map<Integer, ReplicationServerInfo> rsInfos =
newRSInfos(newRSInfo(11, WINNER, aState, 0, 1));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte)1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(), entry(11, NOTE_BEST_RS.ordinal()));
}
/**
* Test with 2 replication servers, up to date.
*/
@Test
public void test2ServersUp() throws Exception
{
String testCase = "test2ServersUp";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState(new CSN(1, 0, myId1));
ServerState aState1 = newServerState(new CSN(1, 0, myId1));
ServerState aState2 = newServerState(new CSN(2, 0, myId1));
Map<Integer, ReplicationServerInfo> rsInfos = newRSInfos(
newRSInfo(11, LOOSER1, aState1, 0, 1),
newRSInfo(12, WINNER, aState2, 0, 1));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte)1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(),
entry(11, NOTE_RS_LATER_THAN_ANOTHER_RS_MORE_UP_TO_DATE_THAN_LOCAL_DS.ordinal()),
entry(12, NOTE_BEST_RS.ordinal()));
}
/**
* Test with 2 replication servers, up to date, but 2 different group ids.
*/
@Test
public void testDiffGroup2ServersUp() throws Exception
{
String testCase = "testDiffGroup2ServersUp";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState(new CSN(1, 0, myId1));
ServerState aState1 = newServerState(new CSN(1, 0, myId1));
ServerState aState2 = newServerState(new CSN(2, 0, myId1));
Map<Integer, ReplicationServerInfo> rsInfos = newRSInfos(
// This server has less changes than the other one but it has the same
// group id as us so he should be the winner
newRSInfo(11, WINNER, aState1, 0, 1),
newRSInfo(12, LOOSER1, aState2, 0, 2));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte)1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(),
entry(11, NOTE_BEST_RS.ordinal()),
entry(12, NOTE_RS_HAS_DIFFERENT_GROUP_ID_THAN_DS.ordinal()));
}
private void containsOnly(final Map<Integer, LocalizableMessage> evaluations, MapEntry... entries)
{
final List<MapEntry> notFound = newArrayList(entries);
for (Iterator<MapEntry> iter = notFound.iterator(); iter.hasNext();)
{
final MapEntry entry = iter.next();
final LocalizableMessage reason = evaluations.get(entry.key);
if (reason != null && reason.ordinal()==(Integer)entry.value)
{
iter.remove();
}
}
if (!notFound.isEmpty())
{
final StringBuilder sb = new StringBuilder("expecting ordinals:\n");
sb.append(" <").append(getOrdinal(evaluations)).append(">\n");
sb.append(" to contain:\n");
sb.append(" <").append(Arrays.asList(entries)).append(">\n");
sb.append(" but could not find:\n");
sb.append(" <").append(notFound).append(">");
throw new AssertionError(sb.toString());
}
Assertions.assertThat(evaluations).hasSize(entries.length);
}
/** Contains ordinal for each message. */
private Map<Integer, Integer> getOrdinal(Map<Integer, LocalizableMessage> evaluations)
{
final Map<Integer, Integer> result = new LinkedHashMap<>();
for (Entry<Integer, LocalizableMessage> entry : evaluations.entrySet())
{
result.put(entry.getKey(), entry.getValue().ordinal());
}
return result;
}
/**
* Test with 2 replication servers, none of them from our group id.
*/
@Test
public void testNotOurGroup() throws Exception
{
String testCase = "testNotOurGroup";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState(new CSN(1, 0, myId1));
ServerState aState1 = newServerState(new CSN(1, 0, myId1));
ServerState aState2 = newServerState(new CSN(2, 0, myId1));
Map<Integer, ReplicationServerInfo> rsInfos = newRSInfos(
newRSInfo(11, LOOSER1, aState1, 0, 2),
newRSInfo(12, WINNER, aState2, 0, 2));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte)1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(),
entry(11, NOTE_RS_LATER_THAN_ANOTHER_RS_MORE_UP_TO_DATE_THAN_LOCAL_DS.ordinal()),
entry(12, NOTE_BEST_RS.ordinal()));
}
/**
* Test with 3 replication servers, up to date.
*/
@Test
public void test3ServersUp() throws Exception
{
String testCase = "test3ServersUp";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState(new CSN(1, 0, myId1));
ServerState aState1 = newServerState(new CSN(1, 0, myId1));
ServerState aState2 = newServerState(new CSN(2, 0, myId1));
ServerState aState3 = newServerState(new CSN(3, 0, myId1));
Map<Integer, ReplicationServerInfo> rsInfos = newRSInfos(
newRSInfo(11, LOOSER1, aState1, 0, 1),
newRSInfo(12, LOOSER2, aState2, 0, 1),
newRSInfo(13, WINNER, aState3, 0, 1));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte)1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(),
entry(11, NOTE_RS_LATER_THAN_ANOTHER_RS_MORE_UP_TO_DATE_THAN_LOCAL_DS.ordinal()),
entry(12, NOTE_RS_LATER_THAN_ANOTHER_RS_MORE_UP_TO_DATE_THAN_LOCAL_DS.ordinal()),
entry(13, NOTE_BEST_RS.ordinal()));
}
/**
* Test with 3 replication servers: 2 are up to date with the directory
* server, 1 is more up to date than the directory server.
*/
@Test
public void test2ServersUpToDateAnd1EvenMoreUpToDate() throws Exception
{
String testCase = "test3ServersUp";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState(new CSN(1, 0, myId1));
ServerState aState1 = newServerState(new CSN(1, 0, myId1));
ServerState aState2 = newServerState(new CSN(1, 0, myId1));
ServerState aState3 = newServerState(new CSN(2, 0, myId1));
Map<Integer, ReplicationServerInfo> rsInfos = newRSInfos(
newRSInfo(11, LOOSER1, aState1, 0, 1),
newRSInfo(12, LOOSER2, aState2, 0, 1),
newRSInfo(13, WINNER, aState3, 0, 1));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte)1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(),
entry(11, NOTE_RS_LATER_THAN_ANOTHER_RS_MORE_UP_TO_DATE_THAN_LOCAL_DS.ordinal()),
entry(12, NOTE_RS_LATER_THAN_ANOTHER_RS_MORE_UP_TO_DATE_THAN_LOCAL_DS.ordinal()),
entry(13, NOTE_BEST_RS.ordinal()));
}
/**
* Test with 3 replication servers, up to date, but 2 different group ids.
*/
@Test
public void testDiffGroup3ServersUp() throws Exception
{
String testCase = "testDiffGroup3ServersUp";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState(new CSN(1, 0, myId1));
ServerState aState1 = newServerState(new CSN(1, 0, myId1));
ServerState aState2 = newServerState(new CSN(2, 0, myId1));
ServerState aState3 = newServerState(new CSN(3, 0, myId1));
Map<Integer, ReplicationServerInfo> rsInfos = newRSInfos(
newRSInfo(11, LOOSER1, aState1, 0, 1),
newRSInfo(12, LOOSER2, aState2, 0, 2),
// This server has less changes than looser2 but it has the same
// group id as us so he should be the winner
newRSInfo(13, WINNER, aState3, 0, 1));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte)1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(),
entry(11, NOTE_RS_LATER_THAN_ANOTHER_RS_MORE_UP_TO_DATE_THAN_LOCAL_DS.ordinal()),
entry(12, NOTE_RS_HAS_DIFFERENT_GROUP_ID_THAN_DS.ordinal()),
entry(13, NOTE_BEST_RS.ordinal()));
}
/**
* Test with one replication server, late.
*/
@Test
public void test1ServerLate() throws Exception
{
String testCase = "test1ServerLate";
debugInfo("Starting " + testCase);
ServerState mySt = newServerState(new CSN(1, 0, myId1));
ServerState aState = newServerState(new CSN(0, 0, myId1));
Map<Integer, ReplicationServerInfo> rsInfos =
newRSInfos(newRSInfo(11, WINNER, aState, 0, 1));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte) 1, 0);
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(), entry(11, NOTE_BEST_RS.ordinal()));
}
@DataProvider(name = "create3ServersData")
public Object[][] create3ServersData() {
return new Object[][] {
// first RS is up to date, the others are late none is local
{ 4, 2, 3, false,
1, 2, 3, false,
2, 3, 4, false},
// test that the local RS is chosen first when all up to date
{ 4, 2, 3, true,
4, 2, 3, false,
4, 2, 3, false},
// test that the local ServerID is more important than the others
{ 4, 0, 0, false,
2, 100, 100, false,
1, 100, 100, false},
// test that a remote RS is chosen first when up to date when the local
// one is late
{ 4, 1, 1, false,
3, 1, 1, true,
3, 1, 1, false},
// test that the local RS is not chosen first when it is missing
// local changes
{ 4, 1, 1, false,
3, 2, 3, false,
1, 1, 1, true},
// test that a RS which is more up to date than the DS is chosen
{ 5, 1, 1, false,
2, 0, 0, false,
1, 1, 1, false},
// test that a RS which is more up to date than the DS is chosen even
// is some RS with the same last change from the DS
{ 5, 1, 1, false,
4, 0, 0, false,
4, 1, 1, false},
// test that the local RS is chosen first when it is missing
// the same local changes as the other RSs
{ 3, 1, 1, true,
2, 1, 1, false,
3, 1, 1, false},
};
}
/**
* Test with 3 replication servers (see data provider).
*/
@Test(dataProvider = "create3ServersData")
public void test3Servers(
long winnerT1, long winnerT2, long winnerT3, boolean winnerIsLocal,
long looser1T1, long looser1T2, long looser1T3, boolean looser1IsLocal,
long looser2T1, long looser2T2, long looser2T3, boolean looser2IsLocal)
throws Exception
{
String testCase = "test3ServersLate";
debugInfo("Starting " + testCase);
// definitions for server names
final String WINNER = "localhost:123";
final String LOOSER1 = "localhost:456";
final String LOOSER2 = "localhost:789";
// Create my state
ServerState mySt = newServerState(
new CSN(4, 0, myId1),
new CSN(2, 0, myId2), // myId2 should not be used inside algo (same for the other ServerStates)
new CSN(3, 0, myId3)); // myId3 should not be used inside algo (same for the other ServerStates)
// State for server 1
ServerState aState1 = newServerState(
new CSN(looser1T1, 0, myId1),
new CSN(looser1T2, 0, myId2),
new CSN(looser1T3, 0, myId3));
if (looser1IsLocal)
{
ReplicationServer.onlyForTestsAddlocalReplicationServer(LOOSER1);
}
// State for server 2
ServerState aState2 = newServerState(
new CSN(winnerT1, 0, myId1),
new CSN(winnerT2, 0, myId2),
new CSN(winnerT3, 0, myId3));
if (winnerIsLocal)
{
ReplicationServer.onlyForTestsAddlocalReplicationServer(WINNER);
}
// State for server 3
ServerState aState3 = newServerState(
new CSN(looser2T1, 0, myId1),
new CSN(looser2T2, 0, myId2),
new CSN(looser2T3, 0, myId3));
if (looser2IsLocal)
{
ReplicationServer.onlyForTestsAddlocalReplicationServer(LOOSER2);
}
Map<Integer, ReplicationServerInfo> rsInfos = newRSInfos(
newRSInfo(11, LOOSER1, aState1, 0, 1),
newRSInfo(12, WINNER, aState2, 0, 1),
newRSInfo(13, LOOSER2, aState3, 0, 1));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte) 1, 0);
ReplicationServer.onlyForTestsClearLocalReplicationServerList();
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
final boolean winnerIsLatestRS = winnerT1 > 4 && looser1T1 == 4 && looser2T1 == 4;
containsOnly(evals.getEvaluations(),
entry(11, getEval1(winnerIsLocal, looser1IsLocal, winnerIsLatestRS)),
entry(12, NOTE_BEST_RS.ordinal()),
entry(13, getEval1(winnerIsLocal, looser2IsLocal, winnerIsLatestRS)));
}
private Integer getEval1(boolean winnerIsLocal, boolean looserIsLocal, boolean winnerIsLatestRS)
{
if (winnerIsLocal && !looserIsLocal)
{
return NOTE_RS_ON_DIFFERENT_VM_THAN_DS.ordinal();
}
else if (winnerIsLatestRS)
{
return NOTE_RS_LATER_THAN_ANOTHER_RS_MORE_UP_TO_DATE_THAN_LOCAL_DS.ordinal();
}
return NOTE_RS_LATER_THAN_LOCAL_DS.ordinal();
}
@DataProvider(name = "test3ServersMoreCriteria")
public Object[][] create3ServersMoreCriteriaData() {
return new Object[][] {
// Test that a RS is chosen if its group is ok whereas the other parameters
// are not ok
{ 1L, 1L, 1, false,
4L, 0L, 2, false,
4L, 0L, 3, false},
// Test that a RS is chosen if its genid is ok (all RS with same group)
// and state is not ok
{ 1L, 0L, 1, false,
4L, 1L, 1, false,
4L, 2L, 1, false},
// Test that a RS is chosen if all servers have wrong genid and group id
// but it is local
{ 1L, 1L, 2, true,
4L, 2L, 3, false,
5L, 3L, 4, false}
};
}
/**
* Test with 3 replication servers (see data provider).
*/
@Test(dataProvider = "test3ServersMoreCriteria")
public void test3ServersMoreCriteria(
long winnerT1, long winnerGenId, int winnerGroupId, boolean winnerIsLocal,
long looser1T1, long looser1GenId, int looser1GroupId, boolean looser1IsLocal,
long looser2T1, long looser2GenId, int looser2GroupId, boolean looser2IsLocal)
throws Exception
{
String testCase = "test3ServersMoreCriteria";
debugInfo("Starting " + testCase);
// definitions for server names
final String WINNER = "localhost:123";
final String LOOSER1 = "localhost:456";
final String LOOSER2 = "localhost:789";
// Create my state
ServerState mySt = newServerState(new CSN(4, 0, myId1));
// State for server 1
ServerState aState1 = newServerState(new CSN(looser1T1, 0, myId1));
if (looser1IsLocal)
{
ReplicationServer.onlyForTestsAddlocalReplicationServer(LOOSER1);
}
// State for server 2
ServerState aState2 = newServerState(new CSN(winnerT1, 0, myId1));
if (winnerIsLocal)
{
ReplicationServer.onlyForTestsAddlocalReplicationServer(WINNER);
}
// State for server 3
ServerState aState3 = newServerState(new CSN(looser2T1, 0, myId1));
if (looser2IsLocal)
{
ReplicationServer.onlyForTestsAddlocalReplicationServer(LOOSER2);
}
Map<Integer, ReplicationServerInfo> rsInfos = newRSInfos(
newRSInfo(11, LOOSER1, aState1, looser1GenId, looser1GroupId),
newRSInfo(12, WINNER, aState2, winnerGenId, winnerGroupId),
newRSInfo(13, LOOSER2, aState3, looser2GenId, looser2GroupId));
RSEvaluations evals =
computeBestReplicationServer(true, -1, mySt, rsInfos, myId1, (byte) 1, 0);
ReplicationServer.onlyForTestsClearLocalReplicationServerList();
assertEquals(evals.getBestRS().getServerURL(), WINNER,
"Wrong best replication server.");
containsOnly(evals.getEvaluations(),
entry(11, getEval2(winnerGroupId == looser1GroupId, winnerIsLocal, looser1IsLocal)),
entry(12, NOTE_BEST_RS.ordinal()),
entry(13, getEval2(winnerGroupId == looser2GroupId, winnerIsLocal, looser2IsLocal)));
}
private Integer getEval2(boolean sameGroupId, boolean winnerIsLocal, boolean looserIsLocal)
{
if (winnerIsLocal && !looserIsLocal)
{
return NOTE_RS_ON_DIFFERENT_VM_THAN_DS.ordinal();
}
else if (!sameGroupId)
{
return NOTE_RS_HAS_DIFFERENT_GROUP_ID_THAN_DS.ordinal();
}
return NOTE_RS_HAS_DIFFERENT_GENERATION_ID_THAN_DS.ordinal();
}
@SuppressWarnings("unchecked")
@DataProvider(name = "testComputeBestServerForWeightProvider")
public Object[][] testComputeBestServerForWeightProvider() {
Object[][] testData = new Object[24][];
int idx = 0;
Map<Integer, ReplicationServerInfo> rsInfos = null;
/************************
* First connection tests
************************/
/**
* 1 RS, no connected DSs
* Expected winner: the RS
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "AwinnerHost:123", 0L, (byte)1, 1),
EMPTY_SET);
testData[idx++] = new Object[] {
rsInfos,
-1, // current RS id
-1, // local DS id
"AwinnerHost:123", // winner url
};
/**
* 2 RSs with TL=0.5, no connected DSs
* Excepted winner: first in the list
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "BwinnerHost:123", 0L, (byte)1, 1),
EMPTY_SET);
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 1),
EMPTY_SET);
testData[idx++] = new Object[] {
rsInfos,
-1, // current RS id
-1, // local DS id
"BwinnerHost:123", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.5 - CL=1.0 - DS=1 ; RS2: TL=0.5 - CL=0 - DS=0
* Excepted winner: R2 (still no connected DS)
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 1),
newHashSet(1));
put(rsInfos,
new RSInfo(12, "CwinnerHost:456", 0L, (byte)1, 1),
EMPTY_SET);
testData[idx++] = new Object[] {
rsInfos,
-1, // current RS id
-1, // local DS id
"CwinnerHost:456", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.5 - CL=0.5 - DS=1 ; RS2: TL=0.5 - CL=0.5 - DS=1
* Excepted winner: first in the list as both RSs reached TL
* and have same weight
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "DwinnerHost:123", 0L, (byte)1, 1),
newHashSet(1));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 1),
newHashSet(101));
testData[idx++] = new Object[] {
rsInfos,
-1, // current RS id
-1, // local DS id
"DwinnerHost:123", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.5 - CL=2/3 - DS=2 ; RS2: TL=0.5 - CL=1/3 - DS=1
* Excepted winner: RS2 -> 2 DSs on each RS
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 1),
newHashSet(1, 2));
put(rsInfos,
new RSInfo(12, "EwinnerHost:456", 0L, (byte)1, 1),
newHashSet(101));
testData[idx++] = new Object[] {
rsInfos,
-1, // current RS id
-1, // local DS id
"EwinnerHost:456", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=1/3 - CL=0.5 - DS=1 ; RS2: TL=2/3 - CL=0.5 - DS=1
* Excepted winner: RS2 -> go to perfect load balance
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 1),
newHashSet(1));
put(rsInfos,
new RSInfo(12, "FwinnerHost:456", 0L, (byte)1, 2),
newHashSet(101));
testData[idx++] = new Object[] {
rsInfos,
-1, // current RS id
-1, // local DS id
"FwinnerHost:456", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=1/3 - CL=1/3 - DS=1 ; RS2: TL=2/3 - CL=2/3 - DS=2
* Excepted winner: RS2 -> already load balanced so choose server with the
* highest weight
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 1),
newHashSet(1));
put(rsInfos,
new RSInfo(12, "GwinnerHost:456", 0L, (byte)1, 2),
newHashSet(101, 102));
testData[idx++] = new Object[] {
rsInfos,
-1, // current RS id
-1, // local DS id
"GwinnerHost:456", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=1/3 - CL=1/3 - DS=2 ; RS2: TL=2/3 - CL=2/3 - DS=4
* Excepted winner: RS2 -> already load balanced so choose server with the
* highest weight
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 1),
newHashSet(1, 2));
put(rsInfos,
new RSInfo(12, "HwinnerHost:456", 0L, (byte)1, 2),
newHashSet(101, 102, 103, 104));
testData[idx++] = new Object[] {
rsInfos,
-1, // current RS id
-1, // local DS id
"HwinnerHost:456", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=1/6 - CL=1/6 - DS=1 ; RS2: TL=2/6 - CL=2/6 - DS=2 ; RS3: TL=3/6 - CL=3/6 - DS=3
* Excepted winner: RS3 -> already load balanced so choose server with the
* highest weight
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 1),
newHashSet(1));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 2),
newHashSet(101, 102));
put(rsInfos,
new RSInfo(13, "IwinnerHost:789", 0L, (byte)1, 3),
newHashSet(201, 202, 203));
testData[idx++] = new Object[] {
rsInfos,
-1, // current RS id
-1, // local DS id
"IwinnerHost:789", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=5/10 - CL=3/9 - DS=3 ; RS2: TL=3/10 - CL=5/9 - DS=5 ; RS3: TL=2/10 - CL=1/9 - DS=1
* Excepted winner: RS1 -> misses more DSs than RS3
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "JwinnerHost:123", 0L, (byte)1, 5),
newHashSet(1, 2, 3));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 3),
newHashSet(101, 102, 103, 104, 105));
put(rsInfos,
new RSInfo(13, "looserHost:789", 0L, (byte)1, 2),
newHashSet(201));
testData[idx++] = new Object[] {
rsInfos,
-1, // current RS id
-1, // local DS id
"JwinnerHost:123", // winner url
};
/*************************
* Already connected tests
*************************/
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.5 - CL=0.5 - DS=1 ; RS2: TL=0.5 - CL=0.5 - DS=1
* Excepted winner: RS2 (stay connected to it as load correctly spread)
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 1),
newHashSet(1));
put(rsInfos,
new RSInfo(12, "KwinnerHost:456", 0L, (byte)1, 1),
newHashSet(101));
testData[idx++] = new Object[] {
rsInfos,
12, // current RS id
101, // local DS id
"KwinnerHost:456", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.5 - CL=1.0 - DS=2 ; RS2: TL=0.5 - CL=0.0 - DS=0
* Excepted winner: RS2 (one must disconnect from RS1)
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 1),
newHashSet(1, 2));
put(rsInfos,
new RSInfo(12, "LwinnerHost:456", 0L, (byte)1, 1),
EMPTY_SET);
testData[idx++] = new Object[] {
rsInfos,
11, // current RS id
1, // local DS id
null, // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.5 - CL=1.0 - DS=2 ; RS2: TL=0.5 - CL=0.0 - DS=0
* Excepted winner: RS1 (one server must disconnect from RS1 but it is the
* one with the lowest id so not DS with server id 2)
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "MwinnerHost:123", 0L, (byte)1, 1),
newHashSet(1, 2));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 1),
EMPTY_SET);
testData[idx++] = new Object[] {
rsInfos,
11, // current RS id
2, // local DS id
"MwinnerHost:123", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.3 - CL=0.3 - DS=6 ; RS2: TL=0.4 - CL=0.4 - DS=8 ;
* RS3: TL=0.1 - CL=0.1 - DS=2 ; RS4: TL=0.2 - CL=0.2 - DS=4
* Excepted winner: RS2 no change as load correctly spread
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 3),
newHashSet(1, 2, 3, 4, 5, 6));
put(rsInfos,
new RSInfo(12, "NwinnerHost:456", 0L, (byte)1, 4),
newHashSet(101, 102, 103, 104, 105, 106, 107, 108));
put(rsInfos,
new RSInfo(13, "looserHost:789", 0L, (byte)1, 1),
newHashSet(201, 202));
put(rsInfos,
new RSInfo(14, "looserHost:1011", 0L, (byte)1, 2),
newHashSet(301, 302, 303, 304));
testData[idx++] = new Object[] {
rsInfos,
12, // current RS id
101, // local DS id
"NwinnerHost:456", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.3 - CL=0.2 - DS=4 ; RS2: TL=0.4 - CL=0.4 - DS=8 ;
* RS3: TL=0.1 - CL=0.1 - DS=2 ; RS4: TL=0.2 - CL=0.3 - DS=6
* Excepted winner: RS2: no change load ok on current server and there is the
* possibility to arrange load for other servers with disconnection from
* 2 DSs from RS4 and reconnect them to RS1 (we moved these 2 servers from
* previous test where the loads were ok)
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 3),
newHashSet(1, 2, 3, 4));
put(rsInfos,
new RSInfo(12, "OwinnerHost:456", 0L, (byte)1, 4),
newHashSet(101, 102, 103, 104, 105, 106, 107, 108));
put(rsInfos,
new RSInfo(13, "looserHost:789", 0L, (byte)1, 1),
newHashSet(201, 202));
put(rsInfos,
new RSInfo(14, "looserHost:1011", 0L, (byte)1, 2),
newHashSet(301, 302, 303, 304, 305, 306));
testData[idx++] = new Object[] {
rsInfos,
12, // current RS id
101, // local DS id
"OwinnerHost:456", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.3 - CL=0.2 - DS=4 ; RS2: TL=0.4 - CL=0.4 - DS=8 ;
* RS3: TL=0.1 - CL=0.1 - DS=2 ; RS4: TL=0.2 - CL=0.3 - DS=6
* Excepted winner: RS4 : 2 DSs should go away from RS4 and server id 302
* is one of the two lowest ids connected to RS4
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "PwinnerHost:123", 0L, (byte)1, 3),
newHashSet(1, 2, 3, 4));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 4),
newHashSet(101, 102, 103, 104, 105, 106, 107, 108));
put(rsInfos,
new RSInfo(13, "looserHost:789", 0L, (byte)1, 1),
newHashSet(201, 202));
put(rsInfos,
new RSInfo(14, "looserHost:1011", 0L, (byte)1, 2),
newHashSet(306, 305, 304, 303, 302, 301));
testData[idx++] = new Object[] {
rsInfos,
14, // current RS id
302, // local DS id
null, // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.3 - CL=0.2 - DS=4 ; RS2: TL=0.4 - CL=0.4 - DS=8 ;
* RS3: TL=0.1 - CL=0.1 - DS=2 ; RS4: TL=0.2 - CL=0.3 - DS=6
* Excepted winner: RS1 : 2 DSs should go away from RS4 but server id 303
* is not one of the two lowest ids connected to RS4
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 3),
newHashSet(1, 2, 3, 4));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 4),
newHashSet(101, 102, 103, 104, 105, 106, 107, 108));
put(rsInfos,
new RSInfo(13, "looserHost:789", 0L, (byte)1, 1),
newHashSet(201, 202));
put(rsInfos,
new RSInfo(14, "QwinnerHost:1011", 0L, (byte)1, 2),
newHashSet(306, 305, 304, 303, 302, 301));
testData[idx++] = new Object[] {
rsInfos,
14, // current RS id
303, // local DS id
"QwinnerHost:1011", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.3 - CL=0.2 - DS=4 ; RS2: TL=0.4 - CL=0.65 - DS=13 ;
* RS3: TL=0.1 - CL=0.1 - DS=2 ; RS4: TL=0.2 - CL=0.05 - DS=1
* Excepted winner: RS2: no change load ok on current server and there is the
* possibility to arrange load for other servers with disconnection from
* 2 DSs from RS4 and reconnect them to RS1 (we moved these 2 servers from
* previous test where the loads were ok)
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte) 1, 3),
newHashSet(1, 2, 3, 4));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 4),
newHashSet(113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101));
put(rsInfos,
new RSInfo(13, "looserHost:789", 0L, (byte)1, 1),
newHashSet(201, 202));
put(rsInfos,
new RSInfo(14, "looserHost:1011", 0L, (byte)1, 2),
newHashSet(301));
testData[idx++] = new Object[] {
rsInfos,
12, // current RS id
105, // local DS id
null, // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.5 - CL=2/3 - DS=2 ; RS2: TL=0.5 - CL=1/3 - DS=1
* Excepted winner: RS1. Local server should stay connected to current one
* as the balance cannot be done. We already have the nearest possible
* balance to the load goals: disconnection would cause a yoyo effect and
* the local server would not stop going and coming back to/from the other
* RS.
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "RwinnerHost:123", 0L, (byte)1, 1),
newHashSet(1, 2));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 1),
newHashSet(3));
testData[idx++] = new Object[] {
rsInfos,
11, // current RS id
1, // local DS id
"RwinnerHost:123", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=0.5 - CL=2/3 - DS=2 ; RS2: TL=0.5 - CL=1/3 - DS=1
* Excepted winner: RS1. Local server should stay connected to current one
* as the balance cannot be done. We already have the nearest possible
* balance to the load goals: disconnection would cause a yoyo effect and
* the local server would not stop going and coming back to/from the other
* RS.
* Note: Same test as before, but not with the lowest local DS server id
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "SwinnerHost:123", 0L, (byte)1, 1),
newHashSet(1, 2));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 1),
newHashSet(3));
testData[idx++] = new Object[] {
rsInfos,
11, // current RS id
2, // local DS id
"SwinnerHost:123", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=1/3 - CL=2/4 - DS=2 ; RS2: TL=1/3 - CL=1/4 - DS=1 ; RS3: TL=1/3 - CL=1/4 - DS=1
* Excepted winner: RS1. Local server should stay connected to current one
* as the balance cannot be done. We already have the nearest possible
* balance to the load goals: disconnection would cause a yoyo effect and
* the local server would not stop going and coming back between RSs.
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "TwinnerHost:123", 0L, (byte)1, 1),
newHashSet(1, 2));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 1),
newHashSet(3));
put(rsInfos,
new RSInfo(13, "looserHost:789", 0L, (byte)1, 1),
newHashSet(4));
testData[idx++] = new Object[] {
rsInfos,
11, // current RS id
1, // local DS id
"TwinnerHost:123", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=1/3 - CL=3/7 - DS=3 ; RS2: TL=1/3 - CL=2/7 - DS=2 ; RS3: TL=1/3 - CL=2/7 - DS=2
* Excepted winner: RS1. Local server should stay connected to current one
* as the balance cannot be done. We already have the nearest possible
* balance to the load goals: disconnection would cause a yoyo effect and
* the local server would not stop going and coming back between RSs.
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "UwinnerHost:123", 0L, (byte)1, 1),
newHashSet(1, 2, 3));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 1),
newHashSet(4, 5));
put(rsInfos,
new RSInfo(13, "looserHost:789", 0L, (byte)1, 1),
newHashSet(6, 7));
testData[idx++] = new Object[] {
rsInfos,
11, // current RS id
1, // local DS id
"UwinnerHost:123", // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=1/3 - CL=2/3 - DS=2 ; RS2: TL=1/3 - CL=1/3 - DS=1 ; RS3: TL=1/3 - CL=0 - DS=0
* Excepted winner: RS3. Local server should disconnect for reconnection to
* RS3
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "looserHost:123", 0L, (byte)1, 1),
newHashSet(1, 2));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 1),
newHashSet(3));
put(rsInfos,
new RSInfo(13, "VwinnerHost:789", 0L, (byte)1, 1),
EMPTY_SET);
testData[idx++] = new Object[] {
rsInfos,
11, // current RS id
1, // local DS id
null, // winner url
};
/**
* TL = target load
* CL = current load
* DS = connected DSs number
* RS1: TL=1/3 - CL=2/3 - DS=2 ; RS2: TL=1/3 - CL=1/3 - DS=1 ; RS3: TL=1/3 - CL=0 - DS=0
* Excepted winner: RS3. Local server (2) should stay connected while
* DS server id 1 should disconnect for reconnection to RS3
*/
rsInfos = new HashMap<>();
put(rsInfos,
new RSInfo(11, "WwinnerHost:123", 0L, (byte)1, 1),
newHashSet(1, 2));
put(rsInfos,
new RSInfo(12, "looserHost:456", 0L, (byte)1, 1),
newHashSet(3));
put(rsInfos,
new RSInfo(13, "looserHost:789", 0L, (byte)1, 1),
EMPTY_SET);
testData[idx++] = new Object[] {
rsInfos,
11, // current RS id
2, // local DS id
"WwinnerHost:123", // winner url
};
return testData;
}
private void put(Map<Integer, ReplicationServerInfo> rsInfos, RSInfo rsInfo,
Set<Integer> connectedDSs)
{
ReplicationServerInfo info = new ReplicationServerInfo(rsInfo, connectedDSs);
rsInfos.put(info.getServerId(), info);
}
/**
* Test the method that chooses the best RS using the RS weights.
*/
@Test(dataProvider = "testComputeBestServerForWeightProvider")
public void testComputeBestServerForWeight(
Map<Integer, ReplicationServerInfo> servers, int currentRsServerId,
int localServerId, String winnerUrl)
throws Exception
{
String testCase = "testComputeBestServerForWeight";
debugInfo("Starting " + testCase);
final RSEvaluations evals = new RSEvaluations(localServerId, servers);
computeBestServerForWeight(evals, currentRsServerId, localServerId);
final ReplicationServerInfo bestServer = evals.getBestRS();
if (winnerUrl == null)
{
// We expect null
String url = null;
if (bestServer != null)
{
url = bestServer.getServerURL();
}
assertNull(bestServer, "The best server should be null but is: " + url);
}
else
{
assertNotNull(bestServer, "The best server should not be null");
assertEquals(bestServer.getServerURL(),
winnerUrl, "Wrong best replication server: " + bestServer.getServerURL());
}
}
}