Add FlowMessageService 14/50714/14
authormiroslav.macko <miroslav.macko@pantheon.tech>
Fri, 20 Jan 2017 13:00:38 +0000 (14:00 +0100)
committerTomas Slusny <tomas.slusny@pantheon.tech>
Wed, 15 Feb 2017 15:13:41 +0000 (16:13 +0100)
See also: bug 7139

Change-Id: Idb4f5b40ce8f033deee209eec1596df2b8ff7d10
Signed-off-by: miroslav.macko <miroslav.macko@pantheon.tech>
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/FlowMessageService.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/SalFlowServiceImpl.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/SalFlowServiceImplTest.java

diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/FlowMessageService.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/FlowMessageService.java
new file mode 100644 (file)
index 0000000..6282abb
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * 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;
+
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.FlowModCommand;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+final class FlowMessageService<O extends DataObject> extends AbstractMessageService<Flow, FlowMessageBuilder, O> {
+    protected FlowMessageService(final RequestContextStack requestContextStack, final DeviceContext deviceContext, final Class<O> clazz) {
+        super(requestContextStack, deviceContext, clazz);
+    }
+
+    @Override
+    protected OfHeader buildRequest(final Xid xid, final Flow input) throws ServiceException {
+        final FlowMessageBuilder flowMessageBuilder = new FlowMessageBuilder(input);
+        final Class<? extends DataContainer> clazz = input.getImplementedInterface();
+
+        if (clazz.equals(AddFlowInput.class)
+                || clazz.equals(UpdatedFlow.class)) {
+            flowMessageBuilder.setCommand(FlowModCommand.OFPFCADD);
+        } else if (clazz.equals(RemoveFlowInput.class)
+                || clazz.equals(OriginalFlow.class)) {
+            flowMessageBuilder.setCommand(Boolean.TRUE.equals(input.isStrict())
+                    ? FlowModCommand.OFPFCDELETESTRICT
+                    : FlowModCommand.OFPFCDELETE);
+        }
+
+        return flowMessageBuilder
+                .setVersion(getVersion())
+                .setXid(xid.getValue())
+                .build();
+    }
+
+    @Override
+    public boolean isSupported() {
+        return super.isSupported() && getVersion() >= OFConstants.OFP_VERSION_1_3;
+    }
+
+}
index 5a4ed71f75fa31bd683ccf159873f79946e18a8a..50cd420b3610e79fe87e696740b730f64384d0d1 100644 (file)
@@ -11,11 +11,13 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Future;
 import javax.annotation.Nullable;
+import org.opendaylight.openflowplugin.api.OFConstants;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
 import org.opendaylight.openflowplugin.api.openflow.registry.flow.DeviceFlowRegistry;
@@ -49,7 +51,9 @@ 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.openflow.protocol.rev130731.FlowModInputBuilder;
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,6 +62,9 @@ public class SalFlowServiceImpl implements SalFlowService, ItemLifeCycleSource {
     private final FlowService<UpdateFlowOutput> flowUpdate;
     private final FlowService<AddFlowOutput> flowAdd;
     private final FlowService<RemoveFlowOutput> flowRemove;
+    private final FlowMessageService<AddFlowOutput> flowAddMessage;
+    private final FlowMessageService<UpdateFlowOutput> flowUpdateMessage;
+    private final FlowMessageService<RemoveFlowOutput> flowRemoveMessage;
     private final DeviceContext deviceContext;
     private ItemLifecycleListener itemLifecycleListener;
 
@@ -66,6 +73,9 @@ public class SalFlowServiceImpl implements SalFlowService, ItemLifeCycleSource {
         flowRemove = new FlowService<>(requestContextStack, deviceContext, RemoveFlowOutput.class, convertorExecutor);
         flowAdd = new FlowService<>(requestContextStack, deviceContext, AddFlowOutput.class, convertorExecutor);
         flowUpdate = new FlowService<>(requestContextStack, deviceContext, UpdateFlowOutput.class, convertorExecutor);
+        flowAddMessage = new FlowMessageService<>(requestContextStack, deviceContext, AddFlowOutput.class);
+        flowUpdateMessage = new FlowMessageService<>(requestContextStack, deviceContext, UpdateFlowOutput.class);
+        flowRemoveMessage= new FlowMessageService<>(requestContextStack, deviceContext, RemoveFlowOutput.class);
     }
 
     @Override
@@ -76,17 +86,32 @@ public class SalFlowServiceImpl implements SalFlowService, ItemLifeCycleSource {
     @Override
     public Future<RpcResult<AddFlowOutput>> addFlow(final AddFlowInput input) {
         final FlowRegistryKey flowRegistryKey = FlowRegistryKeyFactory.create(deviceContext.getDeviceInfo().getVersion(), input);
-        final ListenableFuture<RpcResult<AddFlowOutput>> future =
-                flowAdd.processFlowModInputBuilders(flowAdd.toFlowModInputs(input));
-        Futures.addCallback(future, new AddFlowCallback(input, flowRegistryKey));
+        final ListenableFuture<RpcResult<AddFlowOutput>> future;
+
+        if (flowAddMessage.isSupported()) {
+            future = flowAddMessage.handleServiceCall(input);
+            Futures.addCallback(future, new AddFlowCallback(input, flowRegistryKey));
+        } else {
+            future = flowAdd.processFlowModInputBuilders(flowAdd.toFlowModInputs(input));
+            Futures.addCallback(future, new AddFlowCallback(input, flowRegistryKey));
+
+        }
         return future;
     }
 
     @Override
     public Future<RpcResult<RemoveFlowOutput>> removeFlow(final RemoveFlowInput input) {
-        final ListenableFuture<RpcResult<RemoveFlowOutput>> future =
-                flowRemove.processFlowModInputBuilders(flowRemove.toFlowModInputs(input));
-        Futures.addCallback(future, new RemoveFlowCallback(input));
+        final ListenableFuture<RpcResult<RemoveFlowOutput>> future;
+
+        if (flowRemoveMessage.isSupported()) {
+            future = flowRemoveMessage.handleServiceCall(input);
+            Futures.addCallback(future, new RemoveFlowCallback(input));
+
+        } else {
+            future = flowRemove.processFlowModInputBuilders(flowRemove.toFlowModInputs(input));
+            Futures.addCallback(future, new RemoveFlowCallback(input));
+        }
+
         return future;
     }
 
@@ -98,22 +123,71 @@ public class SalFlowServiceImpl implements SalFlowService, ItemLifeCycleSource {
         final List<FlowModInputBuilder> allFlowMods = new ArrayList<>();
         final List<FlowModInputBuilder> ofFlowModInputs;
 
-        if (!FlowCreatorUtil.canModifyFlow(original, updated, flowUpdate.getVersion())) {
-            // We would need to remove original and add updated.
+        ListenableFuture<RpcResult<UpdateFlowOutput>> future;
+        if (flowUpdateMessage.isSupported()) {
+
+            if (!FlowCreatorUtil.canModifyFlow(original, updated, flowUpdateMessage.getVersion())) {
+                final SettableFuture<RpcResult<UpdateFlowOutput>> objectSettableFuture = SettableFuture.create();
+
+                final ListenableFuture<List<RpcResult<UpdateFlowOutput>>> listListenableFuture = Futures.successfulAsList(
+                        flowUpdateMessage.handleServiceCall(input.getOriginalFlow()),
+                        flowUpdateMessage.handleServiceCall(input.getUpdatedFlow()));
+
+                Futures.addCallback(listListenableFuture, new FutureCallback<List<RpcResult<UpdateFlowOutput>>>() {
+                    @Override
+                    public void onSuccess(final List<RpcResult<UpdateFlowOutput>> results) {
+                        final ArrayList<RpcError> errors = new ArrayList();
+                        for (RpcResult<UpdateFlowOutput> flowModResult : results) {
+                            if (flowModResult == null) {
+                                errors.add(RpcResultBuilder.newError(
+                                        RpcError.ErrorType.PROTOCOL, OFConstants.APPLICATION_TAG,
+                                        "unexpected flowMod result (null) occurred"));
+                            } else if (!flowModResult.isSuccessful()) {
+                                errors.addAll(flowModResult.getErrors());
+                            }
+                        }
+
+                        final RpcResultBuilder<UpdateFlowOutput> rpcResultBuilder;
+                        if (errors.isEmpty()) {
+                            rpcResultBuilder = RpcResultBuilder.success();
+                        } else {
+                            rpcResultBuilder = RpcResultBuilder.<UpdateFlowOutput>failed().withRpcErrors(errors);
+                        }
+
+                        objectSettableFuture.set(rpcResultBuilder.build());
+                    }
+
+                    @Override
+                    public void onFailure(final Throwable t) {
+                        RpcResultBuilder<UpdateFlowOutput> rpcResultBuilder = RpcResultBuilder.failed();
+                        objectSettableFuture.set(rpcResultBuilder.build());
+                    }
+                });
 
-            // remove flow
-            final RemoveFlowInputBuilder removeflow = new RemoveFlowInputBuilder(original);
-            final List<FlowModInputBuilder> ofFlowRemoveInput = flowUpdate.toFlowModInputs(removeflow.build());
-            // remove flow should be the first
-            allFlowMods.addAll(ofFlowRemoveInput);
-            final AddFlowInputBuilder addFlowInputBuilder = new AddFlowInputBuilder(updated);
-            ofFlowModInputs = flowUpdate.toFlowModInputs(addFlowInputBuilder.build());
+                future = objectSettableFuture;
+            } else {
+                future = flowUpdateMessage.handleServiceCall(input.getUpdatedFlow());
+            }
         } else {
-            ofFlowModInputs = flowUpdate.toFlowModInputs(updated);
+            if (!FlowCreatorUtil.canModifyFlow(original, updated, flowUpdate.getVersion())) {
+                // We would need to remove original and add updated.
+
+                // remove flow
+                final RemoveFlowInputBuilder removeflow = new RemoveFlowInputBuilder(original);
+                final List<FlowModInputBuilder> ofFlowRemoveInput = flowUpdate.toFlowModInputs(removeflow.build());
+                // remove flow should be the first
+                allFlowMods.addAll(ofFlowRemoveInput);
+                final AddFlowInputBuilder addFlowInputBuilder = new AddFlowInputBuilder(updated);
+                ofFlowModInputs = flowUpdate.toFlowModInputs(addFlowInputBuilder.build());
+            } else {
+                ofFlowModInputs = flowUpdate.toFlowModInputs(updated);
+            }
+
+            allFlowMods.addAll(ofFlowModInputs);
+
+            future = flowUpdate.processFlowModInputBuilders(allFlowMods);
         }
 
-        allFlowMods.addAll(ofFlowModInputs);
-        ListenableFuture<RpcResult<UpdateFlowOutput>> future = flowUpdate.processFlowModInputBuilders(allFlowMods);
         Futures.addCallback(future, new UpdateFlowCallback(input));
         return future;
     }
index 89cbef6d7e49435b9e08035672bddc5fb532c03b..46af7563d9db6a8348419718f671a65fff722247 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.openflowplugin.impl.services;
 
 
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
 
 import com.google.common.util.concurrent.Futures;
@@ -75,7 +76,6 @@ import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 public class SalFlowServiceImplTest extends TestCase {
 
     private static final BigInteger DUMMY_DATAPATH_ID = new BigInteger("444");
-    private static final Short DUMMY_VERSION = OFConstants.OFP_VERSION_1_3;
     private static final String DUMMY_NODE_ID = "dummyNodeID";
     private static final String DUMMY_FLOW_ID = "dummyFlowID";
     private static final Short DUMMY_TABLE_ID = (short) 0;
@@ -104,7 +104,6 @@ public class SalFlowServiceImplTest extends TestCase {
     private OutboundQueue outboundQueue;
     @Mock
     private Match match;
-    private SalFlowServiceImpl salFlowService;
 
     @Mock
     private DeviceState mockedDeviceState;
@@ -118,40 +117,57 @@ public class SalFlowServiceImplTest extends TestCase {
     @Before
     public void initialization() {
         when(mockedFeatures.getDatapathId()).thenReturn(DUMMY_DATAPATH_ID);
-        when(mockedFeatures.getVersion()).thenReturn(DUMMY_VERSION);
         when(mockedFeaturesOutput.getDatapathId()).thenReturn(DUMMY_DATAPATH_ID);
-        when(mockedFeaturesOutput.getVersion()).thenReturn(DUMMY_VERSION);
 
         when(mockedPrimConnectionContext.getFeatures()).thenReturn(mockedFeatures);
         when(mockedPrimConnectionContext.getConnectionAdapter()).thenReturn(mockedConnectionAdapter);
         when(mockedPrimConnectionContext.getOutboundQueueProvider()).thenReturn(outboundQueue);
 
         when(mockedDeviceContext.getPrimaryConnectionContext()).thenReturn(mockedPrimConnectionContext);
-
         when(mockedDeviceContext.getMessageSpy()).thenReturn(mockedMessagSpy);
         when(mockedDeviceContext.getDeviceFlowRegistry()).thenReturn(deviceFlowRegistry);
-        when(mockedRequestContextStack.createRequestContext()).thenReturn(requestContext);
 
         when(requestContext.getXid()).thenReturn(new Xid(84L));
         when(requestContext.getFuture()).thenReturn(RpcResultBuilder.success().buildFuture());
+        when(mockedRequestContextStack.createRequestContext()).thenReturn(requestContext);
 
         when(mockedDeviceInfo.getNodeInstanceIdentifier()).thenReturn(NODE_II);
         when(mockedDeviceInfo.getDatapathId()).thenReturn(DUMMY_DATAPATH_ID);
-        when(mockedDeviceInfo.getVersion()).thenReturn(DUMMY_VERSION);
+
         when(mockedDeviceContext.getDeviceState()).thenReturn(mockedDeviceState);
         when(mockedDeviceContext.getDeviceInfo()).thenReturn(mockedDeviceInfo);
+    }
+
+    private SalFlowServiceImpl mockSalFlowService(final short version) {
+        when(mockedFeatures.getVersion()).thenReturn(version);
+        when(mockedFeaturesOutput.getVersion()).thenReturn(version);
+        when(mockedDeviceInfo.getVersion()).thenReturn(version);
+
+        if (OFConstants.OFP_VERSION_1_3 >= version) {
+            when(mockedDeviceContext.isUseSingleLayerSerialization()).thenReturn(true);
+        }
 
         final ConvertorManager convertorManager = ConvertorManagerFactory.createDefaultManager();
-        salFlowService = new SalFlowServiceImpl(mockedRequestContextStack, mockedDeviceContext, convertorManager);
+        return new SalFlowServiceImpl(mockedRequestContextStack, mockedDeviceContext, convertorManager);
     }
 
     @Test
     public void testAddFlow() throws Exception {
-        addFlow(null);
+        addFlow(null, OFConstants.OFP_VERSION_1_0);
+        addFlow(null, OFConstants.OFP_VERSION_1_3);
     }
 
     @Test
     public void testAddFlowFailCallback() throws Exception {
+        addFlowFailCallback(OFConstants.OFP_VERSION_1_0);
+    }
+
+    @Test
+    public void testAddFlowFailCallback1() throws Exception {
+        addFlowFailCallback(OFConstants.OFP_VERSION_1_3);
+    }
+
+    private void addFlowFailCallback(short version) throws InterruptedException, ExecutionException {
         AddFlowInput mockedAddFlowInput = new AddFlowInputBuilder()
                 .setMatch(match)
                 .setTableId((short)1)
@@ -161,7 +177,7 @@ public class SalFlowServiceImplTest extends TestCase {
                 .when(requestContext).getFuture();
 
         mockingFlowRegistryLookup();
-        final Future<RpcResult<AddFlowOutput>> rpcResultFuture = salFlowService.addFlow(mockedAddFlowInput);
+        final Future<RpcResult<AddFlowOutput>> rpcResultFuture = mockSalFlowService(version).addFlow(mockedAddFlowInput);
 
         assertNotNull(rpcResultFuture);
         final RpcResult<?> addFlowOutputRpcResult = rpcResultFuture.get();
@@ -171,6 +187,15 @@ public class SalFlowServiceImplTest extends TestCase {
 
     @Test
     public void testRemoveFlowFailCallback() throws Exception {
+        removeFlowFailCallback(OFConstants.OFP_VERSION_1_0);
+    }
+
+    @Test
+    public void testRemoveFlowFailCallback1() throws Exception {
+        removeFlowFailCallback(OFConstants.OFP_VERSION_1_3);
+    }
+
+    private void removeFlowFailCallback(short version) throws InterruptedException, ExecutionException {
         RemoveFlowInput mockedRemoveFlowInput = new RemoveFlowInputBuilder()
                 .setMatch(match)
                 .build();
@@ -178,7 +203,7 @@ public class SalFlowServiceImplTest extends TestCase {
         Mockito.doReturn(Futures.<RequestContext<Object>>immediateFailedFuture(new Exception("ut-failed-response")))
                 .when(requestContext).getFuture();
 
-        final Future<RpcResult<RemoveFlowOutput>> rpcResultFuture = salFlowService.removeFlow(mockedRemoveFlowInput);
+        final Future<RpcResult<RemoveFlowOutput>> rpcResultFuture = mockSalFlowService(version).removeFlow(mockedRemoveFlowInput);
 
         assertNotNull(rpcResultFuture);
         final RpcResult<?> removeFlowOutputRpcResult = rpcResultFuture.get();
@@ -188,15 +213,16 @@ public class SalFlowServiceImplTest extends TestCase {
 
     @Test
     public void testAddFlowWithItemLifecycle() throws Exception {
-        addFlow(mock(ItemLifecycleListener.class));
+        addFlow(mock(ItemLifecycleListener.class), OFConstants.OFP_VERSION_1_0);
+        addFlow(mock(ItemLifecycleListener.class), OFConstants.OFP_VERSION_1_3);
     }
 
-    private void addFlow(final ItemLifecycleListener itemLifecycleListener) throws ExecutionException, InterruptedException {
+    private void addFlow(final ItemLifecycleListener itemLifecycleListener, short version) throws ExecutionException, InterruptedException {
         AddFlowInput mockedAddFlowInput = new AddFlowInputBuilder()
                 .setMatch(match)
                 .setTableId((short)1)
                 .build();
-
+        SalFlowServiceImpl salFlowService = mockSalFlowService(version);
         salFlowService.setItemLifecycleListener(itemLifecycleListener);
 
         mockingFlowRegistryLookup();
@@ -208,20 +234,23 @@ public class SalFlowServiceImplTest extends TestCase {
 
     @Test
     public void testRemoveFlow() throws Exception {
-        removeFlow(null);
+        removeFlow(null, OFConstants.OFP_VERSION_1_0);
+        removeFlow(null, OFConstants.OFP_VERSION_1_3);
     }
 
     @Test
     public void testRemoveFlowWithItemLifecycle() throws Exception {
-        removeFlow(mock(ItemLifecycleListener.class));
+        removeFlow(mock(ItemLifecycleListener.class), OFConstants.OFP_VERSION_1_0);
+        removeFlow(mock(ItemLifecycleListener.class), OFConstants.OFP_VERSION_1_3);
     }
 
-    private void removeFlow(final ItemLifecycleListener itemLifecycleListener) throws Exception {
+    private void removeFlow(final ItemLifecycleListener itemLifecycleListener, short version) throws Exception {
         RemoveFlowInput mockedRemoveFlowInput = new RemoveFlowInputBuilder()
                 .setMatch(match)
                 .setTableId((short)1)
                 .build();
 
+        SalFlowServiceImpl salFlowService = mockSalFlowService(version);
         if (itemLifecycleListener != null) {
             salFlowService.setItemLifecycleListener(itemLifecycleListener);
             mockingFlowRegistryLookup();
@@ -237,44 +266,64 @@ public class SalFlowServiceImplTest extends TestCase {
 
     @Test
     public void testUpdateFlow() throws Exception {
-        updateFlow(null);
+        updateFlow(null, OFConstants.OFP_VERSION_1_0);
+        updateFlow(null, OFConstants.OFP_VERSION_1_3);
     }
 
     @Test
     public void testUpdateFlowWithItemLifecycle() throws Exception {
-        updateFlow(mock(ItemLifecycleListener.class));
+        updateFlow(mock(ItemLifecycleListener.class), OFConstants.OFP_VERSION_1_0);
+        updateFlow(mock(ItemLifecycleListener.class), OFConstants.OFP_VERSION_1_3);
     }
 
-    private void updateFlow(final ItemLifecycleListener itemLifecycleListener) throws Exception {
+    private void updateFlow(final ItemLifecycleListener itemLifecycleListener, short version) throws Exception {
         UpdateFlowInput mockedUpdateFlowInput = mock(UpdateFlowInput.class);
+        UpdateFlowInput mockedUpdateFlowInput1 = mock(UpdateFlowInput.class);
 
         UpdatedFlow mockedUpdateFlow = new UpdatedFlowBuilder()
                 .setMatch(match)
                 .setTableId((short)1)
                 .build();
 
+        UpdatedFlow mockedUpdateFlow1 = new UpdatedFlowBuilder()
+                .setMatch(match)
+                .setTableId((short)1)
+                .setPriority(Integer.valueOf(1))
+                .build();
+
         when(mockedUpdateFlowInput.getUpdatedFlow()).thenReturn(mockedUpdateFlow);
+        when(mockedUpdateFlowInput1.getUpdatedFlow()).thenReturn(mockedUpdateFlow1);
 
         FlowRef mockedFlowRef = mock(FlowRef.class);
         Mockito.doReturn(TABLE_II.child(Flow.class, new FlowKey(new FlowId(DUMMY_FLOW_ID)))).when(mockedFlowRef).getValue();
         when(mockedUpdateFlowInput.getFlowRef()).thenReturn(mockedFlowRef);
+        when(mockedUpdateFlowInput1.getFlowRef()).thenReturn(mockedFlowRef);
 
         OriginalFlow mockedOriginalFlow = new OriginalFlowBuilder()
                 .setMatch(match)
                 .setTableId((short)1)
                 .build();
 
+        OriginalFlow mockedOriginalFlow1 = new OriginalFlowBuilder()
+                .setMatch(match)
+                .setTableId((short)1)
+                .setPriority(Integer.valueOf(2))
+                .build();
+
         when(mockedUpdateFlowInput.getOriginalFlow()).thenReturn(mockedOriginalFlow);
+        when(mockedUpdateFlowInput1.getOriginalFlow()).thenReturn(mockedOriginalFlow1);
 
+        SalFlowServiceImpl salFlowService = mockSalFlowService(version);
         if (itemLifecycleListener != null) {
             salFlowService.setItemLifecycleListener(itemLifecycleListener);
             mockingFlowRegistryLookup();
         }
 
         verifyOutput(salFlowService.updateFlow(mockedUpdateFlowInput));
+        verifyOutput(salFlowService.updateFlow(mockedUpdateFlowInput1));
 
         if (itemLifecycleListener != null) {
-            Mockito.verify(itemLifecycleListener).onUpdated(Matchers.<KeyedInstanceIdentifier<Flow, FlowKey>>any(), Matchers.<Flow>any());
+            Mockito.verify(itemLifecycleListener, times(2)).onUpdated(Matchers.<KeyedInstanceIdentifier<Flow, FlowKey>>any(), Matchers.<Flow>any());
         }
 
     }