Merge "Add metrics for NCMP passthrough read operation"
[cps.git] / cps-ncmp-service / src / test / groovy / org / onap / cps / ncmp / api / impl / events / lcm / LcmEventsCmHandleStateHandlerImplSpec.groovy
1 /*
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2022-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.ncmp.api.impl.events.lcm
22
23 import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.ADVISED
24 import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.DELETED
25 import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.DELETING
26 import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.LOCKED
27 import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.READY
28 import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_SYNC_FAILED
29
30 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
31 import org.onap.cps.ncmp.api.impl.inventory.CompositeState
32 import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
33 import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
34 import spock.lang.Specification
35
36 class LcmEventsCmHandleStateHandlerImplSpec extends Specification {
37
38     def mockInventoryPersistence = Mock(InventoryPersistence)
39     def mockLcmEventsCreator = Mock(LcmEventsCreator)
40     def mockLcmEventsService = Mock(LcmEventsService)
41
42     def lcmEventsCmHandleStateHandlerAsyncHelper = new LcmEventsCmHandleStateHandlerAsyncHelper(mockLcmEventsCreator, mockLcmEventsService)
43     def objectUnderTest = new LcmEventsCmHandleStateHandlerImpl(mockInventoryPersistence, lcmEventsCmHandleStateHandlerAsyncHelper)
44
45     def cmHandleId = 'cmhandle-id-1'
46     def compositeState
47     def yangModelCmHandle
48
49     def 'Update and Publish Events on State Change #stateChange'() {
50         given: 'Cm Handle represented as YangModelCmHandle'
51             compositeState = new CompositeState(cmHandleState: fromCmHandleState)
52             yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState)
53         when: 'update state is invoked'
54             objectUnderTest.updateCmHandleState(yangModelCmHandle, toCmHandleState)
55         then: 'state is saved using inventory persistence'
56             expectedCallsToInventoryPersistence * mockInventoryPersistence.saveCmHandleState(cmHandleId, _)
57         and: 'event service is called to publish event'
58             expectedCallsToEventService * mockLcmEventsService.publishLcmEvent(cmHandleId, _, _)
59         where: 'state change parameters are provided'
60             stateChange          | fromCmHandleState | toCmHandleState || expectedCallsToInventoryPersistence | expectedCallsToEventService
61             'ADVISED to READY'   | ADVISED           | READY           || 1                                   | 1
62             'READY to LOCKED'    | READY             | LOCKED          || 1                                   | 1
63             'ADVISED to ADVISED' | ADVISED           | ADVISED         || 0                                   | 0
64             'READY to READY'     | READY             | READY           || 0                                   | 0
65             'LOCKED to LOCKED'   | LOCKED            | LOCKED          || 0                                   | 0
66             'DELETED to ADVISED' | DELETED           | ADVISED         || 0                                   | 1
67     }
68
69     def 'Update and Publish Events on State Change from NO_EXISTING state to ADVISED'() {
70         given: 'Cm Handle represented as YangModelCmHandle'
71             yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [])
72         when: 'update state is invoked'
73             objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED)
74         then: 'state is saved using inventory persistence'
75             1 * mockInventoryPersistence.saveCmHandle(yangModelCmHandle)
76         and: 'event service is called to publish event'
77             1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _, _)
78     }
79
80     def 'Update and Publish Events on State Change from LOCKED to ADVISED'() {
81         given: 'Cm Handle represented as YangModelCmHandle in LOCKED state'
82             compositeState = new CompositeState(cmHandleState: LOCKED,
83                 lockReason: CompositeState.LockReason.builder().lockReasonCategory(MODULE_SYNC_FAILED).details('some lock details').build())
84             yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState)
85         when: 'update state is invoked'
86             objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED)
87         then: 'state is saved using inventory persistence and old lock reason details are retained'
88             1 * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) >> {
89                 args -> {
90                     assert (args[1] as CompositeState).lockReason.details == 'some lock details'
91                 }
92             }
93         and: 'event service is called to publish event'
94             1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _, _)
95     }
96
97     def 'Update and Publish Events on State Change from DELETING to ADVISED'() {
98         given: 'Cm Handle represented as YangModelCmHandle in DELETING state'
99             yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState)
100         when: 'update state is invoked'
101             objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED)
102         then: 'the cm handle is saved using inventory persistence'
103             1 * mockInventoryPersistence.saveCmHandle(yangModelCmHandle)
104         and: 'event service is called to publish event'
105             1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _, _)
106     }
107
108     def 'Update and Publish Events on State Change to READY'() {
109         given: 'Cm Handle represented as YangModelCmHandle'
110             compositeState = new CompositeState(cmHandleState: ADVISED)
111             yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState)
112         and: 'global sync flag is set'
113             compositeState.setDataSyncEnabled(false)
114         when: 'update cmhandle state is invoked'
115             objectUnderTest.updateCmHandleState(yangModelCmHandle, READY)
116         then: 'state is saved using inventory persistence with expected dataSyncState'
117             1 * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) >> {
118                 args-> {
119                     def result = (args[1] as CompositeState)
120                     assert result.dataSyncEnabled == false
121                     assert result.dataStores.operationalDataStore.dataStoreSyncState == DataStoreSyncState.NONE_REQUESTED
122
123                 }
124             }
125         and: 'event service is called to publish event'
126             1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _, _)
127     }
128
129     def 'Update cmHandle state to "DELETING"' (){
130         given: 'cm Handle as Yang model'
131             compositeState = new CompositeState(cmHandleState: READY)
132             yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState)
133         when: 'updating cm handle state to "DELETING"'
134             objectUnderTest.updateCmHandleState(yangModelCmHandle, DELETING)
135         then: 'the cm handle state is as expected'
136             yangModelCmHandle.getCompositeState().getCmHandleState() == DELETING
137         and: 'method to persist cm handle state is called once'
138             1 * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState())
139         and: 'the method to publish Lcm event is called once'
140             1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _, _)
141     }
142
143     def 'Update cmHandle state to "DELETED"' (){
144         given: 'cm Handle with state "DELETING" as Yang model '
145             compositeState = new CompositeState(cmHandleState: DELETING)
146             yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState)
147         when: 'updating cm handle state to "DELETED"'
148             objectUnderTest.updateCmHandleState(yangModelCmHandle, DELETED)
149         then: 'the cm handle state is as expected'
150             yangModelCmHandle.getCompositeState().getCmHandleState() == DELETED
151         and: 'the method to publish Lcm event is called once'
152             1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _, _)
153     }
154
155     def 'No state change and no event to be published'() {
156         given: 'Cm Handle batch with same state transition as before'
157             def cmHandleStateMap = setupBatch('NO_CHANGE')
158         when: 'updating a batch of changes'
159             objectUnderTest.updateCmHandleStateBatch(cmHandleStateMap)
160         then: 'batch is empty and nothing to update'
161             1 * mockInventoryPersistence.saveCmHandleBatch(_) >> {
162                 args -> {
163                     assert (args[0] as Collection<YangModelCmHandle>).size() == 0
164                 }
165             }
166         and: 'no event will be published'
167             0 * mockLcmEventsService.publishLcmEvent(*_)
168     }
169
170     def 'Batch of new cm handles provided'() {
171         given: 'A batch of new cm handles'
172             def yangModelCmHandlesToBeCreated = setupBatch('NEW')
173         when: 'instantiating a batch of new cm handles'
174             objectUnderTest.initiateStateAdvised(yangModelCmHandlesToBeCreated)
175         then: 'new cm handles are saved using inventory persistence'
176             1 * mockInventoryPersistence.saveCmHandleBatch(_) >> {
177                 args -> {
178                     assert (args[0] as Collection<YangModelCmHandle>).id.containsAll('cmhandle1', 'cmhandle2')
179                 }
180             }
181         and: 'event service is called to publish events'
182             2 * mockLcmEventsService.publishLcmEvent(_, _, _)
183     }
184
185     def 'Batch of existing cm handles is updated'() {
186         given: 'A batch of updated cm handles'
187             def cmHandleStateMap = setupBatch('UPDATE')
188         when: 'updating a batch of changes'
189             objectUnderTest.updateCmHandleStateBatch(cmHandleStateMap)
190         then : 'existing cm handles composite state is persisted'
191             1 * mockInventoryPersistence.saveCmHandleStateBatch(_) >> {
192                 args -> {
193                     assert (args[0] as Map<String, CompositeState>).keySet().containsAll(['cmhandle1','cmhandle2'])
194                 }
195             }
196         and: 'event service is called to publish events'
197             2 * mockLcmEventsService.publishLcmEvent(_, _, _)
198     }
199
200     def 'Batch of existing cm handles is deleted'() {
201         given: 'A batch of deleted cm handles'
202             def cmHandleStateMap = setupBatch('DELETED')
203         when: 'updating a batch of changes'
204             objectUnderTest.updateCmHandleStateBatch(cmHandleStateMap)
205         then : 'existing cm handles composite state is persisted'
206             1 * mockInventoryPersistence.saveCmHandleStateBatch(_) >> {
207                 args -> {
208                     assert (args[0] as Map<String, CompositeState>).isEmpty()
209                 }
210             }
211         and: 'event service is called to publish events'
212             2 * mockLcmEventsService.publishLcmEvent(_, _, _)
213     }
214
215     def setupBatch(type) {
216
217         def yangModelCmHandle1 = new YangModelCmHandle(id: 'cmhandle1', dmiProperties: [], publicProperties: [])
218         def yangModelCmHandle2 = new YangModelCmHandle(id: 'cmhandle2', dmiProperties: [], publicProperties: [])
219
220         if ('NEW' == type) {
221             return [yangModelCmHandle1, yangModelCmHandle2]
222         }
223
224         if ('DELETED' == type) {
225             yangModelCmHandle1.compositeState = new CompositeState(cmHandleState: READY)
226             yangModelCmHandle2.compositeState = new CompositeState(cmHandleState: READY)
227             return [(yangModelCmHandle1): DELETED, (yangModelCmHandle2): DELETED]
228         }
229
230         if ('UPDATE' == type) {
231             yangModelCmHandle1.compositeState = new CompositeState(cmHandleState: ADVISED)
232             yangModelCmHandle2.compositeState = new CompositeState(cmHandleState: READY)
233             return [(yangModelCmHandle1): READY, (yangModelCmHandle2): DELETING]
234         }
235
236         if ('NO_CHANGE' == type) {
237             yangModelCmHandle1.compositeState = new CompositeState(cmHandleState: ADVISED)
238             yangModelCmHandle2.compositeState = new CompositeState(cmHandleState: READY)
239             return [(yangModelCmHandle1): ADVISED, (yangModelCmHandle2): READY]
240         }
241     }
242 }