Unit tests for flow objective manager
Change-Id: I2f4e3084493174fcff7d64d2da1806b7b811b41f
diff --git a/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManagerTest.java b/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManagerTest.java
new file mode 100644
index 0000000..5360e10
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManagerTest.java
@@ -0,0 +1,416 @@
+/*
+ * 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.net.flowobjective.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.packet.ChassisId;
+import org.onosproject.mastership.MastershipEvent;
+import org.onosproject.mastership.MastershipListener;
+import org.onosproject.mastership.MastershipServiceAdapter;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.net.behaviour.DefaultNextGroup;
+import org.onosproject.net.behaviour.NextGroup;
+import org.onosproject.net.behaviour.PipelinerAdapter;
+import org.onosproject.net.behaviour.PipelinerContext;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.driver.AbstractDriverLoader;
+import org.onosproject.net.driver.Behaviour;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.net.driver.DefaultDriverProviderService;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverData;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flowobjective.DefaultFilteringObjective;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.DefaultNextObjective;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.flowobjective.ObjectiveEvent;
+import org.onosproject.net.intent.TestTools;
+import org.onosproject.openflow.DriverAdapter;
+import org.onosproject.openflow.DriverServiceAdapter;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onlab.junit.TestUtils.TestUtilsException;
+
+/**
+ * Tests for the flow objective manager.
+ */
+public class FlowObjectiveManagerTest {
+
+ private static final int RETRY_MS = 250;
+ private FlowObjectiveManager manager;
+ DeviceId id1 = NetTestTools.did("d1");
+ DefaultDevice d1 = new DefaultDevice(NetTestTools.PID, id1, Device.Type.SWITCH,
+ "test", "1.0", "1.0",
+ "abacab", new ChassisId("c"),
+ DefaultAnnotations.EMPTY);
+
+ DeviceId id2 = NetTestTools.did("d2");
+ DefaultDevice d2 = new DefaultDevice(NetTestTools.PID, id2, Device.Type.SWITCH,
+ "test", "1.0", "1.0",
+ "abacab", new ChassisId("c"),
+ DefaultAnnotations.EMPTY);
+
+ List<String> filteringObjectives;
+ List<String> forwardingObjectives;
+ List<String> nextObjectives;
+
+ private class TestDeviceService extends DeviceServiceAdapter {
+
+ List<Device> deviceList;
+
+ TestDeviceService() {
+ deviceList = new ArrayList<>();
+
+ deviceList.add(d1);
+ }
+
+ @Override
+ public Iterable<Device> getDevices() {
+ return deviceList;
+ }
+
+ @Override
+ public boolean isAvailable(DeviceId deviceId) {
+ return true;
+ }
+ }
+
+ private class TestFlowObjectiveStore extends FlowObjectiveStoreAdapter {
+ @Override
+ public NextGroup getNextGroup(Integer nextId) {
+ if (nextId != 4) {
+ byte[] data = new byte[1];
+ data[0] = 5;
+ return new DefaultNextGroup(data);
+ } else {
+ return null;
+ }
+ }
+
+ }
+
+ private class TestDriversLoader extends AbstractDriverLoader implements DefaultDriverProviderService {
+ public TestDriversLoader() {
+ super("/onos-drivers.xml");
+ }
+ }
+
+ private class TestDriver extends DriverAdapter {
+
+ @Override
+ public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
+ return true;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T extends Behaviour> T createBehaviour(DriverData data, Class<T> behaviourClass) {
+ return (T) new TestPipeliner();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T extends Behaviour> T createBehaviour(DriverHandler handler, Class<T> behaviourClass) {
+ return (T) new TestPipeliner();
+ }
+
+ }
+
+ private class TestPipeliner extends PipelinerAdapter {
+ DeviceId deviceId;
+
+ @Override
+ public void init(DeviceId deviceId, PipelinerContext context) {
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public void filter(FilteringObjective filterObjective) {
+ filteringObjectives.add(deviceId.toString());
+ }
+
+ @Override
+ public void forward(ForwardingObjective forwardObjective) {
+ forwardingObjectives.add(deviceId.toString());
+ }
+
+ @Override
+ public void next(NextObjective nextObjective) {
+ nextObjectives.add(deviceId.toString());
+ }
+ }
+
+ private class TestDriverService extends DriverServiceAdapter {
+ @Override
+ public DriverHandler createHandler(DeviceId deviceId, String... credentials) {
+ Driver driver = new TestDriver();
+ return new DefaultDriverHandler(new DefaultDriverData(driver, id1));
+ }
+ }
+
+ @Before
+ public void initializeTest() {
+ manager = new FlowObjectiveManager();
+ manager.flowObjectiveStore = new TestFlowObjectiveStore();
+ manager.mastershipService = new MastershipServiceAdapter();
+ manager.deviceService = new TestDeviceService();
+ manager.defaultDriverService = new TestDriversLoader();
+ manager.driverService = new TestDriverService();
+
+ filteringObjectives = new ArrayList<>();
+ forwardingObjectives = new ArrayList<>();
+ nextObjectives = new ArrayList<>();
+ manager.activate();
+ }
+
+ @After
+ public void tearDownTest() {
+ manager.deactivate();
+ manager = null;
+ filteringObjectives.clear();
+ forwardingObjectives.clear();
+ nextObjectives.clear();
+ }
+
+ /**
+ * Tests adding a forwarding objective.
+ */
+ @Test
+ public void forwardingObjective() {
+ TrafficSelector selector = DefaultTrafficSelector.emptySelector();
+ TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+ ForwardingObjective forward =
+ DefaultForwardingObjective.builder()
+ .fromApp(NetTestTools.APP_ID)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .makePermanent()
+ .add();
+
+ manager.forward(id1, forward);
+
+ TestTools.assertAfter(RETRY_MS, () ->
+ assertThat(forwardingObjectives, hasSize(1)));
+
+ assertThat(forwardingObjectives, hasItem("of:d1"));
+ assertThat(filteringObjectives, hasSize(0));
+ assertThat(nextObjectives, hasSize(0));
+ }
+
+ /**
+ * Tests adding a filtering objective.
+ */
+ @Test
+ public void filteringObjective() {
+ TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+ FilteringObjective filter =
+ DefaultFilteringObjective.builder()
+ .fromApp(NetTestTools.APP_ID)
+ .withMeta(treatment)
+ .makePermanent()
+ .deny()
+ .addCondition(Criteria.matchEthType(12))
+ .add();
+
+ manager.activate();
+ manager.filter(id1, filter);
+
+ TestTools.assertAfter(RETRY_MS, () ->
+ assertThat(filteringObjectives, hasSize(1)));
+
+ assertThat(forwardingObjectives, hasSize(0));
+ assertThat(filteringObjectives, hasItem("of:d1"));
+ assertThat(nextObjectives, hasSize(0));
+ }
+
+ /**
+ * Tests adding a next objective.
+ */
+ @Test
+ public void nextObjective() {
+ TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+ NextObjective next =
+ DefaultNextObjective.builder()
+ .withId(manager.allocateNextId())
+ .addTreatment(treatment)
+ .withType(NextObjective.Type.BROADCAST)
+ .fromApp(NetTestTools.APP_ID)
+ .makePermanent()
+ .add();
+
+ manager.next(id1, next);
+
+ TestTools.assertAfter(RETRY_MS, () ->
+ assertThat(nextObjectives, hasSize(1)));
+
+ assertThat(forwardingObjectives, hasSize(0));
+ assertThat(filteringObjectives, hasSize(0));
+ assertThat(nextObjectives, hasItem("of:d1"));
+ }
+
+ /**
+ * Tests adding a pending forwarding objective.
+ *
+ * @throws TestUtilsException if lookup of a field fails
+ */
+ @Test
+ public void pendingForwardingObjective() throws TestUtilsException {
+ TrafficSelector selector = DefaultTrafficSelector.emptySelector();
+ TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+
+ ForwardingObjective forward4 =
+ DefaultForwardingObjective.builder()
+ .fromApp(NetTestTools.APP_ID)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .makePermanent()
+ .nextStep(4)
+ .add();
+ ForwardingObjective forward5 =
+ DefaultForwardingObjective.builder()
+ .fromApp(NetTestTools.APP_ID)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .makePermanent()
+ .nextStep(5)
+ .add();
+
+ // multiple pending forwards should be combined
+ manager.forward(id1, forward4);
+ manager.forward(id1, forward4);
+ manager.forward(id1, forward5);
+
+
+ // 1 should be complete, 1 pending
+ TestTools.assertAfter(RETRY_MS, () ->
+ assertThat(forwardingObjectives, hasSize(1)));
+
+ assertThat(forwardingObjectives, hasItem("of:d1"));
+ assertThat(filteringObjectives, hasSize(0));
+ assertThat(nextObjectives, hasSize(0));
+
+ // Now send events to trigger the objective still in the queue
+ ObjectiveEvent event1 = new ObjectiveEvent(ObjectiveEvent.Type.ADD, 4);
+ FlowObjectiveStoreDelegate delegate = TestUtils.getField(manager, "delegate");
+ delegate.notify(event1);
+
+ // all should be processed now
+ TestTools.assertAfter(RETRY_MS, () ->
+ assertThat(forwardingObjectives, hasSize(2)));
+ assertThat(forwardingObjectives, hasItem("of:d1"));
+ assertThat(filteringObjectives, hasSize(0));
+ assertThat(nextObjectives, hasSize(0));
+ }
+
+ /**
+ * Tests receipt of a device up event.
+ *
+ * @throws TestUtilsException if lookup of a field fails
+ */
+ @Test
+ public void deviceUpEvent() throws TestUtilsException {
+ TrafficSelector selector = DefaultTrafficSelector.emptySelector();
+ TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+
+ DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, d2);
+ DeviceListener listener = TestUtils.getField(manager, "deviceListener");
+ assertThat(listener, notNullValue());
+
+ listener.event(event);
+
+ ForwardingObjective forward =
+ DefaultForwardingObjective.builder()
+ .fromApp(NetTestTools.APP_ID)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .makePermanent()
+ .add();
+ manager.forward(id2, forward);
+
+ // new device should have an objective now
+ TestTools.assertAfter(RETRY_MS, () ->
+ assertThat(forwardingObjectives, hasSize(1)));
+
+ assertThat(forwardingObjectives, hasItem("of:d2"));
+ assertThat(filteringObjectives, hasSize(0));
+ assertThat(nextObjectives, hasSize(0));
+ }
+
+ /**
+ * Tests recepit of a device mastership event.
+ *
+ * @throws TestUtilsException if lookup of a field fails
+ */
+ @Test
+ public void deviceMastershipEvent() throws TestUtilsException {
+ TrafficSelector selector = DefaultTrafficSelector.emptySelector();
+ TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+
+ MastershipEvent event =
+ new MastershipEvent(MastershipEvent.Type.MASTER_CHANGED, id2, null);
+ MastershipListener listener = TestUtils.getField(manager, "mastershipListener");
+ assertThat(listener, notNullValue());
+
+ listener.event(event);
+
+ ForwardingObjective forward =
+ DefaultForwardingObjective.builder()
+ .fromApp(NetTestTools.APP_ID)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .makePermanent()
+ .add();
+ manager.forward(id2, forward);
+
+ // new device should have an objective now
+ TestTools.assertAfter(RETRY_MS, () ->
+ assertThat(forwardingObjectives, hasSize(1)));
+
+ assertThat(forwardingObjectives, hasItem("of:d2"));
+ assertThat(filteringObjectives, hasSize(0));
+ assertThat(nextObjectives, hasSize(0));
+ }
+}
diff --git a/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveStoreAdapter.java b/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveStoreAdapter.java
new file mode 100644
index 0000000..378ea73
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveStoreAdapter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.net.flowobjective.impl;
+
+import org.onosproject.net.behaviour.NextGroup;
+import org.onosproject.net.flowobjective.FlowObjectiveStore;
+import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
+
+/**
+ * Test adapter for the flow objective store API.
+ */
+public class FlowObjectiveStoreAdapter implements FlowObjectiveStore {
+ @Override
+ public void putNextGroup(Integer nextId, NextGroup group) {
+
+ }
+
+ @Override
+ public NextGroup getNextGroup(Integer nextId) {
+ return null;
+ }
+
+ @Override
+ public NextGroup removeNextGroup(Integer nextId) {
+ return null;
+ }
+
+ @Override
+ public int allocateNextId() {
+ return 0;
+ }
+
+ @Override
+ public void setDelegate(FlowObjectiveStoreDelegate delegate) {
+
+ }
+
+ @Override
+ public void unsetDelegate(FlowObjectiveStoreDelegate delegate) {
+
+ }
+
+ @Override
+ public boolean hasDelegate() {
+ return false;
+ }
+}