API versioning supported and added different versions for POST APIs
[cps.git] / cps-ri / src / test / groovy / org / onap / cps / spi / impl / CpsDataPersistenceServiceSpec.groovy
index 1bbf358..e69cbee 100644 (file)
@@ -24,8 +24,7 @@ import org.hibernate.StaleStateException
 import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.entities.AnchorEntity
 import org.onap.cps.spi.entities.FragmentEntity
-import org.onap.cps.spi.entities.SchemaSetEntity
-import org.onap.cps.spi.entities.YangResourceEntity
+import org.onap.cps.spi.entities.FragmentExtract
 import org.onap.cps.spi.exceptions.ConcurrencyException
 import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.spi.model.DataNode
@@ -35,7 +34,6 @@ import org.onap.cps.spi.repository.DataspaceRepository
 import org.onap.cps.spi.repository.FragmentRepository
 import org.onap.cps.spi.utils.SessionManager
 import org.onap.cps.utils.JsonObjectMapper
-import spock.lang.Shared
 import spock.lang.Specification
 
 class CpsDataPersistenceServiceSpec extends Specification {
@@ -46,27 +44,7 @@ class CpsDataPersistenceServiceSpec extends Specification {
     def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
     def mockSessionManager = Mock(SessionManager)
 
-    def objectUnderTest = new CpsDataPersistenceServiceImpl(
-            mockDataspaceRepository, mockAnchorRepository, mockFragmentRepository, jsonObjectMapper,mockSessionManager)
-
-    @Shared
-    def NEW_RESOURCE_CONTENT = 'module stores {\n' +
-            '    yang-version 1.1;\n' +
-            '    namespace "org:onap:ccsdk:sample";\n' +
-            '\n' +
-            '    prefix book-store;\n' +
-            '\n' +
-            '    revision "2020-09-15" {\n' +
-            '        description\n' +
-            '        "Sample Model";\n' +
-            '    }' +
-            '}'
-
-    @Shared
-    def yangResourceSet = [new YangResourceEntity(moduleName: 'moduleName', content: NEW_RESOURCE_CONTENT,
-            fileName: 'sampleYangResource'
-    )] as Set
-
+    def objectUnderTest = new CpsDataPersistenceServiceImpl(mockDataspaceRepository, mockAnchorRepository, mockFragmentRepository, jsonObjectMapper, mockSessionManager)
 
     def 'Handling of StaleStateException (caused by concurrent updates) during update data node and descendants.'() {
         given: 'the fragment repository returns a fragment entity'
@@ -86,26 +64,30 @@ class CpsDataPersistenceServiceSpec extends Specification {
             assert concurrencyException.getDetails().contains('/some/xpath')
     }
 
-    def 'Handling of StaleStateException (caused by concurrent updates) during  update data nodes and descendants.'() {
-        given: 'the fragment repository returns a list of fragment entities'
-            mockFragmentRepository.getByDataspaceAndAnchorAndXpath(*_) >> new FragmentEntity()
-        and: 'a data node is concurrently updated by another transaction'
+    def 'Handling of StaleStateException (caused by concurrent updates) during update data nodes and descendants.'() {
+        given: 'the system contains and can update one datanode'
+            def dataNode1 = mockDataNodeAndFragmentEntity('/node1', 'OK')
+        and: 'the system contains two more datanodes that throw an exception while updating'
+            def dataNode2 = mockDataNodeAndFragmentEntity('/node2', 'EXCEPTION')
+            def dataNode3 = mockDataNodeAndFragmentEntity('/node3', 'EXCEPTION')
+        and: 'the batch update will therefore also fail'
             mockFragmentRepository.saveAll(*_) >> { throw new StaleStateException("concurrent updates") }
-        when: 'attempt to update data node with submitted data nodes'
-            objectUnderTest.updateDataNodesAndDescendants('some-dataspace', 'some-anchor', [])
+        when: 'attempt batch update data nodes'
+            objectUnderTest.updateDataNodesAndDescendants('some-dataspace', 'some-anchor', [dataNode1, dataNode2, dataNode3])
         then: 'concurrency exception is thrown'
-            def concurrencyException = thrown(ConcurrencyException)
-            assert concurrencyException.getDetails().contains('some-dataspace')
-            assert concurrencyException.getDetails().contains('some-anchor')
+            def thrown = thrown(ConcurrencyException)
+            assert thrown.message == 'Concurrent Transactions'
+        and: 'it does not contain the successfull datanode'
+            assert !thrown.details.contains('/node1')
+        and: 'it contains the failed datanodes'
+            assert thrown.details.contains('/node2')
+            assert thrown.details.contains('/node3')
     }
 
+
     def 'Retrieving a data node with a property JSON value of #scenario'() {
-        given: 'a fragment with a property JSON value of #scenario'
-        mockFragmentRepository.getByDataspaceAndAnchorAndXpath(*_) >> {
-            new FragmentEntity(childFragments: Collections.emptySet(),
-                    attributes: "{\"some attribute\": ${dataString}}",
-                    anchor: new AnchorEntity(schemaSet: new SchemaSetEntity(yangResources: yangResourceSet )))
-        }
+        given: 'the db has a fragment with an attribute property JSON value of #scenario'
+            mockFragmentWithJson("{\"some attribute\": ${dataString}}")
         when: 'getting the data node represented by this fragment'
             def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor',
                     '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
@@ -129,9 +111,7 @@ class CpsDataPersistenceServiceSpec extends Specification {
 
     def 'Retrieving a data node with invalid JSON'() {
         given: 'a fragment with invalid JSON'
-            mockFragmentRepository.getByDataspaceAndAnchorAndXpath(*_) >> {
-                new FragmentEntity(childFragments: Collections.emptySet(), attributes: '{invalid json')
-            }
+            mockFragmentWithJson('{invalid json')
         when: 'getting the data node represented by this fragment'
             objectUnderTest.getDataNode('my-dataspace', 'my-anchor',
                     '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
@@ -193,4 +173,27 @@ class CpsDataPersistenceServiceSpec extends Specification {
                 assert fragmentEntities.size() == 2
             }})
     }
-}
\ No newline at end of file
+
+    def mockDataNodeAndFragmentEntity(xpath, scenario) {
+        def dataNode = new DataNodeBuilder().withXpath(xpath).build()
+        def fragmentEntity = new FragmentEntity(xpath: xpath, childFragments: [])
+        mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, xpath) >> fragmentEntity
+        if ('EXCEPTION' == scenario) {
+            mockFragmentRepository.save(fragmentEntity) >> { throw new StaleStateException("concurrent updates") }
+        }
+        return dataNode
+    }
+
+    def mockFragmentWithJson(json) {
+        def anchorName = 'some anchor'
+        def mockAnchor = Mock(AnchorEntity)
+        mockAnchor.getId() >> 123
+        mockAnchor.getName() >> anchorName
+        mockAnchorRepository.getByDataspaceAndName(*_) >> mockAnchor
+        def mockFragmentExtract = Mock(FragmentExtract)
+        mockFragmentExtract.getId() >> 456
+        mockFragmentExtract.getAttributes() >> json
+        mockFragmentRepository.findByAnchorIdAndParentXpath(*_) >> [mockFragmentExtract]
+    }
+
+}