blob: 1510e354ede74c7213534fad5cd7000b29d10920 [file] [log] [blame]
/*
* Copyright 2015-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.net.meter.impl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestTools;
import org.onlab.junit.TestUtils;
import org.onlab.packet.IpAddress;
import org.onlab.util.KryoNamespace;
import org.onosproject.TestApplicationId;
import org.onosproject.cfg.ComponentConfigAdapter;
import org.onosproject.cluster.ClusterServiceAdapter;
import org.onosproject.cluster.ControllerNode;
import org.onosproject.cluster.DefaultControllerNode;
import org.onosproject.cluster.NodeId;
import org.onosproject.common.event.impl.TestEventDispatcher;
import org.onosproject.mastership.MastershipServiceAdapter;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.behaviour.MeterQuery;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.net.config.NetworkConfigServiceAdapter;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.driver.DefaultDriver;
import org.onosproject.net.driver.DriverRegistry;
import org.onosproject.net.driver.impl.DriverManager;
import org.onosproject.net.driver.impl.DriverRegistryManager;
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.MeterCellId;
import org.onosproject.net.meter.MeterFeatures;
import org.onosproject.net.meter.MeterId;
import org.onosproject.net.meter.MeterOperation;
import org.onosproject.net.meter.MeterOperations;
import org.onosproject.net.meter.MeterProgrammable;
import org.onosproject.net.meter.MeterProvider;
import org.onosproject.net.meter.MeterProviderRegistry;
import org.onosproject.net.meter.MeterProviderService;
import org.onosproject.net.meter.MeterRequest;
import org.onosproject.net.meter.MeterScope;
import org.onosproject.net.meter.MeterService;
import org.onosproject.net.meter.MeterState;
import org.onosproject.net.pi.PiPipeconfServiceAdapter;
import org.onosproject.net.pi.model.PiMeterId;
import org.onosproject.net.pi.runtime.PiMeterCellId;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.meter.impl.DistributedMeterStore;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.TestStorageService;
import org.osgi.service.component.ComponentContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.concurrent.CompletableFuture;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.onosproject.net.NetTestTools.APP_ID;
import static org.onosproject.net.NetTestTools.did;
import static org.onosproject.net.NetTestTools.injectEventDispatcher;
import static org.onosproject.net.OsgiPropertyConstants.MM_USER_DEFINED_INDEX;
/**
* Meter manager tests.
*/
public class MeterManagerTest {
// 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 static final ProviderId PID = new ProviderId("of", "foo");
private static final ProviderId PROGRAMMABLE_PROVIDER = new ProviderId("foo", "foo");
private static final DeviceId PROGRAMMABLE_DID = DeviceId.deviceId("test:002");
private static final DefaultAnnotations ANNOTATIONS =
DefaultAnnotations.builder().set(AnnotationKeys.DRIVER, "foo").build();
private static final Device PROGRAMMABLE_DEV =
new DefaultDevice(PROGRAMMABLE_PROVIDER, PROGRAMMABLE_DID, Device.Type.SWITCH,
"", "", "", "", null, ANNOTATIONS);
private MeterService service;
// Test Driver service used during the tests
private DriverManager driverService;
// Test device service used during the tests
private DeviceService deviceService;
// Test provider used during the tests
private TestProvider provider;
// Meter manager
private MeterManager manager;
// Meter provider registry
private MeterProviderRegistry registry;
// Meter provider service
private MeterProviderService providerService;
// 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);
private MeterCellId cid0 = PiMeterCellId.ofIndirect(PiMeterId.of("foo"), 0L);
// Bands used during the tests
private static 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();
private static Meter mProgrammable = DefaultMeter.builder()
.forDevice(PROGRAMMABLE_DID)
.fromApp(APP_ID)
.withId(MeterId.meterId(1))
.withUnit(Meter.Unit.KB_PER_SEC)
.withBands(Collections.singletonList(b1))
.build();
private static Meter mProgrammable2 = DefaultMeter.builder()
.forDevice(PROGRAMMABLE_DID)
.fromApp(APP_ID)
.withId(MeterId.meterId(2))
.withUnit(Meter.Unit.KB_PER_SEC)
.withBands(Collections.singletonList(b1))
.build();
private static Meter mUserDefined = DefaultMeter.builder()
.forDevice(PROGRAMMABLE_DID)
.fromApp(APP_ID)
.withCellId(PiMeterCellId.ofIndirect(PiMeterId.of("foo"), 0L))
.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));
private MeterRequest.Builder mProgrammableRequest = DefaultMeterRequest.builder()
.forDevice(PROGRAMMABLE_DID)
.fromApp(APP_ID)
.withUnit(Meter.Unit.KB_PER_SEC)
.withBands(Collections.singletonList(b1));
private MeterRequest.Builder mProgrammableRequest2 = DefaultMeterRequest.builder()
.forDevice(PROGRAMMABLE_DID)
.fromApp(APP_ID)
.withUnit(Meter.Unit.KB_PER_SEC)
.withBands(Collections.singletonList(b1));
private MeterRequest.Builder userDefinedRequest = DefaultMeterRequest.builder()
.forDevice(PROGRAMMABLE_DID)
.fromApp(APP_ID)
.withUnit(Meter.Unit.KB_PER_SEC)
.withBands(Collections.singletonList(b1))
.withScope(MeterScope.of("foo"))
.withIndex(0L);
// 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();
private MeterFeatures programmableMef1 = DefaultMeterFeatures.builder().forDevice(PROGRAMMABLE_DID)
.withStartIndex(1)
.withEndIndex(10L)
.withBandTypes(new HashSet<>())
.withUnits(new HashSet<>())
.hasStats(false)
.hasBurst(false)
.withMaxBands((byte) 0)
.withMaxColors((byte) 0)
.build();
private MeterFeatures programmableMef2 = DefaultMeterFeatures.builder().forDevice(PROGRAMMABLE_DID)
.withStartIndex(0)
.withEndIndex(10L)
.withScope(MeterScope.of("foo"))
.withBandTypes(new HashSet<>())
.withUnits(new HashSet<>())
.hasStats(false)
.hasBurst(false)
.withMaxBands((byte) 0)
.withMaxColors((byte) 0)
.build();
private ComponentContext componentContext = EasyMock.createMock(ComponentContext.class);
@Before
public void setup() {
//Init step for the deviceService
deviceService = new TestDeviceService();
//Init step for the driver registry and driver service.
DriverRegistryManager driverRegistry = new DriverRegistryManager();
driverService = new TestDriverManager(driverRegistry, deviceService, new NetworkConfigServiceAdapter());
driverRegistry.addDriver(new DefaultDriver("foo", ImmutableList.of(), "",
"", "",
ImmutableMap.of(MeterProgrammable.class,
TestMeterProgrammable.class, MeterQuery.class, TestMeterQuery.class),
ImmutableMap.of()));
// 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, "driverService", driverService);
// Inject TestApplicationId into the DistributedMeterStore serializer
KryoNamespace.Builder testKryoBuilder = TestUtils.getField(meterStore, "APP_KRYO_BUILDER");
testKryoBuilder.register(TestApplicationId.class);
Serializer testSerializer = Serializer.using(Lists.newArrayList(testKryoBuilder.build()));
TestUtils.setField(meterStore, "serializer", testSerializer);
// Activate the store
meterStore.activate();
// Init step for the manager
manager = new MeterManager();
// Let's initialize some internal services of the manager
TestUtils.setField(manager, "store", meterStore);
injectEventDispatcher(manager, new TestEventDispatcher());
manager.deviceService = deviceService;
manager.mastershipService = new TestMastershipService();
manager.cfgService = new ComponentConfigAdapter();
manager.clusterService = new TestClusterService();
// Init the reference of the registry
registry = manager;
manager.driverService = driverService;
// Activate the manager
Dictionary<String, Object> cfgDict = new Hashtable<>();
expect(componentContext.getProperties()).andReturn(cfgDict);
replay(componentContext);
manager.activate(componentContext);
// Initialize the test provider
provider = new TestProvider(PID);
// Register the provider against the manager
providerService = registry.register(provider);
// Verify register
assertTrue("provider should be registered",
registry.getProviders().contains(provider.id()));
}
@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();
}
// Store meter features for all the devices
private void initMeterStore() {
meterStore.storeMeterFeatures(mef1);
meterStore.storeMeterFeatures(mef2);
meterStore.storeMeterFeatures(programmableMef1);
meterStore.storeMeterFeatures(programmableMef2);
}
// Emulate metrics coming from the dataplane
private void pushMetrics(MeterOperation.Type type, Meter meter) {
if (type == MeterOperation.Type.ADD) {
((DefaultMeter) meter).setState(MeterState.ADDED);
providerService.pushMeterMetrics(meter.deviceId(), Collections.singletonList(meter));
} else {
providerService.pushMeterMetrics(meter.deviceId(), Collections.emptyList());
}
}
/**
* Verify enabling user defined index mode in meter service.
*/
@Test
public void testEnableUserDefinedIndex() {
reset(componentContext);
Dictionary<String, Object> cfgDict = new Hashtable<>();
cfgDict.put(MM_USER_DEFINED_INDEX, true);
expect(componentContext.getProperties()).andReturn(cfgDict);
replay(componentContext);
Object returnValue = TestUtils.callMethod(manager, "readComponentConfiguration",
ComponentContext.class, componentContext);
assertNull(returnValue);
assertTrue(manager.userDefinedIndex);
}
/**
* Verify disabling user defined index mode in meter service.
*/
@Test
public void testDisableUserDefinedIndex() {
testEnableUserDefinedIndex();
reset(componentContext);
Dictionary<String, Object> cfgDict = new Hashtable<>();
cfgDict.put(MM_USER_DEFINED_INDEX, false);
expect(componentContext.getProperties()).andReturn(cfgDict);
replay(componentContext);
Object returnValue = TestUtils.callMethod(manager, "readComponentConfiguration",
ComponentContext.class, componentContext);
assertNull(returnValue);
assertFalse(manager.userDefinedIndex);
}
/**
* Test add meter.
*/
@Test
public void testAdd() {
// Init store
initMeterStore();
// Submit meter request
manager.submit(m1Request.add());
// Verify add
assertEquals("The meter was not added", 1, manager.getAllMeters().size());
assertEquals("The meter was not added", 1, manager.getMeters(did1).size());
// 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));
assertEquals("The meter was not installed", 1, manager.getAllMeters().size());
assertEquals("The meter was not installed", 1, manager.getMeters(did1).size());
}
/**
* Test add meter with user defined index.
*/
@Test
public void testAddWithUserDefinedIndex() {
initMeterStore();
testEnableUserDefinedIndex();
manager.submit(userDefinedRequest.add());
assertEquals("The meter was not added", 1, manager.getAllMeters().size());
assertEquals("The meter was not added", 1, manager.getMeters(PROGRAMMABLE_DID).size());
Meter installingMeter = manager.getMeter(PROGRAMMABLE_DID, cid0);
assertThat(installingMeter, is(mUserDefined));
assertThat(installingMeter.state(), is(MeterState.PENDING_ADD));
pushMetrics(MeterOperation.Type.ADD, installingMeter);
Meter installedMeter = manager.getMeter(PROGRAMMABLE_DID, cid0);
assertThat(installedMeter.state(), is(MeterState.ADDED));
assertEquals("The meter was not installed", 1, manager.getAllMeters().size());
assertEquals("The meter was not installed", 1, manager.getMeters(PROGRAMMABLE_DID).size());
}
/**
* Test wrong add meter.
*/
@Test(expected = IllegalArgumentException.class)
public void testWrongAdd() {
initMeterStore();
manager.submit(userDefinedRequest.add());
}
/**
* Test wrong add meter in user defined index mode.
*/
@Test(expected = IllegalArgumentException.class)
public void testWrongAddInUserDefinedIndexMode() {
initMeterStore();
testEnableUserDefinedIndex();
manager.submit(m1Request.add());
}
/**
* 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());
// Get Meter
Meter withdrawingMeter = manager.getMeter(did1, mid1);
// Verify withdrawing
assertThat(withdrawingMeter.state(), is(MeterState.PENDING_REMOVE));
assertEquals("The meter was not withdrawn", 1, manager.getAllMeters().size());
assertEquals("The meter was not withdrawn", 1, manager.getMeters(did1).size());
// Let's simulate a working data-plane
pushMetrics(MeterOperation.Type.REMOVE, withdrawingMeter);
// Verify withdrawn
assertNull(manager.getMeter(did1, mid1));
assertEquals("The meter was not removed", 0, manager.getAllMeters().size());
assertEquals("The meter was not removed", 0, manager.getMeters(did1).size());
}
/**
* Test remove meter in user defined index mode.
*/
@Test
public void testRemoveInUserDefinedIndexMode() {
initMeterStore();
testEnableUserDefinedIndex();
manager.submit(userDefinedRequest.add());
manager.withdraw(userDefinedRequest.remove(), cid0);
Meter withdrawingMeter = manager.getMeter(PROGRAMMABLE_DID, cid0);
assertThat(withdrawingMeter.state(), is(MeterState.PENDING_REMOVE));
assertEquals("The meter was not withdrawn", 1, manager.getAllMeters().size());
assertEquals("The meter was not withdrawn", 1, manager.getMeters(PROGRAMMABLE_DID).size());
pushMetrics(MeterOperation.Type.REMOVE, withdrawingMeter);
assertNull(manager.getMeter(PROGRAMMABLE_DID, cid0));
assertEquals("The meter was not removed", 0, manager.getAllMeters().size());
assertEquals("The meter was not removed", 0, manager.getMeters(PROGRAMMABLE_DID).size());
}
/**
* Test add multiple devices.
*/
@Test
public void testAddMultipleDevice() {
// Init store
initMeterStore();
// Submit meter 1
manager.submit(m1Request.add());
// Submit meter 2
manager.submit(m2Request.add());
// Verify add
assertEquals("The meter was not added", 2, manager.getAllMeters().size());
assertEquals("The meter was not added", 1, manager.getMeters(did1).size());
assertEquals("The meter was not added", 1, manager.getMeters(did2).size());
// 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));
assertEquals("The meter was not installed", 2, manager.getAllMeters().size());
assertEquals("The meter was not installed", 1, manager.getMeters(did1).size());
assertEquals("The meter was not installed", 1, manager.getMeters(did2).size());
}
/**
* Test remove multiple devices.
*/
@Test
public void testRemoveMultipleDevice() {
// Init store
initMeterStore();
// Submit meter 1
manager.submit(m1Request.add());
// 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));
assertEquals("The meter was not withdrawn", 2, manager.getAllMeters().size());
assertEquals("The meter was not withdrawn", 1, manager.getMeters(did1).size());
assertEquals("The meter was not withdrawn", 1, manager.getMeters(did2).size());
// 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));
assertEquals("The meter was not removed", 0, manager.getAllMeters().size());
assertEquals("The meter was not removed", 0, manager.getMeters(did1).size());
assertEquals("The meter was not removed", 0, manager.getMeters(did2).size());
}
/**
* Test purge meter.
*/
@Test
public void testPurge() {
// Init store
initMeterStore();
// Submit meter request
manager.submit(m1Request.add());
// Verify submit
Meter submittingMeter = manager.getMeter(did1, mid1);
assertThat(submittingMeter.state(), is(MeterState.PENDING_ADD));
assertEquals("The meter was not added", 1, manager.getAllMeters().size());
assertEquals("The meter was not added", 1, manager.getMeters(did1).size());
// Purge the meters
manager.purgeMeters(did1);
// Verify purge
assertNull(manager.getMeter(did1, mid1));
assertEquals("The meter was not purged", 0, manager.getAllMeters().size());
assertEquals("The meter was not purged", 0, manager.getMeters(did1).size());
}
/**
* Test submit for programmable devices.
*/
@Test
public void testAddFromMeterProgrammable() {
// Init store
initMeterStore();
manager.submit(mProgrammableRequest.add());
TestTools.assertAfter(500, () -> {
assertEquals("The meter was not added", 1, manager.getAllMeters().size());
assertThat(manager.getMeter(PROGRAMMABLE_DID, MeterId.meterId(1)), is(mProgrammable));
});
}
/**
* Test batch submission for meter programmable.
*/
@Test
public void testAddBatchFromMeterProgrammable() {
// Init store
initMeterStore();
List<MeterOperation> operations = ImmutableList.of(new MeterOperation(mProgrammable, MeterOperation.Type.ADD));
manager.defaultProvider().performMeterOperation(PROGRAMMABLE_DID, new MeterOperations(operations));
TestTools.assertAfter(500, () -> {
assertEquals("The meter was not added", 1, meterOperations.size());
assertEquals("Wrong Meter Operation", meterOperations.get(0).meter().id(), mProgrammable.id());
});
}
/**
* Verify get from meter programmable.
*/
@Test
public void testGetFromMeterProgrammable() {
// Init store
initMeterStore();
MeterDriverProvider fallback = (MeterDriverProvider) manager.defaultProvider();
testAddFromMeterProgrammable();
fallback.init(manager.deviceService, fallback.meterProviderService, manager.mastershipService, 1);
TestTools.assertAfter(2000, () -> {
assertEquals("The meter was not added", 1, manager.getAllMeters().size());
Meter m = manager.getMeters(PROGRAMMABLE_DID).iterator().next();
assertEquals("incorrect state", MeterState.ADDED, m.state());
});
}
/**
* Verify installation of missing meters when using meter programmable devices.
*/
@Test
public void testMissingFromMeterProgrammable() {
// Workaround when running the tests all together
meterOperations.clear();
testGetFromMeterProgrammable();
assertThat(meterOperations.size(), is(1));
manager.submit(mProgrammableRequest2.add());
TestTools.assertAfter(500, () -> {
assertEquals("The meter was not added", 2, manager.getAllMeters().size());
assertThat(manager.getMeter(PROGRAMMABLE_DID, MeterId.meterId(2)), is(mProgrammable2));
assertThat(meterOperations.size(), is(2));
assertThat(meterOperations.get(meterOperations.size() - 1), is(new MeterOperation(mProgrammable2,
MeterOperation.Type.ADD)));
});
TestTools.assertAfter(2000, () -> {
assertEquals("The meter was not added", 2, manager.getAllMeters().size());
Meter pendingMeter = manager.getMeter(PROGRAMMABLE_DID, MeterId.meterId(2));
assertThat(pendingMeter, is(mProgrammable2));
assertEquals("incorrect state", MeterState.PENDING_ADD, pendingMeter.state());
assertThat(meterOperations.size(), is(3));
assertThat(meterOperations.get(meterOperations.size() - 1), is(new MeterOperation(mProgrammable2,
MeterOperation.Type.ADD)));
});
}
/**
* Verify removal of unknown meters when using meter programmable devices.
*/
@Test
public void testUnknownFromMeterProgrammable() {
meterOperations.clear();
testGetFromMeterProgrammable();
TestMeterProgrammable.unknownMeter = true;
assertThat(meterOperations.size(), is(1));
TestTools.assertAfter(2000, () -> {
assertEquals("The meter was not added", 1, manager.getAllMeters().size());
Meter pendingMeter = manager.getMeter(PROGRAMMABLE_DID, MeterId.meterId(2));
assertNull(pendingMeter);
assertThat(meterOperations.size(), is(2));
assertThat(meterOperations.get(meterOperations.size() - 1), is(new MeterOperation(mProgrammable2,
MeterOperation.Type.REMOVE)));
});
}
/**
* Verify removal of meters when using meter programmable devices.
*/
@Test
public void testRemoveFromMeterProgrammable() {
testEnableUserDefinedIndex();
initMeterStore();
MeterDriverProvider fallback = (MeterDriverProvider) manager.defaultProvider();
fallback.init(manager.deviceService, fallback.meterProviderService, manager.mastershipService, 1);
manager.submit(mProgrammableRequest2.withIndex(2L).add());
TestTools.assertAfter(500, () -> {
assertEquals("The meter was not added", 1, manager.getAllMeters().size());
Meter pendingMeter = manager.getMeter(PROGRAMMABLE_DID, MeterId.meterId(2));
assertThat(pendingMeter, is(mProgrammable2));
assertEquals("incorrect state", MeterState.PENDING_ADD, pendingMeter.state());
});
manager.withdraw(mProgrammableRequest2.remove(), MeterId.meterId(2));
TestTools.assertAfter(500, () -> {
assertEquals("The meter was not withdrawn", 1, manager.getAllMeters().size());
Meter pendingMeter = manager.getMeter(PROGRAMMABLE_DID, MeterId.meterId(2));
assertThat(pendingMeter, is(mProgrammable2));
assertEquals("incorrect state", MeterState.PENDING_REMOVE, pendingMeter.state());
});
TestTools.assertAfter(2000, () -> {
assertEquals("The meter was not removed", 0, manager.getAllMeters().size());
Meter pendingMeter = manager.getMeter(PROGRAMMABLE_DID, MeterId.meterId(2));
assertNull(pendingMeter);
});
}
// Test cluster service
private final class TestClusterService extends ClusterServiceAdapter {
private ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST);
@Override
public ControllerNode getLocalNode() {
return local;
}
@Override
public Set<ControllerNode> getNodes() {
return Sets.newHashSet();
}
}
private static class TestDeviceService extends DeviceServiceAdapter {
@Override
public int getDeviceCount() {
return 1;
}
@Override
public Iterable<Device> getDevices() {
return ImmutableList.of(PROGRAMMABLE_DEV);
}
@Override
public Iterable<Device> getAvailableDevices() {
return getDevices();
}
@Override
public Device getDevice(DeviceId deviceId) {
return PROGRAMMABLE_DEV;
}
}
private class TestDriverManager extends DriverManager {
TestDriverManager(DriverRegistry registry, DeviceService deviceService,
NetworkConfigService networkConfigService) {
this.registry = registry;
this.deviceService = deviceService;
this.networkConfigService = networkConfigService;
this.pipeconfService = new PiPipeconfServiceAdapter();
activate();
}
}
public static class TestMeterQuery extends AbstractHandlerBehaviour
implements MeterQuery {
private static final long MAX_METER = 0x00000FFF;
@Override
public long getMaxMeters() {
return MAX_METER;
}
}
private static List<MeterOperation> meterOperations = new ArrayList<>();
public static class TestMeterProgrammable extends AbstractHandlerBehaviour
implements MeterProgrammable {
private static boolean unknownMeter;
@Override
public CompletableFuture<Boolean> performMeterOperation(MeterOperation meterOp) {
return CompletableFuture.completedFuture(meterOperations.add(meterOp));
}
@Override
public CompletableFuture<Collection<Meter>> getMeters() {
//ADD METER
Collection<Meter> meters = Lists.newArrayList();
DefaultMeter mProgrammableAdded = (DefaultMeter) mProgrammable;
mProgrammableAdded.setState(MeterState.ADDED);
meters.add(mProgrammableAdded);
if (unknownMeter) {
DefaultMeter mProgrammable2Added = (DefaultMeter) mProgrammable2;
mProgrammable2Added.setState(MeterState.ADDED);
meters.add(mProgrammable2Added);
}
return CompletableFuture.completedFuture(meters);
}
@Override
public CompletableFuture<Collection<MeterFeatures>> getMeterFeatures() {
//Currently unused.
return CompletableFuture.completedFuture(Collections.emptySet());
}
}
private class TestProvider extends AbstractProvider implements MeterProvider {
protected TestProvider(ProviderId id) {
super(PID);
}
@Override
public void performMeterOperation(DeviceId deviceId, MeterOperations meterOps) {
//Currently unused.
}
@Override
public void performMeterOperation(DeviceId deviceId, MeterOperation meterOp) {
//Currently unused
}
}
// Test mastership service
private final class TestMastershipService extends MastershipServiceAdapter {
@Override
public NodeId getMasterFor(DeviceId deviceId) {
return NID_LOCAL;
}
@Override
public MastershipRole getLocalRole(DeviceId deviceId) {
return MastershipRole.MASTER;
}
}
}