/*
* Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.openflowplugin.impl.util;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.opendaylight.openflowplugin.impl.services.batch.BatchPlanStep;
import org.opendaylight.openflowplugin.impl.services.batch.BatchStepType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchOutputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.Batch;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.BatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.BatchChoice;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchAddFlowCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchAddGroupCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchAddMeterCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchRemoveFlowCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchRemoveGroupCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchRemoveMeterCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchUpdateFlowCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchUpdateGroupCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchUpdateMeterCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.add.flow._case.FlatBatchAddFlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.add.group._case.FlatBatchAddGroupBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.add.meter._case.FlatBatchAddMeterBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.remove.flow._case.FlatBatchRemoveFlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.remove.group._case.FlatBatchRemoveGroupBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.remove.meter._case.FlatBatchRemoveMeterBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.update.flow._case.FlatBatchUpdateFlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.update.group._case.FlatBatchUpdateGroupBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.update.meter._case.FlatBatchUpdateMeterBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.output.BatchFailure;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.output.BatchFailureBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.output.batch.failure.batch.item.id.choice.FlatBatchFailureFlowIdCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Test for {@link FlatBatchUtil}.
*/
public class FlatBatchUtilTest {
private static final Logger LOG = LoggerFactory.getLogger(FlatBatchUtilTest.class);
@Test
public void testMarkBarriersWhereNeeded_noBarrier() throws Exception {
final List<Batch> batches = Lists.newArrayList(
//general part - no flush required
createBatch(BatchStepType.GROUP_REMOVE),
createBatch(BatchStepType.METER_REMOVE),
createBatch(BatchStepType.FLOW_ADD),
createBatch(BatchStepType.FLOW_REMOVE, 2),
createBatch(BatchStepType.FLOW_ADD),
createBatch(BatchStepType.FLOW_UPDATE),
createBatch(BatchStepType.GROUP_ADD),
createBatch(BatchStepType.GROUP_UPDATE),
createBatch(BatchStepType.METER_ADD),
createBatch(BatchStepType.METER_UPDATE)
);
final List<BatchPlanStep> batchPlan = FlatBatchUtil.assembleBatchPlan(batches);
FlatBatchUtil.markBarriersWhereNeeded(batchPlan);
Assert.assertEquals(10, batchPlan.size());
for (int i = 0; i < batchPlan.size(); i++) {
final BatchPlanStep planStep = batchPlan.get(i);
final boolean barrierBefore = planStep.isBarrierAfter();
LOG.debug("checking barrier mark @ {} {} -> {}",
i, planStep.getStepType(), barrierBefore);
Assert.assertFalse(barrierBefore);
}
}
@Test
public void testMarkBarriersWhereNeeded_allBarriers() throws Exception {
// need to flush G+/F+
checkBarriersBetween(BatchStepType.GROUP_ADD, BatchStepType.FLOW_ADD);
// need to flush G+/F*
checkBarriersBetween(BatchStepType.GROUP_ADD, BatchStepType.FLOW_UPDATE);
// need to flush F-/G-
checkBarriersBetween(BatchStepType.FLOW_REMOVE, BatchStepType.GROUP_REMOVE);
// need to flush F*/G-
checkBarriersBetween(BatchStepType.FLOW_UPDATE, BatchStepType.GROUP_REMOVE);
// need to flush G+/G+
checkBarriersBetween(BatchStepType.GROUP_ADD, BatchStepType.GROUP_ADD);
// need to flush G-/G-
checkBarriersBetween(BatchStepType.GROUP_REMOVE, BatchStepType.GROUP_REMOVE);
// need to flush G*/G+
checkBarriersBetween(BatchStepType.GROUP_UPDATE, BatchStepType.GROUP_ADD);
// need to flush G*/G-
checkBarriersBetween(BatchStepType.GROUP_UPDATE, BatchStepType.GROUP_REMOVE);
// need to flush M+/F+
checkBarriersBetween(BatchStepType.METER_ADD, BatchStepType.FLOW_ADD);
// need to flush M+/F*
checkBarriersBetween(BatchStepType.METER_ADD, BatchStepType.FLOW_UPDATE);
// need to flush F-/M-
checkBarriersBetween(BatchStepType.FLOW_REMOVE, BatchStepType.METER_REMOVE);
// need to flush F*/M-
checkBarriersBetween(BatchStepType.FLOW_UPDATE, BatchStepType.METER_REMOVE);
}
private void checkBarriersBetween(final BatchStepType typeOfFirst, final BatchStepType typeOfSecond) {
final List<Batch> batches = Lists.newArrayList(createBatch(typeOfFirst), createBatch(typeOfSecond));
final List<BatchPlanStep> batchPlan = FlatBatchUtil.assembleBatchPlan(batches);
FlatBatchUtil.markBarriersWhereNeeded(batchPlan);
LOG.debug("checking barrier between {} / {}", typeOfFirst, typeOfSecond);
Assert.assertEquals(2, batchPlan.size());
Assert.assertTrue("barrier expected between " + typeOfFirst + " / " + typeOfSecond, batchPlan.get(0).isBarrierAfter());
Assert.assertFalse(batchPlan.get(1).isBarrierAfter());
}
@Test
public void testMarkBarriersWhereNeeded_single() throws Exception {
final List<Batch> batches = Lists.newArrayList(
//general part - no flush required
createBatch(BatchStepType.GROUP_REMOVE)
);
final List<BatchPlanStep> batchPlan = FlatBatchUtil.assembleBatchPlan(batches);
FlatBatchUtil.markBarriersWhereNeeded(batchPlan);
Assert.assertEquals(1, batchPlan.size());
Assert.assertFalse(batchPlan.get(0).isBarrierAfter());
}
@Test
public void testDecideBarrier() throws Exception {
Assert.assertTrue(FlatBatchUtil.decideBarrier(EnumSet.of(BatchStepType.GROUP_ADD), BatchStepType.FLOW_ADD));
Assert.assertTrue(FlatBatchUtil.decideBarrier(EnumSet.of(BatchStepType.GROUP_ADD), BatchStepType.FLOW_UPDATE));
Assert.assertTrue(FlatBatchUtil.decideBarrier(EnumSet.of(BatchStepType.FLOW_REMOVE), BatchStepType.GROUP_REMOVE));
Assert.assertTrue(FlatBatchUtil.decideBarrier(EnumSet.of(BatchStepType.FLOW_UPDATE), BatchStepType.GROUP_REMOVE));
Assert.assertTrue(FlatBatchUtil.decideBarrier(EnumSet.of(BatchStepType.METER_ADD), BatchStepType.FLOW_ADD));
Assert.assertTrue(FlatBatchUtil.decideBarrier(EnumSet.of(BatchStepType.METER_ADD), BatchStepType.FLOW_UPDATE));
Assert.assertTrue(FlatBatchUtil.decideBarrier(EnumSet.of(BatchStepType.FLOW_REMOVE), BatchStepType.METER_REMOVE));
Assert.assertTrue(FlatBatchUtil.decideBarrier(EnumSet.of(BatchStepType.FLOW_UPDATE), BatchStepType.METER_REMOVE));
}
@Test
public void testAssembleBatchPlan() throws Exception {
final List<Batch> batches = Lists.newArrayList(
createBatch(BatchStepType.GROUP_ADD),
createBatch(BatchStepType.GROUP_REMOVE, 2),
createBatch(BatchStepType.GROUP_REMOVE),
createBatch(BatchStepType.GROUP_ADD),
createBatch(BatchStepType.GROUP_UPDATE, 3)
);
final List<BatchPlanStep> batchPlanSteps = FlatBatchUtil.assembleBatchPlan(batches);
Assert.assertEquals(5, batchPlanSteps.size());
int i = 0;
checkSegment(batchPlanSteps.get(i++), BatchStepType.GROUP_ADD, 1);
checkSegment(batchPlanSteps.get(i++), BatchStepType.GROUP_REMOVE, 2);
checkSegment(batchPlanSteps.get(i++), BatchStepType.GROUP_REMOVE, 1);
checkSegment(batchPlanSteps.get(i++), BatchStepType.GROUP_ADD, 1);
checkSegment(batchPlanSteps.get(i++), BatchStepType.GROUP_UPDATE, 3);
}
private void checkSegment(final BatchPlanStep planStep, final BatchStepType stepType, final int expected) {
Assert.assertEquals(stepType, planStep.getStepType());
Assert.assertEquals(expected, planStep.getTaskBag().size());
}
@Test
public void testDetectBatchStepType() throws Exception {
for (BatchStepType stepType : BatchStepType.values()) {
LOG.debug("checking detection of: {}", stepType);
final Batch batch = createBatch(stepType);
final BatchStepType actualType = FlatBatchUtil.detectBatchStepType(batch.getBatchChoice());
Assert.assertEquals(stepType, actualType);
}
}
private Batch createBatch(BatchStepType type) {
return createBatch(type, 1);
}
private Batch createBatch(BatchStepType type, final int size) {
final BatchChoice batchCase;
switch (type) {
case FLOW_ADD:
batchCase = new FlatBatchAddFlowCaseBuilder()
.setFlatBatchAddFlow(repeatIntoList(new FlatBatchAddFlowBuilder().build(), size))
.build();
break;
case FLOW_REMOVE:
batchCase = new FlatBatchRemoveFlowCaseBuilder()
.setFlatBatchRemoveFlow(repeatIntoList(new FlatBatchRemoveFlowBuilder().build(), size))
.build();
break;
case FLOW_UPDATE:
batchCase = new FlatBatchUpdateFlowCaseBuilder()
.setFlatBatchUpdateFlow(repeatIntoList(new FlatBatchUpdateFlowBuilder().build(), size))
.build();
break;
case GROUP_ADD:
batchCase = new FlatBatchAddGroupCaseBuilder()
.setFlatBatchAddGroup(repeatIntoList(new FlatBatchAddGroupBuilder().build(), size))
.build();
break;
case GROUP_REMOVE:
batchCase = new FlatBatchRemoveGroupCaseBuilder()
.setFlatBatchRemoveGroup(repeatIntoList(new FlatBatchRemoveGroupBuilder().build(), size))
.build();
break;
case GROUP_UPDATE:
batchCase = new FlatBatchUpdateGroupCaseBuilder()
.setFlatBatchUpdateGroup(repeatIntoList(new FlatBatchUpdateGroupBuilder().build(), size))
.build();
break;
case METER_ADD:
batchCase = new FlatBatchAddMeterCaseBuilder()
.setFlatBatchAddMeter(repeatIntoList(new FlatBatchAddMeterBuilder().build(), size))
.build();
break;
case METER_REMOVE:
batchCase = new FlatBatchRemoveMeterCaseBuilder()
.setFlatBatchRemoveMeter(repeatIntoList(new FlatBatchRemoveMeterBuilder().build(), size))
.build();
break;
case METER_UPDATE:
batchCase = new FlatBatchUpdateMeterCaseBuilder()
.setFlatBatchUpdateMeter(repeatIntoList(new FlatBatchUpdateMeterBuilder().build(), size))
.build();
break;
default:
LOG.warn("unsupported batch type: {}", type);
throw new IllegalArgumentException("unsupported batch type: " + type);
}
return new BatchBuilder()
.setBatchChoice(batchCase)
.build();
}
private <T> List<T> repeatIntoList(final T element, final int size) {
final List<T> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
list.add(element);
}
return list;
}
@Test
public void testMergeJobsResultsFutures() throws Exception {
final BatchFailure batchFailure = new BatchFailureBuilder()
.setBatchOrder(9)
.setBatchItemIdChoice(new FlatBatchFailureFlowIdCaseBuilder()
.setFlowId(new FlowId("11"))
.build())
.build();
final ProcessFlatBatchOutput output = new ProcessFlatBatchOutputBuilder().setBatchFailure(Lists.newArrayList(batchFailure)).build();
final RpcResult<ProcessFlatBatchOutput> rpcResultFailed = RpcResultBuilder.<ProcessFlatBatchOutput>failed()
.withError(RpcError.ErrorType.APPLICATION, "ut-rpcError")
.withResult(output).build();
final RpcResult<ProcessFlatBatchOutput> rpcResultSuccess = RpcResultBuilder.<ProcessFlatBatchOutput>success()
.withResult(new ProcessFlatBatchOutputBuilder().setBatchFailure(new ArrayList<>())).build();
final RpcResult<ProcessFlatBatchOutput> rpcResult1 = FlatBatchUtil.mergeRpcResults().apply(Lists.newArrayList(rpcResultFailed, rpcResultSuccess));
Assert.assertEquals(1, rpcResult1.getErrors().size());
Assert.assertFalse(rpcResult1.isSuccessful());
final RpcResult<ProcessFlatBatchOutput> rpcResult2 = FlatBatchUtil.mergeRpcResults().apply(Lists.newArrayList(rpcResultFailed, rpcResultFailed));
Assert.assertEquals(2, rpcResult2.getErrors().size());
Assert.assertFalse(rpcResult2.isSuccessful());
final RpcResult<ProcessFlatBatchOutput> rpcResult3 = FlatBatchUtil.mergeRpcResults().apply(Lists.newArrayList(rpcResultSuccess, rpcResultSuccess));
Assert.assertEquals(0, rpcResult3.getErrors().size());
Assert.assertTrue(rpcResult3.isSuccessful());
}
}