Repository: telstra/open-kilda
Issue: flow_id in the request line is ignored while flow update

Steps
case 1
1) create flow (e.g. with flow_id = flow1) - POST [/v2/flows]
2) make **wrong** put request to update it  - - PUT [/v2/flows/flow_not_match]
where body of the request contains flow_id = flow1
note: system shouldn't contain any flow with "flow_not_match" id

actual result: flow is updated successfully
expected result: 404 with the corresponding error message like "flow not found"

case 2
1) create flow (e.g. with flow_id = flow1) - POST [/v2/flows]
2) make  put request to update it  - - PUT [/v2/flows/flow1]
where body of the request **doesn't contains** flow_id = flow1
e.g. body should contain flow_id = flow_not_match
note: system shouldn't contain any flow with "flow_not_match" id

actual result: 404 with the corresponding error message like "flow not found"
expected result: flow should be updated, flow_id from the body should be ignored

actually we are taking flow_id from body, but it should be taken from the request line
also flow_id update is not supported, so it can be set as nullable in the body



Changed files:
src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v2/FlowControllerTest.java
src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/SwitchControllerTest.java
src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v1/FlowController.java
src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/TestMessageMock.java
src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v2/FlowControllerV2.java
src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/FlowService.java
src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java
src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/TestConfig.java
src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/FlowControllerTest.java

diff --git a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v1/FlowController.java b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v1/FlowController.java
index 003911b8f..ad05eef1d 100644
--- a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v1/FlowController.java
+++ b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v1/FlowController.java
@@ -137,7 +137,7 @@ public class FlowController extends BaseController {
     @ResponseStatus(HttpStatus.OK)
     public CompletableFuture<FlowResponsePayload> updateFlow(@PathVariable(name = "flow-id") String flowId,
                                                              @RequestBody FlowUpdatePayload flow) {
-        return flowService.updateFlow(flow);
+        return flowService.updateFlow(flowId, flow);
     }
 
     /**
diff --git a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v2/FlowControllerV2.java b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v2/FlowControllerV2.java
index a64191910..3b4727345 100644
--- a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v2/FlowControllerV2.java
+++ b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v2/FlowControllerV2.java
@@ -80,7 +80,7 @@ public class FlowControllerV2 extends BaseController {
     public CompletableFuture<FlowResponseV2> updateFlow(@PathVariable(name = "flow_id") String flowId,
                                                         @RequestBody FlowRequestV2 flow) {
         verifyRequest(flow);
-        return flowService.updateFlow(flow);
+        return flowService.updateFlow(flowId, flow);
     }
 
     /**
diff --git a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/FlowService.java b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/FlowService.java
index 863d75610..6418894c3 100644
--- a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/FlowService.java
+++ b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/FlowService.java
@@ -87,7 +87,7 @@ public interface FlowService {
      * @param flow flow
      * @return updated flow
      */
-    CompletableFuture<FlowResponsePayload> updateFlow(final FlowUpdatePayload flow);
+    CompletableFuture<FlowResponsePayload> updateFlow(final String flowId, final FlowUpdatePayload flow);
 
     /**
      * Updates flow.
@@ -95,7 +95,7 @@ public interface FlowService {
      * @param flow flow
      * @return updated flow
      */
-    CompletableFuture<FlowResponseV2> updateFlow(FlowRequestV2 flow);
+    CompletableFuture<FlowResponseV2> updateFlow(final String flowId, FlowRequestV2 flow);
 
     /**
      * Patch flow.
diff --git a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java
index 7bb83e6b7..93ba668b4 100644
--- a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java
+++ b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java
@@ -239,8 +239,8 @@ public class FlowServiceImpl implements FlowService {
      * {@inheritDoc}
      */
     @Override
-    public CompletableFuture<FlowResponsePayload> updateFlow(final FlowUpdatePayload request) {
-        log.info("API request: Update flow request for flow {}", request);
+    public CompletableFuture<FlowResponsePayload> updateFlow(final String flowId, final FlowUpdatePayload request) {
+        log.info("API request: Update flow request for flow {}: {}", flowId, request);
 
         final String correlationId = RequestCorrelationId.getId();
         FlowRequest updateRequest;
@@ -252,6 +252,7 @@ public class FlowServiceImpl implements FlowService {
             throw new MessageException(correlationId, System.currentTimeMillis(), ErrorType.DATA_INVALID,
                     e.getMessage(), "Can not parse arguments of the update flow request");
         }
+        validateFlowId(updateRequest.getFlowId(), flowId, correlationId);
 
         CommandMessage command = new CommandMessage(updateRequest,
                 System.currentTimeMillis(), correlationId, Destination.WFM);
@@ -263,8 +264,8 @@ public class FlowServiceImpl implements FlowService {
     }
 
     @Override
-    public CompletableFuture<FlowResponseV2> updateFlow(FlowRequestV2 request) {
-        log.info("API request: Processing flow update: {}", request);
+    public CompletableFuture<FlowResponseV2> updateFlow(final String flowId, FlowRequestV2 request) {
+        log.info("API request: Update flow request for flow {}: {}", flowId, request);
 
         final String correlationId = RequestCorrelationId.getId();
         FlowRequest updateRequest;
@@ -276,6 +277,7 @@ public class FlowServiceImpl implements FlowService {
             throw new MessageException(correlationId, System.currentTimeMillis(), ErrorType.DATA_INVALID,
                     e.getMessage(), "Can not parse arguments of the update flow request");
         }
+        validateFlowId(updateRequest.getFlowId(), flowId, correlationId);
 
         CommandMessage command = new CommandMessage(updateRequest,
                 System.currentTimeMillis(), correlationId, Destination.WFM);
@@ -861,4 +863,12 @@ public class FlowServiceImpl implements FlowService {
                         .map(encoder)
                         .collect(Collectors.toList()));
     }
+
+    private void validateFlowId(String requestFlowId, String pathFlowId, String correlationId) {
+        if (!requestFlowId.equals(pathFlowId)) {
+            throw new MessageException(correlationId, System.currentTimeMillis(), ErrorType.DATA_INVALID,
+                    "flow_id from body and from path are different",
+                    format("Body flow_id: %s, path flow_id: %s", requestFlowId, pathFlowId));
+        }
+    }
 }
diff --git a/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/TestConfig.java b/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/TestConfig.java
index d957ca40a..af5318997 100644
--- a/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/TestConfig.java
+++ b/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/TestConfig.java
@@ -18,7 +18,7 @@ package org.openkilda.northbound.controller;
 import org.openkilda.northbound.config.KafkaConfig;
 import org.openkilda.northbound.config.SecurityConfig;
 import org.openkilda.northbound.config.WebConfig;
-import org.openkilda.northbound.controller.v1.TestMessageMock;
+import org.openkilda.northbound.controller.mock.TestMessageMock;
 import org.openkilda.northbound.messaging.MessagingChannel;
 import org.openkilda.northbound.utils.CorrelationIdFactory;
 import org.openkilda.northbound.utils.TestCorrelationIdFactory;
diff --git a/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/TestMessageMock.java b/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/mock/TestMessageMock.java
similarity index 76%
rename from src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/TestMessageMock.java
rename to src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/mock/TestMessageMock.java
index d68c638c2..c65edb3e4 100644
--- a/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/TestMessageMock.java
+++ b/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/mock/TestMessageMock.java
@@ -13,10 +13,12 @@
  *   limitations under the License.
  */
 
-package org.openkilda.northbound.controller.v1;
+package org.openkilda.northbound.controller.mock;
 
+import static java.lang.String.format;
 import static java.util.Collections.singletonList;
 import static java.util.concurrent.CompletableFuture.completedFuture;
+import static org.openkilda.messaging.Utils.DEFAULT_CORRELATION_ID;
 import static org.openkilda.messaging.error.ErrorType.OPERATION_TIMED_OUT;
 
 import org.openkilda.messaging.Destination;
@@ -30,6 +32,7 @@ import org.openkilda.messaging.command.switches.SwitchRulesDeleteRequest;
 import org.openkilda.messaging.error.ErrorData;
 import org.openkilda.messaging.error.ErrorMessage;
 import org.openkilda.messaging.error.ErrorType;
+import org.openkilda.messaging.error.MessageError;
 import org.openkilda.messaging.error.MessageException;
 import org.openkilda.messaging.info.InfoData;
 import org.openkilda.messaging.info.event.PathInfoData;
@@ -53,6 +56,7 @@ import org.openkilda.messaging.payload.flow.PathNodePayload;
 import org.openkilda.model.SwitchId;
 import org.openkilda.northbound.dto.v2.flows.DetectConnectedDevicesV2;
 import org.openkilda.northbound.dto.v2.flows.FlowEndpointV2;
+import org.openkilda.northbound.dto.v2.flows.FlowRequestV2;
 import org.openkilda.northbound.dto.v2.flows.SwapFlowEndpointPayload;
 import org.openkilda.northbound.dto.v2.flows.SwapFlowPayload;
 import org.openkilda.northbound.messaging.MessagingChannel;
@@ -71,33 +75,42 @@ import java.util.concurrent.ConcurrentHashMap;
  */
 @Component
 public class TestMessageMock implements MessagingChannel {
-    static final String FLOW_ID = "ff:00";
+    public static final String FLOW_ID = "flow_id_1";
     static final String SECOND_FLOW_ID = "second_flow";
-    static final SwitchId SWITCH_ID = new SwitchId(FLOW_ID);
+    public static final String FLOW_ID_FROM_PATH = "different_flow_id";
+    static final SwitchId SWITCH_ID = new SwitchId("ff:00");
     static final SwitchId SECOND_SWITCH_ID = new SwitchId("ff:01");
-    static final String ERROR_FLOW_ID = "error-flow";
-    static final String TEST_SWITCH_ID = "ff:01";
-    static final long TEST_SWITCH_RULE_COOKIE = 1L;
-    static final FlowEndpointPayload flowEndpoint = new FlowEndpointPayload(SWITCH_ID, 1, 1,
+    public static final String ERROR_FLOW_ID = "error-flow";
+    public static final String TEST_SWITCH_ID = "ff:01";
+    public static final long TEST_SWITCH_RULE_COOKIE = 1L;
+    public static final FlowEndpointPayload FLOW_ENDPOINT = new FlowEndpointPayload(SWITCH_ID, 1, 1,
             new DetectConnectedDevicesPayload(false, false));
     static final FlowEndpointPayload secondFlowEndpoint = new FlowEndpointPayload(SECOND_SWITCH_ID, 2, 2,
             new DetectConnectedDevicesPayload(false, false));
-    static final FlowEndpointV2 flowPayloadEndpoint = new FlowEndpointV2(SWITCH_ID, 1, 1,
+    public static final FlowEndpointV2 FLOW_PAYLOAD_ENDPOINT = new FlowEndpointV2(SWITCH_ID, 1, 1,
             new DetectConnectedDevicesV2(false, false));
     static final FlowEndpointV2 secondFlowPayloadEndpoint = new FlowEndpointV2(SECOND_SWITCH_ID, 2, 2,
             new DetectConnectedDevicesV2(false, false));
-    public static final FlowPayload flow = FlowPayload.builder()
+
+    public static final FlowPayload FLOW = FlowPayload.builder()
             .id(FLOW_ID)
-            .source(flowEndpoint)
-            .destination(flowEndpoint)
+            .source(FLOW_ENDPOINT)
+            .destination(FLOW_ENDPOINT)
             .maximumBandwidth(10000)
             .description(FLOW_ID)
             .status(FlowState.UP.getState())
             .build();
-    public static final FlowResponsePayload flowResponsePayload = FlowResponsePayload.flowResponsePayloadBuilder()
+
+    public static final FlowRequestV2 FLOW_REQUEST_V2 = FlowRequestV2.builder()
+            .flowId(FLOW_ID)
+            .source(FLOW_PAYLOAD_ENDPOINT)
+            .destination(FLOW_PAYLOAD_ENDPOINT)
+            .build();
+
+    public static final FlowResponsePayload FLOW_RESPONSE_PAYLOAD = FlowResponsePayload.flowResponsePayloadBuilder()
             .id(FLOW_ID)
-            .source(flowEndpoint)
-            .destination(flowEndpoint)
+            .source(FLOW_ENDPOINT)
+            .destination(FLOW_ENDPOINT)
             .maximumBandwidth(10000)
             .description(FLOW_ID)
             .status(FlowState.UP.getState())
@@ -105,8 +118,8 @@ public class TestMessageMock implements MessagingChannel {
 
     public static final SwapFlowPayload firstSwapFlow = SwapFlowPayload.builder()
             .flowId(FLOW_ID)
-            .source(flowPayloadEndpoint)
-            .destination(flowPayloadEndpoint)
+            .source(FLOW_PAYLOAD_ENDPOINT)
+            .destination(FLOW_PAYLOAD_ENDPOINT)
             .build();
 
     public static final SwapFlowPayload secondSwapFlow = SwapFlowPayload.builder()
@@ -116,10 +129,10 @@ public class TestMessageMock implements MessagingChannel {
             .build();
 
     public static final SwapFlowEndpointPayload bulkFlow = new SwapFlowEndpointPayload(firstSwapFlow, secondSwapFlow);
-    static final FlowIdStatusPayload flowStatus = new FlowIdStatusPayload(FLOW_ID, FlowState.UP);
+    public static final FlowIdStatusPayload FLOW_STATUS = new FlowIdStatusPayload(FLOW_ID, FlowState.UP);
     static final PathInfoData path = new PathInfoData(0L, Collections.emptyList());
     static final List<PathNodePayload> pathPayloadsList = singletonList(new PathNodePayload(SWITCH_ID, 1, 1));
-    static final FlowPathPayload flowPath = FlowPathPayload.builder()
+    public static final FlowPathPayload FLOW_PATH = FlowPathPayload.builder()
             .id(FLOW_ID)
             .forwardPath(pathPayloadsList)
             .reversePath(pathPayloadsList)
@@ -151,6 +164,10 @@ public class TestMessageMock implements MessagingChannel {
             new SwitchRulesResponse(singletonList(TEST_SWITCH_RULE_COOKIE));
     private static final Map<String, CommandData> messages = new ConcurrentHashMap<>();
 
+    public static final MessageError DIFFERENT_FLOW_ID_ERROR = new MessageError(DEFAULT_CORRELATION_ID, 0,
+            ErrorType.DATA_INVALID.toString(), "flow_id from body and from path are different",
+            format("Body flow_id: %s, path flow_id: %s", FLOW_ID, FLOW_ID_FROM_PATH));
+
     /**
      * Chooses response by request.
      *
@@ -160,7 +177,7 @@ public class TestMessageMock implements MessagingChannel {
     private CompletableFuture<InfoData> formatResponse(final String correlationId, final CommandData data) {
         CompletableFuture<InfoData> result = new CompletableFuture<>();
         if (data instanceof FlowRequest) {
-            result.complete(flowResponse);
+            result.complete(buildFlowResponse((FlowRequest) data));
         } else if (data instanceof FlowDeleteRequest) {
             result.complete(flowResponse);
         } else if (data instanceof FlowReadRequest) {
@@ -176,6 +193,22 @@ public class TestMessageMock implements MessagingChannel {
         return result;
     }
 
+    private FlowResponse buildFlowResponse(FlowRequest flowRequest) {
+        return new FlowResponse(FlowDto.builder()
+                .flowId(flowRequest.getFlowId())
+                .bandwidth(flowRequest.getBandwidth())
+                .description(flowRequest.getDescription())
+                .sourceSwitch(flowRequest.getSource().getSwitchId())
+                .destinationSwitch(flowRequest.getDestination().getSwitchId())
+                .sourcePort(flowRequest.getSource().getPortNumber())
+                .destinationPort(flowRequest.getDestination().getPortNumber())
+                .sourceVlan(flowRequest.getSource().getOuterVlanId())
+                .destinationVlan(flowRequest.getDestination().getOuterVlanId())
+                .meterId(1)
+                .state(FlowState.UP)
+                .build());
+    }
+
     @Override
     public CompletableFuture<InfoData> sendAndGet(String topic, Message message) {
         if ("error-topic".equals(topic)) {
diff --git a/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/FlowControllerTest.java b/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/FlowControllerTest.java
index 1f3d8ae0b..72c644f10 100644
--- a/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/FlowControllerTest.java
+++ b/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/FlowControllerTest.java
@@ -20,7 +20,7 @@ import static org.openkilda.messaging.Utils.CORRELATION_ID;
 import static org.openkilda.messaging.Utils.DEFAULT_CORRELATION_ID;
 import static org.openkilda.messaging.Utils.EXTRA_AUTH;
 import static org.openkilda.messaging.Utils.MAPPER;
-import static org.openkilda.northbound.controller.v1.TestMessageMock.ERROR_FLOW_ID;
+import static org.openkilda.northbound.controller.mock.TestMessageMock.ERROR_FLOW_ID;
 import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE;
 import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
 import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
@@ -37,6 +37,7 @@ import org.openkilda.messaging.payload.flow.FlowIdStatusPayload;
 import org.openkilda.messaging.payload.flow.FlowPathPayload;
 import org.openkilda.messaging.payload.flow.FlowResponsePayload;
 import org.openkilda.northbound.controller.TestConfig;
+import org.openkilda.northbound.controller.mock.TestMessageMock;
 import org.openkilda.northbound.utils.RequestCorrelationId;
 
 import com.fasterxml.jackson.core.type.TypeReference;
@@ -90,7 +91,7 @@ public class FlowControllerTest {
         MvcResult mvcResult = mockMvc.perform(put("/v1/flows")
                 .header(CORRELATION_ID, testCorrelationId())
                 .contentType(APPLICATION_JSON_VALUE)
-                .content(MAPPER.writeValueAsString(TestMessageMock.flow)))
+                .content(MAPPER.writeValueAsString(TestMessageMock.FLOW)))
                 .andReturn();
 
         MvcResult result = mockMvc.perform(asyncDispatch(mvcResult))
@@ -100,7 +101,7 @@ public class FlowControllerTest {
         System.out.println("RESPONSE: " + result.getResponse().getContentAsString());
         FlowResponsePayload response = MAPPER.readValue(result.getResponse().getContentAsString(),
                 FlowResponsePayload.class);
-        assertEquals(TestMessageMock.flowResponsePayload, response);
+        assertEquals(TestMessageMock.FLOW_RESPONSE_PAYLOAD, response);
     }
 
     @Test
@@ -118,7 +119,7 @@ public class FlowControllerTest {
                 .andReturn();
         FlowResponsePayload response = MAPPER.readValue(result.getResponse().getContentAsString(),
                 FlowResponsePayload.class);
-        assertEquals(TestMessageMock.flowResponsePayload, response);
+        assertEquals(TestMessageMock.FLOW_RESPONSE_PAYLOAD, response);
     }
 
     @Test
@@ -135,7 +136,7 @@ public class FlowControllerTest {
                 .andReturn();
         FlowResponsePayload response = MAPPER.readValue(result.getResponse().getContentAsString(),
                 FlowResponsePayload.class);
-        assertEquals(TestMessageMock.flowResponsePayload, response);
+        assertEquals(TestMessageMock.FLOW_RESPONSE_PAYLOAD, response);
     }
 
     @Test
@@ -153,7 +154,7 @@ public class FlowControllerTest {
                 .andReturn();
         FlowResponsePayload[] response = MAPPER.readValue(result.getResponse().getContentAsString(),
                 FlowResponsePayload[].class);
-        assertEquals(TestMessageMock.flowResponsePayload, response[0]);
+        assertEquals(TestMessageMock.FLOW_RESPONSE_PAYLOAD, response[0]);
     }
 
     @Test
@@ -171,7 +172,7 @@ public class FlowControllerTest {
         MvcResult mvcResult = mockMvc.perform(put("/v1/flows/{flow-id}", TestMessageMock.FLOW_ID)
                 .header(CORRELATION_ID, testCorrelationId())
                 .contentType(APPLICATION_JSON_VALUE)
-                .content(MAPPER.writeValueAsString(TestMessageMock.flow)))
+                .content(MAPPER.writeValueAsString(TestMessageMock.FLOW)))
                 .andReturn();
 
         MvcResult result = mockMvc.perform(asyncDispatch(mvcResult))
@@ -180,9 +181,25 @@ public class FlowControllerTest {
                 .andReturn();
         FlowResponsePayload response = MAPPER.readValue(result.getResponse().getContentAsString(),
                 FlowResponsePayload.class);
-        assertEquals(TestMessageMock.flowResponsePayload, response);
+        assertEquals(TestMessageMock.FLOW_RESPONSE_PAYLOAD, response);
     }
 
+    @Test
+    @WithMockUser(username = USERNAME, password = PASSWORD, roles = ROLE)
+    public void updateFlowDifferentFlowIdInPathFails() throws Exception {
+        MvcResult result = mockMvc.perform(put("/v1/flows/{flow-id}", TestMessageMock.FLOW_ID_FROM_PATH)
+                        .header(CORRELATION_ID, testCorrelationId())
+                        .contentType(APPLICATION_JSON_VALUE)
+                        .content(MAPPER.writeValueAsString(TestMessageMock.FLOW)))
+                .andExpect(status().isBadRequest())
+                .andExpect(content().contentType(APPLICATION_JSON_VALUE))
+                .andReturn();
+
+        MessageError response = MAPPER.readValue(result.getResponse().getContentAsString(), MessageError.class);
+        assertEquals(TestMessageMock.DIFFERENT_FLOW_ID_ERROR, response);
+    }
+
+
     @Test
     @WithMockUser(username = USERNAME, password = PASSWORD, roles = ROLE)
     public void getFlows() throws Exception {
@@ -198,7 +215,7 @@ public class FlowControllerTest {
         List<FlowResponsePayload> response = MAPPER.readValue(
                 result.getResponse().getContentAsString(),
                 new TypeReference<List<FlowResponsePayload>>() {});
-        assertEquals(Collections.singletonList(TestMessageMock.flowResponsePayload), response);
+        assertEquals(Collections.singletonList(TestMessageMock.FLOW_RESPONSE_PAYLOAD), response);
     }
 
     @Test
@@ -215,7 +232,7 @@ public class FlowControllerTest {
                 .andReturn();
         FlowIdStatusPayload response =
                 MAPPER.readValue(result.getResponse().getContentAsString(), FlowIdStatusPayload.class);
-        assertEquals(TestMessageMock.flowStatus, response);
+        assertEquals(TestMessageMock.FLOW_STATUS, response);
     }
 
     @Test
@@ -231,7 +248,7 @@ public class FlowControllerTest {
                 .andExpect(content().contentType(APPLICATION_JSON_VALUE))
                 .andReturn();
         FlowPathPayload response = MAPPER.readValue(result.getResponse().getContentAsString(), FlowPathPayload.class);
-        assertEquals(TestMessageMock.flowPath, response);
+        assertEquals(TestMessageMock.FLOW_PATH, response);
     }
 
     @Test
diff --git a/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/SwitchControllerTest.java b/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/SwitchControllerTest.java
index e76fad6c0..f659527ab 100644
--- a/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/SwitchControllerTest.java
+++ b/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v1/SwitchControllerTest.java
@@ -19,8 +19,8 @@ import static org.junit.Assert.assertEquals;
 import static org.openkilda.messaging.Utils.CORRELATION_ID;
 import static org.openkilda.messaging.Utils.EXTRA_AUTH;
 import static org.openkilda.messaging.Utils.MAPPER;
-import static org.openkilda.northbound.controller.v1.TestMessageMock.TEST_SWITCH_ID;
-import static org.openkilda.northbound.controller.v1.TestMessageMock.TEST_SWITCH_RULE_COOKIE;
+import static org.openkilda.northbound.controller.mock.TestMessageMock.TEST_SWITCH_ID;
+import static org.openkilda.northbound.controller.mock.TestMessageMock.TEST_SWITCH_RULE_COOKIE;
 import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
 import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
diff --git a/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v2/FlowControllerTest.java b/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v2/FlowControllerTest.java
index 94a27c2a4..e1190d142 100644
--- a/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v2/FlowControllerTest.java
+++ b/src-java/northbound-service/northbound/src/test/java/org/openkilda/northbound/controller/v2/FlowControllerTest.java
@@ -23,11 +23,13 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
 import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
+import org.openkilda.messaging.error.MessageError;
 import org.openkilda.northbound.controller.TestConfig;
-import org.openkilda.northbound.controller.v1.TestMessageMock;
+import org.openkilda.northbound.controller.mock.TestMessageMock;
 import org.openkilda.northbound.dto.v2.flows.SwapFlowEndpointPayload;
 import org.openkilda.northbound.utils.RequestCorrelationId;
 
@@ -87,6 +89,21 @@ public class FlowControllerTest {
         assertEquals(TestMessageMock.bulkFlow.getSecondFlow(), response.getSecondFlow());
     }
 
+    @Test
+    @WithMockUser(username = USERNAME, password = PASSWORD, roles = ROLE)
+    public void updateFlowDifferentFlowIdInPathFails() throws Exception {
+        MvcResult result = mockMvc.perform(put("/v2/flows/{flow-id}", TestMessageMock.FLOW_ID_FROM_PATH)
+                        .header(CORRELATION_ID, testCorrelationId())
+                        .contentType(APPLICATION_JSON_VALUE)
+                        .content(MAPPER.writeValueAsString(TestMessageMock.FLOW_REQUEST_V2)))
+                .andExpect(status().isBadRequest())
+                .andExpect(content().contentType(APPLICATION_JSON_VALUE))
+                .andReturn();
+
+        MessageError response = MAPPER.readValue(result.getResponse().getContentAsString(), MessageError.class);
+        assertEquals(TestMessageMock.DIFFERENT_FLOW_ID_ERROR, response);
+    }
+
     private static String testCorrelationId() {
         return UUID.randomUUID().toString();
     }