aboutsummaryrefslogtreecommitdiffstats
path: root/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
diff options
context:
space:
mode:
Diffstat (limited to 'cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy')
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy161
1 files changed, 94 insertions, 67 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 003dbf5b0..2c2212773 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,103 +21,133 @@
package org.onap.cps.ncmp.api.impl.client
+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
+
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.HttpClientRequestException
+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.spockframework.spring.SpringBean
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
-
+import org.onap.cps.utils.JsonObjectMapper
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
-import org.springframework.test.context.ContextConfiguration
-import org.springframework.test.context.TestPropertySource
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 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
-
-@SpringBootTest
-@ContextConfiguration(classes = [DmiWebClientConfiguration, 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
- DmiWebClientConfiguration.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)
- @Autowired
- ObjectMapper objectMapper
+ JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
- def mockRequestBodyUriSpec = Mock(WebClient.RequestBodyUriSpec)
- def mockResponseSpec = Mock(WebClient.ResponseSpec)
- def mockResponseEntity = Mock(ResponseEntity)
- def monoSpec = Mono.just(mockResponseEntity)
- def 'DMI POST operation with JSON.'() {
+ DmiRestClient objectUnderTest = new DmiRestClient(mockDmiProperties, jsonObjectMapper, mockDataServicesWebClient, mockModelServicesWebClient, mockHealthChecksWebClient)
+
+ def setup() {
+ mockRequestBody.uri(_) >> mockRequestBody
+ mockRequestBody.headers(_) >> mockRequestBody
+ mockRequestBody.body(_) >> mockRequestBody
+ mockRequestBody.retrieve() >> mockResponse
+ }
+
+ 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
- mockWebclientResponse()
- mockRequestBodyUriSpec.body(_) >> mockRequestBodyUriSpec
- mockResponseSpec.toEntity(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 result = 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'
- result == mockResponseEntity
+ 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.'() {
- given: 'the rest template returns a valid response entity'
- def serverResponse = 'server response'.getBytes()
- def httpServerErrorException = new HttpServerErrorException(HttpStatus.FORBIDDEN, 'status text', serverResponse, null)
- mockWebClient.post() >> { throw httpServerErrorException }
+ def 'Failing DMI POST operation for server error'() {
+ given: 'the web client throws an exception'
+ mockDataServicesWebClient.post() >> { throw new HttpServerErrorException(SERVICE_UNAVAILABLE, null, null, null) }
when: 'POST operation is invoked'
- def result = objectUnderTest.postOperationWithJsonData('/some', 'some json', operation, null)
- then: 'a Http Client Exception is thrown'
- def thrown = thrown(HttpClientRequestException)
+ 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.httpStatus == 403
- assert thrown.message == "Unable to ${operation} resource data."
- assert thrown.details == 'server response'
- where: 'the following operation is executed'
+ 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(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'
+ 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'
+ mockDataServicesWebClient.post() >> mockRequestBody
+ mockResponse.toEntity(Object.class) >> Mono.error(exceptionType)
+ when: 'POST operation is invoked'
+ 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 == expectedNcmpResponseStatusCode
+ assert thrown.httpStatusCode == httpStatusCode
+ where: 'the following errors occur'
+ 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'() {
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')
- def monoResponse = Mono.just(jsonNode)
- mockWebClient.get() >> mockRequestBodyUriSpec
- mockWebclientResponse()
- 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'
@@ -125,15 +155,18 @@ class DmiRestClientSpec extends Specification {
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
@@ -143,10 +176,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
}
-
- def mockWebclientResponse() {
- mockRequestBodyUriSpec.uri(_) >> mockRequestBodyUriSpec
- mockRequestBodyUriSpec.headers(_) >> mockRequestBodyUriSpec
- mockRequestBodyUriSpec.retrieve() >> mockResponseSpec
- }
-}
+} \ No newline at end of file