aboutsummaryrefslogtreecommitdiffstats
path: root/cps-ncmp-service/src/test/groovy/org/onap
diff options
context:
space:
mode:
Diffstat (limited to 'cps-ncmp-service/src/test/groovy/org/onap')
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy124
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy52
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy19
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy70
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy2
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy41
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy6
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy29
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy23
10 files changed, 207 insertions, 163 deletions
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 c8e34b1a5..d2dce06b0 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
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation
+ * Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,28 +21,33 @@
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.impl.operations.OperationType.CREATE
+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
+
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.NcmpConfiguration
-import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration.DmiProperties;
-import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException
+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.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.HttpEntity
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.client.RestTemplate
+import org.springframework.web.reactive.function.client.WebClient
+import reactor.core.publisher.Mono
import spock.lang.Specification
-
-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.impl.operations.OperationType.CREATE
+import org.springframework.web.reactive.function.client.WebClientResponseException
+import org.onap.cps.ncmp.api.impl.config.DmiProperties
@SpringBootTest
@ContextConfiguration(classes = [DmiProperties, DmiRestClient, ObjectMapper])
@@ -52,61 +57,103 @@ class DmiRestClientSpec extends Specification {
static final BASIC_AUTH_HEADER = 'Basic c29tZS11c2VyOnNvbWUtcGFzc3dvcmQ='
static final BEARER_AUTH_HEADER = 'Bearer my-bearer-token'
- @SpringBean
- RestTemplate mockRestTemplate = Mock(RestTemplate)
-
@Autowired
- NcmpConfiguration.DmiProperties dmiProperties
+ DmiProperties dmiProperties
@Autowired
DmiRestClient objectUnderTest
- @Autowired
- ObjectMapper objectMapper
+ @SpringBean
+ WebClient mockWebClient = Mock(WebClient);
- def responseFromRestTemplate = Mock(ResponseEntity)
+ @SpringBean
+ JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+
+ def mockRequestBodyUriSpec = Mock(WebClient.RequestBodyUriSpec)
+ def mockResponseSpec = Mock(WebClient.ResponseSpec)
+ def mockResponseEntity = Mock(ResponseEntity)
+
+ def setup() {
+ mockRequestBodyUriSpec.uri(_) >> mockRequestBodyUriSpec
+ mockRequestBodyUriSpec.headers(_) >> mockRequestBodyUriSpec
+ mockRequestBodyUriSpec.retrieve() >> mockResponseSpec
+ }
def 'DMI POST operation with JSON.'() {
- given: 'the rest template returns a valid response entity for the expected parameters'
- mockRestTemplate.postForEntity('my url', _ as HttpEntity, Object.class) >> responseFromRestTemplate
+ 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
when: 'POST operation is invoked'
- def result = objectUnderTest.postOperationWithJsonData('my url', 'some json', READ, null)
+ def response = objectUnderTest.postOperationWithJsonData('/my/url', 'some json', READ, null)
then: 'the output of the method is equal to the output from the test template'
- result == responseFromRestTemplate
+ assert response.statusCode.value() == 200
+ assert response.hasBody()
}
- def 'Failing DMI POST operation.'() {
- given: 'the rest template returns a valid response entity'
- def serverResponse = 'server response'.getBytes()
- def httpServerErrorException = new HttpServerErrorException(HttpStatus.FORBIDDEN, 'status text', serverResponse, null)
- mockRestTemplate.postForEntity(*_) >> { throw httpServerErrorException }
+ 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) }
when: 'POST operation is invoked'
- def result = objectUnderTest.postOperationWithJsonData('some url', 'some json', operation, null)
- then: 'a Http Client Exception is thrown'
- def thrown = thrown(HttpClientRequestException)
+ objectUnderTest.postOperationWithJsonData('/some', 'some json', READ, null)
+ 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
+ }
+
+ 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)
+ 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 == 403
- assert thrown.message == "Unable to ${operation} resource data."
- assert thrown.details == 'server response'
- where: 'the following operation is executed'
+ assert thrown.httpStatus == 400
+ assert 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
+ when: 'POST operation is invoked'
+ objectUnderTest.postOperationWithJsonData('/my/url', 'some json', READ, null)
+ 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.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
+ }
+
def 'Dmi trust level is determined by spring boot health status'() {
given: 'a health check response'
def dmiPluginHealthCheckResponseJsonData = TestUtils.getResourceFileContent('dmiPluginHealthCheckResponse.json')
- def jsonNode = objectMapper.readValue(dmiPluginHealthCheckResponseJsonData, JsonNode.class)
+ def jsonNode = jsonObjectMapper.convertJsonString(dmiPluginHealthCheckResponseJsonData, JsonNode.class)
((ObjectNode) jsonNode).put('status', 'my status')
- mockRestTemplate.getForObject(*_) >> {jsonNode}
+ def monoResponse = Mono.just(jsonNode)
+ mockWebClient.get() >> mockRequestBodyUriSpec
+ mockResponseSpec.bodyToMono(_) >> monoResponse
+ monoResponse.block() >> jsonNode
when: 'get trust level of the dmi plugin'
- def result = objectUnderTest.getDmiHealthStatus('some url')
+ def result = objectUnderTest.getDmiHealthStatus('some/url')
then: 'the status value from the json is return'
assert result == 'my status'
}
def 'Failing to get dmi plugin health status #scenario'() {
given: 'rest template with #scenario'
- mockRestTemplate.getForObject(*_) >> healthStatusResponse
+ mockWebClient.get() >> healthStatusResponse
when: 'attempt to get health status of the dmi plugin'
def result = objectUnderTest.getDmiHealthStatus('some url')
then: 'result will be empty'
@@ -132,5 +179,4 @@ class DmiRestClientSpec extends Specification {
'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
}
-
}
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
new file mode 100644
index 000000000..ee7ab3f28
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 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.config
+
+import org.springframework.boot.context.properties.EnableConfigurationProperties
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.ContextConfiguration
+import org.springframework.test.context.TestPropertySource
+import org.springframework.web.reactive.function.client.WebClient
+import spock.lang.Specification
+
+@SpringBootTest
+@ContextConfiguration(classes = [HttpClientConfiguration])
+@TestPropertySource(properties = ['ncmp.dmi.httpclient.connectionTimeoutInSeconds=1', 'ncmp.dmi.httpclient.maximumInMemorySizeInMegabytes=1'])
+@EnableConfigurationProperties
+class DmiWebClientConfigurationSpec extends Specification {
+
+ def httpClientConfiguration = Spy(HttpClientConfiguration.class)
+
+ def objectUnderTest = new DmiWebClientConfiguration(httpClientConfiguration)
+
+ def 'Web Client Configuration construction.'() {
+ expect: 'the system can create an instance'
+ 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
+ }
+}
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 2c76b5bb4..4ede360e6 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
@@ -1,6 +1,6 @@
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation.
+ * 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.
@@ -17,32 +17,31 @@
* SPDX-License-Identifier: Apache-2.0
* ============LICENSE_END=========================================================
*/
+
package org.onap.cps.ncmp.api.impl.config
-import java.time.Duration
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.TestPropertySource
-import org.springframework.test.context.support.AnnotationConfigContextLoader
import spock.lang.Specification
@SpringBootTest
@ContextConfiguration(classes = [HttpClientConfiguration])
@EnableConfigurationProperties(HttpClientConfiguration.class)
-@TestPropertySource(properties = ["ncmp.dmi.httpclient.connectionTimeoutInSeconds=1", "ncmp.dmi.httpclient.maximumConnectionsTotal=200"])
+@TestPropertySource(properties = ["ncmp.dmi.httpclient.readTimeoutInSeconds=123", "ncmp.dmi.httpclient.maximumConnectionsTotal=200"])
class HttpClientConfigurationSpec extends Specification {
@Autowired
private HttpClientConfiguration httpClientConfiguration
def 'Test HttpClientConfiguration properties with custom and default values'() {
- expect: 'custom property values'
- assert httpClientConfiguration.getConnectionTimeoutInSeconds() == Duration.ofSeconds(1)
- assert httpClientConfiguration.getMaximumConnectionsTotal() == 200
- and: 'default property values'
- assert httpClientConfiguration.getMaximumConnectionsPerRoute() == 50
- assert httpClientConfiguration.getIdleConnectionEvictionThresholdInSeconds() == Duration.ofSeconds(5)
+ 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
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy
deleted file mode 100644
index 74e342405..000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 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.config
-
-import org.apache.hc.client5.http.impl.classic.CloseableHttpClient
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.boot.web.client.RestTemplateBuilder
-import org.springframework.http.MediaType
-import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
-import org.springframework.test.context.ContextConfiguration
-import org.springframework.web.client.RestTemplate
-import spock.lang.Specification
-
-@SpringBootTest
-@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, HttpClientConfiguration])
-class NcmpConfigurationSpec extends Specification{
-
- @Autowired
- NcmpConfiguration.DmiProperties dmiProperties
-
- @Autowired
- HttpClientConfiguration httpClientConfiguration
-
- def mockRestTemplateBuilder = new RestTemplateBuilder()
-
- def 'NcmpConfiguration Construction.'() {
- expect: 'the system can create an instance'
- new NcmpConfiguration() != null
- }
-
- def 'DMI Properties.'() {
- expect: 'properties are set to values in test configuration yaml file'
- dmiProperties.authUsername == 'some-user'
- dmiProperties.authPassword == 'some-password'
- }
-
- def 'Rest Template creation with CloseableHttpClient and MappingJackson2HttpMessageConverter.'() {
- when: 'a rest template is created'
- def result = NcmpConfiguration.restTemplate(mockRestTemplateBuilder, httpClientConfiguration)
- then: 'the rest template is returned'
- assert result instanceof RestTemplate
- and: 'the rest template is created with httpclient5'
- assert result.getRequestFactory() instanceof HttpComponentsClientHttpRequestFactory
- assert ((HttpComponentsClientHttpRequestFactory) result.getRequestFactory()).getHttpClient() instanceof CloseableHttpClient;
- and: 'a jackson media converter has been added'
- def lastMessageConverter = result.getMessageConverters().get(result.getMessageConverters().size()-1)
- lastMessageConverter instanceof MappingJackson2HttpMessageConverter
- and: 'the jackson media converters supports the expected media types'
- lastMessageConverter.getSupportedMediaTypes() == [MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN];
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy
index 9c84c51b2..f07f3c1e6 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy
@@ -72,8 +72,6 @@ class CmNotificationSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpe
.withSource(URI.create('some-resource'))
.withExtension('correlationid', 'test-cmhandle1').build()
def consumerRecord = new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', testCloudEventSent)
- and: 'notifications are enabled'
- objectUnderTest.notificationFeatureEnabled = true
when: 'the valid event is consumed'
objectUnderTest.consumeSubscriptionEvent(consumerRecord)
then: 'an event is logged with level INFO'
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 eb6c7a0f4..d04052f79 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,10 +21,18 @@
package org.onap.cps.ncmp.api.impl.operations
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA
+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 com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
-import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException
+import org.onap.cps.ncmp.api.impl.config.DmiProperties
+import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException
import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder
import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext
import org.onap.cps.ncmp.api.models.DataOperationRequest
@@ -40,19 +48,8 @@ import org.springframework.http.ResponseEntity
import org.springframework.test.context.ContextConfiguration
import spock.lang.Shared
-import java.util.concurrent.TimeoutException
-
-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
-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
-
@SpringBootTest
-@ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext, NcmpConfiguration.DmiProperties, DmiDataOperations])
+@ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext, DmiProperties, DmiDataOperations])
class DmiDataOperationsSpec extends DmiOperationsBaseSpec {
@SpringBean
@@ -105,7 +102,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec {
and: 'a positive response from DMI service when it is called with valid request parameters'
def responseFromDmi = new ResponseEntity<Object>(HttpStatus.ACCEPTED)
def expectedDmiBatchResourceDataUrl = "ncmp/v1/data/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","cmHandleProperties":{"prop1":"val1"}}]}]}'
+ 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
dmiServiceUrlBuilder.getDataOperationRequestUrl(_, _) >> expectedDmiBatchResourceDataUrl
when: 'get resource data for group of cm handles are invoked'
@@ -114,26 +111,22 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec {
1 * mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, expectedBatchRequestAsJson, READ, NO_AUTH_HEADER)
}
- def 'Execute (async) data operation from DMI service for #scenario.'() {
+ def 'Execute (async) data operation from DMI service with dmi client exception.'() {
given: 'data operation request body and dmi resource url'
def dmiDataOperation = DmiDataOperation.builder().operationId('some-operation-id').build()
- dmiDataOperation.getCmHandles().add(CmHandle.builder().id('some-cm-handle-id').build())
+ dmiDataOperation.getCmHandles().add(DmiOperationCmHandle.builder().id('some-cm-handle-id').build())
def dmiDataOperationResourceDataUrl = "http://dmi-service-name:dmi-port/dmi/v1/data?topic=my-topic-name&requestId=some-request-id"
def actualDataOperationCloudEvent = null
when: 'exception occurs after sending request to dmi service'
- objectUnderTest.handleTaskCompletionException(new Throwable(exception), dmiDataOperationResourceDataUrl, List.of(dmiDataOperation))
+ objectUnderTest.handleTaskCompletionException(new DmiClientRequestException(123, 'message', 'details', UNABLE_TO_READ_RESOURCE_DATA), dmiDataOperationResourceDataUrl, List.of(dmiDataOperation))
then: 'a cloud event is published'
eventsPublisher.publishCloudEvent('my-topic-name', 'some-request-id', _) >> { args -> actualDataOperationCloudEvent = args[2] }
and: 'the event contains the expected error details'
def eventDataValue = extractDataValue(actualDataOperationCloudEvent)
assert eventDataValue.operationId == dmiDataOperation.operationId
assert eventDataValue.ids == dmiDataOperation.cmHandles.id
- assert eventDataValue.statusCode == responseCode.code
- assert eventDataValue.statusMessage == responseCode.message
- where: 'the following exceptions are occurred'
- scenario | exception || responseCode
- 'http client request exception' | new HttpClientRequestException('error-message', 'error-details', HttpStatus.SERVICE_UNAVAILABLE.value()) || UNABLE_TO_READ_RESOURCE_DATA
- 'timeout exception' | new TimeoutException() || DMI_SERVICE_NOT_RESPONDING
+ assert eventDataValue.statusCode == '103'
+ assert eventDataValue.statusMessage == UNABLE_TO_READ_RESOURCE_DATA.message
}
def 'call get all resource data.'() {
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 9aab46747..88af0479d 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
@@ -23,7 +23,7 @@ package org.onap.cps.ncmp.api.impl.operations
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
+import org.onap.cps.ncmp.api.impl.config.DmiProperties
import org.onap.cps.spi.model.ModuleReference
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
@@ -37,7 +37,7 @@ import spock.lang.Shared
import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
@SpringBootTest
-@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiModelOperations])
+@ContextConfiguration(classes = [DmiProperties, DmiModelOperations])
class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
@Shared
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
index 72a0f2f11..3518440ca 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation
+ * Copyright (C) 2021-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.
@@ -22,7 +22,7 @@ package org.onap.cps.ncmp.api.impl.operations
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.ncmp.api.impl.client.DmiRestClient
-import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
+import org.onap.cps.ncmp.api.impl.config.DmiProperties
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder
import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
@@ -50,7 +50,7 @@ abstract class DmiOperationsBaseSpec extends Specification {
ObjectMapper spyObjectMapper = Spy()
@SpringBean
- DmiServiceUrlBuilder dmiServiceUrlBuilder = new DmiServiceUrlBuilder(new NcmpConfiguration.DmiProperties(), mockCpsValidator)
+ DmiServiceUrlBuilder dmiServiceUrlBuilder = new DmiServiceUrlBuilder(new DmiProperties(), mockCpsValidator)
def yangModelCmHandle = new YangModelCmHandle()
def static dmiServiceName = 'some service name'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
index fbf2c3d78..2c7fa654c 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
@@ -22,10 +22,10 @@ package org.onap.cps.ncmp.api.impl.utils
import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
+import org.onap.cps.ncmp.api.impl.config.DmiProperties
import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService
import org.onap.cps.spi.utils.CpsValidator
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import spock.lang.Specification
@@ -34,7 +34,7 @@ class DmiServiceUrlBuilderSpec extends Specification {
static YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle('dmiServiceName',
'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id'),'my-module-set-tag', 'my-alternate-id', 'my-data-producer-identifier')
- NcmpConfiguration.DmiProperties dmiProperties = new NcmpConfiguration.DmiProperties()
+ DmiProperties dmiProperties = new DmiProperties()
def mockCpsValidator = Mock(CpsValidator)
@@ -48,17 +48,19 @@ class DmiServiceUrlBuilderSpec extends Specification {
given: 'uri variables'
def uriVars = objectUnderTest.populateUriVariables(PASSTHROUGH_RUNNING.datastoreName, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), 'cmHandle')
and: 'query params'
- def uriQueries = objectUnderTest.populateQueryParams(resourceId, 'optionsParamInQuery', topic)
+ def uriQueries = objectUnderTest.populateQueryParams(resourceId, 'optionsParamInQuery', topic, moduleSetTag)
when: 'a dmi datastore service url is generated'
def dmiServiceUrl = objectUnderTest.getDmiDatastoreUrl(uriQueries, uriVars)
then: 'service url is generated as expected'
assert dmiServiceUrl == expectedDmiServiceUrl
where: 'the following parameters are used'
- scenario | topic | resourceId || expectedDmiServiceUrl
- 'With valid resourceId' | 'topicParamInQuery' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
- 'With Empty resourceId' | 'topicParamInQuery' | '' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?options=optionsParamInQuery&topic=topicParamInQuery'
- 'With Empty dmi base path' | 'topicParamInQuery' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
- 'With Empty topicParamInQuery' | '' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery'
+ scenario | topic | moduleSetTag | resourceId || expectedDmiServiceUrl
+ 'With valid resourceId' | 'topicParamInQuery' | '' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
+ 'With Empty resourceId' | 'topicParamInQuery' | '' | '' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?options=optionsParamInQuery&topic=topicParamInQuery'
+ 'With valid moduleSetTag' | 'topicParamInQuery' | 'module-set-tag1' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery&moduleSetTag=module-set-tag1'
+ 'With Empty moduleSetTag' | 'topicParamInQuery' | '' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
+ 'With Empty dmi base path' | 'topicParamInQuery' | '' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
+ 'With Empty topicParamInQuery' | '' | '' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery'
}
def 'Populate dmi data store url #scenario.'() {
@@ -66,15 +68,16 @@ class DmiServiceUrlBuilderSpec extends Specification {
dmiProperties.dmiBasePath = dmiBasePath
def uriVars = objectUnderTest.populateUriVariables(PASSTHROUGH_RUNNING.datastoreName, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), 'cmHandle')
and: 'null query params'
- def uriQueries = objectUnderTest.populateQueryParams(null, null, null)
+ def uriQueries = objectUnderTest.populateQueryParams(null, null, null, null)
when: 'a dmi datastore service url is generated'
def dmiServiceUrl = objectUnderTest.getDmiDatastoreUrl(uriQueries, uriVars)
then: 'the created dmi service url matches the expected'
assert dmiServiceUrl == expectedDmiServiceUrl
where: 'the following parameters are used'
- scenario | decription | dmiBasePath || expectedDmiServiceUrl
- 'with base path / ' | 'Invalid base path as it starts with /' | '/dmi' || 'dmiServiceName//dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running'
- 'without base path / ' | 'Valid path as it does not starts with /' | 'dmi' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running'
+ scenario | decription | dmiBasePath || expectedDmiServiceUrl
+ 'base path starts with /' | 'Remove / from start of base path' | '/dmi' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running'
+ 'base path ends with / ' | 'Remove / from end of base path' | 'dmi/' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running'
+ 'base path without any / ' | 'base path does not contains any /' | 'dmi' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running'
}
def 'Bath request Url creation.'() {
@@ -85,7 +88,7 @@ class DmiServiceUrlBuilderSpec extends Specification {
when: 'a URL is created'
def result = objectUnderTest.getDataOperationRequestUrl(batchRequestQueryParams, batchRequestUriVariables)
then: 'it is formed correctly'
- assert result.toString() == 'some-service/testBase/v1/data?topic=some topic&requestId=some id'
+ assert result.toString() == 'some-service/testBase/v1/data?topic=some+topic&requestId=some+id'
}
def 'Populate batch uri variables.'() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy
index 8df27bb62..9028b9e5e 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy
@@ -90,6 +90,23 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
'dmi2' | 2 || 'operational-15' | 'ncmp-datastore:passthrough-operational' | ['ch4-dmi2']
}
+ def 'Process one data operation request with #serviceName and Module Set Tag set.'() {
+ given: 'data operation request'
+ def dataOperationRequestJsonData = TestUtils.getResourceFileContent('dataOperationRequest.json')
+ def dataOperationRequest = jsonObjectMapper.convertJsonString(dataOperationRequestJsonData, DataOperationRequest.class)
+ and: '1 known cm handles: ch1-dmi1'
+ def yangModelCmHandles = getYangModelCmHandlesForOneCmHandle()
+ when: 'data operation request is processed'
+ def operationsOutPerDmiServiceName = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(clientTopic,'request-id', dataOperationRequest, yangModelCmHandles)
+ and: 'converted to a json node'
+ def dmiDataOperationRequestBody = operationsOutPerDmiServiceName['dmi1']
+ def cmHandlesInRequestBody = dmiDataOperationRequestBody[0].cmHandles
+ then: 'it contains the correct operation details'
+ assert cmHandlesInRequestBody.size() == 1
+ assert cmHandlesInRequestBody[0].id == 'ch1-dmi1'
+ assert cmHandlesInRequestBody[0].moduleSetTag == 'module-set-tag1'
+ }
+
def 'Process per data operation request with non-ready, non-existing cm handle and publish event to client specified topic'() {
given: 'consumer subscribing to client topic'
def cloudEventKafkaConsumer = new KafkaConsumer<>(eventConsumerConfigProperties('test-1', CloudEventDeserializer))
@@ -156,4 +173,10 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
new YangModelCmHandle(id: 'non-ready-cm-handle', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: advisedState)
]
}
+
+ static def getYangModelCmHandlesForOneCmHandle() {
+ def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
+ def readyState = new CompositeStateBuilder().withCmHandleState(CmHandleState.READY).withLastUpdatedTimeNow().build()
+ return [new YangModelCmHandle(id: 'ch1-dmi1', dmiServiceName: 'dmi1', moduleSetTag: 'module-set-tag1', dmiProperties: dmiProperties, compositeState: readyState)]
+ }
}