package com.rayo.storage.lb;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import com.rayo.server.storage.model.RayoNode;
public class NodeSetTest {
private Map<RayoNode, Integer> totals = new HashMap<RayoNode, Integer>();
public void setup() {
totals.clear();
}
@Test
public void testEqualBalancing() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23"},
new int[]{10,10,10});
for (int i=0;i<120;i++) {
RayoNode next = nodeSet.next(nodes);
RayoNode node = nodes.get(i%3);
assertEquals(next,node);
inc(node);
}
assertEquals(totals.get(nodes.get(0)),(Integer)40);
assertEquals(totals.get(nodes.get(1)),(Integer)40);
assertEquals(totals.get(nodes.get(2)),(Integer)40);
}
@Test
public void testEqualBalancing2() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23"},
new int[]{37,37,37});
for (int i=0;i<300;i++) {
RayoNode next = nodeSet.next(nodes);
RayoNode node = nodes.get(i%3);
assertEquals(next,node);
inc(node);
}
assertEquals(totals.get(nodes.get(0)),(Integer)100);
assertEquals(totals.get(nodes.get(1)),(Integer)100);
assertEquals(totals.get(nodes.get(2)),(Integer)100);
}
@Test
public void testNodeGetsDoubleRequests() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23"},
new int[]{10,10,20});
for (int i=0;i<300;i++) {
// This part asserts that nodes are evenly load balanced. Other algorithms may
// otherwise just load balance the first requests on all the nodes and then
// send all the remaining requests to the last node which is not really load
// balancing
RayoNode next = nodeSet.next(nodes);
int nodeIndex = i%4;
if (nodeIndex == 0) {
nodeIndex = 2; // first one will go to 2nd because the 1sts nodes will pass
} else {
nodeIndex = nodeIndex - 1;
}
RayoNode node = nodes.get(nodeIndex);
assertEquals(next,node);
inc(node);
}
assertEquals(totals.get(nodes.get(0)),(Integer)75);
assertEquals(totals.get(nodes.get(1)),(Integer)75);
assertEquals(totals.get(nodes.get(2)),(Integer)150);
}
@Test
public void testFiveNodesLoadBalancing() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo","tropo","jobsket"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23","11.120.187.66","12.12.55.55"},
new int[]{10,10,20,40,10});
for (int i=0;i<900;i++) {
RayoNode next = nodeSet.next(nodes);
RayoNode node = null;
switch(i%9) {
case 0:
case 2:
case 3:
case 7: node = nodes.get(3); break;
case 1:
case 6: node = nodes.get(2); break;
case 4: node = nodes.get(0); break;
case 5: node = nodes.get(1); break;
case 8: node = nodes.get(4); break;
}
assertEquals(node,next);
inc(next);
}
assertEquals(totals.get(nodes.get(0)),(Integer)100);
assertEquals(totals.get(nodes.get(1)),(Integer)100);
assertEquals(totals.get(nodes.get(2)),(Integer)200);
assertEquals(totals.get(nodes.get(3)),(Integer)400);
assertEquals(totals.get(nodes.get(4)),(Integer)100);
}
@Test
public void testWeightUpdated() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23"},
new int[]{10,10,10});
for (int i=0;i<120;i++) {
RayoNode next = nodeSet.next(nodes);
RayoNode node = nodes.get(i%3);
assertEquals(next,node);
inc(node);
}
assertEquals(totals.get(nodes.get(0)),(Integer)40);
assertEquals(totals.get(nodes.get(1)),(Integer)40);
assertEquals(totals.get(nodes.get(2)),(Integer)40);
nodes.get(2).setWeight(20);
for (int i=0;i<120;i++) {
RayoNode next = nodeSet.next(nodes);
int nodeIndex = i%4;
if (nodeIndex == 0) {
nodeIndex = 2; // first one will go to 2nd because the 1sts nodes will pass
} else {
nodeIndex = nodeIndex - 1;
}
RayoNode node = nodes.get(nodeIndex);
assertEquals(next,node);
inc(node);
}
assertEquals(totals.get(nodes.get(0)),(Integer)70);
assertEquals(totals.get(nodes.get(1)),(Integer)70);
assertEquals(totals.get(nodes.get(2)),(Integer)100);
}
@Test
public void testAddNodes() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo","tropo","jobsket"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23","11.120.187.66","12.12.55.55"},
new int[]{10,10,20,40,10});
for (int i=0;i<90;i++) {
RayoNode next = nodeSet.next(nodes);
inc(next);
}
assertEquals(totals.get(nodes.get(0)),(Integer)10);
assertEquals(totals.get(nodes.get(1)),(Integer)10);
assertEquals(totals.get(nodes.get(2)),(Integer)20);
assertEquals(totals.get(nodes.get(3)),(Integer)40);
assertEquals(totals.get(nodes.get(4)),(Integer)10);
totals.clear();
nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo","tropo","jobsket","local2","local3"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23","11.120.187.66","12.12.55.55","127.0.0.2","127.0.0.3"},
new int[]{10,10,20,40,10,20,20});
for (int i=0;i<130;i++) {
RayoNode next = nodeSet.next(nodes);
inc(next);
}
assertEquals(totals.get(nodes.get(0)),(Integer)10);
assertEquals(totals.get(nodes.get(1)),(Integer)10);
assertEquals(totals.get(nodes.get(2)),(Integer)20);
assertEquals(totals.get(nodes.get(3)),(Integer)40);
assertEquals(totals.get(nodes.get(4)),(Integer)10);
assertEquals(totals.get(nodes.get(5)),(Integer)20);
assertEquals(totals.get(nodes.get(6)),(Integer)20);
}
@Test
public void testRemoveNode() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23"},
new int[]{10,10,10});
for (int i=0;i<120;i++) {
RayoNode next = nodeSet.next(nodes);
RayoNode node = nodes.get(i%3);
assertEquals(next,node);
inc(node);
}
assertEquals(totals.get(nodes.get(0)),(Integer)40);
assertEquals(totals.get(nodes.get(1)),(Integer)40);
assertEquals(totals.get(nodes.get(2)),(Integer)40);
List<RayoNode> newNodes = createNodes("staging",
new String[]{"connfu","voxeo"},
new String[]{"10.123.5.34", "208.9.3.23"},
new int[]{10,10});
for (int i=0;i<120;i++) {
RayoNode next = nodeSet.next(newNodes);
RayoNode node = newNodes.get((i%2));
assertEquals(next,node);
inc(node);
}
assertEquals(totals.get(nodes.get(0)),(Integer)40);
assertEquals(totals.get(nodes.get(1)),(Integer)100);
assertEquals(totals.get(nodes.get(2)),(Integer)100);
}
@Test
public void testRemoveNodesNeedsRecalculation() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23"},
new int[]{10,20,30});
for (int i=0;i<600;i++) {
RayoNode next = nodeSet.next(nodes);
inc(next);
}
assertEquals(totals.get(nodes.get(0)),(Integer)100);
assertEquals(totals.get(nodes.get(1)),(Integer)200);
assertEquals(totals.get(nodes.get(2)),(Integer)300);
List<RayoNode> newnodes = createNodes("staging",
new String[]{"connfu","voxeo"},
new String[]{"10.123.5.34", "208.9.3.23"},
new int[]{20,30});
totals.clear();
for (int i=0;i<500;i++) {
RayoNode next = nodeSet.next(newnodes);
inc(next);
}
assertNull(totals.get(nodes.get(0)));
assertEquals(totals.get(nodes.get(1)),(Integer)200);
assertEquals(totals.get(nodes.get(2)),(Integer)300);
}
@Test
public void testNodesWithLowPriorityDoNotGetCalls() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23"},
new int[]{10,10,10},
new int[]{1,1,2});
for (int i=0;i<120;i++) {
RayoNode next = nodeSet.next(nodes);
RayoNode node = nodes.get(i%2);
assertEquals(next,node);
inc(node);
}
assertEquals(totals.get(nodes.get(0)),(Integer)60);
assertEquals(totals.get(nodes.get(1)),(Integer)60);
assertNull(totals.get(nodes.get(2)));
}
@Test
public void testRemoveNodesTakesPriorityIntoAccount() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23"},
new int[]{10,10,10},
new int[]{1,2,2});
for (int i=0;i<120;i++) {
RayoNode next = nodeSet.next(nodes);
RayoNode node = nodes.get(0);
assertEquals(next,node);
inc(node);
}
assertEquals(totals.get(nodes.get(0)),(Integer)120);
assertNull(totals.get(nodes.get(1)));
assertNull(totals.get(nodes.get(2)));
List<RayoNode> newnodes = createNodes("staging",
new String[]{"connfu","voxeo"},
new String[]{"10.123.5.34", "208.9.3.23"},
new int[]{10,10},
new int[]{2,2});
for (int i=0;i<120;i++) {
RayoNode next = nodeSet.next(newnodes);
RayoNode node = newnodes.get(i%2);
assertEquals(next,node);
inc(node);
}
assertEquals(totals.get(nodes.get(0)),(Integer)120);
assertEquals(totals.get(nodes.get(1)),(Integer)60);
assertEquals(totals.get(nodes.get(2)),(Integer)60);
}
@Test
public void testAddNodesTakesPriorityIntoAccount() {
NodeSet nodeSet = new NodeSet();
List<RayoNode> nodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23"},
new int[]{10,10,10},
new int[]{2,2,2});
for (int i=0;i<120;i++) {
RayoNode next = nodeSet.next(nodes);
inc(next);
}
assertEquals(totals.get(nodes.get(0)),(Integer)40);
assertEquals(totals.get(nodes.get(1)),(Integer)40);
assertEquals(totals.get(nodes.get(2)),(Integer)40);
List<RayoNode> newnodes = createNodes("staging",
new String[]{"localhost","connfu","voxeo","newone"},
new String[]{"127.0.0.1","10.123.5.34", "208.9.3.23","1.1.1.1"},
new int[]{10,10,10,10},
new int[]{2,2,2,1});
for (int i=0;i<120;i++) {
RayoNode next = nodeSet.next(newnodes);
inc(next);
}
assertEquals(totals.get(newnodes.get(0)),(Integer)40);
assertEquals(totals.get(newnodes.get(1)),(Integer)40);
assertEquals(totals.get(newnodes.get(2)),(Integer)40);
assertEquals(totals.get(newnodes.get(3)),(Integer)120);
}
private List<RayoNode> createNodes(String platform, String[] hostnames, String[] ips, int[] weights) {
return createNodes(platform, hostnames, ips, weights, null);
}
private List<RayoNode> createNodes(String platform, String[] hostnames, String[] ips, int[] weights, int[] priorities) {
List<RayoNode> nodes = new ArrayList<RayoNode>();
Set<String> platforms = new HashSet<String>();
platforms.add(platform);
for(int i=0;i<hostnames.length;i++) {
RayoNode node = new RayoNode(hostnames[i],ips[i],platforms);
node.setWeight(weights[i]);
nodes.add(node);
if (priorities != null) {
node.setPriority(priorities[i]);
}
}
return nodes;
}
private void inc(RayoNode node) {
Integer count = totals.get(node);
if (count == null) {
count = 0;
}
count++;
totals.put(node, count);
}
}