Adds unit test for OpenstackRoutingIcmpHandler.

Change-Id: I764aa769c25a21ff410fa431cdc7552d6af1c059
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/IcmpEcho.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/IcmpEcho.java
new file mode 100644
index 0000000..5b78719
--- /dev/null
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/IcmpEcho.java
@@ -0,0 +1,269 @@
+/*
+ * 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 org.onlab.packet.Data;
+import org.onlab.packet.Deserializer;
+import org.onlab.packet.ICMP;
+import org.onlab.packet.IPv4;
+
+import java.nio.ByteBuffer;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onlab.packet.PacketUtils.checkInput;
+
+/**
+ * ICMP packet class for echo purpose.
+ */
+public class IcmpEcho extends ICMP {
+    protected byte icmpType;
+    protected byte icmpCode;
+    protected short checksum;
+    protected short identifier;
+    protected short sequenceNum;
+
+    public static final short ICMP_HEADER_LENGTH = 8;
+
+    /**
+     * @return the icmpType
+     */
+    public byte getIcmpType() {
+        return this.icmpType;
+    }
+
+    /**
+     * @param icmpType to set
+     * @return this
+     */
+    public IcmpEcho setIcmpType(final byte icmpType) {
+        this.icmpType = icmpType;
+        return this;
+    }
+
+    /**
+     * @return the icmp code
+     */
+    public byte getIcmpCode() {
+        return this.icmpCode;
+    }
+
+    /**
+     * @param icmpCode code to set
+     * @return this
+     */
+    public IcmpEcho setIcmpCode(final byte icmpCode) {
+        this.icmpCode = icmpCode;
+        return this;
+    }
+
+    /**
+     * @return the checksum
+     */
+    public short getChecksum() {
+        return this.checksum;
+    }
+
+    /**
+     * @param checksum the checksum to set
+     * @return this
+     */
+    public IcmpEcho setChecksum(final short checksum) {
+        this.checksum = checksum;
+        return this;
+    }
+
+    /**
+     * Sets the identifier.
+     *
+     * @param identifier identifier
+     * @return this
+     */
+    public IcmpEcho setIdentifier(final short identifier) {
+        this.identifier = identifier;
+        return this;
+    }
+
+    /**
+     * Sets the sequencer number.
+     *
+     * @param sequenceNum sequence number
+     * @return this
+     */
+
+    public IcmpEcho setSequenceNum(final short sequenceNum) {
+        this.sequenceNum = sequenceNum;
+        return this;
+    }
+
+    /**
+     * Gets the identifier.
+     *
+     * @return identifier
+     */
+    public short getIdentifier() {
+        return this.identifier;
+    }
+
+    /**
+     * Gets the sequence number.
+     *
+     * @return sequence number
+     */
+    public short getSequenceNum() {
+        return this.sequenceNum;
+    }
+
+    /**
+     * Serializes the packet. Will compute and set the following fields if they
+     * are set to specific values at the time serialize is called: -checksum : 0
+     * -length : 0
+     */
+    @Override
+    public byte[] serialize() {
+        int length = 8;
+        byte[] payloadData = null;
+        if (this.payload != null) {
+            this.payload.setParent(this);
+            payloadData = this.payload.serialize();
+            length += payloadData.length;
+        }
+
+        final byte[] data = new byte[length];
+        final ByteBuffer bb = ByteBuffer.wrap(data);
+
+        bb.put(this.icmpType);
+        bb.put(this.icmpCode);
+        bb.putShort(this.checksum);
+        bb.putShort(this.identifier);
+        bb.putShort(this.sequenceNum);
+        if (payloadData != null) {
+            bb.put(payloadData);
+        }
+
+        if (this.parent != null && this.parent instanceof IPv4) {
+            ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_ICMP);
+        }
+
+        // compute checksum if needed
+        if (this.checksum == 0) {
+            bb.rewind();
+            int accumulation = 0;
+
+            for (int i = 0; i < length / 2; ++i) {
+                accumulation += 0xffff & bb.getShort();
+            }
+            // pad to an even number of shorts
+            if (length % 2 > 0) {
+                accumulation += (bb.get() & 0xff) << 8;
+            }
+
+            accumulation = (accumulation >> 16 & 0xffff)
+                    + (accumulation & 0xffff);
+            this.checksum = (short) (~accumulation & 0xffff);
+            bb.putShort(2, this.checksum);
+        }
+        return data;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 5807;
+        int result = super.hashCode();
+        result = prime * result + this.icmpType;
+        result = prime * result + this.icmpCode;
+        result = prime * result + this.checksum;
+        result = prime * result + this.identifier;
+        result = prime * result + this.sequenceNum;
+        return result;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof IcmpEcho)) {
+            return false;
+        }
+        final IcmpEcho other = (IcmpEcho) obj;
+        if (this.icmpType != other.icmpType) {
+            return false;
+        }
+        if (this.icmpCode != other.icmpCode) {
+            return false;
+        }
+        if (this.checksum != other.checksum) {
+            return false;
+        }
+        if (this.identifier != other.identifier) {
+            return false;
+        }
+        if (this.sequenceNum != other.sequenceNum) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Deserializer function for ICMP packets.
+     *
+     * @return deserializer function
+     */
+    public static Deserializer<ICMP> deserializer() {
+        return (data, offset, length) -> {
+            checkInput(data, offset, length, ICMP_HEADER_LENGTH);
+
+            IcmpEcho icmp = new IcmpEcho();
+
+            final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+            icmp.icmpType = bb.get();
+            icmp.icmpCode = bb.get();
+            icmp.checksum = bb.getShort();
+            icmp.identifier = bb.getShort();
+            icmp.sequenceNum = bb.getShort();
+
+            icmp.payload = Data.deserializer()
+                    .deserialize(data, bb.position(), bb.limit()
+                            - bb.position());
+            icmp.payload.setParent(icmp);
+            return icmp;
+        };
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(getClass())
+                .add("icmpType", Byte.toString(icmpType))
+                .add("icmpCode", Byte.toString(icmpCode))
+                .add("checksum", Short.toString(checksum))
+                .add("identifier", Short.toString(identifier))
+                .add("sequenceNumber", Short.toString(sequenceNum))
+                .toString();
+    }
+}
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackRouterServiceAdapter.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackRouterServiceAdapter.java
new file mode 100644
index 0000000..34341d2
--- /dev/null
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackRouterServiceAdapter.java
@@ -0,0 +1,79 @@
+/*
+ * 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 org.onosproject.openstacknetworking.api.OpenstackRouterListener;
+import org.onosproject.openstacknetworking.api.OpenstackRouterService;
+import org.openstack4j.model.network.NetFloatingIP;
+import org.openstack4j.model.network.Router;
+import org.openstack4j.model.network.RouterInterface;
+
+import java.util.Set;
+
+/**
+ * Test adapter for OpenstackRouterService.
+ */
+public class OpenstackRouterServiceAdapter implements OpenstackRouterService {
+    @Override
+    public Router router(String osRouterId) {
+        return null;
+    }
+
+    @Override
+    public Set<Router> routers() {
+        return null;
+    }
+
+    @Override
+    public RouterInterface routerInterface(String osRouterIfaceId) {
+        return null;
+    }
+
+    @Override
+    public Set<RouterInterface> routerInterfaces() {
+        return null;
+    }
+
+    @Override
+    public Set<RouterInterface> routerInterfaces(String osRouterId) {
+        return null;
+    }
+
+    @Override
+    public NetFloatingIP floatingIp(String floatingIpId) {
+        return null;
+    }
+
+    @Override
+    public Set<NetFloatingIP> floatingIps() {
+        return null;
+    }
+
+    @Override
+    public Set<NetFloatingIP> floatingIps(String routerId) {
+        return null;
+    }
+
+    @Override
+    public void addListener(OpenstackRouterListener listener) {
+
+    }
+
+    @Override
+    public void removeListener(OpenstackRouterListener listener) {
+
+    }
+}
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandlerTest.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandlerTest.java
new file mode 100644
index 0000000..ece96ee
--- /dev/null
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandlerTest.java
@@ -0,0 +1,511 @@
+/*
+ * 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.Maps;
+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.DeserializationException;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP;
+import org.onlab.packet.IPv4;
+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.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.packet.DefaultInboundPacket;
+import org.onosproject.net.packet.DefaultPacketContext;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketServiceAdapter;
+import org.onosproject.openstacknetworking.api.Constants;
+import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
+import org.onosproject.openstacknetworking.api.InstancePort;
+import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeAdapter;
+import org.onosproject.store.service.TestStorageService;
+import org.openstack4j.model.network.ExternalGateway;
+import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.Router;
+import org.openstack4j.model.network.RouterInterface;
+import org.openstack4j.model.network.Subnet;
+import org.openstack4j.openstack.networking.domain.NeutronPort;
+import org.openstack4j.openstack.networking.domain.NeutronRouter;
+import org.openstack4j.openstack.networking.domain.NeutronSubnet;
+
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.onlab.packet.Ethernet.TYPE_IPV4;
+import static org.onlab.packet.ICMP.TYPE_ECHO_REPLY;
+import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
+import static org.onosproject.net.NetTestTools.connectPoint;
+
+public class OpenstackRoutingIcmpHandlerTest {
+    private OpenstackRoutingIcmpHandler icmpHandler;
+    private static final byte CODE_ECHO_REQUEST = 0x00;
+    private static final byte CODE_ECHO_REPLY = 0x00;
+
+    protected PacketProcessor packetProcessor;
+    private InstancePort instancePort1;
+    private InstancePort instancePort2;
+    private InstancePort instancePort3;
+    private RouterInterface routerInterface1;
+    private Router router1;
+
+    private MacAddress srcMacPort1 = MacAddress.valueOf("11:22:33:44:55:66");
+    private IpAddress srcIpPort1 = IpAddress.valueOf("10.0.0.3");
+    private DeviceId srcDeviceId1 = DeviceId.deviceId("of:000000000000000a");
+    private PortNumber srcPortNum1 = PortNumber.portNumber(1);
+    private IpAddress targetIpToGw = IpAddress.valueOf("10.0.0.1");
+    private IpAddress targetIpToExternal = IpAddress.valueOf("8.8.8.8");
+    private IpAddress sNatIp = IpAddress.valueOf("172.27.0.13");
+    private MacAddress targetMac = Constants.DEFAULT_GATEWAY_MAC;
+    private MacAddress peerRouterMac = Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
+    private Port port1;
+    private Port externalPort;
+    private Subnet subnet1;
+
+    Map<String, Port> portMap = Maps.newHashMap();
+    Map<String, InstancePort> instancePortMap = Maps.newHashMap();
+    Map<String, Router> osRouterMap = Maps.newHashMap();
+    Map<String, RouterInterface> osRouterInterfaceMap = Maps.newHashMap();
+
+    /**
+     * Initial setup for this unit test.
+     */
+    @Before
+    public void setUp() {
+
+        icmpHandler = new OpenstackRoutingIcmpHandler();
+
+        icmpHandler.coreService = new TestCoreService();
+        icmpHandler.packetService = new TestPacketService();
+        icmpHandler.storageService = new TestStorageService();
+        icmpHandler.osNodeService = new TestOpenstackNodeService();
+        icmpHandler.instancePortService = new TestInstancePortService();
+        icmpHandler.osNetworkService = new TestOpenstackNetworkService();
+        icmpHandler.osRouterService = new TestOpenstackRouterService();
+        TestUtils.setField(icmpHandler, "eventExecutor", MoreExecutors.newDirectExecutorService());
+        icmpHandler.activate();
+
+        createPort();
+        createSubnet();
+        createInstancePortMap();
+        createRouterInterfaceMap();
+        createRouterMap();
+    }
+
+    /**
+     * Tears down all of this unit test.
+     */
+    @After
+    public void tearDown() {
+        icmpHandler.deactivate();
+
+    }
+
+    /**
+     * Tests the icmp request to gateway.
+     */
+    @Test
+    public void testRequestToGw() {
+        Ethernet icmpRequest = constructIcmpRequestPacket(srcIpPort1,
+                srcMacPort1,
+                targetIpToGw,
+                targetMac,
+                TYPE_ECHO_REQUEST);
+        sendPacket(icmpRequest);
+    }
+
+    /**
+     * Tests the icmp request to external.
+     */
+    @Test
+    public void testRequestToExternal() {
+        Ethernet icmpRequest = constructIcmpRequestPacket(srcIpPort1,
+                srcMacPort1,
+                targetIpToExternal,
+                targetMac,
+                TYPE_ECHO_REQUEST);
+
+        sendPacket(icmpRequest);
+
+        Ethernet icmpResponse = constructIcmpRequestPacket(targetIpToExternal,
+                peerRouterMac,
+                sNatIp,
+                targetMac,
+                TYPE_ECHO_REPLY);
+
+        sendPacket(icmpResponse);
+    }
+
+    private void sendPacket(Ethernet ethernet) {
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(ethernet.serialize());
+        InboundPacket inPacket = new DefaultInboundPacket(connectPoint(srcDeviceId1.toString(),
+                Integer.parseInt(srcPortNum1.toString())),
+                ethernet,
+                byteBuffer);
+
+        PacketContext context = new TestPacketContext(127L, inPacket, null, false);
+        packetProcessor.process(context);
+    }
+
+    private void validatePacket(Ethernet ethernet) {
+        IPv4 ipPacket = (IPv4) ethernet.getPayload();
+
+        if (IPv4.fromIPv4Address(ipPacket.getSourceAddress()).equals(targetIpToGw.toString())) {
+            validateIcmpReqToGw(ipPacket);
+        } else if (IPv4.fromIPv4Address(ipPacket.getSourceAddress())
+                .equals(sNatIp.toString())) {
+            validateIcmpReqToExternal(ipPacket);
+        } else if (IPv4.fromIPv4Address(ipPacket.getSourceAddress())
+                .equals(targetIpToExternal.toString())) {
+            validateIcmpRespFromExternal(ipPacket);
+        }
+    }
+
+    private void validateIcmpRespFromExternal(IPv4 ipPacket) {
+        ICMP icmpResp = (ICMP) ipPacket.getPayload();
+        short icmpId = ByteBuffer.wrap(icmpResp.serialize(), 4, 2).getShort();
+        short seqNum = ByteBuffer.wrap(icmpResp.serialize(), 6, 2).getShort();
+
+        assertEquals(icmpResp.getIcmpType(), TYPE_ECHO_REPLY);
+        assertEquals(icmpResp.getIcmpCode(), CODE_ECHO_REPLY);
+        assertEquals(icmpId, 0);
+        assertEquals(seqNum, 0);
+        assertEquals(IPv4.fromIPv4Address(ipPacket.getSourceAddress()), targetIpToExternal.toString());
+        assertEquals(IPv4.fromIPv4Address(ipPacket.getDestinationAddress()), srcIpPort1.toString());
+    }
+
+    private void validateIcmpReqToExternal(IPv4 ipPacket) {
+        ICMP icmpReq = (ICMP) ipPacket.getPayload();
+        short icmpId = ByteBuffer.wrap(icmpReq.serialize(), 4, 2).getShort();
+        short seqNum = ByteBuffer.wrap(icmpReq.serialize(), 6, 2).getShort();
+
+
+        assertEquals(icmpReq.getIcmpType(), TYPE_ECHO_REQUEST);
+        assertEquals(icmpReq.getIcmpCode(), CODE_ECHO_REQUEST);
+        assertEquals(icmpId, 0);
+        assertEquals(seqNum, 0);
+        assertEquals(IPv4.fromIPv4Address(ipPacket.getSourceAddress()), sNatIp.toString());
+        assertEquals(IPv4.fromIPv4Address(ipPacket.getDestinationAddress()), targetIpToExternal.toString());
+
+    }
+    private void validateIcmpReqToGw(IPv4 ipPacket) {
+        ICMP icmpReq = (ICMP) ipPacket.getPayload();
+        short icmpId = ByteBuffer.wrap(icmpReq.serialize(), 4, 2).getShort();
+        short seqNum = ByteBuffer.wrap(icmpReq.serialize(), 6, 2).getShort();
+
+        assertEquals(icmpReq.getIcmpType(), TYPE_ECHO_REPLY);
+        assertEquals(icmpReq.getIcmpCode(), CODE_ECHO_REPLY);
+        assertEquals(icmpId, 0);
+        assertEquals(seqNum, 0);
+        assertEquals(IPv4.fromIPv4Address(ipPacket.getSourceAddress()), targetIpToGw.toString());
+        assertEquals(IPv4.fromIPv4Address(ipPacket.getDestinationAddress()), srcIpPort1.toString());
+    }
+
+    private Ethernet constructIcmpRequestPacket(IpAddress srcIp,
+                                                MacAddress srcMac,
+                                                IpAddress dstIp,
+                                                MacAddress dstMac, byte icmpType) {
+        try {
+            IcmpEcho icmp = new IcmpEcho();
+            if (icmpType == TYPE_ECHO_REQUEST) {
+                icmp.setIcmpType(TYPE_ECHO_REQUEST)
+                        .setIcmpCode(CODE_ECHO_REQUEST);
+            } else {
+                icmp.setIcmpType(TYPE_ECHO_REPLY)
+                        .setIcmpCode(CODE_ECHO_REPLY);
+            }
+
+            icmp.setChecksum((short) 0)
+                    .setIdentifier((short) 0)
+                    .setSequenceNum((short) 0);
+
+            ByteBuffer bb = ByteBuffer.wrap(icmp.serialize());
+
+            IPv4 iPacket = new IPv4();
+            iPacket.setDestinationAddress(dstIp.toString());
+            iPacket.setSourceAddress(srcIp.toString());
+            iPacket.setTtl((byte) 64);
+            iPacket.setChecksum((short) 0);
+            iPacket.setDiffServ((byte) 0);
+            iPacket.setProtocol(IPv4.PROTOCOL_ICMP);
+
+            iPacket.setPayload(ICMP.deserializer().deserialize(bb.array(), 0, 8));
+
+            Ethernet ethPacket = new Ethernet();
+
+            ethPacket.setEtherType(TYPE_IPV4);
+            ethPacket.setSourceMACAddress(srcMac);
+            ethPacket.setDestinationMACAddress(dstMac);
+            ethPacket.setPayload(iPacket);
+
+            return ethPacket;
+        } catch (DeserializationException e) {
+            return null;
+        }
+    }
+
+    private class TestCoreService extends CoreServiceAdapter {
+        @Override
+        public ApplicationId registerApplication(String name) {
+            return new DefaultApplicationId(200, "test");
+        }
+    }
+
+    /**
+     * Mocks the PacketService.
+     */
+    private class TestPacketService extends PacketServiceAdapter {
+        @Override
+        public void addProcessor(PacketProcessor processor, int priority) {
+            packetProcessor = processor;
+        }
+
+        @Override
+        public void emit(OutboundPacket packet) {
+            try {
+                Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(),
+                        0, packet.data().array().length);
+                validatePacket(eth);
+            } catch (Exception e) {
+                fail(e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Mocks the OpenstackNodeService.
+     */
+    private class TestOpenstackNodeService extends OpenstackNodeServiceAdapter {
+
+        @Override
+        public OpenstackNode node(DeviceId deviceId) {
+            return new TestOpenstackNode();
+        }
+    }
+
+    /**
+     * Mocks the InstancePortService.
+     */
+    private class TestInstancePortService extends InstancePortServiceAdapter {
+        @Override
+        public InstancePort instancePort(MacAddress macAddress) {
+            return instancePortMap.values().stream()
+                    .filter(port -> Objects.equals(port.macAddress(), macAddress))
+                    .findAny().orElse(null);
+        }
+
+        @Override
+        public InstancePort instancePort(IpAddress ipAddress, String osNetId) {
+            return instancePortMap.values().stream()
+                    .filter(port -> port.networkId().equals(osNetId))
+                    .filter(port -> port.ipAddress().equals(ipAddress))
+                    .findFirst().orElse(null);
+        }
+
+        @Override
+        public InstancePort instancePort(String osPortId) {
+            return instancePortMap.get(osPortId);
+        }
+
+        @Override
+        public Set<InstancePort> instancePorts() {
+            return ImmutableSet.copyOf(instancePortMap.values());
+        }
+
+        @Override
+        public Set<InstancePort> instancePorts(String osNetId) {
+            Set<InstancePort> ports = instancePortMap.values().stream()
+                    .filter(port -> port.networkId().equals(osNetId))
+                    .collect(Collectors.toSet());
+
+            return ImmutableSet.copyOf(ports);
+        }
+    }
+
+    /**
+     * Mocks the OpenstackNetworkService.
+     */
+    private class TestOpenstackNetworkService extends OpenstackNetworkServiceAdapter {
+        @Override
+        public Set<Port> ports(String netId) {
+            return ImmutableSet.copyOf(portMap.values());
+        }
+        @Override
+        public Port port(String portId) {
+
+            return port1;
+        }
+
+        @Override
+        public Subnet subnet(String subnetId) {
+
+            return subnet1;
+        }
+
+        @Override
+        public ExternalPeerRouter externalPeerRouter(ExternalGateway externalGateway) {
+            return DefaultExternalPeerRouter.builder()
+                    .ipAddress(IpAddress.valueOf("172.27.0.1"))
+                    .macAddress(peerRouterMac)
+                    .vlanId(VlanId.NONE)
+                    .build();
+        }
+    }
+
+    /**
+     * Mocks the OpenstackRouterService.
+     */
+    private class TestOpenstackRouterService extends OpenstackRouterServiceAdapter {
+        @Override
+        public Set<RouterInterface> routerInterfaces() {
+            return ImmutableSet.copyOf(osRouterInterfaceMap.values());
+        }
+
+        @Override
+        public Router router(String osRouterId) {
+            return osRouterMap.get(osRouterId);
+        }
+        public Set<RouterInterface> routerInterfaces(String osRouterId) {
+            return osRouterInterfaceMap.values().stream()
+                    .filter(iface -> iface.getId().equals(osRouterId))
+                    .collect(Collectors.toSet());
+        }
+
+    }
+
+    /**
+     * Mocks the DefaultPacket context.
+     */
+    private final class TestPacketContext extends DefaultPacketContext {
+        private TestPacketContext(long time, InboundPacket inPkt,
+                                  OutboundPacket outPkt, boolean block) {
+            super(time, inPkt, outPkt, block);
+        }
+
+        @Override
+        public void send() {
+            // We don't send anything out.
+        }
+    }
+
+
+    private void createPort() {
+        InputStream portJsonStream1 = OpenstackRoutingIcmpHandlerTest.class
+                .getResourceAsStream("openstack-port-1.json");
+        port1 = (Port) OpenstackNetworkingUtil.jsonToModelEntity(portJsonStream1, NeutronPort.class);
+
+        InputStream portJsonStream2 = OpenstackRoutingIcmpHandlerTest.class
+                .getResourceAsStream("openstack-port-external.json");
+        externalPort = (Port) OpenstackNetworkingUtil.jsonToModelEntity(portJsonStream2, NeutronPort.class);
+
+        portMap.put(port1.getId(), port1);
+        portMap.put(externalPort.getId(), externalPort);
+
+    }
+
+    private void createSubnet() {
+        InputStream subnetJsonStream1 = OpenstackRoutingIcmpHandlerTest.class
+                .getResourceAsStream("openstack-subnet-1.json");
+        subnet1 = (Subnet) OpenstackNetworkingUtil.jsonToModelEntity(subnetJsonStream1, NeutronSubnet.class);
+    }
+
+    private void createRouterInterfaceMap() {
+        routerInterface1 = new TestRouterInterface("router-id-1",
+                "subnet-id-1",
+                "router-interface-id-1",
+                "tenant-id-1");
+
+        osRouterInterfaceMap.put(routerInterface1.getPortId(), routerInterface1);
+    }
+
+    private void createRouterMap() {
+        InputStream routerStream1 = OpenstackRoutingIcmpHandlerTest.class
+                .getResourceAsStream("openstack-router-1.json");
+        router1 = (Router)
+                OpenstackNetworkingUtil.jsonToModelEntity(routerStream1, NeutronRouter.class);
+        osRouterMap.put(router1.getId(), router1);
+
+    }
+    private void createInstancePortMap() {
+        instancePort1 = DefaultInstancePort.builder()
+                .networkId("net-id-1")
+                .portId("ce705c24-c1ef-408a-bda3-7bbd946164ab")
+                .deviceId(srcDeviceId1)
+                .portNumber(srcPortNum1)
+                .ipAddress(srcIpPort1)
+                .macAddress(srcMacPort1)
+                .state(InstancePort.State.valueOf("ACTIVE"))
+                .build();
+
+        instancePort2 = DefaultInstancePort.builder()
+                .networkId("net-id-2")
+                .portId("port-id-2")
+                .deviceId(DeviceId.deviceId("of:000000000000000b"))
+                .portNumber(PortNumber.portNumber(2))
+                .ipAddress(IpAddress.valueOf("10.10.10.2"))
+                .macAddress(MacAddress.valueOf("22:33:44:55:66:11"))
+                .state(InstancePort.State.valueOf("ACTIVE"))
+                .build();
+
+        instancePort3 = DefaultInstancePort.builder()
+                .networkId("net-id-3")
+                .portId("port-id-3")
+                .deviceId(DeviceId.deviceId("of:000000000000000c"))
+                .oldDeviceId(DeviceId.deviceId("of:000000000000000d"))
+                .oldPortNumber(PortNumber.portNumber(4, "tap-4"))
+                .portNumber(PortNumber.portNumber(3, "tap-3"))
+                .ipAddress(IpAddress.valueOf("10.10.10.3"))
+                .macAddress(MacAddress.valueOf("33:44:55:66:11:22"))
+                .state(InstancePort.State.valueOf("ACTIVE"))
+                .build();
+
+        instancePortMap.put(instancePort1.portId(), instancePort1);
+        instancePortMap.put(instancePort2.portId(), instancePort2);
+        instancePortMap.put(instancePort3.portId(), instancePort3);
+    }
+
+
+    private class TestOpenstackNode extends OpenstackNodeAdapter {
+        public TestOpenstackNode() {
+            super();
+        }
+        @Override
+        public PortNumber uplinkPortNum() {
+            return PortNumber.portNumber(1);
+        }
+    }
+}
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/TestRouterInterface.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/TestRouterInterface.java
new file mode 100644
index 0000000..c23ccd8
--- /dev/null
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/TestRouterInterface.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.openstack4j.model.network.RouterInterface;
+
+/**
+ * Test implementation class of router interface.
+ */
+public final class TestRouterInterface implements RouterInterface {
+    private final String id;
+    private final String subnetId;
+    private final String portId;
+    private final String tenantId;
+
+    public TestRouterInterface(String id, String subnetId,
+                               String portId, String tenantId) {
+        this.id = id;
+        this.subnetId = subnetId;
+        this.portId = portId;
+        this.tenantId = tenantId;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String getSubnetId() {
+        return subnetId;
+    }
+
+    @Override
+    public String getPortId() {
+        return portId;
+    }
+
+    @Override
+    public String getTenantId() {
+        return tenantId;
+    }
+}