Save new cm notification subscription
[cps.git] / integration-test / src / test / groovy / org / onap / cps / integration / functional / NcmpCmHandleCreateSpec.groovy
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2024 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.functional
22
23 import java.time.OffsetDateTime
24 import org.onap.cps.integration.base.CpsIntegrationSpecBase
25 import org.onap.cps.ncmp.api.NetworkCmProxyDataService
26 import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
27 import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
28 import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
29 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
30 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
31 import spock.util.concurrent.PollingConditions
32
33 class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
34
35     NetworkCmProxyDataService objectUnderTest
36
37     static final MODULE_REFERENCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
38     static final MODULE_RESOURCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
39     static final MODULE_REFERENCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json')
40     static final MODULE_RESOURCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json')
41
42     def setup() {
43         objectUnderTest = networkCmProxyDataService
44     }
45
46     def 'CM Handle registration is successful.'() {
47         given: 'DMI will return modules when requested'
48             mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
49
50         when: 'a CM-handle is registered for creation'
51             def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
52             def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate])
53             def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
54
55         then: 'registration gives successful response'
56             assert dmiPluginRegistrationResponse.createdCmHandles == [CmHandleRegistrationResponse.createSuccessResponse('ch-1')]
57
58         and: 'CM-handle is initially in ADVISED state'
59             assert CmHandleState.ADVISED == objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState
60
61         when: 'module sync runs'
62             moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
63
64         then: 'CM-handle goes to READY state'
65             new PollingConditions().within(3, () -> {
66                 assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState
67             })
68
69         and: 'the CM-handle has expected modules'
70             assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
71
72         and: 'DMI received expected requests'
73             mockDmiServer.verify()
74
75         cleanup: 'deregister CM handle'
76             deregisterCmHandle(DMI_URL, 'ch-1')
77     }
78
79     def 'CM Handle goes to LOCKED state when DMI gives error during module sync.'() {
80         given: 'DMI is not available to handle requests'
81             mockDmiIsNotAvailableForModuleSync(DMI_URL, 'ch-1')
82
83         when: 'a CM-handle is registered for creation'
84             def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
85             def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate])
86             networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
87
88         and: 'module sync runs'
89             moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
90
91         then: 'CM-handle goes to LOCKED state with reason MODULE_SYNC_FAILED'
92             new PollingConditions().within(3, () -> {
93                 def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState('ch-1')
94                 assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
95                 assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_SYNC_FAILED
96             })
97
98         and: 'CM-handle has no modules'
99             assert objectUnderTest.getYangResourcesModuleReferences('ch-1').empty
100
101         cleanup: 'deregister CM handle'
102             deregisterCmHandle(DMI_URL, 'ch-1')
103     }
104
105     def 'Create a CM-handle with existing moduleSetTag.'() {
106         given: 'existing CM-handles cm-1 with moduleSetTag "A", and cm-2 with moduleSetTag "B"'
107             registerCmHandle(DMI_URL, 'ch-1', 'A', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
108             registerCmHandle(DMI_URL, 'ch-2', 'B', MODULE_REFERENCES_RESPONSE_B, MODULE_RESOURCES_RESPONSE_B)
109             assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
110             assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences('ch-2').moduleName.sort()
111
112         when: 'a CM-handle is registered for creation with moduleSetTag "B"'
113             def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-3', moduleSetTag: 'B')
114             networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate]))
115
116         then: 'the CM-handle goes to READY state after module sync'
117             moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
118             new PollingConditions().within(3, () -> {
119                 assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-3').cmHandleState
120             })
121
122         and: 'the CM-handle has expected moduleSetTag'
123             assert objectUnderTest.getNcmpServiceCmHandle('ch-3').moduleSetTag == 'B'
124
125         and: 'the CM-handle has expected modules from module set "B": M1 and M3'
126             assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences('ch-3').moduleName.sort()
127
128         cleanup: 'deregister CM handles'
129             deregisterCmHandles(DMI_URL, ['ch-1', 'ch-2', 'ch-3'])
130     }
131
132     def 'CM Handle retry after failed module sync.'() {
133         given: 'DMI is not initially available to handle requests'
134             mockDmiIsNotAvailableForModuleSync(DMI_URL, 'ch-1')
135             mockDmiIsNotAvailableForModuleSync(DMI_URL, 'ch-2')
136         and: 'DMI will be available for retry'
137             mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
138             mockDmiResponsesForModuleSync(DMI_URL, 'ch-2', MODULE_REFERENCES_RESPONSE_B, MODULE_RESOURCES_RESPONSE_B)
139
140         when: 'CM-handles are registered for creation'
141             def cmHandlesToCreate = [new NcmpServiceCmHandle(cmHandleId: 'ch-1'), new NcmpServiceCmHandle(cmHandleId: 'ch-2')]
142             def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: cmHandlesToCreate)
143             networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
144         and: 'module sync runs'
145             moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
146         then: 'CM-handles go to LOCKED state'
147             new PollingConditions().within(3, () -> {
148                 assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.LOCKED
149                 assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.LOCKED
150             })
151
152         when: 'we wait for LOCKED CM handle retry time (actually just subtract 3 minutes from handles lastUpdateTime)'
153             overrideCmHandleLastUpdateTime('ch-1', OffsetDateTime.now().minusMinutes(3))
154             overrideCmHandleLastUpdateTime('ch-2', OffsetDateTime.now().minusMinutes(3))
155         and: 'failed CM handles are reset'
156             moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
157         then: 'CM-handles are ADVISED state'
158             assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.ADVISED
159             assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.ADVISED
160
161         when: 'module sync runs'
162             moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
163         then: 'CM-handles go to READY state'
164             new PollingConditions().within(3, () -> {
165                 assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.READY
166                 assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.READY
167             })
168         and: 'CM-handles have expected modules'
169             assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
170             assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences('ch-2').moduleName.sort()
171         and: 'CM-handles have expected module set tags (blank)'
172             assert objectUnderTest.getNcmpServiceCmHandle('ch-1').moduleSetTag == ''
173             assert objectUnderTest.getNcmpServiceCmHandle('ch-2').moduleSetTag == ''
174         and: 'DMI received expected requests'
175             mockDmiServer.verify()
176
177         cleanup: 'deregister CM handle'
178             deregisterCmHandles(DMI_URL, ['ch-1', 'ch-2'])
179     }
180 }