Unit Test framework for Device Manager and with UT cases

add two more testing cases and handle code review comments

Change-Id: I2ea20b16da6e9c349045d5ee1f9c91b2137ccd7e
diff --git a/src/main/java/net/onrc/onos/core/devicemanager/OnosDeviceManager.java b/src/main/java/net/onrc/onos/core/devicemanager/OnosDeviceManager.java
index 38a8746..f1cc8f7 100644
--- a/src/main/java/net/onrc/onos/core/devicemanager/OnosDeviceManager.java
+++ b/src/main/java/net/onrc/onos/core/devicemanager/OnosDeviceManager.java
@@ -58,7 +58,7 @@
     private IDatagridService datagrid;
     private IEventChannel<Long, OnosDevice> eventChannel;
     private static final String DEVICE_CHANNEL_NAME = "onos.device";
-    private Map<Long, OnosDevice> mapDevice = new ConcurrentHashMap<Long, OnosDevice>();
+    private final Map<Long, OnosDevice> mapDevice = new ConcurrentHashMap<Long, OnosDevice>();
     private ITopologyService topologyService;
     private Topology topology;
 
@@ -67,8 +67,8 @@
     }
 
     private class OnosDeviceUpdate implements IUpdate {
-        private OnosDevice device;
-        private OnosDeviceUpdateType type;
+        private final OnosDevice device;
+        private final OnosDeviceUpdateType type;
 
         public OnosDeviceUpdate(OnosDevice device, OnosDeviceUpdateType type) {
             this.device = device;
@@ -110,7 +110,7 @@
     @Override
     public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
         if (msg.getType().equals(OFType.PACKET_IN) &&
-            (msg instanceof OFPacketIn)) {
+                (msg instanceof OFPacketIn)) {
             OFPacketIn pi = (OFPacketIn) msg;
 
             Ethernet eth = IFloodlightProviderService.bcStore.
@@ -250,14 +250,16 @@
      * @param pi  the original packetin
      * @return the entity from the packet
      */
-    private OnosDevice getSourceDeviceFromPacket(Ethernet eth,
-                                                 long swdpid,
-                                                 short port) {
+    protected OnosDevice getSourceDeviceFromPacket(Ethernet eth,
+            long swdpid,
+            short port) {
         byte[] dlAddrArr = eth.getSourceMACAddress();
         long dlAddr = Ethernet.toLong(dlAddrArr);
 
-        // Ignore broadcast/multicast source
-        if ((dlAddrArr[0] & 0x1) != 0) {
+        /*
+         *  Ignore broadcast/multicast source
+         */
+        if (eth.isMulticast() || eth.isBroadcast()) {
             return null;
         }
 
diff --git a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
index 5961037..81463aa 100644
--- a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
+++ b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
@@ -74,7 +74,7 @@
 
     @Override
     public synchronized void addOFMessageListener(OFType type,
-                                                  IOFMessageListener listener) {
+            IOFMessageListener listener) {
         ListenerDispatcher<OFType, IOFMessageListener> ldd =
                 listeners.get(type);
         if (ldd == null) {
@@ -86,7 +86,7 @@
 
     @Override
     public synchronized void removeOFMessageListener(OFType type,
-                                                     IOFMessageListener listener) {
+            IOFMessageListener listener) {
         ListenerDispatcher<OFType, IOFMessageListener> ldd =
                 listeners.get(type);
         if (ldd != null) {
@@ -97,11 +97,12 @@
     /**
      * @return the listeners
      */
+    @Override
     public Map<OFType, List<IOFMessageListener>> getListeners() {
         Map<OFType, List<IOFMessageListener>> lers =
                 new HashMap<OFType, List<IOFMessageListener>>();
         for (Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e :
-                listeners.entrySet()) {
+            listeners.entrySet()) {
             lers.put(e.getKey(), e.getValue().getOrderedListeners());
         }
         return Collections.unmodifiableMap(lers);
@@ -153,6 +154,7 @@
         }
     }
 
+    @Override
     public void handleOutgoingMessage(IOFSwitch sw, OFMessage m, FloodlightContext bc) {
         List<IOFMessageListener> msgListeners = null;
         if (listeners.containsKey(m.getType())) {
@@ -186,6 +188,7 @@
         return switchListeners;
     }
 
+    @Override
     public void terminate() {
     }
 
@@ -197,7 +200,7 @@
 
     @Override
     public boolean injectOfMessage(IOFSwitch sw, OFMessage msg,
-                                   FloodlightContext bContext) {
+            FloodlightContext bContext) {
         dispatchMessage(sw, msg, bContext);
         return true;
     }
@@ -223,10 +226,9 @@
     @Override
     public Map<Class<? extends IFloodlightService>, IFloodlightService>
     getServiceImpls() {
-        Map<Class<? extends IFloodlightService>,
-                IFloodlightService> m =
+        Map<Class<? extends IFloodlightService>, IFloodlightService> m =
                 new HashMap<Class<? extends IFloodlightService>,
-                        IFloodlightService>();
+                IFloodlightService>();
         m.put(IFloodlightProviderService.class, this);
         return m;
     }
@@ -270,7 +272,7 @@
     private void logListeners() {
         for (Map.Entry<OFType,
                 ListenerDispatcher<OFType,
-                        IOFMessageListener>> entry
+                IOFMessageListener>> entry
                 : listeners.entrySet()) {
 
             OFType type = entry.getKey();
diff --git a/src/test/java/net/onrc/onos/core/devicemanager/OnosDeviceManagerTest.java b/src/test/java/net/onrc/onos/core/devicemanager/OnosDeviceManagerTest.java
new file mode 100644
index 0000000..dd104e2
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/devicemanager/OnosDeviceManagerTest.java
@@ -0,0 +1,399 @@
+package net.onrc.onos.core.devicemanager;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import java.util.Date;
+
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IListener.Command;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IUpdate;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.test.FloodlightTestCase;
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.core.datagrid.IDatagridService;
+import net.onrc.onos.core.datagrid.IEventChannel;
+import net.onrc.onos.core.datagrid.IEventChannelListener;
+import net.onrc.onos.core.intent.MockTopology;
+import net.onrc.onos.core.packet.ARP;
+import net.onrc.onos.core.packet.DHCP;
+import net.onrc.onos.core.packet.Data;
+import net.onrc.onos.core.packet.Ethernet;
+import net.onrc.onos.core.packet.IPacket;
+import net.onrc.onos.core.packet.IPv4;
+import net.onrc.onos.core.packet.UDP;
+import net.onrc.onos.core.registry.IControllerRegistryService;
+import net.onrc.onos.core.topology.ITopologyListener;
+import net.onrc.onos.core.topology.ITopologyService;
+
+import org.easymock.EasyMock;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFType;
+
+/**
+ * @author patrick.liu@huawei.com
+ *         <p/>
+ *         Unit tests for the Device Manager module (OnosDeviceManger).
+ *         These test cases check the result of add/delete device and
+ *         verify the result of processPacketIn through inject faked packets
+ *         floodLightProvider, datagridService, networkGraphService,
+ *         controllerRegistryService, eventChannel are mocked out.
+ */
+public class OnosDeviceManagerTest extends FloodlightTestCase {
+    private IPacket pkt0, pkt1, pkt2, pkt3, pkt4;
+    private IOFSwitch sw1;
+    private long sw1Dpid;
+    private short sw1DevPort;
+    private OnosDeviceManager odm;
+    private OFPacketIn pktIn;
+    private FloodlightModuleContext modContext;
+    private ITopologyService networkGraphService;
+    private IEventChannel<Long, OnosDevice> eventChannel;
+    private IFloodlightProviderService floodLightProvider;
+    private Date lastSeenTimestamp;
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        MockTopology topology = new MockTopology();
+        IDatagridService datagridService;
+        IControllerRegistryService controllerRegistryService;
+
+        topology.createSampleTopology1();
+        modContext = new FloodlightModuleContext();
+
+        floodLightProvider = createMock(IFloodlightProviderService.class);
+        datagridService = createMock(IDatagridService.class);
+        networkGraphService = createMock(ITopologyService.class);
+        controllerRegistryService = createMock(IControllerRegistryService.class);
+        eventChannel = createMock(IEventChannel.class);
+        expect(networkGraphService.getTopology()).andReturn(topology).anyTimes();
+        networkGraphService.registerTopologyListener(anyObject(ITopologyListener.class));
+        expectLastCall();
+
+        expect(datagridService.createChannel("onos.device", Long.class, OnosDevice.class))
+        .andReturn(eventChannel).once();
+        expect(topology.getOutgoingLink((long)1,(long)100)).andReturn(null).anyTimes();
+        expect(datagridService.addListener(
+                eq("onos.device"),
+                anyObject(IEventChannelListener.class),
+                eq(Long.class),
+                eq(OnosDevice.class)))
+                .andReturn(eventChannel).once();
+
+        replay(datagridService);
+        replay(networkGraphService);
+        replay(controllerRegistryService);
+
+        modContext.addService(IDatagridService.class,datagridService);
+        modContext.addService(ITopologyService.class,networkGraphService);
+        modContext.addService(IFloodlightProviderService.class, floodLightProvider);
+        modContext.getServiceImpl(IFloodlightProviderService.class);
+        sw1Dpid = 1L;
+        sw1 = createMockSwitch(sw1Dpid);
+        replay(sw1);
+
+        sw1DevPort = 100;
+
+        odm = new OnosDeviceManager();
+        /*
+         * Broadcast address
+         */
+        this.pkt0 = new Ethernet()
+        .setDestinationMACAddress("FF:FF:FF:FF:FF:FF")
+        .setSourceMACAddress("00:44:33:22:11:33")
+        .setEtherType(Ethernet.TYPE_IPV4)
+        .setPayload(
+                new IPv4()
+                .setTtl((byte) 128)
+                .setSourceAddress("192.168.10.1")
+                .setDestinationAddress("192.168.255.255")
+                .setPayload(new UDP()
+                .setSourcePort((short) 5000)
+                .setDestinationPort((short) 5001)
+                .setPayload(new Data(new byte[]{0x01}))));
+        /*
+         * Normal IPv4 packet
+         */
+        this.pkt1 = new Ethernet()
+        .setDestinationMACAddress("00:11:22:33:44:55")
+        .setSourceMACAddress("00:44:33:22:11:00")
+        .setEtherType(Ethernet.TYPE_IPV4)
+        .setPayload(
+                new IPv4()
+                .setTtl((byte) 128)
+                .setSourceAddress("192.168.1.1")
+                .setDestinationAddress("192.168.1.2")
+                .setPayload(new UDP()
+                .setSourcePort((short) 5000)
+                .setDestinationPort((short) 5001)
+                .setPayload(new Data(new byte[]{0x01}))));
+        /*
+         * Same MAC header as pkt1,but not IP address set
+         */
+        this.pkt2 = new Ethernet()
+        .setSourceMACAddress("00:44:33:22:11:01")
+        .setDestinationMACAddress("00:11:22:33:44:55")
+        .setEtherType(Ethernet.TYPE_IPV4)
+        .setPayload(
+                new IPv4()
+                .setTtl((byte) 128)
+                .setPayload(new UDP()
+                .setSourcePort((short) 5000)
+                .setDestinationPort((short) 5001)
+                .setPayload(new Data(new byte[]{0x01}))));
+        /*
+         * DHCP packet
+         */
+        this.pkt3 = new Ethernet()
+        .setSourceMACAddress("00:44:33:22:11:01")
+        .setDestinationMACAddress("00:11:22:33:44:55")
+        .setEtherType(Ethernet.TYPE_IPV4)
+        .setPayload(
+                new IPv4()
+                .setTtl((byte) 128)
+                .setSourceAddress("192.168.1.1")
+                .setDestinationAddress("192.168.1.2")
+                .setPayload(new UDP()
+                .setSourcePort((short) 5000)
+                .setDestinationPort((short) 5001)
+                .setChecksum((short) 0)
+                .setPayload(
+                        new DHCP()
+                        .setOpCode(DHCP.OPCODE_REPLY)
+                        .setHardwareType(DHCP.HWTYPE_ETHERNET)
+                        .setHardwareAddressLength((byte) 6)
+                        .setHops((byte) 0)
+                        .setTransactionId(0x00003d1d)
+                        .setSeconds((short) 0)
+                        .setFlags((short) 0)
+                        .setClientIPAddress(0)
+                        .setYourIPAddress(0)
+                        .setServerIPAddress(0)
+                        .setGatewayIPAddress(0))));
+        /*
+         * ARP packet
+         */
+        this.pkt4 = new Ethernet()
+        .setSourceMACAddress("00:44:33:22:11:01")
+        .setDestinationMACAddress("00:11:22:33:44:55")
+        .setEtherType(Ethernet.TYPE_ARP)
+        .setPayload(
+                new ARP()
+                .setHardwareType(ARP.HW_TYPE_ETHERNET)
+                .setProtocolType(ARP.PROTO_TYPE_IP)
+                .setHardwareAddressLength((byte) 6)
+                .setProtocolAddressLength((byte) 4)
+                .setOpCode(ARP.OP_REPLY)
+                .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01"))
+                .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
+                .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
+                .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
+
+
+        this.pktIn = new OFPacketIn()
+        .setInPort(sw1DevPort);
+
+        lastSeenTimestamp = new Date(1);
+
+        odm.init(modContext);
+        odm.startUp(modContext);
+    }
+
+    @Override
+    @After
+    public void tearDown() throws Exception {
+    }
+
+    public IOFSwitch createMockSwitch(Long id) {
+        IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
+        expect(mockSwitch.getId()).andReturn(id).anyTimes();
+        return mockSwitch;
+    }
+
+    /**
+     * Test set operation on lastSeenTimstamp field in OnosDevice
+     */
+    @Test
+    public void testSetLastSeenTimestamp() {
+        Ethernet eth = (Ethernet)pkt1;
+        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
+
+        floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN), EasyMock.isA(OnosDeviceManager.class));
+        srcDevice.setLastSeenTimestamp(lastSeenTimestamp);
+        assertEquals(lastSeenTimestamp, srcDevice.getLastSeenTimestamp());
+    }
+    /**
+     * test the functionality to get the source device from Packet header
+     * information.
+     */
+    @Test
+    public void testGetSourceDeviceFromPacket() {
+        byte[] address = new byte[] {0x00,0x44,0x33,0x22,0x11,0x01};
+        MACAddress srcMac = new MACAddress(address);
+        IPv4 v4Pkt = new IPv4()
+        .setSourceAddress("192.168.1.1")
+        .setDestinationAddress("192.168.1.2");
+        OnosDevice dev1 = new OnosDevice(srcMac,
+                null,
+                v4Pkt.getSourceAddress(),
+                sw1Dpid,
+                sw1DevPort,
+                null);
+
+        /*
+         * test DHCP packet case
+         */
+        Ethernet eth = (Ethernet)pkt3;
+        OnosDevice dev2 = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
+        assertEquals(dev1, dev2);
+
+        /*
+         * test ARP packet case
+         */
+        eth = (Ethernet)pkt4;
+        dev2 = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
+        assertEquals(dev1, dev2);
+    }
+
+    /**
+     * This test will invoke addOnosDevice to add a new device through Packet pkt1
+     */
+    @Test
+    public void testProcessPacketInAddNewDevice() {
+        Ethernet eth = (Ethernet)pkt1;
+        Long longmac = eth.getSourceMAC().toLong();
+        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
+
+        floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN), EasyMock.isA(OnosDeviceManager.class));
+        EasyMock.expectLastCall();
+        eventChannel.addEntry(longmac, srcDevice);
+        EasyMock.expectLastCall();
+        floodLightProvider.publishUpdate(EasyMock.isA(IUpdate.class));
+        EasyMock.expectLastCall();
+        replay(floodLightProvider, eventChannel);
+
+        Command cmd = odm.processPacketIn(sw1, pktIn, (Ethernet)pkt1);
+        assertEquals(Command.CONTINUE, cmd);
+
+        verify(eventChannel);
+    }
+
+    /**
+     * This test will test return Command.STOP path in processPacketIn method
+     * by injecting a broadcast packet
+     */
+    @Test
+    public void testProcessPacketInStop() {
+        Command cmd = odm.processPacketIn(sw1, pktIn, (Ethernet)pkt0);
+        assertEquals(Command.STOP, cmd);
+    }
+
+    /**
+     * This tests same packet received case.
+     */
+    @Test
+    public void testProcessPacketInSamePacket() {
+        Ethernet eth = (Ethernet)pkt2;
+        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
+        odm.entryAdded(srcDevice);
+        srcDevice.setLastSeenTimestamp(lastSeenTimestamp);
+
+        Command cmd = odm.processPacketIn(sw1, pktIn, (Ethernet)pkt2);
+        assertEquals(Command.CONTINUE, cmd);
+        assertTrue(lastSeenTimestamp.before(srcDevice.getLastSeenTimestamp()));
+    }
+
+    /**
+     * This tests the packet with the same MAC but the second one without IP address
+     */
+    @Test
+    public void testProcessPacketInNoIpAddress() {
+        Ethernet eth = (Ethernet)pkt3;
+        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
+        odm.entryAdded(srcDevice);
+        srcDevice.setLastSeenTimestamp(lastSeenTimestamp);
+
+        Command cmd = odm.processPacketIn(sw1, pktIn, (Ethernet)pkt2);
+        assertEquals(Command.CONTINUE, cmd);
+        assertTrue(lastSeenTimestamp.before(srcDevice.getLastSeenTimestamp()));
+    }
+
+    /**
+     * Test add a device from the information from packet
+     */
+    @Test
+    public void testAddOnosDevice() {
+        Ethernet eth = (Ethernet)pkt1;
+        Long longmac = eth.getSourceMAC().toLong();
+        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
+
+        floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN), EasyMock.isA(OnosDeviceManager.class));
+        EasyMock.expectLastCall();
+        eventChannel.addEntry(longmac, srcDevice);
+        EasyMock.expectLastCall();
+        floodLightProvider.publishUpdate(EasyMock.isA(IUpdate.class));
+        EasyMock.expectLastCall();
+        replay(floodLightProvider, eventChannel);
+
+        odm.addOnosDevice(longmac, srcDevice);
+
+        verify(eventChannel);
+    }
+
+    /**
+     * Test delete a device
+     */
+    @Test
+    public void testDeleteOnosDevice() {
+        Ethernet eth = (Ethernet)pkt1;
+        Long longmac = eth.getSourceMAC().toLong();
+        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
+
+        floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN), EasyMock.isA(OnosDeviceManager.class));
+        EasyMock.expectLastCall();
+        eventChannel.removeEntry(longmac);
+        EasyMock.expectLastCall();
+        floodLightProvider.publishUpdate(EasyMock.isA(IUpdate.class));
+        EasyMock.expectLastCall();
+        replay(floodLightProvider, eventChannel);
+
+        odm.deleteOnosDevice(srcDevice);
+
+        verify(eventChannel);
+    }
+
+    /**
+     * Test delete a device by using its source mac address
+     */
+    @Test
+    public void testDeleteOnosDeviceByMac() {
+        Ethernet eth = (Ethernet)pkt1;
+        MACAddress mac = eth.getSourceMAC();
+        Long longmac = mac.toLong();
+        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
+
+        floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN), EasyMock.isA(OnosDeviceManager.class));
+        EasyMock.expectLastCall();
+        eventChannel.removeEntry(longmac);
+        EasyMock.expectLastCall();
+        floodLightProvider.publishUpdate(EasyMock.isA(IUpdate.class));
+        EasyMock.expectLastCall();
+        replay(floodLightProvider, eventChannel);
+
+        odm.entryAdded(srcDevice);
+        odm.deleteOnosDeviceByMac(mac);
+        verify(eventChannel);
+    }
+}