X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=cps-ri%2Fsrc%2Ftest%2Fgroovy%2Forg%2Fonap%2Fcps%2Fspi%2Fperformance%2FCpsDataPersistenceServicePerfTest.groovy;h=7f1fb20f72de938c7fb6822f17e17ae2ee357a2b;hb=refs%2Fchanges%2F43%2F133943%2F1;hp=910d8a46014f642711bad70dcadb73edc7d14581;hpb=ef2b1518cf984f34b0640eb16ed44b26c9192efe;p=cps.git diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServicePerfTest.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServicePerfTest.groovy index 910d8a460..7f1fb20f7 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServicePerfTest.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServicePerfTest.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,150 +20,139 @@ package org.onap.cps.spi.performance -import org.springframework.util.StopWatch +import org.onap.cps.spi.impl.CpsPersistencePerfSpecBase import org.onap.cps.spi.CpsDataPersistenceService -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.AnchorRepository +import org.onap.cps.spi.repository.DataspaceRepository +import org.onap.cps.spi.repository.FragmentRepository import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.jdbc.Sql -import java.util.concurrent.TimeUnit - import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS -class CpsDataPersistenceServicePerfTest extends CpsPersistenceSpecBase { - - static final String PERF_TEST_DATA = '/data/perf-test.sql' +class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase { @Autowired CpsDataPersistenceService objectUnderTest - static def PERF_TEST_PARENT = '/perf-parent-1' + @Autowired + DataspaceRepository dataspaceRepository + + @Autowired + AnchorRepository anchorRepository + + @Autowired + FragmentRepository fragmentRepository + static def NUMBER_OF_CHILDREN = 200 static def NUMBER_OF_GRAND_CHILDREN = 50 static def TOTAL_NUMBER_OF_NODES = 1 + NUMBER_OF_CHILDREN + (NUMBER_OF_CHILDREN * NUMBER_OF_GRAND_CHILDREN) // Parent + Children + Grand-children - static def ALLOWED_SETUP_TIME_MS = TimeUnit.SECONDS.toMillis(10) - static def ALLOWED_READ_TIME_AL_NODES_MS = 500 - - def stopWatch = new StopWatch() @Sql([CLEAR_DATA, PERF_TEST_DATA]) def 'Create a node with many descendants (please note, subsequent tests depend on this running first).'() { given: 'a node with a large number of descendants is created' stopWatch.start() - createLineage() + createLineage(objectUnderTest, NUMBER_OF_CHILDREN, NUMBER_OF_GRAND_CHILDREN, false) stopWatch.stop() def setupDurationInMillis = stopWatch.getTotalTimeMillis() - and: 'setup duration is under #ALLOWED_SETUP_TIME_MS milliseconds' - assert setupDurationInMillis < ALLOWED_SETUP_TIME_MS + and: 'setup duration is under 10 seconds' + recordAndAssertPerformance('Setup', 10000, setupDurationInMillis) } def 'Get data node with many descendants by xpath #scenario'() { when: 'get parent is executed with all descendants' stopWatch.start() - def result = objectUnderTest.getDataNode('PERF-DATASPACE', 'PERF-ANCHOR', xpath, INCLUDE_ALL_DESCENDANTS) + def result = objectUnderTest.getDataNodes(PERF_DATASPACE, PERF_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) stopWatch.stop() def readDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'read duration is under 500 milliseconds' - assert readDurationInMillis < ALLOWED_READ_TIME_AL_NODES_MS + then: 'read duration is under #allowedDuration milliseconds' + recordAndAssertPerformance("Get ${scenario}", allowedDuration, readDurationInMillis) and: 'data node is returned with all the descendants populated' - assert countDataNodes(result) == TOTAL_NUMBER_OF_NODES + assert countDataNodes(result[0]) == TOTAL_NUMBER_OF_NODES where: 'the following xPaths are used' - scenario || xpath - 'parent' || PERF_TEST_PARENT - 'root' || '' + scenario | xpath || allowedDuration + 'parent' | PERF_TEST_PARENT || 500 + 'root' | '/' || 500 } def 'Query parent data node with many descendants by cps-path'() { when: 'query is executed with all descendants' stopWatch.start() - def result = objectUnderTest.queryDataNodes('PERF-DATASPACE', 'PERF-ANCHOR', '//perf-parent-1' , INCLUDE_ALL_DESCENDANTS) + def result = objectUnderTest.queryDataNodes(PERF_DATASPACE, PERF_ANCHOR, '//perf-parent-1' , INCLUDE_ALL_DESCENDANTS) stopWatch.stop() def readDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'read duration is under 500 milliseconds' - assert readDurationInMillis < ALLOWED_READ_TIME_AL_NODES_MS + then: 'read duration is under 350 milliseconds' + recordAndAssertPerformance('Query with many descendants', 350, readDurationInMillis) and: 'data node is returned with all the descendants populated' assert countDataNodes(result) == TOTAL_NUMBER_OF_NODES } + def 'Performance of finding multiple xpaths'() { + when: 'we query for all grandchildren (except 1 for fun) with the new native method' + xpathsToAllGrandChildren.remove(0) + stopWatch.start() + def result = objectUnderTest.getDataNodesForMultipleXpaths(PERF_DATASPACE, PERF_ANCHOR, xpathsToAllGrandChildren, INCLUDE_ALL_DESCENDANTS) + stopWatch.stop() + def readDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'the returned number of entities equal to the number of children * number of grandchildren' + assert result.size() == xpathsToAllGrandChildren.size() + and: 'it took less then 1000ms' + recordAndAssertPerformance('Find multiple xpaths', 1000, readDurationInMillis) + } + def 'Query many descendants by cps-path with #scenario'() { when: 'query is executed with all descendants' stopWatch.start() - def result = objectUnderTest.queryDataNodes('PERF-DATASPACE', 'PERF-ANCHOR', '//perf-test-grand-child-1', descendantsOption) + def result = objectUnderTest.queryDataNodes(PERF_DATASPACE, PERF_ANCHOR, '//perf-test-grand-child-1', descendantsOption) stopWatch.stop() def readDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'read duration is under 500 milliseconds' - assert readDurationInMillis < alowedDuration + then: 'read duration is under #allowedDuration milliseconds' + recordAndAssertPerformance("Query many descendants by cpspath (${scenario})", allowedDuration, readDurationInMillis) and: 'data node is returned with all the descendants populated' assert result.size() == NUMBER_OF_CHILDREN where: 'the following options are used' - scenario | descendantsOption || alowedDuration + scenario | descendantsOption || allowedDuration 'omit descendants ' | OMIT_DESCENDANTS || 150 'include descendants (although there are none)' | INCLUDE_ALL_DESCENDANTS || 150 } - def 'Delete 50 grandchildren (that have no descendants)'() { - when: 'target nodes are deleted' - stopWatch.start() - (1..50).each { - def grandchildPath = "${PERF_TEST_PARENT}/perf-test-child-1/perf-test-grand-child-${it}".toString(); - objectUnderTest.deleteDataNode('PERF-DATASPACE', 'PERF-ANCHOR', grandchildPath) + def 'Update data nodes with descendants'() { + given: 'a list of xpaths to data nodes with descendants (xpath for each child)' + def xpaths = (1..20).collect { + "${PERF_TEST_PARENT}/perf-test-child-${it}".toString() } - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 1000 milliseconds' - assert deleteDurationInMillis < 1000 - } - - def 'Delete 5 children with grandchildren'() { - when: 'child nodes are deleted' + and: 'the correct number of data nodes are fetched' + def dataNodes = objectUnderTest.getDataNodesForMultipleXpaths(PERF_DATASPACE, PERF_ANCHOR, xpaths, INCLUDE_ALL_DESCENDANTS) + assert dataNodes.size() == 20 + assert countDataNodes(dataNodes) == 20 + 20 * 50 + when: 'the fragment entities are updated by the data nodes' stopWatch.start() - (1..5).each { - def childPath = "${PERF_TEST_PARENT}/perf-test-child-${it}".toString(); - objectUnderTest.deleteDataNode('PERF-DATASPACE', 'PERF-ANCHOR', childPath) - } + objectUnderTest.updateDataNodesAndDescendants(PERF_DATASPACE, PERF_ANCHOR, dataNodes) stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 10000 milliseconds' - assert deleteDurationInMillis < 10000 + def updateDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'update duration is under 600 milliseconds' + recordAndAssertPerformance('Update data nodes with descendants', 600, updateDurationInMillis) } - def 'Delete 1 large data node with many descendants'() { - when: 'parent node is deleted' + def 'Update data nodes without descendants'() { + given: 'a list of xpaths to data nodes without descendants (xpath for each grandchild)' + def xpaths = [] + for (int childIndex = 21; childIndex <= 40; childIndex++) { + xpaths.addAll((1..50).collect { + "${PERF_TEST_PARENT}/perf-test-child-${childIndex}/perf-test-grand-child-${it}".toString() + }) + } + and: 'the correct number of data nodes are fetched' + def dataNodes = objectUnderTest.getDataNodesForMultipleXpaths(PERF_DATASPACE, PERF_ANCHOR, xpaths, OMIT_DESCENDANTS) + assert dataNodes.size() == 20 * 50 + assert countDataNodes(dataNodes) == 20 * 50 + when: 'the fragment entities are updated by the data nodes' stopWatch.start() - objectUnderTest.deleteDataNode('PERF-DATASPACE', 'PERF-ANCHOR', PERF_TEST_PARENT) + objectUnderTest.updateDataNodesAndDescendants(PERF_DATASPACE, PERF_ANCHOR, dataNodes) stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 5000 milliseconds' - assert deleteDurationInMillis < 5000 - } - - def createLineage() { - (1..NUMBER_OF_CHILDREN).each { - def childName = "perf-test-child-${it}".toString() - def child = goForthAndMultiply(PERF_TEST_PARENT, childName) - objectUnderTest.addChildDataNode('PERF-DATASPACE', 'PERF-ANCHOR', PERF_TEST_PARENT, child) - } - } - - def goForthAndMultiply(parentXpath, childName) { - def grandChildren = [] - (1..NUMBER_OF_GRAND_CHILDREN).each { - def grandChild = new DataNodeBuilder().withXpath("${parentXpath}/${childName}/perf-test-grand-child-${it}").build() - grandChildren.add(grandChild) - } - return new DataNodeBuilder().withXpath("${parentXpath}/${childName}").withChildDataNodes(grandChildren).build() - } - - def countDataNodes(dataNodes) { - int nodeCount = 1 - for (DataNode parent : dataNodes) { - for (DataNode child : parent.childDataNodes) { - nodeCount = nodeCount + (countDataNodes(child)) - } - } - return nodeCount + def updateDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'update duration is under 900 milliseconds' + recordAndAssertPerformance('Update data nodes without descendants', 900, updateDurationInMillis) } }