port SdnIpTest.java to onos-next

Change-Id: Iec9de810b168e3fbc8f1aa447778d3883fba03a1
diff --git a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/TestHostService.java b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/TestHostService.java
new file mode 100644
index 0000000..9edddc1
--- /dev/null
+++ b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/TestHostService.java
@@ -0,0 +1,183 @@
+package org.onlab.onos.sdnip;
+
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.DefaultHost;
+import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.Host;
+import org.onlab.onos.net.HostId;
+import org.onlab.onos.net.HostLocation;
+import org.onlab.onos.net.host.HostEvent;
+import org.onlab.onos.net.host.HostListener;
+import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.host.PortAddresses;
+import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.sdnip.Router.InternalHostListener;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Test version of the HostService which is used to simulate delays in
+ * receiving ARP replies, as you would see in a real system due to the time
+ * it takes to proxy ARP packets to/from the host. Requests are asynchronous,
+ * and replies may come back to the requestor in a different order than the
+ * requests were sent, which again you would expect to see in a real system.
+ */
+public class TestHostService implements HostService {
+
+    /**
+     * The maximum possible delay before an ARP reply is received.
+     */
+    private static final int MAX_ARP_REPLY_DELAY = 30; // milliseconds
+
+    /**
+     * The probability that we already have the MAC address cached when the
+     * caller calls {@link #getHostsByIp(IpAddress ipAddress)}.
+     */
+    private static final float MAC_ALREADY_KNOWN_PROBABILITY = 0.3f;
+
+    private final ScheduledExecutorService replyTaskExecutor;
+    private final Random random;
+
+    /**
+     * Class constructor.
+     */
+    public TestHostService() {
+        replyTaskExecutor = Executors.newSingleThreadScheduledExecutor();
+        random = new Random();
+    }
+
+    /**
+     * Task used to reply to ARP requests from a different thread. Replies
+     * usually come on a different thread in the real system, so we need to
+     * ensure we test this behavior.
+     */
+    private class ReplyTask implements Runnable {
+        private HostListener listener;
+        private IpAddress ipAddress;
+
+        /**
+         * Class constructor.
+         *
+         * @param listener the client who requests and waits the MAC address
+         * @param ipAddress the target IP address of the request
+         */
+        public ReplyTask(InternalHostListener listener,
+                IpAddress ipAddress) {
+            this.listener = listener;
+            this.ipAddress = ipAddress;
+        }
+
+        @Override
+        public void run() {
+            Host host = getHostsByIp(ipAddress).iterator().next();
+            HostEvent hostevent =
+                    new HostEvent(HostEvent.Type.HOST_ADDED, host);
+            listener.event(hostevent);
+        }
+    }
+
+    @Override
+    public Set<Host> getHostsByIp(IpAddress ipAddress) {
+        float replyChance = random.nextFloat();
+
+        // We don't care what the attachment point is in the test,
+        // so for all the hosts, we use a same ConnectPoint.
+        Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
+                SdnIpTest.generateMacAddress(ipAddress), VlanId.NONE,
+                new HostLocation(SdnIpTest.SW1_ETH1, 1),
+                Sets.newHashSet(ipAddress));
+
+        if (replyChance < MAC_ALREADY_KNOWN_PROBABILITY) {
+            // Some percentage of the time we already know the MAC address, so
+            // we reply directly when the requestor asks for the MAC address
+            return Sets.newHashSet(host);
+        }
+        return new HashSet<Host>();
+    }
+
+    @Override
+    public void startMonitoringIp(IpAddress ipAddress) {
+
+        // Randomly select an amount of time to delay the reply coming back to
+        int delay = random.nextInt(MAX_ARP_REPLY_DELAY);
+        ReplyTask replyTask = new ReplyTask(
+                (SdnIpTest.router.new InternalHostListener()), ipAddress);
+        replyTaskExecutor.schedule(replyTask, delay, TimeUnit.MILLISECONDS);
+    }
+
+    @Override
+    public int getHostCount() {
+        return 0;
+    }
+
+    @Override
+    public Iterable<Host> getHosts() {
+        return null;
+    }
+
+    @Override
+    public Host getHost(HostId hostId) {
+        return null;
+    }
+
+    @Override
+    public Set<Host> getHostsByVlan(VlanId vlanId) {
+        return null;
+    }
+
+    @Override
+    public Set<Host> getHostsByMac(MacAddress mac) {
+        return null;
+    }
+
+    @Override
+    public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
+        return null;
+    }
+
+    @Override
+    public Set<Host> getConnectedHosts(DeviceId deviceId) {
+        return null;
+    }
+
+    @Override
+    public void stopMonitoringIp(IpAddress ip) {
+
+    }
+
+    @Override
+    public void requestMac(IpAddress ip) {
+
+    }
+
+    @Override
+    public Set<PortAddresses> getAddressBindings() {
+        return null;
+    }
+
+    @Override
+    public Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint) {
+        return null;
+    }
+
+    @Override
+    public void addListener(HostListener listener) {
+
+    }
+
+    @Override
+    public void removeListener(HostListener listener) {
+
+    }
+
+}