blob: 99f5db928116f07c31ff40a7f7be9e2bc2e19bd8 [file] [log] [blame]
/*
* Copyright 2017-present 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.intent.impl.installer;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.VlanId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.NetworkResource;
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.Criterion;
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.FlowObjectiveServiceAdapter;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.intent.FlowObjectiveIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentInstallationContext;
import org.onosproject.net.intent.IntentOperationContext;
import org.onosproject.net.intent.IntentState;
import org.onosproject.store.service.WallClockTimestamp;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.*;
import static org.onosproject.net.flowobjective.ObjectiveError.*;
/**
* Tests for flow objective Intent installer.
*/
public class FlowObjectiveIntentInstallerTest extends AbstractIntentInstallerTest {
private static final int NEXT_ID_1 = 1;
protected FlowObjectiveIntentInstaller installer;
protected TestFlowObjectiveService flowObjectiveService;
@Before
public void setup() {
super.setup();
flowObjectiveService = new TestFlowObjectiveService();
installer = new FlowObjectiveIntentInstaller();
installer.flowObjectiveService = flowObjectiveService;
installer.trackerService = trackerService;
installer.intentExtensionService = intentExtensionService;
installer.intentInstallCoordinator = intentInstallCoordinator;
installer.activate();
}
@After
public void tearDown() {
super.tearDown();
installer.deactivated();
}
/**
* Installs flow objective Intents.
*/
@Test
public void testInstallIntent() {
List<Intent> intentsToUninstall = Lists.newArrayList();
List<Intent> intentsToInstall = createFlowObjectiveIntents();
IntentData toUninstall = null;
IntentData toInstall = new IntentData(createP2PIntent(),
IntentState.INSTALLING,
new WallClockTimestamp());
toInstall = new IntentData(toInstall, intentsToInstall);
IntentOperationContext<FlowObjectiveIntent> operationContext;
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
installer.apply(operationContext);
IntentOperationContext successContext = intentInstallCoordinator.successContext;
assertEquals(successContext, operationContext);
}
/**
* Uninstalls flow objective Intents.
*/
@Test
public void testUninstallIntent() {
List<Intent> intentsToUninstall = createFlowObjectiveIntents();
List<Intent> intentsToInstall = Lists.newArrayList();
IntentData toInstall = null;
IntentData toUninstall = new IntentData(createP2PIntent(),
IntentState.WITHDRAWING,
new WallClockTimestamp());
toUninstall = new IntentData(toUninstall, intentsToUninstall);
IntentOperationContext<FlowObjectiveIntent> operationContext;
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
installer.apply(operationContext);
IntentOperationContext successContext = intentInstallCoordinator.successContext;
assertEquals(successContext, operationContext);
}
/**
* Do both uninstall and install flow objective Intents.
*/
@Test
public void testUninstallAndInstallIntent() {
List<Intent> intentsToUninstall = createFlowObjectiveIntents();
List<Intent> intentsToInstall = createAnotherFlowObjectiveIntents();
IntentData toInstall = new IntentData(createP2PIntent(),
IntentState.INSTALLING,
new WallClockTimestamp());
toInstall = new IntentData(toInstall, intentsToInstall);
IntentData toUninstall = new IntentData(createP2PIntent(),
IntentState.INSTALLED,
new WallClockTimestamp());
toUninstall = new IntentData(toUninstall, intentsToUninstall);
IntentOperationContext<FlowObjectiveIntent> operationContext;
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
installer.apply(operationContext);
IntentOperationContext successContext = intentInstallCoordinator.successContext;
assertEquals(successContext, operationContext);
}
/**
* Nothing to uninstall or install.
*/
@Test
public void testNoAnyIntentToApply() {
IntentData toInstall = null;
IntentData toUninstall = null;
IntentOperationContext<FlowObjectiveIntent> operationContext;
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
operationContext = new IntentOperationContext<>(ImmutableList.of(), ImmutableList.of(), context);
installer.apply(operationContext);
IntentOperationContext successContext = intentInstallCoordinator.successContext;
assertEquals(successContext, operationContext);
}
/*
* Error handling
*/
IntentOperationContext context;
IntentOperationContext failedContext;
IntentOperationContext successContext;
List<ObjectiveError> errors;
/**
* Handles UNSUPPORTED error.
*/
@Test
public void testUnsupportedError() {
// Unsupported, should just failed
intentInstallCoordinator = new TestIntentInstallCoordinator();
installer.intentInstallCoordinator = intentInstallCoordinator;
installer.flowObjectiveService = new TestFailedFlowObjectiveService();
context = createInstallContext();
installer.apply(context);
assertEquals(intentInstallCoordinator.failedContext, context);
}
/**
* Handles FLOWINSTALLATIONFAILED error with touch the threshold.
*/
@Test
public void testFlowInstallationFailedError() {
// flow install failed, should retry until retry threshold
intentInstallCoordinator = new TestIntentInstallCoordinator();
installer.intentInstallCoordinator = intentInstallCoordinator;
errors = ImmutableList.of(FLOWINSTALLATIONFAILED, FLOWINSTALLATIONFAILED,
FLOWINSTALLATIONFAILED, FLOWINSTALLATIONFAILED,
FLOWINSTALLATIONFAILED, FLOWINSTALLATIONFAILED,
FLOWINSTALLATIONFAILED);
installer.flowObjectiveService = new TestFailedFlowObjectiveService(errors);
context = createInstallContext();
installer.apply(context);
failedContext = intentInstallCoordinator.failedContext;
assertEquals(failedContext, context);
}
/**
* Handles FLOWINSTALLATIONFAILED error without touch the threshold.
*/
@Test
public void testFlowInstallationFailedErrorUnderThreshold() {
// And retry two times and success
intentInstallCoordinator = new TestIntentInstallCoordinator();
installer.intentInstallCoordinator = intentInstallCoordinator;
errors = ImmutableList.of(FLOWINSTALLATIONFAILED, FLOWINSTALLATIONFAILED);
installer.flowObjectiveService = new TestFailedFlowObjectiveService(errors);
context = createInstallContext();
installer.apply(context);
successContext = intentInstallCoordinator.successContext;
assertEquals(successContext, context);
}
/**
* Handles GROUPINSTALLATIONFAILED error with touch the threshold.
*/
@Test
public void testGroupInstallationFailedError() {
// Group install failed, and retry threshold exceed
intentInstallCoordinator = new TestIntentInstallCoordinator();
installer.intentInstallCoordinator = intentInstallCoordinator;
errors = ImmutableList.of(GROUPINSTALLATIONFAILED, GROUPINSTALLATIONFAILED,
GROUPINSTALLATIONFAILED, GROUPINSTALLATIONFAILED,
GROUPINSTALLATIONFAILED, GROUPINSTALLATIONFAILED,
GROUPINSTALLATIONFAILED);
installer.flowObjectiveService = new TestFailedFlowObjectiveService(errors);
context = createInstallContext();
installer.apply(context);
failedContext = intentInstallCoordinator.failedContext;
assertEquals(failedContext, context);
}
/**
* Handles GROUPINSTALLATIONFAILED error without touch the threshold.
*/
@Test
public void testGroupInstallationFailedErrorUnderThreshold() {
// group install failed, and retry two times.
intentInstallCoordinator = new TestIntentInstallCoordinator();
installer.intentInstallCoordinator = intentInstallCoordinator;
errors = ImmutableList.of(GROUPINSTALLATIONFAILED, GROUPINSTALLATIONFAILED);
installer.flowObjectiveService = new TestFailedFlowObjectiveService(errors);
context = createInstallContext();
installer.apply(context);
successContext = intentInstallCoordinator.successContext;
assertEquals(successContext, context);
}
/**
* Handles GROUPEXISTS error.
*/
@Test
public void testGroupExistError() {
// group exists, retry by using add to exist
intentInstallCoordinator = new TestIntentInstallCoordinator();
installer.intentInstallCoordinator = intentInstallCoordinator;
errors = ImmutableList.of(GROUPEXISTS);
installer.flowObjectiveService = new TestFailedFlowObjectiveService(errors);
context = createInstallContext();
installer.apply(context);
successContext = intentInstallCoordinator.successContext;
assertEquals(successContext, context);
}
/**
* Handles GROUPMISSING error with ADD_TO_EXIST operation.
*/
@Test
public void testGroupMissingError() {
// group exist -> group missing -> add group
intentInstallCoordinator = new TestIntentInstallCoordinator();
installer.intentInstallCoordinator = intentInstallCoordinator;
errors = ImmutableList.of(GROUPEXISTS, GROUPMISSING);
installer.flowObjectiveService = new TestFailedFlowObjectiveService(errors);
context = createInstallContext();
installer.apply(context);
successContext = intentInstallCoordinator.successContext;
assertEquals(successContext, context);
}
/**
* Handles GROUPMISSING error with ADD operation.
*/
@Test
public void testGroupChainElementMissingError() {
// group chain element missing
intentInstallCoordinator = new TestIntentInstallCoordinator();
installer.intentInstallCoordinator = intentInstallCoordinator;
errors = ImmutableList.of(GROUPMISSING);
installer.flowObjectiveService = new TestFailedFlowObjectiveService(errors);
context = createInstallContext();
installer.apply(context);
successContext = intentInstallCoordinator.successContext;
assertEquals(successContext, context);
}
/**
* Handles GROUPMISSING error with REMOVE operation.
*/
@Test
public void testGroupAlreadyRemoved() {
// group already removed
intentInstallCoordinator = new TestIntentInstallCoordinator();
installer.intentInstallCoordinator = intentInstallCoordinator;
errors = ImmutableList.of(GROUPMISSING);
installer.flowObjectiveService = new TestFailedFlowObjectiveService(errors);
context = createUninstallContext();
installer.apply(context);
successContext = intentInstallCoordinator.successContext;
assertEquals(successContext, context);
}
/**
* Creates Intent operation context for uninstall Intents.
*
* @return the context
*/
private IntentOperationContext createUninstallContext() {
List<Intent> intentsToUninstall = createFlowObjectiveIntents();
List<Intent> intentsToInstall = Lists.newArrayList();
IntentData toInstall = null;
IntentData toUninstall = new IntentData(createP2PIntent(),
IntentState.INSTALLING,
new WallClockTimestamp());
toUninstall = new IntentData(toUninstall, intentsToUninstall);
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
return new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
}
/**
* Creates Intent operation context for install Intents.
*
* @return the context
*/
private IntentOperationContext createInstallContext() {
List<Intent> intentsToUninstall = Lists.newArrayList();
List<Intent> intentsToInstall = createFlowObjectiveIntents();
IntentData toUninstall = null;
IntentData toInstall = new IntentData(createP2PIntent(),
IntentState.INSTALLING,
new WallClockTimestamp());
toInstall = new IntentData(toInstall, intentsToInstall);
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
return new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
}
/**
* Creates flow objective Intents.
*
* @return the flow objective intents
*/
private List<Intent> createFlowObjectiveIntents() {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchInPort(CP1.port())
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(CP2.port())
.build();
FilteringObjective filt = DefaultFilteringObjective.builder()
.addCondition(selector.getCriterion(Criterion.Type.IN_PORT))
.withPriority(DEFAULT_PRIORITY)
.fromApp(APP_ID)
.permit()
.add();
NextObjective next = DefaultNextObjective.builder()
.withMeta(selector)
.addTreatment(treatment)
.makePermanent()
.withPriority(DEFAULT_PRIORITY)
.fromApp(APP_ID)
.withType(NextObjective.Type.SIMPLE)
.withId(NEXT_ID_1)
.add();
ForwardingObjective fwd = DefaultForwardingObjective.builder()
.withSelector(selector)
.fromApp(APP_ID)
.withPriority(DEFAULT_PRIORITY)
.makePermanent()
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.nextStep(NEXT_ID_1)
.add();
List<Objective> objectives = ImmutableList.of(filt, next, fwd);
List<DeviceId> deviceIds = ImmutableList.of(CP1.deviceId(), CP1.deviceId(), CP1.deviceId());
List<NetworkResource> resources = ImmutableList.of(CP1.deviceId());
Intent intent = new FlowObjectiveIntent(APP_ID, KEY1, deviceIds, objectives, resources, RG1);
return ImmutableList.of(intent);
}
/**
* Creates flow objective Intents with different selector.
*
* @return the flow objective Intents
*/
private List<Intent> createAnotherFlowObjectiveIntents() {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchVlanId(VlanId.vlanId("100"))
.matchInPort(CP1.port())
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(CP2.port())
.build();
FilteringObjective filt = DefaultFilteringObjective.builder()
.addCondition(selector.getCriterion(Criterion.Type.IN_PORT))
.addCondition(selector.getCriterion(Criterion.Type.VLAN_VID))
.withPriority(DEFAULT_PRIORITY)
.fromApp(APP_ID)
.permit()
.add();
NextObjective next = DefaultNextObjective.builder()
.withMeta(selector)
.addTreatment(treatment)
.makePermanent()
.withPriority(DEFAULT_PRIORITY)
.fromApp(APP_ID)
.withType(NextObjective.Type.SIMPLE)
.withId(NEXT_ID_1)
.add();
ForwardingObjective fwd = DefaultForwardingObjective.builder()
.withSelector(selector)
.fromApp(APP_ID)
.withPriority(DEFAULT_PRIORITY)
.makePermanent()
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.nextStep(NEXT_ID_1)
.add();
List<Objective> objectives = ImmutableList.of(filt, next, fwd);
List<DeviceId> deviceIds = ImmutableList.of(CP1.deviceId(), CP1.deviceId(), CP1.deviceId());
List<NetworkResource> resources = ImmutableList.of(CP1.deviceId());
Intent intent = new FlowObjectiveIntent(APP_ID, KEY1, deviceIds, objectives, resources, RG1);
return ImmutableList.of(intent);
}
/**
* Flow objective service for test; always successful for every flow objectives.
*/
class TestFlowObjectiveService extends FlowObjectiveServiceAdapter {
List<DeviceId> devices = Lists.newArrayList();
List<Objective> objectives = Lists.newArrayList();
@Override
public void apply(DeviceId deviceId, Objective objective) {
devices.add(deviceId);
objectives.add(objective);
objective.context().ifPresent(context -> context.onSuccess(objective));
}
}
/**
* Flow objective service for test; contains errors for every flow objective
* submission.
*/
class TestFailedFlowObjectiveService extends TestFlowObjectiveService {
private final Set<ObjectiveError> groupErrors =
ImmutableSet.of(GROUPEXISTS, GROUPINSTALLATIONFAILED,
GROUPMISSING, GROUPREMOVALFAILED);
/**
* Error states to test error handler by given error queue
* e.g.
* FLOWINSTALLATIONFAILED -> FLOWINSTALLATIONFAILED -> null: should be success
* FLOWINSTALLATIONFAILED -> five same error -> .... : should be failed
*/
List<ObjectiveError> errors;
public TestFailedFlowObjectiveService() {
errors = Lists.newArrayList();
errors.add(UNSUPPORTED);
}
public TestFailedFlowObjectiveService(List<ObjectiveError> errors) {
this.errors = Lists.newArrayList(errors);
}
@Override
public void apply(DeviceId deviceId, Objective objective) {
if (errors.size() != 0) {
if (groupErrors.contains(errors.get(0)) && objective instanceof NextObjective) {
ObjectiveError error = errors.remove(0);
objective.context().ifPresent(context -> context.onError(objective, error));
return;
}
if (!groupErrors.contains(errors.get(0)) && !(objective instanceof NextObjective)) {
ObjectiveError error = errors.remove(0);
objective.context().ifPresent(context -> context.onError(objective, error));
return;
}
}
objective.context().ifPresent(context -> context.onSuccess(objective));
}
}
}