Bug 5575 introduced counters for sync strategies 29/38329/7
authorAndrej Leitner <anleitne@cisco.com>
Tue, 3 May 2016 12:31:25 +0000 (14:31 +0200)
committerAndrej Leitner <anleitne@cisco.com>
Tue, 24 May 2016 06:32:07 +0000 (08:32 +0200)
    - flat-batch & incremental
    - added more unit tests + fixed counters

Change-Id: I66d27d6d6615bdd66e9f0f2831bfb3ea51c5a691
Signed-off-by: Andrej Leitner <anleitne@cisco.com>
applications/forwardingrules-sync/src/main/java/org/opendaylight/openflowplugin/applications/frsync/impl/SimplifiedOperationalListener.java
applications/forwardingrules-sync/src/main/java/org/opendaylight/openflowplugin/applications/frsync/impl/strategy/SyncPlanPushStrategyFlatBatchImpl.java
applications/forwardingrules-sync/src/main/java/org/opendaylight/openflowplugin/applications/frsync/util/CrudCounts.java
applications/forwardingrules-sync/src/main/java/org/opendaylight/openflowplugin/applications/frsync/util/SyncCrudCounters.java
applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/DSInputFactory.java [new file with mode: 0644]
applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/SyncReactorImplTest.java
applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/strategy/DiffInputFactory.java [new file with mode: 0644]
applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/strategy/SyncPlanPushStrategyFlatBatchImplTest.java
applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/strategy/SyncPlanPushStrategyIncrementalImplTest.java

index 51f2a631c730e1b14b5736871ecaf2fc5c92f355..e66bf3f25f8f4c5106b6bc70c6099ddf4afc30a2 100644 (file)
@@ -64,7 +64,7 @@ public class SimplifiedOperationalListener extends AbstractFrmSyncListener<Node>
      * <li>Node is deleted from operational cache is removed.</li>
      * <li>Skip this event otherwise.</li>
      * </ul>
-     * 
+     *
      * @throws InterruptedException from syncup
      */
     protected Optional<ListenableFuture<Boolean>> processNodeModification(
@@ -74,13 +74,14 @@ public class SimplifiedOperationalListener extends AbstractFrmSyncListener<Node>
         if (isAdd(modification) || isAddLogical(modification)) {
             return reconciliation(modification);
         }
+        // TODO: else = explicit reconciliation required
 
         return skipModification(modification);
     }
 
     /**
      * Remove if delete. Update only if FlowCapableNode Augmentation modified.
-     * 
+     *
      * @param modification
      */
     protected void updateCache(DataTreeModification<Node> modification) {
@@ -90,7 +91,7 @@ public class SimplifiedOperationalListener extends AbstractFrmSyncListener<Node>
                 operationalSnaphot.updateCache(nodeId(modification), Optional.<FlowCapableNode>absent());
                 return;
             }
-            
+
             operationalSnaphot.updateCache(nodeId(modification), Optional.fromNullable(flowCapableNodeAfter(modification)));
         } catch(Exception e) {
             LOG.error("update cache failed {}", nodeId(modification), e);
index c42b31dcfbcfbc93560c513bed027c7baa51d461..48560a457581128ec451afe58805d2a9b93dea1a 100644 (file)
@@ -9,14 +9,20 @@
 package org.opendaylight.openflowplugin.applications.frsync.impl.strategy;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.PeekingIterator;
+import com.google.common.collect.Range;
 import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.JdkFutureAdapters;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Future;
+import javax.annotation.Nullable;
 import org.opendaylight.openflowplugin.applications.frsync.SyncPlanPushStrategy;
 import org.opendaylight.openflowplugin.applications.frsync.impl.TableForwarder;
 import org.opendaylight.openflowplugin.applications.frsync.util.FxChainUtil;
@@ -30,14 +36,24 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev16032
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.SalFlatBatchService;
 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.FlatBatchAddFlowCase;
 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.FlatBatchAddGroupCase;
 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.FlatBatchAddMeterCase;
 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.FlatBatchRemoveFlowCase;
 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.FlatBatchRemoveGroupCase;
 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.FlatBatchRemoveMeterCase;
 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.FlatBatchUpdateFlowCase;
 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.FlatBatchUpdateGroupCase;
 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.FlatBatchUpdateMeterCase;
 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;
@@ -57,6 +73,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev16032
 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.FlatBatchUpdateMeter;
 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.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
@@ -92,6 +109,19 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
         final InstanceIdentifier<FlowCapableNode> nodeIdent = diffInput.getNodeIdent();
         final NodeId nodeId = PathUtil.digNodeId(nodeIdent);
 
+        // prepare default (full) counts
+        counters.getGroupCrudCounts().setAdded(ReconcileUtil.countTotalPushed(diffInput.getGroupsToAddOrUpdate()));
+        counters.getGroupCrudCounts().setUpdated(ReconcileUtil.countTotalUpdated(diffInput.getGroupsToAddOrUpdate()));
+        counters.getGroupCrudCounts().setRemoved(ReconcileUtil.countTotalPushed(diffInput.getGroupsToRemove()));
+
+        counters.getFlowCrudCounts().setAdded(ReconcileUtil.countTotalPushed(diffInput.getFlowsToAddOrUpdate().values()));
+        counters.getFlowCrudCounts().setUpdated(ReconcileUtil.countTotalUpdated(diffInput.getFlowsToAddOrUpdate().values()));
+        counters.getFlowCrudCounts().setRemoved(ReconcileUtil.countTotalPushed(diffInput.getFlowsToRemove().values()));
+
+        counters.getMeterCrudCounts().setAdded(diffInput.getMetersToAddOrUpdate().getItemsToPush().size());
+        counters.getMeterCrudCounts().setUpdated(diffInput.getMetersToAddOrUpdate().getItemsToUpdate().size());
+        counters.getMeterCrudCounts().setRemoved(diffInput.getMetersToRemove().getItemsToPush().size());
+
         /* Tables - have to be pushed before groups */
         // TODO enable table-update when ready
         //resultVehicle = updateTableFeatures(nodeIdent, configTree);
@@ -127,6 +157,13 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
 
                 final Future<RpcResult<ProcessFlatBatchOutput>> rpcResultFuture = flatBatchService.processFlatBatch(flatBatchInput);
 
+                final int failureIndexLimit = batchOrder;
+
+                if (LOG.isDebugEnabled()) {
+                    Futures.addCallback(JdkFutureAdapters.listenInPoolThread(rpcResultFuture),
+                            createCounterCallback(batchBag, failureIndexLimit, counters));
+                }
+
                 return Futures.transform(JdkFutureAdapters.listenInPoolThread(rpcResultFuture),
                         ReconcileUtil.<ProcessFlatBatchOutput>createRpcResultToVoidFunction("flat-batch"));
             }
@@ -136,6 +173,76 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
         return resultVehicle;
     }
 
+    private FutureCallback<RpcResult<ProcessFlatBatchOutput>> createCounterCallback(final List<Batch> inputBatchBag,
+                                                                                    final int failureIndexLimit,
+                                                                                    final SyncCrudCounters counters) {
+        return new FutureCallback<RpcResult<ProcessFlatBatchOutput>>() {
+            @Override
+            public void onSuccess(@Nullable final RpcResult<ProcessFlatBatchOutput> result) {
+                if (!result.isSuccessful() && result.getResult() != null && !result.getResult().getBatchFailure().isEmpty()) {
+                    Map<Range<Integer>, Batch> batchMap = mapBachesToRanges(inputBatchBag, failureIndexLimit);
+
+                    for (BatchFailure batchFailure : result.getResult().getBatchFailure()) {
+                        for (Map.Entry<Range<Integer>, Batch> rangeBatchEntry : batchMap.entrySet()) {
+                            if (rangeBatchEntry.getKey().contains(batchFailure.getBatchOrder())) {
+                                // get type and decrease
+                                final BatchChoice batchChoice = rangeBatchEntry.getValue().getBatchChoice();
+                                decrementCounters(batchChoice, counters);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
+            @Override
+            public void onFailure(final Throwable t) {
+                counters.resetAll();
+            }
+        };
+    }
+
+    static void decrementCounters(final BatchChoice batchChoice, final SyncCrudCounters counters) {
+        if (batchChoice instanceof FlatBatchAddFlowCase) {
+            counters.getFlowCrudCounts().decAdded();
+        } else if (batchChoice instanceof FlatBatchUpdateFlowCase) {
+            counters.getFlowCrudCounts().decUpdated();
+        } else if (batchChoice instanceof FlatBatchRemoveFlowCase) {
+            counters.getFlowCrudCounts().decRemoved();
+        } else if (batchChoice instanceof FlatBatchAddGroupCase) {
+            counters.getGroupCrudCounts().decAdded();
+        } else if (batchChoice instanceof FlatBatchUpdateGroupCase) {
+            counters.getGroupCrudCounts().decUpdated();
+        } else if (batchChoice instanceof FlatBatchRemoveGroupCase) {
+            counters.getGroupCrudCounts().decRemoved();
+        } else if (batchChoice instanceof FlatBatchAddMeterCase) {
+            counters.getMeterCrudCounts().decAdded();
+        } else if (batchChoice instanceof FlatBatchUpdateMeterCase) {
+            counters.getMeterCrudCounts().decUpdated();
+        } else if (batchChoice instanceof FlatBatchRemoveMeterCase) {
+            counters.getMeterCrudCounts().decRemoved();
+        }
+    }
+
+    static Map<Range<Integer>, Batch> mapBachesToRanges(final List<Batch> inputBatchBag, final int failureIndexLimit) {
+        final Map<Range<Integer>, Batch> batchMap = new LinkedHashMap<>();
+        final PeekingIterator<Batch> batchPeekingIterator = Iterators.peekingIterator(inputBatchBag.iterator());
+        while (batchPeekingIterator.hasNext()) {
+            final Batch batch = batchPeekingIterator.next();
+            final int nextBatchOrder = batchPeekingIterator.hasNext()
+                    ? batchPeekingIterator.peek().getBatchOrder()
+                    : failureIndexLimit;
+            batchMap.put(Range.closed(batch.getBatchOrder(), nextBatchOrder - 1), batch);
+        }
+        return batchMap;
+    }
+
+    private int getNextBatchLimit(final PeekingIterator<Batch> inputBatchIterator, final int failureIndexLimit) {
+        return inputBatchIterator.hasNext()
+                ? inputBatchIterator.peek().getBatchOrder()
+                : failureIndexLimit;
+    }
+
     @VisibleForTesting
     static int assembleRemoveFlows(final List<Batch> batchBag, int batchOrder, final Map<TableKey, ItemSyncBox<Flow>> flowItemSyncTableMap) {
         // process flow remove
@@ -158,8 +265,9 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
                             .setBatchChoice(new FlatBatchRemoveFlowCaseBuilder()
                                     .setFlatBatchRemoveFlow(flatBatchRemoveFlowBag)
                                     .build())
-                            .setBatchOrder(batchOrder++)
+                            .setBatchOrder(batchOrder)
                             .build();
+                    batchOrder += itemOrder;
                     batchBag.add(batch);
                 }
             }
@@ -183,8 +291,9 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
                             .setBatchChoice(new FlatBatchAddGroupCaseBuilder()
                                     .setFlatBatchAddGroup(flatBatchAddGroupBag)
                                     .build())
-                            .setBatchOrder(batchOrder++)
+                            .setBatchOrder(batchOrder)
                             .build();
+                    batchOrder += itemOrder;
                     batchBag.add(batch);
                 }
 
@@ -203,8 +312,9 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
                             .setBatchChoice(new FlatBatchUpdateGroupCaseBuilder()
                                     .setFlatBatchUpdateGroup(flatBatchUpdateGroupBag)
                                     .build())
-                            .setBatchOrder(batchOrder++)
+                            .setBatchOrder(batchOrder)
                             .build();
+                    batchOrder += itemOrder;
                     batchBag.add(batch);
                 }
             }
@@ -228,28 +338,9 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
                             .setBatchChoice(new FlatBatchRemoveGroupCaseBuilder()
                                     .setFlatBatchRemoveGroup(flatBatchRemoveGroupBag)
                                     .build())
-                            .setBatchOrder(batchOrder++)
-                            .build();
-                    batchBag.add(batch);
-                }
-
-                if (!groupItemSyncBox.getItemsToUpdate().isEmpty()) {
-                    final List<FlatBatchUpdateGroup> flatBatchUpdateGroupBag =
-                            new ArrayList<>(groupItemSyncBox.getItemsToUpdate().size());
-                    int itemOrder = 0;
-                    for (ItemSyncBox.ItemUpdateTuple<Group> groupUpdate : groupItemSyncBox.getItemsToUpdate()) {
-                        flatBatchUpdateGroupBag.add(new FlatBatchUpdateGroupBuilder()
-                                .setBatchOrder(itemOrder++)
-                                .setOriginalBatchedGroup(new OriginalBatchedGroupBuilder(groupUpdate.getOriginal()).build())
-                                .setUpdatedBatchedGroup(new UpdatedBatchedGroupBuilder(groupUpdate.getUpdated()).build())
-                                .build());
-                    }
-                    final Batch batch = new BatchBuilder()
-                            .setBatchChoice(new FlatBatchUpdateGroupCaseBuilder()
-                                    .setFlatBatchUpdateGroup(flatBatchUpdateGroupBag)
-                                    .build())
-                            .setBatchOrder(batchOrder++)
+                            .setBatchOrder(batchOrder)
                             .build();
+                    batchOrder += itemOrder;
                     batchBag.add(batch);
                 }
             }
@@ -272,8 +363,9 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
                         .setBatchChoice(new FlatBatchAddMeterCaseBuilder()
                                 .setFlatBatchAddMeter(flatBatchAddMeterBag)
                                 .build())
-                        .setBatchOrder(batchOrder++)
+                        .setBatchOrder(batchOrder)
                         .build();
+                batchOrder += itemOrder;
                 batchBag.add(batch);
             }
 
@@ -292,8 +384,9 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
                         .setBatchChoice(new FlatBatchUpdateMeterCaseBuilder()
                                 .setFlatBatchUpdateMeter(flatBatchUpdateMeterBag)
                                 .build())
-                        .setBatchOrder(batchOrder++)
+                        .setBatchOrder(batchOrder)
                         .build();
+                batchOrder += itemOrder;
                 batchBag.add(batch);
             }
         }
@@ -315,8 +408,9 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
                         .setBatchChoice(new FlatBatchRemoveMeterCaseBuilder()
                                 .setFlatBatchRemoveMeter(flatBatchRemoveMeterBag)
                                 .build())
-                        .setBatchOrder(batchOrder++)
+                        .setBatchOrder(batchOrder)
                         .build();
+                batchOrder += itemOrder;
                 batchBag.add(batch);
             }
         }
@@ -345,8 +439,9 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
                             .setBatchChoice(new FlatBatchAddFlowCaseBuilder()
                                     .setFlatBatchAddFlow(flatBatchAddFlowBag)
                                     .build())
-                            .setBatchOrder(batchOrder++)
+                            .setBatchOrder(batchOrder)
                             .build();
+                    batchOrder += itemOrder;
                     batchBag.add(batch);
                 }
 
@@ -366,8 +461,9 @@ public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
                             .setBatchChoice(new FlatBatchUpdateFlowCaseBuilder()
                                     .setFlatBatchUpdateFlow(flatBatchUpdateFlowBag)
                                     .build())
-                            .setBatchOrder(batchOrder++)
+                            .setBatchOrder(batchOrder)
                             .build();
+                    batchOrder += itemOrder;
                     batchBag.add(batch);
                 }
             }
index a6fdd2dd0115ab38773070694bfa86bcbe4877d2..23a7be8949985b78be608dce8c3a958fea1ed8bc 100644 (file)
@@ -50,4 +50,16 @@ public class CrudCounts {
     public void incRemoved() {
         removed++;
     }
+
+    public void decAdded() {
+        added--;
+    }
+
+    public void decUpdated() {
+        updated--;
+    }
+
+    public void decRemoved() {
+        removed--;
+    }
 }
index 5e3cfe3bb1a7db43176506113397332a7612e050..487f0650828d1e0d7b9434ca1a36f3092fb65c13 100644 (file)
@@ -43,4 +43,18 @@ public class SyncCrudCounters {
     public void setStartNano(final long startNano) {
         this.startNano = startNano;
     }
+
+    public void resetAll() {
+        getGroupCrudCounts().setUpdated(0);
+        getGroupCrudCounts().setAdded(0);
+        getGroupCrudCounts().setRemoved(0);
+
+        getFlowCrudCounts().setUpdated(0);
+        getFlowCrudCounts().setAdded(0);
+        getFlowCrudCounts().setRemoved(0);
+
+        getMeterCrudCounts().setUpdated(0);
+        getMeterCrudCounts().setAdded(0);
+        getMeterCrudCounts().setRemoved(0);
+    }
 }
diff --git a/applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/DSInputFactory.java b/applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/DSInputFactory.java
new file mode 100644 (file)
index 0000000..f41f7d5
--- /dev/null
@@ -0,0 +1,159 @@
+/**
+ * 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.applications.frsync.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.BandId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DropBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.MeterBandHeadersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.MeterBandHeaderBuilder;
+
+/**
+ * Provides create methods for dataObjects involved in
+ * {@link org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener} by inventory.
+ */
+public class DSInputFactory {
+    public static Group createGroup(final long groupIdValue) {
+        final Buckets buckets = new BucketsBuilder()
+                .setBucket(Collections.<Bucket>emptyList())
+                .build();
+        return new GroupBuilder()
+                .setGroupId(new GroupId(groupIdValue))
+                .setBuckets(buckets)
+                .build();
+    }
+
+    public static Group createGroupWithAction(final long groupIdValue) {
+        final Buckets buckets = new BucketsBuilder()
+                .setBucket(Collections.singletonList(new BucketBuilder()
+                        .setAction(Collections.singletonList(new ActionBuilder()
+                                .setAction(new OutputActionCaseBuilder()
+                                        .setOutputAction(new OutputActionBuilder()
+                                                .setOutputNodeConnector(new Uri("ut-port-1"))
+                                                .build())
+                                        .build())
+                                .build()))
+                        .build()))
+                .build();
+        return new GroupBuilder()
+                .setGroupId(new GroupId(groupIdValue))
+                .setBuckets(buckets)
+                .build();
+    }
+
+    public static Flow createFlow(final String flowIdValue, final int priority) {
+        return new FlowBuilder()
+                .setId(new FlowId(flowIdValue))
+                .setPriority(priority)
+                .setTableId((short) 42)
+                .setMatch(new MatchBuilder().build())
+                .build();
+    }
+
+    public static Flow createFlowWithInstruction(final String flowIdValue, final int priority) {
+        return new FlowBuilder()
+                .setId(new FlowId(flowIdValue))
+                .setPriority(priority)
+                .setTableId((short) 42)
+                .setMatch(new MatchBuilder().build())
+                .setInstructions(new InstructionsBuilder()
+                        .setInstruction(Collections.singletonList(new InstructionBuilder()
+                                .setInstruction(new ApplyActionsCaseBuilder()
+                                        .setApplyActions(new ApplyActionsBuilder()
+                                                .setAction(Collections.singletonList(new ActionBuilder()
+                                                        .setAction(new OutputActionCaseBuilder()
+                                                                .setOutputAction(new OutputActionBuilder()
+                                                                        .setOutputNodeConnector(new Uri("ut-port-1"))
+                                                                        .build())
+                                                                .build())
+                                                        .build()))
+                                                .build())
+                                        .build())
+                                .build()))
+                        .build())
+                .build();
+    }
+
+    public static Meter createMeter(final Long meterIdValue) {
+        return new MeterBuilder()
+                .setMeterId(new MeterId(meterIdValue))
+                .build();
+    }
+
+    public static Meter createMeterWithBody(final Long meterIdValue) {
+        return new MeterBuilder()
+                .setMeterId(new MeterId(meterIdValue))
+                .setMeterBandHeaders(new MeterBandHeadersBuilder()
+                        .setMeterBandHeader(Collections.singletonList(new MeterBandHeaderBuilder()
+                                .setBandId(new BandId(42L))
+                                .setBandType(new DropBuilder()
+                                        .setDropRate(43L)
+                                        .build())
+                                .build()))
+                        .build())
+                .build();
+    }
+
+    public static Group createGroupWithPreconditions(final long groupIdValue, final long... requiredId) {
+        final List<Action> actionBag = new ArrayList<>();
+        for (long groupIdPrecondition : requiredId) {
+            final GroupAction groupAction = new GroupActionBuilder()
+                    .setGroupId(groupIdPrecondition)
+                    .build();
+            final GroupActionCase groupActionCase = new GroupActionCaseBuilder()
+                    .setGroupAction(groupAction)
+                    .build();
+            final Action action = new ActionBuilder()
+                    .setAction(groupActionCase)
+                    .build();
+            actionBag.add(action);
+        }
+
+        final Bucket bucket = new BucketBuilder()
+                .setAction(actionBag)
+                .build();
+        final Buckets buckets = new BucketsBuilder()
+                .setBucket(Collections.singletonList(bucket))
+                .build();
+
+        return new GroupBuilder()
+                .setGroupId(new GroupId(groupIdValue))
+                .setBuckets(buckets)
+                .build();
+    }
+}
index 0567cdc5122dabd77b88ed9507bcdb5a22860ed9..17f470bb2e363dda02a3760b691ea148f365be78 100644 (file)
@@ -8,17 +8,28 @@
 
 package org.opendaylight.openflowplugin.applications.frsync.impl;
 
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+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.Matchers;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.openflowplugin.applications.frsync.SyncPlanPushStrategy;
+import org.opendaylight.openflowplugin.applications.frsync.impl.strategy.SynchronizationDiffInput;
+import org.opendaylight.openflowplugin.applications.frsync.util.ReconcileUtil;
+import org.opendaylight.openflowplugin.applications.frsync.util.SyncCrudCounters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
@@ -27,6 +38,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,6 +75,8 @@ public class SyncReactorImplTest {
     private ArgumentCaptor<Meter> meterUpdateCaptor;
     @Captor
     private ArgumentCaptor<TableFeatures> tableFeaturesCaptor;
+    @Captor
+    private ArgumentCaptor<SynchronizationDiffInput> syncDiffInputCaptor;
 
     @Before
     public void setUp() throws Exception {
@@ -70,6 +85,55 @@ public class SyncReactorImplTest {
 
     @Test
     public void testSyncup() throws Exception {
-        // TODO: add test body as soon as strategies are settled
+        final FlowCapableNode configFcn = new FlowCapableNodeBuilder()
+                .setGroup(Collections.singletonList(DSInputFactory.createGroup(1L)))
+                .setTable(Collections.singletonList(new TableBuilder()
+                        .setFlow(Collections.singletonList(DSInputFactory.createFlow("f1", 1)))
+                        .build()))
+                .setMeter(Collections.singletonList(DSInputFactory.createMeter(1L)))
+                .build();
+
+        final FlowCapableNode operationalFcn = new FlowCapableNodeBuilder()
+                .setGroup(Collections.singletonList(DSInputFactory.createGroup(2L)))
+                .setTable(Collections.singletonList(new TableBuilder()
+                        .setFlow(Collections.singletonList(DSInputFactory.createFlow("f2", 2)))
+                        .build()))
+                .setMeter(Collections.singletonList(DSInputFactory.createMeter(2L)))
+                .build();
+
+        Mockito.when(syncPlanPushStrategy.executeSyncStrategy(
+                Matchers.<ListenableFuture<RpcResult<Void>>>any(),
+                Matchers.<SynchronizationDiffInput>any(),
+                Matchers.<SyncCrudCounters>any()))
+                .thenReturn(RpcResultBuilder.<Void>success().buildFuture());
+
+        final ListenableFuture<Boolean> syncupResult = reactor.syncup(NODE_IDENT, configFcn, operationalFcn);
+        try {
+            Assert.assertTrue(syncupResult.isDone());
+            final Boolean voidRpcResult = syncupResult.get(2, TimeUnit.SECONDS);
+            Assert.assertTrue(voidRpcResult);
+
+            Mockito.verify(syncPlanPushStrategy).executeSyncStrategy(
+                    Matchers.<ListenableFuture<RpcResult<Void>>>any(),
+                    syncDiffInputCaptor.capture(),
+                    Matchers.<SyncCrudCounters>any()
+            );
+
+            final SynchronizationDiffInput diffInput = syncDiffInputCaptor.getValue();
+            Assert.assertEquals(1, ReconcileUtil.countTotalPushed(diffInput.getFlowsToAddOrUpdate().values()));
+            Assert.assertEquals(0, ReconcileUtil.countTotalUpdated(diffInput.getFlowsToAddOrUpdate().values()));
+            Assert.assertEquals(1, ReconcileUtil.countTotalPushed(diffInput.getFlowsToRemove().values()));
+
+            Assert.assertEquals(1, ReconcileUtil.countTotalPushed(diffInput.getGroupsToAddOrUpdate()));
+            Assert.assertEquals(0, ReconcileUtil.countTotalUpdated(diffInput.getGroupsToAddOrUpdate()));
+            Assert.assertEquals(1, ReconcileUtil.countTotalPushed(diffInput.getGroupsToRemove()));
+
+            Assert.assertEquals(1, diffInput.getMetersToAddOrUpdate().getItemsToPush().size());
+            Assert.assertEquals(0, diffInput.getMetersToAddOrUpdate().getItemsToUpdate().size());
+            Assert.assertEquals(1, diffInput.getMetersToRemove().getItemsToPush().size());
+        } catch (Exception e) {
+            LOG.warn("syncup failed", e);
+            Assert.fail("syncup failed: " + e.getMessage());
+        }
     }
 }
\ No newline at end of file
diff --git a/applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/strategy/DiffInputFactory.java b/applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/strategy/DiffInputFactory.java
new file mode 100644 (file)
index 0000000..a30d600
--- /dev/null
@@ -0,0 +1,97 @@
+/**
+ * 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.applications.frsync.impl.strategy;
+
+import org.opendaylight.openflowplugin.applications.frsync.util.ItemSyncBox;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
+
+/**
+ * Provides create methods for data involved in {@link SynchronizationDiffInput}.
+ */
+public class DiffInputFactory {
+    static ItemSyncBox<Group> createGroupSyncBox(final long... groupIDs) {
+        final ItemSyncBox<Group> groupBox = new ItemSyncBox<>();
+
+        for (long gid : groupIDs) {
+            groupBox.getItemsToPush().add(createPlainGroup(gid));
+        }
+        return groupBox;
+    }
+
+    static ItemSyncBox<Group> createGroupSyncBoxWithUpdates(final long... groupIDs) {
+        final ItemSyncBox<Group> groupBox = new ItemSyncBox<>();
+
+        for (long gid : groupIDs) {
+            groupBox.getItemsToPush().add(createPlainGroup(gid));
+            groupBox.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(createPlainGroup(gid + 50),
+                    createPlainGroup(gid + 100)));
+        }
+        return groupBox;
+    }
+
+    static Group createPlainGroup(final long gid) {
+        return new GroupBuilder().setGroupId(new GroupId(gid)).build();
+    }
+
+    static ItemSyncBox<Meter> createMeterSyncBox(final long... meterIDs) {
+        final ItemSyncBox<Meter> groupBox = new ItemSyncBox<>();
+
+        for (long gid : meterIDs) {
+            groupBox.getItemsToPush().add(createPlainMeter(gid));
+        }
+        return groupBox;
+    }
+
+    static ItemSyncBox<Meter> createMeterSyncBoxWithUpdates(final long... meterIDs) {
+        final ItemSyncBox<Meter> groupBox = new ItemSyncBox<>();
+
+        for (long mid : meterIDs) {
+            groupBox.getItemsToPush().add(createPlainMeter(mid));
+            groupBox.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(createPlainMeter(mid + 50),
+                    createPlainMeter(mid + 100)));
+        }
+        return groupBox;
+    }
+
+    static Meter createPlainMeter(final long mid) {
+        return new MeterBuilder().setMeterId(new MeterId(mid)).build();
+    }
+
+    static ItemSyncBox<Flow> createFlowSyncBox(final String... flowIDs) {
+        final ItemSyncBox<Flow> flowBox = new ItemSyncBox<>();
+
+        for (String fid : flowIDs) {
+            flowBox.getItemsToPush().add(createPlainFlow(fid));
+        }
+        return flowBox;
+    }
+
+    static ItemSyncBox<Flow> createFlowSyncBoxWithUpdates(final String... flowIDs) {
+        final ItemSyncBox<Flow> groupBox = new ItemSyncBox<>();
+
+        for (String fid : flowIDs) {
+            groupBox.getItemsToPush().add(createPlainFlow(fid));
+            groupBox.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(createPlainFlow(fid + "orig"),
+                    createPlainFlow(fid + "upd")));
+        }
+        return groupBox;
+    }
+
+    static Flow createPlainFlow(final String fid) {
+        return new FlowBuilder().setId(new FlowId(fid)).build();
+    }
+}
index 337a5ee8c1a23572c0b60f781a84a56dae1c1d7d..e83d9b036212141eb0c0753d29b10f42440d4d5e 100644 (file)
@@ -9,6 +9,8 @@
 package org.opendaylight.openflowplugin.applications.frsync.impl.strategy;
 
 import com.google.common.collect.Lists;
+import com.google.common.collect.Range;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -17,36 +19,50 @@ 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.Matchers;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.openflowplugin.applications.frsync.impl.TableForwarder;
 import org.opendaylight.openflowplugin.applications.frsync.util.ItemSyncBox;
+import org.opendaylight.openflowplugin.applications.frsync.util.SyncCrudCounters;
+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.ProcessFlatBatchOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.SalFlatBatchService;
 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.FlatBatchAddFlowCase;
+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.FlatBatchAddGroupCase;
+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.FlatBatchAddMeterCase;
+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.FlatBatchRemoveFlowCase;
+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.FlatBatchRemoveGroupCase;
+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.FlatBatchRemoveMeterCase;
+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.FlatBatchUpdateFlowCase;
+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.FlatBatchUpdateGroupCase;
+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.FlatBatchUpdateMeterCase;
+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.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 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.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 
 /**
  * Test for {@link SyncPlanPushStrategyFlatBatchImpl}.
@@ -61,7 +77,9 @@ public class SyncPlanPushStrategyFlatBatchImplTest {
     @Mock
     private SalFlatBatchService flatBatchService;
     @Mock
-    private SalFlatBatchService tableUpdateService;
+    private TableForwarder tableForwarder;
+    @Captor
+    private ArgumentCaptor<ProcessFlatBatchInput> processFlatBatchInputCpt;
 
     private List<ItemSyncBox<Group>> groupsToAddOrUpdate;
     private List<ItemSyncBox<Group>> groupsToRemove;
@@ -74,90 +92,20 @@ public class SyncPlanPushStrategyFlatBatchImplTest {
     private SyncPlanPushStrategyFlatBatchImpl syncPlanPushStrategy;
 
     public SyncPlanPushStrategyFlatBatchImplTest() {
-        groupsToAddOrUpdate = Lists.newArrayList(createGroupSyncBox(1, 2, 3), createGroupSyncBoxWithUpdates(4, 5, 6));
-        groupsToRemove = Lists.newArrayList(createGroupSyncBox(1, 2, 3), createGroupSyncBox(4, 5, 6));
+        groupsToAddOrUpdate = Lists.newArrayList(DiffInputFactory.createGroupSyncBox(1, 2, 3),
+                DiffInputFactory.createGroupSyncBoxWithUpdates(4, 5, 6));
+        groupsToRemove = Lists.newArrayList(DiffInputFactory.createGroupSyncBox(1, 2, 3),
+                DiffInputFactory.createGroupSyncBox(4, 5, 6));
 
-        metersToAddOrUpdate = createMeterSyncBoxWithUpdates(1, 2, 3);
-        metersToRemove = createMeterSyncBox(1, 2, 3);
+        metersToAddOrUpdate = DiffInputFactory.createMeterSyncBoxWithUpdates(1, 2, 3);
+        metersToRemove = DiffInputFactory.createMeterSyncBox(1, 2, 3);
 
         flowsToAddOrUpdate = new HashMap<>();
-        flowsToAddOrUpdate.put(new TableKey((short) 0), createFlowSyncBox("1", "2", "3"));
-        flowsToAddOrUpdate.put(new TableKey((short) 1), createFlowSyncBoxWithUpdates("4", "5", "6"));
+        flowsToAddOrUpdate.put(new TableKey((short) 0), DiffInputFactory.createFlowSyncBox("1", "2", "3"));
+        flowsToAddOrUpdate.put(new TableKey((short) 1), DiffInputFactory.createFlowSyncBoxWithUpdates("4", "5", "6"));
         flowsToRemove = new HashMap<>();
-        flowsToRemove.put(new TableKey((short) 0), createFlowSyncBox("1", "2", "3"));
-        flowsToRemove.put(new TableKey((short) 1), createFlowSyncBox("4", "5", "6"));
-    }
-
-    private ItemSyncBox<Group> createGroupSyncBox(final long... groupIDs) {
-        final ItemSyncBox<Group> groupBox = new ItemSyncBox<>();
-
-        for (long gid : groupIDs) {
-            groupBox.getItemsToPush().add(createPlainGroup(gid));
-        }
-        return groupBox;
-    }
-
-    private ItemSyncBox<Group> createGroupSyncBoxWithUpdates(final long... groupIDs) {
-        final ItemSyncBox<Group> groupBox = new ItemSyncBox<>();
-
-        for (long gid : groupIDs) {
-            groupBox.getItemsToPush().add(createPlainGroup(gid));
-            groupBox.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(createPlainGroup(gid),
-                    createPlainGroup(gid + 100)));
-        }
-        return groupBox;
-    }
-
-    private Group createPlainGroup(final long gid) {
-        return new GroupBuilder().setGroupId(new GroupId(gid)).build();
-    }
-
-    private ItemSyncBox<Meter> createMeterSyncBox(final long... meterIDs) {
-        final ItemSyncBox<Meter> groupBox = new ItemSyncBox<>();
-
-        for (long gid : meterIDs) {
-            groupBox.getItemsToPush().add(createPlainMeter(gid));
-        }
-        return groupBox;
-    }
-
-    private ItemSyncBox<Meter> createMeterSyncBoxWithUpdates(final long... meterIDs) {
-        final ItemSyncBox<Meter> groupBox = new ItemSyncBox<>();
-
-        for (long mid : meterIDs) {
-            groupBox.getItemsToPush().add(createPlainMeter(mid));
-            groupBox.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(createPlainMeter(mid),
-                    createPlainMeter(mid + 100)));
-        }
-        return groupBox;
-    }
-
-    private Meter createPlainMeter(final long mid) {
-        return new MeterBuilder().setMeterId(new MeterId(mid)).build();
-    }
-
-    private ItemSyncBox<Flow> createFlowSyncBox(final String... flowIDs) {
-        final ItemSyncBox<Flow> flowBox = new ItemSyncBox<>();
-
-        for (String fid : flowIDs) {
-            flowBox.getItemsToPush().add(createPlainFlow(fid));
-        }
-        return flowBox;
-    }
-
-    private ItemSyncBox<Flow> createFlowSyncBoxWithUpdates(final String... flowIDs) {
-        final ItemSyncBox<Flow> groupBox = new ItemSyncBox<>();
-
-        for (String fid : flowIDs) {
-            groupBox.getItemsToPush().add(createPlainFlow(fid));
-            groupBox.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(createPlainFlow(fid),
-                    createPlainFlow(fid + "upd")));
-        }
-        return groupBox;
-    }
-
-    private Flow createPlainFlow(final String fid) {
-        return new FlowBuilder().setId(new FlowId(fid)).build();
+        flowsToRemove.put(new TableKey((short) 0), DiffInputFactory.createFlowSyncBox("1", "2", "3"));
+        flowsToRemove.put(new TableKey((short) 1), DiffInputFactory.createFlowSyncBox("4", "5", "6"));
     }
 
 
@@ -165,7 +113,7 @@ public class SyncPlanPushStrategyFlatBatchImplTest {
     public void setUp() throws Exception {
         syncPlanPushStrategy = new SyncPlanPushStrategyFlatBatchImpl();
         syncPlanPushStrategy.setFlatBatchService(flatBatchService);
-        syncPlanPushStrategy.setFlatBatchService(tableUpdateService);
+        syncPlanPushStrategy.setTableForwarder(tableForwarder);
 
         batchBag = new ArrayList<>();
     }
@@ -173,14 +121,42 @@ public class SyncPlanPushStrategyFlatBatchImplTest {
     @Test
     public void testExecuteSyncStrategy() throws Exception {
         final SynchronizationDiffInput diffInput = new SynchronizationDiffInput(NODE_IDENT,
-                groupsToAddOrUpdate, null, null, null, null, null);
+                groupsToAddOrUpdate, metersToAddOrUpdate, flowsToAddOrUpdate, flowsToRemove, metersToRemove, groupsToRemove);
+
+        Mockito.when(flatBatchService.processFlatBatch(Matchers.<ProcessFlatBatchInput>any()))
+                .thenReturn(RpcResultBuilder.success(new ProcessFlatBatchOutputBuilder().build()).buildFuture());
+
+        final SyncCrudCounters counters = new SyncCrudCounters();
+        final ListenableFuture<RpcResult<Void>> rpcResult = syncPlanPushStrategy.executeSyncStrategy(
+                RpcResultBuilder.<Void>success().buildFuture(), diffInput, counters);
+
+        Mockito.verify(flatBatchService).processFlatBatch(processFlatBatchInputCpt.capture());
+
+        final ProcessFlatBatchInput processFlatBatchInput = processFlatBatchInputCpt.getValue();
+        Assert.assertFalse(processFlatBatchInput.isExitOnFirstError());
+        Assert.assertEquals(13, processFlatBatchInput.getBatch().size());
+
+        Assert.assertTrue(rpcResult.isDone());
+        Assert.assertTrue(rpcResult.get().isSuccessful());
+
+        Assert.assertEquals(6, counters.getFlowCrudCounts().getAdded());
+        Assert.assertEquals(3, counters.getFlowCrudCounts().getUpdated());
+        Assert.assertEquals(6, counters.getFlowCrudCounts().getRemoved());
+
+        Assert.assertEquals(6, counters.getGroupCrudCounts().getAdded());
+        Assert.assertEquals(3, counters.getGroupCrudCounts().getUpdated());
+        Assert.assertEquals(6, counters.getGroupCrudCounts().getRemoved());
+
+        Assert.assertEquals(3, counters.getMeterCrudCounts().getAdded());
+        Assert.assertEquals(3, counters.getMeterCrudCounts().getUpdated());
+        Assert.assertEquals(3, counters.getMeterCrudCounts().getRemoved());
     }
 
     @Test
     public void testAssembleRemoveFlows() throws Exception {
         final int lastOrder = SyncPlanPushStrategyFlatBatchImpl.assembleRemoveFlows(batchBag, 0, flowsToRemove);
 
-        Assert.assertEquals(2, lastOrder);
+        Assert.assertEquals(6, lastOrder);
         Assert.assertEquals(2, batchBag.size());
         Assert.assertEquals(FlatBatchRemoveFlowCase.class, batchBag.get(0).getBatchChoice().getImplementedInterface());
         Assert.assertEquals(3, ((FlatBatchRemoveFlowCase) batchBag.get(0).getBatchChoice())
@@ -194,7 +170,7 @@ public class SyncPlanPushStrategyFlatBatchImplTest {
     public void testAssembleAddOrUpdateGroups() throws Exception {
         final int lastOrder = SyncPlanPushStrategyFlatBatchImpl.assembleAddOrUpdateGroups(batchBag, 0, groupsToAddOrUpdate);
 
-        Assert.assertEquals(3, lastOrder);
+        Assert.assertEquals(9, lastOrder);
         Assert.assertEquals(3, batchBag.size());
         Assert.assertEquals(FlatBatchAddGroupCase.class, batchBag.get(0).getBatchChoice().getImplementedInterface());
         Assert.assertEquals(3, ((FlatBatchAddGroupCase) batchBag.get(0).getBatchChoice())
@@ -211,7 +187,7 @@ public class SyncPlanPushStrategyFlatBatchImplTest {
     public void testAssembleRemoveGroups() throws Exception {
         final int lastOrder = SyncPlanPushStrategyFlatBatchImpl.assembleRemoveGroups(batchBag, 0, groupsToRemove);
 
-        Assert.assertEquals(2, lastOrder);
+        Assert.assertEquals(6, lastOrder);
         Assert.assertEquals(2, batchBag.size());
         Assert.assertEquals(FlatBatchRemoveGroupCase.class, batchBag.get(0).getBatchChoice().getImplementedInterface());
         Assert.assertEquals(3, ((FlatBatchRemoveGroupCase) batchBag.get(0).getBatchChoice())
@@ -225,7 +201,7 @@ public class SyncPlanPushStrategyFlatBatchImplTest {
     public void testAssembleAddOrUpdateMeters() throws Exception {
         final int lastOrder = SyncPlanPushStrategyFlatBatchImpl.assembleAddOrUpdateMeters(batchBag, 0, metersToAddOrUpdate);
 
-        Assert.assertEquals(2, lastOrder);
+        Assert.assertEquals(6, lastOrder);
         Assert.assertEquals(2, batchBag.size());
         Assert.assertEquals(FlatBatchAddMeterCase.class, batchBag.get(0).getBatchChoice().getImplementedInterface());
         Assert.assertEquals(3, ((FlatBatchAddMeterCase) batchBag.get(0).getBatchChoice())
@@ -239,7 +215,7 @@ public class SyncPlanPushStrategyFlatBatchImplTest {
     public void testAssembleRemoveMeters() throws Exception {
         final int lastOrder = SyncPlanPushStrategyFlatBatchImpl.assembleRemoveMeters(batchBag, 0, metersToRemove);
 
-        Assert.assertEquals(1, lastOrder);
+        Assert.assertEquals(3, lastOrder);
         Assert.assertEquals(1, batchBag.size());
         Assert.assertEquals(FlatBatchRemoveMeterCase.class, batchBag.get(0).getBatchChoice().getImplementedInterface());
         Assert.assertEquals(3, ((FlatBatchRemoveMeterCase) batchBag.get(0).getBatchChoice())
@@ -250,7 +226,7 @@ public class SyncPlanPushStrategyFlatBatchImplTest {
     public void testAssembleAddOrUpdateFlows() throws Exception {
         final int lastOrder = SyncPlanPushStrategyFlatBatchImpl.assembleAddOrUpdateFlows(batchBag, 0, flowsToAddOrUpdate);
 
-        Assert.assertEquals(3, lastOrder);
+        Assert.assertEquals(9, lastOrder);
         Assert.assertEquals(3, batchBag.size());
         Assert.assertEquals(FlatBatchAddFlowCase.class, batchBag.get(0).getBatchChoice().getImplementedInterface());
         Assert.assertEquals(3, ((FlatBatchAddFlowCase) batchBag.get(0).getBatchChoice())
@@ -262,4 +238,66 @@ public class SyncPlanPushStrategyFlatBatchImplTest {
         Assert.assertEquals(3, ((FlatBatchAddFlowCase) batchBag.get(2).getBatchChoice())
                 .getFlatBatchAddFlow().size());
     }
+
+    @Test
+    public void testDecrementCounters() throws Exception {
+        final SyncCrudCounters counters = new SyncCrudCounters();
+        counters.getFlowCrudCounts().setAdded(100);
+        counters.getFlowCrudCounts().setUpdated(100);
+        counters.getFlowCrudCounts().setRemoved(100);
+
+        counters.getGroupCrudCounts().setAdded(100);
+        counters.getGroupCrudCounts().setUpdated(100);
+        counters.getGroupCrudCounts().setRemoved(100);
+
+        counters.getMeterCrudCounts().setAdded(100);
+        counters.getMeterCrudCounts().setUpdated(100);
+        counters.getMeterCrudCounts().setRemoved(100);
+
+        SyncPlanPushStrategyFlatBatchImpl.decrementCounters(new FlatBatchAddFlowCaseBuilder().build(), counters);
+        SyncPlanPushStrategyFlatBatchImpl.decrementCounters(new FlatBatchUpdateFlowCaseBuilder().build(), counters);
+        SyncPlanPushStrategyFlatBatchImpl.decrementCounters(new FlatBatchRemoveFlowCaseBuilder().build(), counters);
+
+        SyncPlanPushStrategyFlatBatchImpl.decrementCounters(new FlatBatchAddGroupCaseBuilder().build(), counters);
+        SyncPlanPushStrategyFlatBatchImpl.decrementCounters(new FlatBatchUpdateGroupCaseBuilder().build(), counters);
+        SyncPlanPushStrategyFlatBatchImpl.decrementCounters(new FlatBatchRemoveGroupCaseBuilder().build(), counters);
+
+        SyncPlanPushStrategyFlatBatchImpl.decrementCounters(new FlatBatchAddMeterCaseBuilder().build(), counters);
+        SyncPlanPushStrategyFlatBatchImpl.decrementCounters(new FlatBatchUpdateMeterCaseBuilder().build(), counters);
+        SyncPlanPushStrategyFlatBatchImpl.decrementCounters(new FlatBatchRemoveMeterCaseBuilder().build(), counters);
+
+        Assert.assertEquals(99, counters.getFlowCrudCounts().getAdded());
+        Assert.assertEquals(99, counters.getFlowCrudCounts().getUpdated());
+        Assert.assertEquals(99, counters.getFlowCrudCounts().getRemoved());
+
+        Assert.assertEquals(99, counters.getGroupCrudCounts().getAdded());
+        Assert.assertEquals(99, counters.getGroupCrudCounts().getUpdated());
+        Assert.assertEquals(99, counters.getGroupCrudCounts().getRemoved());
+
+        Assert.assertEquals(99, counters.getMeterCrudCounts().getAdded());
+        Assert.assertEquals(99, counters.getMeterCrudCounts().getUpdated());
+        Assert.assertEquals(99, counters.getMeterCrudCounts().getRemoved());
+    }
+
+    @Test
+    public void testMapBachesToRanges() throws Exception {
+        final List<Batch> inputBatchBag = Lists.newArrayList(
+                new BatchBuilder().setBatchOrder(0).build(),
+                new BatchBuilder().setBatchOrder(5).build(),
+                new BatchBuilder().setBatchOrder(9).build(),
+                new BatchBuilder().setBatchOrder(15).build()
+        );
+        final Map<Range<Integer>, Batch> rangeBatchMap = SyncPlanPushStrategyFlatBatchImpl.mapBachesToRanges(inputBatchBag, 42);
+
+        Assert.assertEquals(4, rangeBatchMap.size());
+        int idx = 0;
+        final int[] lower = new int[]{0, 5, 9, 15};
+        final int[] upper = new int[]{4, 8, 14, 41};
+        for (Map.Entry<Range<Integer>, Batch> rangeBatchEntry : rangeBatchMap.entrySet()) {
+            Assert.assertEquals(lower[idx], rangeBatchEntry.getKey().lowerEndpoint().intValue());
+            Assert.assertEquals(upper[idx], rangeBatchEntry.getKey().upperEndpoint().intValue());
+            Assert.assertSame(inputBatchBag.get(idx), rangeBatchEntry.getValue());
+            idx++;
+        }
+    }
 }
\ No newline at end of file
index 75de98f8405bf9f9326620256ce55eea7c05e450..75a34b81a09920396f4e74a35386c6770217ebd1 100644 (file)
@@ -10,6 +10,12 @@ package org.opendaylight.openflowplugin.applications.frsync.impl.strategy;
 
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Future;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -24,50 +30,28 @@ import org.mockito.invocation.InvocationOnMock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.openflowplugin.applications.frsync.impl.DSInputFactory;
 import org.opendaylight.openflowplugin.applications.frsync.impl.FlowForwarder;
 import org.opendaylight.openflowplugin.applications.frsync.impl.GroupForwarder;
 import org.opendaylight.openflowplugin.applications.frsync.impl.MeterForwarder;
 import org.opendaylight.openflowplugin.applications.frsync.impl.TableForwarder;
 import org.opendaylight.openflowplugin.applications.frsync.util.ItemSyncBox;
 import org.opendaylight.openflowplugin.applications.frsync.util.SyncCrudCounters;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupAction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev150304.FlowCapableTransactionService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev150304.SendBarrierInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
@@ -75,11 +59,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.BandId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DropBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.MeterBandHeadersBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.MeterBandHeaderBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.UpdateTableOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
@@ -89,13 +68,6 @@ import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Future;
-
 /**
  * Test for {@link SyncPlanPushStrategyIncrementalImpl}.
  */
@@ -140,9 +112,72 @@ public class SyncPlanPushStrategyIncrementalImplTest {
 
     private SyncCrudCounters counters;
 
+    private List<ItemSyncBox<Group>> groupsToAddOrUpdate;
+    private List<ItemSyncBox<Group>> groupsToRemove;
+    private ItemSyncBox<Meter> metersToAddOrUpdate;
+    private ItemSyncBox<Meter> metersToRemove;
+    private Map<TableKey, ItemSyncBox<Flow>> flowsToAddOrUpdate;
+    private Map<TableKey, ItemSyncBox<Flow>> flowsToRemove;
+
+    public SyncPlanPushStrategyIncrementalImplTest() {
+        groupsToAddOrUpdate = Lists.newArrayList(DiffInputFactory.createGroupSyncBox(1, 2, 3),
+                DiffInputFactory.createGroupSyncBoxWithUpdates(4, 5, 6));
+        groupsToRemove = Lists.newArrayList(DiffInputFactory.createGroupSyncBox(1, 2, 3),
+                DiffInputFactory.createGroupSyncBox(4, 5, 6));
+
+        metersToAddOrUpdate = DiffInputFactory.createMeterSyncBoxWithUpdates(1, 2, 3);
+        metersToRemove = DiffInputFactory.createMeterSyncBox(1, 2, 3);
+
+        flowsToAddOrUpdate = new HashMap<>();
+        flowsToAddOrUpdate.put(new TableKey((short) 0), DiffInputFactory.createFlowSyncBox("1", "2", "3"));
+        flowsToAddOrUpdate.put(new TableKey((short) 1), DiffInputFactory.createFlowSyncBoxWithUpdates("4", "5", "6"));
+        flowsToRemove = new HashMap<>();
+        flowsToRemove.put(new TableKey((short) 0), DiffInputFactory.createFlowSyncBox("1", "2", "3"));
+        flowsToRemove.put(new TableKey((short) 1), DiffInputFactory.createFlowSyncBox("4", "5", "6"));
+    }
+
     @Test
     public void testExecuteSyncStrategy() throws Exception {
+        final SynchronizationDiffInput diffInput = new SynchronizationDiffInput(NODE_IDENT,
+                groupsToAddOrUpdate, metersToAddOrUpdate, flowsToAddOrUpdate, flowsToRemove, metersToRemove, groupsToRemove);
 
+        final SyncCrudCounters counters = new SyncCrudCounters();
+        final ListenableFuture<RpcResult<Void>> rpcResult = syncPlanPushStrategy.executeSyncStrategy(
+                RpcResultBuilder.<Void>success().buildFuture(), diffInput, counters);
+
+        Mockito.verify(groupCommitter, Mockito.times(6)).add(Matchers.<InstanceIdentifier<Group>>any(),Matchers.<Group>any(),
+                Matchers.<InstanceIdentifier<FlowCapableNode>>any());
+        Mockito.verify(groupCommitter, Mockito.times(3)).update(Matchers.<InstanceIdentifier<Group>>any(),Matchers.<Group>any(),
+               Matchers.<Group>any(), Matchers.<InstanceIdentifier<FlowCapableNode>>any());
+        Mockito.verify(groupCommitter, Mockito.times(6)).remove(Matchers.<InstanceIdentifier<Group>>any(),Matchers.<Group>any(),
+                Matchers.<InstanceIdentifier<FlowCapableNode>>any());
+        Mockito.verify(flowCommitter, Mockito.times(6)).add(Matchers.<InstanceIdentifier<Flow>>any(),Matchers.<Flow>any(),
+                Matchers.<InstanceIdentifier<FlowCapableNode>>any());
+        Mockito.verify(flowCommitter, Mockito.times(3)).update(Matchers.<InstanceIdentifier<Flow>>any(),Matchers.<Flow>any(),
+               Matchers.<Flow>any(), Matchers.<InstanceIdentifier<FlowCapableNode>>any());
+        Mockito.verify(flowCommitter, Mockito.times(6)).remove(Matchers.<InstanceIdentifier<Flow>>any(),Matchers.<Flow>any(),
+                Matchers.<InstanceIdentifier<FlowCapableNode>>any());
+        Mockito.verify(meterCommitter, Mockito.times(3)).add(Matchers.<InstanceIdentifier<Meter>>any(), Matchers.<Meter>any(),
+                Matchers.<InstanceIdentifier<FlowCapableNode>>any());
+        Mockito.verify(meterCommitter, Mockito.times(3)).update(Matchers.<InstanceIdentifier<Meter>>any(), Matchers.<Meter>any(),
+                Matchers.<Meter>any(), Matchers.<InstanceIdentifier<FlowCapableNode>>any());
+        Mockito.verify(meterCommitter, Mockito.times(3)).remove(Matchers.<InstanceIdentifier<Meter>>any(), Matchers.<Meter>any(),
+                Matchers.<InstanceIdentifier<FlowCapableNode>>any());
+
+        Assert.assertTrue(rpcResult.isDone());
+        Assert.assertTrue(rpcResult.get().isSuccessful());
+
+        Assert.assertEquals(6, counters.getFlowCrudCounts().getAdded());
+        Assert.assertEquals(3, counters.getFlowCrudCounts().getUpdated());
+        Assert.assertEquals(6, counters.getFlowCrudCounts().getRemoved());
+
+        Assert.assertEquals(6, counters.getGroupCrudCounts().getAdded());
+        Assert.assertEquals(3, counters.getGroupCrudCounts().getUpdated());
+        Assert.assertEquals(6, counters.getGroupCrudCounts().getRemoved());
+
+        Assert.assertEquals(3, counters.getMeterCrudCounts().getAdded());
+        Assert.assertEquals(3, counters.getMeterCrudCounts().getUpdated());
+        Assert.assertEquals(3, counters.getMeterCrudCounts().getRemoved());
     }
 
     @Before
@@ -203,115 +238,6 @@ public class SyncPlanPushStrategyIncrementalImplTest {
         };
     }
 
-    private Group createGroup(final long groupIdValue) {
-        final Buckets buckets = new BucketsBuilder()
-                .setBucket(Collections.<Bucket>emptyList())
-                .build();
-        return new GroupBuilder()
-                .setGroupId(new GroupId(groupIdValue))
-                .setBuckets(buckets)
-                .build();
-    }
-
-    private Group createGroupWithAction(final long groupIdValue) {
-        final Buckets buckets = new BucketsBuilder()
-                .setBucket(Collections.singletonList(new BucketBuilder()
-                        .setAction(Collections.singletonList(new ActionBuilder()
-                                .setAction(new OutputActionCaseBuilder()
-                                        .setOutputAction(new OutputActionBuilder()
-                                                .setOutputNodeConnector(new Uri("ut-port-1"))
-                                                .build())
-                                        .build())
-                                .build()))
-                        .build()))
-                .build();
-        return new GroupBuilder()
-                .setGroupId(new GroupId(groupIdValue))
-                .setBuckets(buckets)
-                .build();
-    }
-
-    private Flow createFlow(final String flowIdValue, final int priority) {
-        return new FlowBuilder()
-                .setId(new FlowId(flowIdValue))
-                .setPriority(priority)
-                .setTableId((short) 42)
-                .setMatch(new MatchBuilder().build())
-                .build();
-    }
-
-    private Flow createFlowWithInstruction(final String flowIdValue, final int priority) {
-        return new FlowBuilder()
-                .setId(new FlowId(flowIdValue))
-                .setPriority(priority)
-                .setTableId((short) 42)
-                .setMatch(new MatchBuilder().build())
-                .setInstructions(new InstructionsBuilder()
-                        .setInstruction(Collections.singletonList(new InstructionBuilder()
-                                .setInstruction(new ApplyActionsCaseBuilder()
-                                        .setApplyActions(new ApplyActionsBuilder()
-                                                .setAction(Collections.singletonList(new ActionBuilder()
-                                                        .setAction(new OutputActionCaseBuilder()
-                                                                .setOutputAction(new OutputActionBuilder()
-                                                                        .setOutputNodeConnector(new Uri("ut-port-1"))
-                                                                        .build())
-                                                                .build())
-                                                        .build()))
-                                                .build())
-                                        .build())
-                                .build()))
-                        .build())
-                .build();
-    }
-
-    private Meter createMeter(final Long meterIdValue) {
-        return new MeterBuilder()
-                .setMeterId(new MeterId(meterIdValue))
-                .build();
-    }
-
-    private Meter createMeterWithBody(final Long meterIdValue) {
-        return new MeterBuilder()
-                .setMeterId(new MeterId(meterIdValue))
-                .setMeterBandHeaders(new MeterBandHeadersBuilder()
-                        .setMeterBandHeader(Collections.singletonList(new MeterBandHeaderBuilder()
-                                .setBandId(new BandId(42L))
-                                .setBandType(new DropBuilder()
-                                        .setDropRate(43L)
-                                        .build())
-                                .build()))
-                        .build())
-                .build();
-    }
-
-    private Group createGroupWithPreconditions(final long groupIdValue, final long... requiredId) {
-        final List<Action> actionBag = new ArrayList<>();
-        for (long groupIdPrecondition : requiredId) {
-            final GroupAction groupAction = new GroupActionBuilder()
-                    .setGroupId(groupIdPrecondition)
-                    .build();
-            final GroupActionCase groupActionCase = new GroupActionCaseBuilder()
-                    .setGroupAction(groupAction)
-                    .build();
-            final Action action = new ActionBuilder()
-                    .setAction(groupActionCase)
-                    .build();
-            actionBag.add(action);
-        }
-
-        final Bucket bucket = new BucketBuilder()
-                .setAction(actionBag)
-                .build();
-        final Buckets buckets = new BucketsBuilder()
-                .setBucket(Collections.singletonList(bucket))
-                .build();
-
-        return new GroupBuilder()
-                .setGroupId(new GroupId(groupIdValue))
-                .setBuckets(buckets)
-                .build();
-    }
-
     @Test
     public void testAddMissingFlows() throws Exception {
         Mockito.when(flowCommitter.add(Matchers.<InstanceIdentifier<Flow>>any(), flowCaptor.capture(),
@@ -319,8 +245,8 @@ public class SyncPlanPushStrategyIncrementalImplTest {
                 .thenReturn(RpcResultBuilder.success(new AddFlowOutputBuilder().build()).buildFuture());
 
         final ItemSyncBox<Flow> flowBox = new ItemSyncBox<>();
-        flowBox.getItemsToPush().add(createFlow("f3", 3));
-        flowBox.getItemsToPush().add(createFlow("f4", 4));
+        flowBox.getItemsToPush().add(DSInputFactory.createFlow("f3", 3));
+        flowBox.getItemsToPush().add(DSInputFactory.createFlow("f4", 4));
 
         final Map<TableKey, ItemSyncBox<Flow>> flowBoxMap = new LinkedHashMap<>();
         flowBoxMap.put(new TableKey((short) 0), flowBox);
@@ -351,8 +277,8 @@ public class SyncPlanPushStrategyIncrementalImplTest {
                 .thenReturn(RpcResultBuilder.success(new RemoveFlowOutputBuilder().build()).buildFuture());
 
         final ItemSyncBox<Flow> flowBox = new ItemSyncBox<>();
-        flowBox.getItemsToPush().add(createFlow("f3", 3));
-        flowBox.getItemsToPush().add(createFlow("f4", 4));
+        flowBox.getItemsToPush().add(DSInputFactory.createFlow("f3", 3));
+        flowBox.getItemsToPush().add(DSInputFactory.createFlow("f4", 4));
 
         final Map<TableKey, ItemSyncBox<Flow>> flowBoxMap = new LinkedHashMap<>();
         flowBoxMap.put(new TableKey((short) 0), flowBox);
@@ -388,10 +314,10 @@ public class SyncPlanPushStrategyIncrementalImplTest {
                 .thenReturn(RpcResultBuilder.success(new UpdateFlowOutputBuilder().build()).buildFuture());
 
         final ItemSyncBox<Flow> flowBox = new ItemSyncBox<>();
-        flowBox.getItemsToPush().add(createFlow("f3", 3));
-        flowBox.getItemsToPush().add(createFlow("f4", 4));
+        flowBox.getItemsToPush().add(DSInputFactory.createFlow("f3", 3));
+        flowBox.getItemsToPush().add(DSInputFactory.createFlow("f4", 4));
         flowBox.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(
-                createFlow("f1", 1), createFlowWithInstruction("f1", 1)));
+                DSInputFactory.createFlow("f1", 1), DSInputFactory.createFlowWithInstruction("f1", 1)));
 
         final Map<TableKey, ItemSyncBox<Flow>> flowBoxMap = new LinkedHashMap<>();
         flowBoxMap.put(new TableKey((short) 0), flowBox);
@@ -434,8 +360,8 @@ public class SyncPlanPushStrategyIncrementalImplTest {
                 .thenReturn(RpcResultBuilder.success(new AddMeterOutputBuilder().build()).buildFuture());
 
         final ItemSyncBox<Meter> meterSyncBox = new ItemSyncBox<>();
-        meterSyncBox.getItemsToPush().add(createMeter(2L));
-        meterSyncBox.getItemsToPush().add(createMeter(4L));
+        meterSyncBox.getItemsToPush().add(DSInputFactory.createMeter(2L));
+        meterSyncBox.getItemsToPush().add(DSInputFactory.createMeter(4L));
 
         final ListenableFuture<RpcResult<Void>> result = syncPlanPushStrategy.addMissingMeters(
                 NODE_ID, NODE_IDENT, meterSyncBox, counters);
@@ -467,10 +393,10 @@ public class SyncPlanPushStrategyIncrementalImplTest {
                 .thenReturn(RpcResultBuilder.success(new UpdateMeterOutputBuilder().build()).buildFuture());
 
         final ItemSyncBox<Meter> meterSyncBox = new ItemSyncBox<>();
-        meterSyncBox.getItemsToPush().add(createMeter(2L));
-        meterSyncBox.getItemsToPush().add(createMeter(4L));
+        meterSyncBox.getItemsToPush().add(DSInputFactory.createMeter(2L));
+        meterSyncBox.getItemsToPush().add(DSInputFactory.createMeter(4L));
         meterSyncBox.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(
-                createMeter(1L), createMeterWithBody(1L)));
+                DSInputFactory.createMeter(1L), DSInputFactory.createMeterWithBody(1L)));
 
         final ListenableFuture<RpcResult<Void>> result = syncPlanPushStrategy.addMissingMeters(
                 NODE_ID, NODE_IDENT, meterSyncBox, counters);
@@ -507,10 +433,10 @@ public class SyncPlanPushStrategyIncrementalImplTest {
                 .thenReturn(RpcResultBuilder.success(new RemoveMeterOutputBuilder().build()).buildFuture());
 
         final ItemSyncBox<Meter> meterSyncBox = new ItemSyncBox<>();
-        meterSyncBox.getItemsToPush().add(createMeter(2L));
-        meterSyncBox.getItemsToPush().add(createMeter(4L));
+        meterSyncBox.getItemsToPush().add(DSInputFactory.createMeter(2L));
+        meterSyncBox.getItemsToPush().add(DSInputFactory.createMeter(4L));
         meterSyncBox.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(
-                createMeter(1L), createMeterWithBody(1L)));
+                DSInputFactory.createMeter(1L), DSInputFactory.createMeterWithBody(1L)));
 
         final ListenableFuture<RpcResult<Void>> result = syncPlanPushStrategy.removeRedundantMeters(
                 NODE_ID, NODE_IDENT, meterSyncBox, counters);
@@ -538,14 +464,14 @@ public class SyncPlanPushStrategyIncrementalImplTest {
                 .thenReturn(RpcResultBuilder.success(new AddGroupOutputBuilder().build()).buildFuture());
 
         ItemSyncBox<Group> groupBox1 = new ItemSyncBox<>();
-        groupBox1.getItemsToPush().add(createGroup(2L));
+        groupBox1.getItemsToPush().add(DSInputFactory.createGroup(2L));
 
         ItemSyncBox<Group> groupBox2 = new ItemSyncBox<>();
-        groupBox2.getItemsToPush().add(createGroupWithPreconditions(3L, 2L));
-        groupBox2.getItemsToPush().add(createGroupWithPreconditions(4L, 2L));
+        groupBox2.getItemsToPush().add(DSInputFactory.createGroupWithPreconditions(3L, 2L));
+        groupBox2.getItemsToPush().add(DSInputFactory.createGroupWithPreconditions(4L, 2L));
 
         ItemSyncBox<Group> groupBox3 = new ItemSyncBox<>();
-        groupBox3.getItemsToPush().add(createGroupWithPreconditions(5L, 3L, 4L));
+        groupBox3.getItemsToPush().add(DSInputFactory.createGroupWithPreconditions(5L, 3L, 4L));
 
         final List<ItemSyncBox<Group>> groupBoxLot = Lists.newArrayList(groupBox1, groupBox2, groupBox3);
 
@@ -591,16 +517,16 @@ public class SyncPlanPushStrategyIncrementalImplTest {
                 .thenReturn(RpcResultBuilder.success(new UpdateGroupOutputBuilder().build()).buildFuture());
 
         ItemSyncBox<Group> groupBox1 = new ItemSyncBox<>();
-        groupBox1.getItemsToPush().add(createGroup(2L));
+        groupBox1.getItemsToPush().add(DSInputFactory.createGroup(2L));
         groupBox1.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(
-                createGroup(1L), createGroupWithAction(1L)));
+                DSInputFactory.createGroup(1L), DSInputFactory.createGroupWithAction(1L)));
 
         ItemSyncBox<Group> groupBox2 = new ItemSyncBox<>();
-        groupBox2.getItemsToPush().add(createGroupWithPreconditions(3L, 2L));
-        groupBox2.getItemsToPush().add(createGroupWithPreconditions(4L, 2L));
+        groupBox2.getItemsToPush().add(DSInputFactory.createGroupWithPreconditions(3L, 2L));
+        groupBox2.getItemsToPush().add(DSInputFactory.createGroupWithPreconditions(4L, 2L));
 
         ItemSyncBox<Group> groupBox3 = new ItemSyncBox<>();
-        groupBox3.getItemsToPush().add(createGroupWithPreconditions(5L, 3L, 4L));
+        groupBox3.getItemsToPush().add(DSInputFactory.createGroupWithPreconditions(5L, 3L, 4L));
 
         final List<ItemSyncBox<Group>> groupBoxLot = Lists.newArrayList(groupBox1, groupBox2, groupBox3);
         final ListenableFuture<RpcResult<Void>> result = syncPlanPushStrategy.addMissingGroups(
@@ -649,16 +575,16 @@ public class SyncPlanPushStrategyIncrementalImplTest {
                 .thenReturn(RpcResultBuilder.success(new RemoveGroupOutputBuilder().build()).buildFuture());
 
         ItemSyncBox<Group> groupBox1 = new ItemSyncBox<>();
-        groupBox1.getItemsToPush().add(createGroup(2L));
+        groupBox1.getItemsToPush().add(DSInputFactory.createGroup(2L));
         groupBox1.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(
-                createGroup(1L), createGroupWithAction(1L)));
+                DSInputFactory.createGroup(1L), DSInputFactory.createGroupWithAction(1L)));
 
         ItemSyncBox<Group> groupBox2 = new ItemSyncBox<>();
-        groupBox2.getItemsToPush().add(createGroupWithPreconditions(3L, 2L));
-        groupBox2.getItemsToPush().add(createGroupWithPreconditions(4L, 2L));
+        groupBox2.getItemsToPush().add(DSInputFactory.createGroupWithPreconditions(3L, 2L));
+        groupBox2.getItemsToPush().add(DSInputFactory.createGroupWithPreconditions(4L, 2L));
 
         ItemSyncBox<Group> groupBox3 = new ItemSyncBox<>();
-        groupBox3.getItemsToPush().add(createGroupWithPreconditions(5L, 3L, 4L));
+        groupBox3.getItemsToPush().add(DSInputFactory.createGroupWithPreconditions(5L, 3L, 4L));
 
         final List<ItemSyncBox<Group>> groupBoxLot = Lists.newArrayList(groupBox1, groupBox2, groupBox3);
         final ListenableFuture<RpcResult<Void>> result = syncPlanPushStrategy.removeRedundantGroups(