Bug: ProvMnS error handling returning all DMI error responses as 500 56/142456/1
authorseanbeirne <sean.beirne@est.tech>
Tue, 18 Nov 2025 17:11:17 +0000 (17:11 +0000)
committerseanbeirne <sean.beirne@est.tech>
Wed, 19 Nov 2025 09:36:49 +0000 (09:36 +0000)
Issue-ID: CPS-3048
Change-Id: I9bc30f4f09664c331e396cb4aa18c90be3475f7c
Signed-off-by: seanbeirne <sean.beirne@est.tech>
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiRestClient.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiRestClientIntegrationSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/provmns/ProvMnSRestApiSpec.groovy

index 26f4663..17693a0 100644 (file)
@@ -46,6 +46,7 @@ import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Component;
 import org.springframework.web.reactive.function.BodyInserters;
+import org.springframework.web.reactive.function.client.ClientResponse;
 import org.springframework.web.reactive.function.client.WebClient;
 import org.springframework.web.reactive.function.client.WebClientRequestException;
 import org.springframework.web.reactive.function.client.WebClientResponseException;
@@ -131,8 +132,7 @@ public class DmiRestClient {
             .get()
             .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables())
             .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION))
-            .retrieve()
-            .toEntity(Object.class)
+            .exchangeToMono(this::createIdenticalResponseForClient)
             .block();
     }
 
@@ -152,8 +152,7 @@ public class DmiRestClient {
             .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables())
             .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION))
             .bodyValue(body)
-            .retrieve()
-            .toEntity(Object.class)
+            .exchangeToMono(this::createIdenticalResponseForClient)
             .block();
     }
 
@@ -176,8 +175,7 @@ public class DmiRestClient {
             .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION))
             .contentType(MediaType.parseMediaType(contentType))
             .bodyValue(body)
-            .retrieve()
-            .toEntity(Object.class)
+            .exchangeToMono(this::createIdenticalResponseForClient)
             .block();
     }
 
@@ -226,12 +224,11 @@ public class DmiRestClient {
     }
 
     /**
-     * Sends a synchronous (blocking) DELETE operation to the DMI with a JSON body without error mapping.
+     * Sends a synchronous (blocking) DELETE operation to the DMI without error mapping.
      *
      * @param requiredDmiService    Determines if the required service is for a data or model operation.
      * @param urlTemplateParameters The DMI resource URL template with variables.
-     * @return ResponseEntity from the DMI Plugin
-     * @throws DmiClientRequestException If there is an error during the DMI request.
+     * @return                      ResponseEntity containing the response from the DMI.
      *
      */
     public ResponseEntity<Object> synchronousDeleteOperation(final RequiredDmiService requiredDmiService,
@@ -240,8 +237,7 @@ public class DmiRestClient {
                 .delete()
                 .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables())
                 .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION))
-                .retrieve()
-                .toEntity(Object.class)
+                .exchangeToMono(this::createIdenticalResponseForClient)
                 .block();
     }
 
@@ -276,4 +272,16 @@ public class DmiRestClient {
                 UNKNOWN_ERROR);
     }
 
+    private Mono<ResponseEntity<Object>> createIdenticalResponseForClient(final ClientResponse clientResponse) {
+        final HttpStatus status = (HttpStatus) clientResponse.statusCode();
+        return clientResponse.bodyToMono(String.class)
+            .defaultIfEmpty("")
+            .map(body -> {
+                return ResponseEntity
+                    .status(status)
+                    .headers(clientResponse.headers().asHttpHeaders())
+                    .body(body);
+            });
+    }
+
 }
index f5b9835..ae09fae 100644 (file)
@@ -53,7 +53,7 @@ class DmiRestClientIntegrationSpec extends Specification {
     }
 
     def 'Synchronous DMI #method request.'() {
-        given: 'Web Server wil return OK response'
+        given: 'Web Server will return OK response'
             mockWebServer.enqueue(new MockResponse().setResponseCode(HttpStatus.OK.value))
         when: 'synchronous #method request is made'
             def result
index 698ff1a..78ae3d0 100644 (file)
@@ -38,9 +38,8 @@ class ProvMnSRestApiSpec extends CpsIntegrationSpecBase{
         given: 'a registered cm handle'
             dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
             registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, '/A=1/B=2/C=3')
-        expect: 'not implemented response on GET endpoint'
-            mvc.perform(get("/ProvMnS/v1/A=1/B=2/C=3"))
-                    .andExpect(status().is2xxSuccessful())
+        expect: 'an OK response on GET endpoint'
+            mvc.perform(get("/ProvMnS/v1/A=1/B=2/C=3")).andExpect(status().isOk())
         cleanup: 'deregister CM handles'
             deregisterCmHandle(DMI1_URL, 'ch-1')
     }
@@ -50,7 +49,7 @@ class ProvMnSRestApiSpec extends CpsIntegrationSpecBase{
             dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
             registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, '/A=1/B=2/C=3')
             def jsonBody = jsonObjectMapper.asJsonString(new ResourceOneOf('test'))
-        expect: 'not implemented response on PUT endpoint'
+        expect: 'an OK response on PUT endpoint'
             mvc.perform(put("/ProvMnS/v1/A=1/B=2/C=3")
                     .contentType(MediaType.APPLICATION_JSON)
                     .content(jsonBody))
@@ -64,7 +63,7 @@ class ProvMnSRestApiSpec extends CpsIntegrationSpecBase{
             dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
             registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, '/A=1/B=2/C=3')
             def jsonBody = jsonObjectMapper.asJsonString([new PatchItem(op: 'REMOVE', path: 'someUriLdnFirstPart')])
-        expect: 'not implemented response on PATCH endpoint'
+        expect: 'an OK response on PATCH endpoint'
             mvc.perform(patch("/ProvMnS/v1/A=1/B=2/C=3")
                     .contentType(new MediaType('application', 'json-patch+json'))
                     .content(jsonBody))