diff options
11 files changed, 264 insertions, 526 deletions
diff --git a/cps-ri/pom.xml b/cps-ri/pom.xml index ea1efcb3e9..3162aa89a9 100644 --- a/cps-ri/pom.xml +++ b/cps-ri/pom.xml @@ -147,18 +147,10 @@ <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <excludes>
- <exclude>%regex[.*PerfTest.*]</exclude>
- </excludes>
- </configuration>
</plugin>
</plugins>
</build>
</profile>
- <profile>
- <id>include-performance</id>
- </profile>
</profiles>
<build>
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsPersistencePerfSpecBase.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsPersistencePerfSpecBase.groovy deleted file mode 100644 index daa774698f..0000000000 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsPersistencePerfSpecBase.groovy +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.spi.impl - -import org.onap.cps.spi.model.DataNode -import org.onap.cps.spi.model.DataNodeBuilder -import org.springframework.util.StopWatch - -class CpsPersistencePerfSpecBase extends CpsPersistenceSpecBase { - - static final String PERF_TEST_DATA = '/data/perf-test.sql' - static final String PERF_DATASPACE = 'PERF-DATASPACE' - static final String PERF_ANCHOR = 'PERF-ANCHOR' - static final String PERF_TEST_PARENT = '/perf-parent-1' - - static def xpathsToAllGrandChildren = [] - - static def PERFORMANCE_RECORD = [] - - def stopWatch = new StopWatch() - - def cleanupSpec() { - println('#############################################################################') - println('## P E R F O R M A N C E T E S T R E S U L T S ##') - println('#############################################################################') - PERFORMANCE_RECORD.sort().each { println(it) } - PERFORMANCE_RECORD.clear() - } - - def createLineage(cpsDataPersistenceService, numberOfChildren, numberOfGrandChildren, createLists) { - xpathsToAllGrandChildren = [] - (1..numberOfChildren).each { - if (createLists) { - def xpathFormat = "${PERF_TEST_PARENT}/perf-test-list-${it}[@key='%d']" - def listElements = goForthAndMultiply(xpathFormat, numberOfGrandChildren) - cpsDataPersistenceService.addListElements(PERF_DATASPACE, PERF_ANCHOR, PERF_TEST_PARENT, listElements) - } else { - def xpathFormat = "${PERF_TEST_PARENT}/perf-test-child-${it}/perf-test-grand-child-%d" - def grandChildren = goForthAndMultiply(xpathFormat, numberOfGrandChildren) - def child = new DataNodeBuilder() - .withXpath("${PERF_TEST_PARENT}/perf-test-child-${it}") - .withChildDataNodes(grandChildren) - .build() - cpsDataPersistenceService.addChildDataNode(PERF_DATASPACE, PERF_ANCHOR, PERF_TEST_PARENT, child) - } - } - } - - def goForthAndMultiply(xpathFormat, numberOfGrandChildren) { - def grandChildren = [] - (1..numberOfGrandChildren).each { - def xpath = String.format(xpathFormat as String, it) - def grandChild = new DataNodeBuilder().withXpath(xpath).build() - xpathsToAllGrandChildren.add(grandChild.xpath) - grandChildren.add(grandChild) - } - return grandChildren - } - - def countDataNodes(Collection<DataNode> dataNodes) { - int nodeCount = 0 - for (DataNode parent : dataNodes) { - nodeCount = nodeCount + countDataNodes(parent) - } - return nodeCount - } - - def countDataNodes(DataNode dataNode) { - int nodeCount = 1 - for (DataNode child : dataNode.childDataNodes) { - nodeCount = nodeCount + countDataNodes(child) - } - return nodeCount - } - - def recordAndAssertPerformance(String shortTitle, thresholdInMs, recordedTimeInMs) { - def pass = recordedTimeInMs <= thresholdInMs - if (shortTitle.length()>40) { - shortTitle = shortTitle.substring(0,40) - } - def record = String.format('%2d.%-40s limit%,7d took %,7d ms ', PERFORMANCE_RECORD.size()+1, shortTitle, thresholdInMs, recordedTimeInMs) - record += pass?'PASS':'FAIL' - PERFORMANCE_RECORD.add(record) - assert recordedTimeInMs <= thresholdInMs - return true - } -} diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy deleted file mode 100644 index 428088135a..0000000000 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy +++ /dev/null @@ -1,239 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.spi.performance - -import org.onap.cps.spi.CpsDataPersistenceService -import org.onap.cps.spi.impl.CpsPersistencePerfSpecBase -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.test.context.jdbc.Sql - -class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase { - - @Autowired - CpsDataPersistenceService objectUnderTest - - @Sql([CLEAR_DATA, PERF_TEST_DATA]) - def 'Create a node with many descendants (please note, subsequent tests depend on this running first).'() { - when: 'a node with a large number of descendants is created' - stopWatch.start() - createLineage(objectUnderTest, 150, 50, false) - stopWatch.stop() - def setupDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'setup duration is under 10 seconds' - recordAndAssertPerformance('Setup', 10_000, setupDurationInMillis) - } - - def 'Delete 10 children with grandchildren'() { - when: 'child nodes are deleted' - stopWatch.start() - (1..10).each { - def childPath = "${PERF_TEST_PARENT}/perf-test-child-${it}".toString() - objectUnderTest.deleteDataNode(PERF_DATASPACE, PERF_ANCHOR, childPath) - } - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 300 milliseconds' - recordAndAssertPerformance('Delete 10 children', 300, deleteDurationInMillis) - } - - def 'Batch delete 100 children with grandchildren'() { - given: 'a list of xpaths to delete' - def xpathsToDelete = (11..110).collect { - "${PERF_TEST_PARENT}/perf-test-child-${it}".toString() - } - when: 'child nodes are deleted' - stopWatch.start() - objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR, xpathsToDelete) - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 300 milliseconds' - recordAndAssertPerformance('Batch delete 100 children', 300, deleteDurationInMillis) - } - - 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-111/perf-test-grand-child-${it}".toString() - objectUnderTest.deleteDataNode(PERF_DATASPACE, PERF_ANCHOR, grandchildPath) - } - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 700 milliseconds' - recordAndAssertPerformance('Delete 50 grandchildren', 700, deleteDurationInMillis) - } - - def 'Batch delete 500 grandchildren (that have no descendants)'() { - given: 'a list of xpaths to delete' - def xpathsToDelete = [] - for (int childIndex = 0; childIndex < 10; childIndex++) { - xpathsToDelete.addAll((1..50).collect { - "${PERF_TEST_PARENT}/perf-test-child-${112+childIndex}/perf-test-grand-child-${it}".toString() - }) - } - when: 'target nodes are deleted' - stopWatch.start() - objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR, xpathsToDelete) - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 100 milliseconds' - recordAndAssertPerformance('Batch delete 500 grandchildren', 100, deleteDurationInMillis) - } - - @Sql([CLEAR_DATA, PERF_TEST_DATA]) - def 'Create a node with many list elements (please note, subsequent tests depend on this running first).'() { - when: 'a node with a large number of lists is created' - stopWatch.start() - createLineage(objectUnderTest, 150, 50, true) - stopWatch.stop() - def setupDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'setup duration is under 6 seconds' - recordAndAssertPerformance('Setup lists', 6_000, setupDurationInMillis) - } - - def 'Delete 10 whole lists'() { - when: 'lists are deleted' - stopWatch.start() - (1..10).each { - def childPath = "${PERF_TEST_PARENT}/perf-test-list-${it}".toString() - objectUnderTest.deleteListDataNode(PERF_DATASPACE, PERF_ANCHOR, childPath) - } - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 300 milliseconds' - recordAndAssertPerformance('Delete 10 whole lists', 300, deleteDurationInMillis) - } - - def 'Batch delete 100 whole lists'() { - given: 'a list of xpaths to delete' - def xpathsToDelete = (11..110).collect { - "${PERF_TEST_PARENT}/perf-test-list-${it}".toString() - } - when: 'lists are deleted' - stopWatch.start() - objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR, xpathsToDelete) - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 600 milliseconds' - recordAndAssertPerformance('Batch delete 100 whole lists', 600, deleteDurationInMillis) - } - - def 'Delete 10 list elements'() { - when: 'list elements are deleted' - stopWatch.start() - (1..10).each { - def grandchildPath = "${PERF_TEST_PARENT}/perf-test-list-111[@key='${it}']".toString() - objectUnderTest.deleteListDataNode(PERF_DATASPACE, PERF_ANCHOR, grandchildPath) - } - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 200 milliseconds' - recordAndAssertPerformance('Delete 10 lists elements', 200, deleteDurationInMillis) - } - - def 'Batch delete 500 list elements'() { - given: 'a list of xpaths to delete' - def xpathsToDelete = [] - for (int childIndex = 0; childIndex < 10; childIndex++) { - xpathsToDelete.addAll((1..50).collect { - "${PERF_TEST_PARENT}/perf-test-list-${112+childIndex}[@key='${it}']".toString() - }) - } - when: 'list elements are deleted' - stopWatch.start() - objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR, xpathsToDelete) - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 100 milliseconds' - recordAndAssertPerformance('Batch delete 500 lists elements', 100, deleteDurationInMillis) - } - - @Sql([CLEAR_DATA, PERF_TEST_DATA]) - def 'Delete 1 large data node'() { - given: 'a node with a large number of descendants is created' - createLineage(objectUnderTest, 50, 50, false) - createLineage(objectUnderTest, 50, 50, true) - when: 'parent node is deleted' - stopWatch.start() - objectUnderTest.deleteDataNode(PERF_DATASPACE, PERF_ANCHOR, PERF_TEST_PARENT) - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 300 milliseconds' - recordAndAssertPerformance('Delete one large node', 300, deleteDurationInMillis) - } - - @Sql([CLEAR_DATA, PERF_TEST_DATA]) - def 'Batch delete 1 large data node'() { - given: 'a node with a large number of descendants is created' - createLineage(objectUnderTest, 50, 50, false) - createLineage(objectUnderTest, 50, 50, true) - when: 'parent node is batch deleted' - stopWatch.start() - objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR, [PERF_TEST_PARENT]) - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 300 milliseconds' - recordAndAssertPerformance('Batch delete one large node', 300, deleteDurationInMillis) - } - - @Sql([CLEAR_DATA, PERF_TEST_DATA]) - def 'Delete root node with many descendants'() { - given: 'a node with a large number of descendants is created' - createLineage(objectUnderTest, 50, 50, false) - createLineage(objectUnderTest, 50, 50, true) - when: 'root node is deleted' - stopWatch.start() - objectUnderTest.deleteDataNode(PERF_DATASPACE, PERF_ANCHOR, '/') - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 300 milliseconds' - recordAndAssertPerformance('Delete root node', 300, deleteDurationInMillis) - } - - @Sql([CLEAR_DATA, PERF_TEST_DATA]) - def 'Delete data nodes for an anchor'() { - given: 'a node with a large number of descendants is created' - createLineage(objectUnderTest, 50, 50, false) - createLineage(objectUnderTest, 50, 50, true) - when: 'data nodes are deleted' - stopWatch.start() - objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR) - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 300 milliseconds' - recordAndAssertPerformance('Delete data nodes for anchor', 300, deleteDurationInMillis) - } - - @Sql([CLEAR_DATA, PERF_TEST_DATA]) - def 'Delete data nodes for multiple anchors'() { - given: 'a node with a large number of descendants is created' - createLineage(objectUnderTest, 50, 50, false) - createLineage(objectUnderTest, 50, 50, true) - when: 'data nodes are deleted' - stopWatch.start() - objectUnderTest.deleteDataNodes(PERF_DATASPACE, [PERF_ANCHOR]) - stopWatch.stop() - def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 300 milliseconds' - recordAndAssertPerformance('Delete data nodes for anchors', 300, deleteDurationInMillis) - } - -} 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 deleted file mode 100644 index 2628e9697f..0000000000 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServicePerfTest.groovy +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.spi.performance - -import org.onap.cps.spi.impl.CpsPersistencePerfSpecBase -import org.onap.cps.spi.CpsDataPersistenceService -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 static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS -import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS - -class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase { - - @Autowired - CpsDataPersistenceService objectUnderTest - - @Autowired - DataspaceRepository dataspaceRepository - - @Autowired - AnchorRepository anchorRepository - - @Autowired - FragmentRepository fragmentRepository - - static def NUMBER_OF_CHILDREN = 200 - static def NUMBER_OF_GRAND_CHILDREN = 50 - - @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(objectUnderTest, NUMBER_OF_CHILDREN, NUMBER_OF_GRAND_CHILDREN, false) - stopWatch.stop() - def setupDurationInMillis = stopWatch.getTotalTimeMillis() - and: 'setup duration is under 10 seconds' - recordAndAssertPerformance('Setup', 10000, setupDurationInMillis) - } - - 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() - } - 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() - objectUnderTest.updateDataNodesAndDescendants(PERF_DATASPACE, PERF_ANCHOR, dataNodes) - stopWatch.stop() - def updateDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'update duration is under 600 milliseconds' - recordAndAssertPerformance('Update data nodes with descendants', 600, updateDurationInMillis) - } - - 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.updateDataNodesAndDescendants(PERF_DATASPACE, PERF_ANCHOR, dataNodes) - stopWatch.stop() - def updateDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'update duration is under 900 milliseconds' - recordAndAssertPerformance('Update data nodes without descendants', 900, updateDurationInMillis) - } -} diff --git a/cps-ri/src/test/resources/data/perf-test.sql b/cps-ri/src/test/resources/data/perf-test.sql deleted file mode 100644 index 5119f26b24..0000000000 --- a/cps-ri/src/test/resources/data/perf-test.sql +++ /dev/null @@ -1,28 +0,0 @@ -/* - ============LICENSE_START======================================================= - Copyright (C) 2022 Nordix Foundation. - ================================================================================ - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - SPDX-License-Identifier: Apache-2.0 - ============LICENSE_END========================================================= -*/ - -INSERT INTO DATASPACE (ID, NAME) VALUES (9001, 'PERF-DATASPACE'); - -INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES (9002, 'PERF-SCHEMA-SET', 9001); - -INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES (9003, 'PERF-ANCHOR', 9001, 9002); - -INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH) VALUES (0, 9001, 9003, null, '/perf-parent-1'); - diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/CpsPerfTestBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/CpsPerfTestBase.groovy index d339f6ddcf..6b1efe955f 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/CpsPerfTestBase.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/CpsPerfTestBase.groovy @@ -81,7 +81,7 @@ class CpsPerfTestBase extends PerfTestBase { addAnchorsWithData(5, CPS_PERFORMANCE_TEST_DATASPACE, LARGE_SCHEMA_SET, 'openroadm', data) stopWatch.stop() def durationInMillis = stopWatch.getTotalTimeMillis() - recordAndAssertPerformance('Creating openroadm anchors with large data tree', 25_000, durationInMillis) + recordAndAssertPerformance('Creating openroadm anchors with large data tree', 30_000, durationInMillis) } def generateOpenRoadData(numberOfNodes) { @@ -98,8 +98,8 @@ class CpsPerfTestBase extends PerfTestBase { assert countDataNodesInTree(result) == 1 stopWatch.stop() def durationInMillis = stopWatch.getTotalTimeMillis() - then: 'all data is read within 25 seconds (warm up not critical)' - recordAndAssertPerformance("Warming database", 25_000, durationInMillis) + then: 'all data is read within 30 seconds (warm up not critical)' + recordAndAssertPerformance("Warming database", 30_000, durationInMillis) } } diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsModuleReferenceRepositoryPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsModuleServicePerfTest.groovy index 222a828b9f..ce0ed5c171 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsModuleReferenceRepositoryPerfTest.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsModuleServicePerfTest.groovy @@ -18,23 +18,16 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.spi.performance +package org.onap.cps.integration.performance.cps -import org.onap.cps.spi.CpsModulePersistenceService -import org.onap.cps.spi.entities.SchemaSetEntity -import org.onap.cps.spi.impl.CpsPersistenceSpecBase +import org.onap.cps.api.CpsModuleService +import org.onap.cps.integration.performance.base.CpsPerfTestBase import org.onap.cps.spi.model.ModuleReference -import org.onap.cps.spi.repository.ModuleReferenceRepository -import org.onap.cps.spi.repository.SchemaSetRepository -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.test.context.jdbc.Sql import org.springframework.util.StopWatch import java.util.concurrent.ThreadLocalRandom -class CpsModuleReferenceRepositoryPerfTest extends CpsPersistenceSpecBase { - - static final String PERF_TEST_DATA = '/data/perf-test.sql' +class CpsModuleServicePerfTest extends CpsPerfTestBase { def NEW_RESOURCE_CONTENT = 'module stores {\n' + ' yang-version 1.1;\n' + @@ -48,16 +41,10 @@ class CpsModuleReferenceRepositoryPerfTest extends CpsPersistenceSpecBase { ' }' + '}' - @Autowired - CpsModulePersistenceService objectUnderTest - - @Autowired - SchemaSetRepository schemaSetRepository + CpsModuleService objectUnderTest - @Autowired - ModuleReferenceRepository moduleReferenceRepository + def setup() { objectUnderTest = cpsModuleService } - @Sql([CLEAR_DATA, PERF_TEST_DATA]) def 'Store new schema set with many modules'() { when: 'a new schema set with 200 modules is stored' def newYangResourcesNameToContentMap = [:] @@ -68,17 +55,16 @@ class CpsModuleReferenceRepositoryPerfTest extends CpsPersistenceSpecBase { def content = NEW_RESOURCE_CONTENT.replace('2020',String.valueOf(year)).replace('stores',moduleName) newYangResourcesNameToContentMap.put(resourceName, content) } - objectUnderTest.storeSchemaSet('PERF-DATASPACE', 'perfSchemaSet', newYangResourcesNameToContentMap) + objectUnderTest.createSchemaSet(CPS_PERFORMANCE_TEST_DATASPACE, 'perfSchemaSet', newYangResourcesNameToContentMap) then: 'the schema set is persisted correctly' - def dataspaceEntity = dataspaceRepository.getByName('PERF-DATASPACE') - SchemaSetEntity result = schemaSetRepository.getByDataspaceAndName(dataspaceEntity, 'perfSchemaSet') - result.yangResources.size() == 200 + def result = cpsModuleService.getSchemaSet(CPS_PERFORMANCE_TEST_DATASPACE, 'perfSchemaSet') + result.moduleReferences.size() == 200 and: 'identification of new module resources is fast enough (1,000 executions less then 6,000 milliseconds)' def stopWatch = new StopWatch() 1000.times() { def moduleReferencesToCheck = createModuleReferencesWithRandomMatchingExistingModuleReferences() stopWatch.start() - def newModuleReferences = moduleReferenceRepository.identifyNewModuleReferences(moduleReferencesToCheck) + def newModuleReferences = objectUnderTest.identifyNewModuleReferences(moduleReferencesToCheck) stopWatch.stop() assert newModuleReferences.size() > 0 && newModuleReferences.size() < 300 } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/DeletePerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/DeletePerfTest.groovy new file mode 100644 index 0000000000..db36b8809b --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/DeletePerfTest.groovy @@ -0,0 +1,170 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.integration.performance.cps + +import java.time.OffsetDateTime +import org.onap.cps.api.CpsDataService +import org.onap.cps.integration.performance.base.CpsPerfTestBase + +class DeletePerfTest extends CpsPerfTestBase { + + CpsDataService objectUnderTest + + def setup() { objectUnderTest = cpsDataService } + + def 'Create test data (please note, subsequent tests depend on this running first).'() { + when: 'multiple anchors with a node with a large number of descendants is created' + stopWatch.start() + def data = generateOpenRoadData(50) + addAnchorsWithData(9, CPS_PERFORMANCE_TEST_DATASPACE, LARGE_SCHEMA_SET, 'delete', data) + stopWatch.stop() + def setupDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'setup duration is under 40 seconds' + recordAndAssertPerformance('Delete test setup', 40_000, setupDurationInMillis) + } + + def 'Delete 10 container nodes'() { + when: 'child nodes are deleted' + stopWatch.start() + (1..10).each { + def childPath = "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']/org-openroadm-device" + objectUnderTest.deleteDataNode(CPS_PERFORMANCE_TEST_DATASPACE, 'delete1', childPath, OffsetDateTime.now()) + } + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 300 milliseconds' + recordAndAssertPerformance('Delete 10 containers', 300, deleteDurationInMillis) + } + + def 'Batch delete 50 container nodes'() { + given: 'a list of xpaths to delete' + def xpathsToDelete = (1..50).collect { + "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']/org-openroadm-device" + } + when: 'child nodes are deleted' + stopWatch.start() + objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'delete2', xpathsToDelete, OffsetDateTime.now()) + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 300 milliseconds' + recordAndAssertPerformance('Batch delete 50 containers', 300, deleteDurationInMillis) + } + + def 'Delete 20 list elements'() { + when: 'list elements are deleted' + stopWatch.start() + (1..20).each { + def listElementXpath = "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-1']/org-openroadm-device/degree[@degree-number=" + it + "]" + objectUnderTest.deleteDataNode(CPS_PERFORMANCE_TEST_DATASPACE, 'delete3', listElementXpath, OffsetDateTime.now()) + } + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 300 milliseconds' + recordAndAssertPerformance('Delete 20 lists elements', 300, deleteDurationInMillis) + } + + def 'Batch delete 1000 list elements'() { + given: 'a list of xpaths to delete' + def xpathsToDelete = [] + for (int childIndex = 1; childIndex <= 50; childIndex++) { + xpathsToDelete.addAll((1..20).collect { + "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-${childIndex}']/org-openroadm-device/degree[@degree-number=${it}]".toString() + }) + } + when: 'list elements are deleted' + stopWatch.start() + objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'delete4', xpathsToDelete, OffsetDateTime.now()) + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 300 milliseconds' + recordAndAssertPerformance('Batch delete 1000 lists elements', 300, deleteDurationInMillis) + } + + def 'Delete 10 whole lists'() { + when: 'lists are deleted' + stopWatch.start() + (1..10).each { + def childPath = "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']/org-openroadm-device/degree" + objectUnderTest.deleteDataNode(CPS_PERFORMANCE_TEST_DATASPACE, 'delete5', childPath, OffsetDateTime.now()) + } + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 300 milliseconds' + recordAndAssertPerformance('Delete 10 whole lists', 300, deleteDurationInMillis) + } + + def 'Batch delete 30 whole lists'() { + given: 'a list of xpaths to delete' + def xpathsToDelete = (1..30).collect { + "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']/org-openroadm-device/degree" + } + when: 'lists are deleted' + stopWatch.start() + objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'delete6', xpathsToDelete, OffsetDateTime.now()) + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 300 milliseconds' + recordAndAssertPerformance('Batch delete 30 whole lists', 300, deleteDurationInMillis) + } + + def 'Delete 1 large data node'() { + when: 'parent node is deleted' + stopWatch.start() + objectUnderTest.deleteDataNode(CPS_PERFORMANCE_TEST_DATASPACE, 'delete7', '/openroadm-devices', OffsetDateTime.now()) + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 300 milliseconds' + recordAndAssertPerformance('Delete one large node', 300, deleteDurationInMillis) + } + + def 'Delete root node with many descendants'() { + when: 'root node is deleted' + stopWatch.start() + objectUnderTest.deleteDataNode(CPS_PERFORMANCE_TEST_DATASPACE, 'delete8', '/', OffsetDateTime.now()) + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 300 milliseconds' + recordAndAssertPerformance('Delete root node', 300, deleteDurationInMillis) + } + + def 'Delete data nodes for an anchor'() { + when: 'data nodes are deleted' + stopWatch.start() + objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'delete9', OffsetDateTime.now()) + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 300 milliseconds' + recordAndAssertPerformance('Delete data nodes for anchor', 300, deleteDurationInMillis) + } + + def 'Clean up test data'() { + given: 'a list of anchors to delete' + def anchorNames = (1..9).collect {'delete' + it} + when: 'data nodes are deleted' + stopWatch.start() + cpsAdminService.deleteAnchors(CPS_PERFORMANCE_TEST_DATASPACE, anchorNames) + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 1000 milliseconds' + recordAndAssertPerformance('Delete test cleanup', 1000, deleteDurationInMillis) + } + +} diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy index c072755d31..d20da46cc5 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy @@ -45,8 +45,8 @@ class GetPerfTest extends CpsPerfTestBase { where: 'the following parameters are used' scenario | fetchDescendantsOption | anchor || durationLimit | expectedNumberOfDataNodes 'no descendants' | OMIT_DESCENDANTS | 'openroadm1' || 100 | 1 - 'direct descendants' | DIRECT_CHILDREN_ONLY | 'openroadm2' || 100 | 1 + 50 - 'all descendants' | INCLUDE_ALL_DESCENDANTS | 'openroadm3' || 350 | 1 + 50 * 86 + 'direct descendants' | DIRECT_CHILDREN_ONLY | 'openroadm2' || 150 | 1 + 50 + 'all descendants' | INCLUDE_ALL_DESCENDANTS | 'openroadm3' || 600 | 1 + 50 * 86 } def 'Read data trees for multiple xpaths'() { @@ -58,8 +58,8 @@ class GetPerfTest extends CpsPerfTestBase { stopWatch.stop() assert countDataNodesInTree(result) == 50 * 86 def durationInMillis = stopWatch.getTotalTimeMillis() - then: 'all data is read within 350 ms' - recordAndAssertPerformance("Read datatrees for multiple xpaths", 350, durationInMillis) + then: 'all data is read within 500 ms' + recordAndAssertPerformance("Read datatrees for multiple xpaths", 500, durationInMillis) } def 'Read complete data trees using #scenario.'() { @@ -75,10 +75,10 @@ class GetPerfTest extends CpsPerfTestBase { recordAndAssertPerformance("Read datatrees using ${scenario}", durationLimit, durationInMillis) where: 'the following xpaths are used' scenario | anchorPrefix | xpath || durationLimit | expectedNumberOfDataNodes - 'bookstore root' | 'bookstore' | '/' || 250 | 78 - 'bookstore top element' | 'bookstore' | '/bookstore' || 250 | 78 - 'openroadm root' | 'openroadm' | '/' || 1000 | 1 + 50 * 86 - 'openroadm top element' | 'openroadm' | '/openroadm-devices' || 1000 | 1 + 50 * 86 + 'bookstore root' | 'bookstore' | '/' || 300 | 78 + 'bookstore top element' | 'bookstore' | '/bookstore' || 300 | 78 + 'openroadm root' | 'openroadm' | '/' || 1200 | 1 + 50 * 86 + 'openroadm top element' | 'openroadm' | '/openroadm-devices' || 1200 | 1 + 50 * 86 } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy index ecc44ff9d3..885f1c2038 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy @@ -45,10 +45,10 @@ class QueryPerfTest extends CpsPerfTestBase { recordAndAssertPerformance("Query 1 anchor ${scenario}", durationLimit, durationInMillis) where: 'the following parameters are used' scenario | anchor | cpsPath || durationLimit | expectedNumberOfDataNodes - 'top element' | 'openroadm1' | '/openroadm-devices' || 250 | 50 * 86 + 1 - 'leaf condition' | 'openroadm2' | '//openroadm-device[@ne-state="inservice"]' || 250 | 50 * 86 - 'ancestors' | 'openroadm3' | '//openroadm-device/ancestor::openroadm-devices' || 250 | 50 * 86 + 1 - 'leaf condition + ancestors' | 'openroadm4' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || 250 | 50 * 86 + 1 + 'top element' | 'openroadm1' | '/openroadm-devices' || 500 | 50 * 86 + 1 + 'leaf condition' | 'openroadm2' | '//openroadm-device[@ne-state="inservice"]' || 500 | 50 * 86 + 'ancestors' | 'openroadm3' | '//openroadm-device/ancestor::openroadm-devices' || 500 | 50 * 86 + 1 + 'leaf condition + ancestors' | 'openroadm4' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || 500 | 50 * 86 + 1 } def 'Query complete data trees across all anchors with #scenario.'() { @@ -63,10 +63,10 @@ class QueryPerfTest extends CpsPerfTestBase { recordAndAssertPerformance("Query across anchors ${scenario}", durationLimit, durationInMillis) where: 'the following parameters are used' scenario | cpspath || durationLimit | expectedNumberOfDataNodes - 'top element' | '/openroadm-devices' || 1000 | 5 * (50 * 86 + 1) - 'leaf condition' | '//openroadm-device[@ne-state="inservice"]' || 1000 | 5 * (50 * 86) - 'ancestors' | '//openroadm-device/ancestor::openroadm-devices' || 1000 | 5 * (50 * 86 + 1) - 'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || 1000 | 5 * (50 * 86 + 1) + 'top element' | '/openroadm-devices' || 2000 | 5 * (50 * 86 + 1) + 'leaf condition' | '//openroadm-device[@ne-state="inservice"]' || 2000 | 5 * (50 * 86) + 'ancestors' | '//openroadm-device/ancestor::openroadm-devices' || 2000 | 5 * (50 * 86 + 1) + 'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || 2000 | 5 * (50 * 86 + 1) } def 'Query with leaf condition and #scenario.'() { @@ -82,8 +82,8 @@ class QueryPerfTest extends CpsPerfTestBase { where: 'the following parameters are used' scenario | fetchDescendantsOption | anchor || durationLimit | expectedNumberOfDataNodes 'no descendants' | OMIT_DESCENDANTS | 'openroadm1' || 100 | 50 - 'direct descendants' | DIRECT_CHILDREN_ONLY | 'openroadm2' || 150 | 50 * 2 - 'all descendants' | INCLUDE_ALL_DESCENDANTS | 'openroadm3' || 200 | 50 * 86 + 'direct descendants' | DIRECT_CHILDREN_ONLY | 'openroadm2' || 200 | 50 * 2 + 'all descendants' | INCLUDE_ALL_DESCENDANTS | 'openroadm3' || 500 | 50 * 86 } def 'Query ancestors with #scenario.'() { @@ -100,7 +100,7 @@ class QueryPerfTest extends CpsPerfTestBase { scenario | fetchDescendantsOption | anchor || durationLimit | expectedNumberOfDataNodes 'no descendants' | OMIT_DESCENDANTS | 'openroadm1' || 100 | 1 'direct descendants' | DIRECT_CHILDREN_ONLY | 'openroadm2' || 200 | 1 + 50 - 'all descendants' | INCLUDE_ALL_DESCENDANTS | 'openroadm3' || 300 | 1 + 50 * 86 + 'all descendants' | INCLUDE_ALL_DESCENDANTS | 'openroadm3' || 500 | 1 + 50 * 86 } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy new file mode 100644 index 0000000000..c281908653 --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy @@ -0,0 +1,62 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.integration.performance.cps + +import java.time.OffsetDateTime +import org.onap.cps.api.CpsDataService +import org.onap.cps.integration.performance.base.CpsPerfTestBase + +class UpdatePerfTest extends CpsPerfTestBase { + + CpsDataService objectUnderTest + + def setup() { objectUnderTest = cpsDataService } + + def 'Update 1 data node with descendants'() { + given: 'a list of data nodes to update as JSON' + def parentNodeXpath = "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-10']" + def jsonData = readResourceDataFile('openroadm/innerNode.json').replace('NODE_ID_HERE', '10') + when: 'the fragment entities are updated by the data nodes' + stopWatch.start() + objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm1', parentNodeXpath, jsonData, OffsetDateTime.now()) + stopWatch.stop() + def updateDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'update duration is under 1000 milliseconds' + recordAndAssertPerformance('Update 1 data node', 1000, updateDurationInMillis) + } + + def 'Batch update 10 data nodes with descendants'() { + given: 'a list of data nodes to update as JSON' + def innerNodeJson = readResourceDataFile('openroadm/innerNode.json') + def nodesJsonData = (20..30).collectEntries {[ + "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']", + innerNodeJson.replace('NODE_ID_HERE', it.toString()) + ]} + when: 'the fragment entities are updated by the data nodes' + stopWatch.start() + objectUnderTest.updateDataNodesAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm2', nodesJsonData, OffsetDateTime.now()) + stopWatch.stop() + def updateDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'update duration is under 5000 milliseconds' + recordAndAssertPerformance('Update 10 data nodes', 5000, updateDurationInMillis) + } + +} |