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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.cps.integration.performance.cps
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
29 import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
31 class UpdatePerfTest extends CpsPerfTestBase {
32 static final def UPDATE_TEST_ANCHOR = 'updateTestAnchor'
33 static final def INNER_NODE_JSON = readResourceDataFile('openroadm/innerNode.json')
35 CpsDataService objectUnderTest
36 def now = OffsetDateTime.now()
38 def setup() { objectUnderTest = cpsDataService }
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')
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')
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
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'
71 objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now)
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())
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
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'
97 objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now)
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())
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
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)
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())
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)
141 def generateJsonForOpenRoadmDevices(int startId, int totalNodes, boolean changeLeaves) {
142 return '{ "openroadm-device": [' + (0..<totalNodes).collect {makeInnerNodeJson(it + startId, changeLeaves) }.join(',') + ']}}'
145 def makeInnerNodeJson(int nodeId, boolean changeLeaf) {
146 def nodeJson = INNER_NODE_JSON.replace('NODE_ID_HERE', nodeId.toString())
148 nodeJson = nodeJson.replace('"status": "success"', '"status": "fail"')
153 def countDataNodes(String cpsPathQuery) {
154 return cpsQueryService.queryDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, cpsPathQuery, OMIT_DESCENDANTS).size()