Merge "Rename Subscrption Perf Test class to fit filename"
[cps.git] / integration-test / src / test / groovy / org / onap / cps / integration / performance / ncmp / CmDataSubscriptionsPerfTest.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.ncmp
22
23 import org.onap.cps.api.CpsQueryService
24 import org.onap.cps.integration.performance.base.NcmpPerfTestBase
25 import org.onap.cps.spi.model.DataNode
26
27 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
28
29 class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
30
31     def datastore1cmHandlePlaceHolder = '{"datastores":{"datastore":[{"name":"ds-1","cm-handles":{"cm-handle":[]}}]}}'
32     def xPathForDataStore1CmHandles = '/datastores/datastore[@name="ds-1"]/cm-handles'
33
34     CpsQueryService objectUnderTest
35
36     def setup() { objectUnderTest = cpsQueryService }
37
38     def totalNumberOfEntries = numberOfFiltersPerCmHandle * numberOfCmHandlesPerCmDataSubscription
39
40     def random = new Random()
41
42     def 'Find many subscribers in large dataset.'() {
43         when: 'all filters are queried'
44             stopWatch.start()
45             def cpsPath = '//filter'
46             def result = objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, cpsPath, INCLUDE_ALL_DESCENDANTS)
47         then: 'got all filter entries'
48             result.size() == totalNumberOfEntries
49         then: 'find a random subscriptions by iteration (worst case: whole subscription matches previous entries)'
50             def matches = querySubscriptionsByIteration(result, -1)
51             stopWatch.stop()
52             matches.size() == numberOfFiltersPerCmHandle * numberOfCmHandlesPerCmDataSubscription
53         and: 'query all subscribers within 1 second'
54             def durationInMillis = stopWatch.getTotalTimeMillis()
55             recordAndAssertPerformance("Query all subscribers", 1_000, durationInMillis)
56     }
57
58     def 'Worst case new subscription (200x10 new entries).'() {
59         given: 'a new subscription with non-matching data'
60             def subscribers = createLeafList('subscribers',1, subscriberIdPrefix)
61             def filters = '"filters":' + createJsonArray('filter',numberOfFiltersPerCmHandle,'xpath','other_' + xpathPrefix,subscribers)
62             def cmHandles = createJsonArray('cm-handle',numberOfCmHandlesPerCmDataSubscription,'id','other' + cmHandlePrefix, filters)
63         when: 'Insert a new subscription'
64             stopWatch.start()
65             cpsDataService.saveData(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, xPathForDataStore1CmHandles, cmHandles, now)
66             stopWatch.stop()
67             def durationInMillis = stopWatch.getTotalTimeMillis()
68         then: 'insert new subscription with 1 second'
69             recordAndAssertPerformance("Insert new subscription", 1_000, durationInMillis)
70     }
71
72     def 'Worst case subscription update (200x10 matching entries).'() {
73         given: 'all filters are queried'
74             def cpsPath = '//filter'
75             def result = objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, cpsPath, INCLUDE_ALL_DESCENDANTS)
76         and: 'find all entries for an existing subscriptions'
77             def matches = querySubscriptionsByIteration(result, 1)
78         when: 'Update all subscriptions found'
79             stopWatch.start()
80             /* the production code version of this should manipulate the original subscribersAsArray of course
81                but for the (performance) poc creating another array with one extra element suffices
82              */
83             def jsonPerPath = [:]
84             matches.each { xpath, subscribersAsArray ->
85                 def updatedSubscribers = createLeafList('subscribers', 1 + numberOfCmDataSubscribers, subscriberIdPrefix)
86                 def filterEntry = '{"filter": {"xpath":"' + xpath + '", ' + updatedSubscribers + ' } }'
87                 def parentPath = xpath.toString().substring(0, xpath.toString().indexOf('/filter[@xpath='))
88                 jsonPerPath.put(parentPath, filterEntry)
89             }
90             cpsDataService.updateDataNodesAndDescendants(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, jsonPerPath, now)
91             stopWatch.stop()
92             def durationInMillis = stopWatch.getTotalTimeMillis()
93         then: 'Update matching subscription within 8 seconds'
94             //TODO Toine check with Daniel if this can be optimized quickly without really changing production code
95             // ie is there a better way of doing these 2,000 updates
96             recordAndAssertPerformance("Update matching subscription", 8_000, durationInMillis)
97     }
98
99     def querySubscriptionsByIteration(Collection<DataNode> allSubscriptionsAsDataNodes, targetSubscriptionSequenceNumber) {
100         def matches = [:]
101         allSubscriptionsAsDataNodes.each {
102             String[] subscribersAsArray = it.leaves.get('subscribers')
103             Set<String> subscribersAsSet = new HashSet<>(Arrays.asList(subscribersAsArray))
104             def targetSubscriptionId = subscriberIdPrefix + '-' + ( targetSubscriptionSequenceNumber > 0 ? targetSubscriptionSequenceNumber
105                                                                                                      : 1 + random.nextInt(numberOfCmDataSubscribers) )
106             if (subscribersAsSet.contains(targetSubscriptionId)) {
107                 matches.put(it.xpath, subscribersAsArray)
108             }
109         }
110         return matches
111     }
112
113 }