Delete DataNode (xpath) for a given Anchor 45/125545/1
authorDylanB95EST <dylan.byrne@est.tech>
Tue, 2 Nov 2021 17:25:18 +0000 (17:25 +0000)
committerDylanB95EST <dylan.byrne@est.tech>
Tue, 2 Nov 2021 17:25:23 +0000 (17:25 +0000)
Delete Datanode within CPS. Deprecates delete functionality of
/v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes.
New api is backwards compatible with this API

Issue-ID: CPS-313
Change-Id: I110c4ab1446e8a1399a0d9bf89c0be614a9104df
Signed-off-by: DylanB95EST <dylan.byrne@est.tech>
cps-rest/docs/openapi/cpsData.yml
cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy

index ca21df5..2b65ae4 100644 (file)
@@ -103,6 +103,7 @@ listElementByDataspaceAndAnchor:
 
   delete:
     description: Delete one or all list element(s) for a given anchor and dataspace
+    deprecated: true
     tags:
       - cps-data
     summary: Delete one or all list element(s)
@@ -177,6 +178,28 @@ nodesByDataspaceAndAnchor:
       '403':
         $ref: 'components.yml#/components/responses/Forbidden'
 
+  delete:
+    description: Delete a datanode for a given dataspace and anchor given a node xpath.
+    tags:
+      - cps-data
+    summary: Delete a data node
+    operationId: deleteDataNode
+    parameters:
+      - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+      - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+      - $ref: 'components.yml#/components/parameters/xpathInQuery'
+      - $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+    responses:
+      '204':
+        $ref: 'components.yml#/components/responses/NoContent'
+      '400':
+        $ref: 'components.yml#/components/responses/BadRequest'
+      '401':
+        $ref: 'components.yml#/components/responses/Unauthorized'
+      '403':
+        $ref: 'components.yml#/components/responses/Forbidden'
+
+
   put:
     description: Replace a node with descendants for a given dataspace, anchor and a parent node xpath
     tags:
index f29ead9..e57fb3c 100755 (executable)
@@ -59,6 +59,14 @@ public class DataRestController implements CpsDataApi {
         return new ResponseEntity<>(HttpStatus.CREATED);
     }
 
+    @Override
+    public ResponseEntity<Void> deleteDataNode(final String dataspaceName, final String anchorName,
+                                               final String xpath, final String observedTimestamp) {
+        cpsDataService.deleteDataNode(dataspaceName, anchorName, xpath,
+            toOffsetDateTime(observedTimestamp));
+        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+    }
+
     @Override
     public ResponseEntity<String> addListElements(final String parentNodeXpath,
         final String dataspaceName, final String anchorName, final String jsonData, final String observedTimestamp) {
index 06f2f57..2c28834 100755 (executable)
@@ -342,4 +342,26 @@ class DataRestControllerSpec extends Specification {
             'without observed-timestamp'      | null                           || 1                | HttpStatus.NO_CONTENT
             'with invalid observed-timestamp' | 'invalid'                      || 0                | HttpStatus.BAD_REQUEST
     }
+
+    def 'Delete data node #scenario.'() {
+        given: 'data node xpath'
+            def dataNodeXpath = '/dataNodeXpath'
+        when: 'delete data node endpoint is invoked'
+            def deleteDataNodeRequest = delete( "$dataNodeBaseEndpoint/anchors/$anchorName/nodes")
+                .param('xpath', dataNodeXpath)
+        and: 'observed timestamp is added to the parameters'
+            if (observedTimestamp != null)
+                deleteDataNodeRequest.param('observed-timestamp', observedTimestamp)
+            def response = mvc.perform(deleteDataNodeRequest).andReturn().response
+        then: 'a successful response is returned'
+            response.status == expectedHttpStatus.value()
+        and: 'the api is called with the correct parameters'
+            expectedApiCount * mockCpsDataService.deleteDataNode(dataspaceName, anchorName, dataNodeXpath,
+                { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) })
+        where:
+            scenario                            | observedTimestamp                 || expectedApiCount | expectedHttpStatus
+            'with observed timestamp'           | '2021-03-03T23:59:59.999-0400'    || 1                | HttpStatus.NO_CONTENT
+            'without observed timestamp'        | null                              || 1                | HttpStatus.NO_CONTENT
+            'with invalid observed timestamp'   | 'invalid'                         || 0                | HttpStatus.BAD_REQUEST
+    }
 }
index e6cb65f..f455e47 100644 (file)
@@ -119,6 +119,17 @@ public interface CpsDataService {
     void replaceListContent(@NonNull String dataspaceName, @NonNull String anchorName, @NonNull String parentNodeXpath,
                             @NonNull String jsonData, OffsetDateTime observedTimestamp);
 
+    /**
+     * Deletes data node for given anchor and dataspace.
+     *
+     * @param dataspaceName dataspace name
+     * @param anchorName anchor name
+     * @param dataNodeXpath data node xpath
+     * @param observedTimestamp observed timestamp
+     */
+    void deleteDataNode(@NonNull String dataspaceName, @NonNull String anchorName, @NonNull String dataNodeXpath,
+                        OffsetDateTime observedTimestamp);
+
     /**
      * Deletes a list or a list-element under given anchor and dataspace.
      *
index 44a17f8..1445cca 100755 (executable)
@@ -133,6 +133,13 @@ public class CpsDataServiceImpl implements CpsDataService {
         processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
     }
 
+    @Override
+    public void deleteDataNode(final String dataspaceName, final String anchorName, final String dataNodeXpath,
+                               final OffsetDateTime observedTimestamp) {
+        cpsDataPersistenceService.deleteDataNode(dataspaceName, anchorName, dataNodeXpath);
+        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
+    }
+
     @Override
     public void deleteListOrListElement(final String dataspaceName, final String anchorName, final String listNodeXpath,
         final OffsetDateTime observedTimestamp) {
index 2bd4482..ba9c156 100644 (file)
@@ -227,6 +227,17 @@ class CpsDataServiceImplSpec extends Specification {
             1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
     }
 
+    def 'Delete data node under anchor and dataspace.'() {
+        given: 'schema set for given anchor and dataspace references test tree model'
+            setupSchemaSetMocks('test-tree.yang')
+        when: 'delete data node method is invoked with correct parameters'
+            objectUnderTest.deleteDataNode(dataspaceName, anchorName, '/data-node', observedTimestamp)
+        then: 'the persistence service method is invoked with the correct parameters'
+            1 * mockCpsDataPersistenceService.deleteDataNode(dataspaceName, anchorName, '/data-node')
+        and: 'data updated event is sent to notification service'
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
+    }
+
     def setupSchemaSetMocks(String... yangResources) {
         def anchor = Anchor.builder().name(anchorName).schemaSetName(schemaSetName).build()
         mockCpsAdminService.getAnchor(dataspaceName, anchorName) >> anchor