Add memory usage to integration tests [UPDATED] 29/136029/6
authoremaclee <lee.anjella.macabuhay@est.tech>
Tue, 26 Sep 2023 10:01:38 +0000 (11:01 +0100)
committeremaclee <lee.anjella.macabuhay@est.tech>
Wed, 11 Oct 2023 08:39:06 +0000 (09:39 +0100)
Issue-ID: CPS-1753
Signed-off-by: emaclee <lee.anjella.macabuhay@est.tech>
Change-Id: I08fd0802f536b8fe333ddbfc9301356095f58171

12 files changed:
integration-test/src/test/groovy/org/onap/cps/integration/performance/base/CpsPerfTestBase.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/base/PerfTestBase.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimitsPerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/DeletePerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy
integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java [new file with mode: 0644]

index 5fd2747..e7a847e 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.cps.integration.performance.base
 
+import org.onap.cps.integration.ResourceMeter
 import org.onap.cps.rest.utils.MultipartFileUtil
 import org.onap.cps.spi.FetchDescendantsOption
 import org.springframework.web.multipart.MultipartFile
@@ -33,6 +34,8 @@ class CpsPerfTestBase extends PerfTestBase {
     static final def OPENROADM_DEVICES_PER_ANCHOR = 1000
     static final def OPENROADM_DATANODES_PER_DEVICE = 86
 
+    ResourceMeter resourceMeter = new ResourceMeter()
+
     def printTitle() {
         println('##        C P S   P E R F O R M A N C E   T E S T   R E S U L T S          ##')
     }
@@ -62,11 +65,11 @@ class CpsPerfTestBase extends PerfTestBase {
 
     def addOpenRoadData() {
         def data = generateOpenRoadData(OPENROADM_DEVICES_PER_ANCHOR)
-        stopWatch.start()
+        resourceMeter.start()
         addAnchorsWithData(OPENROADM_ANCHORS, CPS_PERFORMANCE_TEST_DATASPACE, LARGE_SCHEMA_SET, 'openroadm', data)
-        stopWatch.stop()
-        def durationInMillis = stopWatch.getTotalTimeMillis()
-        recordAndAssertPerformance('Creating openroadm anchors with large data tree', TimeUnit.SECONDS.toMillis(200), durationInMillis)
+        resourceMeter.stop()
+        def durationInMillis = resourceMeter.getTotalTimeMillis()
+        recordAndAssertResourceUsage('Creating openroadm anchors with large data tree', TimeUnit.SECONDS.toMillis(200), durationInMillis, 200, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def generateOpenRoadData(numberOfNodes) {
@@ -78,13 +81,15 @@ class CpsPerfTestBase extends PerfTestBase {
 
     def 'Warm the database'() {
         when: 'dummy get data nodes runs so that populating the DB does not get included in other test timings'
-            stopWatch.start()
+            resourceMeter.start()
             def result = cpsDataService.getDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm1', '/', FetchDescendantsOption.OMIT_DESCENDANTS)
             assert countDataNodesInTree(result) == 1
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'all data is read within expected time'
-            recordAndAssertPerformance("Warming database", TimeUnit.SECONDS.toMillis(200), durationInMillis)
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'memory used is within #peakMemoryUsage'
+            assert resourceMeter.getTotalMemoryUsageInMB() <= 30
+        and: 'all data is read within expected time'
+            recordAndAssertResourceUsage("Warming database", TimeUnit.SECONDS.toMillis(200), durationInMillis, 200, resourceMeter.getTotalMemoryUsageInMB())
     }
 
 }
index f5d7c5e..7bacf1d 100644 (file)
@@ -21,6 +21,7 @@
 package org.onap.cps.integration.performance.base
 
 import java.time.OffsetDateTime
+import org.onap.cps.integration.ResourceMeter
 
 class NcmpPerfTestBase extends PerfTestBase {
 
@@ -36,6 +37,8 @@ class NcmpPerfTestBase extends PerfTestBase {
     def numberOfFiltersPerCmHandle = 10
     def numberOfCmHandlesPerCmDataSubscription = 200
 
+    ResourceMeter resourceMeter = new ResourceMeter()
+
 // SHORT versions for easier debugging
 //    def subscriberIdPrefix = 'sub'
 //    def xpathPrefix = 'f'
index b6ceb91..8e5fe06 100644 (file)
@@ -28,8 +28,6 @@ abstract class PerfTestBase extends CpsIntegrationSpecBase {
     static def LARGE_SCHEMA_SET = 'largeSchemaSet'
     static def PERFORMANCE_RECORD = []
 
-    def stopWatch = new StopWatch()
-
     def cleanupSpec() {
         println('#############################################################################')
         printTitle()
@@ -56,15 +54,16 @@ abstract class PerfTestBase extends CpsIntegrationSpecBase {
 
     abstract def createInitialData()
 
-    def recordAndAssertPerformance(String shortTitle, thresholdInMs, recordedTimeInMs) {
+    def recordAndAssertResourceUsage(String shortTitle, thresholdInMs, recordedTimeInMs, memoryLimit, memoryUsageInMB) {
         def pass = recordedTimeInMs <= thresholdInMs
         if (shortTitle.length() > 40) {
             shortTitle = shortTitle.substring(0, 40)
         }
-        def record = String.format('%2d.%-40s limit%,8d took %,8d ms ', PERFORMANCE_RECORD.size() + 1, shortTitle, thresholdInMs, recordedTimeInMs)
+        def record = String.format('%2d.%-40s limit%,8d took %,8d ms %,8.2f MB used ', PERFORMANCE_RECORD.size() + 1, shortTitle, thresholdInMs, recordedTimeInMs, memoryUsageInMB)
         record += pass ? 'PASS' : 'FAIL'
         PERFORMANCE_RECORD.add(record)
         assert recordedTimeInMs <= thresholdInMs
+        assert memoryUsageInMB <= memoryLimit
         return true
     }
 }
index 659c9f5..1aea123 100644 (file)
@@ -41,15 +41,15 @@ class CpsDataServiceLimitsPerfTest extends CpsPerfTestBase {
             def parentNodeData = '{"bookstore": { "categories": [{ "code": 1, "name": "Test", "books" : [] }] }}'
             cpsDataService.saveData(CPS_PERFORMANCE_TEST_DATASPACE, 'limitsAnchor', parentNodeData, OffsetDateTime.now())
         when: '33,000 books are added'
-            stopWatch.start()
+            resourceMeter.start()
             for (int i = 1; i <= 33_000; i+=100) {
                 def booksData = '{"books":[' + (i..<i+100).collect {'{ "title": "' + it + '" }' }.join(',') + ']}'
                 cpsDataService.saveData(CPS_PERFORMANCE_TEST_DATASPACE, 'limitsAnchor', '/bookstore/categories[@code=1]', booksData, OffsetDateTime.now())
             }
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'the operation completes within 25 seconds'
-            recordAndAssertPerformance("Creating 33,000 books", TimeUnit.SECONDS.toMillis(25), durationInMillis)
+            recordAndAssertResourceUsage("Creating 33,000 books", TimeUnit.SECONDS.toMillis(25), durationInMillis, 200, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Get data nodes from multiple xpaths 32K (2^15) limit exceeded.'() {
@@ -84,13 +84,13 @@ class CpsDataServiceLimitsPerfTest extends CpsPerfTestBase {
 
     def 'Clean up test data.'() {
         when:
-            stopWatch.start()
+            resourceMeter.start()
             cpsDataService.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'limitsAnchor', OffsetDateTime.now())
             cpsAdminService.deleteAnchor(CPS_PERFORMANCE_TEST_DATASPACE, 'limitsAnchor')
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'test data is deleted in 1 second'
-            recordAndAssertPerformance("Deleting test data", TimeUnit.SECONDS.toMillis(1), durationInMillis)
+            recordAndAssertResourceUsage("Deleting test data", TimeUnit.SECONDS.toMillis(1), durationInMillis, 200, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def countDataNodes() {
index 0bab615..91c1082 100644 (file)
@@ -36,13 +36,13 @@ class DeletePerfTest extends CpsPerfTestBase {
 
     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()
+            resourceMeter.start()
             def data = generateOpenRoadData(300)
             addAnchorsWithData(10, CPS_PERFORMANCE_TEST_DATASPACE, LARGE_SCHEMA_SET, 'delete', data)
-            stopWatch.stop()
-            def setupDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'setup duration is within expected time'
-            recordAndAssertPerformance('Delete test setup', TimeUnit.SECONDS.toMillis(200), setupDurationInMillis)
+            resourceMeter.stop()
+            def setupDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'setup duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Delete test setup', TimeUnit.SECONDS.toMillis(200), setupDurationInMillis, 200, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Delete 100 container nodes'() {
@@ -51,14 +51,14 @@ class DeletePerfTest extends CpsPerfTestBase {
                 "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']/org-openroadm-device"
             }
         when: 'child nodes are deleted'
-            stopWatch.start()
+            resourceMeter.start()
             xpathsToDelete.each {
                 objectUnderTest.deleteDataNode(CPS_PERFORMANCE_TEST_DATASPACE, 'delete1', it, OffsetDateTime.now())
             }
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Delete 100 containers', TimeUnit.SECONDS.toMillis(2), deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Delete 100 containers', TimeUnit.SECONDS.toMillis(2), deleteDurationInMillis, 30, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Batch delete 100 container nodes'() {
@@ -67,12 +67,12 @@ class DeletePerfTest extends CpsPerfTestBase {
                 "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']/org-openroadm-device"
             }
         when: 'child nodes are deleted'
-            stopWatch.start()
+            resourceMeter.start()
             objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'delete2', xpathsToDelete, OffsetDateTime.now())
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Batch delete 100 containers', 500, deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Batch delete 100 containers', 500, deleteDurationInMillis, 5, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Delete 100 list elements'() {
@@ -81,14 +81,14 @@ class DeletePerfTest extends CpsPerfTestBase {
                 "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']"
             }
         when: 'list elements are deleted'
-            stopWatch.start()
+            resourceMeter.start()
             xpathsToDelete.each {
                 objectUnderTest.deleteDataNode(CPS_PERFORMANCE_TEST_DATASPACE, 'delete3', it, OffsetDateTime.now())
             }
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Delete 100 lists elements', TimeUnit.SECONDS.toMillis(2), deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Delete 100 lists elements', TimeUnit.SECONDS.toMillis(2), deleteDurationInMillis, 20, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Batch delete 100 list elements'() {
@@ -97,12 +97,12 @@ class DeletePerfTest extends CpsPerfTestBase {
                 "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']"
             }
         when: 'list elements are deleted'
-            stopWatch.start()
+            resourceMeter.start()
             objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'delete4', xpathsToDelete, OffsetDateTime.now())
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Batch delete 100 lists elements', 500, deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Batch delete 100 lists elements', 500, deleteDurationInMillis, 2, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Delete 100 whole lists'() {
@@ -111,14 +111,14 @@ class DeletePerfTest extends CpsPerfTestBase {
                 "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']/org-openroadm-device/degree"
             }
         when: 'lists are deleted'
-            stopWatch.start()
+            resourceMeter.start()
             xpathsToDelete.each {
                 objectUnderTest.deleteDataNode(CPS_PERFORMANCE_TEST_DATASPACE, 'delete5', it, OffsetDateTime.now())
             }
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Delete 100 whole lists', TimeUnit.SECONDS.toMillis(5), deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Delete 100 whole lists', TimeUnit.SECONDS.toMillis(5), deleteDurationInMillis, 30, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Batch delete 100 whole lists'() {
@@ -127,68 +127,68 @@ class DeletePerfTest extends CpsPerfTestBase {
                 "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']/org-openroadm-device/degree"
             }
         when: 'lists are deleted'
-            stopWatch.start()
+            resourceMeter.start()
             objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'delete6', xpathsToDelete, OffsetDateTime.now())
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Batch delete 100 whole lists', TimeUnit.SECONDS.toMillis(4), deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Batch delete 100 whole lists', TimeUnit.SECONDS.toMillis(4), deleteDurationInMillis, 5, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Delete 1 large data node'() {
         when: 'parent node is deleted'
-            stopWatch.start()
+            resourceMeter.start()
             objectUnderTest.deleteDataNode(CPS_PERFORMANCE_TEST_DATASPACE, 'delete7', '/openroadm-devices', OffsetDateTime.now())
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Delete one large node', TimeUnit.SECONDS.toMillis(2), deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Delete one large node', TimeUnit.SECONDS.toMillis(2), deleteDurationInMillis, 2, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Delete root node with many descendants'() {
         when: 'root node is deleted'
-            stopWatch.start()
+            resourceMeter.start()
             objectUnderTest.deleteDataNode(CPS_PERFORMANCE_TEST_DATASPACE, 'delete8', '/', OffsetDateTime.now())
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Delete root node', TimeUnit.SECONDS.toMillis(2), deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Delete root node', TimeUnit.SECONDS.toMillis(2), deleteDurationInMillis, 2, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Delete data nodes for an anchor'() {
         when: 'data nodes are deleted'
-            stopWatch.start()
+            resourceMeter.start()
             objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'delete9', OffsetDateTime.now())
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Delete data nodes for anchor', TimeUnit.SECONDS.toMillis(2), deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Delete data nodes for anchor', TimeUnit.SECONDS.toMillis(2), deleteDurationInMillis, 2, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Batch delete 100 non-existing nodes'() {
         given: 'a list of xpaths to delete'
             def xpathsToDelete = (1..100).collect { "/path/to/non-existing/node[@id='" + it + "']" }
         when: 'child nodes are deleted'
-            stopWatch.start()
+            resourceMeter.start()
             try {
                 objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'delete10', xpathsToDelete, OffsetDateTime.now())
             } catch (DataNodeNotFoundException ignored) {}
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Batch delete 100 non-existing', TimeUnit.SECONDS.toMillis(7), deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Batch delete 100 non-existing', TimeUnit.SECONDS.toMillis(7), deleteDurationInMillis, 5, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Clean up test data'() {
         given: 'a list of anchors to delete'
             def anchorNames = (1..10).collect {'delete' + it}
         when: 'data nodes are deleted'
-            stopWatch.start()
+            resourceMeter.start()
             cpsAdminService.deleteAnchors(CPS_PERFORMANCE_TEST_DATASPACE, anchorNames)
-            stopWatch.stop()
-            def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is within expected time'
-            recordAndAssertPerformance('Delete test cleanup', TimeUnit.SECONDS.toMillis(10), deleteDurationInMillis)
+            resourceMeter.stop()
+            def deleteDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'delete duration is within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Delete test cleanup', TimeUnit.SECONDS.toMillis(10), deleteDurationInMillis, 2, resourceMeter.getTotalMemoryUsageInMB())
     }
 
 }
index 048b3b4..8b76ef5 100644 (file)
@@ -22,9 +22,7 @@ package org.onap.cps.integration.performance.cps
 
 import org.onap.cps.api.CpsDataService
 import org.onap.cps.integration.performance.base.CpsPerfTestBase
-
 import java.util.concurrent.TimeUnit
-
 import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY
 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
 import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
@@ -37,62 +35,62 @@ class GetPerfTest extends CpsPerfTestBase {
 
     def 'Read top-level node with #scenario.'() {
         when: 'get data nodes from 1 anchor'
-            stopWatch.start()
+            resourceMeter.start()
             def result = objectUnderTest.getDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm1', '/openroadm-devices', fetchDescendantsOption)
-            stopWatch.stop()
+            resourceMeter.stop()
             assert countDataNodesInTree(result) == expectedNumberOfDataNodes
-            def durationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'all data is read within #durationLimit ms'
-            recordAndAssertPerformance("Read datatrees with ${scenario}", durationLimit, durationInMillis)
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'all data is read within #durationLimit ms and memory used is within limit'
+            recordAndAssertResourceUsage("Read datatrees with ${scenario}", durationLimit, durationInMillis, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following parameters are used'
-            scenario             | fetchDescendantsOption  || durationLimit                | expectedNumberOfDataNodes
-            'no descendants'     | OMIT_DESCENDANTS        || 10                           | 1
-            'direct descendants' | DIRECT_CHILDREN_ONLY    || 50                           | 1 + OPENROADM_DEVICES_PER_ANCHOR
-            'all descendants'    | INCLUDE_ALL_DESCENDANTS || TimeUnit.SECONDS.toMillis(2) | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            scenario             | fetchDescendantsOption  || durationLimit                | memoryLimit  | expectedNumberOfDataNodes
+            'no descendants'     | OMIT_DESCENDANTS        || 10                           | 5            | 1
+            'direct descendants' | DIRECT_CHILDREN_ONLY    || 50                           | 10           | 1 + OPENROADM_DEVICES_PER_ANCHOR
+            'all descendants'    | INCLUDE_ALL_DESCENDANTS || TimeUnit.SECONDS.toMillis(2) | 200          | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
     }
 
     def 'Read data trees for multiple xpaths'() {
         given: 'a collection of xpaths to get'
             def xpaths = (1..OPENROADM_DEVICES_PER_ANCHOR).collect { "/openroadm-devices/openroadm-device[@device-id='C201-7-1A-" + it + "']" }
         when: 'get data nodes from 1 anchor'
-            stopWatch.start()
+            resourceMeter.start()
             def result = objectUnderTest.getDataNodesForMultipleXpaths(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm2', xpaths, INCLUDE_ALL_DESCENDANTS)
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'requested nodes and their descendants are returned'
             assert countDataNodesInTree(result) == OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
-        and: 'all data is read within expected time'
-            recordAndAssertPerformance("Read datatrees for multiple xpaths", TimeUnit.SECONDS.toMillis(3) , durationInMillis)
+        and: 'all data is read within expected time and memory used is within limit'
+            recordAndAssertResourceUsage("Read datatrees for multiple xpaths", TimeUnit.SECONDS.toMillis(3) , durationInMillis, 200, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Read for multiple xpaths to non-existing datanodes'() {
         given: 'a collection of xpaths to get'
             def xpaths = (1..50).collect { "/path/to/non-existing/node[@id='" + it + "']" }
         when: 'get data nodes from 1 anchor'
-            stopWatch.start()
+            resourceMeter.start()
             def result = objectUnderTest.getDataNodesForMultipleXpaths(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm2', xpaths, INCLUDE_ALL_DESCENDANTS)
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'no data is returned'
             assert result.isEmpty()
         and: 'the operation completes within within expected time'
-            recordAndAssertPerformance("Read non-existing xpaths", 10, durationInMillis)
+            recordAndAssertResourceUsage("Read non-existing xpaths", 10, durationInMillis, 2, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Read complete data trees using #scenario.'() {
         when: 'get data nodes from 1 anchor'
-            stopWatch.start()
+            resourceMeter.start()
             def result = objectUnderTest.getDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm3', xpath, INCLUDE_ALL_DESCENDANTS)
             assert countDataNodesInTree(result) == expectedNumberOfDataNodes
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'all data is read within expected time'
-            recordAndAssertPerformance("Read datatrees using ${scenario}", durationLimit, durationInMillis)
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'all data is read within expected time and memory used is within limit'
+            recordAndAssertResourceUsage("Read datatrees using ${scenario}", durationLimit, durationInMillis, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following xpaths are used'
-            scenario                | xpath                                  || durationLimit                | expectedNumberOfDataNodes
-            'openroadm root'        | '/'                                    || TimeUnit.SECONDS.toMillis(2) | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
-            'openroadm top element' | '/openroadm-devices'                   || TimeUnit.SECONDS.toMillis(2) | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
-            'openroadm whole list'  | '/openroadm-devices/openroadm-device'  || TimeUnit.SECONDS.toMillis(3) | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            scenario                | xpath                                  || durationLimit                | memoryLimit  | expectedNumberOfDataNodes
+            'openroadm root'        | '/'                                    || TimeUnit.SECONDS.toMillis(2) | 200          | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            'openroadm top element' | '/openroadm-devices'                   || TimeUnit.SECONDS.toMillis(2) | 200          | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            'openroadm whole list'  | '/openroadm-devices/openroadm-device'  || TimeUnit.SECONDS.toMillis(3) | 200          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
     }
 
 }
index 0136918..595d038 100644 (file)
@@ -23,9 +23,7 @@ package org.onap.cps.integration.performance.cps
 import org.onap.cps.api.CpsQueryService
 import org.onap.cps.integration.performance.base.CpsPerfTestBase
 import org.onap.cps.spi.PaginationOption
-
 import java.util.concurrent.TimeUnit
-
 import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY
 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
 import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
@@ -33,79 +31,77 @@ import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
 class QueryPerfTest extends CpsPerfTestBase {
 
     CpsQueryService objectUnderTest
-
     def setup() { objectUnderTest = cpsQueryService }
 
     def 'Query complete data trees with #scenario.'() {
         when: 'query data nodes (using a fresh anchor with identical data for each test)'
-            stopWatch.start()
+            resourceMeter.start()
             def result = objectUnderTest.queryDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm1', cpsPath, INCLUDE_ALL_DESCENDANTS)
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'the expected number of nodes is returned'
             assert countDataNodesInTree(result) == expectedNumberOfDataNodes
-        and: 'all data is read within #durationLimit ms'
-            recordAndAssertPerformance("Query 1 anchor ${scenario}", durationLimit, durationInMillis)
+        and: 'all data is read within #durationLimit ms  and memory used is within limit'
+            recordAndAssertResourceUsage("Query 1 anchor ${scenario}", durationLimit, durationInMillis, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following parameters are used'
-            scenario                     | cpsPath                                                             || durationLimit                | expectedNumberOfDataNodes
-            'top element'                | '/openroadm-devices'                                                || TimeUnit.SECONDS.toMillis(2) | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
-            'leaf condition'             | '//openroadm-device[@ne-state="inservice"]'                         || TimeUnit.SECONDS.toMillis(3) | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
-            'ancestors'                  | '//openroadm-device/ancestor::openroadm-devices'                    || TimeUnit.SECONDS.toMillis(2) | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
-            'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || TimeUnit.SECONDS.toMillis(2) | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
-            'non-existing data'          | '/path/to/non-existing/node[@id="1"]'                               || 100                          | 0
+            scenario                     | cpsPath                                                             || durationLimit                          | memoryLimit  | expectedNumberOfDataNodes
+            'top element'                | '/openroadm-devices'                                                || TimeUnit.SECONDS.toMillis(2)           | 300          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
+            'leaf condition'             | '//openroadm-device[@ne-state="inservice"]'                         || TimeUnit.SECONDS.toMillis(3)           | 200          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            'ancestors'                  | '//openroadm-device/ancestor::openroadm-devices'                    || TimeUnit.SECONDS.toMillis(2)           | 200          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
+            'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || TimeUnit.SECONDS.toMillis(2)           | 300          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
     }
 
     def 'Query complete data trees across all anchors with #scenario.'() {
         when: 'query data nodes across all anchors'
-            stopWatch.start()
+            resourceMeter.start()
             def result = objectUnderTest.queryDataNodesAcrossAnchors(CPS_PERFORMANCE_TEST_DATASPACE, cpspath, INCLUDE_ALL_DESCENDANTS, PaginationOption.NO_PAGINATION)
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'the expected number of nodes is returned'
             assert countDataNodesInTree(result) == expectedNumberOfDataNodes
-        and: 'all data is read within #durationLimit ms'
-            recordAndAssertPerformance("Query across anchors ${scenario}", durationLimit, durationInMillis)
+        and: 'all data is read within #durationLimit ms and memory used is within limit'
+            recordAndAssertResourceUsage("Query across anchors ${scenario}", durationLimit, durationInMillis, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following parameters are used'
-            scenario                     | cpspath                                                             || durationLimit                | expectedNumberOfDataNodes
-            'top element'                | '/openroadm-devices'                                                || TimeUnit.SECONDS.toMillis(6) | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
-            'leaf condition'             | '//openroadm-device[@ne-state="inservice"]'                         || TimeUnit.SECONDS.toMillis(6) | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE)
-            'ancestors'                  | '//openroadm-device/ancestor::openroadm-devices'                    || TimeUnit.SECONDS.toMillis(6) | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
-            'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || TimeUnit.SECONDS.toMillis(6) | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
-            'non-existing data'          | '/path/to/non-existing/node[@id="1"]'                               || 100                          | 0
+            scenario                     | cpspath                                                             || durationLimit                 | memoryLimit   | expectedNumberOfDataNodes
+            'top element'                | '/openroadm-devices'                                                || TimeUnit.SECONDS.toMillis(6)  | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
+            'leaf condition'             | '//openroadm-device[@ne-state="inservice"]'                         || TimeUnit.SECONDS.toMillis(6)  | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE)
+            'ancestors'                  | '//openroadm-device/ancestor::openroadm-devices'                    || TimeUnit.SECONDS.toMillis(6)  | 800           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
+            'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || TimeUnit.SECONDS.toMillis(6)  | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
+            'non-existing data'          | '/path/to/non-existing/node[@id="1"]'                               || 100                           | 3             | 0
     }
 
     def 'Query with leaf condition and #scenario.'() {
         when: 'query data nodes (using a fresh anchor with identical data for each test)'
-            stopWatch.start()
+            resourceMeter.start()
             def result = objectUnderTest.queryDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm2', '//openroadm-device[@status="success"]', fetchDescendantsOption)
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'the expected number of nodes is returned'
             assert countDataNodesInTree(result) == expectedNumberOfDataNodes
-        and: 'all data is read within #durationLimit ms'
-            recordAndAssertPerformance("Query with ${scenario}", durationLimit, durationInMillis)
+        and: 'all data is read within #durationLimit ms and memory used is within limit'
+            recordAndAssertResourceUsage("Query with ${scenario}", durationLimit, durationInMillis, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following parameters are used'
-            scenario             | fetchDescendantsOption  || durationLimit                | expectedNumberOfDataNodes
-            'no descendants'     | OMIT_DESCENDANTS        || 100                          | OPENROADM_DEVICES_PER_ANCHOR
-            'direct descendants' | DIRECT_CHILDREN_ONLY    || 150                          | OPENROADM_DEVICES_PER_ANCHOR * 2
-            'all descendants'    | INCLUDE_ALL_DESCENDANTS || TimeUnit.SECONDS.toMillis(2) | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            scenario             | fetchDescendantsOption  || durationLimit                | memoryLimit   | expectedNumberOfDataNodes
+            'no descendants'     | OMIT_DESCENDANTS        || 100                          | 30            | OPENROADM_DEVICES_PER_ANCHOR
+            'direct descendants' | DIRECT_CHILDREN_ONLY    || 150                          | 30            | OPENROADM_DEVICES_PER_ANCHOR * 2
+            'all descendants'    | INCLUDE_ALL_DESCENDANTS || TimeUnit.SECONDS.toMillis(2) | 200           | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
     }
 
     def 'Query ancestors with #scenario.'() {
         when: 'query data nodes (using a fresh anchor with identical data for each test)'
-            stopWatch.start()
+            resourceMeter.start()
             def result = objectUnderTest.queryDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm3', '//openroadm-device[@ne-state="inservice"]/ancestor::openroadm-devices', fetchDescendantsOption)
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'the expected number of nodes is returned'
             assert countDataNodesInTree(result) == expectedNumberOfDataNodes
-        and: 'all data is read within #durationLimit ms'
-            recordAndAssertPerformance("Query ancestors with ${scenario}", durationLimit, durationInMillis)
+        and: 'all data is read within #durationLimit ms and memory used is within limit'
+            recordAndAssertResourceUsage("Query ancestors with ${scenario}", durationLimit, durationInMillis, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following parameters are used'
-            scenario             | fetchDescendantsOption  || durationLimit                | expectedNumberOfDataNodes
-            'no descendants'     | OMIT_DESCENDANTS        || 100                          | 1
-            'direct descendants' | DIRECT_CHILDREN_ONLY    || 100                          | 1 + OPENROADM_DEVICES_PER_ANCHOR
-            'all descendants'    | INCLUDE_ALL_DESCENDANTS || TimeUnit.SECONDS.toMillis(2) | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            scenario             | fetchDescendantsOption  || durationLimit                | memoryLimit | expectedNumberOfDataNodes
+            'no descendants'     | OMIT_DESCENDANTS        || 100                          | 20          | 1
+            'direct descendants' | DIRECT_CHILDREN_ONLY    || 100                          | 20          | 1 + OPENROADM_DEVICES_PER_ANCHOR
+            'all descendants'    | INCLUDE_ALL_DESCENDANTS || TimeUnit.SECONDS.toMillis(2) | 200         | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
     }
 
 }
index 5bb8192..3e26ac1 100644 (file)
@@ -23,7 +23,6 @@ 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
-
 import java.util.concurrent.TimeUnit
 
 class UpdatePerfTest extends CpsPerfTestBase {
@@ -38,12 +37,12 @@ class UpdatePerfTest extends CpsPerfTestBase {
             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()
+            resourceMeter.start()
             objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm1', parentNodeXpath, jsonData, now)
-            stopWatch.stop()
-            def updateDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'update completes within expected time'
-            recordAndAssertPerformance('Update 1 data node', 600, updateDurationInMillis)
+            resourceMeter.stop()
+            def updateDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'update completes within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Update 1 data node', 600, updateDurationInMillis, 200, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Batch update 100 data nodes with descendants'() {
@@ -54,12 +53,12 @@ class UpdatePerfTest extends CpsPerfTestBase {
                 innerNodeJson.replace('NODE_ID_HERE', it.toString())
             ]}
         when: 'the fragment entities are updated by the data nodes'
-            stopWatch.start()
+            resourceMeter.start()
             objectUnderTest.updateDataNodesAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm1', nodesJsonData, now)
-            stopWatch.stop()
-            def updateDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'update completes within expected time'
-            recordAndAssertPerformance('Update 100 data nodes', TimeUnit.SECONDS.toMillis(30), updateDurationInMillis)
+            resourceMeter.stop()
+            def updateDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'update completes within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Update 100 data nodes', TimeUnit.SECONDS.toMillis(30), updateDurationInMillis, 800, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Update leaves for 1 data node (twice)'() {
@@ -67,13 +66,13 @@ class UpdatePerfTest extends CpsPerfTestBase {
             def jsonDataUpdated  = "{'openroadm-device':{'device-id':'C201-7-1A-10','status':'fail','ne-state':'jeopardy'}}"
             def jsonDataOriginal = "{'openroadm-device':{'device-id':'C201-7-1A-10','status':'success','ne-state':'inservice'}}"
         when: 'update is performed for leaves'
-            stopWatch.start()
+            resourceMeter.start()
             objectUnderTest.updateNodeLeaves(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm2', "/openroadm-devices", jsonDataUpdated, now)
             objectUnderTest.updateNodeLeaves(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm2', "/openroadm-devices", jsonDataOriginal, now)
-            stopWatch.stop()
-            def updateDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'update completes within expected time'
-            recordAndAssertPerformance('Update leaves for 1 data node', 500, updateDurationInMillis)
+            resourceMeter.stop()
+            def updateDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'update completes within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Update leaves for 1 data node', 500, updateDurationInMillis, 300, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Batch update leaves for 100 data nodes (twice)'() {
@@ -81,13 +80,13 @@ class UpdatePerfTest extends CpsPerfTestBase {
             def jsonDataUpdated  = "{'openroadm-device':[" + (1..100).collect { "{'device-id':'C201-7-1A-" + it + "','status':'fail','ne-state':'jeopardy'}" }.join(",") + "]}"
             def jsonDataOriginal = "{'openroadm-device':[" + (1..100).collect { "{'device-id':'C201-7-1A-" + it + "','status':'success','ne-state':'inservice'}" }.join(",") + "]}"
         when: 'update is performed for leaves'
-            stopWatch.start()
+            resourceMeter.start()
             objectUnderTest.updateNodeLeaves(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm2', "/openroadm-devices", jsonDataUpdated, now)
             objectUnderTest.updateNodeLeaves(CPS_PERFORMANCE_TEST_DATASPACE, 'openroadm2', "/openroadm-devices", jsonDataOriginal, now)
-            stopWatch.stop()
-            def updateDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'update completes within expected time'
-            recordAndAssertPerformance('Batch update leaves for 100 data nodes', TimeUnit.SECONDS.toMillis(1), updateDurationInMillis)
+            resourceMeter.stop()
+            def updateDurationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'update completes within expected time and memory used is within limit'
+            recordAndAssertResourceUsage('Batch update leaves for 100 data nodes', TimeUnit.SECONDS.toMillis(1), updateDurationInMillis, 300, resourceMeter.getTotalMemoryUsageInMB())
     }
 
 }
index d03aec2..f9f0986 100644 (file)
@@ -33,12 +33,12 @@ class WritePerfTest extends CpsPerfTestBase {
         and: 'a list of device nodes to add'
             def jsonData = generateOpenRoadData(totalNodes)
         when: 'device nodes are added'
-            stopWatch.start()
+            resourceMeter.start()
             cpsDataService.saveData(CPS_PERFORMANCE_TEST_DATASPACE, 'writeAnchor', jsonData, OffsetDateTime.now())
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'the operation takes less than #expectedDuration'
-            recordAndAssertPerformance("Writing ${totalNodes} devices", TimeUnit.SECONDS.toMillis(expectedDurationInSeconds), durationInMillis)
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'the operation takes less than #expectedDuration and memory used is within limit'
+            recordAndAssertResourceUsage("Writing ${totalNodes} devices", TimeUnit.SECONDS.toMillis(expectedDurationInSeconds), durationInMillis, 400, resourceMeter.getTotalMemoryUsageInMB())
         cleanup:
             cpsDataService.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'writeAnchor', OffsetDateTime.now())
             cpsAdminService.deleteAnchor(CPS_PERFORMANCE_TEST_DATASPACE, 'writeAnchor')
@@ -61,12 +61,12 @@ class WritePerfTest extends CpsPerfTestBase {
         and: 'a list of books to add'
             def booksData = '{"books":[' + (1..totalBooks).collect {'{ "title": "' + it + '" }' }.join(',') + ']}'
         when: 'books are added'
-            stopWatch.start()
+            resourceMeter.start()
             cpsDataService.saveData(CPS_PERFORMANCE_TEST_DATASPACE, 'writeAnchor', '/bookstore/categories[@code=1]', booksData, OffsetDateTime.now())
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'the operation takes less than #expectedDuration'
-            recordAndAssertPerformance("Writing ${totalBooks} books", expectedDuration, durationInMillis)
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
+        then: 'the operation takes less than #expectedDuration and memory used is within limit'
+            recordAndAssertResourceUsage("Writing ${totalBooks} books", expectedDuration, durationInMillis, 400, resourceMeter.getTotalMemoryUsageInMB())
         cleanup:
             cpsDataService.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'writeAnchor', OffsetDateTime.now())
             cpsAdminService.deleteAnchor(CPS_PERFORMANCE_TEST_DATASPACE, 'writeAnchor')
index cf5c3f6..b12dbaa 100644 (file)
@@ -41,18 +41,18 @@ class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
 
     def 'Find many subscribers in large dataset.'() {
         when: 'all filters are queried'
-            stopWatch.start()
+            resourceMeter.start()
             def cpsPath = '//filter'
             def result = objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, cpsPath, INCLUDE_ALL_DESCENDANTS)
         then: 'got all filter entries'
             result.size() == totalNumberOfEntries
         then: 'find a random subscriptions by iteration (worst case: whole subscription matches previous entries)'
             def matches = querySubscriptionsByIteration(result, -1)
-            stopWatch.stop()
+            resourceMeter.stop()
             matches.size() == numberOfFiltersPerCmHandle * numberOfCmHandlesPerCmDataSubscription
         and: 'query all subscribers within 1 second'
-            def durationInMillis = stopWatch.getTotalTimeMillis()
-            recordAndAssertPerformance("Query all subscribers", 1_000, durationInMillis)
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
+            recordAndAssertResourceUsage("Query all subscribers", 1_000, durationInMillis, 400, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Worst case subscription update (200x10 matching entries).'() {
@@ -64,7 +64,7 @@ class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
         and: 'find all entries for an existing subscriptions'
             def matches = querySubscriptionsByIteration(result, 1)
         when: 'update all subscriptions found'
-            stopWatch.start()
+            resourceMeter.start()
             HashMap<String, List<String>> filterEntriesPerPath = [:]
             matches.each { dataNode, subscribersAsArray ->
                 def updatedSubscribers = createLeafList('subscribers', 1 + numberOfCmDataSubscribers, subscriberIdPrefix)
@@ -89,13 +89,13 @@ class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
                 cpsDataService.updateNodeLeaves(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, parentPath, json, now)
             }
 
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'a subscriber has been added to each filter entry'
             def resultAfter = objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, cpsPath, INCLUDE_ALL_DESCENDANTS)
             assert resultAfter.collect {it.leaves.subscribers.size()}.sum() == totalNumberOfEntries * (1 + numberOfCmDataSubscribers)
         and: 'update matching subscription within 8 seconds'
-            recordAndAssertPerformance("Update matching subscription", 8_000, durationInMillis)
+            recordAndAssertResourceUsage("Update matching subscription", 8_000, durationInMillis, 400, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Worst case new subscription (200x10 new entries).'() {
@@ -104,12 +104,12 @@ class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
             def filters = '"filters":' + createJsonArray('filter',numberOfFiltersPerCmHandle,'xpath','other_' + xpathPrefix,subscribers)
             def cmHandles = createJsonArray('cm-handle',numberOfCmHandlesPerCmDataSubscription,'id','other' + cmHandlePrefix, filters)
         when: 'Insert a new subscription'
-            stopWatch.start()
+            resourceMeter.start()
             cpsDataService.saveData(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, xPathForDataStore1CmHandles, cmHandles, now)
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'insert new subscription with 1 second'
-            recordAndAssertPerformance("Insert new subscription", 1_000, durationInMillis)
+            recordAndAssertResourceUsage("Insert new subscription", 1_000, durationInMillis, 400,resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def querySubscriptionsByIteration(Collection<DataNode> allSubscriptionsAsDataNodes, targetSubscriptionSequenceNumber) {
@@ -118,7 +118,7 @@ class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
             String[] subscribersAsArray = it.leaves.get('subscribers')
             Set<String> subscribersAsSet = new HashSet<>(Arrays.asList(subscribersAsArray))
             def targetSubscriptionId = subscriberIdPrefix + '-' + ( targetSubscriptionSequenceNumber > 0 ? targetSubscriptionSequenceNumber
-                                                                                                     : 1 + random.nextInt(numberOfCmDataSubscribers) )
+                    : 1 + random.nextInt(numberOfCmDataSubscribers) )
             if (subscribersAsSet.contains(targetSubscriptionId)) {
                 matches.put(it, subscribersAsArray)
             }
index 54e56d8..02881fe 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.cps.integration.performance.ncmp
 
+import org.onap.cps.integration.ResourceMeter
 import java.util.stream.Collectors
 import org.onap.cps.api.CpsQueryService
 import org.onap.cps.integration.performance.base.NcmpPerfTestBase
@@ -29,22 +30,23 @@ import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
 class CmHandleQueryPerfTest extends NcmpPerfTestBase {
 
     CpsQueryService objectUnderTest
+    ResourceMeter resourceMeter = new ResourceMeter()
 
     def setup() { objectUnderTest = cpsQueryService }
 
     def 'Query CM Handle IDs by a property name and value.'() {
         when: 'a cps-path query on name-value pair is performed (without getting descendants)'
-            stopWatch.start()
+            resourceMeter.start()
             def cpsPath = '//additional-properties[@name="neType" and @value="RadioNode"]/ancestor::cm-handles'
             def dataNodes = objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, cpsPath, OMIT_DESCENDANTS)
         and: 'the ids of the result are extracted and converted to xpath'
             def xpaths = dataNodes.stream().map(dataNode -> "/dmi-registry/cm-handles[@id='${dataNode.leaves.id}']".toString() ).collect(Collectors.toSet())
         and: 'a single get is executed to get all the parent objects and their descendants'
             def result = cpsDataService.getDataNodesForMultipleXpaths(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, xpaths, INCLUDE_ALL_DESCENDANTS)
-            stopWatch.stop()
-            def durationInMillis = stopWatch.getTotalTimeMillis()
+            resourceMeter.stop()
+            def durationInMillis = resourceMeter.getTotalTimeMillis()
         then: 'the required operations are performed within 1200 ms'
-            recordAndAssertPerformance("CpsPath Registry attributes Query", 250, durationInMillis)
+            recordAndAssertResourceUsage("CpsPath Registry attributes Query", 250, durationInMillis, 150, resourceMeter.getTotalMemoryUsageInMB())
         and: 'all but 1 (other node) are returned'
             result.size() == 999
         and: 'the tree contains all the expected descendants too'
diff --git a/integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java b/integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java
new file mode 100644 (file)
index 0000000..c6ad96e
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  ============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;
+
+import org.springframework.util.StopWatch;
+
+/**
+ * Time and memory stop watch, exposing total running time and memory used.
+ */
+public class ResourceMeter {
+    private final StopWatch stopWatch = new StopWatch();
+    private long memoryUsedBefore;
+    private long memoryUsedAfter;
+
+    /**
+     * Start measurement.
+     */
+    public void start() {
+        System.gc();
+        memoryUsedBefore = getCurrentMemoryUsage();
+        stopWatch.start();
+    }
+
+    /**
+     * Stop measurement.
+     */
+    public void stop() {
+        stopWatch.stop();
+        memoryUsedAfter = getCurrentMemoryUsage();
+    }
+
+    /**
+     * Get the total time in milliseconds.
+     * @return total time in milliseconds
+     */
+    public long getTotalTimeMillis() {
+        return stopWatch.getTotalTimeMillis();
+    }
+
+    /**
+     * Get the total memory used in megabytes.
+     * @return total memory used in megabytes
+     */
+    public double getTotalMemoryUsageInMB() {
+        return (memoryUsedAfter - memoryUsedBefore) / 1_000_000.0;
+    }
+
+    private static long getCurrentMemoryUsage() {
+        return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+    }
+}
+