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