/* * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.services.sal; import com.google.common.collect.Lists; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.ListenableFuture; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Future; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InOrder; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import org.opendaylight.openflowplugin.impl.services.batch.BatchPlanStep; import org.opendaylight.openflowplugin.impl.services.batch.BatchStepJob; import org.opendaylight.openflowplugin.impl.services.batch.BatchStepType; import org.opendaylight.openflowplugin.impl.util.FlatBatchUtil; import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchInputBuilder; 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.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.FlatBatchAddFlow; 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.FlatBatchFailureFlowIdCase; 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.yang.gen.v1.urn.opendaylight.flows.service.rev160314.AddFlowsBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.AddFlowsBatchOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.AddFlowsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.RemoveFlowsBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.RemoveFlowsBatchOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.RemoveFlowsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.SalFlowsBatchService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.UpdateFlowsBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.UpdateFlowsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.batch.flow.output.list.grouping.BatchFailedFlowsOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.SalGroupsBatchService; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.input.update.grouping.OriginalBatchedGroupBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.input.update.grouping.UpdatedBatchedGroupBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId; import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.AddMetersBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.AddMetersBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.RemoveMetersBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.RemoveMetersBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.SalMetersBatchService; import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.UpdateMetersBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.UpdateMetersBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.batch.meter.input.update.grouping.OriginalBatchedMeterBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.batch.meter.input.update.grouping.UpdatedBatchedMeterBuilder; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; /** * Test for {@link org.opendaylight.openflowplugin.impl.services.sal.SalFlatBatchServiceImpl}. */ @RunWith(MockitoJUnitRunner.class) public class SalFlatBatchServiceImplTest { private static final NodeId NODE_ID = new NodeId("ut-node-id"); private static final InstanceIdentifier<Node> NODE_II = InstanceIdentifier.create(Nodes.class) .child(Node.class, new NodeKey(NODE_ID)); private static final NodeRef NODE_REF = new NodeRef(NODE_II); @Mock private SalFlowsBatchService salFlowsBatchService; @Mock private SalGroupsBatchService salGroupsBatchService; @Mock private SalMetersBatchService salMetersBatchService; @Captor private ArgumentCaptor<AddFlowsBatchInput> addFlowsBatchInputCpt; private SalFlatBatchServiceImpl salFlatBatchService; @Before public void setUp() throws Exception { salFlatBatchService = new SalFlatBatchServiceImpl(salFlowsBatchService, salGroupsBatchService, salMetersBatchService); } @After public void tearDown() throws Exception { Mockito.verifyNoMoreInteractions(salFlowsBatchService, salGroupsBatchService, salMetersBatchService); } @Test public void testProcessFlatBatch_allSuccessFinished() throws Exception { Mockito.when(salFlowsBatchService.addFlowsBatch(Matchers.<AddFlowsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new AddFlowsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salFlowsBatchService.removeFlowsBatch(Matchers.<RemoveFlowsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new RemoveFlowsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salFlowsBatchService.updateFlowsBatch(Matchers.<UpdateFlowsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new UpdateFlowsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salGroupsBatchService.addGroupsBatch(Matchers.<AddGroupsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new AddGroupsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salGroupsBatchService.removeGroupsBatch(Matchers.<RemoveGroupsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new RemoveGroupsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salGroupsBatchService.updateGroupsBatch(Matchers.<UpdateGroupsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new UpdateGroupsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salMetersBatchService.addMetersBatch(Matchers.<AddMetersBatchInput>any())) .thenReturn(RpcResultBuilder.success(new AddMetersBatchOutputBuilder().build()).buildFuture()); Mockito.when(salMetersBatchService.removeMetersBatch(Matchers.<RemoveMetersBatchInput>any())) .thenReturn(RpcResultBuilder.success(new RemoveMetersBatchOutputBuilder().build()).buildFuture()); Mockito.when(salMetersBatchService.updateMetersBatch(Matchers.<UpdateMetersBatchInput>any())) .thenReturn(RpcResultBuilder.success(new UpdateMetersBatchOutputBuilder().build()).buildFuture()); ProcessFlatBatchInput batchInput = new ProcessFlatBatchInputBuilder() .setNode(NODE_REF) .setBatch(Lists.newArrayList( createFlowAddBatch(0, "f1"), createFlowRemoveBatch(1, "f2"), createFlowUpdateBatch(2, "f3"), createGroupAddBatch(3, 1L), createGroupRemoveBatch(4, 2L), createGroupUpdateBatch(5, 3L), createMeterAddBatch(3, 1L), createMeterRemoveBatch(4, 2L), createMeterUpdateBatch(5, 3L) )) .setExitOnFirstError(true) .build(); final Future<RpcResult<ProcessFlatBatchOutput>> rpcResultFuture = salFlatBatchService.processFlatBatch(batchInput); Assert.assertTrue(rpcResultFuture.isDone()); final RpcResult<ProcessFlatBatchOutput> rpcResult = rpcResultFuture.get(); Assert.assertTrue(rpcResult.isSuccessful()); Assert.assertTrue(rpcResult.getErrors().isEmpty()); Assert.assertTrue(rpcResult.getResult().getBatchFailure().isEmpty()); final InOrder inOrder = Mockito.inOrder(salFlowsBatchService, salGroupsBatchService, salMetersBatchService); inOrder.verify(salFlowsBatchService).addFlowsBatch(Matchers.<AddFlowsBatchInput>any()); inOrder.verify(salFlowsBatchService).removeFlowsBatch(Matchers.<RemoveFlowsBatchInput>any()); inOrder.verify(salFlowsBatchService).updateFlowsBatch(Matchers.<UpdateFlowsBatchInput>any()); inOrder.verify(salGroupsBatchService).addGroupsBatch(Matchers.<AddGroupsBatchInput>any()); inOrder.verify(salGroupsBatchService).removeGroupsBatch(Matchers.<RemoveGroupsBatchInput>any()); inOrder.verify(salGroupsBatchService).updateGroupsBatch(Matchers.<UpdateGroupsBatchInput>any()); inOrder.verify(salMetersBatchService).addMetersBatch(Matchers.<AddMetersBatchInput>any()); inOrder.verify(salMetersBatchService).removeMetersBatch(Matchers.<RemoveMetersBatchInput>any()); inOrder.verify(salMetersBatchService).updateMetersBatch(Matchers.<UpdateMetersBatchInput>any()); } @Test public void testProcessFlatBatch_firstFailedInterrupted() throws Exception { prepareFirstFailingMockService(); int idx = 0; ProcessFlatBatchInput batchInput = new ProcessFlatBatchInputBuilder() .setNode(NODE_REF) .setBatch(Lists.newArrayList( createFlowAddBatch(idx++, "f1", 2), createFlowRemoveBatch(idx++, "f2"), createFlowUpdateBatch(idx++, "f3"), createGroupAddBatch(idx++, 1L), createGroupRemoveBatch(idx++, 2L), createGroupUpdateBatch(idx++, 3L), createMeterAddBatch(idx++, 1L), createMeterRemoveBatch(idx++, 2L), createMeterUpdateBatch(idx++, 3L) )) .setExitOnFirstError(true) .build(); final Future<RpcResult<ProcessFlatBatchOutput>> rpcResultFuture = salFlatBatchService.processFlatBatch(batchInput); Assert.assertTrue(rpcResultFuture.isDone()); final RpcResult<ProcessFlatBatchOutput> rpcResult = rpcResultFuture.get(); Assert.assertFalse(rpcResult.isSuccessful()); Assert.assertEquals(1, rpcResult.getErrors().size()); Assert.assertEquals(1, rpcResult.getResult().getBatchFailure().size()); Assert.assertEquals(3, rpcResult.getResult().getBatchFailure().get(0).getBatchOrder().intValue()); final InOrder inOrder = Mockito.inOrder(salFlowsBatchService, salGroupsBatchService, salMetersBatchService); inOrder.verify(salFlowsBatchService).addFlowsBatch(Matchers.<AddFlowsBatchInput>any()); inOrder.verify(salFlowsBatchService).removeFlowsBatch(Matchers.<RemoveFlowsBatchInput>any()); inOrder.verify(salFlowsBatchService).updateFlowsBatch(Matchers.<UpdateFlowsBatchInput>any()); inOrder.verify(salGroupsBatchService).addGroupsBatch(Matchers.<AddGroupsBatchInput>any()); } @Test public void testProcessFlatBatch_firstFailedContinue() throws Exception { prepareFirstFailingMockService(); int idx = 0; ProcessFlatBatchInput batchInput = new ProcessFlatBatchInputBuilder() .setNode(NODE_REF) .setBatch(Lists.newArrayList( createFlowAddBatch(idx++, "f1", 2), createFlowRemoveBatch(idx++, "f2"), createFlowUpdateBatch(idx++, "f3"), createGroupAddBatch(idx++, 1L), createGroupRemoveBatch(idx++, 2L), createGroupUpdateBatch(idx++, 3L), createMeterAddBatch(idx++, 1L), createMeterRemoveBatch(idx++, 2L), createMeterUpdateBatch(idx++, 3L) )) .setExitOnFirstError(false) .build(); final Future<RpcResult<ProcessFlatBatchOutput>> rpcResultFuture = salFlatBatchService.processFlatBatch(batchInput); Assert.assertTrue(rpcResultFuture.isDone()); final RpcResult<ProcessFlatBatchOutput> rpcResult = rpcResultFuture.get(); Assert.assertFalse(rpcResult.isSuccessful()); Assert.assertEquals(1, rpcResult.getErrors().size()); Assert.assertEquals(1, rpcResult.getResult().getBatchFailure().size()); Assert.assertEquals(3, rpcResult.getResult().getBatchFailure().get(0).getBatchOrder().intValue()); final InOrder inOrder = Mockito.inOrder(salFlowsBatchService, salGroupsBatchService, salMetersBatchService); inOrder.verify(salFlowsBatchService).addFlowsBatch(Matchers.<AddFlowsBatchInput>any()); inOrder.verify(salFlowsBatchService).removeFlowsBatch(Matchers.<RemoveFlowsBatchInput>any()); inOrder.verify(salFlowsBatchService).updateFlowsBatch(Matchers.<UpdateFlowsBatchInput>any()); inOrder.verify(salGroupsBatchService).addGroupsBatch(Matchers.<AddGroupsBatchInput>any()); inOrder.verify(salGroupsBatchService).removeGroupsBatch(Matchers.<RemoveGroupsBatchInput>any()); inOrder.verify(salGroupsBatchService).updateGroupsBatch(Matchers.<UpdateGroupsBatchInput>any()); inOrder.verify(salMetersBatchService).addMetersBatch(Matchers.<AddMetersBatchInput>any()); inOrder.verify(salMetersBatchService).removeMetersBatch(Matchers.<RemoveMetersBatchInput>any()); inOrder.verify(salMetersBatchService).updateMetersBatch(Matchers.<UpdateMetersBatchInput>any()); } private void prepareFirstFailingMockService() { Mockito.when(salFlowsBatchService.addFlowsBatch(Matchers.<AddFlowsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new AddFlowsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salFlowsBatchService.removeFlowsBatch(Matchers.<RemoveFlowsBatchInput>any())) .thenReturn(RpcResultBuilder.<RemoveFlowsBatchOutput>failed() .withResult(new RemoveFlowsBatchOutputBuilder() .setBatchFailedFlowsOutput(Lists.newArrayList( new BatchFailedFlowsOutputBuilder() .setBatchOrder(1) .setFlowId(new FlowId("123")) .build())) .build()) .withError(RpcError.ErrorType.APPLICATION, "ut-firstFlowAddError") .buildFuture()); Mockito.when(salFlowsBatchService.updateFlowsBatch(Matchers.<UpdateFlowsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new UpdateFlowsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salGroupsBatchService.addGroupsBatch(Matchers.<AddGroupsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new AddGroupsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salGroupsBatchService.removeGroupsBatch(Matchers.<RemoveGroupsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new RemoveGroupsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salGroupsBatchService.updateGroupsBatch(Matchers.<UpdateGroupsBatchInput>any())) .thenReturn(RpcResultBuilder.success(new UpdateGroupsBatchOutputBuilder().build()).buildFuture()); Mockito.when(salMetersBatchService.addMetersBatch(Matchers.<AddMetersBatchInput>any())) .thenReturn(RpcResultBuilder.success(new AddMetersBatchOutputBuilder().build()).buildFuture()); Mockito.when(salMetersBatchService.removeMetersBatch(Matchers.<RemoveMetersBatchInput>any())) .thenReturn(RpcResultBuilder.success(new RemoveMetersBatchOutputBuilder().build()).buildFuture()); Mockito.when(salMetersBatchService.updateMetersBatch(Matchers.<UpdateMetersBatchInput>any())) .thenReturn(RpcResultBuilder.success(new UpdateMetersBatchOutputBuilder().build()).buildFuture()); } private Batch createFlowAddBatch(final int batchOrder, final String flowIdValue) { return createFlowAddBatch(batchOrder, flowIdValue, 1); } private Batch createFlowAddBatch(final int batchOrder, final String flowIdValue, int amount) { return new BatchBuilder() .setBatchOrder(batchOrder) .setBatchChoice(new FlatBatchAddFlowCaseBuilder() .setFlatBatchAddFlow(repeatInList(new FlatBatchAddFlowBuilder() .setFlowId(new FlowId(flowIdValue)) .build(), amount)) .build()) .build(); } private <T> List<T> repeatInList(final T item, final int amount) { final List<T> list = new ArrayList<>(); for (int i = 0; i < amount; i++) { list.add(item); } return list; } private Batch createFlowRemoveBatch(final int batchOrder, final String flowIdValue) { return new BatchBuilder() .setBatchOrder(batchOrder) .setBatchChoice(new FlatBatchRemoveFlowCaseBuilder() .setFlatBatchRemoveFlow(Collections.singletonList(new FlatBatchRemoveFlowBuilder() .setFlowId(new FlowId(flowIdValue)) .build())) .build()) .build(); } private Batch createFlowUpdateBatch(final int batchOrder, final String flowIdValue) { return new BatchBuilder() .setBatchOrder(batchOrder) .setBatchChoice(new FlatBatchUpdateFlowCaseBuilder() .setFlatBatchUpdateFlow(Collections.singletonList(new FlatBatchUpdateFlowBuilder() .setFlowId(new FlowId(flowIdValue)) .build())) .build()) .build(); } private Batch createGroupAddBatch(final int batchOrder, final long groupIdValue) { return new BatchBuilder() .setBatchOrder(batchOrder) .setBatchChoice(new FlatBatchAddGroupCaseBuilder() .setFlatBatchAddGroup(Collections.singletonList(new FlatBatchAddGroupBuilder() .setGroupId(new GroupId(groupIdValue)) .build())) .build()) .build(); } private Batch createGroupRemoveBatch(final int batchOrder, final long groupIdValue) { return new BatchBuilder() .setBatchOrder(batchOrder) .setBatchChoice(new FlatBatchRemoveGroupCaseBuilder() .setFlatBatchRemoveGroup(Collections.singletonList(new FlatBatchRemoveGroupBuilder() .setGroupId(new GroupId(groupIdValue)) .build())) .build()) .build(); } private Batch createGroupUpdateBatch(final int batchOrder, final long groupIdValue) { return new BatchBuilder() .setBatchOrder(batchOrder) .setBatchChoice(new FlatBatchUpdateGroupCaseBuilder() .setFlatBatchUpdateGroup(Collections.singletonList(new FlatBatchUpdateGroupBuilder() .setOriginalBatchedGroup(new OriginalBatchedGroupBuilder() .setGroupId(new GroupId(groupIdValue)) .build()) .setUpdatedBatchedGroup(new UpdatedBatchedGroupBuilder() .setGroupId(new GroupId(groupIdValue)) .build()) .build())) .build()) .build(); } private Batch createMeterAddBatch(final int batchOrder, final long groupIdValue) { return new BatchBuilder() .setBatchOrder(batchOrder) .setBatchChoice(new FlatBatchAddMeterCaseBuilder() .setFlatBatchAddMeter(Collections.singletonList(new FlatBatchAddMeterBuilder() .setMeterId(new MeterId(groupIdValue)) .build())) .build()) .build(); } private Batch createMeterRemoveBatch(final int batchOrder, final long groupIdValue) { return new BatchBuilder() .setBatchOrder(batchOrder) .setBatchChoice(new FlatBatchRemoveMeterCaseBuilder() .setFlatBatchRemoveMeter(Collections.singletonList(new FlatBatchRemoveMeterBuilder() .setMeterId(new MeterId(groupIdValue)) .build())) .build()) .build(); } private Batch createMeterUpdateBatch(final int batchOrder, final long groupIdValue) { return new BatchBuilder() .setBatchOrder(batchOrder) .setBatchChoice(new FlatBatchUpdateMeterCaseBuilder() .setFlatBatchUpdateMeter(Collections.singletonList(new FlatBatchUpdateMeterBuilder() .setOriginalBatchedMeter(new OriginalBatchedMeterBuilder() .setMeterId(new MeterId(groupIdValue)) .build()) .setUpdatedBatchedMeter(new UpdatedBatchedMeterBuilder() .setMeterId(new MeterId(groupIdValue)) .build()) .build())) .build()) .build(); } @Test public void testExecuteBatchPlan() throws Exception { BatchStepJob batchStepJob1 = Mockito.mock(BatchStepJob.class); BatchStepJob batchStepJob2 = Mockito.mock(BatchStepJob.class); AsyncFunction<RpcResult<ProcessFlatBatchOutput>, RpcResult<ProcessFlatBatchOutput>> function1 = Mockito.mock(AsyncFunction.class); AsyncFunction<RpcResult<ProcessFlatBatchOutput>, RpcResult<ProcessFlatBatchOutput>> function2 = Mockito.mock(AsyncFunction.class); Mockito.when(batchStepJob1.getStepFunction()).thenReturn(function1); Mockito.when(batchStepJob2.getStepFunction()).thenReturn(function2); BatchPlanStep batchPlanStep1 = new BatchPlanStep(BatchStepType.GROUP_ADD); batchPlanStep1.setBarrierAfter(true); BatchPlanStep batchPlanStep2 = new BatchPlanStep(BatchStepType.FLOW_ADD); batchPlanStep1.setBarrierAfter(false); Mockito.when(batchStepJob1.getPlanStep()).thenReturn(batchPlanStep1); Mockito.when(batchStepJob2.getPlanStep()).thenReturn(batchPlanStep2); final ListenableFuture<RpcResult<ProcessFlatBatchOutput>> succeededChainOutput = FlatBatchUtil.createEmptyRpcBatchResultFuture(true); final ListenableFuture<RpcResult<ProcessFlatBatchOutput>> failedChainOutput = RpcResultBuilder.<ProcessFlatBatchOutput>failed() .withError(RpcError.ErrorType.APPLICATION, "ut-chainError") .withResult(createFlatBatchOutput(createFlowBatchFailure(0, "f1"), createFlowBatchFailure(1, "f2"))) .buildFuture(); Mockito.when(batchStepJob1.getStepFunction().apply(Matchers.<RpcResult<ProcessFlatBatchOutput>>any())) .thenReturn(succeededChainOutput); Mockito.when(batchStepJob2.getStepFunction().apply(Matchers.<RpcResult<ProcessFlatBatchOutput>>any())) .thenReturn(failedChainOutput); final List<BatchStepJob> batchChainElements = Lists.newArrayList(batchStepJob1, batchStepJob2); final Future<RpcResult<ProcessFlatBatchOutput>> rpcResultFuture = salFlatBatchService.executeBatchPlan(batchChainElements); Assert.assertTrue(rpcResultFuture.isDone()); final RpcResult<ProcessFlatBatchOutput> rpcResult = rpcResultFuture.get(); Assert.assertFalse(rpcResult.isSuccessful()); Assert.assertEquals(1, rpcResult.getErrors().size()); Assert.assertEquals(2, rpcResult.getResult().getBatchFailure().size()); Assert.assertEquals("f2", ((FlatBatchFailureFlowIdCase) rpcResult.getResult().getBatchFailure().get(1).getBatchItemIdChoice()).getFlowId().getValue()); } private BatchFailure createFlowBatchFailure(final int batchOrder, final String flowIdValue) { return new BatchFailureBuilder() .setBatchOrder(batchOrder) .setBatchItemIdChoice(new FlatBatchFailureFlowIdCaseBuilder() .setFlowId(new FlowId(flowIdValue)) .build()) .build(); } private ProcessFlatBatchOutput createFlatBatchOutput(BatchFailure... batchFailures) { return new ProcessFlatBatchOutputBuilder() .setBatchFailure(Lists.newArrayList(batchFailures)) .build(); } @Test public void testPrepareBatchPlan_success() throws Exception { final FlatBatchAddFlow flatBatchAddFlow = new FlatBatchAddFlowBuilder() .setFlowId(new FlowId("f1")) .build(); final BatchPlanStep batchPlanStep = new BatchPlanStep(BatchStepType.FLOW_ADD); batchPlanStep.getTaskBag().addAll(Lists.newArrayList(flatBatchAddFlow, flatBatchAddFlow)); final List<BatchPlanStep> batchPlan = Lists.newArrayList(batchPlanStep); final List<BatchStepJob> batchChain = salFlatBatchService.prepareBatchChain(batchPlan, NODE_REF, true); Assert.assertEquals(1, batchChain.size()); Mockito.when(salFlowsBatchService.addFlowsBatch(Matchers.<AddFlowsBatchInput>any())) .thenReturn(RpcResultBuilder .success(new AddFlowsBatchOutputBuilder().build()) .buildFuture()); final Future<RpcResult<ProcessFlatBatchOutput>> rpcResultFuture = salFlatBatchService.executeBatchPlan(batchChain); Assert.assertTrue(rpcResultFuture.isDone()); final RpcResult<ProcessFlatBatchOutput> rpcResult = rpcResultFuture.get(); Assert.assertTrue(rpcResult.isSuccessful()); Assert.assertEquals(0, rpcResult.getErrors().size()); Assert.assertEquals(0, rpcResult.getResult().getBatchFailure().size()); Mockito.verify(salFlowsBatchService).addFlowsBatch(Matchers.<AddFlowsBatchInput>any()); } @Test public void testPrepareBatchPlan_failure() throws Exception { final FlatBatchAddFlow flatBatchAddFlow = new FlatBatchAddFlowBuilder() .setFlowId(new FlowId("f1")) .build(); final BatchPlanStep batchPlanStep = new BatchPlanStep(BatchStepType.FLOW_ADD); batchPlanStep.getTaskBag().addAll(Lists.newArrayList(flatBatchAddFlow, flatBatchAddFlow)); final List<BatchPlanStep> batchPlan = Lists.newArrayList(batchPlanStep, batchPlanStep); final List<BatchStepJob> batchChain = salFlatBatchService.prepareBatchChain(batchPlan, NODE_REF, true); Assert.assertEquals(2, batchChain.size()); Mockito.when(salFlowsBatchService.addFlowsBatch(Matchers.<AddFlowsBatchInput>any())) .thenReturn(RpcResultBuilder .<AddFlowsBatchOutput>failed() .withResult(new AddFlowsBatchOutputBuilder() .setBatchFailedFlowsOutput(Lists.newArrayList( new BatchFailedFlowsOutputBuilder() .setBatchOrder(0) .setFlowId(new FlowId("f1")) .build(), new BatchFailedFlowsOutputBuilder() .setBatchOrder(1) .setFlowId(new FlowId("f2")) .build())) .build()) .withError(RpcError.ErrorType.APPLICATION, "ut-addFlowBatchError") .buildFuture()); final Future<RpcResult<ProcessFlatBatchOutput>> rpcResultFuture = salFlatBatchService.executeBatchPlan(batchChain); Assert.assertTrue(rpcResultFuture.isDone()); final RpcResult<ProcessFlatBatchOutput> rpcResult = rpcResultFuture.get(); Assert.assertFalse(rpcResult.isSuccessful()); Assert.assertEquals(2, rpcResult.getErrors().size()); Assert.assertEquals(4, rpcResult.getResult().getBatchFailure().size()); Mockito.verify(salFlowsBatchService, Mockito.times(2)).addFlowsBatch(addFlowsBatchInputCpt.capture()); Assert.assertEquals(2, addFlowsBatchInputCpt.getValue().getBatchAddFlows().size()); } }