Merge "XML content support on replace a node with descendants"
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java
index 3891d5b..d57ed2e 100644
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java
+++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java
@@ -23,6 +23,7 @@
 import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUCCESS;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import io.cloudevents.CloudEvent;
 import io.cloudevents.core.builder.CloudEventBuilder;
@@ -69,6 +70,7 @@
 public class DmiRestStubController {
 
     private static final String DEFAULT_TAG = "tagD";
+    private static final String DEFAULT_PASSTHROUGH_OPERATION = "read";
     private static final String dataOperationEventType = "org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent";
     private static final Map<String, String> moduleSetTagPerCmHandleId = new HashMap<>();
     private final KafkaTemplate<String, CloudEvent> cloudEventKafkaTemplate;
@@ -80,8 +82,10 @@
     private long moduleReferencesDelayMs;
     @Value("${delay.module-resources-delay-ms}")
     private long moduleResourcesDelayMs;
-    @Value("${delay.data-for-cm-handle-delay-ms}")
-    private long dataForCmHandleDelayMs;
+    @Value("${delay.read-data-for-cm-handle-delay-ms}")
+    private long readDataForCmHandleDelayMs;
+    @Value("${delay.write-data-for-cm-handle-delay-ms}")
+    private long writeDataForCmHandleDelayMs;
 
     /**
      * This code defines a REST API endpoint for adding new the module set tag mapping. The endpoint receives the
@@ -208,7 +212,12 @@
             @RequestHeader(value = "Authorization", required = false) final String authorization,
             @RequestBody final String requestBody) {
         log.info("DMI AUTH HEADER: {}", authorization);
-        delay(dataForCmHandleDelayMs);
+        final String passthroughOperationType = getPassthroughOperationType(requestBody);
+        if (passthroughOperationType.equals("read")) {
+            delay(readDataForCmHandleDelayMs);
+        } else {
+            delay(writeDataForCmHandleDelayMs);
+        }
         log.info("Logging request body {}", requestBody);
 
         final String sampleJson = ResourceFileReaderUtil.getResourceFileContent(applicationContext.getResource(
@@ -229,7 +238,7 @@
             @RequestParam(value = "topic") final String topic,
             @RequestParam(value = "requestId") final String requestId,
             @RequestBody final DmiDataOperationRequest dmiDataOperationRequest) {
-        delay(dataForCmHandleDelayMs);
+        delay(writeDataForCmHandleDelayMs);
         try {
             log.info("Request received from the NCMP to DMI Plugin: {}",
                     objectMapper.writeValueAsString(dmiDataOperationRequest));
@@ -312,6 +321,16 @@
         return ResourceFileReaderUtil.getResourceFileContent(moduleResponseResource);
     }
 
+    private String getPassthroughOperationType(final String requestBody) {
+        try {
+            final JsonNode rootNode = objectMapper.readTree(requestBody);
+            return rootNode.path("operation").asText();
+        } catch (final JsonProcessingException jsonProcessingException) {
+            log.error("Invalid JSON format. cause : {}", jsonProcessingException.getMessage());
+        }
+        return DEFAULT_PASSTHROUGH_OPERATION;
+    }
+
     private void delay(final long milliseconds) {
         try {
             Thread.sleep(milliseconds);
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/application.yml b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/application.yml
index b78a5b2..e1e3354 100644
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/application.yml
+++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/application.yml
@@ -53,7 +53,8 @@
 delay:
     module-references-delay-ms: ${MODULE_REFERENCES_DELAY_MS:100}
     module-resources-delay-ms: ${MODULE_RESOURCES_DELAY_MS:1000}
-    data-for-cm-handle-delay-ms: ${DATA_FOR_CM_HANDLE_DELAY_MS:2500}
+    read-data-for-cm-handle-delay-ms: ${READ_DATA_FOR_CM_HANDLE_DELAY_MS:300}
+    write-data-for-cm-handle-delay-ms: ${WRITE_DATA_FOR_CM_HANDLE_DELAY_MS:670}
 
 logging:
     level:
diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml
index 2ecd456..86afe78 100644
--- a/docker-compose/docker-compose.yml
+++ b/docker-compose/docker-compose.yml
@@ -137,7 +137,8 @@
       NCMP_ASYNC_M2M_TOPIC: ncmp-async-m2m
       MODULE_REFERENCES_DELAY_MS: 100
       MODULE_RESOURCES_DELAY_MS: 1000
-      DATA_FOR_CM_HANDLE_DELAY_MS: 2500
+      READ_DATA_FOR_CM_HANDLE_DELAY_MS: 300
+      WRITE_DATA_FOR_CM_HANDLE_DELAY_MS: 670
     restart: unless-stopped
     profiles:
       - dmi-stub
diff --git a/k6-tests/ncmp/common/utils.js b/k6-tests/ncmp/common/utils.js
index 75c4ec7..4bf066c 100644
--- a/k6-tests/ncmp/common/utils.js
+++ b/k6-tests/ncmp/common/utils.js
@@ -58,7 +58,7 @@
     summaryCsv += makeSummaryCsvLine(2, 'De-registration of CM-handles', 'CM-handles/second', 'cmhandles_deleted_per_second', data, options);
     summaryCsv += makeSummaryCsvLine(3, 'CM-handle ID search with Module filter', 'milliseconds', 'http_req_duration{scenario:id_search_module}', data, options);
     summaryCsv += makeSummaryCsvLine(4, 'CM-handle search with Module filter', 'milliseconds', 'http_req_duration{scenario:cm_search_module}', data, options);
-    summaryCsv += makeSummaryCsvLine(5, 'Synchronous single CM-handle pass-through read', 'milliseconds', 'http_req_duration{scenario:passthrough_read}', data, options);
+    summaryCsv += makeSummaryCsvLine(5, 'Synchronous single CM-handle pass-through read', 'requests/second', 'http_reqs{scenario:passthrough_read}', data, options);
     summaryCsv += makeSummaryCsvLine(6, 'Synchronous single CM-handle pass-through write', 'requests/second', 'http_reqs{scenario:passthrough_write}', data, options);
     return summaryCsv;
 }
diff --git a/k6-tests/ncmp/ncmp-kpi.js b/k6-tests/ncmp/ncmp-kpi.js
index 24fbef0..6bf0568 100644
--- a/k6-tests/ncmp/ncmp-kpi.js
+++ b/k6-tests/ncmp/ncmp-kpi.js
@@ -62,11 +62,10 @@
     thresholds: {
         'cmhandles_created_per_second': ['value >= 22'],
         'cmhandles_deleted_per_second': ['value >= 22'],
-        'http_req_failed{scenario:passthrough_read}': ['rate == 0'],
         'http_reqs{scenario:passthrough_write}': ['rate >= 13'],
+        'http_reqs{scenario:passthrough_read}': ['rate >= 25'],
         'http_req_failed{scenario:id_search_module}': ['rate == 0'],
         'http_req_failed{scenario:cm_search_module}': ['rate == 0'],
-        'http_req_duration{scenario:passthrough_read}': ['avg <= 2600'], // DMI delay + 100 ms
         'http_req_duration{scenario:id_search_module}': ['avg <= 625'],
         'http_req_duration{scenario:cm_search_module}': ['avg <= 13000'],
     },