Merge "Add performance tests for saveListElements"
[cps.git] / integration-test / src / test / groovy / org / onap / cps / integration / performance / cps / UpdatePerfTest.groovy
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2023 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the 'License');
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an 'AS IS' BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20
21 package org.onap.cps.integration.performance.cps
22
23 import java.time.OffsetDateTime
24 import org.onap.cps.api.CpsDataService
25 import org.onap.cps.integration.performance.base.CpsPerfTestBase
26
27 import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
28
29 class UpdatePerfTest extends CpsPerfTestBase {
30     static final def UPDATE_TEST_ANCHOR = 'updateTestAnchor'
31     static final def INNER_NODE_JSON = readResourceDataFile('openroadm/innerNode.json')
32
33     CpsDataService objectUnderTest
34     def now = OffsetDateTime.now()
35
36     def setup() { objectUnderTest = cpsDataService }
37
38     def 'Test setup for CPS Update API.'() {
39         given: 'an anchor and empty container node for OpenROADM devices'
40             cpsAnchorService.createAnchor(CPS_PERFORMANCE_TEST_DATASPACE, LARGE_SCHEMA_SET, UPDATE_TEST_ANCHOR)
41             cpsDataService.saveData(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR,
42                     '{ "openroadm-devices": { "openroadm-device": []}}', now)
43         expect: 'no device nodes exist yet'
44             assert 0 == countDataNodes('/openroadm-devices/openroadm-device')
45     }
46
47     def 'JVM warm up for update tests: #scenario.'() {
48         given: 'replacement JSON for node containing list of device nodes'
49             def jsonData = '{ "openroadm-devices": ' + generateJsonForOpenRoadmDevices(startId, totalNodes, changeLeaves) + '}'
50         when: 'the container node is updated'
51             objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now)
52         then: 'there are the expected number of total nodes'
53             assert totalNodes == countDataNodes('/openroadm-devices/openroadm-device')
54         where:
55             scenario                           | totalNodes | startId | changeLeaves
56             'Replace 0 nodes with 100'         | 100        | 1       | false
57             'Replace 100 using same data'      | 100        | 1       | false
58             'Replace 100 with new leaf values' | 100        | 1       | true
59             'Replace 100 with 100 new nodes'   | 100        | 101     | false
60             'Replace 50 existing and 50 new'   | 100        | 151     | true
61             'Replace 100 nodes with 0'         | 0          | 1       | false
62     }
63
64     def 'Replace single data node and descendants: #scenario.'() {
65         given: 'replacement JSON for node containing list of device nodes'
66             def jsonData = '{ "openroadm-devices": ' + generateJsonForOpenRoadmDevices(startId, totalNodes, changeLeaves) + '}'
67         when: 'the container node is updated'
68             resourceMeter.start()
69             objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now)
70             resourceMeter.stop()
71         then: 'there are the expected number of total nodes'
72             assert totalNodes == countDataNodes('/openroadm-devices/openroadm-device')
73         and: 'data leaves have expected values'
74             assert totalNodes == countDataNodes(changeLeaves? '/openroadm-devices/openroadm-device[@status="fail"]'
75                                                             : '/openroadm-devices/openroadm-device[@status="success"]')
76         and: 'update completes within expected time and memory used is within limit'
77             recordAndAssertResourceUsage(scenario,
78                     timeLimit, resourceMeter.getTotalTimeInSeconds(),
79                     memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
80         where:
81             scenario                           | totalNodes | startId | changeLeaves || timeLimit | memoryLimit
82             'Replace 0 nodes with 100'         | 100        | 1       | false        ||         7 | 250
83             'Replace 100 using same data'      | 100        | 1       | false        ||         5 | 250
84             'Replace 100 with new leaf values' | 100        | 1       | true         ||         5 | 250
85             'Replace 100 with 100 new nodes'   | 100        | 101     | false        ||        12 | 300
86             'Replace 50 existing and 50 new'   | 100        | 151     | true         ||         8 | 250
87             'Replace 100 nodes with 0'         | 0          | 1       | false        ||         5 | 250
88     }
89
90     def 'Replace list content: #scenario.'() {
91         given: 'replacement JSON for list of device nodes'
92             def jsonListData = generateJsonForOpenRoadmDevices(startId, totalNodes, changeLeaves)
93         when: 'the container node is updated'
94             resourceMeter.start()
95             objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now)
96             resourceMeter.stop()
97         then: 'there are the expected number of total nodes'
98             assert totalNodes == countDataNodes('/openroadm-devices/openroadm-device')
99         and: 'data leaves have expected values'
100             assert totalNodes == countDataNodes(changeLeaves? '/openroadm-devices/openroadm-device[@status="fail"]'
101                                                             : '/openroadm-devices/openroadm-device[@status="success"]')
102         and: 'update completes within expected time and memory used is within limit'
103             recordAndAssertResourceUsage(scenario,
104                     timeLimit, resourceMeter.getTotalTimeInSeconds(),
105                     memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
106         where:
107             scenario                                   | totalNodes | startId | changeLeaves || timeLimit | memoryLimit
108             'Replace list of 0 with 100'               | 100        | 1       | false        ||         7 | 250
109             'Replace list of 100 using same data'      | 100        | 1       | false        ||         5 | 250
110             'Replace list of 100 with new leaf values' | 100        | 1       | true         ||         5 | 250
111             'Replace list with 100 new nodes'          | 100        | 101     | false        ||        12 | 300
112             'Replace list with 50 existing and 50 new' | 100        | 151     | true         ||         8 | 250
113             'Replace list of 100 nodes with 1'         | 1          | 1       | false        ||         5 | 250
114     }
115
116     def 'Update leaves for 100 data nodes.'() {
117         given: 'there are 200 existing data nodes'
118             def jsonListData = generateJsonForOpenRoadmDevices(1, 200, false)
119             objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now)
120         and: 'JSON for updated data leaves of 100 nodes'
121             def jsonDataUpdated  = "{'openroadm-device':[" + (1..100).collect {"{'device-id':'C201-7-1A-" + it + "','status':'fail','ne-state':'jeopardy'}" }.join(",") + "]}"
122         when: 'update is performed for leaves'
123             resourceMeter.start()
124             objectUnderTest.updateNodeLeaves(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, "/openroadm-devices", jsonDataUpdated, now)
125             resourceMeter.stop()
126         then: 'data leaves have expected values'
127             assert 100 == countDataNodes('/openroadm-devices/openroadm-device[@status="fail"]')
128         and: 'update completes within expected time and memory used is within limit'
129             recordAndAssertResourceUsage('Update leaves for 100 data nodes',
130                     0.5, resourceMeter.getTotalTimeInSeconds(),
131                     120, resourceMeter.getTotalMemoryUsageInMB())
132     }
133
134     def 'Clean up for CPS Update API.'() {
135         cleanup: 'test anchor and data nodes'
136             cpsAnchorService.deleteAnchor(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR)
137     }
138
139     def generateJsonForOpenRoadmDevices(int startId, int totalNodes, boolean changeLeaves) {
140         return '{ "openroadm-device": [' + (0..<totalNodes).collect {makeInnerNodeJson(it + startId, changeLeaves) }.join(',') + ']}}'
141     }
142
143     def makeInnerNodeJson(int nodeId, boolean changeLeaf) {
144         def nodeJson = INNER_NODE_JSON.replace('NODE_ID_HERE', nodeId.toString())
145         if (changeLeaf) {
146             nodeJson = nodeJson.replace('"status": "success"', '"status": "fail"')
147         }
148         return nodeJson
149     }
150
151     def countDataNodes(String cpsPathQuery) {
152         return cpsQueryService.queryDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, cpsPathQuery, OMIT_DESCENDANTS).size()
153     }
154
155 }