CPS-341 Support for multiple data tree instances under 1 anchor
[cps.git] / cps-ri / src / test / groovy / org / onap / cps / spi / impl / CpsDataPersistenceServiceIntegrationSpec.groovy
index fbf414d..12585eb 100755 (executable)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2021-2022 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021-2022 Bell Canada.
+ *  Modifications Copyright (C) 2022 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,7 +27,6 @@ import com.google.common.collect.ImmutableSet
 import org.onap.cps.cpspath.parser.PathParsingException
 import org.onap.cps.spi.CpsDataPersistenceService
 import org.onap.cps.spi.entities.FragmentEntity
-import org.onap.cps.spi.exceptions.AlreadyDefinedException
 import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch
 import org.onap.cps.spi.exceptions.AnchorNotFoundException
 import org.onap.cps.spi.exceptions.CpsAdminException
@@ -48,25 +48,25 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
     @Autowired
     CpsDataPersistenceService objectUnderTest
 
-    static final JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
-    static final DataNodeBuilder dataNodeBuilder = new DataNodeBuilder()
+    static JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+    static DataNodeBuilder dataNodeBuilder = new DataNodeBuilder()
 
     static final String SET_DATA = '/data/fragment.sql'
-    static final int DATASPACE_1001_ID = 1001L
-    static final int ANCHOR_3003_ID = 3003L
-    static final long ID_DATA_NODE_WITH_DESCENDANTS = 4001
-    static final String XPATH_DATA_NODE_WITH_DESCENDANTS = '/parent-1'
-    static final String XPATH_DATA_NODE_WITH_LEAVES = '/parent-207'
-    static final long DATA_NODE_202_FRAGMENT_ID = 4202L
-    static final long CHILD_OF_DATA_NODE_202_FRAGMENT_ID = 4203L
-    static final long LIST_DATA_NODE_PARENT201_FRAGMENT_ID = 4206L
-    static final long LIST_DATA_NODE_PARENT203_FRAGMENT_ID = 4214L
-    static final long LIST_DATA_NODE_PARENT202_FRAGMENT_ID = 4211L
-    static final long PARENT_3_FRAGMENT_ID = 4003L
-
-    static final DataNode newDataNode = new DataNodeBuilder().build()
-    static DataNode existingDataNode
-    static DataNode existingChildDataNode
+    static int DATASPACE_1001_ID = 1001L
+    static int ANCHOR_3003_ID = 3003L
+    static long ID_DATA_NODE_WITH_DESCENDANTS = 4001
+    static String XPATH_DATA_NODE_WITH_DESCENDANTS = '/parent-1'
+    static String XPATH_DATA_NODE_WITH_LEAVES = '/parent-207'
+    static long DATA_NODE_202_FRAGMENT_ID = 4202L
+    static long CHILD_OF_DATA_NODE_202_FRAGMENT_ID = 4203L
+    static long LIST_DATA_NODE_PARENT201_FRAGMENT_ID = 4206L
+    static long LIST_DATA_NODE_PARENT203_FRAGMENT_ID = 4214L
+    static long LIST_DATA_NODE_PARENT202_FRAGMENT_ID = 4211L
+    static long PARENT_3_FRAGMENT_ID = 4003L
+
+    static Collection<DataNode> newDataNodes = [new DataNodeBuilder().build()]
+    static Collection<DataNode> existingDataNodes = [createDataNodeTree(XPATH_DATA_NODE_WITH_DESCENDANTS)]
+    static Collection<DataNode> existingChildDataNodes = [createDataNodeTree('/parent-1/child-1')]
 
     def expectedLeavesByXpathMap = [
             '/parent-207'                      : ['parent-leaf': 'parent-leaf value'],
@@ -75,11 +75,6 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
             '/parent-207/child-002/grand-child': ['grand-child-leaf': 'grand-child-leaf value']
     ]
 
-    static {
-        existingDataNode = createDataNodeTree(XPATH_DATA_NODE_WITH_DESCENDANTS)
-        existingChildDataNode = createDataNodeTree('/parent-1/child-1')
-    }
-
     @Sql([CLEAR_DATA, SET_DATA])
     def 'Get existing datanode with descendants.'() {
         when: 'the node is retrieved by its xpath'
@@ -93,13 +88,13 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
-    def 'Storing and Retrieving a new DataNode with descendants.'() {
+    def 'Storing and Retrieving a new DataNodes with descendants.'() {
         when: 'a fragment with descendants is stored'
             def parentXpath = '/parent-new'
             def childXpath = '/parent-new/child-new'
             def grandChildXpath = '/parent-new/child-new/grandchild-new'
-            objectUnderTest.storeDataNode(DATASPACE_NAME, ANCHOR_NAME1,
-                    createDataNodeTree(parentXpath, childXpath, grandChildXpath))
+            def dataNodes = [createDataNodeTree(parentXpath, childXpath, grandChildXpath)]
+            objectUnderTest.storeDataNodes(DATASPACE_NAME, ANCHOR_NAME1, dataNodes)
         then: 'it can be retrieved by its xpath'
             def dataNode = objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_NAME1, parentXpath, INCLUDE_ALL_DESCENDANTS)
             assert dataNode.xpath == parentXpath
@@ -117,9 +112,9 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
     def 'Store data node for multiple anchors using the same schema.'() {
         def xpath = '/parent-new'
         given: 'a fragment is stored for an anchor'
-            objectUnderTest.storeDataNode(DATASPACE_NAME, ANCHOR_NAME1, createDataNodeTree(xpath))
+            objectUnderTest.storeDataNodes(DATASPACE_NAME, ANCHOR_NAME1, [createDataNodeTree(xpath)])
         when: 'another fragment is stored for an other anchor, using the same schema set'
-            objectUnderTest.storeDataNode(DATASPACE_NAME, ANCHOR_NAME3, createDataNodeTree(xpath))
+            objectUnderTest.storeDataNodes(DATASPACE_NAME, ANCHOR_NAME3, [createDataNodeTree(xpath)])
         then: 'both fragments can be retrieved by their xpath'
             def fragment1 = getFragmentByXpath(DATASPACE_NAME, ANCHOR_NAME1, xpath)
             fragment1.anchor.name == ANCHOR_NAME1
@@ -130,45 +125,48 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
-    def 'Store datanode error scenario: #scenario.'() {
+    def 'Store datanodes error scenario: #scenario.'() {
         when: 'attempt to store a data node with #scenario'
-            objectUnderTest.storeDataNode(dataspaceName, anchorName, dataNode)
+            objectUnderTest.storeDataNodes(dataspaceName, anchorName, dataNodes)
         then: 'a #expectedException is thrown'
             thrown(expectedException)
         where: 'the following data is used'
-            scenario                    | dataspaceName  | anchorName     | dataNode         || expectedException
-            'dataspace does not exist'  | 'unknown'      | 'not-relevant' | newDataNode      || DataspaceNotFoundException
-            'schema set does not exist' | DATASPACE_NAME | 'unknown'      | newDataNode      || AnchorNotFoundException
-            'anchor already exists'     | DATASPACE_NAME | ANCHOR_NAME1   | newDataNode      || ConstraintViolationException
-            'datanode already exists'   | DATASPACE_NAME | ANCHOR_NAME1   | existingDataNode || AlreadyDefinedException
+            scenario                    | dataspaceName  | anchorName     | dataNode         || expectedException
+            'dataspace does not exist'  | 'unknown'      | 'not-relevant' | newDataNode      || DataspaceNotFoundException
+            'schema set does not exist' | DATASPACE_NAME | 'unknown'      | newDataNode      || AnchorNotFoundException
+            'anchor already exists'     | DATASPACE_NAME | ANCHOR_NAME1   | newDataNode      || ConstraintViolationException
+            'datanode already exists'   | DATASPACE_NAME | ANCHOR_NAME1   | existingDataNodes  || AlreadyDefinedExceptionBatch
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
-    def 'Add a child to a Fragment that already has a child.'() {
-        given: ' a new child node'
-            def newChild = createDataNodeTree('xpath for new child')
+    def 'Add children to a Fragment that already has a child.'() {
+        given: 'collection of new child data nodes'
+            def newChild1 = createDataNodeTree('/parent-1/child-2')
+            def newChild2 = createDataNodeTree('/parent-1/child-3')
+            def newChildrenCollection = [newChild1, newChild2]
         when: 'the child is added to an existing parent with 1 child'
-            objectUnderTest.addChildDataNode(DATASPACE_NAME, ANCHOR_NAME1, XPATH_DATA_NODE_WITH_DESCENDANTS, newChild)
-        then: 'the parent is now has to 2 children'
+            objectUnderTest.addChildDataNodes(DATASPACE_NAME, ANCHOR_NAME1, XPATH_DATA_NODE_WITH_DESCENDANTS, newChildrenCollection)
+        then: 'the parent is now has to 3 children'
             def expectedExistingChildPath = '/parent-1/child-1'
             def parentFragment = fragmentRepository.findById(ID_DATA_NODE_WITH_DESCENDANTS).orElseThrow()
-            parentFragment.childFragments.size() == 2
+            parentFragment.childFragments.size() == 3
         and: 'it still has the old child'
             parentFragment.childFragments.find({ it.xpath == expectedExistingChildPath })
-        and: 'it has the new child'
-            parentFragment.childFragments.find({ it.xpath == newChild.xpath })
+        and: 'it has the new children'
+            parentFragment.childFragments.find({ it.xpath == newChildrenCollection[0].xpath })
+            parentFragment.childFragments.find({ it.xpath == newChildrenCollection[1].xpath })
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
     def 'Add child error scenario: #scenario.'() {
         when: 'attempt to add a child data node with #scenario'
-            objectUnderTest.addChildDataNode(DATASPACE_NAME, ANCHOR_NAME1, parentXpath, dataNode)
+            objectUnderTest.addChildDataNodes(DATASPACE_NAME, ANCHOR_NAME1, parentXpath, dataNodes)
         then: 'a #expectedException is thrown'
             thrown(expectedException)
         where: 'the following data is used'
-            scenario                 | parentXpath                      | dataNode              || expectedException
-            'parent does not exist'  | '/unknown'                       | newDataNode           || DataNodeNotFoundException
-            'already existing child' | XPATH_DATA_NODE_WITH_DESCENDANTS | existingChildDataNode || AlreadyDefinedException
+            scenario                 | parentXpath                      | dataNode              || expectedException
+            'parent does not exist'  | '/unknown'                       | newDataNode           || DataNodeNotFoundException
+            'already existing child' | XPATH_DATA_NODE_WITH_DESCENDANTS | existingChildDataNodes  || AlreadyDefinedExceptionBatch
     }
 
     @Sql([CLEAR_DATA, SET_DATA])