Implement updateMetric and getLoad methods of ControlPlaneMonitor

- Add rrd4j jar, and wrap it as a bundle for karaf
- Implement updateMetric and getLoad methods
- Add unit test for two methods
- Revise the DefaultMetricDatabase to make it generate unique in
  memory storage space
- Revise the ControlPlaneMonitor interface
- Rename percentage to ratio, due to long string unsupport
  issue in RRD

Change-Id: Ia9d56f8e4f4bcd7ef7a29732668caa9c6a885ecf
diff --git a/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/ControlPlaneMonitorTest.java b/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/ControlPlaneMonitorTest.java
new file mode 100644
index 0000000..7c1afef
--- /dev/null
+++ b/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/ControlPlaneMonitorTest.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2016 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.cpman.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.ControllerNode;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.cpman.ControlMetric;
+import org.onosproject.cpman.ControlMetricType;
+import org.onosproject.cpman.MetricValue;
+import org.onosproject.net.DeviceId;
+
+import java.util.Optional;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.onosproject.cpman.ControlMetricType.CPU_IDLE_TIME;
+import static org.onosproject.cpman.ControlMetricType.CPU_LOAD;
+import static org.onosproject.cpman.ControlMetricType.DISK_READ_BYTES;
+import static org.onosproject.cpman.ControlMetricType.DISK_WRITE_BYTES;
+import static org.onosproject.cpman.ControlMetricType.FLOW_MOD_PACKET;
+import static org.onosproject.cpman.ControlMetricType.FLOW_REMOVED_PACKET;
+import static org.onosproject.cpman.ControlMetricType.INBOUND_PACKET;
+import static org.onosproject.cpman.ControlMetricType.MEMORY_FREE;
+import static org.onosproject.cpman.ControlMetricType.MEMORY_FREE_RATIO;
+import static org.onosproject.cpman.ControlMetricType.MEMORY_USED;
+import static org.onosproject.cpman.ControlMetricType.MEMORY_USED_RATIO;
+import static org.onosproject.cpman.ControlMetricType.NW_INCOMING_BYTES;
+import static org.onosproject.cpman.ControlMetricType.NW_INCOMING_PACKETS;
+import static org.onosproject.cpman.ControlMetricType.NW_OUTGOING_BYTES;
+import static org.onosproject.cpman.ControlMetricType.NW_OUTGOING_PACKETS;
+import static org.onosproject.cpman.ControlMetricType.OUTBOUND_PACKET;
+import static org.onosproject.cpman.ControlMetricType.REPLY_PACKET;
+import static org.onosproject.cpman.ControlMetricType.REQUEST_PACKET;
+import static org.onosproject.cpman.ControlMetricType.SYS_CPU_TIME;
+import static org.onosproject.cpman.ControlMetricType.TOTAL_CPU_TIME;
+import static org.onosproject.cpman.ControlMetricType.USER_CPU_TIME;
+
+/**
+ * Unit test of control plane monitoring service.
+ */
+public class ControlPlaneMonitorTest {
+
+    private ControlPlaneMonitor monitor;
+    private static final Integer UPDATE_INTERVAL = 1;
+    private ClusterService mockClusterService;
+    private ControllerNode mockControllerNode;
+    private NodeId nodeId;
+    private static final ImmutableSet<ControlMetricType> CPU_METRICS =
+            ImmutableSet.of(CPU_IDLE_TIME, CPU_LOAD, SYS_CPU_TIME,
+                    USER_CPU_TIME, TOTAL_CPU_TIME);
+    private static final ImmutableSet<ControlMetricType> MEMORY_METRICS =
+            ImmutableSet.of(MEMORY_FREE, MEMORY_FREE_RATIO, MEMORY_USED,
+                    MEMORY_USED_RATIO);
+    private static final ImmutableSet<ControlMetricType> DISK_METRICS =
+            ImmutableSet.of(DISK_READ_BYTES, DISK_WRITE_BYTES);
+    private static final ImmutableSet<ControlMetricType> NETWORK_METRICS =
+            ImmutableSet.of(NW_INCOMING_BYTES, NW_OUTGOING_BYTES,
+                    NW_INCOMING_PACKETS, NW_OUTGOING_PACKETS);
+    private static final ImmutableSet<ControlMetricType> CTRL_MSGS =
+            ImmutableSet.of(INBOUND_PACKET, OUTBOUND_PACKET, FLOW_MOD_PACKET,
+                    FLOW_REMOVED_PACKET, REQUEST_PACKET, REPLY_PACKET);
+
+    @Before
+    public void setup() throws Exception {
+        monitor = new ControlPlaneMonitor();
+        monitor.activate();
+
+        nodeId = new NodeId("1");
+        mockControllerNode = new MockControllerNode(nodeId);
+        mockClusterService = createMock(ClusterService.class);
+        monitor.clusterService = mockClusterService;
+
+        expect(mockClusterService.getNode(anyObject()))
+                .andReturn(mockControllerNode).anyTimes();
+        expect(mockClusterService.getLocalNode())
+                .andReturn(mockControllerNode).anyTimes();
+        replay(mockClusterService);
+    }
+
+    /**
+     * Mock class for a controller node.
+     */
+    private static class MockControllerNode implements ControllerNode {
+        final NodeId id;
+
+        public MockControllerNode(NodeId id) {
+            this.id = id;
+        }
+
+        @Override
+        public NodeId id() {
+            return this.id;
+        }
+
+        @Override
+        public IpAddress ip() {
+            return null;
+        }
+
+        @Override
+        public int tcpPort() {
+            return 0;
+        }
+    }
+
+    private void testUpdateMetricWithoutId(ControlMetricType cmt, MetricValue mv) {
+        ControlMetric cm = new ControlMetric(cmt, mv);
+        monitor.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+    }
+
+    private void testLoadMetricWithoutId(ControlMetricType cmt, MetricValue mv) {
+        assertThat(monitor.getLoad(nodeId, cmt, Optional.ofNullable(null)).latest(), is(mv.getLoad()));
+    }
+
+    private void testUpdateMetricWithResource(ControlMetricType cmt, MetricValue mv, String resoureName) {
+        ControlMetric cm = new ControlMetric(cmt, mv);
+        monitor.updateMetric(cm, UPDATE_INTERVAL, resoureName);
+    }
+
+    private void testLoadMetricWithResource(ControlMetricType cmt, MetricValue mv, String resoureName) {
+        assertThat(monitor.getLoad(nodeId, cmt, resoureName).latest(), is(mv.getLoad()));
+    }
+
+    private void testUpdateMetricWithId(ControlMetricType cmt, MetricValue mv, DeviceId did) {
+        ControlMetric cm = new ControlMetric(cmt, mv);
+        monitor.updateMetric(cm, UPDATE_INTERVAL, Optional.of(did));
+    }
+
+    private void testLoadMetricWithId(ControlMetricType cmt, MetricValue mv, DeviceId did) {
+        assertThat(monitor.getLoad(nodeId, cmt, Optional.of(did)).latest(), is(mv.getLoad()));
+    }
+
+    @Test
+    public void testCpuMetric() {
+        MetricValue mv = new MetricValue.Builder().load(30).add();
+
+        CPU_METRICS.forEach(cmt -> testUpdateMetricWithoutId(cmt, mv));
+        CPU_METRICS.forEach(cmt -> testLoadMetricWithoutId(cmt, mv));
+    }
+
+    @Test
+    public void testMemoryMetric() {
+        MetricValue mv = new MetricValue.Builder().load(40).add();
+
+        MEMORY_METRICS.forEach(cmt -> testUpdateMetricWithoutId(cmt, mv));
+        MEMORY_METRICS.forEach(cmt -> testLoadMetricWithoutId(cmt, mv));
+    }
+
+    @Test
+    public void testDiskMetric() {
+        MetricValue mv = new MetricValue.Builder().load(50).add();
+
+        ImmutableSet<String> set = ImmutableSet.of("disk1", "disk2");
+
+        set.forEach(disk -> DISK_METRICS.forEach(cmt ->
+                testUpdateMetricWithResource(cmt, mv, disk)));
+
+        set.forEach(disk -> DISK_METRICS.forEach(cmt ->
+                testLoadMetricWithResource(cmt, mv, disk)));
+    }
+
+    @Test
+    public void testNetworkMetric() {
+        MetricValue mv = new MetricValue.Builder().load(10).add();
+
+        ImmutableSet<String> set = ImmutableSet.of("eth0", "eth1");
+
+        set.forEach(network -> NETWORK_METRICS.forEach(cmt ->
+                testUpdateMetricWithResource(cmt, mv, network)));
+
+        set.forEach(network -> NETWORK_METRICS.forEach(cmt ->
+                testLoadMetricWithResource(cmt, mv, network)));
+    }
+
+    @Test
+    public void testUpdateControlMessage() {
+        MetricValue mv = new MetricValue.Builder().load(10).add();
+
+        ImmutableSet<String> set = ImmutableSet.of("of:0000000000000001",
+                                                   "of:0000000000000002");
+
+        set.forEach(ctrlMsg -> CTRL_MSGS.forEach(cmt ->
+                testUpdateMetricWithId(cmt, mv, DeviceId.deviceId(ctrlMsg))));
+
+        set.forEach(ctrlMsg -> CTRL_MSGS.forEach(cmt ->
+                testLoadMetricWithId(cmt, mv, DeviceId.deviceId(ctrlMsg))));
+    }
+}