5753d7b675c0b38cda4b1c74e1ac4ddb4b0cde03
[cps.git] / cps-ncmp-service / src / test / groovy / org / onap / cps / ncmp / api / impl / NetworkCmProxyDataServiceImplSpec.groovy
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2022 Nordix Foundation
4  *  Modifications Copyright (C) 2021 Pantheon.tech
5  *  Modifications Copyright (C) 2021 Bell Canada
6  *  ================================================================================
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  *
19  *  SPDX-License-Identifier: Apache-2.0
20  *  ============LICENSE_END=========================================================
21  */
22
23 package org.onap.cps.ncmp.api.impl
24
25 import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL
26 import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING
27 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.CREATE
28 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.READ
29 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE
30
31 import com.fasterxml.jackson.core.JsonProcessingException
32 import com.fasterxml.jackson.databind.ObjectMapper
33 import org.onap.cps.api.CpsAdminService
34 import org.onap.cps.api.CpsDataService
35 import org.onap.cps.api.CpsModuleService
36 import org.onap.cps.ncmp.api.impl.exception.NcmpException
37 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
38 import org.onap.cps.spi.FetchDescendantsOption
39 import org.onap.cps.spi.model.DataNode
40 import org.springframework.http.HttpStatus
41 import org.springframework.http.ResponseEntity
42 import spock.lang.Specification
43
44 class NetworkCmProxyDataServiceImplSpec extends Specification {
45
46     def mockCpsDataService = Mock(CpsDataService)
47     def mockCpsModuleService = Mock(CpsModuleService)
48     def mockCpsAdminService = Mock(CpsAdminService)
49     def spyObjectMapper = Spy(ObjectMapper)
50     def mockDmiDataOperations = Mock(DmiDataOperations)
51
52     def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockDmiDataOperations, null,
53         mockCpsModuleService, mockCpsDataService, mockCpsAdminService, spyObjectMapper)
54
55     def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
56
57
58     def 'Write resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
59         given: 'a data node'
60             def dataNode = getDataNode(includeCmHandleProperties)
61         and: 'cpsDataService returns valid datanode'
62             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
63                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
64         when: 'get resource data is called'
65             objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
66                 'testResourceId', CREATE,
67                 '{some-json}', 'application/json')
68         then: 'dmi called with correct data'
69             1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
70                 CREATE, '{some-json}', 'application/json')
71                 >> { new ResponseEntity<>(HttpStatus.CREATED) }
72         where:
73             scenario  | includeCmHandleProperties || expectedJsonForCmhandleProperties
74             'with'    | true                      || '{"testName":"testValue"}'
75             'without' | false                     || '{}'
76     }
77
78     def 'Write resource data for pass-through running from dmi using POST "not found" response (from DMI).'() {
79         given: 'a data node'
80             def dataNode = getDataNode(true)
81         and: 'cpsDataService returns valid dataNode'
82             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
83                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
84         and: 'dmi returns a response with 404 status code'
85             mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle',
86                 'testResourceId', CREATE,
87                 '{some-json}', 'application/json')
88                 >> { new ResponseEntity<>(HttpStatus.NOT_FOUND) }
89         when: 'write resource data is called'
90             objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
91                 'testResourceId', CREATE,
92                 '{some-json}', 'application/json')
93         then: 'exception is thrown'
94             def exceptionThrown = thrown(NcmpException.class)
95         and: 'details contains (not found) error code: 404'
96             exceptionThrown.details.contains('404')
97     }
98
99
100     def 'Get resource data for pass-through operational from dmi.'() {
101         given: 'a data node'
102             def dataNode = getDataNode(true)
103         and: 'get data node is called'
104             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
105                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
106         and: 'get resource data from dmi is called'
107             mockDmiDataOperations.getResourceDataFromDmi(
108                 'testCmHandle',
109                 'testResourceId',
110                 '(a=1,b=2)',
111                 'testAcceptParam' ,
112                 PASSTHROUGH_OPERATIONAL) >> new ResponseEntity<>('result-json', HttpStatus.OK)
113         when: 'get resource data operational for cm-handle is called'
114             def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
115                 'testResourceId',
116                 'testAcceptParam',
117                 '(a=1,b=2)')
118         then: 'dmi returns a json response'
119             response == 'result-json'
120     }
121
122     def 'Get resource data for pass-through operational from dmi with Json Processing Exception.'() {
123         given: 'a data node'
124             def dataNode = getDataNode(true)
125         and: 'cps data service returns valid data node'
126             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
127                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
128         and: 'objectMapper not able to parse object'
129             def mockObjectMapper = Mock(ObjectMapper)
130             objectUnderTest.objectMapper = mockObjectMapper
131             mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
132         and: 'dmi returns NOK response'
133             mockDmiDataOperations.getResourceDataFromDmi(*_)
134                 >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
135         when: 'get resource data is called'
136             objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
137                 'testResourceId',
138                 'testAcceptParam',
139                 '(a=1,b=2)')
140         then: 'exception is thrown with the expected details'
141             def exceptionThrown = thrown(NcmpException.class)
142             exceptionThrown.details == 'DMI status code: 404, DMI response body: NOK-json'
143     }
144
145     def 'Get resource data for pass-through operational from dmi return NOK response.'() {
146         given: 'a data node'
147             def dataNode = getDataNode(true)
148         and: 'cps data service returns valid data node'
149             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
150                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
151         and: 'dmi returns NOK response'
152             mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
153                 'testResourceId',
154                 '(a=1,b=2)',
155                 'testAcceptParam',
156                 PASSTHROUGH_OPERATIONAL)
157                 >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
158         when: 'get resource data is called'
159             objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
160                 'testResourceId',
161                 'testAcceptParam',
162                 '(a=1,b=2)')
163         then: 'exception is thrown'
164             def exceptionThrown = thrown(NcmpException.class)
165         and: 'details contains the original response'
166             exceptionThrown.details.contains('NOK-json')
167     }
168
169     def 'Get resource data for pass-through running from dmi.'() {
170         given: 'a data node'
171             def dataNode = getDataNode(true)
172         and: 'cpsDataService returns valid data node'
173             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
174                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
175         and: 'dmi returns valid response and data'
176             mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
177                 'testResourceId',
178                 '(a=1,b=2)',
179                 'testAcceptParam',
180                 PASSTHROUGH_RUNNING) >> new ResponseEntity<>('{result-json}', HttpStatus.OK)
181         when: 'get resource data is called'
182             def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
183                 'testResourceId',
184                 'testAcceptParam',
185                 '(a=1,b=2)')
186         then: 'get resource data returns expected response'
187             response == '{result-json}'
188     }
189
190     def 'Get resource data for pass-through running from dmi return NOK response.'() {
191         given: 'a data node'
192             def dataNode = getDataNode(true)
193         and: 'cpsDataService returns valid dataNode'
194             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
195                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
196         and: 'dmi returns NOK response'
197             mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
198                 'testResourceId',
199                 '(a=1,b=2)',
200                 'testAcceptParam',
201                 PASSTHROUGH_RUNNING)
202                 >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
203         when: 'get resource data is called'
204             objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
205                 'testResourceId',
206                 'testAcceptParam',
207                 '(a=1,b=2)')
208         then: 'exception is thrown'
209             def exceptionThrown = thrown(NcmpException.class)
210         and: 'details contains the original response'
211             exceptionThrown.details.contains('NOK-json')
212     }
213
214     def 'Getting Yang Resources.'() {
215         when: 'yang resources is called'
216             objectUnderTest.getYangResourcesModuleReferences('some cm handle')
217         then: 'CPS module services is invoked for the correct dataspace and cm handle'
218             1 * mockCpsModuleService.getYangResourcesModuleReferences('NFP-Operational','some cm handle')
219     }
220
221     def 'Get cm handle identifiers for the given module names.'() {
222         when: 'execute a cm handle search for the given module names'
223             objectUnderTest.executeCmHandleHasAllModulesSearch(['some-module-name'])
224         then: 'get anchor identifiers is invoked  with the expected parameters'
225             1 * mockCpsAdminService.queryAnchorNames('NFP-Operational', ['some-module-name'])
226     }
227
228
229     def 'Update resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
230         given: 'a data node'
231             def dataNode = getDataNode(includeCmHandleProperties)
232         and: 'cpsDataService returns valid datanode'
233             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
234                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
235         when: 'get resource data is called'
236             objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
237                 'testResourceId', UPDATE,
238                 '{some-json}', 'application/json')
239         then: 'dmi called with correct data'
240             1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
241                 UPDATE, '{some-json}', 'application/json')
242                 >> { new ResponseEntity<>(HttpStatus.OK) }
243         where:
244             scenario  | includeCmHandleProperties || expectedJsonForCmhandleProperties
245             'with'    | true                      || '{"testName":"testValue"}'
246             'without' | false                     || '{}'
247     }
248
249     def 'Verify error message from handleResponse is correct for #scenario operation.'() {
250         given: 'writeResourceDataPassThroughRunningFromDmi fails to return OK HttpStatus'
251             mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi(*_)
252                 >> new ResponseEntity<>(HttpStatus.NOT_FOUND)
253         when: 'get resource data is called'
254             def response = objectUnderTest.writeResourceDataPassThroughRunningForCmHandle(
255                 'testCmHandle',
256                 'testResourceId',
257                 givenOperation,
258                 '{some-json}',
259                 'application/json')
260         then: 'an exception is thrown with the expected error message detailsd with correct operation'
261             def exceptionThrown = thrown(NcmpException.class)
262             exceptionThrown.getMessage().contains(expectedResponseMessage)
263         where:
264             scenario | givenOperation || expectedResponseMessage
265             'CREATE' | CREATE         || 'Not able to create resource data.'
266             'READ'   | READ           || 'Not able to read resource data.'
267             'UPDATE' | UPDATE         || 'Not able to update resource data.'
268     }
269
270     def getDataNode(boolean includeCmHandleProperties) {
271         def dataNode = new DataNode()
272         dataNode.leaves = ['dmi-service-name': 'testDmiService']
273         if (includeCmHandleProperties) {
274             def cmHandlePropertyDataNode = new DataNode()
275             cmHandlePropertyDataNode.leaves = ['name': 'testName', 'value': 'testValue']
276             dataNode.childDataNodes = [cmHandlePropertyDataNode]
277         }
278         return dataNode
279     }
280 }