Add unit tests for instancePort and its manager classes

Change-Id: I7a170729794a3dbeba3dcb60bb83d175400ae42a
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/DefaultExternalPeerRouter.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/DefaultExternalPeerRouter.java
index fb18502..57b997c 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/DefaultExternalPeerRouter.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/DefaultExternalPeerRouter.java
@@ -26,11 +26,11 @@
 /**
  * Implementation of external peer router.
  */
-public class DefaultExternalPeerRouter implements ExternalPeerRouter {
+public final class DefaultExternalPeerRouter implements ExternalPeerRouter {
 
-    private IpAddress externalPeerRouterIp;
-    private MacAddress externalPeerRouterMac;
-    private VlanId externalPeerRouterVlanId;
+    private final IpAddress externalPeerRouterIp;
+    private final MacAddress externalPeerRouterMac;
+    private final VlanId externalPeerRouterVlanId;
 
     public DefaultExternalPeerRouter(IpAddress externalPeerRouterIp,
                                      MacAddress externalPeerRouterMac,
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/DefaultExternalPeerRouterTest.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/DefaultExternalPeerRouterTest.java
new file mode 100644
index 0000000..c3aeab1
--- /dev/null
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/DefaultExternalPeerRouterTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.impl;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+/**
+ * Unit tests for DefaultExternalPeerRouter.
+ */
+public class DefaultExternalPeerRouterTest {
+
+    private static final IpAddress ROUTER_IP_1 = IpAddress.valueOf("1.2.3.4");
+    private static final IpAddress ROUTER_IP_2 = IpAddress.valueOf("5.6.7.8");
+    private static final MacAddress ROUTER_MAC_1 = MacAddress.valueOf("11:22:33:44:55:66");
+    private static final MacAddress ROUTER_MAC_2 = MacAddress.valueOf("77:88:99:AA:BB:CC");
+    private static final VlanId VLAN_ID_1 = VlanId.vlanId("1");
+    private static final VlanId VLAN_ID_2 = VlanId.vlanId("2");
+
+    private ExternalPeerRouter router1;
+    private ExternalPeerRouter sameAsRouter1;
+    private ExternalPeerRouter router2;
+
+    /**
+     * Checks that the DefaultExternalPeerRouter class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(DefaultExternalPeerRouter.class);
+    }
+
+    /**
+     * Initial setup for this unit test.
+     */
+    @Before
+    public void setUp() {
+        router1 = new DefaultExternalPeerRouter(ROUTER_IP_1, ROUTER_MAC_1, VLAN_ID_1);
+        sameAsRouter1 = new DefaultExternalPeerRouter(ROUTER_IP_1, ROUTER_MAC_1, VLAN_ID_1);
+        router2 = new DefaultExternalPeerRouter(ROUTER_IP_2, ROUTER_MAC_2, VLAN_ID_2);
+    }
+
+    /**
+     * Tests object equality.
+     */
+    @Test
+    public void testEquality() {
+        new EqualsTester().addEqualityGroup(router1, sameAsRouter1)
+                .addEqualityGroup(router2)
+                .testEquals();
+    }
+
+    /**
+     * Test object construction.
+     */
+    @Test
+    public void testConstruction() {
+        ExternalPeerRouter router = router1;
+
+        assertThat(router.externalPeerRouterIp(), is(router1.externalPeerRouterIp()));
+        assertThat(router.externalPeerRouterMac(), is(router1.externalPeerRouterMac()));
+        assertThat(router.externalPeerRouterVlanId(), is(router1.externalPeerRouterVlanId()));
+    }
+}
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/DefaultInstancePortTest.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/DefaultInstancePortTest.java
new file mode 100644
index 0000000..6fecc1a
--- /dev/null
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/DefaultInstancePortTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.impl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.testing.EqualsTester;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultHost;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.openstacknetworking.api.InstancePort;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
+import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_CREATE_TIME;
+
+/**
+ * Unit tests for the default instance port class.
+ */
+public class DefaultInstancePortTest {
+
+    private static final String ANNOTATION_NETWORK_ID = "networkId";
+    private static final String ANNOTATION_PORT_ID = "portId";
+
+    private static final IpAddress IP_ADDRESS_1 = IpAddress.valueOf("1.2.3.4");
+    private static final IpAddress IP_ADDRESS_2 = IpAddress.valueOf("5.6.7.8");
+
+    private static final MacAddress MAC_ADDRESS_1 = MacAddress.valueOf("11:22:33:44:55:66");
+    private static final MacAddress MAC_ADDRESS_2 = MacAddress.valueOf("77:88:99:AA:BB:CC");
+
+    private static final DeviceId DEV_ID_1 = DeviceId.deviceId("of:0000000000000001");
+    private static final DeviceId DEV_ID_2 = DeviceId.deviceId("of:0000000000000002");
+    private static final PortNumber PORT_NUM_1 = PortNumber.portNumber(1L);
+    private static final PortNumber PORT_NUM_2 = PortNumber.portNumber(2L);
+
+    private static final VlanId VLAN_ID = VlanId.vlanId();
+    private static final ProviderId PROVIDER_ID = ProviderId.NONE;
+    private static final HostId HOST_ID_1 = HostId.hostId("00:00:11:00:00:01/1");
+    private static final HostId HOST_ID_2 = HostId.hostId("00:00:11:00:00:02/1");
+
+    private static final String NETWORK_ID_1 = "net-id-1";
+    private static final String NETWORK_ID_2 = "net-id-2";
+    private static final String PORT_ID_1 = "port-id-1";
+    private static final String PORT_ID_2 = "port-id-2";
+
+    private static final long TIME_1 = 1L;
+    private static final long TIME_2 = 2L;
+
+    private InstancePort instancePort1;
+    private InstancePort sameAsInstancePort1;
+    private InstancePort instancePort2;
+
+    /**
+     * Checks that the DefaultInstancePort class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(DefaultInstancePort.class);
+    }
+
+    /**
+     * Initial setup for this unit test.
+     */
+    @Before
+    public void setUp() {
+
+        HostLocation location1 = new HostLocation(DEV_ID_1, PORT_NUM_1, TIME_1);
+        HostLocation location2 = new HostLocation(DEV_ID_2, PORT_NUM_2, TIME_2);
+
+        DefaultAnnotations.Builder annotations1 = DefaultAnnotations.builder()
+                .set(ANNOTATION_NETWORK_ID, NETWORK_ID_1)
+                .set(ANNOTATION_PORT_ID, PORT_ID_1)
+                .set(ANNOTATION_CREATE_TIME, String.valueOf(TIME_1));
+
+        DefaultAnnotations.Builder annotations2 = DefaultAnnotations.builder()
+                .set(ANNOTATION_NETWORK_ID, NETWORK_ID_2)
+                .set(ANNOTATION_PORT_ID, PORT_ID_2)
+                .set(ANNOTATION_CREATE_TIME, String.valueOf(TIME_2));
+
+        Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_1, MAC_ADDRESS_1,
+                                VLAN_ID, location1, ImmutableSet.of(IP_ADDRESS_1),
+                                annotations1.build());
+        Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_2, MAC_ADDRESS_2,
+                                VLAN_ID, location2, ImmutableSet.of(IP_ADDRESS_2),
+                                annotations2.build());
+
+        instancePort1 = DefaultInstancePort.from(host1, ACTIVE);
+        sameAsInstancePort1 = DefaultInstancePort.from(host1, ACTIVE);
+        instancePort2 = DefaultInstancePort.from(host2, ACTIVE);
+    }
+
+    /**
+     * Tests object equality.
+     */
+    @Test
+    public void testEquality() {
+        new EqualsTester().addEqualityGroup(instancePort1, sameAsInstancePort1)
+                .addEqualityGroup(instancePort2)
+                .testEquals();
+    }
+
+    /**
+     * Test object construction.
+     */
+    @Test
+    public void testConstruction() {
+        InstancePort instancePort = instancePort1;
+
+        assertThat(instancePort.portId(), is(PORT_ID_1));
+        assertThat(instancePort.networkId(), is(NETWORK_ID_1));
+        assertThat(instancePort.macAddress(), is(MAC_ADDRESS_1));
+        assertThat(instancePort.ipAddress(), is(IP_ADDRESS_1));
+        assertThat(instancePort.portNumber(), is(PORT_NUM_1));
+        assertThat(instancePort.deviceId(), is(DEV_ID_1));
+        assertThat(instancePort.state(), is(ACTIVE));
+    }
+}
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/InstancePortManagerTest.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/InstancePortManagerTest.java
new file mode 100644
index 0000000..9070452
--- /dev/null
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/InstancePortManagerTest.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.impl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.event.Event;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultHost;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.host.HostServiceAdapter;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.openstacknetworking.api.InstancePort;
+import org.onosproject.openstacknetworking.api.InstancePortEvent;
+import org.onosproject.openstacknetworking.api.InstancePortListener;
+import org.onosproject.store.service.TestStorageService;
+
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
+import static org.onosproject.openstacknetworking.api.InstancePort.State.INACTIVE;
+import static org.onosproject.openstacknetworking.api.InstancePort.State.MIGRATING;
+import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
+import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
+import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_PORT_DETECTED;
+import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_PORT_UPDATED;
+import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_PORT_VANISHED;
+import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_RESTARTED;
+import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_TERMINATED;
+import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_CREATE_TIME;
+
+/**
+ * Unit tests for instance port manager.
+ */
+public class InstancePortManagerTest {
+
+    private static final ApplicationId TEST_APP_ID = new DefaultApplicationId(1, "test");
+
+    private static final String ANNOTATION_NETWORK_ID = "networkId";
+    private static final String ANNOTATION_PORT_ID = "portId";
+
+    private static final IpAddress IP_ADDRESS_1 = IpAddress.valueOf("1.2.3.4");
+    private static final IpAddress IP_ADDRESS_2 = IpAddress.valueOf("5.6.7.8");
+
+    private static final MacAddress MAC_ADDRESS_1 = MacAddress.valueOf("11:22:33:44:55:66");
+    private static final MacAddress MAC_ADDRESS_2 = MacAddress.valueOf("77:88:99:AA:BB:CC");
+
+    private static final DeviceId DEV_ID_1 = DeviceId.deviceId("of:0000000000000001");
+    private static final DeviceId DEV_ID_2 = DeviceId.deviceId("of:0000000000000002");
+    private static final PortNumber PORT_NUM_1 = PortNumber.portNumber(1L);
+    private static final PortNumber PORT_NUM_2 = PortNumber.portNumber(2L);
+
+    private static final VlanId VLAN_ID = VlanId.vlanId();
+    private static final ProviderId PROVIDER_ID = ProviderId.NONE;
+    private static final HostId HOST_ID_1 = HostId.hostId("00:00:11:00:00:01/1");
+    private static final HostId HOST_ID_2 = HostId.hostId("00:00:11:00:00:02/1");
+
+    private static final String NETWORK_ID_1 = "net-id-1";
+    private static final String NETWORK_ID_2 = "net-id-2";
+    private static final String PORT_ID_1 = "port-id-1";
+    private static final String PORT_ID_2 = "port-id-2";
+    private static final String UNKNOWN_ID = "port-id-x";
+
+    private static final long TIME_1 = 1L;
+    private static final long TIME_2 = 2L;
+
+    private InstancePort instancePort1;
+    private InstancePort instancePort2;
+
+    private InstancePortManager target;
+    private DistributedInstancePortStore store;
+
+    private final TestInstancePortListener testInstancePortListener = new TestInstancePortListener();
+
+    /**
+     * Initial setup for this unit test.
+     */
+    @Before
+    public void setUp() {
+
+        store = new DistributedInstancePortStore();
+        TestUtils.setField(store, "coreService", new TestCoreService());
+        TestUtils.setField(store, "storageService", new TestStorageService());
+        TestUtils.setField(store, "eventExecutor", MoreExecutors.newDirectExecutorService());
+        store.activate();
+
+        target = new InstancePortManager();
+        TestUtils.setField(target, "coreService", new TestCoreService());
+        TestUtils.setField(target, "hostService", new TestHostService());
+        target.instancePortStore = store;
+        target.addListener(testInstancePortListener);
+        target.activate();
+
+        HostLocation location1 = new HostLocation(DEV_ID_1, PORT_NUM_1, TIME_1);
+        HostLocation location2 = new HostLocation(DEV_ID_2, PORT_NUM_2, TIME_2);
+
+        DefaultAnnotations.Builder annotations1 = DefaultAnnotations.builder()
+                .set(ANNOTATION_NETWORK_ID, NETWORK_ID_1)
+                .set(ANNOTATION_PORT_ID, PORT_ID_1)
+                .set(ANNOTATION_CREATE_TIME, String.valueOf(TIME_1));
+
+        DefaultAnnotations.Builder annotations2 = DefaultAnnotations.builder()
+                .set(ANNOTATION_NETWORK_ID, NETWORK_ID_2)
+                .set(ANNOTATION_PORT_ID, PORT_ID_2)
+                .set(ANNOTATION_CREATE_TIME, String.valueOf(TIME_2));
+
+        Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_1, MAC_ADDRESS_1,
+                VLAN_ID, location1, ImmutableSet.of(IP_ADDRESS_1),
+                annotations1.build());
+        Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_2, MAC_ADDRESS_2,
+                VLAN_ID, location2, ImmutableSet.of(IP_ADDRESS_2),
+                annotations2.build());
+
+        instancePort1 = DefaultInstancePort.from(host1, ACTIVE);
+        instancePort2 = DefaultInstancePort.from(host2, INACTIVE);
+    }
+
+    /**
+     * Tears down all of this unit test.
+     */
+    @After
+    public void tearDown() {
+        target.removeListener(testInstancePortListener);
+        store.deactivate();
+        target.deactivate();
+        store = null;
+        target = null;
+    }
+
+    /**
+     * Tests if getting all instance ports returns the correct set of ports.
+     */
+    @Test
+    public void testGetInstancePorts() {
+        createBasicInstancePorts();
+        assertEquals("Number of instance port did not match",
+                2, target.instancePorts().size());
+    }
+
+    /**
+     * Tests if getting an instance port with port ID returns the correct port.
+     */
+    @Test
+    public void testGetInstancePortById() {
+        createBasicInstancePorts();
+        assertNotNull("Instance port did not match", target.instancePort(PORT_ID_1));
+        assertNotNull("Instance port did not match", target.instancePort(PORT_ID_2));
+        assertNull("Instance port did not match", target.instancePort(UNKNOWN_ID));
+    }
+
+
+    /**
+     * Tests if getting an instance port with IP and network ID returns correct port.
+     */
+    @Test
+    public void testGetInstancePortByIpAndNetId() {
+        createBasicInstancePorts();
+        InstancePort port = target.instancePort(IP_ADDRESS_1, NETWORK_ID_1);
+        assertEquals("Instance port did not match", port, instancePort1);
+    }
+
+    /**
+     * Tests if getting an instance port with MAC returns correct port.
+     */
+    @Test
+    public void testGetInstancePortByMac() {
+        createBasicInstancePorts();
+        InstancePort port = target.instancePort(MAC_ADDRESS_1);
+        assertEquals("Instance port did not match", port, instancePort1);
+    }
+
+    /**
+     * Tests if getting instance ports with network ID returns correct ports.
+     */
+    @Test
+    public void testGetInstancePortsByNetId() {
+        createBasicInstancePorts();
+        Set<InstancePort> ports = target.instancePorts(NETWORK_ID_1);
+        assertEquals("Number of instance port did not match",
+                1, ports.size());
+    }
+
+    /**
+     * Tests creating and removing an instance port, and checks if it triggers proper events.
+     */
+    @Test
+    public void testCreateAndRemoveInstancePort() {
+        target.createInstancePort(instancePort1);
+        assertEquals("Number of instance port did not match",
+                1, target.instancePorts().size());
+        assertNotNull("Instance port did not match", target.instancePort(PORT_ID_1));
+
+        target.removeInstancePort(PORT_ID_1);
+        assertEquals("Number of instance port did not match",
+                0, target.instancePorts().size());
+        assertNull("Instance port did not match", target.instancePort(PORT_ID_1));
+
+        validateEvents(OPENSTACK_INSTANCE_PORT_DETECTED, OPENSTACK_INSTANCE_PORT_VANISHED);
+    }
+
+    /**
+     * Tests updating an instance port, and checks if it triggers proper events.
+     */
+    @Test
+    public void testCreateAndUpdateInstancePort() {
+        target.createInstancePort(instancePort1);
+        assertEquals("Number of instance port did not match",
+                1, target.instancePorts().size());
+        assertEquals("Instance port did not match", PORT_NUM_1,
+                target.instancePort(PORT_ID_1).portNumber());
+
+        HostLocation location = new HostLocation(DEV_ID_2, PORT_NUM_2, TIME_2);
+
+        DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
+                .set(ANNOTATION_NETWORK_ID, NETWORK_ID_2)
+                .set(ANNOTATION_PORT_ID, PORT_ID_1)
+                .set(ANNOTATION_CREATE_TIME, String.valueOf(TIME_2));
+
+        Host host = new DefaultHost(PROVIDER_ID, HOST_ID_2, MAC_ADDRESS_2,
+                VLAN_ID, location, ImmutableSet.of(IP_ADDRESS_2),
+                annotations.build());
+
+        final InstancePort updated = DefaultInstancePort.from(host, ACTIVE);
+        target.updateInstancePort(updated);
+
+        assertEquals("Number of instance port did not match",
+                1, target.instancePorts().size());
+        assertEquals("Instance port did not match", PORT_NUM_2,
+                target.instancePort(PORT_ID_1).portNumber());
+
+        validateEvents(OPENSTACK_INSTANCE_PORT_DETECTED, OPENSTACK_INSTANCE_PORT_UPDATED);
+    }
+
+    /**
+     * Tests if creating a null instance port fails with an exception.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testCreateNullInstancePort() {
+        target.createInstancePort(null);
+    }
+
+    /**
+     * Tests if creating a duplicated instance port fails with an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testCreateDuplicateInstancePort() {
+        target.createInstancePort(instancePort1);
+        target.createInstancePort(instancePort1);
+    }
+
+    /**
+     * Tests if removing instance port with null ID fails with an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testRemoveInstancePortWithNull() {
+        target.removeInstancePort(null);
+    }
+
+    /**
+     * Tests if updating an unregistered instance port fails with an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testUpdateUnregisteredInstancePort() {
+        target.updateInstancePort(instancePort1);
+    }
+
+    /**
+     * Tests if it triggers the instance termination event.
+     */
+    @Test
+    public void testTerminateInstance() {
+        InstancePort instancePort = instancePort1;
+        target.createInstancePort(instancePort);
+
+        InstancePort inactiveInstancePort = instancePort.updateState(INACTIVE);
+        target.updateInstancePort(inactiveInstancePort);
+
+        assertEquals("Number of instance port did not match",
+                1, target.instancePorts().size());
+        assertNotNull("Instance port did not match", target.instancePort(PORT_ID_1));
+
+        validateEvents(OPENSTACK_INSTANCE_PORT_DETECTED,
+                OPENSTACK_INSTANCE_PORT_UPDATED, OPENSTACK_INSTANCE_TERMINATED);
+    }
+
+    /**
+     * Tests if it triggers the instance restart event.
+     */
+    @Test
+    public void testRestartInstance() {
+        InstancePort instancePort = instancePort1;
+        InstancePort inactiveInstancePort = instancePort.updateState(INACTIVE);
+
+        target.createInstancePort(inactiveInstancePort);
+        target.updateInstancePort(instancePort);
+
+        assertEquals("Number of instance port did not match",
+                1, target.instancePorts().size());
+        assertNotNull("Instance port did not match", target.instancePort(PORT_ID_1));
+
+        validateEvents(OPENSTACK_INSTANCE_PORT_DETECTED,
+                OPENSTACK_INSTANCE_PORT_UPDATED, OPENSTACK_INSTANCE_RESTARTED);
+    }
+
+    /**
+     * Tests if it triggers the instance migration start event.
+     */
+    @Test
+    public void testMigrateInstanceStart() {
+        InstancePort instancePort = instancePort1;
+        target.createInstancePort(instancePort);
+
+        InstancePort inactiveInstancePort = instancePort.updateState(MIGRATING);
+        target.updateInstancePort(inactiveInstancePort);
+
+        assertEquals("Number of instance port did not match",
+                1, target.instancePorts().size());
+        assertNotNull("Instance port did not match", target.instancePort(PORT_ID_1));
+
+        validateEvents(OPENSTACK_INSTANCE_PORT_DETECTED,
+                OPENSTACK_INSTANCE_PORT_UPDATED, OPENSTACK_INSTANCE_MIGRATION_STARTED);
+    }
+
+    /**
+     * Tests if it triggers the instance migration end event.
+     */
+    @Test
+    public void testMigrateInstanceEnd() {
+        InstancePort instancePort = instancePort1;
+        InstancePort inactiveInstancePort = instancePort.updateState(MIGRATING);
+
+        target.createInstancePort(inactiveInstancePort);
+        target.updateInstancePort(instancePort);
+
+        assertEquals("Number of instance port did not match",
+                1, target.instancePorts().size());
+        assertNotNull("Instance port did not match", target.instancePort(PORT_ID_1));
+
+        validateEvents(OPENSTACK_INSTANCE_PORT_DETECTED,
+                OPENSTACK_INSTANCE_PORT_UPDATED, OPENSTACK_INSTANCE_MIGRATION_ENDED);
+    }
+
+    /**
+     * Tests if it triggers the instance removal event from termination status.
+     */
+    @Test
+    public void testRemoveInstanceFromTermination() {
+        InstancePort instancePort = instancePort1;
+        target.createInstancePort(instancePort);
+
+        InstancePort inactiveInstancePort = instancePort.updateState(INACTIVE);
+        target.updateInstancePort(inactiveInstancePort);
+
+        assertEquals("Number of instance port did not match",
+                1, target.instancePorts().size());
+        assertNotNull("Instance port did not match", target.instancePort(PORT_ID_1));
+
+        target.removeInstancePort(PORT_ID_1);
+
+        assertEquals("Number of instance port did not match",
+                0, target.instancePorts().size());
+        assertNull("Instance port did not match", target.instancePort(PORT_ID_1));
+
+        validateEvents(OPENSTACK_INSTANCE_PORT_DETECTED,
+                OPENSTACK_INSTANCE_PORT_UPDATED, OPENSTACK_INSTANCE_TERMINATED,
+                OPENSTACK_INSTANCE_PORT_VANISHED);
+    }
+
+    /**
+     * Tests if it triggers the instance removal event from migration status.
+     */
+    @Test
+    public void testRemoveInstanceFromMigration() {
+        InstancePort instancePort = instancePort1;
+        target.createInstancePort(instancePort);
+
+        InstancePort inactiveInstancePort = instancePort.updateState(MIGRATING);
+        target.updateInstancePort(inactiveInstancePort);
+
+        assertEquals("Number of instance port did not match",
+                1, target.instancePorts().size());
+        assertNotNull("Instance port did not match", target.instancePort(PORT_ID_1));
+
+        target.removeInstancePort(PORT_ID_1);
+
+        assertEquals("Number of instance port did not match",
+                0, target.instancePorts().size());
+        assertNull("Instance port did not match", target.instancePort(PORT_ID_1));
+
+        validateEvents(OPENSTACK_INSTANCE_PORT_DETECTED,
+                OPENSTACK_INSTANCE_PORT_UPDATED, OPENSTACK_INSTANCE_MIGRATION_STARTED,
+                OPENSTACK_INSTANCE_PORT_VANISHED);
+    }
+
+    private void createBasicInstancePorts() {
+        target.createInstancePort(instancePort1);
+        target.createInstancePort(instancePort2);
+    }
+
+    private static class TestCoreService extends CoreServiceAdapter {
+
+        @Override
+        public ApplicationId registerApplication(String name) {
+            return TEST_APP_ID;
+        }
+    }
+
+    private static class TestHostService extends HostServiceAdapter {
+    }
+
+    private static class TestInstancePortListener implements InstancePortListener {
+        private List<InstancePortEvent> events = Lists.newArrayList();
+
+        @Override
+        public void event(InstancePortEvent event) {
+            events.add(event);
+        }
+    }
+
+    private void validateEvents(Enum... types) {
+        int i = 0;
+        assertEquals("Number of events did not match", types.length,
+                                        testInstancePortListener.events.size());
+        for (Event event : testInstancePortListener.events) {
+            assertEquals("Incorrect event received", types[i], event.type());
+            i++;
+        }
+        testInstancePortListener.events.clear();
+    }
+}