summaryrefslogtreecommitdiffstats
path: root/cps-ri/src/test/groovy
diff options
context:
space:
mode:
authordanielhanrahan <daniel.hanrahan@est.tech>2023-03-07 20:35:14 +0000
committerdanielhanrahan <daniel.hanrahan@est.tech>2023-03-13 13:18:02 +0000
commitb8b29c97ee64b395bceb1e100eaf2a6bf115871f (patch)
tree104f7fc9cf9060091dc478c0f48a5dd3d7db517c /cps-ri/src/test/groovy
parent8e08dc797c89f6e85347c10cc7a2e877c126432a (diff)
Reduce dataspace/anchor lookups in CpsDataPersistenceService
- Remove unneeded calls to DataspaceRepository::getByName - Remove unneeded calls to AnchorRepository::getByDataspaceAndName - Refactor FragmentRepository Issue-ID: CPS-1536 Signed-off-by: danielhanrahan <daniel.hanrahan@est.tech> Change-Id: I2121f6247070ee4a7c000e06ec66a6278b758540
Diffstat (limited to 'cps-ri/src/test/groovy')
-rwxr-xr-xcps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy43
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy35
2 files changed, 27 insertions, 51 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 71253278e9..25f19f7a8d 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
@@ -70,13 +70,6 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
def static deleteTestChildXpath = "${deleteTestParentXPath}/child-with-slash[@key='a/b']"
def static deleteTestGrandChildXPath = "${deleteTestChildXpath}/grandChild"
- def expectedLeavesByXpathMap = [
- '/parent-207' : ['parent-leaf': 'parent-leaf value'],
- '/parent-207/child-001' : ['first-child-leaf': 'first-child-leaf value'],
- '/parent-207/child-002' : ['second-child-leaf': 'second-child-leaf value'],
- '/parent-207/child-002/grand-child': ['grand-child-leaf': 'grand-child-leaf value']
- ]
-
@Sql([CLEAR_DATA, SET_DATA])
def 'Get all datanodes with descendants .'() {
when: 'data nodes are retrieved by their xpath'
@@ -187,7 +180,7 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
and: 'the (grand)child node of the new list entry is also present'
def dataspaceEntity = dataspaceRepository.getByName(DATASPACE_NAME)
def anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, ANCHOR_NAME3)
- def grandChildFragmentEntity = fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, grandChild.xpath)
+ def grandChildFragmentEntity = fragmentRepository.findByAnchorAndXpath(anchorEntity, grandChild.xpath)
assert grandChildFragmentEntity.isPresent()
}
@@ -212,7 +205,7 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
and: 'the new entity is inserted correctly'
def dataspaceEntity = dataspaceRepository.getByName(DATASPACE_NAME)
def anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, ANCHOR_HAVING_SINGLE_TOP_LEVEL_FRAGMENT)
- fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, '/parent-200/child-new2').isPresent()
+ fragmentRepository.findByAnchorAndXpath(anchorEntity, '/parent-200/child-new2').isPresent()
}
@Sql([CLEAR_DATA, SET_DATA])
@@ -674,27 +667,27 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
@Sql([CLEAR_DATA, SET_DATA])
def 'Delete data node for an anchor.'() {
given: 'a data-node exists for an anchor'
- assert fragmentsExistInDB(1001, 3003)
+ assert fragmentsExistInDB(3003)
when: 'data nodes are deleted '
objectUnderTest.deleteDataNodes(DATASPACE_NAME, ANCHOR_NAME3)
then: 'all data-nodes are deleted successfully'
- assert !fragmentsExistInDB(1001, 3003)
+ assert !fragmentsExistInDB(3003)
}
@Sql([CLEAR_DATA, SET_DATA])
def 'Delete data node for multiple anchors.'() {
given: 'a data-node exists for an anchor'
- assert fragmentsExistInDB(1001, 3001)
- assert fragmentsExistInDB(1001, 3003)
+ assert fragmentsExistInDB(3001)
+ assert fragmentsExistInDB(3003)
when: 'data nodes are deleted '
objectUnderTest.deleteDataNodes(DATASPACE_NAME, ['ANCHOR-001', 'ANCHOR-003'])
then: 'all data-nodes are deleted successfully'
- assert !fragmentsExistInDB(1001, 3001)
- assert !fragmentsExistInDB(1001, 3003)
+ assert !fragmentsExistInDB(3001)
+ assert !fragmentsExistInDB(3003)
}
- def fragmentsExistInDB(dataSpaceId, anchorId) {
- !fragmentRepository.findRootsByDataspaceAndAnchor(dataSpaceId, anchorId).isEmpty()
+ def fragmentsExistInDB(anchorId) {
+ fragmentRepository.existsByAnchorId(anchorId)
}
static Collection<DataNode> toDataNodes(xpaths) {
@@ -710,19 +703,6 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
return jsonObjectMapper.convertJsonString(fragmentEntity.attributes, Map<String, Object>.class)
}
- def static assertLeavesMaps(actualLeavesMap, expectedLeavesMap) {
- expectedLeavesMap.forEach((key, value) -> {
- def actualValue = actualLeavesMap[key]
- if (value instanceof Collection<?> && actualValue instanceof Collection<?>) {
- assert value.size() == actualValue.size()
- assert value.containsAll(actualValue)
- } else {
- assert value == actualValue
- }
- })
- return true
- }
-
def static treeToFlatMapByXpath(Map<String, DataNode> flatMap, DataNode dataNodeTree) {
flatMap.put(dataNodeTree.xpath, dataNodeTree)
dataNodeTree.childDataNodes
@@ -756,10 +736,9 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
def getFragmentByXpath(dataspaceName, anchorName, xpath) {
def dataspace = dataspaceRepository.getByName(dataspaceName)
def anchor = anchorRepository.getByDataspaceAndName(dataspace, anchorName)
- return fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspace, anchor, xpath).orElseThrow()
+ return fragmentRepository.findByAnchorAndXpath(anchor, xpath).orElseThrow()
}
-
def createChildListAllHavingAttributeValue(parentXpath, tag, Collection keys, boolean addGrandChild) {
def listElementAsDataNodes = keysToXpaths(parentXpath, keys).collect {
new DataNodeBuilder()
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 ba42a083ea..e74b4a7450 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
@@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
import org.hibernate.StaleStateException
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.entities.AnchorEntity
+import org.onap.cps.spi.entities.DataspaceEntity
import org.onap.cps.spi.entities.FragmentEntity
import org.onap.cps.spi.exceptions.ConcurrencyException
import org.onap.cps.spi.exceptions.DataValidationException
@@ -48,6 +49,12 @@ class CpsDataPersistenceServiceSpec extends Specification {
def objectUnderTest = Spy(new CpsDataPersistenceServiceImpl(mockDataspaceRepository, mockAnchorRepository,
mockFragmentRepository, jsonObjectMapper, mockSessionManager))
+ def anchorEntity = new AnchorEntity(id: 123, dataspace: new DataspaceEntity(id: 1))
+
+ def setup() {
+ mockAnchorRepository.getByDataspaceAndName(_, _) >> anchorEntity
+ }
+
def 'Storing data nodes individually when batch operation fails'(){
given: 'two data nodes and supporting repository mock behavior'
def dataNode1 = createDataNodeAndMockRepositoryMethodSupportingIt('xpath1','OK')
@@ -57,7 +64,7 @@ class CpsDataPersistenceServiceSpec extends Specification {
when: 'trying to store data nodes'
objectUnderTest.storeDataNodes('dataSpaceName', 'anchorName', [dataNode1, dataNode2])
then: 'the two data nodes are saved individually'
- 2 * mockFragmentRepository.save(_);
+ 2 * mockFragmentRepository.save(_)
}
def 'Store single data node.'() {
@@ -71,7 +78,7 @@ class CpsDataPersistenceServiceSpec extends Specification {
def 'Handling of StaleStateException (caused by concurrent updates) during update data node and descendants.'() {
given: 'the fragment repository returns a fragment entity'
- mockFragmentRepository.getByDataspaceAndAnchorAndXpath(*_) >> {
+ mockFragmentRepository.getByAnchorAndXpath(*_) >> {
def fragmentEntity = new FragmentEntity()
fragmentEntity.setChildFragments([new FragmentEntity()] as Set<FragmentEntity>)
return fragmentEntity
@@ -93,8 +100,6 @@ class CpsDataPersistenceServiceSpec extends Specification {
'/node1': 'OK',
'/node2': 'EXCEPTION',
'/node3': 'EXCEPTION'])
- and: 'db contains an anchor'
- mockAnchorRepository.getByDataspaceAndName(*_) >> new AnchorEntity(id:123)
and: 'the batch update will therefore also fail'
mockFragmentRepository.saveAll(*_) >> { throw new StaleStateException("concurrent updates") }
when: 'attempt batch update data nodes'
@@ -144,10 +149,7 @@ class CpsDataPersistenceServiceSpec extends Specification {
}
def 'Retrieving multiple data nodes.'() {
- given: 'db contains an anchor'
- def anchorEntity = new AnchorEntity(id:123)
- mockAnchorRepository.getByDataspaceAndName(*_) >> anchorEntity
- and: 'fragment repository returns a collection of fragments'
+ given: 'fragment repository returns a collection of fragments'
def fragmentEntity1 = new FragmentEntity(xpath: '/xpath1', childFragments: [])
def fragmentEntity2 = new FragmentEntity(xpath: '/xpath2', childFragments: [])
mockFragmentRepository.findByAnchorAndMultipleCpsPaths(123, ['/xpath1', '/xpath2'] as Set<String>) >> [fragmentEntity1, fragmentEntity2]
@@ -182,7 +184,7 @@ class CpsDataPersistenceServiceSpec extends Specification {
def 'update data node leaves: #scenario'(){
given: 'A node exists for the given xpath'
- mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, '/some/xpath') >> new FragmentEntity(xpath: '/some/xpath', attributes: existingAttributes)
+ mockFragmentRepository.getByAnchorAndXpath(_, '/some/xpath') >> new FragmentEntity(xpath: '/some/xpath', attributes: existingAttributes)
when: 'the node leaves are updated'
objectUnderTest.updateDataLeaves('some-dataspace', 'some-anchor', '/some/xpath', newAttributes as Map<String, Serializable>)
then: 'the fragment entity saved has the original and new attributes'
@@ -200,8 +202,7 @@ class CpsDataPersistenceServiceSpec extends Specification {
}
def 'update data node and descendants: #scenario'(){
- given: 'mocked responses'
- mockAnchorRepository.getByDataspaceAndName(_, _) >> new AnchorEntity(id:123)
+ given: 'the fragment repository returns fragment entities related to the xpath inputs'
mockFragmentRepository.findByAnchorAndMultipleCpsPaths(_, [] as Set) >> []
mockFragmentRepository.findByAnchorAndMultipleCpsPaths(_, ['/test/xpath'] as Set) >> [new FragmentEntity(xpath: '/test/xpath', childFragments: [])]
when: 'replace data node tree'
@@ -217,10 +218,8 @@ class CpsDataPersistenceServiceSpec extends Specification {
def 'update data nodes and descendants'() {
given: 'the fragment repository returns fragment entities related to the xpath inputs'
mockFragmentRepository.findByAnchorAndMultipleCpsPaths(_, ['/test/xpath1', '/test/xpath2'] as Set) >> [
- new FragmentEntity(xpath: '/test/xpath1', childFragments: []),
- new FragmentEntity(xpath: '/test/xpath2', childFragments: [])]
- and: 'db contains an anchor'
- mockAnchorRepository.getByDataspaceAndName(*_) >> new AnchorEntity(id:123)
+ new FragmentEntity(xpath: '/test/xpath1', childFragments: [], anchor: anchorEntity),
+ new FragmentEntity(xpath: '/test/xpath2', childFragments: [], anchor: anchorEntity)]
and: 'some data nodes with descendants'
def dataNode1 = new DataNode(xpath: '/test/xpath1', leaves: ['id': 'testId1'], childDataNodes: [new DataNode(xpath: '/test/xpath1/child', leaves: ['id': 'childTestId1'])])
def dataNode2 = new DataNode(xpath: '/test/xpath2', leaves: ['id': 'testId2'], childDataNodes: [new DataNode(xpath: '/test/xpath2/child', leaves: ['id': 'childTestId2'])])
@@ -239,7 +238,7 @@ class CpsDataPersistenceServiceSpec extends Specification {
def createDataNodeAndMockRepositoryMethodSupportingIt(xpath, scenario) {
def dataNode = new DataNodeBuilder().withXpath(xpath).build()
def fragmentEntity = new FragmentEntity(xpath: xpath, childFragments: [])
- mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, xpath) >> fragmentEntity
+ mockFragmentRepository.getByAnchorAndXpath(_, xpath) >> fragmentEntity
if ('EXCEPTION' == scenario) {
mockFragmentRepository.save(fragmentEntity) >> { throw new StaleStateException("concurrent updates") }
}
@@ -256,7 +255,7 @@ class CpsDataPersistenceServiceSpec extends Specification {
dataNodes.add(dataNode)
def fragmentEntity = new FragmentEntity(xpath: xpath, childFragments: [])
fragmentEntities.add(fragmentEntity)
- mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, xpath) >> fragmentEntity
+ mockFragmentRepository.getByAnchorAndXpath(_, xpath) >> fragmentEntity
if ('EXCEPTION' == scenario) {
mockFragmentRepository.save(fragmentEntity) >> { throw new StaleStateException("concurrent updates") }
}
@@ -266,8 +265,6 @@ class CpsDataPersistenceServiceSpec extends Specification {
}
def mockFragmentWithJson(json) {
- def anchorEntity = new AnchorEntity(id:123)
- mockAnchorRepository.getByDataspaceAndName(*_) >> anchorEntity
def fragmentEntity = new FragmentEntity(xpath: '/parent-01', childFragments: [], attributes: json)
mockFragmentRepository.findByAnchorAndMultipleCpsPaths(123, ['/parent-01'] as Set<String>) >> [fragmentEntity]
}