Handle invalid operations on merged datastore endpoint 51/130751/4
authorbmiklos <miklos.baranyak@est.tech>
Mon, 5 Sep 2022 16:25:46 +0000 (18:25 +0200)
committerbmiklos <miklos.baranyak@est.tech>
Wed, 7 Sep 2022 10:07:40 +0000 (12:07 +0200)
- Move the other endpoints under the same thats handling the get
- Add exceptions to handle invalid cases
- Add new tests for testing the invalid cases

Issue-ID: CPS-1001
Issue-ID: CPS-1219
Change-Id: I26fd57b5921f976cde7089b4cf1e8c0e5d8dc43b
Signed-off-by: bmiklos <miklos.baranyak@est.tech>
cps-ncmp-rest-stub/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
cps-ncmp-rest/docs/openapi/ncmp.yml
cps-ncmp-rest/docs/openapi/openapi.yml
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/DatastoreType.java
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/InvalidDatastoreException.java [new file with mode: 0644]
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy

index ac5337d..bb919b5 100644 (file)
@@ -57,13 +57,13 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi {
     private String pathToResponseFiles;
 
     @Override
-    public ResponseEntity<Object> getResourceDataForCmHandle(final String dataStoreType,
+    public ResponseEntity<Object> getResourceDataForCmHandle(final String dataStoreName,
                                                              final String cmHandle,
                                                              final String resourceIdentifier,
                                                              final String optionsParamInQuery,
                                                              final String topicParamInQuery,
                                                              final Boolean includeDescendants) {
-        if (DatastoreType.PASSTHROUGH_OPERATIONAL == DatastoreType.fromDatastoreName(dataStoreType)) {
+        if (DatastoreType.PASSTHROUGH_OPERATIONAL == DatastoreType.fromDatastoreName(dataStoreName)) {
             final ResponseEntity<Map<String, Object>> asyncResponse = populateAsyncResponse(topicParamInQuery);
             final Map<String, Object> asyncResponseData = asyncResponse.getBody();
             Object responseObject = null;
@@ -87,7 +87,8 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi {
     }
 
     @Override
-    public ResponseEntity<Void> createResourceDataRunningForCmHandle(final String resourceIdentifier,
+    public ResponseEntity<Void> createResourceDataRunningForCmHandle(final String datastoreName,
+                                                                     final String resourceIdentifier,
                                                                      final String cmHandleId,
                                                                      final Object body,
                                                                      final String contentType) {
@@ -95,7 +96,8 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi {
     }
 
     @Override
-    public ResponseEntity<Void> deleteResourceDataRunningForCmHandle(final String cmHandleId,
+    public ResponseEntity<Void> deleteResourceDataRunningForCmHandle(final String datastoreName,
+                                                                     final String cmHandleId,
                                                                      final String resourceIdentifier,
                                                                      final String contentType) {
         return new ResponseEntity<>(HttpStatus.NO_CONTENT);
@@ -152,7 +154,8 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi {
     }
 
     @Override
-    public ResponseEntity<Object> patchResourceDataRunningForCmHandle(final String resourceIdentifier,
+    public ResponseEntity<Object> patchResourceDataRunningForCmHandle(final String datastoreName,
+                                                                      final String resourceIdentifier,
                                                                       final String cmHandleId,
                                                                       final Object body,
                                                                       final String contentType) {
@@ -165,7 +168,8 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi {
     }
 
     @Override
-    public ResponseEntity<Object> updateResourceDataRunningForCmHandle(final String resourceIdentifier,
+    public ResponseEntity<Object> updateResourceDataRunningForCmHandle(final String datastoreName,
+                                                                       final String resourceIdentifier,
                                                                        final String cmHandleId,
                                                                        final Object body,
                                                                        final String contentType) {
index 5e22f77..38db26f 100755 (executable)
@@ -18,7 +18,7 @@
 #  SPDX-License-Identifier: Apache-2.0
 #  ============LICENSE_END=========================================================
 
-getResourceDataForCmHandle:
+resourceDataForCmHandle:
   get:
     tags:
       - network-cm-proxy
@@ -53,7 +53,6 @@ getResourceDataForCmHandle:
       502:
         $ref: 'components.yaml#/components/responses/BadGateway'
 
-resourceDataForPassthroughRunning:
   post:
     tags:
       - network-cm-proxy
@@ -61,6 +60,7 @@ resourceDataForPassthroughRunning:
     description: create resource data from pass-through running for given cm handle
     operationId: createResourceDataRunningForCmHandle
     parameters:
+      - $ref: 'components.yaml#/components/parameters/datastoreName'
       - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
       - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
       - $ref: 'components.yaml#/components/parameters/contentParamInHeader'
@@ -100,6 +100,7 @@ resourceDataForPassthroughRunning:
     description: Update resource data from pass-through running for the given cm handle
     operationId: updateResourceDataRunningForCmHandle
     parameters:
+      - $ref: 'components.yaml#/components/parameters/datastoreName'
       - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
       - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
       - $ref: 'components.yaml#/components/parameters/contentParamInHeader'
@@ -139,6 +140,7 @@ resourceDataForPassthroughRunning:
     description: Patch resource data from pass-through running for the given cm handle
     operationId: patchResourceDataRunningForCmHandle
     parameters:
+      - $ref: 'components.yaml#/components/parameters/datastoreName'
       - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
       - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
       - $ref: 'components.yaml#/components/parameters/contentParamInHeader'
@@ -172,6 +174,7 @@ resourceDataForPassthroughRunning:
     description: Delete resource data from pass-through running for a given cm handle
     operationId: deleteResourceDataRunningForCmHandle
     parameters:
+      - $ref: 'components.yaml#/components/parameters/datastoreName'
       - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
       - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
       - $ref: 'components.yaml#/components/parameters/contentParamInHeader'
index ed15fcd..4c546be 100755 (executable)
@@ -27,10 +27,7 @@ servers:
   - url: /ncmp
 paths:
   /v1/ch/{cm-handle}/data/ds/{ncmp-datastore-name}:
-    $ref: 'ncmp.yml#/getResourceDataForCmHandle'
-
-  /v1/ch/{cm-handle}/data/ds/ncmp-datastore:passthrough-running:
-    $ref: 'ncmp.yml#/resourceDataForPassthroughRunning'
+    $ref: 'ncmp.yml#/resourceDataForCmHandle'
 
   /v1/ch/{cm-handle}/modules:
     $ref: 'ncmp.yml#/fetchModuleReferencesByCmHandle'
index 9aa8263..2f6668a 100755 (executable)
@@ -41,6 +41,7 @@ import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi;
 import org.onap.cps.ncmp.rest.controller.handlers.DatastoreType;
 import org.onap.cps.ncmp.rest.controller.handlers.NcmpDatastoreResourceRequestHandler;
 import org.onap.cps.ncmp.rest.controller.handlers.NcmpDatastoreResourceRequestHandlerFactory;
+import org.onap.cps.ncmp.rest.exceptions.InvalidDatastoreException;
 import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper;
 import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties;
 import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
@@ -98,11 +99,26 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
                 optionsParamInQuery, topicParamInQuery, includeDescendants);
     }
 
+    /**
+     * Patch resource data from passthrough-running.
+     *
+     * @param resourceIdentifier resource identifier
+     * @param datastoreName      name of the datastore
+     * @param cmHandle           cm handle identifier
+     * @param requestBody        the request body
+     * @param contentType        content type of body
+     * @return {@code ResponseEntity} response from dmi plugin
+     */
+
     @Override
     public ResponseEntity<Object> patchResourceDataRunningForCmHandle(final String resourceIdentifier,
+                                                                      final String datastoreName,
                                                                       final String cmHandle,
                                                                       final Object requestBody,
                                                                       final String contentType) {
+
+        acceptPassthroughRunningOnly(datastoreName);
+
         final Object responseObject = networkCmProxyDataService
                 .writeResourceDataPassThroughRunningForCmHandle(
                         cmHandle, resourceIdentifier, PATCH,
@@ -114,6 +130,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
      * Create resource data in datastore pass-through running for given cm-handle.
      *
      * @param resourceIdentifier resource identifier
+     * @param datastoreName      name of the datastore
      * @param cmHandle           cm handle identifier
      * @param requestBody        the request body
      * @param contentType        content type of body
@@ -121,9 +138,13 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
      */
     @Override
     public ResponseEntity<Void> createResourceDataRunningForCmHandle(final String resourceIdentifier,
+                                                                     final String datastoreName,
                                                                      final String cmHandle,
                                                                      final Object requestBody,
                                                                      final String contentType) {
+
+        acceptPassthroughRunningOnly(datastoreName);
+
         networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle,
                 resourceIdentifier, CREATE, jsonObjectMapper.asJsonString(requestBody), contentType);
         return new ResponseEntity<>(HttpStatus.CREATED);
@@ -133,34 +154,43 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
      * Update resource data in datastore pass-through running for given cm-handle.
      *
      * @param resourceIdentifier resource identifier
+     * @param datastoreName      name of the datastore
      * @param cmHandle           cm handle identifier
      * @param requestBody        the request body
      * @param contentType        content type of the body
      * @return response entity
      */
+
     @Override
     public ResponseEntity<Object> updateResourceDataRunningForCmHandle(final String resourceIdentifier,
+                                                                       final String datastoreName,
                                                                        final String cmHandle,
                                                                        final Object requestBody,
                                                                        final String contentType) {
+        acceptPassthroughRunningOnly(datastoreName);
+
         networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle,
                 resourceIdentifier, UPDATE, jsonObjectMapper.asJsonString(requestBody), contentType);
         return new ResponseEntity<>(HttpStatus.OK);
     }
 
-
     /**
      * Delete resource data in datastore pass-through running for a given cm-handle.
      *
-     * @param resourceIdentifier resource identifier
+     * @param datastoreName      name of the datastore
      * @param cmHandle           cm handle identifier
+     * @param resourceIdentifier resource identifier
      * @param contentType        content type of the body
      * @return response entity no content if request is successful
      */
     @Override
-    public ResponseEntity<Void> deleteResourceDataRunningForCmHandle(final String cmHandle,
+    public ResponseEntity<Void> deleteResourceDataRunningForCmHandle(final String datastoreName,
+                                                                     final String cmHandle,
                                                                      final String resourceIdentifier,
                                                                      final String contentType) {
+
+        acceptPassthroughRunningOnly(datastoreName);
+
         networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle,
                 resourceIdentifier, DELETE, NO_BODY, contentType);
         return new ResponseEntity<>(HttpStatus.NO_CONTENT);
@@ -290,6 +320,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
         return new ResponseEntity<>(HttpStatus.OK);
     }
 
+
     private RestOutputCmHandle toRestOutputCmHandle(final NcmpServiceCmHandle ncmpServiceCmHandle) {
         final RestOutputCmHandle restOutputCmHandle = new RestOutputCmHandle();
         final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties();
@@ -301,6 +332,12 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
         return restOutputCmHandle;
     }
 
+    private void acceptPassthroughRunningOnly(final String datastoreName) {
+        final DatastoreType datastoreType = DatastoreType.fromDatastoreName(datastoreName);
 
+        if (DatastoreType.PASSTHROUGH_RUNNING != datastoreType) {
+            throw new InvalidDatastoreException(datastoreName + " is not supported");
+        }
+    }
 }
 
index 959c85d..e8ab997 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import lombok.Getter;
+import org.onap.cps.ncmp.rest.exceptions.InvalidDatastoreException;
 
 @Getter
 public enum DatastoreType {
@@ -45,8 +46,21 @@ public enum DatastoreType {
                 type -> datastoreNameToDatastoreType.put(type.getDatastoreName(), type));
     }
 
+    /**
+     * From datastore name get datastore type.
+     *
+     * @param datastoreName the datastore name
+     * @return the datastore type
+     */
     public static DatastoreType fromDatastoreName(final String datastoreName) {
-        return datastoreNameToDatastoreType.get(datastoreName);
+
+        final DatastoreType datastoreType = datastoreNameToDatastoreType.get(datastoreName);
+
+        if (null == datastoreType) {
+            throw new InvalidDatastoreException(datastoreName + " is an invalid datastore name");
+        }
+
+        return datastoreType;
     }
 
 }
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/InvalidDatastoreException.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/InvalidDatastoreException.java
new file mode 100644 (file)
index 0000000..ff13a93
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.rest.exceptions;
+
+public class InvalidDatastoreException extends RuntimeException {
+    /**
+     * Instantiates a new Invalid datastore exception.
+     *
+     * @param message the message
+     */
+    public InvalidDatastoreException(final String message) {
+        super(message);
+    }
+}
index 98d7f6f..f12a1c5 100755 (executable)
@@ -59,7 +59,7 @@ public class NetworkCmProxyRestExceptionHandler {
      */
     @ExceptionHandler
     public static ResponseEntity<Object> handleInternalServerErrorExceptions(
-        final Exception exception) {
+            final Exception exception) {
         return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception);
     }
 
@@ -74,8 +74,8 @@ public class NetworkCmProxyRestExceptionHandler {
         return wrapDmiErrorResponse(HttpStatus.BAD_GATEWAY, httpClientRequestException);
     }
 
-    @ExceptionHandler({DmiRequestException.class, DataValidationException.class, HttpMessageNotReadableException.class,
-            InvalidTopicException.class})
+    @ExceptionHandler({DmiRequestException.class, DataValidationException.class,
+            HttpMessageNotReadableException.class, InvalidTopicException.class, InvalidDatastoreException.class})
     public static ResponseEntity<Object> handleDmiRequestExceptions(final Exception exception) {
         return buildErrorResponse(HttpStatus.BAD_REQUEST, exception);
     }
@@ -104,7 +104,8 @@ public class NetworkCmProxyRestExceptionHandler {
         return new ResponseEntity<>(errorMessage, status);
     }
 
-    private static ResponseEntity<Object> wrapDmiErrorResponse(final HttpStatus httpStatus,
+    private static ResponseEntity<Object> wrapDmiErrorResponse(
+            final HttpStatus httpStatus,
             final HttpClientRequestException httpClientRequestException) {
         final var dmiErrorMessage = new DmiErrorMessage();
         final var dmiErrorResponse = new DmiErrorMessageDmiresponse();
index 6e461fa..b6194bc 100644 (file)
@@ -51,6 +51,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
 import org.springframework.http.HttpStatus
 import org.springframework.http.MediaType
 import org.springframework.test.web.servlet.MockMvc
+import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder
 import spock.lang.Shared
 import spock.lang.Specification
 
@@ -242,7 +243,6 @@ class NetworkCmProxyControllerSpec extends Specification {
         given: 'resource data url'
             def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" +
                 "?resourceIdentifier=parent/child"
-            def requestBody = '{"some-key":"some-value"}'
         when: 'create resource request is performed'
             def response = mvc.perform(
                 post(url)
@@ -476,38 +476,63 @@ class NetworkCmProxyControllerSpec extends Specification {
             'disabled' | false
     }
 
-    def 'Get Resource Data from operational without descendants.'() {
-        given: 'resource data url'
+    def 'Get Resource Data from operational with or without descendants'() {
+        given: 'resource data url with descendants #enabled'
             def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:operational" +
-                "?resourceIdentifier=parent/child&include-descendants=false"
+                "?resourceIdentifier=parent/child&include-descendants=${enabled}"
         when: 'get data resource request is performed'
             def response = mvc.perform(
                 get(getUrl)
                     .contentType(MediaType.APPLICATION_JSON)
             ).andReturn().response
-        then: 'the NCMP data service is called with getResourceDataOperational'
+        then: 'the NCMP data service is called with getResourceDataOperational with #descendantsOption'
             1 * mockNetworkCmProxyDataService.getResourceDataOperational('testCmHandle',
                 'parent/child',
-                FetchDescendantsOption.OMIT_DESCENDANTS)
+                descendantsOption)
         and: 'response status is Ok'
             response.status == HttpStatus.OK.value()
+        where: 'the following parameters are used'
+            enabled | descendantsOption
+            false   | FetchDescendantsOption.OMIT_DESCENDANTS
+            true    | FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
     }
 
-    def 'Get Resource Data from operational including descendants.'() {
+    def 'Attempt execute #operation rest operation on resource data with #scenario'() {
         given: 'resource data url'
-            def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:operational" +
-                "?resourceIdentifier=parent/child&include-descendants=true"
-        when: 'get data resource request is performed'
+            def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/${datastoreInUrl}?resourceIdentifier=parent/child"
+        when: 'selected request for data resource is performed on url'
             def response = mvc.perform(
-                get(getUrl)
-                    .contentType(MediaType.APPLICATION_JSON)
-            ).andReturn().response
-        then: 'the NCMP data service is called with getResourceDataOperational'
-            1 * mockNetworkCmProxyDataService.getResourceDataOperational('testCmHandle',
-                'parent/child',
-                FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
-        and: 'response status is Ok'
-            response.status == HttpStatus.OK.value()
+                executeRestOperation(operation, url))
+                .andReturn().response
+        then: 'the response status is as expected'
+            assert response.status == HttpStatus.BAD_REQUEST.value()
+        and: 'the response is as expected'
+            assert response.getContentAsString().contains(datastoreInUrl)
+        where: 'the following parameters are used'
+            scenario                | operation | datastoreInUrl
+            'unsupported datastore' | 'POST'    | 'ncmp-datastore:operational'
+            'invalid datastore'     | 'POST'    | 'invalid'
+            'unsupported datastore' | 'PUT'     | 'ncmp-datastore:operational'
+            'invalid datastore'     | 'PUT'     | 'invalid'
+            'unsupported datastore' | 'PATCH'   | 'ncmp-datastore:operational'
+            'invalid datastore'     | 'PATCH'   | 'invalid'
+            'unsupported datastore' | 'DELETE'  | 'ncmp-datastore:operational'
+            'invalid datastore'     | 'DELETE'  | 'invalid'
+    }
+
+    def executeRestOperation(operation, url) {
+        if (operation == 'POST') {
+            return post(url).contentType(MediaType.APPLICATION_JSON_VALUE).content(requestBody)
+        }
+        if (operation == 'PUT') {
+            return put(url).contentType(MediaType.APPLICATION_JSON_VALUE).content(requestBody)
+        }
+        if (operation == 'PATCH') {
+            return patch(url).contentType(MediaType.APPLICATION_JSON_VALUE).content(requestBody)
+        }
+        if (operation == 'DELETE') {
+            return delete(url).contentType(MediaType.APPLICATION_JSON_VALUE)
+        }
     }
 
     def dataStores() {