Replace gson mapper with jackson mapper
[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 org.onap.cps.ncmp.api.impl.operations.DmiModelOperations
32 import org.onap.cps.utils.JsonObjectMapper
33 import com.fasterxml.jackson.core.JsonProcessingException
34 import com.fasterxml.jackson.databind.ObjectMapper
35 import org.onap.cps.api.CpsAdminService
36 import org.onap.cps.api.CpsDataService
37 import org.onap.cps.api.CpsModuleService
38 import org.onap.cps.ncmp.api.impl.exception.NcmpException
39 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
40 import org.onap.cps.spi.FetchDescendantsOption
41 import org.onap.cps.spi.model.DataNode
42 import org.springframework.http.HttpStatus
43 import org.springframework.http.ResponseEntity
44 import spock.lang.Specification
45
46 class NetworkCmProxyDataServiceImplSpec extends Specification {
47
48     def mockCpsDataService = Mock(CpsDataService)
49     def mockCpsModuleService = Mock(CpsModuleService)
50     def mockCpsAdminService = Mock(CpsAdminService)
51     def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
52     def mockDmiModelOperations = Mock(DmiModelOperations)
53     def mockDmiDataOperations = Mock(DmiDataOperations)
54
55     def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations, mockDmiModelOperations,
56         mockCpsModuleService, mockCpsAdminService)
57
58     def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
59
60
61     def 'Write resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
62         given: 'a data node'
63             def dataNode = getDataNode(includeCmHandleProperties)
64         and: 'cpsDataService returns valid datanode'
65             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
66                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
67         when: 'get resource data is called'
68             objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
69                 'testResourceId', CREATE,
70                 '{some-json}', 'application/json')
71         then: 'dmi called with correct data'
72             1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
73                 CREATE, '{some-json}', 'application/json')
74                 >> { new ResponseEntity<>(HttpStatus.CREATED) }
75         where:
76             scenario  | includeCmHandleProperties || expectedJsonForCmhandleProperties
77             'with'    | true                      || '{"testName":"testValue"}'
78             'without' | false                     || '{}'
79     }
80
81     def 'Write resource data for pass-through running from dmi using POST "not found" response (from DMI).'() {
82         given: 'a data node'
83             def dataNode = getDataNode(true)
84         and: 'cpsDataService returns valid dataNode'
85             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
86                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
87         and: 'dmi returns a response with 404 status code'
88             mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle',
89                 'testResourceId', CREATE,
90                 '{some-json}', 'application/json')
91                 >> { new ResponseEntity<>(HttpStatus.NOT_FOUND) }
92         when: 'write resource data is called'
93             objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
94                 'testResourceId', CREATE,
95                 '{some-json}', 'application/json')
96         then: 'exception is thrown'
97             def exceptionThrown = thrown(NcmpException.class)
98         and: 'details contains (not found) error code: 404'
99             exceptionThrown.details.contains('404')
100     }
101
102
103     def 'Get resource data for pass-through operational from dmi.'() {
104         given: 'a data node'
105             def dataNode = getDataNode(true)
106         and: 'get data node is called'
107             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
108                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
109         and: 'get resource data from dmi is called'
110             mockDmiDataOperations.getResourceDataFromDmi(
111                 'testCmHandle',
112                 'testResourceId',
113                 '(a=1,b=2)',
114                 'testAcceptParam' ,
115                 PASSTHROUGH_OPERATIONAL) >> new ResponseEntity<>('result-json', HttpStatus.OK)
116         when: 'get resource data operational for cm-handle is called'
117             def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
118                 'testResourceId',
119                 'testAcceptParam',
120                 '(a=1,b=2)')
121         then: 'dmi returns a json response'
122             response == 'result-json'
123     }
124
125     def 'Get resource data for pass-through operational from dmi with Json Processing Exception.'() {
126         given: 'a data node'
127             def dataNode = getDataNode(true)
128         and: 'cps data service returns valid data node'
129             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
130                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
131         and: 'objectMapper not able to parse object'
132             spiedJsonObjectMapper.asJsonString(_) >> { throw new JsonProcessingException('testException') }
133         and: 'dmi returns NOK response'
134             mockDmiDataOperations.getResourceDataFromDmi(*_)
135                 >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
136         when: 'get resource data is called'
137             objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
138                 'testResourceId',
139                 'testAcceptParam',
140                 '(a=1,b=2)')
141         then: 'exception is thrown with the expected details'
142             def exceptionThrown = thrown(NcmpException.class)
143             exceptionThrown.details == 'DMI status code: 404, DMI response body: NOK-json'
144     }
145
146     def 'Get resource data for pass-through operational from dmi return NOK response.'() {
147         given: 'a data node'
148             def dataNode = getDataNode(true)
149         and: 'cps data service returns valid data node'
150             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
151                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
152         and: 'dmi returns NOK response'
153             mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
154                 'testResourceId',
155                 '(a=1,b=2)',
156                 'testAcceptParam',
157                 PASSTHROUGH_OPERATIONAL)
158                 >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
159         when: 'get resource data is called'
160             objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
161                 'testResourceId',
162                 'testAcceptParam',
163                 '(a=1,b=2)')
164         then: 'exception is thrown'
165             def exceptionThrown = thrown(NcmpException.class)
166         and: 'details contains the original response'
167             exceptionThrown.details.contains('NOK-json')
168     }
169
170     def 'Get resource data for pass-through running from dmi.'() {
171         given: 'a data node'
172             def dataNode = getDataNode(true)
173         and: 'cpsDataService returns valid data node'
174             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
175                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
176         and: 'dmi returns valid response and data'
177             mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
178                 'testResourceId',
179                 '(a=1,b=2)',
180                 'testAcceptParam',
181                 PASSTHROUGH_RUNNING) >> new ResponseEntity<>('{result-json}', HttpStatus.OK)
182         when: 'get resource data is called'
183             def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
184                 'testResourceId',
185                 'testAcceptParam',
186                 '(a=1,b=2)')
187         then: 'get resource data returns expected response'
188             response == '{result-json}'
189     }
190
191     def 'Get resource data for pass-through running from dmi return NOK response.'() {
192         given: 'a data node'
193             def dataNode = getDataNode(true)
194         and: 'cpsDataService returns valid dataNode'
195             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
196                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
197         and: 'dmi returns NOK response'
198             mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
199                 'testResourceId',
200                 '(a=1,b=2)',
201                 'testAcceptParam',
202                 PASSTHROUGH_RUNNING)
203                 >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
204         when: 'get resource data is called'
205             objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
206                 'testResourceId',
207                 'testAcceptParam',
208                 '(a=1,b=2)')
209         then: 'exception is thrown'
210             def exceptionThrown = thrown(NcmpException.class)
211         and: 'details contains the original response'
212             exceptionThrown.details.contains('NOK-json')
213     }
214
215     def 'Getting Yang Resources.'() {
216         when: 'yang resources is called'
217             objectUnderTest.getYangResourcesModuleReferences('some cm handle')
218         then: 'CPS module services is invoked for the correct dataspace and cm handle'
219             1 * mockCpsModuleService.getYangResourcesModuleReferences('NFP-Operational','some cm handle')
220     }
221
222     def 'Get cm handle identifiers for the given module names.'() {
223         when: 'execute a cm handle search for the given module names'
224             objectUnderTest.executeCmHandleHasAllModulesSearch(['some-module-name'])
225         then: 'get anchor identifiers is invoked  with the expected parameters'
226             1 * mockCpsAdminService.queryAnchorNames('NFP-Operational', ['some-module-name'])
227     }
228
229
230     def 'Update resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
231         given: 'a data node'
232             def dataNode = getDataNode(includeCmHandleProperties)
233         and: 'cpsDataService returns valid datanode'
234             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
235                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
236         when: 'get resource data is called'
237             objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
238                 'testResourceId', UPDATE,
239                 '{some-json}', 'application/json')
240         then: 'dmi called with correct data'
241             1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
242                 UPDATE, '{some-json}', 'application/json')
243                 >> { new ResponseEntity<>(HttpStatus.OK) }
244         where:
245             scenario  | includeCmHandleProperties || expectedJsonForCmhandleProperties
246             'with'    | true                      || '{"testName":"testValue"}'
247             'without' | false                     || '{}'
248     }
249
250     def 'Verify error message from handleResponse is correct for #scenario operation.'() {
251         given: 'writeResourceDataPassThroughRunningFromDmi fails to return OK HttpStatus'
252             mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi(*_)
253                 >> new ResponseEntity<>(HttpStatus.NOT_FOUND)
254         when: 'get resource data is called'
255             def response = objectUnderTest.writeResourceDataPassThroughRunningForCmHandle(
256                 'testCmHandle',
257                 'testResourceId',
258                 givenOperation,
259                 '{some-json}',
260                 'application/json')
261         then: 'an exception is thrown with the expected error message detailsd with correct operation'
262             def exceptionThrown = thrown(NcmpException.class)
263             exceptionThrown.getMessage().contains(expectedResponseMessage)
264         where:
265             scenario | givenOperation || expectedResponseMessage
266             'CREATE' | CREATE         || 'Not able to create resource data.'
267             'READ'   | READ           || 'Not able to read resource data.'
268             'UPDATE' | UPDATE         || 'Not able to update resource data.'
269     }
270
271     def getDataNode(boolean includeCmHandleProperties) {
272         def dataNode = new DataNode()
273         dataNode.leaves = ['dmi-service-name': 'testDmiService']
274         if (includeCmHandleProperties) {
275             def cmHandlePropertyDataNode = new DataNode()
276             cmHandlePropertyDataNode.leaves = ['name': 'testName', 'value': 'testValue']
277             dataNode.childDataNodes = [cmHandlePropertyDataNode]
278         }
279         return dataNode
280     }
281 }