Improve batch delete schemasets performance
[cps.git] / cps-ri / src / test / groovy / org / onap / cps / spi / performance / CpsDataPersistenceServiceDeletePerfTest.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.spi.performance
22
23 import org.onap.cps.spi.CpsDataPersistenceService
24 import org.onap.cps.spi.impl.CpsPersistencePerfSpecBase
25 import org.springframework.beans.factory.annotation.Autowired
26 import org.springframework.test.context.jdbc.Sql
27 import org.springframework.util.StopWatch
28
29 class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase {
30
31     @Autowired
32     CpsDataPersistenceService objectUnderTest
33
34     def stopWatch = new StopWatch()
35
36     @Sql([CLEAR_DATA, PERF_TEST_DATA])
37     def 'Create a node with many descendants (please note, subsequent tests depend on this running first).'() {
38         when: 'a node with a large number of descendants is created'
39             stopWatch.start()
40             createLineage(objectUnderTest, 150, 50, false)
41             stopWatch.stop()
42             def setupDurationInMillis = stopWatch.getTotalTimeMillis()
43         then: 'setup duration is under 10 seconds'
44             recordAndAssertPerformance('Setup', 10_000, setupDurationInMillis)
45     }
46
47     def 'Delete 5 children with grandchildren'() {
48         when: 'child nodes are deleted'
49             stopWatch.start()
50             (1..5).each {
51                 def childPath = "${PERF_TEST_PARENT}/perf-test-child-${it}".toString()
52                 objectUnderTest.deleteDataNode(PERF_DATASPACE, PERF_ANCHOR, childPath)
53             }
54             stopWatch.stop()
55             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
56         then: 'delete duration is under 350 milliseconds'
57             recordAndAssertPerformance('Delete 5 children', 350, deleteDurationInMillis)
58     }
59
60     def 'Batch delete 100 children with grandchildren'() {
61         given: 'a list of xpaths to delete'
62             def xpathsToDelete = (6..105).collect {
63                 "${PERF_TEST_PARENT}/perf-test-child-${it}".toString()
64             }
65         when: 'child nodes are deleted'
66             stopWatch.start()
67             objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR, xpathsToDelete)
68             stopWatch.stop()
69             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
70         then: 'delete duration is under 350 milliseconds'
71             recordAndAssertPerformance('Batch delete 100 children', 350, deleteDurationInMillis)
72     }
73
74     def 'Delete 50 grandchildren (that have no descendants)'() {
75         when: 'target nodes are deleted'
76             stopWatch.start()
77             (1..50).each {
78                 def grandchildPath = "${PERF_TEST_PARENT}/perf-test-child-106/perf-test-grand-child-${it}".toString()
79                 objectUnderTest.deleteDataNode(PERF_DATASPACE, PERF_ANCHOR, grandchildPath)
80             }
81             stopWatch.stop()
82             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
83         then: 'delete duration is under 350 milliseconds'
84             recordAndAssertPerformance('Delete 50 grandchildren', 350, deleteDurationInMillis)
85     }
86
87     def 'Batch delete 500 grandchildren (that have no descendants)'() {
88         given: 'a list of xpaths to delete'
89             def xpathsToDelete = []
90             for (int childIndex = 0; childIndex < 10; childIndex++) {
91                 xpathsToDelete.addAll((1..50).collect {
92                     "${PERF_TEST_PARENT}/perf-test-child-${107+childIndex}/perf-test-grand-child-${it}".toString()
93                 })
94             }
95         when: 'target nodes are deleted'
96             stopWatch.start()
97             objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR, xpathsToDelete)
98             stopWatch.stop()
99             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
100         then: 'delete duration is under 350 milliseconds'
101             recordAndAssertPerformance('Batch delete 500 grandchildren', 350, deleteDurationInMillis)
102     }
103
104     @Sql([CLEAR_DATA, PERF_TEST_DATA])
105     def 'Create a node with many list elements (please note, subsequent tests depend on this running first).'() {
106         when: 'a node with a large number of lists is created'
107             stopWatch.start()
108             createLineage(objectUnderTest, 150, 50, true)
109             stopWatch.stop()
110             def setupDurationInMillis = stopWatch.getTotalTimeMillis()
111         then: 'setup duration is under 10 seconds'
112             recordAndAssertPerformance('Setup lists', 10_000, setupDurationInMillis)
113     }
114
115     def 'Delete 5 whole lists'() {
116         when: 'lists are deleted'
117             stopWatch.start()
118             (1..5).each {
119                 def childPath = "${PERF_TEST_PARENT}/perf-test-list-${it}".toString()
120                 objectUnderTest.deleteListDataNode(PERF_DATASPACE, PERF_ANCHOR, childPath)
121             }
122             stopWatch.stop()
123             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
124         then: 'delete duration is under 1500 milliseconds'
125             recordAndAssertPerformance('Delete 5 whole lists', 1500, deleteDurationInMillis)
126     }
127
128     def 'Batch delete 100 whole lists'() {
129         given: 'a list of xpaths to delete'
130             def xpathsToDelete = (6..105).collect {
131                 "${PERF_TEST_PARENT}/perf-test-list-${it}".toString()
132             }
133         when: 'lists are deleted'
134             stopWatch.start()
135             objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR, xpathsToDelete)
136             stopWatch.stop()
137             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
138         then: 'delete duration is under 350 milliseconds'
139             recordAndAssertPerformance('Batch delete 100 whole lists', 350, deleteDurationInMillis)
140     }
141
142     def 'Delete 10 list elements'() {
143         when: 'list elements are deleted'
144             stopWatch.start()
145             (1..10).each {
146                 def grandchildPath = "${PERF_TEST_PARENT}/perf-test-list-106[@key='${it}']".toString()
147                 objectUnderTest.deleteListDataNode(PERF_DATASPACE, PERF_ANCHOR, grandchildPath)
148             }
149             stopWatch.stop()
150             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
151         then: 'delete duration is under 750 milliseconds'
152             recordAndAssertPerformance('Delete 10 lists elements', 750, deleteDurationInMillis)
153     }
154
155     def 'Batch delete 500 list elements'() {
156         given: 'a list of xpaths to delete'
157             def xpathsToDelete = []
158             for (int childIndex = 0; childIndex < 10; childIndex++) {
159                 xpathsToDelete.addAll((1..50).collect {
160                     "${PERF_TEST_PARENT}/perf-test-list-${107+childIndex}[@key='${it}']".toString()
161                 })
162             }
163         when: 'list elements are deleted'
164             stopWatch.start()
165             objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR, xpathsToDelete)
166             stopWatch.stop()
167             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
168         then: 'delete duration is under 350 milliseconds'
169             recordAndAssertPerformance('Batch delete 500 lists elements', 350, deleteDurationInMillis)
170     }
171
172     @Sql([CLEAR_DATA, PERF_TEST_DATA])
173     def 'Delete 1 large data node'() {
174         given: 'a node with a large number of descendants is created'
175             createLineage(objectUnderTest, 50, 50, false)
176             createLineage(objectUnderTest, 50, 50, true)
177         when: 'parent node is deleted'
178             stopWatch.start()
179             objectUnderTest.deleteDataNode(PERF_DATASPACE, PERF_ANCHOR, PERF_TEST_PARENT)
180             stopWatch.stop()
181             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
182         then: 'delete duration is under 300 milliseconds'
183             recordAndAssertPerformance('Delete one large node', 300, deleteDurationInMillis)
184     }
185
186     @Sql([CLEAR_DATA, PERF_TEST_DATA])
187     def 'Batch delete 1 large data node'() {
188         given: 'a node with a large number of descendants is created'
189             createLineage(objectUnderTest, 50, 50, false)
190             createLineage(objectUnderTest, 50, 50, true)
191         when: 'parent node is batch deleted'
192             stopWatch.start()
193             objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR, [PERF_TEST_PARENT])
194             stopWatch.stop()
195             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
196         then: 'delete duration is under 300 milliseconds'
197             recordAndAssertPerformance('Batch delete one large node', 300, deleteDurationInMillis)
198     }
199
200     @Sql([CLEAR_DATA, PERF_TEST_DATA])
201     def 'Delete root node with many descendants'() {
202         given: 'a node with a large number of descendants is created'
203             createLineage(objectUnderTest, 50, 50, false)
204             createLineage(objectUnderTest, 50, 50, true)
205         when: 'root node is deleted'
206             stopWatch.start()
207             objectUnderTest.deleteDataNode(PERF_DATASPACE, PERF_ANCHOR, '/')
208             stopWatch.stop()
209             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
210         then: 'delete duration is under 300 milliseconds'
211             recordAndAssertPerformance('Delete root node', 300, deleteDurationInMillis)
212     }
213
214     @Sql([CLEAR_DATA, PERF_TEST_DATA])
215     def 'Delete data nodes for an anchor'() {
216         given: 'a node with a large number of descendants is created'
217             createLineage(objectUnderTest, 50, 50, false)
218             createLineage(objectUnderTest, 50, 50, true)
219         when: 'data nodes are deleted'
220             stopWatch.start()
221             objectUnderTest.deleteDataNodes(PERF_DATASPACE, PERF_ANCHOR)
222             stopWatch.stop()
223             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
224         then: 'delete duration is under 300 milliseconds'
225             recordAndAssertPerformance('Delete data nodes for anchor', 300, deleteDurationInMillis)
226     }
227
228     @Sql([CLEAR_DATA, PERF_TEST_DATA])
229     def 'Delete data nodes for multiple anchors'() {
230         given: 'a node with a large number of descendants is created'
231             createLineage(objectUnderTest, 50, 50, false)
232             createLineage(objectUnderTest, 50, 50, true)
233         when: 'data nodes are deleted'
234             stopWatch.start()
235             objectUnderTest.deleteDataNodes(PERF_DATASPACE, [PERF_ANCHOR])
236             stopWatch.stop()
237             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
238         then: 'delete duration is under 300 milliseconds'
239             recordAndAssertPerformance('Delete data nodes for anchor', 300, deleteDurationInMillis)
240     }
241
242 }