a105d1daa3034866eabe1186085567781fd05a00
[cps.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * Copyright (c) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
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.ncmp.impl.datajobs.subscription.utils
23
24 import static CmDataJobSubscriptionPersistenceService.CPS_PATH_TEMPLATE_FOR_SUBSCRIPTIONS_WITH_DATA_NODE_SELECTOR
25 import static CmDataJobSubscriptionPersistenceService.CPS_PATH_TEMPLATE_FOR_SUBSCRIPTION_WITH_DATA_JOB_ID
26 import static CmDataJobSubscriptionPersistenceService.CPS_PATH_TEMPLATE_FOR_INACTIVE_SUBSCRIPTIONS
27 import static CmDataJobSubscriptionPersistenceService.PARENT_NODE_XPATH
28 import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
29 import static org.onap.cps.ncmp.impl.datajobs.subscription.models.CmSubscriptionStatus.ACCEPTED
30
31 import com.fasterxml.jackson.databind.ObjectMapper
32 import org.onap.cps.api.CpsDataService
33 import org.onap.cps.api.CpsQueryService
34 import org.onap.cps.api.model.DataNode
35 import org.onap.cps.utils.ContentType
36 import org.onap.cps.utils.JsonObjectMapper
37 import spock.lang.Specification
38
39
40 class CmSubscriptionPersistenceServiceSpec extends Specification {
41
42     def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
43     def mockCpsQueryService = Mock(CpsQueryService)
44     def mockCpsDataService = Mock(CpsDataService)
45
46     def objectUnderTest = new CmDataJobSubscriptionPersistenceService(jsonObjectMapper, mockCpsQueryService, mockCpsDataService)
47
48     def 'Check cm data job subscription details has at least one subscriber #scenario'() {
49         given: 'a valid cm data job subscription query'
50             def cpsPathQuery = CPS_PATH_TEMPLATE_FOR_SUBSCRIPTIONS_WITH_DATA_NODE_SELECTOR.formatted('/myDataNodeSelector')
51         and: 'datanodes optionally returned'
52             1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-job-subscriptions', cpsPathQuery, OMIT_DESCENDANTS) >> dataNode
53         when: 'we check if subscription details already has at least one subscriber'
54             def result = objectUnderTest.hasAtLeastOneSubscription('/myDataNodeSelector')
55         then: 'we get expected result'
56             assert result == hasAtLeastOneSubscription
57         where: 'following scenarios are used'
58             scenario                  | dataNode                                              || hasAtLeastOneSubscription
59             'valid datanodes present' | [new DataNode(leaves: ['dataJobId': ['dataJobId1']])] || true
60             'no datanodes present'    | []                                                    || false
61     }
62
63     def 'Checking uniqueness of incoming subscription ID'() {
64         given: 'a cps path with a data job subscription ID for querying'
65             def cpsPathQuery = CPS_PATH_TEMPLATE_FOR_SUBSCRIPTION_WITH_DATA_JOB_ID.formatted('mySubId')
66         and: 'collection of data nodes are returned'
67             1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-job-subscriptions', cpsPathQuery, OMIT_DESCENDANTS) >> dataNodes
68         when: 'a data job subscription id is tested for uniqueness'
69             def result = objectUnderTest.isNewSubscriptionId('mySubId')
70         then: 'result is as expected'
71             assert result == isValidDataJobSubscriptionId
72         where: 'following scenarios are used'
73             scenario               | dataNodes        || isValidDataJobSubscriptionId
74             'datanodes present'    | [new DataNode()] || false
75             'no datanodes present' | []               || true
76     }
77
78     def 'Get all inactive data node selectors for subscription id'() {
79         given: 'the query service returns nodes for subscription id'
80             def expectedDataNode = new DataNode(leaves: ['datajobId': ['id1'], 'dataNodeSelector': '/dataNodeSelector', 'status': 'UNKNOWN'])
81             def queryServiceResponse = [expectedDataNode].asCollection()
82             def cmDataJobSubscriptionIdCpsPath = CPS_PATH_TEMPLATE_FOR_INACTIVE_SUBSCRIPTIONS.formatted('id1')
83             1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-job-subscriptions', cmDataJobSubscriptionIdCpsPath, OMIT_DESCENDANTS) >> queryServiceResponse
84         when: 'retrieving all nodes for data job subscription id'
85             def result = objectUnderTest.getInactiveDataNodeSelectors('id1')
86         then: 'the result returns correct number of datanodes'
87             assert result.size() == 1
88         and: 'the attribute of the data nodes is as expected'
89             assert result.iterator().next() == expectedDataNode.leaves.dataNodeSelector
90     }
91
92     def 'Add subscription for a data node selector that have no subscriptions yet.'() {
93         given: 'a valid cm data job subscription path query'
94             def dataNodeSelector = '/myDataNodeSelector'
95             def query = CPS_PATH_TEMPLATE_FOR_SUBSCRIPTIONS_WITH_DATA_NODE_SELECTOR.formatted(dataNodeSelector)
96         and: 'a data node does not exist for cm data job subscription path query'
97             mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-job-subscriptions', query, OMIT_DESCENDANTS) >> []
98         and: 'data job subscription details is mapped as JSON'
99             def subscriptionIds = ['newSubId']
100             def subscriptionAsJson = objectUnderTest.createSubscriptionDetailsAsJson(dataNodeSelector, subscriptionIds, 'UNKNOWN')
101         when: 'the method to add cm notification subscription is called'
102             objectUnderTest.add('newSubId', dataNodeSelector)
103         then: 'data service method to create new subscription for given subscriber is called once with the correct parameters'
104             1 * mockCpsDataService.saveData('NCMP-Admin', 'cm-data-job-subscriptions', subscriptionAsJson, _, ContentType.JSON)
105     }
106
107     def 'Add subscription for a data node selector that already have subscription(s).'() {
108         given: 'a valid cm subscription path query'
109             def dataNodeSelector = '/myDataNodeSelector'
110             def query = CPS_PATH_TEMPLATE_FOR_SUBSCRIPTIONS_WITH_DATA_NODE_SELECTOR.formatted(dataNodeSelector)
111         and: 'a dataNode exists for the given cps path query'
112             mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-job-subscriptions', query, OMIT_DESCENDANTS) >> [new DataNode(leaves: ['dataJobId': ['existingId'], 'dataNodeSelector': dataNodeSelector, 'status': 'ACCEPTED'])]
113         and: 'updated cm data job subscription details as json'
114             def newListOfSubscriptionIds = ['existingId', 'newSubId']
115             def subscriptionDetailsAsJson = objectUnderTest.createSubscriptionDetailsAsJson(dataNodeSelector, newListOfSubscriptionIds, 'ACCEPTED')
116         when: 'the method to add cm notification subscription is called'
117             objectUnderTest.add('newSubId', dataNodeSelector)
118         then: 'data service method to update list of subscribers is called once'
119             1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'cm-data-job-subscriptions', PARENT_NODE_XPATH, subscriptionDetailsAsJson, _, ContentType.JSON)
120     }
121
122     def 'Update subscription status'() {
123         given: 'a data node selector'
124             def myDataNodeSelector = "/myDataNodeSelector"
125         and: 'a status'
126             def status = ACCEPTED
127         and: 'the query service returns data node'
128             def subscriptionIds = ['someId']
129             mockCpsQueryService.queryDataNodes(_,_,_,_) >> [new DataNode(leaves: ['dataJobId': subscriptionIds, 'dataNodeSelector': myDataNodeSelector, 'status': 'UNKNOWN'])]
130         and: 'updated cm data job subscription details as json'
131             def subscriptionDetailsAsJson = objectUnderTest.createSubscriptionDetailsAsJson(myDataNodeSelector, subscriptionIds, status.name())
132         when: 'the method to update subscription status is called'
133             objectUnderTest.updateCmSubscriptionStatus(myDataNodeSelector, status)
134         then: 'data service method to update list of subscribers is called once'
135             1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'cm-data-job-subscriptions', PARENT_NODE_XPATH, subscriptionDetailsAsJson, _, _)
136
137     }
138
139 }