From aec2a44c3ad4e9206300fd3494dbd542437678b3 Mon Sep 17 00:00:00 2001 From: ToineSiebelink Date: Mon, 12 Dec 2022 17:39:26 +0000 Subject: [PATCH] Query Optimization - Refactor performance tests as multiple separate (data driven) tests - This to improve redability and re-use and amke sure al tets are always ran (makign it easier to test/change thresholds for multiple scenarios at once) - Add new query performance tests (on many descendants) Issue-ID: CPS-475 Signed-off-by: ToineSiebelink Change-Id: If5703fcb9e2233ded64d31d2342de2e7f5549687 --- .../spi/performance/CpsToDataNodePerfTest.groovy | 75 ++++++++++++++-------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsToDataNodePerfTest.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsToDataNodePerfTest.groovy index 387fc1f85..b26cef4de 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsToDataNodePerfTest.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsToDataNodePerfTest.groovy @@ -27,7 +27,11 @@ import org.onap.cps.spi.model.DataNode import org.onap.cps.spi.model.DataNodeBuilder 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 CpsToDataNodePerfTest extends CpsPersistenceSpecBase { @@ -36,66 +40,85 @@ class CpsToDataNodePerfTest extends CpsPersistenceSpecBase { @Autowired CpsDataPersistenceService objectUnderTest - def PERF_TEST_PARENT = '/perf-parent-1' + static def PERF_TEST_PARENT = '/perf-parent-1' + 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 EXPECTED_NUMBER_OF_NODES = 10051 // 1 Parent + 50 Children + 10000 Grand-children + def readStopWatch = new StopWatch() @Sql([CLEAR_DATA, PERF_TEST_DATA]) - def 'Get data node by xpath with all descendants with many children'() { - given: 'nodes and grandchildren have been persisted' + 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' def setupStopWatch = new StopWatch() setupStopWatch.start() createLineage() setupStopWatch.stop() def setupDurationInMillis = setupStopWatch.getTime() - and: 'setup duration is under 10000 milliseconds' - assert setupDurationInMillis < 10000 + and: 'setup duration is under #ALLOWED_SETUP_TIME_MS milliseconds' + assert setupDurationInMillis < ALLOWED_SETUP_TIME_MS + } + + def 'Get data node with many descendants by xpath #scenario'() { when: 'get parent is executed with all descendants' - def readStopWatch = new StopWatch() readStopWatch.start() - def result = objectUnderTest.getDataNode('PERF-DATASPACE', 'PERF-ANCHOR', PERF_TEST_PARENT, INCLUDE_ALL_DESCENDANTS) + def result = objectUnderTest.getDataNode('PERF-DATASPACE', 'PERF-ANCHOR', xpath, INCLUDE_ALL_DESCENDANTS) readStopWatch.stop() def readDurationInMillis = readStopWatch.getTime() then: 'read duration is under 500 milliseconds' - assert readDurationInMillis < 500 + assert readDurationInMillis < ALLOWED_READ_TIME_AL_NODES_MS and: 'data node is returned with all the descendants populated' - assert countDataNodes(result) == EXPECTED_NUMBER_OF_NODES - when: 'get root is executed with all descendants' + assert countDataNodes(result) == TOTAL_NUMBER_OF_NODES + where: 'the following xPaths are used' + scenario || xpath + 'parent' || PERF_TEST_PARENT + 'root' || '' + } + + def 'Query parent data node with many descendants by cps-path'() { + when: 'query is executed with all descendants' readStopWatch.reset() readStopWatch.start() - result = objectUnderTest.getDataNode('PERF-DATASPACE', 'PERF-ANCHOR', '', INCLUDE_ALL_DESCENDANTS) + def result = objectUnderTest.queryDataNodes('PERF-DATASPACE', 'PERF-ANCHOR', '//perf-parent-1' , INCLUDE_ALL_DESCENDANTS) readStopWatch.stop() - readDurationInMillis = readStopWatch.getTime() + def readDurationInMillis = readStopWatch.getTime() then: 'read duration is under 500 milliseconds' - assert readDurationInMillis < 500 + assert readDurationInMillis < ALLOWED_READ_TIME_AL_NODES_MS and: 'data node is returned with all the descendants populated' - assert countDataNodes(result) == EXPECTED_NUMBER_OF_NODES + assert countDataNodes(result) == TOTAL_NUMBER_OF_NODES + } + + def 'Query many descendants by cps-path with #scenario'() { when: 'query is executed with all descendants' readStopWatch.reset() readStopWatch.start() - result = objectUnderTest.queryDataNodes('PERF-DATASPACE', 'PERF-ANCHOR', '//perf-parent-1', INCLUDE_ALL_DESCENDANTS) + def result = objectUnderTest.queryDataNodes('PERF-DATASPACE', 'PERF-ANCHOR', '//perf-test-grand-child-1', descendantsOption) readStopWatch.stop() - readDurationInMillis = readStopWatch.getTime() + def readDurationInMillis = readStopWatch.getTime() then: 'read duration is under 500 milliseconds' - assert readDurationInMillis < 500 + assert readDurationInMillis < alowedDuration and: 'data node is returned with all the descendants populated' - assert countDataNodes(result) == EXPECTED_NUMBER_OF_NODES + assert result.size() == NUMBER_OF_CHILDREN + where: 'the following options are used' + scenario | descendantsOption || alowedDuration + 'omit descendants ' | OMIT_DESCENDANTS || 150 + 'include descendants (although there are none)' | INCLUDE_ALL_DESCENDANTS || 1500 } def createLineage() { - def numOfChildren = 50 - def numOfGrandChildren = 200 - (1..numOfChildren).each { + (1..NUMBER_OF_CHILDREN).each { def childName = "perf-test-child-${it}".toString() - def newChild = goForthAndMultiply(PERF_TEST_PARENT, childName, numOfGrandChildren) + def newChild = goForthAndMultiply(PERF_TEST_PARENT, childName) objectUnderTest.addChildDataNode('PERF-DATASPACE', 'PERF-ANCHOR', PERF_TEST_PARENT, newChild) } } - def goForthAndMultiply(parentXpath, childName, numOfGrandChildren) { + def goForthAndMultiply(parentXpath, childName) { def children = [] - (1..numOfGrandChildren).each { - def child = new DataNodeBuilder().withXpath("${parentXpath}/${childName}/${it}perf-test-grand-child").build() + (1..NUMBER_OF_GRAND_CHILDREN).each { + def child = new DataNodeBuilder().withXpath("${parentXpath}/${childName}/perf-test-grand-child-${it}").build() children.add(child) } return new DataNodeBuilder().withXpath("${parentXpath}/${childName}").withChildDataNodes(children).build() -- 2.16.6