#1: Dedicated web client instance is assigned for data, model and health services

 - Switched web client instance based on dmi service type (like data or model)
 - 3 diff. beans are configured for data, model and health dmi service.
 - Added configurable properties for data and model.
 - Hard coded properties are assigned for health service.

Issue-ID: CPS-2231
Change-Id: I39fb739c07c41430dae43509fe29ece5306b7d71
Signed-off-by: sourabh_sourabh <sourabh.sourabh@est.tech>
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
index ef48c43..7878c5d 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
@@ -26,6 +26,7 @@
 import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR;
 import static org.springframework.http.HttpStatus.BAD_REQUEST;
 import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+import static org.springframework.http.HttpStatus.REQUEST_TIMEOUT;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import java.net.URI;
@@ -37,7 +38,9 @@
 import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException;
 import org.onap.cps.ncmp.api.impl.exception.InvalidDmiResourceUrlException;
 import org.onap.cps.ncmp.api.impl.operations.OperationType;
+import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService;
 import org.onap.cps.utils.JsonObjectMapper;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -45,6 +48,7 @@
 import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.reactive.function.BodyInserters;
 import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.reactive.function.client.WebClientRequestException;
 import org.springframework.web.reactive.function.client.WebClientResponseException;
 
 @Component
@@ -55,31 +59,43 @@
     private static final String HEALTH_CHECK_URL_EXTENSION = "/actuator/health";
     private static final String NOT_SPECIFIED = "";
     private static final String NO_AUTHORIZATION = null;
-    private final WebClient webClient;
+
     private final DmiProperties dmiProperties;
     private final JsonObjectMapper jsonObjectMapper;
+    @Qualifier("dataServicesWebClient")
+    private final WebClient dataServicesWebClient;
+    @Qualifier("modelServicesWebClient")
+    private final WebClient modelServicesWebClient;
+    @Qualifier("healthChecksWebClient")
+    private final WebClient healthChecksWebClient;
 
     /**
-     * Sends POST operation to DMI with json body containing module references.
+     * Sends a POST operation to the DMI with a JSON body containing module references.
      *
-     * @param dmiResourceUrl          dmi resource url
-     * @param requestBodyAsJsonString json data body
-     * @param operationType           the type of operation being executed (for error reporting only)
-     * @param authorization           contents of Authorization header, or null if not present
-     * @return response entity of type String
+     * @param requiredDmiService      Determines if the required service is for a data or model operation.
+     * @param dmiUrl                  The DMI resource URL.
+     * @param requestBodyAsJsonString JSON data body.
+     * @param operationType           The type of operation being executed (for error reporting only).
+     * @param authorization           Contents of the Authorization header, or null if not present.
+     * @return ResponseEntity containing the response from the DMI.
+     * @throws DmiClientRequestException If there is an error during the DMI request.
      */
-    public ResponseEntity<Object> postOperationWithJsonData(final String dmiResourceUrl,
+    public ResponseEntity<Object> postOperationWithJsonData(final RequiredDmiService requiredDmiService,
+                                                            final String dmiUrl,
                                                             final String requestBodyAsJsonString,
                                                             final OperationType operationType,
                                                             final String authorization) {
+        final WebClient webClient = requiredDmiService.equals(RequiredDmiService.DATA)
+                ? dataServicesWebClient : modelServicesWebClient;
         try {
-            return ResponseEntity.ok(webClient.post().uri(toUri(dmiResourceUrl))
+            return webClient.post()
+                    .uri(toUri(dmiUrl))
                     .headers(httpHeaders -> configureHttpHeaders(httpHeaders, authorization))
                     .body(BodyInserters.fromValue(requestBodyAsJsonString))
                     .retrieve()
-                    .bodyToMono(Object.class)
+                    .toEntity(Object.class)
                     .onErrorMap(httpError -> handleDmiClientException(httpError, operationType.getOperationName()))
-                    .block());
+                    .block();
         } catch (final HttpServerErrorException e) {
             throw handleDmiClientException(e, operationType.getOperationName());
         }
@@ -88,31 +104,31 @@
     /**
      * Get DMI plugin health status.
      *
-     * @param       dmiPluginBaseUrl the base URL of the dmi-plugin
-     * @return      plugin health status ("UP" is all OK, "" (not-specified) in case of any exception)
+     * @param dmiUrl the base URL of the dmi-plugin
+     * @return plugin health status ("UP" is all OK, "" (not-specified) in case of any exception)
      */
-    public String getDmiHealthStatus(final String dmiPluginBaseUrl) {
+    public String getDmiHealthStatus(final String dmiUrl) {
         try {
-            final JsonNode responseHealthStatus = webClient.get()
-                    .uri(toUri(dmiPluginBaseUrl + HEALTH_CHECK_URL_EXTENSION))
+            final URI dmiHealthCheckUri = toUri(dmiUrl + HEALTH_CHECK_URL_EXTENSION);
+            final JsonNode responseHealthStatus = healthChecksWebClient.get()
+                    .uri(dmiHealthCheckUri)
                     .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION))
                     .retrieve()
                     .bodyToMono(JsonNode.class).block();
             return responseHealthStatus == null ? NOT_SPECIFIED :
-                    responseHealthStatus.get("status").asText();
+                    responseHealthStatus.path("status").asText();
         } catch (final Exception e) {
-            log.warn("Failed to retrieve health status from {}. Error Message: {}", dmiPluginBaseUrl, e.getMessage());
+            log.warn("Failed to retrieve health status from {}. Error Message: {}", dmiUrl, e.getMessage());
             return NOT_SPECIFIED;
         }
     }
 
-    private HttpHeaders configureHttpHeaders(final HttpHeaders httpHeaders, final String authorization) {
+    private void configureHttpHeaders(final HttpHeaders httpHeaders, final String authorization) {
         if (dmiProperties.isDmiBasicAuthEnabled()) {
             httpHeaders.setBasicAuth(dmiProperties.getAuthUsername(), dmiProperties.getAuthPassword());
         } else if (authorization != null && authorization.toLowerCase(Locale.getDefault()).startsWith("bearer ")) {
             httpHeaders.add(HttpHeaders.AUTHORIZATION, authorization);
         }
-        return httpHeaders;
     }
 
     private static URI toUri(final String dmiResourceUrl) {
@@ -123,22 +139,31 @@
         }
     }
 
-    private DmiClientRequestException handleDmiClientException(final Throwable e, final String operationType) {
-        final String exceptionMessage = "Unable to " + operationType + " resource data.";
-        if (e instanceof WebClientResponseException wcre) {
-            if (wcre.getStatusCode().isSameCodeAs(HttpStatus.REQUEST_TIMEOUT)) {
-                throw new DmiClientRequestException(wcre.getStatusCode().value(), wcre.getMessage(),
-                        jsonObjectMapper.asJsonString(wcre.getResponseBodyAsString()), DMI_SERVICE_NOT_RESPONDING);
+    private DmiClientRequestException handleDmiClientException(final Throwable throwable, final String operationType) {
+        if (throwable instanceof WebClientResponseException webClientResponseException) {
+            if (webClientResponseException.getStatusCode().isSameCodeAs(REQUEST_TIMEOUT)) {
+                throw new DmiClientRequestException(webClientResponseException.getStatusCode().value(),
+                        webClientResponseException.getMessage(),
+                        jsonObjectMapper.asJsonString(webClientResponseException.getResponseBodyAsString()),
+                        DMI_SERVICE_NOT_RESPONDING);
             }
-            throw new DmiClientRequestException(wcre.getStatusCode().value(), wcre.getMessage(),
-                    jsonObjectMapper.asJsonString(wcre.getResponseBodyAsString()), UNABLE_TO_READ_RESOURCE_DATA);
+            throw new DmiClientRequestException(webClientResponseException.getStatusCode().value(),
+                    webClientResponseException.getMessage(),
+                    jsonObjectMapper.asJsonString(webClientResponseException.getResponseBodyAsString()),
+                    UNABLE_TO_READ_RESOURCE_DATA);
 
         }
-        if (e instanceof HttpServerErrorException httpServerErrorException) {
+        final String exceptionMessage = "Unable to " + operationType + " resource data.";
+        if (throwable instanceof WebClientRequestException webClientRequestException) {
+            throw new DmiClientRequestException(HttpStatus.SERVICE_UNAVAILABLE.value(),
+                    webClientRequestException.getMessage(),
+                    exceptionMessage, DMI_SERVICE_NOT_RESPONDING);
+        }
+        if (throwable instanceof HttpServerErrorException httpServerErrorException) {
             throw new DmiClientRequestException(httpServerErrorException.getStatusCode().value(), exceptionMessage,
                     httpServerErrorException.getResponseBodyAsString(), DMI_SERVICE_NOT_RESPONDING);
         }
-        throw new DmiClientRequestException(INTERNAL_SERVER_ERROR.value(), exceptionMessage, e.getMessage(),
+        throw new DmiClientRequestException(INTERNAL_SERVER_ERROR.value(), exceptionMessage, throwable.getMessage(),
                 UNKNOWN_ERROR);
     }
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java
index 2e84f7f..2c0b702 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java
@@ -34,6 +34,10 @@
 import reactor.netty.http.client.HttpClient;
 import reactor.netty.resources.ConnectionProvider;
 
+/**
+ * Configures and creates a WebClient bean that triggers an initialization (warmup) of the host name resolver and
+ * loads the necessary native libraries to avoid the extra time needed to load resources for first request.
+ */
 @Configuration
 @RequiredArgsConstructor
 public class DmiWebClientConfiguration {
@@ -41,30 +45,83 @@
     private final HttpClientConfiguration httpClientConfiguration;
 
     /**
-     * Configures and create a WebClient bean that triggers an initialization (warmup) of the host name resolver and
-     * loads the necessary native libraries to avoid the extra time needed to load resources for first request.
+     * Configures and create a WebClient bean for DMI data service.
      *
-     * @return a WebClient instance.
+     * @return a WebClient instance for data services.
      */
     @Bean
-    public WebClient webClient() {
-        final ConnectionProvider dmiWebClientConnectionProvider = ConnectionProvider.create(
-                "dmiWebClientConnectionPool", httpClientConfiguration.getMaximumConnectionsTotal());
+    public WebClient dataServicesWebClient() {
+        final HttpClientConfiguration.DataServices httpClientConfiguration
+                = this.httpClientConfiguration.getDataServices();
+
+        final HttpClient httpClient = createHttpClient("dataConnectionPool",
+                httpClientConfiguration.getMaximumConnectionsTotal(),
+                httpClientConfiguration.getConnectionTimeoutInSeconds(),
+                httpClientConfiguration.getReadTimeoutInSeconds(),
+                httpClientConfiguration.getWriteTimeoutInSeconds());
+        return buildAndGetWebClient(httpClient, httpClientConfiguration.getMaximumInMemorySizeInMegabytes());
+    }
+
+    /**
+     * Configures and creates a WebClient bean for DMI model service.
+     *
+     * @return a WebClient instance for model services.
+     */
+    @Bean
+    public WebClient modelServicesWebClient() {
+        final HttpClientConfiguration.ModelServices httpClientConfiguration
+                = this.httpClientConfiguration.getModelServices();
+
+        final HttpClient httpClient = createHttpClient("modelConnectionPool",
+                httpClientConfiguration.getMaximumConnectionsTotal(),
+                httpClientConfiguration.getConnectionTimeoutInSeconds(),
+                httpClientConfiguration.getReadTimeoutInSeconds(),
+                httpClientConfiguration.getWriteTimeoutInSeconds());
+        return buildAndGetWebClient(httpClient, httpClientConfiguration.getMaximumInMemorySizeInMegabytes());
+    }
+
+    /**
+     * Configures and creates a WebClient bean for DMI health service.
+     *
+     * @return a WebClient instance for health checks.
+     */
+    @Bean
+    public WebClient healthChecksWebClient() {
+        final HttpClientConfiguration.HealthCheckServices httpClientConfiguration
+                = this.httpClientConfiguration.getHealthCheckServices();
+
+        final HttpClient httpClient = createHttpClient("healthConnectionPool",
+                httpClientConfiguration.getMaximumConnectionsTotal(),
+                httpClientConfiguration.getConnectionTimeoutInSeconds(),
+                httpClientConfiguration.getReadTimeoutInSeconds(),
+                httpClientConfiguration.getWriteTimeoutInSeconds());
+        return buildAndGetWebClient(httpClient, httpClientConfiguration.getMaximumInMemorySizeInMegabytes());
+    }
+
+    private static HttpClient createHttpClient(final String connectionProviderName,
+                                               final Integer maximumConnectionsTotal,
+                                               final Integer connectionTimeoutInSeconds,
+                                               final Integer readTimeoutInSeconds,
+                                               final Integer writeTimeoutInSeconds) {
+        final ConnectionProvider dmiWebClientConnectionProvider = ConnectionProvider.create(connectionProviderName,
+                maximumConnectionsTotal);
 
         final HttpClient httpClient = HttpClient.create(dmiWebClientConnectionProvider)
-                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
-                        httpClientConfiguration.getConnectionTimeoutInSeconds() * 1000)
-                .doOnConnected(connection -> connection.addHandlerLast(new ReadTimeoutHandler(
-                                httpClientConfiguration.getReadTimeoutInSeconds(), TimeUnit.SECONDS))
-                        .addHandlerLast(new WriteTimeoutHandler(
-                                httpClientConfiguration.getWriteTimeoutInSeconds(), TimeUnit.SECONDS)));
+                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeoutInSeconds * 1000)
+                .doOnConnected(connection -> connection.addHandlerLast(new ReadTimeoutHandler(readTimeoutInSeconds,
+                        TimeUnit.SECONDS)).addHandlerLast(new WriteTimeoutHandler(writeTimeoutInSeconds,
+                        TimeUnit.SECONDS)));
         httpClient.warmup().block();
+        return httpClient;
+    }
+
+    private static WebClient buildAndGetWebClient(final HttpClient httpClient,
+                                                  final Integer maximumInMemorySizeInMegabytes) {
         return WebClient.builder()
                 .defaultHeaders(header -> header.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
                 .defaultHeaders(header -> header.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE))
                 .clientConnector(new ReactorClientHttpConnector(httpClient))
                 .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(
-                        httpClientConfiguration.getMaximumInMemorySizeInMegabytes() * 1024 * 1024))
-                .build();
+                        maximumInMemorySizeInMegabytes * 1024 * 1024)).build();
     }
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java
index d2521d9..62432f6 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java
@@ -30,9 +30,37 @@
 @Component
 @ConfigurationProperties(prefix = "ncmp.dmi.httpclient")
 public class HttpClientConfiguration {
-    private Integer maximumConnectionsTotal = 100;
-    private Integer connectionTimeoutInSeconds = 30;
-    private Integer readTimeoutInSeconds = 30;
-    private Integer writeTimeoutInSeconds = 30;
-    private Integer maximumInMemorySizeInMegabytes = 1;
+
+    private final DataServices dataServices = new DataServices();
+    private final ModelServices modelServices = new ModelServices();
+    private final HealthCheckServices healthCheckServices = new HealthCheckServices();
+
+    @Getter
+    @Setter
+    public static class DataServices {
+        private Integer maximumConnectionsTotal = 100;
+        private Integer connectionTimeoutInSeconds = 30;
+        private Integer readTimeoutInSeconds = 30;
+        private Integer writeTimeoutInSeconds = 30;
+        private Integer maximumInMemorySizeInMegabytes = 1;
+    }
+
+    @Getter
+    @Setter
+    public static class ModelServices {
+        private Integer maximumConnectionsTotal = 100;
+        private Integer connectionTimeoutInSeconds = 30;
+        private Integer readTimeoutInSeconds = 30;
+        private Integer writeTimeoutInSeconds = 30;
+        private Integer maximumInMemorySizeInMegabytes = 1;
+    }
+
+    @Getter
+    public static class HealthCheckServices {
+        private final Integer maximumConnectionsTotal = 10;
+        private final Integer connectionTimeoutInSeconds = 30;
+        private final Integer readTimeoutInSeconds = 30;
+        private final Integer writeTimeoutInSeconds = 30;
+        private final Integer maximumInMemorySizeInMegabytes = 1;
+    }
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
index 6370879..9788555 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
@@ -23,6 +23,7 @@
 
 import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING;
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ;
+import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA;
 
 import io.micrometer.core.annotation.Timed;
 import java.util.Collection;
@@ -87,13 +88,9 @@
         final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
         validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
         final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle);
-
-        final String dmiUrl = getDmiResourceDataUrl(cmResourceAddress.datastoreName(),
-                                                    yangModelCmHandle,
-                                                    cmResourceAddress.resourceIdentifier(),
-                                                    optionsParamInQuery,
-                                                    topicParamInQuery);
-        return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, READ, authorization);
+        final String dmiUrl = getDmiResourceDataUrl(cmResourceAddress.datastoreName(), yangModelCmHandle,
+                cmResourceAddress.resourceIdentifier(), optionsParamInQuery, topicParamInQuery);
+        return dmiRestClient.postOperationWithJsonData(DATA, dmiUrl, jsonRequestBody, READ, authorization);
     }
 
     /**
@@ -114,7 +111,7 @@
 
         final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle);
         final String dmiUrl = getDmiResourceDataUrl(datastoreName, yangModelCmHandle, "/", null, null);
-        return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, READ, null);
+        return dmiRestClient.postOperationWithJsonData(DATA, dmiUrl, jsonRequestBody, READ, null);
     }
 
     /**
@@ -171,7 +168,7 @@
                 yangModelCmHandle);
         final String dmiUrl = getDmiResourceDataUrl(PASSTHROUGH_RUNNING.getDatastoreName(),
             yangModelCmHandle, resourceId, null, null);
-        return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, operationType, authorization);
+        return dmiRestClient.postOperationWithJsonData(DATA, dmiUrl, jsonRequestBody, operationType, authorization);
     }
 
     private YangModelCmHandle getYangModelCmHandle(final String cmHandleId) {
@@ -251,7 +248,8 @@
                 .operations(dmiDataOperationRequestBodies).build();
         final String dmiDataOperationRequestAsJsonString = jsonObjectMapper.asJsonString(dmiDataOperationRequest);
         try {
-            dmiRestClient.postOperationWithJsonData(dmiUrl, dmiDataOperationRequestAsJsonString, READ, authorization);
+            dmiRestClient.postOperationWithJsonData(DATA, dmiUrl, dmiDataOperationRequestAsJsonString, READ,
+                    authorization);
         } catch (final DmiClientRequestException e) {
             handleTaskCompletionException(e, dmiUrl, dmiDataOperationRequestBodies);
         }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
index 78d27b5..77dfcb7 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
@@ -111,7 +111,7 @@
                 .variablePathSegment("cmHandleId", cmHandle)
                 .variablePathSegment("resourceName", resourceName)
                 .build(dmiServiceName, dmiProperties.getDmiBasePath());
-        return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, OperationType.READ, null);
+        return dmiRestClient.postOperationWithJsonData(MODEL, dmiUrl, jsonRequestBody, OperationType.READ, null);
     }
 
     private static String getRequestBodyToFetchYangResources(final Collection<ModuleReference> newModuleReferences,
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy
index 369b496..b095f90 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy
@@ -20,6 +20,8 @@
 
 package org.onap.cps.ncmp.api.impl.async
 
+import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
+
 import com.fasterxml.jackson.databind.ObjectMapper
 import io.cloudevents.CloudEvent
 import io.cloudevents.kafka.CloudEventDeserializer
@@ -42,8 +44,6 @@
 import org.testcontainers.spock.Testcontainers
 import java.time.Duration
 
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
-
 @SpringBootTest(classes = [EventsPublisher, DataOperationEventConsumer, RecordFilterStrategies, JsonObjectMapper, ObjectMapper])
 @Testcontainers
 @DirtiesContext
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
index d2dce06..2c22127 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
@@ -21,9 +21,11 @@
 
 package org.onap.cps.ncmp.api.impl.client
 
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
+import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA
 import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE
 import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING
 import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA
@@ -31,109 +33,102 @@
 import com.fasterxml.jackson.databind.JsonNode
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.fasterxml.jackson.databind.node.ObjectNode
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
-import org.onap.cps.ncmp.api.impl.exception.InvalidDmiResourceUrlException
 import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException
+import org.onap.cps.ncmp.api.impl.exception.InvalidDmiResourceUrlException
+import org.onap.cps.ncmp.api.impl.config.DmiProperties
 import org.onap.cps.ncmp.utils.TestUtils
 import org.onap.cps.utils.JsonObjectMapper
-import org.spockframework.spring.SpringBean
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
 import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpStatus
 import org.springframework.http.ResponseEntity
-import org.springframework.test.context.ContextConfiguration
 import org.springframework.web.client.HttpServerErrorException
 import org.springframework.web.reactive.function.client.WebClient
+import org.springframework.web.reactive.function.client.WebClientResponseException
+import org.springframework.web.reactive.function.client.WebClientRequestException
 import reactor.core.publisher.Mono
 import spock.lang.Specification
-import org.springframework.web.reactive.function.client.WebClientResponseException
-import org.onap.cps.ncmp.api.impl.config.DmiProperties
 
-@SpringBootTest
-@ContextConfiguration(classes = [DmiProperties, DmiRestClient, ObjectMapper])
 class DmiRestClientSpec extends Specification {
 
     static final NO_AUTH_HEADER = null
-    static final BASIC_AUTH_HEADER = 'Basic c29tZS11c2VyOnNvbWUtcGFzc3dvcmQ='
+    static final BASIC_AUTH_HEADER = 'Basic c29tZSB1c2VyOnNvbWUgcGFzc3dvcmQ='
     static final BEARER_AUTH_HEADER = 'Bearer my-bearer-token'
 
-    @Autowired
-    DmiProperties dmiProperties
+    def mockDataServicesWebClient = Mock(WebClient)
+    def mockModelServicesWebClient = Mock(WebClient)
+    def mockHealthChecksWebClient = Mock(WebClient)
 
-    @Autowired
-    DmiRestClient objectUnderTest
+    def mockRequestBody = Mock(WebClient.RequestBodyUriSpec)
+    def mockResponse = Mock(WebClient.ResponseSpec)
 
-    @SpringBean
-    WebClient mockWebClient = Mock(WebClient);
+    def responseBody = [message: 'Success']
+    def mockDmiProperties = Mock(DmiProperties)
 
-    @SpringBean
     JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
 
-    def mockRequestBodyUriSpec = Mock(WebClient.RequestBodyUriSpec)
-    def mockResponseSpec = Mock(WebClient.ResponseSpec)
-    def mockResponseEntity = Mock(ResponseEntity)
+    DmiRestClient objectUnderTest = new DmiRestClient(mockDmiProperties, jsonObjectMapper, mockDataServicesWebClient, mockModelServicesWebClient, mockHealthChecksWebClient)
 
     def setup() {
-        mockRequestBodyUriSpec.uri(_) >> mockRequestBodyUriSpec
-        mockRequestBodyUriSpec.headers(_) >> mockRequestBodyUriSpec
-        mockRequestBodyUriSpec.retrieve() >> mockResponseSpec
+        mockRequestBody.uri(_) >> mockRequestBody
+        mockRequestBody.headers(_) >> mockRequestBody
+        mockRequestBody.body(_) >> mockRequestBody
+        mockRequestBody.retrieve() >> mockResponse
     }
 
-    def 'DMI POST operation with JSON.'() {
+    def 'DMI POST Operation with JSON for status #httpStatusCode'() {
         given: 'the web client returns a valid response entity for the expected parameters'
-            mockWebClient.post() >> mockRequestBodyUriSpec
-            mockRequestBodyUriSpec.body(_) >> mockRequestBodyUriSpec
-            def monoSpec = Mono.just(mockResponseEntity)
-            mockResponseSpec.bodyToMono(Object.class) >>  monoSpec
-            monoSpec.block() >> mockResponseEntity
+            mockDataServicesWebClient.post() >> mockRequestBody
+            mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>(responseBody, httpStatusCode))
         when: 'POST operation is invoked'
-            def response = objectUnderTest.postOperationWithJsonData('/my/url', 'some json', READ, null)
+            def response = objectUnderTest.postOperationWithJsonData(DATA, '/my/url', 'some json', READ, NO_AUTH_HEADER)
         then: 'the output of the method is equal to the output from the test template'
-            assert response.statusCode.value() == 200
-            assert response.hasBody()
+            assert response.statusCode == httpStatusCode
+            assert response.body == responseBody
+        where: 'the following status codes are used'
+            httpStatusCode << [HttpStatus.OK, HttpStatus.CREATED, HttpStatus.ACCEPTED]
     }
 
     def 'Failing DMI POST operation for server error'() {
         given: 'the web client throws an exception'
-            mockWebClient.post() >> { throw new HttpServerErrorException(SERVICE_UNAVAILABLE, null, null, null) }
+            mockDataServicesWebClient.post() >> { throw new HttpServerErrorException(SERVICE_UNAVAILABLE, null, null, null) }
         when: 'POST operation is invoked'
-            objectUnderTest.postOperationWithJsonData('/some', 'some json', READ, null)
+            objectUnderTest.postOperationWithJsonData(DATA, '/some', 'some json', READ, NO_AUTH_HEADER)
         then: 'a http client exception is thrown'
             def thrown = thrown(DmiClientRequestException)
         and: 'the exception has the relevant details from the error response'
-            assert thrown.ncmpResponseStatus.code == '102'
-            assert thrown.httpStatusCode == 503
+            thrown.ncmpResponseStatus.code == '102'
+            thrown.httpStatusCode == 503
     }
 
     def 'Failing DMI POST operation due to invalid dmi resource url.'() {
         when: 'POST operation is invoked with invalid dmi resource url'
-            objectUnderTest.postOperationWithJsonData('/invalid dmi url', null, null, null)
+            objectUnderTest.postOperationWithJsonData(DATA, '/invalid dmi url', null, null, NO_AUTH_HEADER)
         then: 'invalid dmi resource url exception is thrown'
             def thrown = thrown(InvalidDmiResourceUrlException)
         and: 'the exception has the relevant details from the error response'
-            assert thrown.httpStatus == 400
-            assert thrown.message == 'Invalid dmi resource url: /invalid dmi url'
+            thrown.httpStatus == 400
+            thrown.message == 'Invalid dmi resource url: /invalid dmi url'
         where: 'the following operations are executed'
             operation << [CREATE, READ, PATCH]
     }
 
     def 'Dmi service sends client error response when #scenario'() {
         given: 'the web client unable to return response entity but error'
-            mockWebClient.post() >> mockRequestBodyUriSpec
-            mockRequestBodyUriSpec.body(_) >> mockRequestBodyUriSpec
-            def monoSpec = Mono.error(new WebClientResponseException('message', httpStatusCode, null, null, null, null))
-            mockResponseSpec.bodyToMono(Object.class) >>  monoSpec
+            mockDataServicesWebClient.post() >> mockRequestBody
+            mockResponse.toEntity(Object.class) >> Mono.error(exceptionType)
         when: 'POST operation is invoked'
-            objectUnderTest.postOperationWithJsonData('/my/url', 'some json', READ, null)
+            objectUnderTest.postOperationWithJsonData(DATA, '/my/url', 'some json', READ, NO_AUTH_HEADER)
         then: 'a http client exception is thrown'
             def thrown = thrown(DmiClientRequestException)
         and: 'the exception has the relevant details from the error response'
-            assert thrown.ncmpResponseStatus.code == expectedNcmpResponseStatusCode
+            assert thrown.ncmpResponseStatus == expectedNcmpResponseStatusCode
             assert thrown.httpStatusCode == httpStatusCode
         where: 'the following errors occur'
-            scenario              | httpStatusCode | expectedNcmpResponseStatusCode
-            'dmi request timeout' | 408            | DMI_SERVICE_NOT_RESPONDING.code
-            'other error code'    | 500            | UNABLE_TO_READ_RESOURCE_DATA.code
+            scenario                  | httpStatusCode | exceptionType                                                                                    || expectedNcmpResponseStatusCode
+            'dmi service unavailable' | 503            | new WebClientRequestException(new RuntimeException('some-error'), null, null, new HttpHeaders()) || DMI_SERVICE_NOT_RESPONDING
+            'dmi request timeout'     | 408            | new WebClientResponseException('message', httpStatusCode, 'statusText', null, null, null)        || DMI_SERVICE_NOT_RESPONDING
+            'dmi server error'        | 500            | new WebClientResponseException('message', httpStatusCode, 'statusText', null, null, null)        || UNABLE_TO_READ_RESOURCE_DATA
+            'unknown error'           | 500            | new Throwable('message')                                                                         || UNKNOWN_ERROR
     }
 
     def 'Dmi trust level is determined by spring boot health status'() {
@@ -141,19 +136,18 @@
             def dmiPluginHealthCheckResponseJsonData = TestUtils.getResourceFileContent('dmiPluginHealthCheckResponse.json')
             def jsonNode = jsonObjectMapper.convertJsonString(dmiPluginHealthCheckResponseJsonData, JsonNode.class)
             ((ObjectNode) jsonNode).put('status', 'my status')
-            def monoResponse = Mono.just(jsonNode)
-            mockWebClient.get() >> mockRequestBodyUriSpec
-            mockResponseSpec.bodyToMono(_) >> monoResponse
-            monoResponse.block() >> jsonNode
+            mockHealthChecksWebClient.get() >> mockRequestBody
+            mockResponse.bodyToMono(JsonNode.class) >> Mono.just(jsonNode)
         when: 'get trust level of the dmi plugin'
             def result = objectUnderTest.getDmiHealthStatus('some/url')
-        then: 'the status value from the json is return'
+        then: 'the status value from the json is returned'
             assert result == 'my status'
     }
 
     def 'Failing to get dmi plugin health status #scenario'() {
         given: 'rest template with #scenario'
-            mockWebClient.get() >> healthStatusResponse
+            mockHealthChecksWebClient.get() >> mockRequestBody
+            mockResponse.bodyToMono(_) >> healthStatusResponse
         when: 'attempt to get health status of the dmi plugin'
             def result = objectUnderTest.getDmiHealthStatus('some url')
         then: 'result will be empty'
@@ -161,15 +155,18 @@
         where: 'the following responses are used'
             scenario    | healthStatusResponse
             'null'      | null
-            'exception' | {throw new Exception()}
+            'exception' | { throw new Exception() }
     }
 
     def 'DMI auth header #scenario'() {
         when: 'Specific dmi properties are provided'
-            dmiProperties.dmiBasicAuthEnabled = authEnabled
+            mockDmiProperties.dmiBasicAuthEnabled >> authEnabled
+            mockDmiProperties.authUsername >> 'some user'
+            mockDmiProperties.authPassword >> 'some password'
         then: 'http headers to conditionally have Authorization header'
-            def authHeaderValues = objectUnderTest.configureHttpHeaders(new HttpHeaders(), ncmpAuthHeader).getOrEmpty('Authorization')
-            def outputAuthHeader = (authHeaderValues == null ? null : authHeaderValues[0])
+            def httpHeaders = new HttpHeaders()
+            objectUnderTest.configureHttpHeaders(httpHeaders, ncmpAuthHeader)
+            def outputAuthHeader = (httpHeaders.Authorization == null ? null : httpHeaders.Authorization[0])
             assert outputAuthHeader == expectedAuthHeader
         where: 'the following configurations are used'
             scenario                                          | authEnabled | ncmpAuthHeader     || expectedAuthHeader
@@ -179,4 +176,4 @@
             'DMI basic auth disabled, with NCMP bearer token' | false       | BEARER_AUTH_HEADER || BEARER_AUTH_HEADER
             'DMI basic auth disabled, with NCMP basic auth'   | false       | BASIC_AUTH_HEADER  || NO_AUTH_HEADER
     }
-}
+}
\ No newline at end of file
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy
index ee7ab3f..05ecaa1 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy
@@ -29,7 +29,7 @@
 
 @SpringBootTest
 @ContextConfiguration(classes = [HttpClientConfiguration])
-@TestPropertySource(properties = ['ncmp.dmi.httpclient.connectionTimeoutInSeconds=1', 'ncmp.dmi.httpclient.maximumInMemorySizeInMegabytes=1'])
+@TestPropertySource(properties = ['ncmp.dmi.httpclient.data-services.connectionTimeoutInSeconds=1', 'ncmp.dmi.httpclient.model-services.maximumInMemorySizeInMegabytes=1'])
 @EnableConfigurationProperties
 class DmiWebClientConfigurationSpec extends Specification {
 
@@ -42,11 +42,27 @@
             new DmiWebClientConfiguration(httpClientConfiguration) != null
     }
 
-    def 'Creating a WebClient instance.'() {
-        given: 'WebClient configuration invoked'
-            def webClientInstance = objectUnderTest.webClient()
-        expect: 'the system can create an instance'
-            assert webClientInstance != null
-            assert webClientInstance instanceof WebClient
+    def 'Creating a web client instance data service.'() {
+        given: 'Web client configuration is invoked'
+            def dataServicesWebClient = objectUnderTest.dataServicesWebClient()
+        expect: 'the system can create an instance for data service'
+            assert dataServicesWebClient != null
+            assert dataServicesWebClient instanceof WebClient
+    }
+
+    def 'Creating a web client instance model service.'() {
+        given: 'Web client configuration invoked'
+            def modelServicesWebClient = objectUnderTest.modelServicesWebClient()
+        expect: 'the system can create an instance for model service'
+            assert modelServicesWebClient != null
+            assert modelServicesWebClient instanceof WebClient
+    }
+
+    def 'Creating a web client instance health service.'() {
+        given: 'Web client configuration invoked'
+            def healthChecksWebClient = objectUnderTest.healthChecksWebClient()
+        expect: 'the system can create an instance for health service'
+            assert healthChecksWebClient != null
+            assert healthChecksWebClient instanceof WebClient
     }
 }
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy
index 4ede360..b7ced23 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy
@@ -30,18 +30,42 @@
 @SpringBootTest
 @ContextConfiguration(classes = [HttpClientConfiguration])
 @EnableConfigurationProperties(HttpClientConfiguration.class)
-@TestPropertySource(properties = ["ncmp.dmi.httpclient.readTimeoutInSeconds=123", "ncmp.dmi.httpclient.maximumConnectionsTotal=200"])
+@TestPropertySource(properties = ["ncmp.dmi.httpclient.data-services.readTimeoutInSeconds=789", "ncmp.dmi.httpclient.model-services.maximumConnectionsTotal=111"])
 class HttpClientConfigurationSpec extends Specification {
 
     @Autowired
     private HttpClientConfiguration httpClientConfiguration
 
-    def 'Test HttpClientConfiguration properties with custom and default values'() {
-        expect: 'properties are populated correctly'
-            assert httpClientConfiguration.connectionTimeoutInSeconds == 123
-            assert httpClientConfiguration.readTimeoutInSeconds == 123
-            assert httpClientConfiguration.writeTimeoutInSeconds == 30
-            assert httpClientConfiguration.maximumConnectionsTotal == 200
-            assert httpClientConfiguration.maximumInMemorySizeInMegabytes == 16
+    def 'Test http client configuration properties of data with custom and default values'() {
+        expect: 'properties are populated correctly for data'
+            with(httpClientConfiguration.dataServices) {
+                assert connectionTimeoutInSeconds == 123
+                assert readTimeoutInSeconds == 789
+                assert writeTimeoutInSeconds == 30
+                assert maximumConnectionsTotal == 100
+                assert maximumInMemorySizeInMegabytes == 7
+            }
+    }
+
+    def 'Test http client configuration properties of model with custom and default values'() {
+        expect: 'properties are populated correctly for model'
+            with(httpClientConfiguration.modelServices) {
+                assert connectionTimeoutInSeconds == 456
+                assert readTimeoutInSeconds == 30
+                assert writeTimeoutInSeconds == 30
+                assert maximumConnectionsTotal == 111
+                assert maximumInMemorySizeInMegabytes == 8
+            }
+    }
+
+    def 'Test http client configuration properties of health with default values'() {
+        expect: 'properties are populated correctly for health'
+            with(httpClientConfiguration.healthCheckServices) {
+                assert connectionTimeoutInSeconds == 30
+                assert readTimeoutInSeconds == 30
+                assert writeTimeoutInSeconds == 30
+                assert maximumConnectionsTotal == 10
+                assert maximumInMemorySizeInMegabytes == 1
+            }
     }
 }
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
index a84e134..ad3f85c 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
@@ -21,15 +21,14 @@
 
 package org.onap.cps.ncmp.api.impl.operations
 
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
 import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
 import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
 import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
+import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
 
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.onap.cps.events.EventsPublisher
@@ -40,6 +39,7 @@
 import org.onap.cps.ncmp.api.models.CmResourceAddress
 import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent
 import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
 import org.onap.cps.utils.JsonObjectMapper
 import org.spockframework.spring.SpringBean
 import org.springframework.beans.factory.annotation.Autowired
@@ -77,7 +77,7 @@
             def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
             def expectedUrl = "${dmiServiceBaseUrl}${expectedDatastoreInUrl}?resourceIdentifier=${resourceIdentifier}${expectedOptionsInUrl}"
             def expectedJson = '{"operation":"read","cmHandleProperties":'  + expectedProperties + ',"moduleSetTag":""}'
-            mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi
+            mockDmiRestClient.postOperationWithJsonData(DATA, expectedUrl, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi
         when: 'get resource data is invoked'
             def cmResourceAddress = new CmResourceAddress(dataStore.datastoreName, cmHandleId, resourceIdentifier)
             def result = objectUnderTest.getResourceDataFromDmi(cmResourceAddress, options, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER)
@@ -103,11 +103,11 @@
             def responseFromDmi = new ResponseEntity<Object>(HttpStatus.ACCEPTED)
             def expectedDmiBatchResourceDataUrl = "someServiceName/dmi/v1/data?requestId=requestId&topic=my-topic-name"
             def expectedBatchRequestAsJson = '{"operations":[{"operation":"read","operationId":"operational-14","datastore":"ncmp-datastore:passthrough-operational","options":"some option","resourceIdentifier":"some resource identifier","cmHandles":[{"id":"some-cm-handle","moduleSetTag":"","cmHandleProperties":{"prop1":"val1"}}]}]}'
-            mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, _, READ.operationName, NO_AUTH_HEADER) >> responseFromDmi
+            mockDmiRestClient.postOperationWithJsonData(DATA, expectedDmiBatchResourceDataUrl, _, READ, NO_AUTH_HEADER) >> responseFromDmi
         when: 'get resource data for group of cm handles are invoked'
             objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId', NO_AUTH_HEADER)
         then: 'the post operation was called and ncmp generated dmi request body json args'
-            1 * mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, expectedBatchRequestAsJson, READ, NO_AUTH_HEADER)
+            1 * mockDmiRestClient.postOperationWithJsonData(DATA, expectedDmiBatchResourceDataUrl, expectedBatchRequestAsJson, READ, NO_AUTH_HEADER)
     }
 
     def 'Execute (async) data operation from DMI service with Exception.'() {
@@ -139,7 +139,7 @@
             def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
             def expectedUrl = dmiServiceBaseUrl + "passthrough-operational?resourceIdentifier=/"
             def expectedJson = '{"operation":"read","cmHandleProperties":{"prop1":"val1"},"moduleSetTag":"my-module-set-tag"}'
-            mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, READ, null) >> responseFromDmi
+            mockDmiRestClient.postOperationWithJsonData(DATA, expectedUrl, expectedJson, READ, null) >> responseFromDmi
         when: 'get resource data is invoked'
             def result = objectUnderTest.getResourceDataFromDmi( PASSTHROUGH_OPERATIONAL.datastoreName, cmHandleId, NO_REQUEST_ID)
         then: 'the result is the response from the DMI service'
@@ -153,7 +153,7 @@
             def expectedUrl = "${dmiServiceBaseUrl}passthrough-running?resourceIdentifier=${resourceIdentifier}"
             def expectedJson = '{"operation":"' + expectedOperationInUrl + '","dataType":"some data type","data":"requestData","cmHandleProperties":{"prop1":"val1"},"moduleSetTag":""}'
             def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
-            mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, operation, NO_AUTH_HEADER) >> responseFromDmi
+            mockDmiRestClient.postOperationWithJsonData(DATA, expectedUrl, expectedJson, operation, NO_AUTH_HEADER) >> responseFromDmi
         when: 'write resource method is invoked'
             def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId, 'parent/child', operation, 'requestData', 'some data type', NO_AUTH_HEADER)
         then: 'the result is the response from the DMI service'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
index de5e15e..db7f26f 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
@@ -21,6 +21,9 @@
 
 package org.onap.cps.ncmp.api.impl.operations
 
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
+import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL
+
 import com.fasterxml.jackson.core.JsonProcessingException
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.onap.cps.ncmp.api.impl.config.DmiProperties
@@ -34,8 +37,6 @@
 import org.springframework.test.context.ContextConfiguration
 import spock.lang.Shared
 
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
-
 @SpringBootTest
 @ContextConfiguration(classes = [DmiProperties, DmiModelOperations])
 class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
@@ -58,7 +59,7 @@
             def moduleReferencesAsLisOfMaps = [[moduleName: 'mod1', revision: 'A'], [moduleName: 'mod2', revision: 'X']]
             def expectedUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules"
             def responseFromDmi = new ResponseEntity([schemas: moduleReferencesAsLisOfMaps], HttpStatus.OK)
-            mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"cmHandleProperties":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
+            mockDmiRestClient.postOperationWithJsonData(MODEL, expectedUrl, '{"cmHandleProperties":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
         when: 'get module references is called'
             def result = objectUnderTest.getModuleReferences(yangModelCmHandle)
         then: 'the result consists of expected module references'
@@ -89,7 +90,7 @@
             mockYangModelCmHandleRetrieval(dmiProperties)
         and: 'a positive response from DMI service when it is called with tha expected parameters'
             def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK)
-            mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules",
+            mockDmiRestClient.postOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules",
                     '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + ',"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
         when: 'a get module references is called'
             def result = objectUnderTest.getModuleReferences(yangModelCmHandle)
@@ -108,7 +109,7 @@
             def responseFromDmi = new ResponseEntity([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source'],
                                                       [moduleName: 'mod2', revision: 'C', yangSource: 'other yang source']], HttpStatus.OK)
             def expectedModuleReferencesInRequest = '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
-            mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
+            mockDmiRestClient.postOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
                     '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi
         when: 'get new yang resources from DMI service'
             def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences)
@@ -140,7 +141,7 @@
             mockYangModelCmHandleRetrieval(dmiProperties)
         and: 'a positive response from DMI service when it is called with the expected moduleSetTag, modules and properties'
             def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
-            mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
+            mockDmiRestClient.postOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
                     '{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}',
                     READ, NO_AUTH_HEADER) >> responseFromDmi
         when: 'get new yang resources from DMI service'
@@ -158,9 +159,9 @@
             mockYangModelCmHandleRetrieval([], moduleSetTag)
         and: 'a positive response from DMI service when it is called with the expected moduleSetTag'
             def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
-            mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
-                '{' + expectedModuleSetTagInRequest + '"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":{}}',
-                READ, NO_AUTH_HEADER) >> responseFromDmi
+            mockDmiRestClient.postOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
+                    '{' + expectedModuleSetTagInRequest + '"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":{}}',
+                    READ, NO_AUTH_HEADER) >> responseFromDmi
         when: 'get new yang resources from DMI service'
             def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences)
         then: 'the result is the response from DMI service'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy
index b7fa449..ee11716 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy
@@ -1,3 +1,23 @@
+/*
+ * ============LICENSE_START========================================================
+ * Copyright (c) 2023-2024 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an 'AS IS' BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
 package org.onap.cps.ncmp.api.impl.utils.context
 
 import com.fasterxml.jackson.databind.ObjectMapper
diff --git a/cps-ncmp-service/src/test/resources/application.yml b/cps-ncmp-service/src/test/resources/application.yml
index 2a93f40..e35f471 100644
--- a/cps-ncmp-service/src/test/resources/application.yml
+++ b/cps-ncmp-service/src/test/resources/application.yml
@@ -37,8 +37,12 @@
 ncmp:
     dmi:
         httpclient:
-            connectionTimeoutInSeconds: 123
-            maximumInMemorySizeInMegabytes: 16
+            data-services:
+                connectionTimeoutInSeconds: 123
+                maximumInMemorySizeInMegabytes: 7
+            model-services:
+                connectionTimeoutInSeconds: 456
+                maximumInMemorySizeInMegabytes: 8
         auth:
             username: some-user
             password: some-password