package org.scale7.cassandra.pelops.pool;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import com.google.common.collect.Sets;
/**
* Tests the {@link LeastLoadedNodeSelectionStrategy} class.
*/
public class LeastLoadedNodeSelectionStrategyUnitTest {
/**
* Test to verify that if all nodes are are suspended that null is returned.
*/
@Test
public void testAllNodesSuspended() {
Set<String> nodeAddresses = new HashSet<String>(Arrays.asList("node1", "node2", "node3"));
CommonsBackedPool pool = Mockito.mock(CommonsBackedPool.class);
// setup each pooled node to report that it's suspended
for (String nodeAddress : nodeAddresses) {
mockPoolMethods(pool, nodeAddress, new PooledNode(pool, nodeAddress) {
@Override
public boolean isSuspended() {
return true;
}
});
}
LeastLoadedNodeSelectionStrategy strategy = new LeastLoadedNodeSelectionStrategy();
PooledNode node = strategy.select(pool, nodeAddresses, null);
assertNull("No nodes should have been returned", node);
}
/**
* Test to verify that if all but one of the nodes are suspended that that node is returned.
*/
@Test
public void testOnlyOneCandidateNode() {
Set<String> nodeAddresses = new HashSet<String>(Arrays.asList("node1", "node2", "node3"));
CommonsBackedPool pool = Mockito.mock(CommonsBackedPool.class);
// setup each pooled node to report that it's suspended
for (String nodeAddress : nodeAddresses) {
mockPoolMethods(pool, nodeAddress, new PooledNode(pool, nodeAddress) {
@Override
public boolean isSuspended() {
return true;
}
});
}
// setup one node to be good
final String goodNodeAddress = "node4";
nodeAddresses.add(goodNodeAddress);
mockPoolMethods(pool, goodNodeAddress, new PooledNode(pool, goodNodeAddress) {
@Override
public boolean isSuspended() {
return false;
}
@Override
public int getNumActive() {
return 1;
}
@Override
public int getConnectionsCorrupted() {
return 0;
}
});
LeastLoadedNodeSelectionStrategy strategy = new LeastLoadedNodeSelectionStrategy();
PooledNode node = strategy.select(pool, nodeAddresses, null);
assertNotNull("No nodes were returned from the pool", node);
assertEquals("Wrong node returned from the pool", goodNodeAddress, node.getAddress());
}
/**
* Test to verify that the node with the least active connections is selected.
*/
@Test
public void testLeastLoadedNodeSelected() {
String leastLoadedNodeAddress = "node1";
List<String> nodeAddresses = Arrays.asList(leastLoadedNodeAddress, "node2", "node3", "node4", "node5");
CommonsBackedPool pool = Mockito.mock(CommonsBackedPool.class);
// setup each pooled node to report it's number of active connections
for (int i = 0; i < nodeAddresses.size(); i++) {
final int numActive = i;
mockPoolMethods(pool, nodeAddresses.get(i), new PooledNode(pool, nodeAddresses.get(i)) {
@Override
public boolean isSuspended() {
return false;
}
@Override
public int getNumActive() {
return numActive;
}
@Override
public int getConnectionsCorrupted() {
return 0;
}
});
}
LeastLoadedNodeSelectionStrategy strategy = new LeastLoadedNodeSelectionStrategy();
PooledNode node = strategy.select(pool, new HashSet<String>(nodeAddresses), null);
assertNotNull("No nodes were returned from the pool", node);
assertEquals("Wrong node returned from the pool", leastLoadedNodeAddress, node.getAddress());
}
/**
* Test to verify that when all nodes have an equal number of active and borrowed nodes then the node with the least corrupted
* connections is selected.
*/
@Test
public void testNodesEqualThenLeastCorruptedSelected() {
String leastLoadedNodeAddress = "node5";
final List<String> nodeAddresses = Arrays.asList("node1", "node2", "node3", "node4", leastLoadedNodeAddress);
CommonsBackedPool pool = Mockito.mock(CommonsBackedPool.class);
// setup each pooled node to report it's number of active connections
for (int i = 0; i < nodeAddresses.size(); i++) {
final int numCorrupted = i;
mockPoolMethods(pool, nodeAddresses.get(i), new PooledNode(pool, nodeAddresses.get(i)) {
@Override
public boolean isSuspended() {
return false;
}
@Override
public int getNumActive() {
return 0;
}
@Override
public int getConnectionsBorrowedTotal() {
return 0;
}
@Override
public int getConnectionsCorrupted() {
return nodeAddresses.size() - numCorrupted;
}
});
}
LeastLoadedNodeSelectionStrategy strategy = new LeastLoadedNodeSelectionStrategy();
PooledNode node = strategy.select(pool, new HashSet<String>(nodeAddresses), null);
assertNotNull("No nodes were returned from the pool", node);
assertEquals("Wrong node returned from the pool", leastLoadedNodeAddress, node.getAddress());
}
/**
* Test to verify that when all nodes have an equal number of active and borrowed nodes then the node with the least corrupted
* connections is selected.
*/
@Test
public void testNodesEqualThenLeastBorrowedSelected() {
String leastLoadedNodeAddress = "node5";
final List<String> nodeAddresses = Arrays.asList("node1", "node2", "node3", "node4", leastLoadedNodeAddress);
CommonsBackedPool pool = Mockito.mock(CommonsBackedPool.class);
// setup each pooled node to report it's number of active connections
for (int i = 0; i < nodeAddresses.size(); i++) {
final int numCorrupted = i;
mockPoolMethods(pool, nodeAddresses.get(i), new PooledNode(pool, nodeAddresses.get(i)) {
@Override
public boolean isSuspended() {
return false;
}
@Override
public int getNumActive() {
return 0;
}
@Override
public int getConnectionsBorrowedTotal() {
return nodeAddresses.size() - numCorrupted;
}
@Override
public int getConnectionsCorrupted() {
return 0;
}
});
}
LeastLoadedNodeSelectionStrategy strategy = new LeastLoadedNodeSelectionStrategy();
PooledNode node = strategy.select(pool, new HashSet<String>(nodeAddresses), null);
assertNotNull("No nodes were returned from the pool", node);
assertEquals("Wrong node returned from the pool", leastLoadedNodeAddress, node.getAddress());
}
/**
* Test to verify that the node with the least active connections is skipped because of the notNodeHint.
*/
@Test
public void testAvoidNodesHint() {
String avoidNode = "node1";
String selectedNodeAddress = "node2";
List<String> nodeAddresses = Arrays.asList(avoidNode, selectedNodeAddress, "node3", "node4", "node5");
CommonsBackedPool pool = Mockito.mock(CommonsBackedPool.class);
// setup each pooled node to report it's number of active connections
for (int i = 0; i < nodeAddresses.size(); i++) {
final int numActive = i;
mockPoolMethods(pool, nodeAddresses.get(i), new PooledNode(pool, nodeAddresses.get(i)) {
@Override
public boolean isSuspended() {
return false;
}
@Override
public int getNumActive() {
return numActive;
}
@Override
public int getConnectionsCorrupted() {
return 0;
}
});
}
LeastLoadedNodeSelectionStrategy strategy = new LeastLoadedNodeSelectionStrategy();
PooledNode node = strategy.select(pool, new HashSet<String>(nodeAddresses), Sets.newHashSet(avoidNode));
assertNotNull("No nodes were returned from the pool", node);
assertEquals("Wrong node returned from the pool", selectedNodeAddress, node.getAddress());
}
/**
* Test to verify that the node with the least active connections is skipped because of the notNodeHint.
*/
@Test
public void testAvoidNodesHintMultiple() {
String avoidNode1 = "node1";
String avoidNode2 = "node2";
String selectedNodeAddress = "node3";
List<String> nodeAddresses = Arrays.asList(avoidNode1, avoidNode2, selectedNodeAddress, "node4", "node5");
CommonsBackedPool pool = Mockito.mock(CommonsBackedPool.class);
// setup each pooled node to report it's number of active connections
for (int i = 0; i < nodeAddresses.size(); i++) {
final int numActive = i;
mockPoolMethods(pool, nodeAddresses.get(i), new PooledNode(pool, nodeAddresses.get(i)) {
@Override
public boolean isSuspended() {
return false;
}
@Override
public int getNumActive() {
return numActive;
}
@Override
public int getConnectionsCorrupted() {
return 0;
}
});
}
LeastLoadedNodeSelectionStrategy strategy = new LeastLoadedNodeSelectionStrategy();
PooledNode node = strategy.select(pool, new HashSet<String>(nodeAddresses), Sets.newHashSet(avoidNode1, avoidNode2));
assertNotNull("No nodes were returned from the pool", node);
assertEquals("Wrong node returned from the pool", selectedNodeAddress, node.getAddress());
}
private void mockPoolMethods(CommonsBackedPool pool, final String nodeAddress, final PooledNode pooledNode) {
Mockito.when(pool.getPooledNode(nodeAddress)).thenAnswer(new Answer<PooledNode>() {
@Override
public PooledNode answer(InvocationOnMock invocation) throws Throwable {
return pooledNode;
}
});
}
}