Moving DHCP to onos branch. REST API included, GUI to be added later.

Change-Id: Id52781ba93d48ad1d56097a9ceff7613a190c48e
diff --git a/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/IPAssignmentTest.java b/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/IPAssignmentTest.java
new file mode 100644
index 0000000..0783ec7
--- /dev/null
+++ b/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/IPAssignmentTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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.dhcp;
+
+import com.google.common.testing.EqualsTester;
+import junit.framework.TestCase;
+import org.junit.Assert;
+import org.junit.Test;
+import org.onlab.packet.Ip4Address;
+
+import java.util.Date;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.fail;
+
+/**
+ * Unit Tests for IPAssignment class.
+ */
+public class IPAssignmentTest extends TestCase {
+
+    private final Date dateNow = new Date();
+
+    private final IPAssignment stats1 = IPAssignment.builder()
+            .ipAddress(Ip4Address.valueOf("10.10.10.10"))
+            .leasePeriod(300)
+            .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
+            .timestamp(dateNow)
+            .build();
+
+    private final IPAssignment stats2 = IPAssignment.builder()
+            .ipAddress(Ip4Address.valueOf("10.10.10.10"))
+            .leasePeriod(300)
+            .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
+            .timestamp(dateNow)
+            .build();
+
+    private final IPAssignment stats3 = IPAssignment.builder(stats1)
+            .build();
+
+    /**
+     *  Tests the constructor for the class.
+     */
+    @Test
+    public void testConstruction() {
+        assertThat(stats3.ipAddress(), is(Ip4Address.valueOf("10.10.10.10")));
+        assertThat(stats3.timestamp(), is(dateNow));
+        assertThat(stats3.leasePeriod(), is(300));
+        assertThat(stats3.assignmentStatus(), is(IPAssignment.AssignmentStatus.Option_Expired));
+    }
+
+    /**
+     * Tests the equality and inequality of objects using Guava EqualsTester.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester()
+                .addEqualityGroup(stats1, stats1)
+                .addEqualityGroup(stats2)
+                .testEquals();
+    }
+
+    /**
+     * Tests if the toString method returns a consistent value for hashing.
+     */
+    @Test
+    public void testToString() {
+        assertThat(stats1.toString(), is(stats1.toString()));
+    }
+
+    /**
+     * Tests if the validateInputs method returns an exception for malformed object.
+     */
+    @Test
+    public void testValidateInputs() {
+        try {
+            IPAssignment stats4 = IPAssignment.builder()
+                    .ipAddress(Ip4Address.valueOf("10.10.10.10"))
+                    .leasePeriod(300)
+                    .build();
+
+            fail("Construction of a malformed IPAssignment did not throw an exception");
+        } catch (NullPointerException e) {
+            Assert.assertThat(e.getMessage(), containsString("must be specified"));
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/impl/DHCPManagerTest.java b/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/impl/DHCPManagerTest.java
new file mode 100644
index 0000000..3eda1bc
--- /dev/null
+++ b/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/impl/DHCPManagerTest.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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.dhcp.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.DHCP;
+import org.onlab.packet.DHCPOption;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.UDP;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.dhcp.DHCPStore;
+import org.onosproject.net.config.NetworkConfigRegistryAdapter;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.host.HostDescription;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
+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.net.provider.AbstractProvider;
+import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.provider.ProviderId;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.onosproject.net.NetTestTools.connectPoint;
+
+/**
+ * Set of tests of the ONOS application component.
+ */
+
+public class DHCPManagerTest {
+
+    private DHCPManager dhcpManager;
+
+    protected PacketProcessor packetProcessor;
+
+    protected HostProviderService hostProviderService;
+
+    private static final MacAddress CLIENT1_MAC = MacAddress.valueOf("1a:1a:1a:1a:1a:1a");
+
+    private static final String EXPECTED_IP = "10.2.0.2";
+
+    private static final Ip4Address BROADCAST = Ip4Address.valueOf("255.255.255.255");
+
+    private static final int TRANSACTION_ID = 1000;
+
+    private static final ProviderId PID = new ProviderId("of", "foo");
+
+    @Before
+    public void setUp() {
+        dhcpManager = new DHCPManager();
+        dhcpManager.cfgService = new TestNetworkConfigRegistry();
+        dhcpManager.packetService = new TestPacketService();
+        dhcpManager.coreService = new TestCoreService();
+        dhcpManager.dhcpStore = new TestDHCPStore();
+        hostProviderService = new TestHostProviderService(new TestHostProvider());
+        dhcpManager.hostProviderService = hostProviderService;
+        dhcpManager.hostProviderRegistry = new TestHostRegistry();
+        dhcpManager.activate();
+    }
+
+    @After
+    public void tearDown() {
+        dhcpManager.deactivate();
+    }
+
+    /**
+     * Tests the response to a DHCP Discover Packet.
+     */
+    @Test
+    public void testDiscover() {
+        Ethernet reply = constructDHCPPacket(DHCP.DHCPMessageType.MessageType_Discover);
+        sendPacket(reply);
+    }
+
+    /**
+     * Tests the response to a DHCP Request Packet.
+     */
+    @Test
+    public void testRequest() {
+        Ethernet reply = constructDHCPPacket(DHCP.DHCPMessageType.MessageType_Request);
+        sendPacket(reply);
+    }
+
+    /**
+     * Sends an Ethernet packet to the process method of the Packet Processor.
+     * @param reply Ethernet packet
+     */
+    private void sendPacket(Ethernet reply) {
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(reply.serialize());
+        InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1),
+                reply,
+                byteBuffer);
+
+        PacketContext context = new TestPacketContext(127L, inPacket, null, false);
+        packetProcessor.process(context);
+    }
+
+    /**
+     * Constructs an Ethernet packet containing a DHCP Payload.
+     * @param messageType DHCP Message Type
+     * @return Ethernet packet
+     */
+    private Ethernet constructDHCPPacket(DHCP.DHCPMessageType messageType) {
+
+        // Ethernet Frame.
+        Ethernet ethReply = new Ethernet();
+        ethReply.setSourceMACAddress(CLIENT1_MAC);
+        ethReply.setDestinationMACAddress(MacAddress.BROADCAST);
+        ethReply.setEtherType(Ethernet.TYPE_IPV4);
+        ethReply.setVlanID((short) 2);
+
+        // IP Packet
+        IPv4 ipv4Reply = new IPv4();
+        ipv4Reply.setSourceAddress(0);
+        ipv4Reply.setDestinationAddress(BROADCAST.toInt());
+        ipv4Reply.setTtl((byte) 127);
+
+        // UDP Datagram.
+        UDP udpReply = new UDP();
+        udpReply.setSourcePort((byte) UDP.DHCP_CLIENT_PORT);
+        udpReply.setDestinationPort((byte) UDP.DHCP_SERVER_PORT);
+
+        // DHCP Payload.
+        DHCP dhcpReply = new DHCP();
+        dhcpReply.setOpCode(DHCP.OPCODE_REQUEST);
+
+        dhcpReply.setYourIPAddress(0);
+        dhcpReply.setServerIPAddress(0);
+
+        dhcpReply.setTransactionId(TRANSACTION_ID);
+        dhcpReply.setClientHardwareAddress(CLIENT1_MAC.toBytes());
+        dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
+        dhcpReply.setHardwareAddressLength((byte) 6);
+
+        // DHCP Options.
+        DHCPOption option = new DHCPOption();
+        List<DHCPOption> optionList = new ArrayList<>();
+
+        // DHCP Message Type.
+        option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
+        option.setLength((byte) 1);
+        byte[] optionData = {messageType.getValue()};
+        option.setData(optionData);
+        optionList.add(option);
+
+        // DHCP Requested IP.
+        option = new DHCPOption();
+        option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue());
+        option.setLength((byte) 4);
+        optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets();
+        option.setData(optionData);
+        optionList.add(option);
+
+        // End Option.
+        option = new DHCPOption();
+        option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
+        option.setLength((byte) 1);
+        optionList.add(option);
+
+        dhcpReply.setOptions(optionList);
+
+        udpReply.setPayload(dhcpReply);
+        ipv4Reply.setPayload(udpReply);
+        ethReply.setPayload(ipv4Reply);
+
+        return ethReply;
+    }
+
+    /**
+     * Validates the contents of the packet sent by the DHCP Manager.
+     * @param packet Ethernet packet received
+     */
+    private void validatePacket(Ethernet packet) {
+        DHCP dhcpPacket = (DHCP) packet.getPayload().getPayload().getPayload();
+        assertEquals(MacAddress.valueOf(dhcpPacket.getClientHardwareAddress()), CLIENT1_MAC);
+        assertEquals(Ip4Address.valueOf(dhcpPacket.getYourIPAddress()), Ip4Address.valueOf(EXPECTED_IP));
+        assertEquals(dhcpPacket.getTransactionId(), TRANSACTION_ID);
+    }
+
+    /**
+     * Mocks the DHCPStore.
+     */
+    private final class TestDHCPStore implements DHCPStore {
+
+
+        public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
+        }
+
+        public Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP) {
+            return Ip4Address.valueOf(EXPECTED_IP);
+        }
+
+        public boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime) {
+            return true;
+        }
+
+        public void setDefaultTimeoutForPurge(int timeInSeconds) {
+        }
+
+        public void setTimerDelay(int timeInSeconds) {
+        }
+
+        public void releaseIP(MacAddress macID) {
+        }
+
+        public Map<MacAddress, Ip4Address> listMapping() {
+            Map<MacAddress, Ip4Address> map = new HashMap<>();
+            map.put(CLIENT1_MAC, Ip4Address.valueOf(EXPECTED_IP));
+            return map;
+        }
+
+        public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) {
+            return true;
+        }
+
+        public boolean removeStaticIP(MacAddress macID) {
+            return true;
+        }
+
+        public Iterable<Ip4Address> getAvailableIPs() {
+            List<Ip4Address> ipList = new ArrayList<>();
+            ipList.add(Ip4Address.valueOf(EXPECTED_IP));
+            return ImmutableSet.copyOf(ipList);
+        }
+    }
+
+    /**
+     * 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.
+        }
+    }
+
+    /**
+     * Keeps a reference to the PacketProcessor and verifies the OutboundPackets.
+     */
+    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 CoreService.
+     */
+    private class TestCoreService extends CoreServiceAdapter {
+
+    }
+
+    /**
+     * Mocks the NetworkConfigRegistry.
+     */
+    private class TestNetworkConfigRegistry extends NetworkConfigRegistryAdapter {
+
+    }
+
+    /**
+     * Mocks the HostProviderService.
+     */
+    private class TestHostProviderService extends AbstractProviderService<HostProvider>
+            implements HostProviderService {
+
+        protected TestHostProviderService(HostProvider provider) {
+            super(provider);
+        }
+
+        @Override
+        public void hostDetected(HostId hostId, HostDescription hostDescription) {
+        }
+
+        @Override
+        public void hostVanished(HostId hostId) {
+        }
+
+    }
+
+    /**
+     * Mocks the HostProvider.
+     */
+    private static class TestHostProvider extends AbstractProvider
+            implements HostProvider {
+
+        protected TestHostProvider() {
+            super(PID);
+        }
+
+        @Override
+        public ProviderId id() {
+            return PID;
+        }
+
+        @Override
+        public void triggerProbe(Host host) {
+        }
+
+    }
+
+    /**
+     * Mocks the HostProviderRegistry.
+     */
+    private class TestHostRegistry implements HostProviderRegistry {
+
+        @Override
+        public HostProviderService register(HostProvider provider) {
+            return hostProviderService;
+        }
+
+        @Override
+        public void unregister(HostProvider provider) {
+        }
+
+        @Override
+        public Set<ProviderId> getProviders() {
+            return null;
+        }
+
+    }
+
+}
diff --git a/apps/onos-app-dhcp/src/test/resources/dhcp-cfg.json b/apps/onos-app-dhcp/src/test/resources/dhcp-cfg.json
new file mode 100644
index 0000000..8ce5486
--- /dev/null
+++ b/apps/onos-app-dhcp/src/test/resources/dhcp-cfg.json
@@ -0,0 +1,24 @@
+{
+  "apps": {
+    "org.onosproject.dhcp" : {
+      "dhcp" : {
+        "ip": "10.0.0.1",
+        "mac": "1a:2b:3c:4e:5e:6f",
+        "subnet": "255.0.0.0",
+        "broadcast": "10.255.255.255",
+        "router": "10.0.0.1",
+        "domain": "10.0.0.1",
+        "ttl": "63",
+        "lease": "300",
+        "renew": "150",
+        "rebind": "200"
+      },
+      "dhcpstore" : {
+        "delay": "3",
+        "timeout": "150",
+        "startip": "10.0.0.110",
+        "endip": "10.0.0.130"
+      }
+    }
+  }
+}
\ No newline at end of file