[ONOS-7114] Meter Subsystem Refactoring
Changes:
- Moves meter counters in the store
- Uses atomic counter map for meter counters
- Implements atomic counter map adapter and test atomic counter map
- Introduces free meter id
- Changes allocate meter id
- Implements unit tests for MeterManager and MeterStore
Change-Id: I45e3debc0e43ca7edcf6e3b4065866634f76f9f7
diff --git a/core/net/src/test/java/org/onosproject/net/meter/impl/MeterManagerTest.java b/core/net/src/test/java/org/onosproject/net/meter/impl/MeterManagerTest.java
index cc19cd0..51d3384 100644
--- a/core/net/src/test/java/org/onosproject/net/meter/impl/MeterManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/meter/impl/MeterManagerTest.java
@@ -15,7 +15,6 @@
*/
package org.onosproject.net.meter.impl;
-import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
@@ -27,8 +26,6 @@
import org.onosproject.cluster.DefaultControllerNode;
import org.onosproject.cluster.NodeId;
import org.onosproject.common.event.impl.TestEventDispatcher;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.DefaultApplicationId;
import org.onosproject.incubator.store.meter.impl.DistributedMeterStore;
import org.onosproject.mastership.MastershipServiceAdapter;
import org.onosproject.net.DeviceId;
@@ -38,7 +35,7 @@
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.MeterFeatures;
import org.onosproject.net.meter.MeterId;
import org.onosproject.net.meter.MeterOperation;
import org.onosproject.net.meter.MeterOperations;
@@ -46,16 +43,13 @@
import org.onosproject.net.meter.MeterProviderRegistry;
import org.onosproject.net.meter.MeterProviderService;
import org.onosproject.net.meter.MeterRequest;
-import org.onosproject.net.meter.MeterService;
import org.onosproject.net.meter.MeterState;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.service.TestStorageService;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
import static org.hamcrest.Matchers.is;
@@ -69,194 +63,295 @@
*/
public class MeterManagerTest {
- private static final ProviderId PID = new ProviderId("of", "foo");
+ // Test node id
private static final NodeId NID_LOCAL = new NodeId("local");
+
+ // Test ip address
private static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
- private MeterService service;
- private MeterManager manager;
- private DistributedMeterStore meterStore;
- private MeterProviderRegistry registry;
- private MeterProviderService providerService;
+ // Provider id used during the tests
+ private static final ProviderId PID = new ProviderId("of", "foo");
+ // Test provider used during the tests
private TestProvider provider;
- private ApplicationId appId;
+ // Meter manager
+ private MeterManager manager;
+ // Meter provider registry
+ private MeterProviderRegistry registry;
- private Meter m1;
- private Meter m2;
- private MeterRequest.Builder m1Request;
- private MeterRequest.Builder m2Request;
- private MeterRequest.Builder m3Request;
+ // Meter provider service
+ private MeterProviderService providerService;
- private Map<MeterId, Meter> meters = Maps.newHashMap();
+ // Store under testing
+ private DistributedMeterStore meterStore;
+
+ // Device ids used during the tests
+ private DeviceId did1 = did("1");
+ private DeviceId did2 = did("2");
+
+ // Meter ids used during the tests
+ private MeterId mid1 = MeterId.meterId(1);
+
+ // Bands used during the tests
+ private Band b1 = DefaultBand.builder()
+ .ofType(Band.Type.DROP)
+ .withRate(500)
+ .build();
+
+ // Meters used during the tests
+ private Meter m1 = DefaultMeter.builder()
+ .forDevice(did1)
+ .fromApp(APP_ID)
+ .withId(mid1)
+ .withUnit(Meter.Unit.KB_PER_SEC)
+ .withBands(Collections.singletonList(b1))
+ .build();
+ private Meter m2 = DefaultMeter.builder()
+ .forDevice(did2)
+ .fromApp(APP_ID)
+ .withId(mid1)
+ .withUnit(Meter.Unit.KB_PER_SEC)
+ .withBands(Collections.singletonList(b1))
+ .build();
+
+ // Meter requests used during the tests
+ private MeterRequest.Builder m1Request = DefaultMeterRequest.builder()
+ .forDevice(did1)
+ .fromApp(APP_ID)
+ .withUnit(Meter.Unit.KB_PER_SEC)
+ .withBands(Collections.singletonList(b1));
+ private MeterRequest.Builder m2Request = DefaultMeterRequest.builder()
+ .forDevice(did2)
+ .fromApp(APP_ID)
+ .withUnit(Meter.Unit.KB_PER_SEC)
+ .withBands(Collections.singletonList(b1));
+
+ // Meter features used during the tests
+ private MeterFeatures mef1 = DefaultMeterFeatures.builder().forDevice(did1)
+ .withMaxMeters(3L)
+ .withBandTypes(new HashSet<>())
+ .withUnits(new HashSet<>())
+ .hasStats(false)
+ .hasBurst(false)
+ .withMaxBands((byte) 0)
+ .withMaxColors((byte) 0)
+ .build();
+ private MeterFeatures mef2 = DefaultMeterFeatures.builder().forDevice(did2)
+ .withMaxMeters(10L)
+ .withBandTypes(new HashSet<>())
+ .withUnits(new HashSet<>())
+ .hasStats(false)
+ .hasBurst(false)
+ .withMaxBands((byte) 0)
+ .withMaxColors((byte) 0)
+ .build();
@Before
- public void setup() throws Exception {
+ public void setup() {
+ // Init step for the store
meterStore = new DistributedMeterStore();
+ // Let's initialize some internal services of the store
TestUtils.setField(meterStore, "storageService", new TestStorageService());
TestUtils.setField(meterStore, "clusterService", new TestClusterService());
TestUtils.setField(meterStore, "mastershipService", new TestMastershipService());
+ // Activate the store
meterStore.activate();
- meterStore.storeMeterFeatures(DefaultMeterFeatures.builder().forDevice(did("1"))
- .withMaxMeters(255L)
- .withBandTypes(new HashSet<>())
- .withUnits(new HashSet<>())
- .hasStats(false)
- .hasBurst(false)
- .withMaxBands((byte) 0)
- .withMaxColors((byte) 0)
- .build());
- meterStore.storeMeterFeatures(DefaultMeterFeatures.builder().forDevice(did("2"))
- .withMaxMeters(2)
- .withBandTypes(new HashSet<>())
- .withUnits(new HashSet<>())
- .hasBurst(false)
- .hasStats(false)
- .withMaxBands((byte) 0)
- .withMaxColors((byte) 0)
- .build());
-
+ // Init step for the manager
manager = new MeterManager();
- manager.store = meterStore;
- TestUtils.setField(manager, "storageService", new TestStorageService());
+ // Let's initialize some internal services of the manager
+ TestUtils.setField(manager, "store", meterStore);
injectEventDispatcher(manager, new TestEventDispatcher());
- service = manager;
+ // Init the reference of the registry
registry = manager;
-
+ // Activate the manager
manager.activate();
-
+ // Initialize the test provider
provider = new TestProvider(PID);
+ // Register the provider against the manager
providerService = registry.register(provider);
-
- appId = new TestApplicationId(0, "MeterManagerTest");
-
+ // Verify register
assertTrue("provider should be registered",
registry.getProviders().contains(provider.id()));
-
- Band band = DefaultBand.builder()
- .ofType(Band.Type.DROP)
- .withRate(500)
- .build();
-
- m1 = DefaultMeter.builder()
- .forDevice(did("1"))
- .fromApp(APP_ID)
- .withId(MeterId.meterId(1))
- .withUnit(Meter.Unit.KB_PER_SEC)
- .withBands(Collections.singletonList(band))
- .build();
-
- m2 = DefaultMeter.builder()
- .forDevice(did("2"))
- .fromApp(APP_ID)
- .withId(MeterId.meterId(1))
- .withUnit(Meter.Unit.KB_PER_SEC)
- .withBands(Collections.singletonList(band))
- .build();
-
- m1Request = DefaultMeterRequest.builder()
- .forDevice(did("1"))
- .fromApp(APP_ID)
- .withUnit(Meter.Unit.KB_PER_SEC)
- .withBands(Collections.singletonList(band));
-
- m2Request = DefaultMeterRequest.builder()
- .forDevice(did("2"))
- .fromApp(APP_ID)
- .withUnit(Meter.Unit.KB_PER_SEC)
- .withBands(Collections.singletonList(band));
-
- m3Request = DefaultMeterRequest.builder()
- .forDevice(did("1"))
- .fromApp(APP_ID)
- .withUnit(Meter.Unit.KB_PER_SEC)
- .withBands(Collections.singletonList(band));
-
}
@After
public void tearDown() {
+ // Unregister provider
registry.unregister(provider);
+ // Verify unregister
assertFalse("provider should not be registered",
registry.getProviders().contains(provider.id()));
-
+ // Deactivate manager
manager.deactivate();
+ // Remove event dispatcher
injectEventDispatcher(manager, null);
-
+ // Deactivate store
+ meterStore.deactivate();
}
+ private void initMeterStore() {
+ // Let's store feature for device 1
+ meterStore.storeMeterFeatures(mef1);
+ // Let's store feature for device 2
+ meterStore.storeMeterFeatures(mef2);
+ }
+
+ // Emulate metrics coming from the dataplane
+ private void pushMetrics(MeterOperation.Type type, Meter meter) {
+ // If it is an add operation
+ if (type == MeterOperation.Type.ADD) {
+ // Update state to added
+ ((DefaultMeter) meter).setState(MeterState.ADDED);
+ // Push the update in the store
+ providerService.pushMeterMetrics(meter.deviceId(), Collections.singletonList(meter));
+ } else {
+ providerService.pushMeterMetrics(meter.deviceId(), Collections.emptyList());
+ }
+ }
+
+ /**
+ * Test add meter.
+ */
@Test
- public void testAddition() {
+ public void testAdd() {
+ // Init store
+ initMeterStore();
+ // Submit meter request
manager.submit(m1Request.add());
-
+ // Verify add
assertTrue("The meter was not added", manager.getAllMeters().size() == 1);
-
- assertThat(manager.getMeter(did("1"), MeterId.meterId(1)), is(m1));
+ assertTrue("The meter was not added", manager.getMeters(did1).size() == 1);
+ // Get Meter
+ Meter installingMeter = manager.getMeter(did1, mid1);
+ // Verify add of installingMeter and pending add state
+ assertThat(installingMeter, is(m1));
+ // Verify pending add state
+ assertThat(installingMeter.state(), is(MeterState.PENDING_ADD));
+ // Let's simulate a working data-plane
+ pushMetrics(MeterOperation.Type.ADD, installingMeter);
+ // Get meter
+ Meter installedMeter = manager.getMeter(did1, mid1);
+ // Verify installation
+ assertThat(installedMeter.state(), is(MeterState.ADDED));
+ assertTrue("The meter was not installed", manager.getAllMeters().size() == 1);
+ assertTrue("The meter was not installed", manager.getMeters(did1).size() == 1);
}
+ /**
+ * Test remove meter.
+ */
@Test
public void testRemove() {
+ // Init store
+ initMeterStore();
+ // Submit meter request
manager.submit(m1Request.add());
+ // Withdraw meter
manager.withdraw(m1Request.remove(), m1.id());
-
- assertThat(manager.getMeter(did("1"), MeterId.meterId(1)).state(),
- is(MeterState.PENDING_REMOVE));
-
- providerService.pushMeterMetrics(m1.deviceId(), Collections.emptyList());
-
+ // Get Meter
+ Meter withdrawingMeter = manager.getMeter(did1, mid1);
+ // Verify withdrawing
+ assertThat(withdrawingMeter.state(), is(MeterState.PENDING_REMOVE));
+ assertTrue("The meter was not withdrawn", manager.getAllMeters().size() == 1);
+ assertTrue("The meter was not withdrawn", manager.getMeters(did1).size() == 1);
+ // Let's simulate a working data-plane
+ pushMetrics(MeterOperation.Type.REMOVE, withdrawingMeter);
+ // Verify withdrawn
+ assertNull(manager.getMeter(did1, mid1));
assertTrue("The meter was not removed", manager.getAllMeters().size() == 0);
-
+ assertTrue("The meter was not removed", manager.getMeters(did1).size() == 0);
}
+ /**
+ * Test add multiple device.
+ */
@Test
- public void testMultipleDevice() {
+ public void testAddMultipleDevice() {
+ // Init store
+ initMeterStore();
+ // Submit meter 1
manager.submit(m1Request.add());
+ // Submit meter 2
manager.submit(m2Request.add());
-
- assertTrue("The meters were not added", manager.getAllMeters().size() == 2);
-
- assertThat(manager.getMeter(did("1"), MeterId.meterId(1)), is(m1));
- assertThat(manager.getMeter(did("2"), MeterId.meterId(1)), is(m2));
+ // Verify add
+ assertTrue("The meter was not added", manager.getAllMeters().size() == 2);
+ assertTrue("The meter was not added", manager.getMeters(did1).size() == 1);
+ assertTrue("The meter was not added", manager.getMeters(did2).size() == 1);
+ // Get Meters
+ Meter installingMeter1 = manager.getMeter(did1, mid1);
+ Meter installingMeter2 = manager.getMeter(did2, mid1);
+ // Verify add of installingMeter
+ assertThat(installingMeter1, is(m1));
+ assertThat(installingMeter2, is(m2));
+ // Verify pending add state
+ assertThat(installingMeter1.state(), is(MeterState.PENDING_ADD));
+ assertThat(installingMeter2.state(), is(MeterState.PENDING_ADD));
+ // Let's simulate a working data-plane
+ pushMetrics(MeterOperation.Type.ADD, installingMeter1);
+ pushMetrics(MeterOperation.Type.ADD, installingMeter2);
+ // Get meter
+ Meter installedMeter1 = manager.getMeter(did1, mid1);
+ Meter installedMeter2 = manager.getMeter(did2, mid1);
+ // Verify installation
+ assertThat(installedMeter1.state(), is(MeterState.ADDED));
+ assertThat(installedMeter2.state(), is(MeterState.ADDED));
+ assertTrue("The meter was not installed", manager.getAllMeters().size() == 2);
+ assertTrue("The meter was not installed", manager.getMeters(did1).size() == 1);
+ assertTrue("The meter was not installed", manager.getMeters(did2).size() == 1);
}
+ /**
+ * Test remove meter.
+ */
@Test
- public void testMeterFeatures() {
- assertEquals(meterStore.getMaxMeters(MeterFeaturesKey.key(did("1"))), 255L);
- assertEquals(meterStore.getMaxMeters(MeterFeaturesKey.key(did("2"))), 2);
- }
-
- @Test
- public void testMeterReuse() {
+ public void testRemoveMultipleDevice() {
+ // Init store
+ initMeterStore();
+ // Submit meter 1
manager.submit(m1Request.add());
- manager.submit(m3Request.add());
- Collection<Meter> meters = manager.getMeters(did("1"));
- Meter m = meters.iterator().next();
- MeterRequest mr = DefaultMeterRequest.builder()
- .forDevice(m.deviceId())
- .fromApp(m.appId())
- .withBands(m.bands())
- .withUnit(m.unit())
- .remove();
- manager.withdraw(mr, m.id());
- mr = DefaultMeterRequest.builder()
- .forDevice(m.deviceId())
- .fromApp(m.appId())
- .withBands(m.bands())
- .withUnit(m.unit())
- .add();
- Meter meter = manager.submit(mr);
- assertTrue("Meter id not reused", m.id().equals(meter.id()));
-
+ // Submit meter 2
+ manager.submit(m2Request.add());
+ // Withdraw meter
+ manager.withdraw(m1Request.remove(), m1.id());
+ // Withdraw meter
+ manager.withdraw(m2Request.remove(), m2.id());
+ // Get Meters
+ Meter withdrawingMeter1 = manager.getMeter(did1, mid1);
+ Meter withdrawingMeter2 = manager.getMeter(did2, mid1);
+ // Verify withdrawing
+ assertThat(withdrawingMeter1.state(), is(MeterState.PENDING_REMOVE));
+ assertThat(withdrawingMeter2.state(), is(MeterState.PENDING_REMOVE));
+ assertTrue("The meter was not withdrawn", manager.getAllMeters().size() == 2);
+ assertTrue("The meter was not withdrawn", manager.getMeters(did1).size() == 1);
+ assertTrue("The meter was not withdrawn", manager.getMeters(did2).size() == 1);
+ // Let's simulate a working data-plane
+ pushMetrics(MeterOperation.Type.REMOVE, withdrawingMeter1);
+ pushMetrics(MeterOperation.Type.REMOVE, withdrawingMeter2);
+ // Verify withdrawn
+ assertNull(manager.getMeter(did1, mid1));
+ assertNull(manager.getMeter(did2, mid1));
+ assertTrue("The meter was not removed", manager.getAllMeters().size() == 0);
+ assertTrue("The meter was not removed", manager.getMeters(did1).size() == 0);
+ assertTrue("The meter was not removed", manager.getMeters(did2).size() == 0);
}
+ // Test cluster service
+ private final class TestClusterService extends ClusterServiceAdapter {
+ private ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST);
- public class TestApplicationId extends DefaultApplicationId {
- public TestApplicationId(int id, String name) {
- super(id, name);
+ @Override
+ public ControllerNode getLocalNode() {
+ return local;
}
+
+ @Override
+ public Set<ControllerNode> getNodes() {
+ return Sets.newHashSet();
+ }
+
}
private class TestProvider extends AbstractProvider implements MeterProvider {
@@ -272,30 +367,16 @@
@Override
public void performMeterOperation(DeviceId deviceId, MeterOperation meterOp) {
- meters.put(meterOp.meter().id(), meterOp.meter());
+ //Currently unused
}
}
- private final class TestClusterService extends ClusterServiceAdapter {
-
- ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST);
-
- @Override
- public ControllerNode getLocalNode() {
- return local;
- }
-
- @Override
- public Set<ControllerNode> getNodes() {
- return Sets.newHashSet();
- }
-
- }
-
- private class TestMastershipService extends MastershipServiceAdapter {
+ // Test mastership service
+ private final class TestMastershipService extends MastershipServiceAdapter {
@Override
public NodeId getMasterFor(DeviceId deviceId) {
return NID_LOCAL;
}
}
+
}