Squashed commit of the following:
commit a7d29f094ebce1a9183109c15cafd4691c97266f
Author: Naoki Shiota <n-shiota@onlab.us>
Date: Thu Jun 20 17:25:53 2013 -0700
Modify LinkStorageImplTest to use EasyMock.
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 7bf2b1a..b0577a5 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
@@ -5,17 +5,21 @@
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import net.floodlightcontroller.routing.Link;
import net.onrc.onos.ofcontroller.core.ILinkStorage;
import net.onrc.onos.ofcontroller.core.INetMapStorage.DM_OPERATION;
-import net.onrc.onos.ofcontroller.core.internal.TestableGraphDBOperation.TestPortObject;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.onrc.onos.ofcontroller.linkdiscovery.LinkInfo;
import net.onrc.onos.util.GraphDBConnection;
import net.onrc.onos.util.GraphDBOperation;
-import net.onrc.onos.ofcontroller.linkdiscovery.LinkInfo;
-import org.easymock.EasyMock;
+import org.easymock.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
@@ -40,7 +44,54 @@
private static GraphDBConnection conn;
// Mock GraphDBOperation (mocks port-related methods only)
- private static TestableGraphDBOperation ope;
+ private static GraphDBOperation ope;
+
+ // Uncommitted actions executed in LinkStorageImpl
+ private static ArrayList<LinkEvent> actions;
+
+ // Dictionary of mock IPortObject to information of port
+ // -> Used to refer DPID from IPortObject
+ private static Map<IPortObject,PortInfo> mockToPortInfoMap;
+
+
+ // Links existing in virtual graph
+ private List<Link> links;
+
+ //================ Utility classes for logging actions in LinkStorageImpl ===========
+ private enum LinkEventType {
+ ADD, DELETE
+ }
+
+ private class LinkEvent {
+ private Long src_dpid = null;
+ private Long dst_dpid = null;
+ private Short src_port = null;
+ private Short dst_port = null;
+
+ public LinkEventType type;
+
+ public LinkEvent(Link link, LinkEventType type) {
+ this.src_dpid = link.getSrc();
+ this.src_port = link.getSrcPort();
+ this.dst_dpid = link.getDst();
+ this.dst_port = link.getDstPort();
+
+ this.type = type;
+ }
+
+ public Long getSrcDpid() { return src_dpid; }
+ public Short getSrcPort() { return src_port; }
+ public Long getDstDpid() { return dst_dpid; }
+ public Short getDstPort() { return dst_port; }
+ public LinkEventType getType() { return type; }
+ }
+
+ private class PortInfo {
+ public Long dpid = null;
+ public Short port = null;
+
+ public PortInfo(Long dpid, Short port) { this.dpid = dpid; this.port = port; }
+ }
/**
* Setup code called before each tests.
@@ -55,10 +106,13 @@
EasyMock.expect(GraphDBConnection.getInstance((String)EasyMock.anyObject())).andReturn(conn).anyTimes();
PowerMock.replay(GraphDBConnection.class);
- ope = new TestableGraphDBOperation();
- PowerMock.expectNew(GraphDBOperation.class, (GraphDBConnection)EasyMock.anyObject()).andReturn(ope).anyTimes();
+ ope = createMockGraphDBOperation();
+ PowerMock.expectNew(GraphDBOperation.class, new Class<?>[] {GraphDBConnection.class}, EasyMock.anyObject(GraphDBConnection.class)).andReturn(ope).anyTimes();
PowerMock.replay(GraphDBOperation.class);
-
+
+ actions = new ArrayList<LinkEvent>();
+ mockToPortInfoMap = new HashMap<IPortObject,PortInfo>();
+
linkStorage = new LinkStorageImpl();
linkStorage.init("/dummy/path/to/conf");
@@ -74,7 +128,6 @@
public void tearDown() throws Exception {
// finish code
linkStorage.close();
- ope.close();
}
// TODO: remove @Ignore after UPDATE method is implemented
@@ -104,6 +157,14 @@
//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);
}
/**
@@ -145,6 +206,14 @@
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);
+// }
}
/**
@@ -298,7 +367,7 @@
List<Link> list = linkStorage.getLinks(dpid, port);
- assertEquals(list.size(), 1);
+ assertEquals(1, list.size());
Link l = list.get(0);
assertEquals(l.getSrc(), linkToVerify.getSrc());
@@ -310,7 +379,7 @@
List<Link> list2 = linkStorage.getLinks(linkToVerifyNot.getSrc(), (short)linkToVerifyNot.getSrcPort());
- assertEquals(list2.size(), 0);
+ assertEquals(0, list2.size());
}
/**
@@ -398,25 +467,26 @@
}
/**
- * Test if specific link is existing
+ * Test if specific link exists
* @param link
*/
private void doTestLinkExist(Link link) {
- assertTrue(ope.hasLinkBetween(HexString.toHexString(link.getSrc()),
- link.getSrcPort(),
- HexString.toHexString(link.getDst()),
- link.getDstPort()));
+ int count = 0;
+ for(Link lt : links) {
+ if(lt.equals(link)) {
+ ++count;
+ }
+ }
+
+ assertTrue(count == 1);
}
/**
- * Test if titanGraph doesn't have specific link
+ * Test if specific link doesn't exist
* @param link
*/
private void doTestLinkNotExist(Link link) {
- assertFalse(ope.hasLinkBetween(HexString.toHexString(link.getSrc()),
- link.getSrcPort(),
- HexString.toHexString(link.getDst()),
- link.getDstPort()));
+ assertFalse(links.contains(link));
}
/**
@@ -426,6 +496,252 @@
private void doTestLinkHasStateOf(Link link, LinkInfo info) {
}
+ /**
+ * Class defines a function called back when IPortObject#removeLink is called.
+ * @author Naoki Shiota
+ *
+ */
+ private class RemoveLinkCallback implements IAnswer<Object> {
+ private long dpid;
+ private short port;
+ public RemoveLinkCallback(long dpid, short port) {
+ this.dpid = dpid; this.port = port;
+ }
+
+ @Override
+ public Object answer() throws Throwable {
+ IPortObject dstPort = (IPortObject) EasyMock.getCurrentArguments()[0];
+ PortInfo dst = mockToPortInfoMap.get(dstPort);
+
+ Link linkToRemove = new Link(this.dpid,this.port,dst.dpid,dst.port);
+ actions.add(new LinkEvent(linkToRemove,LinkEventType.DELETE));
+
+ return null;
+ }
+ }
+
+ /**
+ * Class defines a function called back when IPortObject#setLinkPort is called.
+ * @author Naoki Shiota
+ *
+ */
+ private class SetLinkPortCallback implements IAnswer<Object> {
+ private long dpid;
+ private short port;
+ public SetLinkPortCallback(long dpid, short port) {
+ this.dpid = dpid; this.port = port;
+ }
+
+ @Override
+ public Object answer() throws Throwable {
+ IPortObject dstPort = (IPortObject) EasyMock.getCurrentArguments()[0];
+ PortInfo dst = mockToPortInfoMap.get(dstPort);
+
+ Link linkToAdd = new Link(this.dpid,this.port,dst.dpid,dst.port);
+ actions.add(new LinkEvent(linkToAdd,LinkEventType.ADD));
+
+ return null;
+ }
+
+ }
+
+ /**
+ * Class defines a function called back when IPortObject#getSwitch is called.
+ * @author Naoki Shiota
+ *
+ */
+ private class GetSwitchCallback implements IAnswer<ISwitchObject> {
+ private long dpid;
+
+ public GetSwitchCallback(long dpid) {
+ this.dpid = dpid;
+ }
+
+ @Override
+ public ISwitchObject answer() throws Throwable {
+ ISwitchObject sw = createMockSwitch(dpid);
+ return sw;
+ }
+ }
+
+ /**
+ * Class defines a function called back when IPortObject#getLinkedPorts is called.
+ * @author Naoki Shiota
+ *
+ */
+ private class GetLinkedPortsCallback implements IAnswer< Iterable<IPortObject> > {
+ private long dpid;
+ private short port;
+
+ public GetLinkedPortsCallback(long dpid, short port) {
+ this.dpid = dpid;
+ this.port = port;
+ }
+
+ @Override
+ public Iterable<IPortObject> answer() throws Throwable {
+ List<IPortObject> ports = new ArrayList<IPortObject>();
+
+ for(Link lk : links) {
+ if(lk.getSrc() == dpid && lk.getSrcPort() == port) {
+ ports.add(createMockPort(lk.getDst(), lk.getDstPort()));
+ }
+ }
+
+ return ports;
+ }
+
+ }
+
+ /**
+ * Class defines a function called back when ISwitchObject#getPorts is called.
+ * @author Naoki Shiota
+ *
+ */
+ private class GetPortsCallback implements IAnswer< Iterable <IPortObject> > {
+ private long dpid;
+
+ public GetPortsCallback(long dpid) {
+ this.dpid = dpid;
+ }
+
+ @Override
+ public Iterable<IPortObject> answer() throws Throwable {
+ List<IPortObject> ports = new ArrayList<IPortObject>();
+
+ for(Short number : getPorts(dpid)) {
+ ports.add(createMockPort(dpid, number));
+ }
+
+ return ports;
+ }
+ }
+
+ // ------------------------Creation of Mock-----------------------------
+ /**
+ * Create a mock GraphDBOperation which hooks port-related methods.
+ * @return EasyMock-wrapped GraphDBOperation object.
+ */
+ @SuppressWarnings("serial")
+ private GraphDBOperation createMockGraphDBOperation() {
+ GraphDBOperation mockDBOpe = EasyMock.createNiceMock(GraphDBOperation.class);
+
+ // Mock searchPort() method to create new mock IPortObject.
+ EasyMock.expect(mockDBOpe.searchPort((String)EasyMock.anyObject(), EasyMock.anyShort())).
+ andAnswer(new IAnswer<IPortObject>() {
+ @Override
+ public IPortObject answer() throws Throwable {
+ long dpid = HexString.toLong((String)EasyMock.getCurrentArguments()[0]);
+ short port = (Short) EasyMock.getCurrentArguments()[1];
+ IPortObject ret = createMockPort(dpid,port);
+
+ return ret;
+ }
+ }).anyTimes();
+
+ // Mock searchSwitch() method to create new mock ISwitchObject.
+ EasyMock.expect(mockDBOpe.searchSwitch((String)EasyMock.anyObject())).
+ andAnswer(new IAnswer<ISwitchObject>() {
+ @Override
+ public ISwitchObject answer() throws Throwable {
+ long dpid = HexString.toLong((String)EasyMock.getCurrentArguments()[0]);
+ ISwitchObject ret = createMockSwitch(dpid);
+
+ return ret;
+ }
+ }).anyTimes();
+
+ // Mock getActiveSwitches() method to create list of mock ISwitchObject.
+ EasyMock.expect(mockDBOpe.getActiveSwitches()).andReturn(new ArrayList<ISwitchObject> () {{
+ for(Long dpid : getDpids()) {
+ add(createMockSwitch(dpid));
+ }
+ }}).anyTimes();
+
+ // Mock commit() method to commit change of link information
+ mockDBOpe.commit();
+ EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+ @Override
+ public Object answer() throws Throwable {
+ for(LinkEvent action : actions) {
+ if(action.getType().equals(LinkEventType.ADD)) {
+ Link linkToAdd = new Link(
+ action.getSrcDpid(),
+ action.getSrcPort(),
+ action.getDstDpid(),
+ action.getDstPort());
+ links.add(linkToAdd);
+ } else if(action.getType().equals(LinkEventType.DELETE)) {
+ Link linkToRemove = new Link(
+ action.getSrcDpid(),
+ action.getSrcPort(),
+ action.getDstDpid(),
+ action.getDstPort());
+ links.remove(linkToRemove);
+ } else {
+ log.error("mock commit(): unexpected action {}", new Object[]{action.getType()});
+ }
+ }
+ actions.clear();
+ return null;
+ }
+ }).atLeastOnce();
+
+ EasyMock.replay(mockDBOpe);
+ return mockDBOpe;
+ }
+
+ /**
+ * Create a mock IPortObject using given DPID and port number.
+ * 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
+ * @return EasyMock-wrapped IPortObject
+ */
+ private IPortObject createMockPort(long dpid, short number) {
+ IPortObject mockPort = EasyMock.createNiceMock(IPortObject.class);
+
+ EasyMock.expect(mockPort.getNumber()).andReturn(number);
+
+ // Mock removeLink() method
+ mockPort.removeLink((IPortObject) EasyMock.anyObject());
+ EasyMock.expectLastCall().andAnswer(new RemoveLinkCallback(dpid, number)).anyTimes();
+
+ // Mock setLinkPort() method
+ mockPort.setLinkPort((IPortObject) EasyMock.anyObject());
+ EasyMock.expectLastCall().andAnswer(new SetLinkPortCallback(dpid, number)).anyTimes();
+
+ // Mock getLinkPorts() method
+ EasyMock.expect(mockPort.getLinkedPorts()).andAnswer(new GetLinkedPortsCallback(dpid, number)).anyTimes();
+
+ // Mock getSwitch() method
+ EasyMock.expect(mockPort.getSwitch()).andAnswer(new GetSwitchCallback(dpid)).anyTimes();
+
+ mockToPortInfoMap.put(mockPort, new PortInfo(dpid,number));
+ EasyMock.replay(mockPort);
+
+ return mockPort;
+ }
+
+ /**
+ * Create a mock ISwitchObject using given DPID number.
+ * Duplication is not checked.
+ * @param dpid DPID of a switch
+ * @return EasyMock-wrapped ISwitchObject
+ */
+ private ISwitchObject createMockSwitch(long dpid) {
+ ISwitchObject mockSw = EasyMock.createNiceMock(ISwitchObject.class);
+
+ EasyMock.expect(mockSw.getPorts()).andAnswer(new GetPortsCallback(dpid)).anyTimes();
+ EasyMock.expect(mockSw.getDPID()).andReturn(HexString.toHexString(dpid)).anyTimes();
+ EasyMock.expect(mockSw.getState()).andReturn("ACTIVE").anyTimes();
+
+ EasyMock.replay(mockSw);
+ return mockSw;
+ }
+
+
//----------------- Creation of test data -----------------------
// Assume a network shown below.
//
@@ -441,38 +757,61 @@
// dpid2 : 00:00:00:00:0a:02
// dpid3 : 00:00:00:00:0a:03
+ /**
+ * Initialize links member to represent test topology above.
+ */
private void initLinks() {
- final String dpid1 = "00:00:00:00:0a:01";
- final String dpid2 = "00:00:00:00:0a:02";
- final String dpid3 = "00:00:00:00:0a:03";
+ links = new ArrayList<Link>();
- ope.createNewSwitchForTest(dpid1).setStateForTest("ACTIVE");
- ope.createNewSwitchForTest(dpid2).setStateForTest("ACTIVE");
- ope.createNewSwitchForTest(dpid3).setStateForTest("ACTIVE");
-
- TestPortObject ports1 [] = {
- ope.createNewPortForTest(dpid1, (short)1),
- ope.createNewPortForTest(dpid1, (short)2),
- ope.createNewPortForTest(dpid1, (short)3),
- ope.createNewPortForTest(dpid1, (short)4),
- };
-
- TestPortObject ports2 [] = {
- ope.createNewPortForTest(dpid2, (short)1),
- ope.createNewPortForTest(dpid2, (short)2),
- };
-
- TestPortObject ports3 [] = {
- ope.createNewPortForTest(dpid3, (short)1),
- ope.createNewPortForTest(dpid3, (short)2),
- };
-
- ope.setLinkBetweenPortsForTest(ports1[0], ports2[0]);
- ope.setLinkBetweenPortsForTest(ports1[3], ports3[1]);
+ links.add(new Link(Long.decode("0x0000000000000a01"), 1, Long.decode("0x0000000000000a02"), 1));
+ links.add(new Link(Long.decode("0x0000000000000a01"), 4, Long.decode("0x0000000000000a03"), 2));
}
/**
- * Returns new Link object of existing link
+ * Returns list of port number attached to the switch specified by given DPID.
+ * @param dpid DPID of the switch
+ * @return List of port number
+ */
+ @SuppressWarnings("serial")
+ private List<Short> getPorts(long dpid) {
+ List<Short> ports;
+
+ if(dpid == Long.decode("0x0000000000000a01")) {
+ ports = new ArrayList<Short>() {{
+ add((short)1);
+ add((short)2);
+ add((short)3);
+ add((short)4);
+ }};
+ } else if(dpid == Long.decode("0x0000000000000a02") || dpid == Long.decode("0x0000000000000a03")) {
+ ports = new ArrayList<Short>() {{
+ add((short)1);
+ add((short)2);
+ }};
+ } else {
+ ports = new ArrayList<Short>();
+ }
+
+ return ports;
+ }
+
+ /**
+ * Returns list of DPIDs in test topology.
+ * @return List of DPIDs
+ */
+ @SuppressWarnings("serial")
+ private List<Long> getDpids() {
+ List<Long> dpids = new ArrayList<Long>() {{
+ add(Long.decode("0x0000000000000a01"));
+ add(Long.decode("0x0000000000000a02"));
+ add(Long.decode("0x0000000000000a03"));
+ }};
+
+ return dpids;
+ }
+
+ /**
+ * Returns new Link object of an existing link
* @return new Link object
*/
private Link createExistingLink() {
@@ -480,7 +819,7 @@
}
/**
- * Returns new Link object of not-existing but feasible link
+ * Returns new Link object of a not-existing but feasible link
* @return new Link object
*/
private Link createFeasibleLink() {