summaryrefslogtreecommitdiffstats
path: root/cps-ri/src/test/groovy
diff options
context:
space:
mode:
authorToineSiebelink <toine.siebelink@est.tech>2022-10-20 18:34:29 +0100
committerToine Siebelink <toine.siebelink@est.tech>2022-10-27 10:52:56 +0000
commita096a7faa35b345c765102201a5a09cc03ef541a (patch)
treebcf99d79138ef5f15e681a564ff655da44f26a5a /cps-ri/src/test/groovy
parent321d969c11826ccc3a01f6002cfaae2d0a5a4f9d (diff)
Read Performance Improvement - Using Native Query
- Native query for FragmentExtracts - Convert FragmentExtracts to tree of FragmentEntity - Native Query now used for all Gets with descendants (orignal hibernate option only used when descendanst ommited) - Added error handling for not-found on native query - Ommit descendants by default on many udpate use-cases (this might have a signifcant perf. improvemnt impact too) - Improved legacy tests for delete use-cases - Corrected performace test expectation - Fix TTL test realizing TTL resolution is whole seconds! Issue-ID: CPS-1301 Signed-off-by: ToineSiebelink <toine.siebelink@est.tech> Change-Id: I658ac1b7b7036f01050f30bdf9e5bd175725ef1d
Diffstat (limited to 'cps-ri/src/test/groovy')
-rwxr-xr-xcps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy35
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy53
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsToDataNodePerfSpec.groovy18
3 files changed, 48 insertions, 58 deletions
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
index 5e15ca795f..412c5aa7b9 100755
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
@@ -531,28 +531,25 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
def 'Confirm deletion of #scenario.'() {
given: 'a valid data node'
def dataNode
- def dataNodeXpath
- when: 'data nodes are deleted'
+ and: 'data nodes are deleted'
objectUnderTest.deleteDataNode(DATASPACE_NAME, ANCHOR_NAME3, xpathForDeletion)
- then: 'verify data nodes are removed'
- try {
- dataNode = objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_NAME3, getDataNodesXpaths, INCLUDE_ALL_DESCENDANTS)
- dataNodeXpath = dataNode.xpath
- assert dataNodeXpath == expectedXpaths
- } catch (DataNodeNotFoundException) {
- assert dataNodeXpath == expectedXpaths
+ when: 'verify data nodes are removed'
+ objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_NAME3, xpathForDeletion, INCLUDE_ALL_DESCENDANTS)
+ then:
+ thrown(DataNodeNotFoundException)
+ and: 'some related object is not deleted'
+ if (xpathSurvivor!=null) {
+ dataNode = objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_NAME3, xpathSurvivor, INCLUDE_ALL_DESCENDANTS)
+ assert dataNode.xpath == xpathSurvivor
}
where: 'following parameters were used'
- scenario | xpathForDeletion | getDataNodesXpaths || expectedXpaths
- 'child of target' | '/parent-206/child-206' | '/parent-206/child-206' || null
- 'child data node, parent still exists' | '/parent-206/child-206' | '/parent-206' || '/parent-206'
- 'list element' | '/parent-206/child-206/grand-child-206[@key="A"]' | '/parent-206/child-206/grand-child-206[@key="A"]' || null
- 'list element, sibling still exists' | '/parent-206/child-206/grand-child-206[@key="A"]' | '/parent-206/child-206/grand-child-206[@key="X"]' || "/parent-206/child-206/grand-child-206[@key='X']"
- 'container node' | '/parent-206' | '/parent-206' || null
- 'container list node' | '/parent-206[@key="A"]' | '/parent-206[@key="B"]' || "/parent-206[@key='B']"
- 'root node with xpath /' | '/' | '/' || null
- 'root node with xpath passed as blank' | '' | '' || null
-
+ scenario | xpathForDeletion || xpathSurvivor
+ 'child data node, parent still exists' | '/parent-206/child-206' || '/parent-206'
+ 'list element, sibling still exists' | '/parent-206/child-206/grand-child-206[@key="A"]' || "/parent-206/child-206/grand-child-206[@key='X']"
+ 'container node' | '/parent-206' || null
+ 'container list node' | '/parent-206[@key="A"]' || "/parent-206[@key='B']"
+ 'root node with xpath /' | '/' || null
+ 'root node with xpath passed as blank' | '' || null
}
@Sql([CLEAR_DATA, SET_DATA])
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
index 3b15b7607f..b124925aa8 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
@@ -25,8 +25,7 @@ import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.cache.AnchorDataCacheEntry
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
@@ -52,25 +51,6 @@ class CpsDataPersistenceServiceSpec extends Specification {
def objectUnderTest = new CpsDataPersistenceServiceImpl(
mockDataspaceRepository, mockAnchorRepository, mockFragmentRepository, jsonObjectMapper, mockSessionManager, mockAnchorDataCache)
- @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 'Handling of StaleStateException (caused by concurrent updates) during update data node and descendants.'() {
given: 'the fragment repository returns a fragment entity'
mockFragmentRepository.getByDataspaceAndAnchorAndXpath(*_) >> {
@@ -107,16 +87,12 @@ class CpsDataPersistenceServiceSpec extends Specification {
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)
@@ -140,9 +116,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)
@@ -214,4 +188,21 @@ class CpsDataPersistenceServiceSpec extends Specification {
}
return dataNode
}
+
+ def mockFragmentWithJson(json) {
+ def anchorName = 'some anchor'
+ def anchorDataCacheEntry = new AnchorDataCacheEntry()
+ anchorDataCacheEntry.setProperty(objectUnderTest.TOP_LEVEL_MODULE_PREFIX_PROPERTY_NAME, 'some prefix')
+ mockAnchorDataCache.containsKey(anchorName) >> true
+ mockAnchorDataCache.get(anchorName) >> anchorDataCacheEntry
+ 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]
+ }
+
}
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsToDataNodePerfSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsToDataNodePerfSpec.groovy
index 5b28028133..283be6b9b8 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsToDataNodePerfSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsToDataNodePerfSpec.groovy
@@ -22,20 +22,23 @@ package org.onap.cps.ri.performance
import org.apache.commons.lang3.time.StopWatch
import org.onap.cps.spi.CpsDataPersistenceService
+import org.onap.cps.spi.impl.CpsDataPersistenceServiceImpl
import org.onap.cps.spi.impl.CpsPersistenceSpecBase
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.DataNodeBuilder
+import org.onap.cps.spi.repository.FragmentRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.jdbc.Sql
import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
class CpsToDataNodePerfSpec extends CpsPersistenceSpecBase {
+ static final String SET_DATA = '/data/fragment.sql'
+
@Autowired
CpsDataPersistenceService objectUnderTest
- static final String SET_DATA = '/data/fragment.sql'
- static final String XPATH_DATA_NODE_WITH_DESCENDANTS = '/parent-1'
+ def XPATH_DATA_NODE_WITH_DESCENDANTS = '/parent-1'
@Sql([CLEAR_DATA, SET_DATA])
def 'Get data node by xpath with all descendants with many children'() {
@@ -48,14 +51,13 @@ class CpsToDataNodePerfSpec extends CpsPersistenceSpecBase {
when: 'data node is requested with all descendants'
def readStopWatch = new StopWatch()
readStopWatch.start()
- def result = objectUnderTest.getDataNode(
- DATASPACE_NAME, ANCHOR_NAME1, XPATH_DATA_NODE_WITH_DESCENDANTS, INCLUDE_ALL_DESCENDANTS)
+ def result = objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_NAME1, XPATH_DATA_NODE_WITH_DESCENDANTS, INCLUDE_ALL_DESCENDANTS)
readStopWatch.stop()
def readDurationInMillis = readStopWatch.getTime()
- then : 'setup duration is under 8 seconds'
+ then: 'setup duration is under 8 seconds'
assert setupDurationInMillis < 8000
- and: 'read duration is under 6 seconds'
- assert readDurationInMillis < 6000
+ and: 'read duration is under 1500 milliseconds'
+ assert readDurationInMillis < 1500
and: 'data node is returned with all the descendants populated'
assert countDataNodes(result) == 1533
}
@@ -86,4 +88,4 @@ class CpsToDataNodePerfSpec extends CpsPersistenceSpecBase {
}
return nodeCount
}
-} \ No newline at end of file
+}