[ONOS-5920] (vCore) Create Meter Manager and Store

Changes.
1. Virtual Meter Manager is added
2. Virtual Meter Store Interface is added
3. Simple meter store is implemented (WIP)
4. Unit tests for meter manager and store are added

Change-Id: I5c936617765a48bbdde417eab60270a1d16f9e77
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMeterManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMeterManagerTest.java
new file mode 100644
index 0000000..71c4f90
--- /dev/null
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMeterManagerTest.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2017-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.incubator.net.virtual.impl;
+
+import com.google.common.collect.Maps;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.packet.IpAddress;
+import org.onosproject.TestApplicationId;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.event.EventDeliveryService;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualNetwork;
+import org.onosproject.incubator.net.virtual.VirtualNetworkMeterStore;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
+import org.onosproject.incubator.net.virtual.event.VirtualListenerRegistryManager;
+import org.onosproject.incubator.net.virtual.impl.provider.VirtualProviderManager;
+import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider;
+import org.onosproject.incubator.net.virtual.provider.VirtualMeterProvider;
+import org.onosproject.incubator.net.virtual.provider.VirtualMeterProviderService;
+import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
+import org.onosproject.incubator.store.virtual.impl.DistributedVirtualNetworkStore;
+import org.onosproject.incubator.store.virtual.impl.SimpleVirtualMeterStore;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.TestableIntentService;
+import org.onosproject.net.meter.Band;
+import org.onosproject.net.meter.DefaultBand;
+import org.onosproject.net.meter.DefaultMeter;
+import org.onosproject.net.meter.DefaultMeterFeatures;
+import org.onosproject.net.meter.DefaultMeterRequest;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterFeaturesKey;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterOperation;
+import org.onosproject.net.meter.MeterOperations;
+import org.onosproject.net.meter.MeterRequest;
+import org.onosproject.net.meter.MeterState;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.TestStorageService;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.*;
+
+/**
+ * Virtual Network meter manager tests.
+ */
+public class VirtualNetworkMeterManagerTest extends VirtualNetworkTestUtil {
+    private static final ProviderId PID = new ProviderId("of", "foo");
+    private static final NodeId NID_LOCAL = new NodeId("local");
+    private static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
+
+    private VirtualNetworkManager manager;
+    private DistributedVirtualNetworkStore virtualNetworkManagerStore;
+    private TestableIntentService intentService = new FakeIntentManager();
+    private ServiceDirectory testDirectory;
+    private VirtualProviderManager providerRegistryService;
+
+    private EventDeliveryService eventDeliveryService;
+    VirtualListenerRegistryManager listenerRegistryManager =
+            VirtualListenerRegistryManager.getInstance();
+
+    private VirtualNetwork vnet1;
+    private VirtualNetwork vnet2;
+
+    private SimpleVirtualMeterStore meterStore;
+
+    private VirtualNetworkMeterManager meterManager1;
+    private VirtualNetworkMeterManager meterManager2;
+
+    private TestProvider provider = new TestProvider();
+    private VirtualMeterProviderService providerService1;
+    private VirtualMeterProviderService providerService2;
+
+    private ApplicationId appId;
+
+    private Meter m1;
+    private Meter m2;
+    private MeterRequest.Builder m1Request;
+    private MeterRequest.Builder m2Request;
+
+    private Map<MeterId, Meter> meters = Maps.newHashMap();
+
+    @Before
+    public void setUp() throws Exception {
+        virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
+        CoreService coreService = new TestCoreService();
+        TestStorageService storageService = new TestStorageService();
+        TestUtils.setField(virtualNetworkManagerStore, "coreService", coreService);
+        TestUtils.setField(virtualNetworkManagerStore, "storageService", storageService);
+        virtualNetworkManagerStore.activate();
+
+        meterStore = new SimpleVirtualMeterStore();
+
+        providerRegistryService = new VirtualProviderManager();
+        providerRegistryService.registerProvider(provider);
+
+        manager = new VirtualNetworkManager();
+        manager.store = virtualNetworkManagerStore;
+        TestUtils.setField(manager, "coreService", coreService);
+
+        eventDeliveryService = new TestEventDispatcher();
+        NetTestTools.injectEventDispatcher(manager, eventDeliveryService);
+//        eventDeliveryService.addSink(VirtualEvent.class, listenerRegistryManager);
+
+        appId = new TestApplicationId("MeterManagerTest");
+
+        testDirectory = new TestServiceDirectory()
+                .add(VirtualNetworkStore.class, virtualNetworkManagerStore)
+                .add(CoreService.class, coreService)
+                .add(VirtualProviderRegistryService.class, providerRegistryService)
+                .add(EventDeliveryService.class, eventDeliveryService)
+                .add(StorageService.class, storageService)
+                .add(VirtualNetworkMeterStore.class, meterStore);
+        TestUtils.setField(manager, "serviceDirectory", testDirectory);
+
+        manager.activate();
+
+        vnet1 = setupVirtualNetworkTopology(manager, TID1);
+        vnet2 = setupVirtualNetworkTopology(manager, TID2);
+
+        meterManager1 = new VirtualNetworkMeterManager(manager, vnet1.id());
+        meterManager2 = new VirtualNetworkMeterManager(manager, vnet2.id());
+
+        providerService1 = (VirtualMeterProviderService)
+                providerRegistryService.getProviderService(vnet1.id(), VirtualMeterProvider.class);
+        providerService2 = (VirtualMeterProviderService)
+                providerRegistryService.getProviderService(vnet2.id(), VirtualMeterProvider.class);
+
+        assertTrue("provider should be registered",
+                   providerRegistryService.getProviders().contains(provider.id()));
+
+        setupMeterTestVariables();
+    }
+
+    @After
+    public void tearDown() {
+        providerRegistryService.unregisterProvider(provider);
+        assertFalse("provider should not be registered",
+                    providerRegistryService.getProviders().contains(provider.id()));
+
+        manager.deactivate();
+        NetTestTools.injectEventDispatcher(manager, null);
+
+        virtualNetworkManagerStore.deactivate();
+    }
+
+    /** Test for meter submit(). */
+    @Test
+    public void testAddition() {
+        meterManager1.submit(m1Request.add());
+
+        assertTrue("The meter was not added",
+                   meterManager1.getAllMeters().size() == 1);
+        assertThat(meterManager1.getMeter(VDID1, MeterId.meterId(1)), is(m1));
+
+        assertTrue("The meter shouldn't be added for vnet2",
+                   meterManager2.getAllMeters().size() == 0);
+    }
+
+    /** Test for meter remove(). */
+    @Test
+    public void testRemove() {
+        meterManager1.submit(m1Request.add());
+        meterManager1.withdraw(m1Request.remove(), m1.id());
+
+        assertThat(meterManager1.getMeter(VDID1, MeterId.meterId(1)).state(),
+                   is(MeterState.PENDING_REMOVE));
+
+        providerService1.pushMeterMetrics(m1.deviceId(), Collections.emptyList());
+
+        assertTrue("The meter was not removed", meterManager1.getAllMeters().size() == 0);
+        assertTrue("The meter shouldn't be added for vnet2",
+                   meterManager2.getAllMeters().size() == 0);
+    }
+
+    /** Test for meter submit with multiple devices. */
+    @Test
+    public void testMultipleDevice() {
+        meterManager1.submit(m1Request.add());
+        meterManager1.submit(m2Request.add());
+
+        assertTrue("The meters were not added",
+                   meterManager1.getAllMeters().size() == 2);
+        assertTrue("The meter shouldn't be added for vnet2",
+                   meterManager2.getAllMeters().size() == 0);
+
+        assertThat(meterManager1.getMeter(VDID1, MeterId.meterId(1)), is(m1));
+        assertThat(meterManager1.getMeter(VDID2, MeterId.meterId(1)), is(m2));
+    }
+
+    /** Test for meter features inside store. */
+    @Test
+    public void testMeterFeatures() {
+        //Test for virtual network 1
+        assertEquals(meterStore.getMaxMeters(vnet1.id(),
+                                             MeterFeaturesKey.key(VDID1)), 255L);
+        assertEquals(meterStore.getMaxMeters(vnet1.id(),
+                                             MeterFeaturesKey.key(VDID2)), 2);
+        //Test for virtual network 2
+        assertEquals(meterStore.getMaxMeters(vnet2.id(),
+                                             MeterFeaturesKey.key(VDID1)), 100);
+        assertEquals(meterStore.getMaxMeters(vnet2.id(),
+                                             MeterFeaturesKey.key(VDID2)), 10);
+    }
+
+    /** Set variables such as meters and request required for testing. */
+    private void setupMeterTestVariables() {
+        Band band = DefaultBand.builder()
+                .ofType(Band.Type.DROP)
+                .withRate(500)
+                .build();
+
+        m1 = DefaultMeter.builder()
+                .forDevice(VDID1)
+                .fromApp(appId)
+                .withId(MeterId.meterId(1))
+                .withUnit(Meter.Unit.KB_PER_SEC)
+                .withBands(Collections.singletonList(band))
+                .build();
+
+        m2 = DefaultMeter.builder()
+                .forDevice(VDID2)
+                .fromApp(appId)
+                .withId(MeterId.meterId(1))
+                .withUnit(Meter.Unit.KB_PER_SEC)
+                .withBands(Collections.singletonList(band))
+                .build();
+
+        m1Request = DefaultMeterRequest.builder()
+                .forDevice(VDID1)
+                .fromApp(appId)
+                .withUnit(Meter.Unit.KB_PER_SEC)
+                .withBands(Collections.singletonList(band));
+
+        m2Request = DefaultMeterRequest.builder()
+                .forDevice(VDID2)
+                .fromApp(appId)
+                .withUnit(Meter.Unit.KB_PER_SEC)
+                .withBands(Collections.singletonList(band));
+
+        meterStore.storeMeterFeatures(vnet1.id(),
+                                      DefaultMeterFeatures.builder().forDevice(VDID1)
+                                              .withMaxMeters(255L)
+                                              .withBandTypes(new HashSet<>())
+                                              .withUnits(new HashSet<>())
+                                              .hasStats(false)
+                                              .hasBurst(false)
+                                              .withMaxBands((byte) 0)
+                                              .withMaxColors((byte) 0)
+                                              .build());
+        meterStore.storeMeterFeatures(vnet1.id(),
+                                      DefaultMeterFeatures.builder().forDevice(VDID2)
+                                              .withMaxMeters(2)
+                                              .withBandTypes(new HashSet<>())
+                                              .withUnits(new HashSet<>())
+                                              .hasBurst(false)
+                                              .hasStats(false)
+                                              .withMaxBands((byte) 0)
+                                              .withMaxColors((byte) 0)
+                                              .build());
+
+        meterStore.storeMeterFeatures(vnet2.id(),
+                                      DefaultMeterFeatures.builder().forDevice(VDID1)
+                                              .withMaxMeters(100L)
+                                              .withBandTypes(new HashSet<>())
+                                              .withUnits(new HashSet<>())
+                                              .hasStats(false)
+                                              .hasBurst(false)
+                                              .withMaxBands((byte) 0)
+                                              .withMaxColors((byte) 0)
+                                              .build());
+        meterStore.storeMeterFeatures(vnet2.id(),
+                                      DefaultMeterFeatures.builder().forDevice(VDID2)
+                                              .withMaxMeters(10)
+                                              .withBandTypes(new HashSet<>())
+                                              .withUnits(new HashSet<>())
+                                              .hasBurst(false)
+                                              .hasStats(false)
+                                              .withMaxBands((byte) 0)
+                                              .withMaxColors((byte) 0)
+                                              .build());
+    }
+
+    private class TestProvider
+            extends AbstractVirtualProvider
+            implements VirtualMeterProvider {
+
+        protected TestProvider() {
+            super(PID);
+        }
+
+        @Override
+        public void performMeterOperation(NetworkId networkId, DeviceId deviceId,
+                                          MeterOperations meterOps) {
+
+        }
+
+        @Override
+        public void performMeterOperation(NetworkId networkId, DeviceId deviceId,
+                                          MeterOperation meterOp) {
+            meters.put(meterOp.meter().id(), meterOp.meter());
+        }
+    }
+}
\ No newline at end of file