Gather topology element info to TopologyImpl

- Moved all the self-contained topology elements (*Event) to
  TopologyImpl. (ONOS-1651)
  Now {Switch, Port, Link, Host}Impl is just a handler attached to
  TopologyImpl.
- BugFix: TopologyManager.addHost(HostEvent)
  HostEvent could be pushed to reorder queue multiple times,
  if multiple attachment point was given.
- BugFix: TopologyManager.{addLink, removePort}
  Properly handle if Host attachment point was removed as side-effect.
- BugFix: Copy HostEvent#lastSeenTime
- BugFix: Event instance notified to listeners (api*Events) should be
  the event which was/will be in the replica. (TopologyManager)
- Added/Modified debug log in TopologyManager so that log will be in
  same format for each event type.
  "{Added, Update, Removed} <Self-contained>"
- Removed backdoor method and use TestUtils instead.

Change-Id: If053d6f11f39574a188e7a52cb6194114f8afe5d
diff --git a/src/test/java/net/onrc/onos/core/topology/MockTopology.java b/src/test/java/net/onrc/onos/core/topology/MockTopology.java
index a089b6c..3208a0d 100644
--- a/src/test/java/net/onrc/onos/core/topology/MockTopology.java
+++ b/src/test/java/net/onrc/onos/core/topology/MockTopology.java
@@ -2,7 +2,9 @@
 
 import net.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.LinkTuple;
 import net.onrc.onos.core.util.PortNumber;
+import net.onrc.onos.core.util.SwitchPort;
 
 /**
  * A mock class of Topology.
@@ -20,35 +22,35 @@
     public SwitchImpl sw1, sw2, sw3, sw4;
 
     public Switch addSwitch(Long switchId) {
-        SwitchImpl sw = new SwitchImpl(this, new Dpid(switchId));
+        SwitchEvent sw = new SwitchEvent(new Dpid(switchId));
         this.putSwitch(sw);
-        return sw;
+        return this.getSwitch(sw.getDpid());
     }
 
     public Port addPort(Switch sw, Long portNumber) {
-        PortImpl port = new PortImpl(this, sw.getDpid(),
+        PortEvent port = new PortEvent(sw.getDpid(),
                                 new PortNumber(portNumber.shortValue()));
         ((TopologyImpl) this).putPort(port);
-        return port;
+        return this.getPort(port.getSwitchPort());
     }
 
-    public Link[] addBidirectionalLinks(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
-        Link[] links = new Link[2];
-        final Dpid srcDpidObj = new Dpid(srcDpid);
-        final Dpid dstDpidObj = new Dpid(dstDpid);
-        final PortNumber srcPortNum = new PortNumber(srcPortNo.shortValue());
-        final PortNumber dstPortNum = new PortNumber(dstPortNo.shortValue());
-        links[0] = new LinkImpl(this,
-                getPort(srcDpidObj, srcPortNum),
-                getPort(dstDpidObj, dstPortNum));
-        links[1] = new LinkImpl(this,
-                getPort(dstDpidObj, dstPortNum),
-                getPort(srcDpidObj, srcPortNum));
+    public void addBidirectionalLinks(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
+        addBidirectionalLinks(srcDpid, srcPortNo, dstDpid, dstPortNo, null);
+    }
+
+    public void addBidirectionalLinks(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo, Double capacity) {
+        LinkEvent[] links = new LinkEvent[2];
+        final SwitchPort src = new SwitchPort(srcDpid, srcPortNo);
+        final SwitchPort dst = new SwitchPort(dstDpid, dstPortNo);
+        links[0] = new LinkEvent(src, dst);
+        links[1] = new LinkEvent(dst, src);
+        if (capacity != null) {
+            links[0].setCapacity(capacity);
+            links[1].setCapacity(capacity);
+        }
 
         putLink(links[0]);
         putLink(links[1]);
-
-        return links;
     }
 
     /**
@@ -81,16 +83,11 @@
         addPort(sw4, 42L); // sw4 -> sw2
         addPort(sw4, 43L); // sw4 -> sw3
 
-        addBidirectionalLinks(1L, 12L, 2L, 21L);
-        addBidirectionalLinks(2L, 23L, 3L, 32L);
-        addBidirectionalLinks(3L, 34L, 4L, 43L);
-        addBidirectionalLinks(4L, 41L, 1L, 14L);
-        addBidirectionalLinks(2L, 24L, 4L, 42L);
-
-        // set capacity of all links to 1000Mbps
-        for (Link link : getLinks()) {
-            ((LinkImpl) link).setCapacity(1000.0);
-        }
+        addBidirectionalLinks(1L, 12L, 2L, 21L, 1000.0);
+        addBidirectionalLinks(2L, 23L, 3L, 32L, 1000.0);
+        addBidirectionalLinks(3L, 34L, 4L, 43L, 1000.0);
+        addBidirectionalLinks(4L, 41L, 1L, 14L, 1000.0);
+        addBidirectionalLinks(2L, 24L, 4L, 42L, 1000.0);
     }
 
     /**
@@ -128,38 +125,39 @@
         Port port43 = addPort(sw4, 43L); // sw4 -> sw3
 
         MACAddress mac1 = MACAddress.valueOf("00:44:33:22:11:00");
-        HostImpl dev1 = new HostImpl(this, mac1);
-        dev1.addAttachmentPoint(port15);
-        dev1.setLastSeenTime(1L);
-        this.putHost(dev1);
+        HostEvent host1 = new HostEvent(mac1);
+        host1.addAttachmentPoint(port15.asSwitchPort());
+        host1.setLastSeenTime(1L);
+        this.putHost(host1);
 
         MACAddress mac3 = MACAddress.valueOf("00:11:22:33:44:55");
-        HostImpl dev3 = new HostImpl(this, mac3);
-        dev3.addAttachmentPoint(port35);
-        dev3.setLastSeenTime(1L);
-        this.putHost(dev3);
+        HostEvent host3 = new HostEvent(mac3);
+        host3.addAttachmentPoint(port35.asSwitchPort());
+        host3.setLastSeenTime(1L);
+        this.putHost(host3);
 
-        addBidirectionalLinks(1L, 12L, 2L, 21L);
-        addBidirectionalLinks(2L, 23L, 3L, 32L);
-        addBidirectionalLinks(3L, 34L, 4L, 43L);
-        addBidirectionalLinks(4L, 41L, 1L, 14L);
-        addBidirectionalLinks(2L, 24L, 4L, 42L);
-
-        // set capacity of all links to 1000Mbps
-        for (Link link : getLinks()) {
-            ((LinkImpl) link).setCapacity(1000.0);
-        }
+        addBidirectionalLinks(1L, 12L, 2L, 21L, 1000.0);
+        addBidirectionalLinks(2L, 23L, 3L, 32L, 1000.0);
+        addBidirectionalLinks(3L, 34L, 4L, 43L, 1000.0);
+        addBidirectionalLinks(4L, 41L, 1L, 14L, 1000.0);
+        addBidirectionalLinks(2L, 24L, 4L, 42L, 1000.0);
     }
 
     public void removeLink(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
-        removeLink(getLink(new Dpid(srcDpid),
+        this.removeLink(new Dpid(srcDpid),
                            new PortNumber(srcPortNo.shortValue()),
                            new Dpid(dstDpid),
-                           new PortNumber(dstPortNo.shortValue())));
+                           new PortNumber(dstPortNo.shortValue()));
     }
 
     public void removeLink(Dpid srcDpid, PortNumber srcPortNo,
-                           Dpid dstDpid, PortNumber dstPortNo) {
-        super.removeLink(getLink(srcDpid, srcPortNo, dstDpid, dstPortNo));
+            Dpid dstDpid, PortNumber dstPortNo) {
+        this.removeLink(srcDpid, srcPortNo, dstDpid, dstPortNo,
+                TopologyElement.TYPE_PACKET_LAYER);
+    }
+    public void removeLink(Dpid srcDpid, PortNumber srcPortNo,
+                           Dpid dstDpid, PortNumber dstPortNo, String type) {
+        super.removeLink(new LinkTuple(srcDpid, srcPortNo, dstDpid, dstPortNo),
+                        type);
     }
 }
diff --git a/src/test/java/net/onrc/onos/core/topology/TopologyImplTest.java b/src/test/java/net/onrc/onos/core/topology/TopologyImplTest.java
index d02142a..df0818f 100644
--- a/src/test/java/net/onrc/onos/core/topology/TopologyImplTest.java
+++ b/src/test/java/net/onrc/onos/core/topology/TopologyImplTest.java
@@ -3,11 +3,14 @@
 import static org.junit.Assert.*;
 import static org.hamcrest.Matchers.*;
 
+import java.util.Collection;
 import java.util.Iterator;
 
 import net.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.LinkTuple;
 import net.onrc.onos.core.util.PortNumber;
+import net.onrc.onos.core.util.SwitchPort;
 
 import org.junit.After;
 import org.junit.Before;
@@ -31,6 +34,7 @@
 
     // Set the test network size, it should be larger than 3
     private static final long TEST_SWITCH_NUM = 100L;
+    private static final long TEST_HOST_NUM = TEST_SWITCH_NUM;
 
     @Before
     public void setUp() throws Exception {
@@ -39,32 +43,33 @@
 
         // Create a number of switches and install two ports for each switch
         for (long switchID = 1; switchID <= TEST_SWITCH_NUM; switchID++) {
-            SwitchImpl testSwitch = new SwitchImpl(testTopology, new Dpid(switchID));
+            final Dpid dpid = new Dpid(switchID);
+            SwitchEvent testSwitch = new SwitchEvent(dpid);
             testTopology.putSwitch(testSwitch);
-            testTopology.putPort(new PortImpl(testTopology,
-                    new Dpid(switchID), PORT_NUMBER_1));
-            testTopology.putPort(new PortImpl(testTopology,
-                    new Dpid(switchID), PORT_NUMBER_2));
-            Port hostPort = new PortImpl(testTopology,
-                    new Dpid(switchID), new PortNumber(SWITCH_HOST_PORT.shortValue()));
+            testTopology.putPort(new PortEvent(dpid, PORT_NUMBER_1));
+            testTopology.putPort(new PortEvent(dpid, PORT_NUMBER_2));
+            PortEvent hostPort = new PortEvent(dpid,
+                    new PortNumber(SWITCH_HOST_PORT.shortValue()));
             testTopology.putPort(hostPort);
 
             // Create a host for each switch
             MACAddress devMac = MACAddress.valueOf(switchID);
-            HostImpl testHost = new HostImpl(testTopology, devMac);
-            testHost.addAttachmentPoint(hostPort);
+            HostEvent testHost = new HostEvent(devMac);
+            testHost.addAttachmentPoint(hostPort.getSwitchPort());
             testTopology.putHost(testHost);
         }
 
         // Create one bidirectional link b/w two switches to construct a ring topology
         for (long switchID = 1; switchID <= TEST_SWITCH_NUM; switchID++) {
-            LinkImpl testLinkEast = new LinkImpl(testTopology,
-                    testTopology.getPort(new Dpid(switchID), PORT_NUMBER_2),
-                    testTopology.getPort(new Dpid(switchID % TEST_SWITCH_NUM + 1), PORT_NUMBER_1)
+            final Dpid dpidA = new Dpid(switchID);
+            final Dpid dpidB = new Dpid(switchID % TEST_SWITCH_NUM + 1);
+            LinkEvent testLinkEast = new LinkEvent(
+                    testTopology.getPort(dpidA, PORT_NUMBER_2).asSwitchPort(),
+                    testTopology.getPort(dpidB, PORT_NUMBER_1).asSwitchPort()
                     );
-            LinkImpl testLinkWest = new LinkImpl(testTopology,
-                    testTopology.getPort(new Dpid(switchID % TEST_SWITCH_NUM + 1), PORT_NUMBER_1),
-                    testTopology.getPort(new Dpid(switchID), PORT_NUMBER_2)
+            LinkEvent testLinkWest = new LinkEvent(
+                    testTopology.getPort(dpidB, PORT_NUMBER_1).asSwitchPort(),
+                    testTopology.getPort(dpidA, PORT_NUMBER_2).asSwitchPort()
                     );
             testTopology.putLink(testLinkEast);
             testTopology.putLink(testLinkWest);
@@ -108,11 +113,12 @@
         PortNumber bogusPortNum = new PortNumber((short) (SWITCH_PORT_2 + 1));
         for (long switchID = 1; switchID <= TEST_SWITCH_NUM; switchID++) {
             // Verify ports are in the graphDB
-            assertNotNull(testTopology.getSwitch(new Dpid(switchID)).getPort(PORT_NUMBER_1));
-            assertNotNull(testTopology.getSwitch(new Dpid(switchID)).getPort(PORT_NUMBER_2));
+            final Dpid dpid = new Dpid(switchID);
+            assertNotNull(testTopology.getSwitch(dpid).getPort(PORT_NUMBER_1));
+            assertNotNull(testTopology.getSwitch(dpid).getPort(PORT_NUMBER_2));
 
             // Verify there is no such port in the graphDB
-            assertNull(testTopology.getSwitch(new Dpid(switchID)).getPort(bogusPortNum));
+            assertNull(testTopology.getSwitch(dpid).getPort(bogusPortNum));
         }
     }
 
@@ -134,6 +140,23 @@
             Switch srcSw = (objectLink.getSrcSwitch());
             Switch dstSw = (objectLink.getDstSwitch());
 
+            LinkTuple linkId = objectLink.getLinkTuple();
+            // Verify the link through #getLink
+            Link linkA = testTopology.getLink(linkId.getSrc().getDpid(),
+                    linkId.getSrc().getPortNumber(),
+                    linkId.getDst().getDpid(),
+                    linkId.getDst().getPortNumber());
+            assertEquals(linkId, linkA.getLinkTuple());
+
+            Link linkB = testTopology.getLink(linkId.getSrc().getDpid(),
+                    linkId.getSrc().getPortNumber(),
+                    linkId.getDst().getDpid(),
+                    linkId.getDst().getPortNumber(),
+                    TopologyElement.TYPE_PACKET_LAYER);
+            assertEquals(linkId, linkB.getLinkTuple());
+
+
+
             // confirm link is forming a link
             final long smallerDpid = Math.min(srcSw.getDpid().value(), dstSw.getDpid().value());
             final long largerDpid = Math.max(srcSw.getDpid().value(), dstSw.getDpid().value());
@@ -152,11 +175,22 @@
     public void testGetOutgoingLink() {
         PortNumber bogusPortNum = new PortNumber((short) (SWITCH_PORT_2 + 1));
         for (long switchID = 1; switchID <= TEST_SWITCH_NUM; switchID++) {
-            assertNotNull(testTopology.getOutgoingLink(new Dpid(switchID), PORT_NUMBER_1));
-            assertNotNull(testTopology.getOutgoingLink(new Dpid(switchID), PORT_NUMBER_2));
+            final Dpid dpid = new Dpid(switchID);
+            assertNotNull(testTopology.getOutgoingLink(dpid, PORT_NUMBER_1));
+            assertNotNull(testTopology.getOutgoingLink(dpid, PORT_NUMBER_2));
+
+            Link la = testTopology.getOutgoingLink(dpid, PORT_NUMBER_2,
+                                TopologyElement.TYPE_PACKET_LAYER);
+            Link lb = testTopology.getOutgoingLink(dpid, PORT_NUMBER_2);
+
+            assertTrue(la.getLinkTuple().equals(lb.getLinkTuple()));
+
+            Collection<Link> links = testTopology.getOutgoingLinks(
+                                        new SwitchPort(dpid, PORT_NUMBER_1));
+            assertEquals(1, links.size());
 
             // Verify there is no such link in the graphDB
-            assertNull(testTopology.getOutgoingLink(new Dpid(switchID), bogusPortNum));
+            assertNull(testTopology.getOutgoingLink(dpid, bogusPortNum));
         }
     }
 
@@ -168,22 +202,33 @@
         PortNumber bogusPortNum = new PortNumber((short) (SWITCH_PORT_2 + 1));
         for (long switchID = 1; switchID <= TEST_SWITCH_NUM; switchID++) {
             // Verify the links are in the graphDB
+            final Dpid dpid = new Dpid(switchID);
             assertNotNull(testTopology.getIncomingLink(
-                                           new Dpid(switchID), PORT_NUMBER_1));
+                                           dpid, PORT_NUMBER_1));
             assertNotNull(testTopology.getIncomingLink(
-                                           new Dpid(switchID), PORT_NUMBER_2));
+                                           dpid, PORT_NUMBER_2));
+
+            Link la = testTopology.getIncomingLink(dpid, PORT_NUMBER_2,
+                                        TopologyElement.TYPE_PACKET_LAYER);
+            Link lb = testTopology.getIncomingLink(dpid, PORT_NUMBER_2);
+
+            assertTrue(la.getLinkTuple().equals(lb.getLinkTuple()));
+
+            Collection<Link> links = testTopology.getIncomingLinks(
+                    new SwitchPort(dpid, PORT_NUMBER_1));
+            assertEquals(1, links.size());
 
             // Verify there is no such link in the graphDB
             assertNull(testTopology.getIncomingLink(
-                                        new Dpid(switchID), bogusPortNum));
+                                        dpid, bogusPortNum));
         }
     }
 
     /**
-     * Test the result of getDeviceByMac function.
+     * Test the result of getHostByMac function.
      */
     @Test
-    public void testGetDeviceByMac() {
+    public void testGetHostByMac() {
         for (long switchID = 1; switchID <= TEST_SWITCH_NUM; switchID++) {
             MACAddress devMac = MACAddress.valueOf(switchID);
 
@@ -193,21 +238,27 @@
     }
 
     /**
-     * Test the result of removeDevice function.
+     * Test the result of removeHost function.
      */
     @Test
-    public void testRemoveDevice() {
+    public void testRemoveHost() {
         int devCount = 0;
         Iterator<Host> itr = testTopology.getHosts().iterator();
         while (itr.hasNext()) {
             Host currDev = itr.next();
-            testTopology.removeHost(currDev);
-            testTopology.getHostByMac(currDev.getMacAddress());
+            final MACAddress mac = currDev.getMacAddress();
+            testTopology.removeHost(mac);
+            assertNull(testTopology.getHostByMac(mac));
             devCount++;
         }
+        for (Switch sw : testTopology.getSwitches()) {
+            for (Port port : sw.getPorts()) {
+                assertTrue(port.getHosts().isEmpty());
+            }
+        }
 
         // Verify all hosts have been removed successfully
-        assertEquals(TEST_SWITCH_NUM, devCount);
+        assertEquals(TEST_HOST_NUM, devCount);
     }
 
     /**
@@ -224,7 +275,8 @@
             Port srcPort = objectLink.getSrcPort();
             Switch dstSw = (objectLink.getDstSwitch());
             Port dstPort = objectLink.getDstPort();
-            testTopology.removeLink(objectLink);
+
+            testTopology.removeLink(objectLink.getLinkTuple());
 
             // Verify the link was removed successfully
             assertNull(testTopology.getLink(
@@ -242,14 +294,18 @@
     @Test
     public void testRemoveSwitch() {
         for (long switchID = 1; switchID <= TEST_SWITCH_NUM; switchID++) {
-            Iterator<Host> itr = testTopology.getSwitch(new Dpid(switchID)).getHosts().iterator();
+            final Dpid dpid = new Dpid(switchID);
+            Iterator<Host> itr = testTopology.getSwitch(dpid).getHosts().iterator();
             while (itr.hasNext()) {
-                testTopology.removeHost(itr.next());
+                testTopology.removeHost(itr.next().getMacAddress());
             }
-            testTopology.removeSwitch(new Dpid(switchID));
+            for (Port port : testTopology.getSwitch(dpid).getPorts()) {
+                testTopology.removePort(port.asSwitchPort());
+            }
+            testTopology.removeSwitch(dpid);
 
             // Verify the switch has been removed from the graphDB successfully
-            assertNull(testTopology.getSwitch(new Dpid(switchID)));
+            assertNull(testTopology.getSwitch(dpid));
         }
 
         // Verify all switches have been removed successfully
diff --git a/src/test/java/net/onrc/onos/core/topology/TopologyManagerTest.java b/src/test/java/net/onrc/onos/core/topology/TopologyManagerTest.java
index e4f6c8c..309bfb4 100644
--- a/src/test/java/net/onrc/onos/core/topology/TopologyManagerTest.java
+++ b/src/test/java/net/onrc/onos/core/topology/TopologyManagerTest.java
@@ -6,6 +6,8 @@
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.*;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -20,6 +22,7 @@
 import net.onrc.onos.core.util.Dpid;
 import net.onrc.onos.core.util.PortNumber;
 import net.onrc.onos.core.util.SwitchPort;
+import net.onrc.onos.core.util.TestUtils;
 
 import org.easymock.EasyMock;
 import org.junit.After;
@@ -111,8 +114,14 @@
         // Create a topologyManager object for testing
         topologyListeners = new CopyOnWriteArrayList<>();
         theTopologyManager = new TopologyManager(registryService, topologyListeners);
+
+        // replace EventHandler to avoid thread from starting
+        TestUtils.setField(theTopologyManager, "eventHandler",
+            EasyMock.createNiceMock(TopologyManager.EventHandler.class));
         theTopologyManager.startup(datagridService);
-        theTopologyManager.debugReplaceDataStore(dataStoreService);
+
+        // replace data store with Mocked object
+        TestUtils.setField(theTopologyManager, "datastore", dataStoreService);
     }
 
     @After
@@ -335,4 +344,621 @@
         verify(eventChannel);
     }
 
+    /**
+     * Test to confirm topology replica transformation.
+     */
+    @Test
+    public void testAddSwitch() {
+        setupTopologyManager();
+
+        final Dpid dpid = new Dpid(1);
+        SwitchEvent sw = new SwitchEvent(dpid);
+        sw.createStringAttribute("foo", "bar");
+
+        TestUtils.callMethod(theTopologyManager, "addSwitch", SwitchEvent.class, sw);
+
+        // check topology structure
+        TopologyInternal topology = (TopologyInternal) theTopologyManager.getTopology();
+        SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
+        assertEquals(sw, swInTopo);
+        assertTrue(swInTopo.isFrozen());
+        assertEquals("bar", swInTopo.getStringAttribute("foo"));
+
+        // check events to be fired
+        List<SwitchEvent> apiAddedSwitchEvents
+            = TestUtils.getField(theTopologyManager, "apiAddedSwitchEvents");
+        assertThat(apiAddedSwitchEvents, hasItem(sw));
+    }
+
+    /**
+     * Test to confirm topology replica transformation.
+     */
+    @Test
+    public void testAddPort() {
+        setupTopologyManager();
+
+        final Dpid dpid = new Dpid(1);
+        SwitchEvent sw = new SwitchEvent(dpid);
+        sw.createStringAttribute("foo", "bar");
+
+        final PortNumber portNumber = new PortNumber((short) 2);
+        PortEvent port = new PortEvent(dpid, portNumber);
+        port.createStringAttribute("fuzz", "buzz");
+
+        TestUtils.callMethod(theTopologyManager, "addSwitch", SwitchEvent.class, sw);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, port);
+
+        // check topology structure
+        TopologyInternal topology = (TopologyInternal) theTopologyManager.getTopology();
+        SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
+        assertEquals(sw, swInTopo);
+        assertTrue(swInTopo.isFrozen());
+        assertEquals("bar", swInTopo.getStringAttribute("foo"));
+
+        final SwitchPort portId = new SwitchPort(dpid, portNumber);
+        PortEvent portInTopo = topology.getPortEvent(portId);
+        assertEquals(port, portInTopo);
+        assertTrue(portInTopo.isFrozen());
+        assertEquals("buzz", portInTopo.getStringAttribute("fuzz"));
+
+        // check events to be fired
+        List<PortEvent> apiAddedPortEvents
+            = TestUtils.getField(theTopologyManager, "apiAddedPortEvents");
+        assertThat(apiAddedPortEvents, hasItem(port));
+    }
+
+    /**
+     * Test to confirm topology replica transformation.
+     */
+    @Test
+    public void testRemovePortThenSwitch() {
+        setupTopologyManager();
+
+        final Dpid dpid = new Dpid(1);
+        SwitchEvent sw = new SwitchEvent(dpid);
+        sw.createStringAttribute("foo", "bar");
+
+        final PortNumber portNumber = new PortNumber((short) 2);
+        PortEvent port = new PortEvent(dpid, portNumber);
+        port.createStringAttribute("fuzz", "buzz");
+
+        TestUtils.callMethod(theTopologyManager, "addSwitch", SwitchEvent.class, sw);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, port);
+
+        // check topology structure
+        TopologyInternal topology = (TopologyInternal) theTopologyManager.getTopology();
+        SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
+        assertEquals(sw, swInTopo);
+        assertTrue(swInTopo.isFrozen());
+        assertEquals("bar", swInTopo.getStringAttribute("foo"));
+
+        final SwitchPort portId = new SwitchPort(dpid, portNumber);
+        PortEvent portInTopo = topology.getPortEvent(portId);
+        assertEquals(port, portInTopo);
+        assertTrue(portInTopo.isFrozen());
+        assertEquals("buzz", portInTopo.getStringAttribute("fuzz"));
+
+        // remove in proper order
+        TestUtils.callMethod(theTopologyManager, "removePort",
+                            PortEvent.class, new PortEvent(port));
+        TestUtils.callMethod(theTopologyManager, "removeSwitch",
+                            SwitchEvent.class, new SwitchEvent(sw));
+
+
+        // check events to be fired
+        List<PortEvent> apiRemovedPortEvents
+            = TestUtils.getField(theTopologyManager, "apiRemovedPortEvents");
+        assertThat(apiRemovedPortEvents, hasItem(port));
+        List<SwitchEvent> apiRemovedSwitchEvents
+            = TestUtils.getField(theTopologyManager, "apiRemovedSwitchEvents");
+        assertThat(apiRemovedSwitchEvents, hasItem(sw));
+    }
+
+    /**
+     * Test to confirm topology replica transformation.
+     */
+    @Test
+    public void testRemoveSwitch() {
+        setupTopologyManager();
+
+        final Dpid dpid = new Dpid(1);
+        SwitchEvent sw = new SwitchEvent(dpid);
+        sw.createStringAttribute("foo", "bar");
+
+        final PortNumber portNumber = new PortNumber((short) 2);
+        PortEvent port = new PortEvent(dpid, portNumber);
+        port.createStringAttribute("fuzz", "buzz");
+
+        TestUtils.callMethod(theTopologyManager, "addSwitch", SwitchEvent.class, sw);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, port);
+
+        // check topology structure
+        TopologyInternal topology = (TopologyInternal) theTopologyManager.getTopology();
+        SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
+        assertEquals(sw, swInTopo);
+        assertTrue(swInTopo.isFrozen());
+        assertEquals("bar", swInTopo.getStringAttribute("foo"));
+
+        final SwitchPort portId = new SwitchPort(dpid, portNumber);
+        PortEvent portInTopo = topology.getPortEvent(portId);
+        assertEquals(port, portInTopo);
+        assertTrue(portInTopo.isFrozen());
+        assertEquals("buzz", portInTopo.getStringAttribute("fuzz"));
+
+        // remove in in-proper order
+//        TestUtils.callMethod(theTopologyManager, "removePort",
+//                            PortEvent.class, new PortEvent(port));
+        TestUtils.callMethod(theTopologyManager, "removeSwitch",
+                            SwitchEvent.class, new SwitchEvent(sw));
+
+
+        // check events to be fired
+        // outcome should be the same as #testRemovePortThenSwitch
+        List<PortEvent> apiRemovedPortEvents
+            = TestUtils.getField(theTopologyManager, "apiRemovedPortEvents");
+        assertThat(apiRemovedPortEvents, hasItem(port));
+        List<SwitchEvent> apiRemovedSwitchEvents
+            = TestUtils.getField(theTopologyManager, "apiRemovedSwitchEvents");
+        assertThat(apiRemovedSwitchEvents, hasItem(sw));
+    }
+
+    /**
+     * Test to confirm topology replica transformation.
+     */
+    @Test
+    public void testAddLink() {
+        setupTopologyManager();
+
+        final Dpid dpid = new Dpid(1);
+        SwitchEvent sw = new SwitchEvent(dpid);
+        sw.createStringAttribute("foo", "bar");
+
+        final PortNumber portNumberA = new PortNumber((short) 2);
+        PortEvent portA = new PortEvent(dpid, portNumberA);
+        portA.createStringAttribute("fuzz", "buzz");
+
+        final PortNumber portNumberB = new PortNumber((short) 3);
+        PortEvent portB = new PortEvent(dpid, portNumberB);
+        portB.createStringAttribute("fizz", "buz");
+
+        LinkEvent linkA = new LinkEvent(portA.getSwitchPort(), portB.getSwitchPort());
+        linkA.createStringAttribute(TopologyElement.TYPE,
+                                    TopologyElement.TYPE_OPTICAL_LAYER);
+        LinkEvent linkB = new LinkEvent(portB.getSwitchPort(), portA.getSwitchPort());
+        linkB.createStringAttribute(TopologyElement.TYPE,
+                                    TopologyElement.TYPE_OPTICAL_LAYER);
+
+        TestUtils.callMethod(theTopologyManager, "addSwitch", SwitchEvent.class, sw);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portA);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portB);
+        TestUtils.callMethod(theTopologyManager, "addLink", LinkEvent.class, linkA);
+        TestUtils.callMethod(theTopologyManager, "addLink", LinkEvent.class, linkB);
+
+        // check topology structure
+        TopologyInternal topology = (TopologyInternal) theTopologyManager.getTopology();
+        SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
+        assertEquals(sw, swInTopo);
+        assertTrue(swInTopo.isFrozen());
+        assertEquals("bar", swInTopo.getStringAttribute("foo"));
+
+        final SwitchPort portIdA = new SwitchPort(dpid, portNumberA);
+        PortEvent portAInTopo = topology.getPortEvent(portIdA);
+        assertEquals(portA, portAInTopo);
+        assertTrue(portAInTopo.isFrozen());
+        assertEquals("buzz", portAInTopo.getStringAttribute("fuzz"));
+
+        final SwitchPort portIdB = new SwitchPort(dpid, portNumberB);
+        PortEvent portBInTopo = topology.getPortEvent(portIdB);
+        assertEquals(portB, portBInTopo);
+        assertTrue(portBInTopo.isFrozen());
+        assertEquals("buz", portBInTopo.getStringAttribute("fizz"));
+
+        LinkEvent linkAInTopo = topology.getLinkEvent(linkA.getLinkTuple());
+        assertEquals(linkA, linkAInTopo);
+        assertTrue(linkAInTopo.isFrozen());
+        assertEquals(TopologyElement.TYPE_OPTICAL_LAYER, linkAInTopo.getType());
+
+        LinkEvent linkBInTopo = topology.getLinkEvent(linkB.getLinkTuple());
+        assertEquals(linkB, linkBInTopo);
+        assertTrue(linkBInTopo.isFrozen());
+        assertEquals(TopologyElement.TYPE_OPTICAL_LAYER, linkBInTopo.getType());
+
+        // check events to be fired
+        List<LinkEvent> apiAddedLinkEvents
+            = TestUtils.getField(theTopologyManager, "apiAddedLinkEvents");
+        assertThat(apiAddedLinkEvents, containsInAnyOrder(linkA, linkB));
+    }
+
+    /**
+     * Test to confirm topology replica transformation.
+     */
+    @Test
+    public void testAddLinkKickingOffHost() {
+        setupTopologyManager();
+
+        final Dpid dpid = new Dpid(1);
+        SwitchEvent sw = new SwitchEvent(dpid);
+        sw.createStringAttribute("foo", "bar");
+
+        final PortNumber portNumberA = new PortNumber((short) 2);
+        PortEvent portA = new PortEvent(dpid, portNumberA);
+        portA.createStringAttribute("fuzz", "buzz");
+
+        final PortNumber portNumberB = new PortNumber((short) 3);
+        PortEvent portB = new PortEvent(dpid, portNumberB);
+        portB.createStringAttribute("fizz", "buz");
+
+        final PortNumber portNumberC = new PortNumber((short) 4);
+        PortEvent portC = new PortEvent(dpid, portNumberC);
+        portC.createStringAttribute("fizz", "buz");
+
+        final MACAddress macA = MACAddress.valueOf(666L);
+        HostEvent hostA = new HostEvent(macA);
+        hostA.addAttachmentPoint(portA.getSwitchPort());
+        final long timestampA = 392893200L;
+        hostA.setLastSeenTime(timestampA);
+
+        final MACAddress macB = MACAddress.valueOf(999L);
+        HostEvent hostB = new HostEvent(macB);
+        hostB.addAttachmentPoint(portB.getSwitchPort());
+        hostB.addAttachmentPoint(portC.getSwitchPort());
+        final long timestampB = 392893201L;
+        hostB.setLastSeenTime(timestampB);
+
+
+        LinkEvent linkA = new LinkEvent(portA.getSwitchPort(), portB.getSwitchPort());
+        linkA.createStringAttribute(TopologyElement.TYPE,
+                                    TopologyElement.TYPE_OPTICAL_LAYER);
+        LinkEvent linkB = new LinkEvent(portB.getSwitchPort(), portA.getSwitchPort());
+        linkB.createStringAttribute(TopologyElement.TYPE,
+                                    TopologyElement.TYPE_OPTICAL_LAYER);
+
+        TestUtils.callMethod(theTopologyManager, "addSwitch", SwitchEvent.class, sw);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portA);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portB);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portC);
+        TestUtils.callMethod(theTopologyManager, "addHost", HostEvent.class, hostA);
+        TestUtils.callMethod(theTopologyManager, "addHost", HostEvent.class, hostB);
+
+        TestUtils.callMethod(theTopologyManager, "addLink", LinkEvent.class, linkA);
+        TestUtils.callMethod(theTopologyManager, "addLink", LinkEvent.class, linkB);
+
+        // check topology structure
+        TopologyInternal topology = (TopologyInternal) theTopologyManager.getTopology();
+        SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
+        assertEquals(sw, swInTopo);
+        assertTrue(swInTopo.isFrozen());
+        assertEquals("bar", swInTopo.getStringAttribute("foo"));
+
+        final SwitchPort portIdA = new SwitchPort(dpid, portNumberA);
+        PortEvent portAInTopo = topology.getPortEvent(portIdA);
+        assertEquals(portA, portAInTopo);
+        assertTrue(portAInTopo.isFrozen());
+        assertEquals("buzz", portAInTopo.getStringAttribute("fuzz"));
+
+        final SwitchPort portIdB = new SwitchPort(dpid, portNumberB);
+        PortEvent portBInTopo = topology.getPortEvent(portIdB);
+        assertEquals(portB, portBInTopo);
+        assertTrue(portBInTopo.isFrozen());
+        assertEquals("buz", portBInTopo.getStringAttribute("fizz"));
+
+        // hostA expected to be removed
+        assertNull(topology.getHostEvent(macA));
+        // hostB expected to be there with reduced attachment point
+        HostEvent hostBrev = new HostEvent(macB);
+        hostBrev.addAttachmentPoint(portC.getSwitchPort());
+        hostBrev.setLastSeenTime(timestampB);
+        hostBrev.freeze();
+        assertEquals(hostBrev, topology.getHostEvent(macB));
+
+
+        LinkEvent linkAInTopo = topology.getLinkEvent(linkA.getLinkTuple());
+        assertEquals(linkA, linkAInTopo);
+        assertTrue(linkAInTopo.isFrozen());
+        assertEquals(TopologyElement.TYPE_OPTICAL_LAYER, linkAInTopo.getType());
+
+        LinkEvent linkBInTopo = topology.getLinkEvent(linkB.getLinkTuple());
+        assertEquals(linkB, linkBInTopo);
+        assertTrue(linkBInTopo.isFrozen());
+        assertEquals(TopologyElement.TYPE_OPTICAL_LAYER, linkBInTopo.getType());
+
+        // check events to be fired
+        List<HostEvent> apiAddedHostEvents
+            = TestUtils.getField(theTopologyManager, "apiAddedHostEvents");
+        assertThat(apiAddedHostEvents, hasItem(hostBrev));
+
+        List<HostEvent> apiRemovedHostEvents
+            = TestUtils.getField(theTopologyManager, "apiRemovedHostEvents");
+        assertThat(apiRemovedHostEvents, hasItem(hostA));
+        List<LinkEvent> apiAddedLinkEvents
+            = TestUtils.getField(theTopologyManager, "apiAddedLinkEvents");
+        assertThat(apiAddedLinkEvents, containsInAnyOrder(linkA, linkB));
+    }
+
+    /**
+     * Test to confirm topology replica transformation.
+     */
+    @Test
+    public void testRemoveLink() {
+        setupTopologyManager();
+
+        final Dpid dpid = new Dpid(1);
+        SwitchEvent sw = new SwitchEvent(dpid);
+        sw.createStringAttribute("foo", "bar");
+
+        final PortNumber portNumberA = new PortNumber((short) 2);
+        PortEvent portA = new PortEvent(dpid, portNumberA);
+        portA.createStringAttribute("fuzz", "buzz");
+
+        final PortNumber portNumberB = new PortNumber((short) 3);
+        PortEvent portB = new PortEvent(dpid, portNumberB);
+        portB.createStringAttribute("fizz", "buz");
+
+        LinkEvent linkA = new LinkEvent(portA.getSwitchPort(), portB.getSwitchPort());
+        linkA.createStringAttribute(TopologyElement.TYPE,
+                                    TopologyElement.TYPE_OPTICAL_LAYER);
+        LinkEvent linkB = new LinkEvent(portB.getSwitchPort(), portA.getSwitchPort());
+        linkB.createStringAttribute(TopologyElement.TYPE,
+                                    TopologyElement.TYPE_OPTICAL_LAYER);
+
+        TestUtils.callMethod(theTopologyManager, "addSwitch", SwitchEvent.class, sw);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portA);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portB);
+        TestUtils.callMethod(theTopologyManager, "addLink", LinkEvent.class, linkA);
+        TestUtils.callMethod(theTopologyManager, "addLink", LinkEvent.class, linkB);
+
+        // check topology structure
+        TopologyInternal topology = (TopologyInternal) theTopologyManager.getTopology();
+        SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
+        assertEquals(sw, swInTopo);
+        assertTrue(swInTopo.isFrozen());
+        assertEquals("bar", swInTopo.getStringAttribute("foo"));
+
+        final SwitchPort portIdA = new SwitchPort(dpid, portNumberA);
+        PortEvent portAInTopo = topology.getPortEvent(portIdA);
+        assertEquals(portA, portAInTopo);
+        assertTrue(portAInTopo.isFrozen());
+        assertEquals("buzz", portAInTopo.getStringAttribute("fuzz"));
+
+        final SwitchPort portIdB = new SwitchPort(dpid, portNumberB);
+        PortEvent portBInTopo = topology.getPortEvent(portIdB);
+        assertEquals(portB, portBInTopo);
+        assertTrue(portBInTopo.isFrozen());
+        assertEquals("buz", portBInTopo.getStringAttribute("fizz"));
+
+        LinkEvent linkAInTopo = topology.getLinkEvent(linkA.getLinkTuple());
+        assertEquals(linkA, linkAInTopo);
+        assertTrue(linkAInTopo.isFrozen());
+        assertEquals(TopologyElement.TYPE_OPTICAL_LAYER, linkAInTopo.getType());
+
+
+        LinkEvent linkBInTopo = topology.getLinkEvent(linkB.getLinkTuple());
+        assertEquals(linkB, linkBInTopo);
+        assertTrue(linkBInTopo.isFrozen());
+        assertEquals(TopologyElement.TYPE_OPTICAL_LAYER, linkBInTopo.getType());
+
+        // check events to be fired
+        // FIXME if link flapped (linkA in this scenario),
+        //  linkA appears in both removed and added is this expected behavior?
+        List<LinkEvent> apiAddedLinkEvents
+            = TestUtils.getField(theTopologyManager, "apiAddedLinkEvents");
+        assertThat(apiAddedLinkEvents, containsInAnyOrder(linkA, linkB));
+
+        // clear event before removing Link
+        apiAddedLinkEvents.clear();
+
+        // remove link
+        TestUtils.callMethod(theTopologyManager, "removeLink", LinkEvent.class, new LinkEvent(linkA));
+
+        LinkEvent linkANotInTopo = topology.getLinkEvent(linkA.getLinkTuple());
+        assertNull(linkANotInTopo);
+
+        List<LinkEvent> apiRemovedLinkEvents
+            = TestUtils.getField(theTopologyManager, "apiRemovedLinkEvents");
+        assertThat(apiRemovedLinkEvents, hasItem(linkA));
+    }
+
+    /**
+     * Test to confirm topology replica transformation.
+     */
+    @Test
+    public void testAddHostIgnoredByLink() {
+        setupTopologyManager();
+
+        final Dpid dpid = new Dpid(1);
+        SwitchEvent sw = new SwitchEvent(dpid);
+        sw.createStringAttribute("foo", "bar");
+
+        final PortNumber portNumberA = new PortNumber((short) 2);
+        PortEvent portA = new PortEvent(dpid, portNumberA);
+        portA.createStringAttribute("fuzz", "buzz");
+
+        final PortNumber portNumberB = new PortNumber((short) 3);
+        PortEvent portB = new PortEvent(dpid, portNumberB);
+        portB.createStringAttribute("fizz", "buz");
+
+        final PortNumber portNumberC = new PortNumber((short) 4);
+        PortEvent portC = new PortEvent(dpid, portNumberC);
+        portC.createStringAttribute("fizz", "buz");
+
+        LinkEvent linkA = new LinkEvent(portA.getSwitchPort(), portB.getSwitchPort());
+        linkA.createStringAttribute(TopologyElement.TYPE,
+                                    TopologyElement.TYPE_OPTICAL_LAYER);
+        LinkEvent linkB = new LinkEvent(portB.getSwitchPort(), portA.getSwitchPort());
+        linkB.createStringAttribute(TopologyElement.TYPE,
+                                    TopologyElement.TYPE_OPTICAL_LAYER);
+
+        TestUtils.callMethod(theTopologyManager, "addSwitch", SwitchEvent.class, sw);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portA);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portB);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portC);
+        TestUtils.callMethod(theTopologyManager, "addLink", LinkEvent.class, linkA);
+        TestUtils.callMethod(theTopologyManager, "addLink", LinkEvent.class, linkB);
+
+        // Add hostA attached to a port which already has a link
+        final MACAddress macA = MACAddress.valueOf(666L);
+        HostEvent hostA = new HostEvent(macA);
+        hostA.addAttachmentPoint(portA.getSwitchPort());
+        final long timestampA = 392893200L;
+        hostA.setLastSeenTime(timestampA);
+
+        TestUtils.callMethod(theTopologyManager, "addHost", HostEvent.class, hostA);
+
+        // Add hostB attached to multiple ports,
+        // some of them which already has a link
+        final MACAddress macB = MACAddress.valueOf(999L);
+        HostEvent hostB = new HostEvent(macB);
+        hostB.addAttachmentPoint(portB.getSwitchPort());
+        hostB.addAttachmentPoint(portC.getSwitchPort());
+        final long timestampB = 392893201L;
+        hostB.setLastSeenTime(timestampB);
+
+        TestUtils.callMethod(theTopologyManager, "addHost", HostEvent.class, hostB);
+
+        // check topology structure
+        TopologyInternal topology = (TopologyInternal) theTopologyManager.getTopology();
+        SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
+        assertEquals(sw, swInTopo);
+        assertTrue(swInTopo.isFrozen());
+        assertEquals("bar", swInTopo.getStringAttribute("foo"));
+
+        final SwitchPort portIdA = new SwitchPort(dpid, portNumberA);
+        PortEvent portAInTopo = topology.getPortEvent(portIdA);
+        assertEquals(portA, portAInTopo);
+        assertTrue(portAInTopo.isFrozen());
+        assertEquals("buzz", portAInTopo.getStringAttribute("fuzz"));
+
+        final SwitchPort portIdB = new SwitchPort(dpid, portNumberB);
+        PortEvent portBInTopo = topology.getPortEvent(portIdB);
+        assertEquals(portB, portBInTopo);
+        assertTrue(portBInTopo.isFrozen());
+        assertEquals("buz", portBInTopo.getStringAttribute("fizz"));
+
+        // hostA expected to be completely ignored
+        assertNull(topology.getHostEvent(macA));
+        // hostB expected to be there with reduced attachment point
+        HostEvent hostBrev = new HostEvent(macB);
+        hostBrev.addAttachmentPoint(portC.getSwitchPort());
+        hostBrev.setLastSeenTime(timestampB);
+        hostBrev.freeze();
+        assertEquals(hostBrev, topology.getHostEvent(macB));
+
+
+        LinkEvent linkAInTopo = topology.getLinkEvent(linkA.getLinkTuple());
+        assertEquals(linkA, linkAInTopo);
+        assertTrue(linkAInTopo.isFrozen());
+        assertEquals(TopologyElement.TYPE_OPTICAL_LAYER, linkAInTopo.getType());
+
+        LinkEvent linkBInTopo = topology.getLinkEvent(linkB.getLinkTuple());
+        assertEquals(linkB, linkBInTopo);
+        assertTrue(linkBInTopo.isFrozen());
+        assertEquals(TopologyElement.TYPE_OPTICAL_LAYER, linkBInTopo.getType());
+
+        // check events to be fired
+        // hostB should be added with reduced attachment points
+        List<HostEvent> apiAddedHostEvents
+            = TestUtils.getField(theTopologyManager, "apiAddedHostEvents");
+        assertThat(apiAddedHostEvents, hasItem(hostBrev));
+
+        // hostA should not be ignored
+        List<HostEvent> apiRemovedHostEvents
+            = TestUtils.getField(theTopologyManager, "apiRemovedHostEvents");
+        assertThat(apiRemovedHostEvents, not(hasItem(hostA)));
+
+        List<LinkEvent> apiAddedLinkEvents
+            = TestUtils.getField(theTopologyManager, "apiAddedLinkEvents");
+        assertThat(apiAddedLinkEvents, containsInAnyOrder(linkA, linkB));
+    }
+
+    /**
+     * Test to confirm topology replica transformation.
+     */
+    @Test
+    public void testAddHostMove() {
+        setupTopologyManager();
+
+        final Dpid dpid = new Dpid(1);
+        SwitchEvent sw = new SwitchEvent(dpid);
+        sw.createStringAttribute("foo", "bar");
+
+        final PortNumber portNumberA = new PortNumber((short) 2);
+        PortEvent portA = new PortEvent(dpid, portNumberA);
+        portA.createStringAttribute("fuzz", "buzz");
+
+        final PortNumber portNumberB = new PortNumber((short) 3);
+        PortEvent portB = new PortEvent(dpid, portNumberB);
+        portB.createStringAttribute("fizz", "buz");
+
+        final PortNumber portNumberC = new PortNumber((short) 4);
+        PortEvent portC = new PortEvent(dpid, portNumberC);
+        portC.createStringAttribute("fizz", "buz");
+
+        TestUtils.callMethod(theTopologyManager, "addSwitch", SwitchEvent.class, sw);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portA);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portB);
+        TestUtils.callMethod(theTopologyManager, "addPort", PortEvent.class, portC);
+
+        // Add hostA attached to a port which already has a link
+        final MACAddress macA = MACAddress.valueOf(666L);
+        HostEvent hostA = new HostEvent(macA);
+        hostA.addAttachmentPoint(portA.getSwitchPort());
+        final long timestampA = 392893200L;
+        hostA.setLastSeenTime(timestampA);
+
+        TestUtils.callMethod(theTopologyManager, "addHost", HostEvent.class, hostA);
+
+
+        // check topology structure
+        TopologyInternal topology = (TopologyInternal) theTopologyManager.getTopology();
+        SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
+        assertEquals(sw, swInTopo);
+        assertTrue(swInTopo.isFrozen());
+        assertEquals("bar", swInTopo.getStringAttribute("foo"));
+
+        final SwitchPort portIdA = new SwitchPort(dpid, portNumberA);
+        PortEvent portAInTopo = topology.getPortEvent(portIdA);
+        assertEquals(portA, portAInTopo);
+        assertTrue(portAInTopo.isFrozen());
+        assertEquals("buzz", portAInTopo.getStringAttribute("fuzz"));
+
+        final SwitchPort portIdB = new SwitchPort(dpid, portNumberB);
+        PortEvent portBInTopo = topology.getPortEvent(portIdB);
+        assertEquals(portB, portBInTopo);
+        assertTrue(portBInTopo.isFrozen());
+        assertEquals("buz", portBInTopo.getStringAttribute("fizz"));
+
+        // hostA expected to be there
+        assertEquals(hostA, topology.getHostEvent(macA));
+        assertEquals(timestampA, topology.getHostEvent(macA).getLastSeenTime());
+
+        // check events to be fired
+        // hostA should be added
+        List<HostEvent> apiAddedHostEvents
+            = TestUtils.getField(theTopologyManager, "apiAddedHostEvents");
+        assertThat(apiAddedHostEvents, hasItem(hostA));
+
+
+        // clear event before moving host
+        apiAddedHostEvents.clear();
+
+        HostEvent hostAmoved = new HostEvent(macA);
+        hostAmoved.addAttachmentPoint(portB.getSwitchPort());
+        final long timestampAmoved = 392893201L;
+        hostAmoved.setLastSeenTime(timestampAmoved);
+
+        TestUtils.callMethod(theTopologyManager, "addHost", HostEvent.class, hostAmoved);
+
+        assertEquals(hostAmoved, topology.getHostEvent(macA));
+        assertEquals(timestampAmoved, topology.getHostEvent(macA).getLastSeenTime());
+
+        // hostA expected to be there with new attachment point
+        apiAddedHostEvents
+            = TestUtils.getField(theTopologyManager, "apiAddedHostEvents");
+        assertThat(apiAddedHostEvents, hasItem(hostAmoved));
+
+        // hostA is updated not removed
+        List<HostEvent> apiRemovedHostEvents
+            = TestUtils.getField(theTopologyManager, "apiRemovedHostEvents");
+        assertThat(apiRemovedHostEvents, not(hasItem(hostA)));
+    }
 }