Merge branch 'master' of https://github.com/OPENNETWORKINGLAB/ONOS
diff --git a/cluster-mgmt/template/onsdemo_core.py.devA b/cluster-mgmt/template/onsdemo_core.py.devA
new file mode 100755
index 0000000..ad74e4b
--- /dev/null
+++ b/cluster-mgmt/template/onsdemo_core.py.devA
@@ -0,0 +1,158 @@
+#!/usr/bin/python
+
+"""
+Start up a Simple topology
+"""
+from mininet.net import Mininet
+from mininet.node import Controller, RemoteController
+from mininet.log import setLogLevel, info, error, warn, debug
+from mininet.cli import CLI
+from mininet.topo import Topo
+from mininet.util import quietRun
+from mininet.moduledeps import pathCheck
+from mininet.link import Link, TCLink
+
+from sys import exit
+import os.path
+from subprocess import Popen, STDOUT, PIPE
+
+import sys
+
+
+#import argparse
+
+class MyController( Controller ):
+ def __init__( self, name, ip='127.0.0.1', port=6633, **kwargs):
+ """Init.
+ name: name to give controller
+ ip: the IP address where the remote controller is
+ listening
+ port: the port where the remote controller is listening"""
+ Controller.__init__( self, name, ip=ip, port=port, **kwargs )
+
+ def start( self ):
+ "Overridden to do nothing."
+ return
+
+ def stop( self ):
+ "Overridden to do nothing."
+ return
+
+ def checkListening( self ):
+ "Warn if remote controller is not accessible"
+ listening = self.cmd( "echo A | telnet -e A %s %d" %
+ ( self.ip, self.port ) )
+ if 'Unable' in listening:
+ warn( "Unable to contact the remote controller"
+ " at %s:%d\n" % ( self.ip, self.port ) )
+
+class SDNTopo( Topo ):
+ "SDN Topology"
+
+ def __init__( self, *args, **kwargs ):
+ Topo.__init__( self, *args, **kwargs )
+
+ sw5 = self.addSwitch('sw5', dpid='00000000ba5eba13')
+ sw2 = self.addSwitch('sw2', dpid='00000000ba5eba11')
+ sw3 = self.addSwitch('sw3', dpid='00000008a208f901')
+ sw4 = self.addSwitch('sw4', dpid='000000000000ba12')
+ sw6 = self.addSwitch('sw6', dpid='0000204e7f518a35')
+ sw1 = self.addSwitch('sw1', dpid='0000001697089a46')
+
+ host1 = self.addHost( 'host1' )
+ host2 = self.addHost( 'host2' )
+ host3 = self.addHost( 'host3' )
+ host4 = self.addHost( 'host4' )
+ host5 = self.addHost( 'host5' )
+ host6 = self.addHost( 'host6' )
+
+ self.addLink( host1, sw1 )
+ self.addLink( host2, sw2 )
+ self.addLink( host3, sw3 )
+ self.addLink( host4, sw4 )
+ self.addLink( host5, sw5 )
+ self.addLink( host6, sw6 )
+
+ self.addLink( sw1, sw2 )
+ self.addLink( sw1, sw6 )
+ self.addLink( sw2, sw3 )
+ self.addLink( sw3, sw4 )
+ self.addLink( sw3, sw6 )
+ self.addLink( sw4, sw5 )
+ self.addLink( sw5, sw6 )
+ self.addLink( sw4, sw6 )
+
+def startsshd( host ):
+ "Start sshd on host"
+ info( '*** Starting sshd\n' )
+ name, intf, ip = host.name, host.defaultIntf(), host.IP()
+ banner = '/tmp/%s.banner' % name
+ host.cmd( 'echo "Welcome to %s at %s" > %s' % ( name, ip, banner ) )
+ host.cmd( '/usr/sbin/sshd -o "Banner %s"' % banner, '-o "UseDNS no"' )
+ info( '***', host.name, 'is running sshd on', intf, 'at', ip, '\n' )
+
+def startsshds ( hosts ):
+ for h in hosts:
+ startsshd( h )
+
+def stopsshd( ):
+ "Stop *all* sshd processes with a custom banner"
+ info( '*** Shutting down stale sshd/Banner processes ',
+ quietRun( "pkill -9 -f Banner" ), '\n' )
+
+def sdnnet(opt):
+# os.system('/home/ubuntu/openflow/controller/controller ptcp: &')
+# os.system('/home/ubuntu/openflow/controller/controller ptcp:7000 &')
+
+ topo = SDNTopo()
+ info( '*** Creating network\n' )
+# net = Mininet( topo=topo, controller=RemoteController )
+ net = Mininet( topo=topo, controller=MyController, link=TCLink)
+# dc = DebugController('c3', ip='127.0.0.1', port=7000)
+# net.addController(dc)
+# net.addController(controller=RemoteController)
+
+ host1, host2, host3, host4, host5, host6 = net.get( 'host1', 'host2', 'host3', 'host4', 'host5', 'host6')
+
+ ## Adding 2nd, 3rd and 4th interface to host1 connected to sw1 (for another BGP peering)
+ sw1 = net.get('sw1')
+ sw2 = net.get('sw2')
+ sw3 = net.get('sw3')
+ sw4 = net.get('sw4')
+ sw5 = net.get('sw5')
+ sw6 = net.get('sw6')
+
+ net.start()
+
+ sw2.attach('tap01_2')
+ sw3.attach('tap01_3')
+ sw4.attach('tap01_4')
+ sw4.attach('tap01_5')
+ sw5.attach('tap01_6')
+ sw6.attach('tap01_7')
+ sw1.attach('tap01_8')
+
+ host1.defaultIntf().setIP('192.168.100.141/16')
+ host2.defaultIntf().setIP('192.168.100.142/16')
+ host3.defaultIntf().setIP('192.168.100.143/16')
+ host4.defaultIntf().setIP('192.168.100.144/16')
+ host5.defaultIntf().setIP('192.168.100.145/16')
+ host6.defaultIntf().setIP('192.168.100.146/16')
+
+ hosts = [ host1, host2, host3, host4, host5, host6 ]
+ stopsshd ()
+ startsshds ( hosts )
+
+ if opt=="cli":
+ CLI(net)
+ stopsshd()
+ net.stop()
+
+if __name__ == '__main__':
+ setLogLevel( 'info' )
+ if len(sys.argv) == 1:
+ sdnnet("cli")
+ elif len(sys.argv) == 2 and sys.argv[1] == "-n":
+ sdnnet("nocli")
+ else:
+ print "%s [-n]" % sys.argv[0]
diff --git a/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java b/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java
index 432e578..10bfff4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java
@@ -140,6 +140,9 @@
// TODO: Add the approprate setup
}
+ public void setDbOperationHandler(GraphDBOperation init_op) {
+ op = init_op;
+ }
static class ShortestPathLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
String dpid;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java
index 2310972..de955ba 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java
@@ -13,7 +13,7 @@
*/
@JsonDeserialize(using=FlowIdDeserializer.class)
@JsonSerialize(using=FlowIdSerializer.class)
-public class FlowId {
+public class FlowId implements Comparable<FlowId> {
private long value;
/**
@@ -76,4 +76,16 @@
public String toString() {
return "0x" + Long.toHexString(this.value);
}
+
+ /**
+ * Compare two FlowId objects numerically using their Flow IDs.
+ *
+ * @return the value 0 if the Flow ID is equal to the argument's Flow ID;
+ * a value less than 0 if the Flow ID is numerically less than the argument's Flow ID;
+ * and a value greater than 0 if the Flow ID is numerically greater than the argument's Flow ID.
+ */
+ @Override
+ public int compareTo(FlowId o) {
+ return Long.valueOf(this.value).compareTo(o.value());
+ }
}
diff --git a/src/main/java/net/onrc/onos/registry/controller/StandaloneRegistry.java b/src/main/java/net/onrc/onos/registry/controller/StandaloneRegistry.java
index e48c519..640a49d 100644
--- a/src/main/java/net/onrc/onos/registry/controller/StandaloneRegistry.java
+++ b/src/main/java/net/onrc/onos/registry/controller/StandaloneRegistry.java
@@ -116,10 +116,22 @@
throw new RuntimeException("Not yet implemented");
}
+ private long blockTop = 0L;
+ private static final long BLOCK_SIZE = 0x1000000L;
+
+ /**
+ * Returns a block of IDs which are unique and unused.
+ * Range of IDs is fixed size and is assigned incrementally as this method called.
+ */
@Override
- public IdBlock allocateUniqueIdBlock(){
- //XXX Not exactly unique...
- return new IdBlock(0L, 0x10000000L, 0x10000000L);
+ public synchronized IdBlock allocateUniqueIdBlock(){
+ long blockHead = blockTop;
+ long blockTail = blockTop + BLOCK_SIZE;
+
+ IdBlock block = new IdBlock(blockHead, blockTail - 1, BLOCK_SIZE);
+ blockTop = blockTail;
+
+ return block;
}
@Override
diff --git a/src/main/java/net/onrc/onos/registry/controller/ZookeeperRegistry.java b/src/main/java/net/onrc/onos/registry/controller/ZookeeperRegistry.java
index 82259a9..2d2083f 100644
--- a/src/main/java/net/onrc/onos/registry/controller/ZookeeperRegistry.java
+++ b/src/main/java/net/onrc/onos/registry/controller/ZookeeperRegistry.java
@@ -109,13 +109,7 @@
}
}
-
- /**
- * Listens for changes to the switch znodes in Zookeeper. This maintains
- * the second level of PathChildrenCaches that hold the controllers
- * contending for each switch - there's one for each switch.
- */
- PathChildrenCacheListener switchPathCacheListener = new PathChildrenCacheListener() {
+ protected class SwitchPathCacheListener implements PathChildrenCacheListener {
@Override
public void childEvent(CuratorFramework client,
PathChildrenCacheEvent event) throws Exception {
@@ -158,6 +152,12 @@
}
};
+ /**
+ * Listens for changes to the switch znodes in Zookeeper. This maintains
+ * the second level of PathChildrenCaches that hold the controllers
+ * contending for each switch - there's one for each switch.
+ */
+ PathChildrenCacheListener switchPathCacheListener = new SwitchPathCacheListener();
protected ServiceDiscovery<ControllerService> serviceDiscovery;
protected ServiceCache<ControllerService> serviceCache;
@@ -379,6 +379,12 @@
return data;
}
+ /**
+ * Returns a block of IDs which are unique and unused.
+ * Range of IDs is fixed size and is assigned incrementally as this method called.
+ * Since the range of IDs is managed by Zookeeper in distributed way, this method may block when
+ * requests come up simultaneously.
+ */
public IdBlock allocateUniqueIdBlock(){
try {
AtomicValue<Long> result = null;
diff --git a/src/test/java/net/floodlightcontroller/core/internal/RoleChangeCallbackTest.java b/src/test/java/net/floodlightcontroller/core/internal/RoleChangeCallbackTest.java
new file mode 100644
index 0000000..2aeb60e
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/RoleChangeCallbackTest.java
@@ -0,0 +1,143 @@
+package net.floodlightcontroller.core.internal;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+// Extends Controller class to access protected inner class
+public class RoleChangeCallbackTest extends Controller {
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ /**
+ * Test if {@link RoleChangeCallback#controlChanged(long, boolean)} correctly calls {@link RoleChanger#submitRequest(Collection, net.floodlightcontroller.core.IFloodlightProviderService.Role)}
+ * when connectedSwitch is not empty.
+ * @throws Exception
+ */
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testNormalSwitches() throws Exception {
+ Long [] dpids = new Long [] { 1000L, 1001L, 1002L, 1003L };
+ final long dpidExist = 1000L;
+ final long dpidNotExist = 2000L;
+
+ roleChanger = EasyMock.createMock(RoleChanger.class);
+
+ // First call will be called with (dpidExist,true)
+ roleChanger.submitRequest(EasyMock.anyObject(Collection.class), EasyMock.anyObject(Role.class));
+ EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+ @Override
+ public Object answer() throws Throwable {
+ Collection<OFSwitchImpl> switches = (Collection<OFSwitchImpl>)EasyMock.getCurrentArguments()[0];
+ Role role = (Role)EasyMock.getCurrentArguments()[1];
+
+ List<Long> dpids = new ArrayList<Long>();
+
+ for(OFSwitchImpl sw : switches) {
+ dpids.add(sw.getId());
+ }
+ assertTrue(dpids.contains(dpidExist));
+ assertEquals(role, Role.MASTER);
+
+ return null;
+ }
+ }).once();
+
+ // Second call will be called with (dpidExist,false)
+ roleChanger.submitRequest(EasyMock.anyObject(Collection.class), EasyMock.anyObject(Role.class));
+ EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+ @Override
+ public Object answer() throws Throwable {
+ Collection<OFSwitchImpl> switches = (Collection<OFSwitchImpl>)EasyMock.getCurrentArguments()[0];
+ Role role = (Role)EasyMock.getCurrentArguments()[1];
+
+ List<Long> dpids = new ArrayList<Long>();
+
+ for(OFSwitchImpl sw : switches) {
+ dpids.add(sw.getId());
+ }
+ assertTrue(dpids.contains(dpidExist));
+ assertEquals(role, Role.SLAVE);
+
+ return null;
+ }
+ }).once();
+
+ EasyMock.replay(roleChanger);
+
+ initNetwork(roleChanger, dpids);
+
+ RoleChangeCallback callback = new RoleChangeCallback();
+ callback.controlChanged(dpidExist, true);
+ callback.controlChanged(dpidExist, false);
+ callback.controlChanged(dpidNotExist, true);
+ callback.controlChanged(dpidNotExist, false);
+
+ EasyMock.verify(roleChanger);
+ }
+
+ /**
+ * Test if {@link RoleChangeCallback#controlChanged(long, boolean)} doesn't call RoleChanger methods
+ * when connectedSwitch is empty.
+ * @throws Exception
+ */
+ @Test
+ public void testEmptySwitches() throws Exception {
+ Long [] dpids = new Long [] {};
+ final long dpidToTest = 1000L;
+
+ roleChanger = EasyMock.createMock(RoleChanger.class);
+ // roleChanger methods must not be used
+ EasyMock.replay(roleChanger);
+
+ initNetwork(roleChanger, dpids);
+
+ RoleChangeCallback callback = new RoleChangeCallback();
+ callback.controlChanged(dpidToTest, true);
+ callback.controlChanged(dpidToTest, false);
+
+ EasyMock.verify(roleChanger);
+ }
+
+ /**
+ * Create mock OFSwitchImpl object.
+ * @param id
+ * @return
+ */
+ private OFSwitchImpl createOFSwitchImplMock(Long id) {
+ OFSwitchImpl sw = EasyMock.createMock(OFSwitchImpl.class);
+
+ EasyMock.expect(sw.getId()).andReturn(id).anyTimes();
+ EasyMock.replay(sw);
+
+ return sw;
+ }
+
+ /**
+ * Setup connectedSwitches
+ * @param changer
+ * @param ids
+ * @throws Exception
+ */
+ private void initNetwork(RoleChanger changer, Long [] ids) throws Exception {
+ connectedSwitches = new HashSet<OFSwitchImpl>();
+
+ for(Long id : ids) {
+ connectedSwitches.add(createOFSwitchImplMock(id));
+ }
+ }
+}
diff --git a/src/test/java/net/onrc/onos/graph/GraphDBConnectionTest.java b/src/test/java/net/onrc/onos/graph/GraphDBConnectionTest.java
new file mode 100644
index 0000000..bee936d
--- /dev/null
+++ b/src/test/java/net/onrc/onos/graph/GraphDBConnectionTest.java
@@ -0,0 +1,229 @@
+/**
+ *
+ */
+package net.onrc.onos.graph;
+
+import static org.junit.Assert.*;
+import static org.easymock.EasyMock.expect;
+import static org.powermock.api.easymock.PowerMock.*;
+
+import java.util.*;
+
+import net.onrc.onos.graph.GraphDBOperation;
+
+import org.easymock.IAnswer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.thinkaurelius.titan.core.TitanFactory;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.util.wrappers.event.EventTransactionalGraph;
+import com.tinkerpop.frames.FramedGraph;
+
+/**
+ * @author Toshio Koide
+ *
+ */
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({
+ GraphDBConnection.class,
+ GraphDBOperation.class,
+ TitanFactory.class,
+ EventTransactionalGraph.class})
+public class GraphDBConnectionTest {
+ private static TitanGraph graph = null;
+ private static EventTransactionalGraph<TitanGraph> eg = null;
+ private static Boolean isGraphOpen = false;
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+ }
+
+
+ private void expectDBConnectionAvailable() throws Exception {
+ isGraphOpen = false;
+
+ // create mock objects
+ mockStatic(TitanFactory.class);
+ mockStatic(EventTransactionalGraph.class);
+ graph = createMock(TitanGraph.class);
+ eg = createMock(EventTransactionalGraph.class);
+
+ // setup expectations
+ expect(graph.isOpen()).andAnswer(new IAnswer<Boolean>() {
+ @Override
+ public Boolean answer() throws Throwable {
+ return isGraphOpen;
+ }
+ }).anyTimes();
+ expect(TitanFactory.open("/path/to/dummy")).andAnswer(new IAnswer<TitanGraph>() {
+ @Override
+ public TitanGraph answer() throws Throwable {
+ isGraphOpen = true;
+ return graph;
+ }
+ }).anyTimes();
+ expect(graph.getIndexedKeys(Vertex.class)).andReturn(new TreeSet<String>());
+ graph.createKeyIndex("dpid", Vertex.class);
+ graph.createKeyIndex("port_id", Vertex.class);
+ graph.createKeyIndex("type", Vertex.class);
+ graph.createKeyIndex("dl_addr", Vertex.class);
+ graph.createKeyIndex("flow_id", Vertex.class);
+ graph.createKeyIndex("flow_entry_id", Vertex.class);
+ graph.createKeyIndex("switch_state", Vertex.class);
+ graph.commit();
+ expectNew(EventTransactionalGraph.class, graph).andReturn(eg);
+ }
+
+ /**
+ * Test method for {@link net.onrc.onos.graph.GraphDBConnection#getInstance(java.lang.String)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testGetInstance() throws Exception {
+ // setup expectations
+ expectDBConnectionAvailable();
+
+ // start the test
+ replayAll();
+ GraphDBConnection conn = GraphDBConnection.getInstance("/path/to/dummy");
+
+ // verify the test
+ verifyAll();
+ assertNotNull(conn);
+ }
+
+ /**
+ * Test method for {@link net.onrc.onos.graph.GraphDBConnection#getFramedGraph()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testGetFramedGraph() throws Exception {
+ // setup expectations
+ expectDBConnectionAvailable();
+
+ // start the test
+ replayAll();
+ GraphDBConnection conn = GraphDBConnection.getInstance("/path/to/dummy");
+ FramedGraph<TitanGraph> fg = conn.getFramedGraph();
+
+ // verify the test
+ verifyAll();
+ assertNotNull(fg);
+ assertEquals(graph, fg.getBaseGraph());
+ }
+
+ /**
+ * Test method for {@link net.onrc.onos.graph.GraphDBConnection#addEventListener(net.onrc.onos.graph.LocalGraphChangedListener)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testAddEventListener() throws Exception {
+ // instantiate required objects
+ LocalGraphChangedListener listener = new LocalTopologyEventListener(null);
+
+ // setup expectations
+ expectDBConnectionAvailable();
+ eg.addListener(listener);
+
+ // start the test
+ replayAll();
+ GraphDBConnection conn = GraphDBConnection.getInstance("/path/to/dummy");
+ conn.addEventListener(listener);
+
+ // verify the test
+ verifyAll();
+ }
+
+ /**
+ * Test method for {@link net.onrc.onos.graph.GraphDBConnection#isValid()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testIsValid() throws Exception {
+ // setup expectations
+ expectDBConnectionAvailable();
+
+ // start the test
+ replayAll();
+ GraphDBConnection conn = GraphDBConnection.getInstance("/path/to/dummy");
+ Boolean result = conn.isValid();
+
+ // verify the test
+ verifyAll();
+ assertTrue(result);
+ }
+
+ /**
+ * Test method for {@link net.onrc.onos.graph.GraphDBConnection#commit()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testCommit() throws Exception {
+ // setup expectations
+ expectDBConnectionAvailable();
+ graph.commit();
+
+ // start the test
+ replayAll();
+ GraphDBConnection conn = GraphDBConnection.getInstance("/path/to/dummy");
+ conn.commit();
+
+ // verify the test
+ verifyAll();
+ }
+
+ /**
+ * Test method for {@link net.onrc.onos.graph.GraphDBConnection#rollback()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testRollback() throws Exception {
+ // setup expectations
+ expectDBConnectionAvailable();
+ graph.rollback();
+
+ // start the test
+ replayAll();
+ GraphDBConnection conn = GraphDBConnection.getInstance("/path/to/dummy");
+ conn.rollback();
+
+ // verify the test
+ verifyAll();
+ }
+
+ /**
+ * Test method for {@link net.onrc.onos.graph.GraphDBConnection#close()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testClose() throws Exception {
+ // setup expectations
+ expectDBConnectionAvailable();
+ graph.commit();
+
+ // start the test
+ replayAll();
+ GraphDBConnection conn = GraphDBConnection.getInstance("/path/to/dummy");
+ conn.close();
+
+ // verify the test
+ verifyAll();
+ }
+
+}
diff --git a/src/test/java/net/onrc/onos/util/GraphDBOperationTest.java b/src/test/java/net/onrc/onos/graph/GraphDBOperationTest.java
similarity index 97%
rename from src/test/java/net/onrc/onos/util/GraphDBOperationTest.java
rename to src/test/java/net/onrc/onos/graph/GraphDBOperationTest.java
index f85cc4f..e99ca81 100644
--- a/src/test/java/net/onrc/onos/util/GraphDBOperationTest.java
+++ b/src/test/java/net/onrc/onos/graph/GraphDBOperationTest.java
@@ -1,7 +1,7 @@
/**
*
*/
-package net.onrc.onos.util;
+package net.onrc.onos.graph;
import static org.junit.Assert.*;
@@ -95,11 +95,12 @@
public final void testNewSwitch() {
assertNull(op.searchSwitch("123"));
- op.newSwitch("123");
+ ISwitchObject sw = op.newSwitch("123");
+ assertEquals(sw.getDPID(), "123");
op.commit();
- ISwitchObject sw = op.searchSwitch("123");
- assertNotNull(op);
+ sw = op.searchSwitch("123");
+ assertNotNull(sw);
assertEquals("123", sw.getDPID());
}
@@ -232,7 +233,7 @@
public final void testNewPort() {
assertFalse(testdb.getVertices("type", "port").iterator().hasNext());
- IPortObject port = op.newPort((short) 10);
+ IPortObject port = op.newPort("1", (short) 10);
assertTrue(port.getNumber() == 10);
op.commit();
@@ -250,12 +251,12 @@
IPortObject port;
sw = op.newSwitch("1");
- sw.addPort(op.newPort((short) 1));
- sw.addPort(op.newPort((short) 2));
+ sw.addPort(op.newPort("1", (short) 1));
+ sw.addPort(op.newPort("1", (short) 2));
sw = op.newSwitch("2");
- sw.addPort(op.newPort((short) 1));
- sw.addPort(op.newPort((short) 2));
+ sw.addPort(op.newPort("2", (short) 1));
+ sw.addPort(op.newPort("2", (short) 2));
op.commit();
@@ -300,8 +301,8 @@
IPortObject port;
sw = op.newSwitch("1");
- sw.addPort(op.newPort((short) 1));
- sw.addPort(op.newPort((short) 2));
+ sw.addPort(op.newPort("1", (short) 1));
+ sw.addPort(op.newPort("1", (short) 2));
op.commit();
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java
index 5c42452..9b1c4d6 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java
@@ -6,7 +6,6 @@
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -33,6 +32,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Unit test for {@link LinkStorageImpl}.
+ * @author Naoki Shiota
+ *
+ */
@RunWith(PowerMockRunner.class)
@PrepareForTest({LinkStorageImpl.class, GraphDBConnection.class, GraphDBOperation.class})
public class LinkStorageImplTest {
@@ -100,12 +104,14 @@
*/
@Before
public void setUp() throws Exception{
+ // Create mock GraphDBConnection (replace Singleton object to mock one)
PowerMock.mockStatic(GraphDBConnection.class);
PowerMock.suppress(PowerMock.constructor(GraphDBConnection.class));
- conn = PowerMock.createNiceMock(GraphDBConnection.class);
+ conn = PowerMock.createMock(GraphDBConnection.class);
EasyMock.expect(GraphDBConnection.getInstance((String)EasyMock.anyObject())).andReturn(conn).anyTimes();
PowerMock.replay(GraphDBConnection.class);
+ // Create mock GraphDBOperation
ope = createMockGraphDBOperation();
PowerMock.expectNew(GraphDBOperation.class, new Class<?>[] {GraphDBConnection.class}, EasyMock.anyObject(GraphDBConnection.class)).andReturn(ope).anyTimes();
PowerMock.replay(GraphDBOperation.class);
@@ -121,18 +127,16 @@
/**
* Closing code called after each tests.
- * Discard test graph data.
* @throws Exception
*/
@After
public void tearDown() throws Exception {
- // finish code
linkStorage.close();
}
// TODO: remove @Ignore after UPDATE method is implemented
/**
- * Test if update() can correctly updates LinkInfo for a Link.
+ * Test if {@link LinkStorageImpl#update(Link, LinkInfo, DM_OPERATION)} can correctly updates LinkInfo for a Link.
*/
@Ignore @Test
public void testUpdate_UpdateSingleLink() {
@@ -147,7 +151,7 @@
}
/**
- * Test if update() can correctly creates a Link.
+ * Test if {@link LinkStorageImpl#update(Link, DM_OPERATION)} can correctly creates a Link.
*/
@Test
public void testUpdate_CreateSingleLink() {
@@ -157,18 +161,10 @@
//Use the link storage API to add the link
linkStorage.update(linkToCreate, ILinkStorage.DM_OPERATION.CREATE);
doTestLinkExist(linkToVerify);
-
- // Avoiding duplication is out of scope. DBOperation is responsible for this.
-// // Add same link
-// Link linkToCreateTwice = createFeasibleLink();
-// linkStorage.update(linkToCreateTwice, ILinkStorage.DM_OPERATION.CREATE);
-//
-// // this occurs assertion failure if there are two links in titanGraph
-// doTestLinkIsInGraph(linkToVerify);
}
/**
- * Test if update() can correctly inserts a Link.
+ * Test if {@link LinkStorageImpl#update(Link, DM_OPERATION)}can correctly inserts a Link.
*/
@Test
public void testUpdate_InsertSingleLink(){
@@ -181,7 +177,7 @@
}
/**
- * Test if update() can correctly deletes a Link.
+ * Test if {@link LinkStorageImpl#update(Link, DM_OPERATION)} can correctly deletes a Link.
*/
@Test
public void testUpdate_DeleteSingleLink(){
@@ -194,7 +190,7 @@
}
/**
- * Test if update() can correctly creates multiple Links.
+ * Test if {@link LinkStorageImpl#update(List, DM_OPERATION)} can correctly creates multiple Links.
*/
@Test
public void testUpdate_CreateLinks(){
@@ -206,34 +202,10 @@
for(Link l : linksToVerify) {
doTestLinkExist(l);
}
-
- // Out of scope: DBOperation is responsible for avoiding duplication.
-// // Test creation of existing links
-// linksToCreate = createFeasibleLinks();
-// linkStorage.update(linksToCreate, ILinkStorage.DM_OPERATION.CREATE);
-// for(Link l : linksToVerify) {
-// doTestLinkIsInGraph(l);
-// }
- }
-
- /**
- * Test if update() can handle mixture of normal/abnormal input for creation of Links.
- * Deprecated: DBOperation is responsible.
- */
- @Ignore @Test
- public void testUpdate_CreateLinks_Mixuture(){
- List<Link> linksToCreate = new ArrayList<Link>();
- linksToCreate.add(createFeasibleLink());
- linksToCreate.add(createExistingLink());
-
- // Test creation of mixture of new/existing links
- linkStorage.update(linksToCreate, ILinkStorage.DM_OPERATION.CREATE);
- doTestLinkExist(createFeasibleLink());
- doTestLinkExist(createExistingLink());
}
/**
- * Test if update() can correctly inserts multiple Links.
+ * Test if {@link LinkStorageImpl#update(List, DM_OPERATION)} can correctly inserts multiple Links.
*/
@Test
public void testUpdate_InsertLinks(){
@@ -248,22 +220,7 @@
}
/**
- * Test if update() can handle mixture of normal/abnormal input for creation of Links.
- */
- @Ignore @Test
- public void testUpdate_InsertLinks_Mixuture(){
- List<Link> linksToInsert = new ArrayList<Link>();
- linksToInsert.add(createFeasibleLink());
- linksToInsert.add(createExistingLink());
-
- // Test insertion of mixture of new/existing links
- linkStorage.update(linksToInsert, ILinkStorage.DM_OPERATION.INSERT);
- doTestLinkExist(createFeasibleLink());
- doTestLinkExist(createExistingLink());
- }
-
- /**
- * Test if update() can correctly deletes multiple Links.
+ * Test if {@link LinkStorageImpl#update(List, DM_OPERATION)} can correctly deletes multiple Links.
*/
@Test
public void testUpdate_DeleteLinks(){
@@ -277,24 +234,9 @@
}
}
- /**
- * Test if update() can handle mixture of normal/abnormal input for deletion of Links.
- */
- @Ignore @Test
- public void testUpdate_DeleteLinks_Mixuture(){
- List<Link> linksToDelete = new ArrayList<Link>();
- linksToDelete.add(createFeasibleLink());
- linksToDelete.add(createExistingLink());
-
- // Test deletion of mixture of new/existing links
- linkStorage.update(linksToDelete, ILinkStorage.DM_OPERATION.DELETE);
- doTestLinkNotExist(createFeasibleLink());
- doTestLinkNotExist(createExistingLink());
- }
-
// TODO: remove @Ignore after UPDATE method is implemented
/**
- * Test if updateLink() can correctly updates LinkInfo for a Link.
+ * Test if {@link LinkStorageImpl#updateLink(Link, LinkInfo, DM_OPERATION)} can correctly updates LinkInfo for a Link.
*/
@Ignore @Test
public void testUpdateLink_Update() {
@@ -309,7 +251,7 @@
}
/**
- * Test if updateLink() can correctly creates a Link.
+ * Test if {@link LinkStorageImpl#updateLink(Link, LinkInfo, DM_OPERATION)} can correctly creates a Link.
*/
@Test
public void testUpdateLink_Create() {
@@ -322,7 +264,7 @@
}
/**
- * Test if updateLink() can correctly inserts a Link.
+ * Test if {@link LinkStorageImpl#updateLink(Link, LinkInfo, DM_OPERATION)} can correctly inserts a Link.
*/
@Test
public void testUpdateLink_Insert() {
@@ -337,7 +279,7 @@
// TODO: Check if addOrUpdateLink() should accept DELETE operation. If not, remove this test.
/**
- * Test if updateLink() can correctly deletes a Link.
+ * Test if {@link LinkStorageImpl#updateLink(Link, LinkInfo, DM_OPERATION)} can correctly deletes a Link.
*/
@Ignore @Test
public void testUpdateLink_Delete() {
@@ -357,7 +299,7 @@
}
/**
- * Test if getLinks() can correctly return Links connected to specific DPID and port.
+ * Test if {@link LinkStorageImpl#getLinks(Long, short)} can correctly return Links connected to specific DPID and port.
*/
@Test
public void testGetLinks_ByDpidPort(){
@@ -383,7 +325,7 @@
}
/**
- * Test if getLinks() can correctly return Links connected to specific MAC address.
+ * Test if {@link LinkStorageImpl#getLinks(String)} can correctly return Links connected to specific MAC address.
*/
@Test
public void testGetLinks_ByString() {
@@ -398,7 +340,7 @@
}
/**
- * Test if deleteLink() can correctly delete a Link.
+ * Test if {@link LinkStorageImpl#deleteLink(Link)} can correctly delete a Link.
*/
@Test
public void testDeleteLink() {
@@ -411,7 +353,7 @@
}
/**
- * Test if deleteLinks() can correctly delete Links.
+ * Test if {@link LinkStorageImpl#deleteLinks(List)} can correctly delete Links.
*/
@Test
public void testDeleteLinks(){
@@ -423,24 +365,9 @@
doTestLinkNotExist(l);
}
}
-
- /**
- * Test if deleteLinks() can handle mixture of normal/abnormal input.
- */
- @Ignore @Test
- public void testDeleteLinks_Mixture(){
- List<Link> linksToDelete = new ArrayList<Link>();
- linksToDelete.add(createFeasibleLink());
- linksToDelete.add(createExistingLink());
-
- // Test deletion of mixture of new/existing links
- linkStorage.deleteLinks(linksToDelete);
- doTestLinkNotExist(createFeasibleLink());
- doTestLinkNotExist(createExistingLink());
- }
/**
- * Test if getActiveLinks() can correctly return active Links.
+ * Test if {@link LinkStorageImpl#getActiveLinks()} can correctly return active Links.
*/
@Test
public void testGetActiveLinks() {
@@ -454,7 +381,7 @@
}
/**
- * Test if deleteLinksOnPort() can delete Links.
+ * Test if {@link LinkStorageImpl#deleteLinksOnPort(Long, short)} can delete Links.
*/
@Test
public void testDeleteLinksOnPort() {
@@ -493,11 +420,12 @@
* Test if titanGraph has specific Link with specific LinkInfo
* @param link
*/
+ // TODO: Fix me
private void doTestLinkHasStateOf(Link link, LinkInfo info) {
}
/**
- * Class defines a function called back when IPortObject#removeLink is called.
+ * Class defines a function called back when {@link IPortObject#removeLink(IPortObject)} is called.
* @author Naoki Shiota
*
*/
@@ -521,9 +449,8 @@
}
/**
- * Class defines a function called back when IPortObject#setLinkPort is called.
+ * Class defines a function called back when {@link IPortObject#setLinkPort(IPortObject)} is called.
* @author Naoki Shiota
- *
*/
private class SetLinkPortCallback implements IAnswer<Object> {
private long dpid;
@@ -546,7 +473,7 @@
}
/**
- * Class defines a function called back when IPortObject#getSwitch is called.
+ * Class defines a function called back when {@link IPortObject#getSwitch()} is called.
* @author Naoki Shiota
*
*/
@@ -565,7 +492,7 @@
}
/**
- * Class defines a function called back when IPortObject#getLinkedPorts is called.
+ * Class defines a function called back when {@link IPortObject#getLinkedPorts()} is called.
* @author Naoki Shiota
*
*/
@@ -594,7 +521,7 @@
}
/**
- * Class defines a function called back when ISwitchObject#getPorts is called.
+ * Class defines a function called back when {@link LinkStorageImplTest} is called.
* @author Naoki Shiota
*
*/
@@ -619,7 +546,7 @@
// ------------------------Creation of Mock-----------------------------
/**
- * Create a mock GraphDBOperation which hooks port-related methods.
+ * Create a mock {@link GraphDBOperation} which hooks port-related methods.
* @return EasyMock-wrapped GraphDBOperation object.
*/
@SuppressWarnings("serial")
@@ -692,8 +619,8 @@
}
/**
- * Create a mock IPortObject using given DPID and port number.
- * IPortObject can't store DPID, so DPID is stored to mockToPortInfoMap for later use.
+ * Create a mock {@link IPortObject} using given DPID and port number.
+ * {@link IPortObject} can't store DPID, so DPID is stored to mockToPortInfoMap for later use.
* Duplication is not checked.
* @param dpid DPID of a port
* @param number Port Number
@@ -725,7 +652,7 @@
}
/**
- * Create a mock ISwitchObject using given DPID number.
+ * Create a mock {@link ISwitchObject} using given DPID number.
* Duplication is not checked.
* @param dpid DPID of a switch
* @return EasyMock-wrapped ISwitchObject
@@ -811,7 +738,7 @@
}
/**
- * Returns new Link object of an existing link
+ * Returns new {@link Link} object of an existing link
* @return new Link object
*/
private Link createExistingLink() {
@@ -819,7 +746,7 @@
}
/**
- * Returns new Link object of a not-existing but feasible link
+ * Returns new {@link Link} object of a not-existing but feasible link
* @return new Link object
*/
private Link createFeasibleLink() {
@@ -833,7 +760,7 @@
}
/**
- * Returns list of Link objects which all has information of existing link in titanGraph
+ * Returns list of existing {@link Link} objects
* @return ArrayList of new Link objects
*/
private List<Link> createExistingLinks() {
@@ -844,7 +771,7 @@
}
/**
- * Returns list of Link objects which all has information of not-existing but feasible link
+ * Returns list of {@link Link} objects that are all not-existing but feasible
* @return ArrayList of new Link objects
*/
private List<Link> createFeasibleLinks() {
@@ -855,7 +782,7 @@
}
/**
- * Returns new LinkInfo object with convenient values.
+ * Returns new {@link LinkInfo} object with convenient values.
* @return LinkInfo object
*/
private LinkInfo createFeasibleLinkInfo(long time) {
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestDatabaseManager.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestDatabaseManager.java
index b4cfc31..b8091fc 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestDatabaseManager.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestDatabaseManager.java
@@ -56,10 +56,19 @@
//Change the type of all port numbers to short in the database
Iterator<Vertex> it = titanGraph.getVertices("type", "port").iterator();
- while (it.hasNext()){
- Vertex port = it.next();
- Integer portNum = (Integer) port.getProperty("number");
- port.setProperty("number", portNum.shortValue());
+ while (it.hasNext()){
+ Vertex port = it.next();
+
+ if(port.getProperty("number") instanceof Short)
+ {
+ Short portNum = (Short) port.getProperty("number");
+ port.setProperty("number", portNum.shortValue());
+ }
+ else{
+ Integer portNum = (Integer) port.getProperty("number");
+ port.setProperty("number", portNum.shortValue());
+ }
+
}
titanGraph.stopTransaction(Conclusion.SUCCESS);
}
@@ -73,4 +82,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java b/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
new file mode 100644
index 0000000..5add3cd
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
@@ -0,0 +1,961 @@
+package net.onrc.onos.ofcontroller.flowmanager;
+
+import static org.junit.Assert.*;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.cmpEq;
+import static org.powermock.api.easymock.PowerMock.*;
+
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.restserver.IRestApiService;
+import net.onrc.onos.graph.GraphDBOperation;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
+import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
+import net.onrc.onos.ofcontroller.util.*;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+/**
+ * @author Toshio Koide
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({FlowManager.class, GraphDBOperation.class, System.class, Executors.class})
+public class FlowManagerTest {
+ private static FloodlightModuleContext context;
+ private static IFloodlightProviderService floodlightProvider;
+ private static ITopoRouteService topoRouteService;
+ private static IRestApiService restApi;
+ private static GraphDBOperation op;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ private void expectInitWithContext() throws Exception {
+ // create mock objects
+ context = createMock(FloodlightModuleContext.class);
+ floodlightProvider = createMock(IFloodlightProviderService.class);
+ topoRouteService = createMock(ITopoRouteService.class);
+ restApi = createMock(IRestApiService.class);
+ op = createMock(GraphDBOperation.class);
+
+ // setup expectations
+ expect(context.getServiceImpl(IFloodlightProviderService.class)).andReturn(floodlightProvider);
+ expect(context.getServiceImpl(ITopoRouteService.class)).andReturn(topoRouteService);
+ expect(context.getServiceImpl(IRestApiService.class)).andReturn(restApi);
+ expectNew(GraphDBOperation.class, new Class<?>[] {String.class}, EasyMock.isA(String.class)).andReturn(op);
+ }
+
+ private IFlowPath createIFlowPathMock(long flowId, String installerID,
+ long srcDpid, int srcPort, long dstDpid, int dstPort) {
+ IFlowPath iFlowPath = createNiceMock(IFlowPath.class);
+ expect(iFlowPath.getFlowId()).andReturn(new FlowId(flowId).toString()).anyTimes();
+ expect(iFlowPath.getInstallerId()).andReturn(installerID).anyTimes();
+ expect(iFlowPath.getSrcSwitch()).andReturn(new Dpid(srcDpid).toString()).anyTimes();
+ expect(iFlowPath.getSrcPort()).andReturn(new Short((short)srcPort)).anyTimes();
+ expect(iFlowPath.getDstSwitch()).andReturn(new Dpid(dstDpid).toString()).anyTimes();
+ expect(iFlowPath.getDstPort()).andReturn(new Short((short)dstPort)).anyTimes();
+ expect(iFlowPath.getFlowEntries()).andReturn(new ArrayList<IFlowEntry>()).anyTimes();
+ return iFlowPath;
+ }
+
+ private FlowPath createTestFlowPath(
+ long flowId,
+ String installerId,
+ final long srcDpid, final int srcPort,
+ final long dstDpid, final int dstPort
+ ) {
+ FlowPath flowPath = new FlowPath();
+ flowPath.setFlowId(new FlowId(flowId));
+ flowPath.setInstallerId(new CallerId(installerId));
+ flowPath.setDataPath(new DataPath() {{
+ setSrcPort(new SwitchPort(new Dpid(srcDpid), new Port((short)srcPort)));
+ setDstPort(new SwitchPort(new Dpid(dstDpid), new Port((short)dstPort)));
+ }});
+ flowPath.setFlowEntryMatch(new FlowEntryMatch());
+ return flowPath;
+ }
+
+ private ArrayList<FlowPath> createTestFlowPaths() {
+ FlowPath flowPath1 = createTestFlowPath(1, "foo caller id", 1, 1, 2, 2);
+ FlowPath flowPath2 = createTestFlowPath(2, "caller id", 1, 1, 2, 2);
+ FlowPath flowPath3 = createTestFlowPath(3, "caller id", 1, 5, 2, 2);
+
+ ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
+ flowPaths.add(flowPath1);
+ flowPaths.add(flowPath2);
+ flowPaths.add(flowPath3);
+
+ return flowPaths;
+ }
+
+
+ // IFlowService methods
+
+
+ /**
+ * Test method for {@link FlowManager#addFlow(FlowPath, FlowId, String)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testAddFlowFailGraphCreatesNoFlow() throws Exception {
+ // instantiate required objects
+ FlowId flowId = new FlowId(123);
+ FlowPath flowPath = new FlowPath();
+ flowPath.setFlowId(flowId);
+
+ // setup expectations
+ expectInitWithContext();
+ expect(op.searchFlowPath(flowId)).andReturn(null);
+ expect(op.newFlowPath()).andReturn(null);
+ op.rollback();
+
+ // start the test
+ replayAll();
+// replay(GraphDBOperation.class);
+
+ FlowManager fm = new FlowManager();
+ fm.init(context);
+ Boolean result = fm.addFlow(flowPath, flowId, "");
+
+ // verify the test
+ verifyAll();
+ assertFalse(result);
+ }
+
+ /**
+ * Test method for {@link FlowManager#addFlow(FlowPath, FlowId, String)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testAddFlowSuccessNormally() throws Exception {
+ final String addFlowEntry = "addFlowEntry";
+ // create mock objects
+ IFlowPath createdFlowPath = createNiceMock(IFlowPath.class);
+ IFlowEntry createdFlowEntry1 = createNiceMock(IFlowEntry.class);
+ IFlowEntry createdFlowEntry2 = createNiceMock(IFlowEntry.class);
+ FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, addFlowEntry);
+
+ // instantiate required objects
+ final FlowEntry flowEntry1 = new FlowEntry();
+ final FlowEntry flowEntry2 = new FlowEntry();
+ ArrayList<FlowEntry> flowEntries = new ArrayList<FlowEntry>();
+ flowEntries.add(flowEntry1);
+ flowEntries.add(flowEntry2);
+
+ DataPath dataPath = new DataPath();
+ dataPath.setSrcPort(new SwitchPort(new Dpid(0x1234), new Port((short)1)));
+ dataPath.setDstPort(new SwitchPort(new Dpid(0x5678), new Port((short)2)));
+ dataPath.setFlowEntries(flowEntries);
+
+ FlowEntryMatch match = new FlowEntryMatch();
+
+ FlowPath flowPath = new FlowPath();
+ flowPath.setFlowId(new FlowId(0x100));
+ flowPath.setInstallerId(new CallerId("installer id"));
+ flowPath.setDataPath(dataPath);
+ flowPath.setFlowEntryMatch(match);
+
+ // setup expectations
+ expectInitWithContext();
+ expect(op.searchFlowPath(cmpEq(new FlowId(0x100)))).andReturn(null);
+ expect(op.newFlowPath()).andReturn(createdFlowPath);
+ createdFlowPath.setFlowId("0x100");
+ createdFlowPath.setType("flow");
+ createdFlowPath.setInstallerId("installer id");
+ createdFlowPath.setSrcSwitch("00:00:00:00:00:00:12:34");
+ createdFlowPath.setSrcPort(new Short((short)1));
+ createdFlowPath.setDstSwitch("00:00:00:00:00:00:56:78");
+ createdFlowPath.setDstPort(new Short((short)2));
+ createdFlowPath.setDataPathSummary("data path summary");
+ createdFlowPath.setUserState("FE_USER_ADD");
+
+ expectPrivate(fm, addFlowEntry, createdFlowPath, flowEntry1)
+ .andReturn(createdFlowEntry1);
+ expectPrivate(fm, addFlowEntry, createdFlowPath, flowEntry2)
+ .andReturn(createdFlowEntry2);
+
+ op.commit();
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ Boolean result = fm.addFlow(flowPath, new FlowId(0x100), "data path summary");
+
+ // verify the test
+ verifyAll();
+ assertTrue(result);
+ }
+
+ /**
+ * Test method for {@link FlowManager#deleteAllFlows()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testDeleteAllFlowsSuccessNormally() throws Exception {
+ // create mock objects
+ IFlowPath flowPath1 = createNiceMock(IFlowPath.class);
+ IFlowPath flowPath2 = createNiceMock(IFlowPath.class);
+
+ // instantiate required objects
+ ArrayList<IFlowPath> flowPaths = new ArrayList<IFlowPath>();
+ flowPaths.add(flowPath1);
+ flowPaths.add(flowPath2);
+
+ // setup expectations
+ expectInitWithContext();
+ expect(op.getAllFlowPaths()).andReturn(flowPaths);
+
+ expect(flowPath1.getFlowId()).andReturn("1").anyTimes();
+ expect(op.searchFlowPath(cmpEq(new FlowId(1)))).andReturn(flowPath1);
+ expect(flowPath1.getFlowEntries()).andReturn(new ArrayList<IFlowEntry>());
+ op.removeFlowPath(flowPath1);
+
+ expect(flowPath2.getFlowId()).andReturn("2").anyTimes();
+ expect(op.searchFlowPath(cmpEq(new FlowId(2)))).andReturn(flowPath2);
+ expect(flowPath2.getFlowEntries()).andReturn(new ArrayList<IFlowEntry>());
+ op.removeFlowPath(flowPath2);
+
+ op.commit();
+ expectLastCall().anyTimes();
+
+ // start the test
+ replayAll();
+
+ FlowManager fm = new FlowManager();
+ fm.init(context);
+ Boolean result = fm.deleteAllFlows();
+
+ // verify the test
+ verifyAll();
+ assertTrue(result);
+ }
+
+ /**
+ * Test method for {@link FlowManager#deleteFlow(FlowId)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testDeleteFlowSuccessEmptyFlowPath() throws Exception {
+ // create mock objects
+ IFlowPath flowObj = createNiceMock(IFlowPath.class);
+
+ // setup expectations
+ expectInitWithContext();
+ expect(op.searchFlowPath(cmpEq(new FlowId(1)))).andReturn(flowObj);
+ expect(flowObj.getFlowEntries()).andReturn(new ArrayList<IFlowEntry>());
+ op.removeFlowPath(flowObj);
+ op.commit();
+ expectLastCall().anyTimes();
+
+ // start the test
+ replayAll();
+
+ FlowManager fm = new FlowManager();
+ fm.init(context);
+ Boolean result = fm.deleteFlow(new FlowId(1));
+
+ // verify the test
+ verifyAll();
+ assertTrue(result);
+ }
+
+ /**
+ * Test method for {@link FlowManager#clearAllFlows()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testClearAllFlowsSuccessNormally() throws Exception {
+ // create mock objects
+ IFlowPath flowPath1 = createNiceMock(IFlowPath.class);
+ IFlowPath flowPath2 = createNiceMock(IFlowPath.class);
+ IFlowPath flowPath3 = createNiceMock(IFlowPath.class);
+ FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, "clearFlow");
+
+ // instantiate required objects
+ ArrayList<IFlowPath> flowPaths = new ArrayList<IFlowPath>();
+ flowPaths.add(flowPath1);
+ flowPaths.add(flowPath2);
+ flowPaths.add(null);
+ flowPaths.add(flowPath3);
+
+ // setup expectations
+ expectInitWithContext();
+ expect(op.getAllFlowPaths()).andReturn(flowPaths);
+ expect(flowPath1.getFlowId()).andReturn(new FlowId(1).toString());
+ expect(flowPath2.getFlowId()).andReturn(null);
+ expect(flowPath3.getFlowId()).andReturn(new FlowId(3).toString());
+ expect(fm.clearFlow(cmpEq(new FlowId(1)))).andReturn(true);
+ expect(fm.clearFlow(cmpEq(new FlowId(3)))).andReturn(true);
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ Boolean result = fm.clearAllFlows();
+
+ //verify the test
+ verifyAll();
+ assertTrue(result);
+ }
+
+ /**
+ * Test method for {@link FlowManager#getFlow()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testGetFlowSuccessNormally() throws Exception {
+ // instantiate required objects
+ FlowManager fm = new FlowManager();
+
+ // setup expectations
+ expectInitWithContext();
+ expect(op.searchFlowPath(cmpEq(new FlowId(1)))).andReturn(
+ createIFlowPathMock(1, "caller id", 1, 1, 2, 2));
+ op.commit();
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ String result = fm.getFlow(new FlowId(1)).installerId().toString();
+
+ //verify the test
+ verifyAll();
+ assertEquals("caller id", result);
+ }
+
+ /**
+ * Test method for {@link FlowManager#getAllFlows(CallerId, DataPathEndpoints)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testGetAllFlowsWithCallerIdAndDataPathEndpointsSuccessNormally() throws Exception {
+ final String getAllFlows = "getAllFlows";
+ // create mock objects
+ FlowManager fm = createPartialMock(FlowManager.class, getAllFlows,
+ new Class<?>[]{}, new Object[]{});
+
+ // instantiate required objects
+ DataPathEndpoints dataPathEndpoints = new DataPathEndpoints(
+ new SwitchPort(new Dpid(1), new Port((short)1)),
+ new SwitchPort(new Dpid(2), new Port((short)2)));
+
+ ArrayList<FlowPath> obtainedAllFlows = createTestFlowPaths();
+
+ //setup expectations
+ expectInitWithContext();
+ expectPrivate(fm, getAllFlows).andReturn(obtainedAllFlows);
+
+ //start the test
+ replayAll();
+
+ fm.init(context);
+ ArrayList<FlowPath> flows = fm.getAllFlows(new CallerId("caller id"), dataPathEndpoints);
+
+ // verify the test
+ verifyAll();
+ assertEquals(1, flows.size());
+ assertEquals(obtainedAllFlows.get(1), flows.get(0));
+ }
+
+ /**
+ * Test method for {@link FlowManager#getAllFlows(DataPathEndpoints)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testGetAllFlowsWithDataPathEndpointsSuccessNormally() throws Exception {
+ final String getAllFlows = "getAllFlows";
+ // create mock objects
+ FlowManager fm = createPartialMock(FlowManager.class, getAllFlows,
+ new Class<?>[]{}, new Object[]{});
+
+ // instantiate required objects
+ DataPathEndpoints dataPathEndpoints = new DataPathEndpoints(
+ new SwitchPort(new Dpid(1), new Port((short)1)),
+ new SwitchPort(new Dpid(2), new Port((short)2)));
+
+ ArrayList<FlowPath> obtainedAllFlows = createTestFlowPaths();
+
+ //setup expectations
+ expectInitWithContext();
+ expectPrivate(fm, getAllFlows).andReturn(obtainedAllFlows);
+
+ //start the test
+ replayAll();
+
+ fm.init(context);
+ ArrayList<FlowPath> flows = fm.getAllFlows(dataPathEndpoints);
+
+ // verify the test
+ verifyAll();
+ assertEquals(2, flows.size());
+ assertEquals(obtainedAllFlows.get(0), flows.get(0));
+ assertEquals(obtainedAllFlows.get(1), flows.get(1));
+ // TODO: ignore the order of flows in the list
+ }
+
+ /**
+ * Test method for {@link FlowManager#getAllFlowsSummary(FlowId, int)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testGetAllFlowsSummarySuccessNormally() throws Exception {
+ final String getAllFlowsWithoutFlowEntries = "getAllFlowsWithoutFlowEntries";
+ // create mock objects
+ FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, getAllFlowsWithoutFlowEntries);
+ IFlowPath flowPath1 = createIFlowPathMock(1, "", 1, 2, 3, 4);
+ IFlowPath flowPath2 = createIFlowPathMock(5, "", 2, 3, 4, 5);
+ IFlowPath flowPath3 = createIFlowPathMock(10, "", 3, 4, 5, 6);
+
+ // instantiate required objects
+ ArrayList<IFlowPath> flows = new ArrayList<IFlowPath>();
+ flows.add(flowPath3);
+ flows.add(flowPath1);
+ flows.add(flowPath2);
+
+ // setup expectations
+ expectInitWithContext();
+ expectPrivate(fm, getAllFlowsWithoutFlowEntries).andReturn(flows);
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ ArrayList<IFlowPath> returnedFlows = fm.getAllFlowsSummary(null, 0);
+
+ // verify the test
+ verifyAll();
+ assertEquals(3, returnedFlows.size());
+ assertEquals(1, new FlowId(returnedFlows.get(0).getFlowId()).value());
+ assertEquals(5, new FlowId(returnedFlows.get(1).getFlowId()).value());
+ assertEquals(10, new FlowId(returnedFlows.get(2).getFlowId()).value());
+ }
+
+ /**
+ * Test method for {@link FlowManager#getAllFlows()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testGetAllFlowsSuccessNormally() throws Exception {
+ // instantiate required objects
+ ArrayList<IFlowPath> flowPaths = new ArrayList<IFlowPath>();
+ flowPaths.add(createIFlowPathMock(1, "caller id", 1, 1, 2, 2));
+ flowPaths.add(createIFlowPathMock(1, "caller id", 2, 5, 3, 5));
+ FlowManager fm = new FlowManager();
+
+ // setup expectations
+ expectInitWithContext();
+ expect(op.getAllFlowPaths()).andReturn(flowPaths);
+ op.commit();
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ ArrayList<FlowPath> flows = fm.getAllFlows();
+
+ // verify the test
+ verifyAll();
+ assertEquals(2, flows.size());
+ assertEquals(new SwitchPort(new Dpid(1), new Port((short)1)).toString(),
+ flows.get(0).dataPath().srcPort().toString());
+ assertEquals(new SwitchPort(new Dpid(2), new Port((short)5)).toString(),
+ flows.get(1).dataPath().srcPort().toString());
+ // TODO: more asserts
+ // TODO: ignore seq. of the list
+ }
+
+ /**
+ * Test method for {@link FlowManager#addAndMaintainShortestPathFlow(FlowPath)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testAddAndMaintainShortestPathFlowSuccessNormally() throws Exception {
+ final String addFlow = "addFlow";
+
+ // create mock objects
+ FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, addFlow);
+
+ // instantiate required objects
+ DataPath dataPath = new DataPath();
+ dataPath.setSrcPort(new SwitchPort(new Dpid(1), new Port((short)3)));
+ dataPath.setDstPort(new SwitchPort(new Dpid(2), new Port((short)4)));
+ FlowEntryMatch match = new FlowEntryMatch();
+ FlowPath paramFlow = new FlowPath();
+ paramFlow.setFlowId(new FlowId(100));
+ paramFlow.setInstallerId(new CallerId("installer id"));
+ paramFlow.setDataPath(dataPath);
+ paramFlow.setFlowEntryMatch(match);
+
+ // setup expectations
+ expectInitWithContext();
+ expectPrivate(fm, addFlow,
+ EasyMock.anyObject(FlowPath.class),
+ EasyMock.anyObject(FlowId.class),
+ EasyMock.anyObject(String.class)
+ ).andAnswer(new IAnswer<Object>() {
+ public Object answer() throws Exception {
+ FlowPath flowPath = (FlowPath)EasyMock.getCurrentArguments()[0];
+ assertEquals(flowPath.flowId().value(), 100);
+ assertEquals(flowPath.installerId().toString(), "installer id");
+ assertEquals(flowPath.dataPath().srcPort().toString(),
+ new SwitchPort(new Dpid(1), new Port((short)3)).toString());
+
+ String dataPathSummary = (String)EasyMock.getCurrentArguments()[2];
+ assertEquals(dataPathSummary, "X");
+
+ return true;
+ }
+ });
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ FlowPath resultFlow = fm.addAndMaintainShortestPathFlow(paramFlow);
+
+ // verify the test
+ verifyAll();
+ assertEquals(paramFlow.flowId().value(), resultFlow.flowId().value());
+ assertEquals(paramFlow.installerId().toString(), resultFlow.installerId().toString());
+ assertEquals(paramFlow.dataPath().toString(), resultFlow.dataPath().toString());
+ assertEquals(paramFlow.flowEntryMatch().toString(), resultFlow.flowEntryMatch().toString());
+ }
+
+ /**
+ * Test method for {@link FlowManager#measurementStorePathFlow(FlowPath)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testMeasurementStorePathFlowSuccessNormally() throws Exception {
+ // instantiate required objects
+ FlowPath paramFlow = createTestFlowPath(100, "installer id", 1, 3, 2, 4);
+ Map<Long, Object> shortestPathMap = new HashMap<Long, Object>();
+ FlowManager fm = new FlowManager();
+
+ // setup expectations
+ expectInitWithContext();
+ expect((Map<Long,Object>)topoRouteService.prepareShortestPathTopo()
+ ).andReturn(shortestPathMap);
+ expect(topoRouteService.getTopoShortestPath(
+ shortestPathMap,
+ paramFlow.dataPath().srcPort(),
+ paramFlow.dataPath().dstPort())).andReturn(null);
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ FlowPath resultFlowPath = fm.measurementStorePathFlow(paramFlow);
+
+ // verify the test
+ verifyAll();
+ assertEquals(paramFlow.flowId().value(), resultFlowPath.flowId().value());
+ assertEquals(paramFlow.installerId().toString(), resultFlowPath.installerId().toString());
+ assertEquals(paramFlow.dataPath().toString(), resultFlowPath.dataPath().toString());
+ assertEquals(paramFlow.flowEntryMatch().toString(), resultFlowPath.flowEntryMatch().toString());
+ }
+
+ /**
+ * Test method for {@link FlowManager#measurementInstallPaths(Integer)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testMeasurementInstallPathsSuccessNormally() throws Exception {
+ final String addFlow = "addFlow";
+
+ // create mock objects
+ FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, addFlow);
+
+ // instantiate required objects
+ FlowPath flow1 = createTestFlowPath(1, "installer id", 1, 2, 3, 4);
+ FlowPath flow2 = createTestFlowPath(2, "installer id", 2, 3, 4, 5);
+ FlowPath flow3 = createTestFlowPath(3, "installer id", 3, 4, 5, 6);
+ Map<Long, Object> shortestPathMap = new HashMap<Long, Object>();
+
+ // setup expectations
+ expectInitWithContext();
+ expect((Map<Long,Object>)topoRouteService.prepareShortestPathTopo()
+ ).andReturn(shortestPathMap);
+
+ expect(topoRouteService.getTopoShortestPath(
+ shortestPathMap,
+ flow1.dataPath().srcPort(),
+ flow1.dataPath().dstPort())).andReturn(null);
+
+ expect(topoRouteService.getTopoShortestPath(
+ shortestPathMap,
+ flow2.dataPath().srcPort(),
+ flow2.dataPath().dstPort())).andReturn(null);
+
+ expect(topoRouteService.getTopoShortestPath(
+ shortestPathMap,
+ flow3.dataPath().srcPort(),
+ flow3.dataPath().dstPort())).andReturn(null);
+
+ expectPrivate(fm, addFlow,
+ EasyMock.cmpEq(flow1),
+ EasyMock.anyObject(FlowId.class),
+ EasyMock.anyObject(String.class)).andReturn(true);
+
+ expectPrivate(fm, addFlow,
+ EasyMock.cmpEq(flow2),
+ EasyMock.anyObject(FlowId.class),
+ EasyMock.anyObject(String.class)).andReturn(true);
+
+ expectPrivate(fm, addFlow,
+ EasyMock.cmpEq(flow3),
+ EasyMock.anyObject(FlowId.class),
+ EasyMock.anyObject(String.class)).andReturn(true);
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ fm.measurementStorePathFlow(flow1);
+ fm.measurementStorePathFlow(flow2);
+ fm.measurementStorePathFlow(flow3);
+ Boolean result = fm.measurementInstallPaths(3);
+
+ // verify the test
+ verifyAll();
+ assertTrue(result);
+ }
+
+ /**
+ * Test method for {@link FlowManager#measurementGetInstallPathsTimeNsec()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testMeasurementGetInstallPathsTimeNsecSuccessNormally() throws Exception {
+ final String addFlow = "addFlow";
+
+ // create mock objects
+ FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, addFlow);
+ mockStaticPartial(System.class, "nanoTime");
+
+ // instantiate required objects
+ FlowPath flow1 = createTestFlowPath(1, "installer id", 1, 2, 3, 4);
+ Map<Long, Object> shortestPathMap = new HashMap<Long, Object>();
+
+ // setup expectations
+ expectInitWithContext();
+ expect(System.nanoTime()).andReturn(new Long(100000));
+ expect(System.nanoTime()).andReturn(new Long(110000));
+ expect((Map<Long,Object>)topoRouteService.prepareShortestPathTopo()
+ ).andReturn(shortestPathMap);
+ expect(topoRouteService.getTopoShortestPath(
+ shortestPathMap,
+ flow1.dataPath().srcPort(),
+ flow1.dataPath().dstPort())).andReturn(null);
+ expectPrivate(fm, addFlow,
+ EasyMock.cmpEq(flow1),
+ EasyMock.anyObject(FlowId.class),
+ EasyMock.anyObject(String.class)).andReturn(true);
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ fm.measurementStorePathFlow(flow1).toString();
+ fm.measurementInstallPaths(1);
+ Long result = fm.measurementGetInstallPathsTimeNsec();
+
+ // verify the test
+ verifyAll();
+ assertEquals(new Long(10000), result);
+ }
+
+ /**
+ * Test method for {@link FlowManager#measurementGetPerFlowInstallTime()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testMeasurementGetPerFlowInstallTimeSuccessNormally() throws Exception {
+ final String addFlow = "addFlow";
+
+ // create mock objects
+ FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, addFlow);
+
+ // instantiate required objects
+ FlowPath flow1 = createTestFlowPath(1, "installer id", 1, 2, 3, 4);
+ Map<Long, Object> shortestPathMap = new HashMap<Long, Object>();
+
+ // setup expectations
+ expectInitWithContext();
+ expect((Map<Long,Object>)topoRouteService.prepareShortestPathTopo()
+ ).andReturn(shortestPathMap);
+
+ expect(topoRouteService.getTopoShortestPath(
+ shortestPathMap,
+ flow1.dataPath().srcPort(),
+ flow1.dataPath().dstPort())).andReturn(null);
+
+ expectPrivate(fm, addFlow,
+ EasyMock.cmpEq(flow1),
+ EasyMock.anyObject(FlowId.class),
+ EasyMock.anyObject(String.class)).andReturn(true);
+
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ fm.measurementStorePathFlow(flow1);
+ fm.measurementInstallPaths(10);
+ String result = fm.measurementGetPerFlowInstallTime();
+
+ // verify the test
+ verifyAll();
+ assertTrue(result.startsWith("ThreadAndTimePerFlow"));
+ }
+
+ /**
+ * Test method for {@link FlowManager#measurementClearAllPaths()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testMeasurementClearAllPathsSuccessNormally() throws Exception {
+ // instantiate required objects
+ FlowPath paramFlow = createTestFlowPath(100, "installer id", 1, 3, 2, 4);
+ Map<Long, Object> shortestPathMap = new HashMap<Long, Object>();
+
+ // setup expectations
+ expectInitWithContext();
+ expect((Map<Long,Object>)topoRouteService.prepareShortestPathTopo()
+ ).andReturn(shortestPathMap);
+ expect(topoRouteService.getTopoShortestPath(
+ shortestPathMap,
+ paramFlow.dataPath().srcPort(),
+ paramFlow.dataPath().dstPort())).andReturn(null);
+ topoRouteService.dropShortestPathTopo(shortestPathMap);
+
+ // start the test
+ replayAll();
+
+ FlowManager fm = new FlowManager();
+ fm.init(context);
+ fm.measurementStorePathFlow(paramFlow);
+ Boolean result = fm.measurementClearAllPaths();
+
+ // verify the test
+ verifyAll();
+ assertTrue(result);
+ assertEquals(new Long(0), fm.measurementGetInstallPathsTimeNsec());
+ assertEquals("", fm.measurementGetPerFlowInstallTime());
+ }
+
+
+ // INetMapStorage methods
+
+
+ /**
+ * Test method for {@link FlowManager#init(String)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testInitSuccessNormally() throws Exception {
+ // create mock objects
+ op = createMock(GraphDBOperation.class);
+
+ // setup expectations
+ expectNew(GraphDBOperation.class, "/dummy/path").andReturn(op);
+
+ // start the test
+ replayAll();
+
+ FlowManager fm = new FlowManager();
+ fm.init("/dummy/path");
+
+ // verify the test
+ verifyAll();
+ }
+
+ /**
+ * Test method for {@link FlowManager#close()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testCloseSuccessNormally() throws Exception {
+ // instantiate required objects
+ FlowManager fm = new FlowManager();
+
+ // setup expectations
+ expectInitWithContext();
+ op.close();
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ fm.close();
+
+ // verify the test
+ verifyAll();
+ }
+
+
+ // IFloodlightModule methods
+
+
+ /**
+ * Test method for {@link FlowManager#getModuleServices()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testGetModuleServicesSuccessNormally() throws Exception {
+ // instantiate required objects
+ FlowManager fm = new FlowManager();
+
+ // setup expectations
+ expectInitWithContext();
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ Collection<Class<? extends IFloodlightService>> l = fm.getModuleServices();
+
+ // verify the test
+ verifyAll();
+ assertEquals(1, l.size());
+ assertEquals(IFlowService.class, l.iterator().next());
+ }
+
+ /**
+ * Test method for {@link FlowManager#getServiceImpls()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testGetServiceImplsSuccessNormally() throws Exception {
+ // instantiate required objects
+ FlowManager fm = new FlowManager();
+
+ // setup expectations
+ expectInitWithContext();
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ Map<Class<? extends IFloodlightService>, IFloodlightService> si = fm.getServiceImpls();
+
+ // verify the test
+ verifyAll();
+ assertEquals(1, si.size());
+ assertTrue(si.containsKey(IFlowService.class));
+ assertEquals(fm, si.get(IFlowService.class));
+ }
+
+ /**
+ * Test method for {@link FlowManager#getModuleDependencies()}.
+ * @throws Exception
+ */
+ @Test
+ public final void testGetModuleDependenciesSuccessNormally() throws Exception {
+ // instantiate required objects
+ FlowManager fm = new FlowManager();
+
+ // setup expectations
+ expectInitWithContext();
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ Collection<Class<? extends IFloodlightService>> md = fm.getModuleDependencies();
+
+ // verify the test
+ verifyAll();
+ assertEquals(3, md.size());
+ assertTrue(md.contains(IFloodlightProviderService.class));
+ assertTrue(md.contains(ITopoRouteService.class));
+ assertTrue(md.contains(IRestApiService.class));
+ }
+
+ /**
+ * Test method for {@link FlowManager#init(FloodlightModuleContext)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testInitWithFloodlightModuleContextSuccessNormally() throws Exception {
+ // instantiate required objects
+ FlowManager fm = new FlowManager();
+
+ // setup expectations
+ expectInitWithContext();
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+
+ // verify the test
+ verifyAll();
+ }
+
+ /**
+ * Test method for {@link FlowManager#startUp(FloodlightModuleContext)}.
+ * @throws Exception
+ */
+ @Test
+ public final void testStartupSuccessNormally() throws Exception {
+ // create mock objects
+ mockStaticPartial(Executors.class, "newScheduledThreadPool");
+ ScheduledExecutorService scheduler = createMock(ScheduledExecutorService.class);
+
+
+ // instantiate required objects
+ FlowManager fm = new FlowManager();
+
+ // setup expectations
+ expectInitWithContext();
+ expect(Executors.newScheduledThreadPool(1)).andReturn(scheduler);
+ expect(Executors.newScheduledThreadPool(1)).andReturn(scheduler);
+ expect(scheduler.scheduleAtFixedRate(
+ EasyMock.anyObject(Runnable.class),
+ EasyMock.anyLong(),
+ EasyMock.anyLong(),
+ EasyMock.anyObject(TimeUnit.class))).andReturn(null).times(2);
+ restApi.addRestletRoutable(EasyMock.anyObject(FlowWebRoutable.class));
+
+ // start the test
+ replayAll();
+
+ fm.init(context);
+ fm.startUp(context);
+
+ // verify the test
+ verifyAll();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/net/onrc/onos/ofcontroller/routing/TopoRouteServiceTest.java b/src/test/java/net/onrc/onos/ofcontroller/routing/TopoRouteServiceTest.java
new file mode 100644
index 0000000..e6d7d16
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/routing/TopoRouteServiceTest.java
@@ -0,0 +1,234 @@
+package net.onrc.onos.ofcontroller.routing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.easymock.EasyMock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.TitanFactory;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
+
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+import net.onrc.onos.graph.GraphDBConnection;
+import net.onrc.onos.graph.GraphDBOperation;
+import net.onrc.onos.ofcontroller.core.internal.TestDatabaseManager;
+import net.onrc.onos.ofcontroller.routing.TopoRouteService;
+import net.onrc.onos.ofcontroller.util.DataPath;
+import net.onrc.onos.ofcontroller.util.Dpid;
+import net.onrc.onos.ofcontroller.util.Port;
+import net.onrc.onos.ofcontroller.util.SwitchPort;
+
+/**
+ * A class for testing the TopoRouteService class.
+ * @see net.onrc.onos.ofcontroller.routing.TopoRouteService
+ * @author Pavlin Radoslavov (pavlin@onlab.us)
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({TitanFactory.class, GraphDBConnection.class, GraphDBOperation.class, TopoRouteService.class})
+public class TopoRouteServiceTest {
+ String conf;
+ private GraphDBConnection conn = null;
+ private GraphDBOperation oper = null;
+ private TitanGraph titanGraph = null;
+ private TopoRouteService topoRouteService = null;
+
+ /**
+ * Setup the tests.
+ */
+ @Before
+ public void setUp() throws Exception {
+ conf = "/dummy/path/to/db";
+
+ //
+ // Make mock database.
+ // Replace TitanFactory.open() to return the mock database.
+ //
+ titanGraph = TestDatabaseManager.getTestDatabase();
+ PowerMock.mockStatic(TitanFactory.class);
+ EasyMock.expect(TitanFactory.open((String)EasyMock.anyObject())).andReturn(titanGraph);
+ PowerMock.replay(TitanFactory.class);
+
+ // Create the connection to the database
+ conn = GraphDBConnection.getInstance(conf);
+ oper = new GraphDBOperation(conn);
+
+ // Populate the database
+ TestDatabaseManager.populateTestData(titanGraph);
+
+ // Prepare the TopoRouteService instance
+ topoRouteService = new TopoRouteService();
+ topoRouteService.setDbOperationHandler(oper);
+ }
+
+ /**
+ * Cleanup after the tests.
+ */
+ @After
+ public void tearDown() throws Exception {
+ titanGraph.shutdown();
+ TestDatabaseManager.deleteTestDatabase();
+ }
+
+ /**
+ * Test method TopoRouteService.getTopoShortestPath()
+ *
+ * @see net.onrc.onos.ofcontroller.routing.TopoRouteService#getTopoShortestPath
+ */
+ @Test
+ public void test_getTopoShortestPath() {
+ DataPath dataPath = null;
+ String srcDpidStr = "00:00:00:00:00:00:0a:01";
+ String dstDpidStr = "00:00:00:00:00:00:0a:06";
+ short srcPortShort = 1;
+ short dstPortShort = 1;
+
+ //
+ // Initialize the source and destination points
+ //
+ Dpid srcDpid = new Dpid(srcDpidStr);
+ Port srcPort = new Port(srcPortShort);
+ Dpid dstDpid = new Dpid(dstDpidStr);
+ Port dstPort = new Port(dstPortShort);
+ SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
+ SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
+
+ //
+ // Test a valid Shortest-Path computation
+ //
+ Map<Long, ?> shortestPathTopo =
+ topoRouteService.prepareShortestPathTopo();
+ dataPath = topoRouteService.getTopoShortestPath(shortestPathTopo,
+ srcSwitchPort,
+ dstSwitchPort);
+ assertTrue(dataPath != null);
+ String dataPathSummaryStr = dataPath.dataPathSummary();
+ // System.out.println(dataPathSummaryStr);
+ String expectedResult = "1/00:00:00:00:00:00:0a:01/2;1/00:00:00:00:00:00:0a:03/2;2/00:00:00:00:00:00:0a:04/3;1/00:00:00:00:00:00:0a:06/1;";
+ assertEquals(dataPathSummaryStr, expectedResult);
+
+ //
+ // Test Shortest-Path computation to non-existing destination
+ //
+ String noSuchDpidStr = "ff:ff:00:00:00:00:0a:06";
+ Dpid noSuchDstDpid = new Dpid(noSuchDpidStr);
+ SwitchPort noSuchDstSwitchPort = new SwitchPort(noSuchDstDpid, dstPort);
+ dataPath = topoRouteService.getTopoShortestPath(shortestPathTopo,
+ srcSwitchPort,
+ noSuchDstSwitchPort);
+ assertTrue(dataPath == null);
+
+ topoRouteService.dropShortestPathTopo(shortestPathTopo);
+ }
+
+ /**
+ * Test method TopoRouteService.getShortestPath()
+ *
+ * @see net.onrc.onos.ofcontroller.routing.TopoRouteService#getShortestPath
+ */
+ @Test
+ public void test_getShortestPath() {
+ DataPath dataPath = null;
+ String srcDpidStr = "00:00:00:00:00:00:0a:01";
+ String dstDpidStr = "00:00:00:00:00:00:0a:06";
+ short srcPortShort = 1;
+ short dstPortShort = 1;
+
+ //
+ // Initialize the source and destination points
+ //
+ Dpid srcDpid = new Dpid(srcDpidStr);
+ Port srcPort = new Port(srcPortShort);
+ Dpid dstDpid = new Dpid(dstDpidStr);
+ Port dstPort = new Port(dstPortShort);
+ SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
+ SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
+
+ //
+ // Test a valid Shortest-Path computation
+ //
+ dataPath = topoRouteService.getShortestPath(srcSwitchPort,
+ dstSwitchPort);
+ assertTrue(dataPath != null);
+ String dataPathSummaryStr = dataPath.dataPathSummary();
+ // System.out.println(dataPathSummaryStr);
+ String expectedResult = "1/00:00:00:00:00:00:0a:01/2;1/00:00:00:00:00:00:0a:03/2;2/00:00:00:00:00:00:0a:04/3;1/00:00:00:00:00:00:0a:06/1;";
+ assertEquals(dataPathSummaryStr, expectedResult);
+
+ //
+ // Test Shortest-Path computation to non-existing destination
+ //
+ String noSuchDpidStr = "ff:ff:00:00:00:00:0a:06";
+ Dpid noSuchDstDpid = new Dpid(noSuchDpidStr);
+ SwitchPort noSuchDstSwitchPort = new SwitchPort(noSuchDstDpid, dstPort);
+
+ dataPath = topoRouteService.getShortestPath(srcSwitchPort,
+ noSuchDstSwitchPort);
+ assertTrue(dataPath == null);
+ }
+
+ /**
+ * Test method TopoRouteService.routeExists()
+ *
+ * @see net.onrc.onos.ofcontroller.routing.TopoRouteService#routeExists
+ */
+ @Test
+ public void test_routeExists() {
+ Boolean result;
+ String srcDpidStr = "00:00:00:00:00:00:0a:01";
+ String dstDpidStr = "00:00:00:00:00:00:0a:06";
+ short srcPortShort = 1;
+ short dstPortShort = 1;
+
+ //
+ // Initialize the source and destination points
+ //
+ Dpid srcDpid = new Dpid(srcDpidStr);
+ Port srcPort = new Port(srcPortShort);
+ Dpid dstDpid = new Dpid(dstDpidStr);
+ Port dstPort = new Port(dstPortShort);
+ SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
+ SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
+
+ //
+ // Test a valid route
+ //
+ result = topoRouteService.routeExists(srcSwitchPort, dstSwitchPort);
+ assertTrue(result == true);
+
+ //
+ // Test a non-existing route
+ //
+ String noSuchDpidStr = "ff:ff:00:00:00:00:0a:06";
+ Dpid noSuchDstDpid = new Dpid(noSuchDpidStr);
+ SwitchPort noSuchDstSwitchPort = new SwitchPort(noSuchDstDpid, dstPort);
+ result = topoRouteService.routeExists(srcSwitchPort,
+ noSuchDstSwitchPort);
+ assertTrue(result != true);
+ }
+}
diff --git a/src/test/java/net/onrc/onos/registry/controller/StandaloneRegistryTest.java b/src/test/java/net/onrc/onos/registry/controller/StandaloneRegistryTest.java
new file mode 100644
index 0000000..7c4a1a0
--- /dev/null
+++ b/src/test/java/net/onrc/onos/registry/controller/StandaloneRegistryTest.java
@@ -0,0 +1,461 @@
+package net.onrc.onos.registry.controller;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.openflow.util.HexString;
+
+/**
+ * Unit test for {@link StandaloneRegistry}.
+ * @author Naoki Shiota
+ *
+ */
+public class StandaloneRegistryTest {
+ protected static final long TIMEOUT_MSEC = 1000;
+
+ protected StandaloneRegistry registry;
+
+ /**
+ * Implementation of {@link ControlChangeCallback} which defines callback interfaces called by Registry.
+ * This class remembers past callback parameters and provides methods to access them.
+ * This class also provides CountDownLatch so one can wait until the callback be called
+ * specific times (specified by constructor parameter). Particularly, the first time callback
+ * called is supposed for registration, this class has an independent latch to wait for
+ * the first callback.
+ * @author Naoki Shiota
+ */
+ public static class LoggingCallback implements ControlChangeCallback {
+ private LinkedList<Long> dpidsCalledback = new LinkedList<Long>();
+ private LinkedList<Boolean> controlsCalledback = new LinkedList<Boolean>();
+ private CountDownLatch lock = null, registerLock = null;;
+
+ /**
+ * Constructor with number of times callback to be called.
+ * @param numberToCall Number of times expected callback to be called
+ */
+ public LoggingCallback(int numberToCall) {
+ lock = new CountDownLatch(numberToCall);
+ registerLock = new CountDownLatch(1);
+ }
+
+ /**
+ * Wait until registration is finished (callback is called for the first time).
+ * @throws InterruptedException
+ */
+ public void waitForRegistration() throws InterruptedException {
+ registerLock.await();
+ }
+
+ /**
+ * Wait for registration specifying timeout.
+ * @param msec Milliseconds to timeout
+ * @throws InterruptedException
+ */
+ public void waitForRegistration(long msec) throws InterruptedException {
+ registerLock.await(msec, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Wait until callback is called specific times.
+ * @throws InterruptedException
+ */
+ public void waitUntilCalled() throws InterruptedException {
+ lock.await();
+ }
+
+ /**
+ * Wait until callback is called specific times, specifying timeout.
+ * @param msec Milliseconds to timeout
+ * @throws InterruptedException
+ */
+ public void waitUntilCalled(long msec) throws InterruptedException {
+ lock.await(msec, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Get DPID parameter given by specific callback time.
+ * @param index Specify which time to get parameter
+ * @return DPID value by number.
+ */
+ public Long getDpid(int index) { return dpidsCalledback.get(index); }
+
+ /**
+ * Get hasControl parameter given by specific callback time.
+ * @param index Specify which time to get parameter
+ * @return hasControl value
+ */
+ public Boolean getControl(int index) { return controlsCalledback.get(index); }
+
+ /**
+ * Get DPID parameter given by latest call.
+ * @return DPID value by number
+ */
+ public Long getLatestDpid() { return dpidsCalledback.peekLast(); }
+
+ /**
+ * Get hasControl parameter given by latest call
+ * @return hasControl value
+ */
+ public Boolean getLatestControl() { return controlsCalledback.peekLast(); }
+
+ @Override
+ public void controlChanged(long dpid, boolean hasControl) {
+ dpidsCalledback.addLast(dpid);
+ controlsCalledback.addLast(hasControl);
+
+ lock.countDown();
+ registerLock.countDown();
+ }
+ };
+
+ @Before
+ public void setUp() throws Exception {
+ FloodlightModuleContext fmc = new FloodlightModuleContext();
+ registry = new StandaloneRegistry();
+ registry.init(fmc);
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test if {@link StandaloneRegistry#registerController(String)} can run without error.
+ */
+ @Test
+ public void testRegisterController() {
+ String controllerIdToRegister = "test";
+ try {
+ registry.registerController(controllerIdToRegister);
+ } catch (RegistryException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ // Register Controller ID doubly
+ try {
+ registry.registerController(controllerIdToRegister);
+ fail("Double registration goes through without exception");
+ } catch (RegistryException e) {
+ // expected behavior
+ }
+ }
+
+ /**
+ * Test if {@link StandaloneRegistry#getControllerId()} can return correct ID.
+ * @throws RegistryException
+ */
+ @Test
+ public void testGetControllerId() throws RegistryException {
+ String controllerIdToRegister = "test";
+
+ // try before controller is registered
+ String controllerId = registry.getControllerId();
+ assertNull(controllerId);
+
+ // register
+ registry.registerController(controllerIdToRegister);
+
+ // call getControllerId and verify
+ controllerId = registry.getControllerId();
+ assertNotNull(controllerId);
+ assertEquals(controllerIdToRegister, controllerId);
+ }
+
+ /**
+ * Test if {@link StandaloneRegistry#getAllControllers()} can return correct list of controllers.
+ * @throws RegistryException
+ */
+ @Test
+ public void testGetAllControllers() throws RegistryException {
+ String controllerIdToRegister = "test";
+
+ // Test before register controller
+ try {
+ Collection<String> ctrls = registry.getAllControllers();
+ assertFalse(ctrls.contains(controllerIdToRegister));
+ } catch (RegistryException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ // register
+ registry.registerController(controllerIdToRegister);
+
+ // Test after register controller
+ try {
+ Collection<String> ctrls = registry.getAllControllers();
+ assertTrue(ctrls.contains(controllerIdToRegister));
+ } catch (RegistryException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Test if {@link StandaloneRegistry#requestControl(long, ControlChangeCallback)} can correctly take control for switch so that callback is called.
+ * @throws RegistryException
+ * @throws InterruptedException
+ */
+ @Test
+ public void testRequestControl() throws InterruptedException, RegistryException {
+ String controllerId = "test";
+ registry.registerController(controllerId);
+
+ LoggingCallback callback = new LoggingCallback(1);
+ long dpidToRequest = 1000L;
+
+ try {
+ registry.requestControl(dpidToRequest, callback);
+ } catch (RegistryException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ callback.waitForRegistration();
+
+ long dpidCallback = callback.getLatestDpid();
+ boolean controlCallback = callback.getLatestControl();
+
+ assertEquals(dpidToRequest, dpidCallback);
+ assertTrue(controlCallback);
+ }
+
+ /**
+ * Test if {@link StandaloneRegistry#releaseControl(long)} can correctly release the control so that callback is called.
+ * @throws InterruptedException
+ * @throws RegistryException
+ */
+ @Test
+ public void testReleaseControl() throws InterruptedException, RegistryException {
+ String controllerId = "test";
+ registry.registerController(controllerId);
+
+ long dpidToRequest = 1000L;
+ LoggingCallback callback = new LoggingCallback(2);
+
+ // to request and wait to take control
+ registry.requestControl(dpidToRequest, callback);
+ callback.waitForRegistration();
+
+ registry.releaseControl(dpidToRequest);
+
+ // verify
+ callback.waitUntilCalled();
+ assertEquals(dpidToRequest, (long)callback.getLatestDpid());
+ assertFalse(callback.getLatestControl());
+ }
+
+ /**
+ * Test if {@link StandaloneRegistry#hasControl(long)} returns correct status.
+ * @throws InterruptedException
+ * @throws RegistryException
+ */
+ @Test
+ public void testHasControl() throws InterruptedException, RegistryException {
+ String controllerId = "test";
+ registry.registerController(controllerId);
+
+ long dpidToRequest = 1000L;
+ LoggingCallback callback = new LoggingCallback(2);
+
+ // Test before request control
+ assertFalse(registry.hasControl(dpidToRequest));
+
+ registry.requestControl(dpidToRequest, callback);
+ callback.waitForRegistration();
+
+ // Test after take control
+ assertTrue(registry.hasControl(dpidToRequest));
+
+ registry.releaseControl(dpidToRequest);
+
+ callback.waitUntilCalled();
+
+ // Test after release control
+ assertFalse(registry.hasControl(dpidToRequest));
+ }
+
+ /**
+ * Test if {@link StandaloneRegistry#getControllerForSwitch(long)} returns correct controller ID.
+ * @throws InterruptedException
+ * @throws RegistryException
+ */
+ @Test
+ public void testGetControllerForSwitch() throws InterruptedException, RegistryException {
+ String controllerId = "test";
+ registry.registerController(controllerId);
+
+ long dpidToRequest = 1000L;
+ LoggingCallback callback = new LoggingCallback(2);
+
+ // Test before request control
+ try {
+ String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
+ assertNotEquals(controllerId,controllerForSw);
+ } catch (RegistryException e) {
+ fail("Failed before request control : " + e.getMessage());
+ e.printStackTrace();
+ }
+
+ registry.requestControl(dpidToRequest, callback);
+ callback.waitForRegistration();
+
+ // Test after take control
+ try {
+ String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
+ assertEquals(controllerId,controllerForSw);
+ } catch (RegistryException e) {
+ fail("Failed after take control : " + e.getMessage());
+ e.printStackTrace();
+ }
+
+ registry.releaseControl(dpidToRequest);
+ callback.waitUntilCalled();
+
+ // Test after release control
+ try {
+ String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
+ assertNotEquals(controllerId,controllerForSw);
+ } catch (RegistryException e) {
+ fail("Failed after release control : " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Test if {@link StandaloneRegistry#getAllSwitches()} returns correct list of switches.
+ * @throws InterruptedException
+ * @throws RegistryException
+ */
+ @Test
+ public void testGetAllSwitches() throws InterruptedException, RegistryException {
+ String controllerId = "test";
+ registry.registerController(controllerId);
+
+ long dpidToRequest = 1000L;
+ String dpidToRequestStr = HexString.toHexString(dpidToRequest);
+ LoggingCallback callback = new LoggingCallback(2);
+
+ // Test before request control
+ Map<String, List<ControllerRegistryEntry>> switches = registry.getAllSwitches();
+ assertNotNull(switches);
+ assertFalse(switches.keySet().contains(dpidToRequestStr));
+
+ registry.requestControl(dpidToRequest, callback);
+ callback.waitForRegistration();
+
+ // Test after take control
+ switches = registry.getAllSwitches();
+ assertNotNull(switches);
+ assertTrue(switches.keySet().contains(dpidToRequestStr));
+ int count = 0;
+ for(ControllerRegistryEntry ctrl : switches.get(dpidToRequestStr)) {
+ if(ctrl.getControllerId().equals(controllerId)) {
+ ++count;
+ }
+ }
+ assertEquals(1,count);
+
+ registry.releaseControl(dpidToRequest);
+ callback.waitUntilCalled();
+
+ // Test after release control
+ switches = registry.getAllSwitches();
+ assertNotNull(switches);
+ assertFalse(switches.keySet().contains(dpidToRequestStr));
+ }
+
+ /**
+ * Test if {@link StandaloneRegistry#getSwitchesControlledByController(String)} returns correct list of switches.
+ * @throws InterruptedException
+ * @throws RegistryException
+ */
+ // TODO: remove @Ignore after implement StandaloneRegistry#getSwitchesControlledByController
+ @Ignore @Test
+ public void testGetSwitchesControlledByController() throws InterruptedException, RegistryException {
+ String controllerId = "test";
+ registry.registerController(controllerId);
+
+ long dpidToRequest = 1000L;
+ String dpidToRequestStr = HexString.toHexString(dpidToRequest);
+ LoggingCallback callback = new LoggingCallback(2);
+
+ // Test before request control
+ Collection<Long> switches = registry.getSwitchesControlledByController(controllerId);
+ assertNotNull(switches);
+ assertFalse(switches.contains(dpidToRequestStr));
+
+ registry.requestControl(dpidToRequest, callback);
+ callback.waitForRegistration();
+
+ // Test after take control
+ switches = registry.getSwitchesControlledByController(controllerId);
+ assertNotNull(switches);
+ assertTrue(switches.contains(dpidToRequestStr));
+ int count = 0;
+ for(Long dpid : switches) {
+ if((long)dpid == dpidToRequest) {
+ ++count;
+ }
+ }
+ assertEquals(1, count);
+
+ registry.releaseControl(dpidToRequest);
+ callback.waitUntilCalled();
+
+ // Test after release control
+ switches = registry.getSwitchesControlledByController(controllerId);
+ assertNotNull(switches);
+ assertFalse(switches.contains(dpidToRequestStr));
+ }
+
+ /**
+ * Test if {@link StandaloneRegistry#allocateUniqueIdBlock()} returns appropriate object.
+ * Get bulk of IdBlocks and check if they do have unique range of IDs.
+ */
+ @Test
+ public void testAllocateUniqueIdBlock() {
+ // Number of blocks to be verified that any of them has unique block
+ final int NUM_BLOCKS = 100;
+ ArrayList<IdBlock> blocks = new ArrayList<IdBlock>(NUM_BLOCKS);
+
+ for(int i = 0; i < NUM_BLOCKS; ++i) {
+ blocks.add(registry.allocateUniqueIdBlock());
+ }
+
+ for(int i = 0; i < NUM_BLOCKS; ++i) {
+ IdBlock block1 = blocks.get(i);
+ for(int j = i + 1; j < NUM_BLOCKS; ++j) {
+ IdBlock block2 = blocks.get(j);
+ IdBlock lower,higher;
+
+ if(block1.getStart() < block2.getStart()) {
+ lower = block1;
+ higher = block2;
+ } else {
+ lower = block2;
+ higher = block1;
+ }
+
+ assertTrue(lower.getSize() > 0L);
+ assertTrue(higher.getSize() > 0L);
+ assertTrue(lower.getEnd() < higher.getStart());
+ }
+ }
+ }
+}
diff --git a/src/test/java/net/onrc/onos/registry/controller/ZookeeperRegistryTest.java b/src/test/java/net/onrc/onos/registry/controller/ZookeeperRegistryTest.java
new file mode 100644
index 0000000..3314ad2
--- /dev/null
+++ b/src/test/java/net/onrc/onos/registry/controller/ZookeeperRegistryTest.java
@@ -0,0 +1,597 @@
+package net.onrc.onos.registry.controller;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.test.FloodlightTestCase;
+import net.onrc.onos.registry.controller.StandaloneRegistryTest.LoggingCallback;
+import net.onrc.onos.registry.controller.ZookeeperRegistry.SwitchLeaderListener;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.openflow.util.HexString;
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.netflix.curator.RetryPolicy;
+import com.netflix.curator.framework.CuratorFramework;
+import com.netflix.curator.framework.CuratorFrameworkFactory;
+import com.netflix.curator.framework.listen.ListenerContainer;
+import com.netflix.curator.framework.recipes.atomic.AtomicValue;
+import com.netflix.curator.framework.recipes.atomic.DistributedAtomicLong;
+import com.netflix.curator.framework.recipes.cache.ChildData;
+import com.netflix.curator.framework.recipes.cache.PathChildrenCache;
+import com.netflix.curator.framework.recipes.cache.PathChildrenCacheEvent;
+import com.netflix.curator.framework.recipes.cache.PathChildrenCacheListener;
+import com.netflix.curator.framework.recipes.cache.PathChildrenCache.StartMode;
+import com.netflix.curator.framework.recipes.leader.LeaderLatch;
+import com.netflix.curator.x.discovery.ServiceCache;
+import com.netflix.curator.x.discovery.ServiceCacheBuilder;
+import com.netflix.curator.x.discovery.ServiceDiscovery;
+import com.netflix.curator.x.discovery.ServiceDiscoveryBuilder;
+import com.netflix.curator.x.discovery.ServiceInstance;
+
+/**
+ * Unit test for {@link ZookeeperRegistry}.
+ * NOTE: {@link FloodlightTestCase} conflicts with PowerMock. If FloodLight-related methods need to be tested,
+ * implement another test class to test them.
+ * @author Naoki Shiota
+ *
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ZookeeperRegistry.class, CuratorFramework.class, CuratorFrameworkFactory.class,
+ ServiceDiscoveryBuilder.class, ServiceDiscovery.class, ServiceCache.class, PathChildrenCache.class,
+ ZookeeperRegistry.SwitchPathCacheListener.class})
+public class ZookeeperRegistryTest extends FloodlightTestCase {
+ private final static Long ID_BLOCK_SIZE = 0x100000000L;
+
+ protected ZookeeperRegistry registry;
+ protected CuratorFramework client;
+
+ protected PathChildrenCacheListener pathChildrenCacheListener;
+ protected final String CONTROLLER_ID = "controller2013";
+
+ /**
+ * Initialize {@link ZookeeperRegistry} Object and inject initial value with {@link ZookeeperRegistry#init(FloodlightModuleContext)} method.
+ * This setup code also tests {@link ZookeeperRegistry#init(FloodlightModuleContext)} method itself.
+ */
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ pathChildrenCacheListener = null;
+
+ // Mock of CuratorFramework
+ client = createCuratorFrameworkMock();
+
+ // Mock of CuratorFrameworkFactory
+ PowerMock.mockStatic(CuratorFrameworkFactory.class);
+ EasyMock.expect(CuratorFrameworkFactory.newClient((String)EasyMock.anyObject(),
+ EasyMock.anyInt(), EasyMock.anyInt(), (RetryPolicy)EasyMock.anyObject())).andReturn(client);
+ PowerMock.replay(CuratorFrameworkFactory.class);
+
+ FloodlightModuleContext fmc = new FloodlightModuleContext();
+ registry = new ZookeeperRegistry();
+ fmc.addService(ZookeeperRegistry.class, registry);
+
+ registry.init(fmc);
+
+ PowerMock.verify(client, CuratorFrameworkFactory.class);
+ }
+
+ /**
+ * Clean up member variables (empty for now).
+ */
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test if {@link ZookeeperRegistry#registerController(String)} method can go through without exception.
+ * (Exceptions are usually out of test target, but {@link ZookeeperRegistry#registerController(String)} throws an exception in case of invalid registration.)
+ */
+ @Test
+ public void testRegisterController() {
+ String controllerIdToRegister = "controller2013";
+
+ try {
+ registry.registerController(controllerIdToRegister);
+ } catch (RegistryException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Test if {@link ZookeeperRegistry#getControllerId()} correctly returns registered ID.
+ * @throws Exception
+ */
+ @Test
+ public void testGetControllerId() throws Exception {
+ String controllerIdToRegister = "controller1";
+
+ // try before controller is registered
+ String controllerId = registry.getControllerId();
+ assertNull(controllerId);
+
+ // register
+ registry.registerController(controllerIdToRegister);
+
+ // call getControllerId and verify
+ controllerId = registry.getControllerId();
+ assertNotNull(controllerId);
+ assertEquals(controllerIdToRegister, controllerId);
+ }
+
+ /**
+ * Test if {@link ZookeeperRegistry#getAllControllers()} returns all controllers.
+ * Controllers to be returned are injected while setup. See {@link ZookeeperRegistryTest#createCuratorFrameworkMock()}
+ * to what controllers are injected using mock {@link ServiceCache}.
+ * @throws Exception
+ */
+ @Test
+ public void testGetAllControllers() throws Exception {
+ String controllerIdRegistered = "controller1";
+ String controllerIdNotRegistered = "controller2013";
+
+ try {
+ Collection<String> ctrls = registry.getAllControllers();
+ assertTrue(ctrls.contains(controllerIdRegistered));
+ assertFalse(ctrls.contains(controllerIdNotRegistered));
+ } catch (RegistryException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Test if {@link ZookeeperRegistry#requestControl(long, net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback)}
+ * correctly take control of specific switch. Because {@link ZookeeperRegistry#requestControl(long, net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback)}
+ * doesn't return values, inject mock {@link LeaderLatch} object and verify latch is correctly set up.
+ * @throws Exception
+ */
+ @Test
+ public void testRequestControl() throws Exception {
+ // Mock LeaderLatch
+ LeaderLatch latch = EasyMock.createMock(LeaderLatch.class);
+ latch.addListener(EasyMock.anyObject(SwitchLeaderListener.class));
+ EasyMock.expectLastCall().once();
+ latch.start();
+ EasyMock.expectLastCall().once();
+ EasyMock.replay(latch);
+
+ PowerMock.expectNew(LeaderLatch.class,
+ EasyMock.anyObject(CuratorFramework.class), EasyMock.anyObject(String.class), EasyMock.anyObject(String.class))
+ .andReturn(latch).once();
+ PowerMock.replay(LeaderLatch.class);
+
+ String controllerId = "controller2013";
+ registry.registerController(controllerId);
+
+ LoggingCallback callback = new LoggingCallback(1);
+ long dpidToRequest = 2000L;
+
+ try {
+ registry.requestControl(dpidToRequest, callback);
+ } catch (RegistryException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ EasyMock.verify(latch);
+ }
+
+ /**
+ * Test if {@link ZookeeperRegistry#releaseControl(long)} correctly release control of specific switch.
+ * Because {@link ZookeeperRegistry#releaseControl(long)} doesn't return values, inject mock
+ * {@link LeaderLatch} object and verify latch is correctly set up.
+ * @throws Exception
+ */
+ @Test
+ public void testReleaseControl() throws Exception {
+ // Mock of LeaderLatch
+ LeaderLatch latch = EasyMock.createMock(LeaderLatch.class);
+ latch.addListener(EasyMock.anyObject(SwitchLeaderListener.class));
+ EasyMock.expectLastCall().once();
+ latch.start();
+ EasyMock.expectLastCall().once();
+ latch.removeAllListeners();
+ EasyMock.expectLastCall().once();
+ latch.close();
+ EasyMock.expectLastCall().once();
+ EasyMock.replay(latch);
+
+ PowerMock.expectNew(LeaderLatch.class,
+ EasyMock.anyObject(CuratorFramework.class), EasyMock.anyObject(String.class), EasyMock.anyObject(String.class))
+ .andReturn(latch).once();
+ PowerMock.replay(LeaderLatch.class);
+
+ String controllerId = "controller2013";
+ registry.registerController(controllerId);
+
+ long dpidToRequest = 2000L;
+ LoggingCallback callback = new LoggingCallback(1);
+
+ registry.requestControl(dpidToRequest, callback);
+ registry.releaseControl(dpidToRequest);
+
+ EasyMock.verify(latch);
+ }
+
+ /**
+ * Test if {@link ZookeeperRegistry#hasControl(long)} returns correct status whether controller has control of specific switch.
+ * @throws Exception
+ */
+ @Test
+ public void testHasControl() throws Exception {
+ // Mock of LeaderLatch
+ LeaderLatch latch = EasyMock.createMock(LeaderLatch.class);
+ latch.addListener(EasyMock.anyObject(SwitchLeaderListener.class));
+ EasyMock.expectLastCall().once();
+ latch.start();
+ EasyMock.expectLastCall().once();
+ EasyMock.expect(latch.hasLeadership()).andReturn(true).anyTimes();
+ latch.removeAllListeners();
+ EasyMock.expectLastCall().once();
+ latch.close();
+ EasyMock.expectLastCall().once();
+ EasyMock.replay(latch);
+
+ PowerMock.expectNew(LeaderLatch.class,
+ EasyMock.anyObject(CuratorFramework.class), EasyMock.anyObject(String.class), EasyMock.anyObject(String.class))
+ .andReturn(latch);
+ PowerMock.replay(LeaderLatch.class);
+
+ String controllerId = "controller2013";
+ registry.registerController(controllerId);
+
+ long dpidToRequest = 2000L;
+ LoggingCallback callback = new LoggingCallback(2);
+
+ // Test before request control
+ assertFalse(registry.hasControl(dpidToRequest));
+
+ registry.requestControl(dpidToRequest, callback);
+
+ // Test after request control
+ assertTrue(registry.hasControl(dpidToRequest));
+
+ registry.releaseControl(dpidToRequest);
+
+ // Test after release control
+ assertFalse(registry.hasControl(dpidToRequest));
+
+ EasyMock.verify(latch);
+ }
+
+ /**
+ * Test if {@link ZookeeperRegistry#getControllerForSwitch(long)} correctly returns controller ID of specific switch.
+ * Relation between controllers and switches are defined by {@link ZookeeperRegistryTest#setPathChildrenCache()} function.
+ * @throws Throwable
+ */
+ @Test
+ public void testGetControllerForSwitch() throws Throwable {
+ long dpidRegistered = 1000L;
+ long dpidNotRegistered = 2000L;
+
+ setPathChildrenCache();
+
+ String controllerForSw = registry.getControllerForSwitch(dpidRegistered);
+ assertEquals("controller1",controllerForSw);
+
+ controllerForSw = registry.getControllerForSwitch(dpidNotRegistered);
+ assertEquals(null, controllerForSw);
+ }
+
+ /**
+ * Test if {@link ZookeeperRegistry#getSwitchesControlledByController(String)} returns correct list of
+ * switches controlled by a controller.
+ * @throws Exception
+ */
+ // TODO: Test after getSwitchesControlledByController() is implemented.
+ @Ignore @Test
+ public void testGetSwitchesControlledByController() throws Exception {
+ String controllerIdRegistered = "controller1";
+ String dpidRegistered = HexString.toHexString(1000L);
+ String controllerIdNotRegistered = CONTROLLER_ID;
+
+ Collection<Long> switches = registry.getSwitchesControlledByController(controllerIdRegistered);
+ assertNotNull(switches);
+ assertTrue(switches.contains(dpidRegistered));
+
+ switches = registry.getSwitchesControlledByController(controllerIdNotRegistered);
+ assertNotNull(switches);
+ assertEquals(0, switches.size());
+ }
+
+ /**
+ * Test if {@link ZookeeperRegistry#getAllSwitches()} returns correct list of all switches.
+ * Switches are injected in {@link ZookeeperRegistryTest#setPathChildrenCache()} function.
+ * @throws Exception
+ */
+ @Test
+ public void testGetAllSwitches() throws Exception {
+ String [] dpids = {
+ HexString.toHexString(1000L),
+ HexString.toHexString(1001L),
+ HexString.toHexString(1002L),
+ };
+
+ setPathChildrenCache();
+
+ Map<String, List<ControllerRegistryEntry>> switches = registry.getAllSwitches();
+ assertNotNull(switches);
+ assertEquals(dpids.length, switches.size());
+ for(String dpid : dpids) {
+ assertTrue(switches.keySet().contains(dpid));
+ }
+ }
+
+ /**
+ * Test if {@link ZookeeperRegistry#allocateUniqueIdBlock()} can assign IdBlock without duplication.
+ */
+ @Test
+ public void testAllocateUniqueIdBlock() {
+ // Number of blocks to be verified that any of them has unique block
+ final int NUM_BLOCKS = 100;
+ ArrayList<IdBlock> blocks = new ArrayList<IdBlock>(NUM_BLOCKS);
+
+ for(int i = 0; i < NUM_BLOCKS; ++i) {
+ IdBlock block = registry.allocateUniqueIdBlock();
+ assertNotNull(block);
+ blocks.add(block);
+ }
+
+ for(int i = 0; i < NUM_BLOCKS; ++i) {
+ IdBlock block1 = blocks.get(i);
+ for(int j = i + 1; j < NUM_BLOCKS; ++j) {
+ IdBlock block2 = blocks.get(j);
+ IdBlock lower,higher;
+
+ if(block1.getStart() < block2.getStart()) {
+ lower = block1;
+ higher = block2;
+ } else {
+ lower = block2;
+ higher = block1;
+ }
+
+ assertTrue(lower.getSize() > 0L);
+ assertTrue(higher.getSize() > 0L);
+ assertTrue(lower.getEnd() <= higher.getStart());
+ }
+ }
+ }
+
+
+ //-------------------------- Creation of mock objects --------------------------
+ /**
+ * Create mock {@link CuratorFramework} object with initial value below.<br>
+ * [Ctrl ID] : [DPID]<br>
+ * controller1 : 1000<br>
+ * controller2 : 1001<br>
+ * controller2 : 1002<br>
+ * controller2013 : nothing
+ * @return Created mock object
+ * @throws Exception
+ */
+ @SuppressWarnings({ "serial", "unchecked" })
+ private CuratorFramework createCuratorFrameworkMock() throws Exception {
+ // Mock of AtomicValue
+ AtomicValue<Long> atomicValue = EasyMock.createMock(AtomicValue.class);
+ EasyMock.expect(atomicValue.succeeded()).andReturn(true).anyTimes();
+ EasyMock.expect(atomicValue.preValue()).andAnswer(new IAnswer<Long>() {
+ private long value = 0;
+ @Override
+ public Long answer() throws Throwable {
+ value += ID_BLOCK_SIZE;
+ return value;
+ }
+ }).anyTimes();
+ EasyMock.expect(atomicValue.postValue()).andAnswer(new IAnswer<Long>() {
+ private long value = ID_BLOCK_SIZE;
+ @Override
+ public Long answer() throws Throwable {
+ value += ID_BLOCK_SIZE;
+ return value;
+ }
+ }).anyTimes();
+ EasyMock.replay(atomicValue);
+
+ // Mock DistributedAtomicLong
+ DistributedAtomicLong daLong = EasyMock.createMock(DistributedAtomicLong.class);
+ EasyMock.expect(daLong.add(EasyMock.anyLong())).andReturn(atomicValue).anyTimes();
+ EasyMock.replay(daLong);
+ PowerMock.expectNew(DistributedAtomicLong.class,
+ new Class<?> [] {CuratorFramework.class, String.class, RetryPolicy.class},
+ EasyMock.anyObject(CuratorFramework.class), EasyMock.anyObject(String.class), EasyMock.anyObject(RetryPolicy.class)).
+ andReturn(daLong).anyTimes();
+ PowerMock.replay(DistributedAtomicLong.class);
+
+ // Mock ListenerContainer
+ ListenerContainer<PathChildrenCacheListener> listenerContainer = EasyMock.createMock(ListenerContainer.class);
+ listenerContainer.addListener(EasyMock.anyObject(PathChildrenCacheListener.class));
+ EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+ @Override
+ public Object answer() throws Throwable {
+ pathChildrenCacheListener = (PathChildrenCacheListener)EasyMock.getCurrentArguments()[0];
+ return null;
+ }
+ }).once();
+ EasyMock.replay(listenerContainer);
+
+ // Mock PathChildrenCache
+ PathChildrenCache pathChildrenCacheMain = createPathChildrenCacheMock(CONTROLLER_ID, new String[] {"/switches"}, listenerContainer);
+ PathChildrenCache pathChildrenCache1 = createPathChildrenCacheMock("controller1", new String[] {HexString.toHexString(1000L)}, listenerContainer);
+ PathChildrenCache pathChildrenCache2 = createPathChildrenCacheMock("controller2", new String[] {
+ HexString.toHexString(1001L), HexString.toHexString(1002L) },listenerContainer);
+
+ // Mock PathChildrenCache constructor
+ PowerMock.expectNew(PathChildrenCache.class,
+ EasyMock.anyObject(CuratorFramework.class), EasyMock.anyObject(String.class), EasyMock.anyBoolean()).
+ andReturn(pathChildrenCacheMain).once();
+ PowerMock.expectNew(PathChildrenCache.class,
+ EasyMock.anyObject(CuratorFramework.class), EasyMock.anyObject(String.class), EasyMock.anyBoolean()).
+ andReturn(pathChildrenCache1).once();
+ PowerMock.expectNew(PathChildrenCache.class,
+ EasyMock.anyObject(CuratorFramework.class), EasyMock.anyObject(String.class), EasyMock.anyBoolean()).
+ andReturn(pathChildrenCache2).anyTimes();
+ PowerMock.replay(PathChildrenCache.class);
+
+ // Mock ServiceCache
+ ServiceCache<ControllerService> serviceCache = EasyMock.createMock(ServiceCache.class);
+ serviceCache.start();
+ EasyMock.expectLastCall().once();
+ EasyMock.expect(serviceCache.getInstances()).andReturn(new ArrayList<ServiceInstance<ControllerService> > () {{
+ add(createServiceInstanceMock("controller1"));
+ add(createServiceInstanceMock("controller2"));
+ }}).anyTimes();
+ EasyMock.replay(serviceCache);
+
+ // Mock ServiceCacheBuilder
+ ServiceCacheBuilder<ControllerService> serviceCacheBuilder = EasyMock.createMock(ServiceCacheBuilder.class);
+ EasyMock.expect(serviceCacheBuilder.name(EasyMock.anyObject(String.class))).andReturn(serviceCacheBuilder).once();
+ EasyMock.expect(serviceCacheBuilder.build()).andReturn(serviceCache).once();
+ EasyMock.replay(serviceCacheBuilder);
+
+ // Mock ServiceDiscovery
+ ServiceDiscovery<ControllerService> serviceDiscovery = EasyMock.createMock(ServiceDiscovery.class);
+ serviceDiscovery.start();
+ EasyMock.expectLastCall().once();
+ EasyMock.expect(serviceDiscovery.serviceCacheBuilder()).andReturn(serviceCacheBuilder).once();
+ serviceDiscovery.registerService(EasyMock.anyObject(ServiceInstance.class));
+ EasyMock.expectLastCall().once();
+ EasyMock.replay(serviceDiscovery);
+
+ // Mock CuratorFramework
+ CuratorFramework client = EasyMock.createMock(CuratorFramework.class);
+ client.start();
+ EasyMock.expectLastCall().once();
+ EasyMock.expect(client.usingNamespace(EasyMock.anyObject(String.class))).andReturn(client);
+ EasyMock.replay(client);
+
+ // Mock ServiceDiscoveryBuilder
+ ServiceDiscoveryBuilder<ControllerService> builder = EasyMock.createMock(ServiceDiscoveryBuilder.class);
+ EasyMock.expect(builder.client(client)).andReturn(builder).once();
+ EasyMock.expect(builder.basePath(EasyMock.anyObject(String.class))).andReturn(builder);
+ EasyMock.expect(builder.build()).andReturn(serviceDiscovery);
+ EasyMock.replay(builder);
+
+ PowerMock.mockStatic(ServiceDiscoveryBuilder.class);
+ EasyMock.expect(ServiceDiscoveryBuilder.builder(ControllerService.class)).andReturn(builder).once();
+ PowerMock.replay(ServiceDiscoveryBuilder.class);
+
+ return client;
+ }
+
+ /**
+ * Create mock {@link ServiceInstance} object using given controller ID.
+ * @param controllerId Controller ID to represent instance's payload (ControllerService).
+ * @return Mock ServiceInstance object
+ */
+ private ServiceInstance<ControllerService> createServiceInstanceMock(String controllerId) {
+ ControllerService controllerService = EasyMock.createMock(ControllerService.class);
+ EasyMock.expect(controllerService.getControllerId()).andReturn(controllerId).anyTimes();
+ EasyMock.replay(controllerService);
+
+ @SuppressWarnings("unchecked")
+ ServiceInstance<ControllerService> serviceInstance = EasyMock.createMock(ServiceInstance.class);
+ EasyMock.expect(serviceInstance.getPayload()).andReturn(controllerService).anyTimes();
+ EasyMock.replay(serviceInstance);
+
+ return serviceInstance;
+ }
+
+ /**
+ * Create mock {@link PathChildrenCache} using given controller ID and DPIDs.
+ * @param controllerId Controller ID to represent current data.
+ * @param paths List of HexString indicating switch's DPID.
+ * @param listener Callback object to be set as Listenable.
+ * @return Mock PathChildrenCache object
+ * @throws Exception
+ */
+ private PathChildrenCache createPathChildrenCacheMock(final String controllerId, final String [] paths,
+ ListenerContainer<PathChildrenCacheListener> listener) throws Exception {
+ PathChildrenCache pathChildrenCache = EasyMock.createMock(PathChildrenCache.class);
+
+ EasyMock.expect(pathChildrenCache.getListenable()).andReturn(listener).anyTimes();
+
+ pathChildrenCache.start(EasyMock.anyObject(StartMode.class));
+ EasyMock.expectLastCall().anyTimes();
+
+ List<ChildData> childs = new ArrayList<ChildData>();
+ for(String path : paths) {
+ childs.add(createChildDataMockForCurrentData(controllerId,path));
+ }
+ EasyMock.expect(pathChildrenCache.getCurrentData()).andReturn(childs).anyTimes();
+
+ pathChildrenCache.rebuild();
+ EasyMock.expectLastCall().anyTimes();
+
+ EasyMock.replay(pathChildrenCache);
+
+ return pathChildrenCache;
+ }
+
+ /**
+ * Create mock {@link ChildData} for {@link PathChildrenCache#getCurrentData()} return value.
+ * This object need to include 'sequence number' in tail of path string. ("-0" means 0th sequence)
+ * @param controllerId Controller ID
+ * @param path HexString indicating switch's DPID
+ * @return Mock ChildData object
+ */
+ private ChildData createChildDataMockForCurrentData(String controllerId, String path) {
+ ChildData data = EasyMock.createMock(ChildData.class);
+ EasyMock.expect(data.getPath()).andReturn(path + "-0").anyTimes();
+ EasyMock.expect(data.getData()).andReturn(controllerId.getBytes()).anyTimes();
+ EasyMock.replay(data);
+
+ return data;
+ }
+
+ /**
+ * Inject relations between controllers and switches using callback object.
+ * @throws Exception
+ */
+ private void setPathChildrenCache() throws Exception {
+ pathChildrenCacheListener.childEvent(client,
+ createChildrenCacheEventMock("controller1", HexString.toHexString(1000L), PathChildrenCacheEvent.Type.CHILD_ADDED));
+ pathChildrenCacheListener.childEvent(client,
+ createChildrenCacheEventMock("controller2", HexString.toHexString(1001L), PathChildrenCacheEvent.Type.CHILD_ADDED));
+ pathChildrenCacheListener.childEvent(client,
+ createChildrenCacheEventMock("controller2", HexString.toHexString(1002L), PathChildrenCacheEvent.Type.CHILD_ADDED));
+ }
+
+ /**
+ * Create mock {@link PathChildrenCacheEvent} object using given controller ID and DPID.
+ * @param controllerId Controller ID.
+ * @param path HexString of DPID.
+ * @param type Event type to be set to mock object.
+ * @return Mock PathChildrenCacheEvent object
+ */
+ private PathChildrenCacheEvent createChildrenCacheEventMock(String controllerId, String path,
+ PathChildrenCacheEvent.Type type) {
+ PathChildrenCacheEvent event = EasyMock.createMock(PathChildrenCacheEvent.class);
+ ChildData data = EasyMock.createMock(ChildData.class);
+
+ EasyMock.expect(data.getPath()).andReturn(path).anyTimes();
+ EasyMock.expect(data.getData()).andReturn(controllerId.getBytes()).anyTimes();
+ EasyMock.replay(data);
+
+ EasyMock.expect(event.getType()).andReturn(type).anyTimes();
+ EasyMock.expect(event.getData()).andReturn(data).anyTimes();
+ EasyMock.replay(event);
+
+ return event;
+ }
+}
diff --git a/titan/schema/test-network.xml b/titan/schema/test-network.xml
index 5c63d90..630c5da 100644
--- a/titan/schema/test-network.xml
+++ b/titan/schema/test-network.xml
@@ -3,6 +3,7 @@
<key id="id" for="node" attr.name="id" attr.type="string"></key>
<key id="type" for="node" attr.name="type" attr.type="string"></key>
+ <key id="state" for="node" attr.name="state" attr.type="string"></key>
<key id="dpid" for="node" attr.name="dpid" attr.type="string"></key>
<key id="desc" for="node" attr.name="desc" attr.type="string"></key>
<key id="number" for="node" attr.name="number" attr.type="int"></key>
@@ -17,31 +18,37 @@
<node id="1">
<data key="type">switch</data>
<data key="dpid">00:00:00:00:00:00:0a:01</data>
+ <data key="state">ACTIVE</data>
<data key="desc">OpenFlow Switch at SEA</data>
</node>
<node id="2">
<data key="type">switch</data>
<data key="dpid">00:00:00:00:00:00:0a:02</data>
+ <data key="state">ACTIVE</data>
<data key="desc">OpenFlow Switch at LAX</data>
</node>
<node id="3">
<data key="type">switch</data>
<data key="dpid">00:00:00:00:00:00:0a:03</data>
+ <data key="state">ACTIVE</data>
<data key="desc">OpenFlow Switch at CHI</data>
</node>
<node id="4">
<data key="type">switch</data>
<data key="dpid">00:00:00:00:00:00:0a:04</data>
+ <data key="state">ACTIVE</data>
<data key="desc">OpenFlow Switch at IAH</data>
</node>
<node id="5">
<data key="type">switch</data>
<data key="dpid">00:00:00:00:00:00:0a:05</data>
+ <data key="state">ACTIVE</data>
<data key="desc">OpenFlow Switch at NYC</data>
</node>
<node id="6">
<data key="type">switch</data>
<data key="dpid">00:00:00:00:00:00:0a:06</data>
+ <data key="state">ACTIVE</data>
<data key="desc">OpenFlow Switch at ATL</data>
</node>
diff --git a/web/config.json.devA b/web/config.json.devA
new file mode 100644
index 0000000..b20639e
--- /dev/null
+++ b/web/config.json.devA
@@ -0,0 +1,22 @@
+{
+ "LB": false,
+ "TESTBED": "sw",
+ "ONOS_DEFAULT_HOST": "localhost",
+ "ONOS_GUI3_CONTROL_HOST": "http://10.128.4.51:9000",
+ "ONOS_GUI3_HOST": "http://10.128.4.51:9000",
+ "cluster_basename": "ONOS",
+ "controllers": [
+ "DevA-ONOS1",
+ "DevA-ONOS2",
+ "DevA-ONOS3",
+ "DevA-ONOS4"
+ ],
+ "core_switches": [
+ "00:00:00:00:ba:5e:ba:11",
+ "00:00:00:00:00:00:ba:12",
+ "00:00:20:4e:7f:51:8a:35",
+ "00:00:00:00:ba:5e:ba:13",
+ "00:00:00:08:a2:08:f9:01",
+ "00:00:00:16:97:08:9a:46"
+ ]
+}
diff --git a/web/ons-demo/data/configuration.json.devA b/web/ons-demo/data/configuration.json.devA
new file mode 100644
index 0000000..f8a6e63
--- /dev/null
+++ b/web/ons-demo/data/configuration.json.devA
@@ -0,0 +1,78 @@
+{
+ "core": [
+ "00:00:00:08:a2:08:f9:01",
+ "00:00:00:00:ba:5e:ba:11",
+ "00:00:20:4e:7f:51:8a:35",
+ "00:00:00:00:00:00:ba:12",
+ "00:00:00:00:ba:5e:ba:13",
+ "00:00:00:16:97:08:9a:46"
+ ],
+ "aggregation": [
+ "00:00:00:00:00:00:02:01",
+ "00:00:00:00:00:00:03:01",
+ "00:00:00:00:00:00:04:01",
+ "00:00:00:00:00:00:05:01",
+ "00:00:00:00:00:00:06:01",
+ "00:00:00:00:00:00:07:01",
+ "00:00:00:00:00:00:08:01"
+ ],
+ "association": {
+ "00:00:20:4e:7f:51:8a:35": [
+ "00:00:00:00:00:00:07:01"
+ ],
+ "00:00:00:00:ba:5e:ba:13": [
+ "00:00:00:00:00:00:06:01"
+ ],
+ "00:00:00:08:a2:08:f9:01": [
+ "00:00:00:00:00:00:03:01"
+ ],
+ "00:00:00:00:00:00:ba:12": [
+ "00:00:00:00:00:00:04:01",
+ "00:00:00:00:00:00:05:01"
+ ],
+ "00:00:00:00:ba:5e:ba:11": [
+ "00:00:00:00:00:00:02:01"
+ ],
+ "00:00:00:16:97:08:9a:46": [
+ "00:00:00:00:00:00:08:01"
+ ]
+ },
+ "geo": {
+ "00:00:20:4e:7f:51:8a:35": {
+ "lat": 41.891033,
+ "lng": -87.628326,
+ "label": "CHI",
+ "fanOutAngle": 180
+ },
+ "00:00:00:00:ba:5e:ba:13": {
+ "lat": 47.611024,
+ "lng": -122.33242,
+ "label": "SEA",
+ "fanOutAngle": 270
+ },
+ "00:00:00:08:a2:08:f9:01": {
+ "lat": 33.758599,
+ "lng": -84.387360,
+ "label": "ATL",
+ "fanOutAngle": 5
+ },
+ "00:00:00:16:97:08:9a:46": {
+ "lat": 41.225925,
+ "lng": -74.00528,
+ "label": "NYC",
+ "fanOutAngle": 150
+ },
+ "00:00:00:00:ba:5e:ba:11": {
+ "lat": 37.901187,
+ "lng": -76.037163,
+ "label": "DC",
+ "fanOutAngle": 45
+ },
+ "00:00:00:00:00:00:ba:12": {
+ "lat": 34.102708,
+ "lng": -118.238983,
+ "label": "LA",
+ "fanOutAngle": 315
+ }
+ }
+}