Merge "Update CmHandle in DMI-Registry for a DMI-Plugin Instance in NCMP as part...
[cps.git] / cps-ncmp-service / src / test / groovy / org / onap / cps / ncmp / api / impl / NetworkCmProxyDataServiceImplSpec.groovy
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021 Nordix Foundation
4  *  Modifications Copyright (C) 2021 Pantheon.tech
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.api.impl
23
24 import com.fasterxml.jackson.core.JsonProcessingException
25 import com.fasterxml.jackson.databind.ObjectMapper
26 import org.onap.cps.api.CpsDataService
27 import org.onap.cps.api.CpsQueryService
28 import org.onap.cps.ncmp.api.impl.exception.NcmpException
29 import org.onap.cps.ncmp.api.impl.operation.DmiOperations
30 import org.onap.cps.ncmp.api.models.CmHandle
31 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
32 import org.onap.cps.spi.FetchDescendantsOption
33 import org.onap.cps.spi.model.DataNode
34 import org.springframework.http.HttpStatus
35 import org.springframework.http.ResponseEntity
36 import spock.lang.Shared
37 import spock.lang.Specification
38
39 class NetworkCmProxyDataServiceImplSpec extends Specification {
40
41     @Shared
42     def persistenceCmHandle = new CmHandle()
43
44     def mockCpsDataService = Mock(CpsDataService)
45     def mockCpsQueryService = Mock(CpsQueryService)
46     def mockDmiOperations = Mock(DmiOperations)
47     def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsDataService, mockCpsQueryService, new ObjectMapper())
48
49     def cmHandle = 'some handle'
50
51     def expectedDataspaceName = 'NFP-Operational'
52     def 'Query data nodes by cps path with #fetchDescendantsOption.'() {
53         given: 'a cm Handle and a cps path'
54             def cpsPath = '/cps-path'
55         when: 'queryDataNodes is invoked'
56             objectUnderTest.queryDataNodes(cmHandle, cpsPath, fetchDescendantsOption)
57         then: 'the persistence service is called once with the correct parameters'
58             1 * mockCpsQueryService.queryDataNodes(expectedDataspaceName, cmHandle, cpsPath, fetchDescendantsOption)
59         where: 'all fetch descendants options are supported'
60             fetchDescendantsOption << FetchDescendantsOption.values()
61     }
62     def 'Create full data node: #scenario.'() {
63         given: 'a cm handle and root xpath'
64             def jsonData = 'some json'
65         when: 'createDataNode is invoked'
66             objectUnderTest.createDataNode(cmHandle, xpath, jsonData)
67         then: 'the CPS service method is invoked once with the expected parameters'
68             1 * mockCpsDataService.saveData(expectedDataspaceName, cmHandle, jsonData)
69         where: 'following parameters were used'
70             scenario           | xpath
71             'no xpath'         | ''
72             'root level xpath' | '/'
73     }
74     def 'Create child data node.'() {
75         given: 'a cm handle and parent node xpath'
76             def jsonData = 'some json'
77             def xpath = '/test-node'
78         when: 'createDataNode is invoked'
79             objectUnderTest.createDataNode(cmHandle, xpath, jsonData)
80         then: 'the CPS service method is invoked once with the expected parameters'
81             1 * mockCpsDataService.saveData(expectedDataspaceName, cmHandle, xpath, jsonData)
82     }
83     def 'Add list-node elements.'() {
84         given: 'a cm handle and parent node xpath'
85             def jsonData = 'some json'
86             def xpath = '/test-node'
87         when: 'addListNodeElements is invoked'
88             objectUnderTest.addListNodeElements(cmHandle, xpath, jsonData)
89         then: 'the CPS service method is invoked once with the expected parameters'
90             1 * mockCpsDataService.saveListNodeData(expectedDataspaceName, cmHandle, xpath, jsonData)
91     }
92     def 'Update data node leaves.'() {
93         given: 'a cm Handle and a cps path'
94             def xpath = '/xpath'
95             def jsonData = 'some json'
96         when: 'updateNodeLeaves is invoked'
97             objectUnderTest.updateNodeLeaves(cmHandle, xpath, jsonData)
98         then: 'the persistence service is called once with the correct parameters'
99             1 * mockCpsDataService.updateNodeLeaves(expectedDataspaceName, cmHandle, xpath, jsonData)
100     }
101     def 'Replace data node tree.'() {
102         given: 'a cm Handle and a cps path'
103             def xpath = '/xpath'
104             def jsonData = 'some json'
105         when: 'replaceNodeTree is invoked'
106             objectUnderTest.replaceNodeTree(cmHandle, xpath, jsonData)
107         then: 'the persistence service is called once with the correct parameters'
108             1 * mockCpsDataService.replaceNodeTree(expectedDataspaceName, cmHandle, xpath, jsonData)
109     }
110
111     def 'Register or re-register a DMI Plugin with #scenario cm handles.'() {
112         given: 'a registration '
113             def dmiRegistryAnchor = 'ncmp-dmi-registry'
114             def dmiPluginRegistration = new DmiPluginRegistration()
115             dmiPluginRegistration.dmiPlugin = 'my-server'
116             persistenceCmHandle.cmHandleID = '123'
117             persistenceCmHandle.cmHandleProperties = [name1: 'value1', name2: 'value2']
118             dmiPluginRegistration.createdCmHandles = createdCmHandles
119             dmiPluginRegistration.updatedCmHandles = updatedCmHandles
120             def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","additional-properties":[{"name":"name1","value":"value1"},{"name":"name2","value":"value2"}]}]}'
121         when: 'registration is updated'
122             objectUnderTest.updateDmiPluginRegistration(dmiPluginRegistration)
123         then: 'the CPS save list node data is invoked with the expected parameters'
124             expectedCallsToSaveNode * mockCpsDataService.saveListNodeData('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', expectedJsonData)
125         and: 'update Node and Child Data Nodes is invoked with correct parameter'
126             expectedCallsToUpdateNode * mockCpsDataService.updateNodeLeavesAndExistingDescendantLeaves('NCMP-Admin', dmiRegistryAnchor, '/dmi-registry', expectedJsonData)
127         where:
128             scenario                | createdCmHandles       | updatedCmHandles       || expectedCallsToSaveNode   | expectedCallsToUpdateNode
129             'create'                | [persistenceCmHandle ] | []                     || 1                         | 0
130             'update'                | []                     | [persistenceCmHandle ] || 0                         | 1
131             'create and update'     | [persistenceCmHandle ] | [persistenceCmHandle ] || 1                         | 1
132
133     }
134     def 'Get resource data for pass-through operational from dmi.'() {
135         given: 'xpath'
136             def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
137         and: 'data node'
138             def dataNode = new DataNode()
139             dataNode.leaves = ['dmi-service-name':'testDmiService']
140             def childDataNode = new DataNode()
141             childDataNode.leaves = ['name':'testName','value':'testValue']
142             dataNode.childDataNodes = [childDataNode]
143         when: 'get resource data is called'
144             def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
145             'testResourceId',
146             'testAcceptParam',
147             'testFieldQuery',
148             5)
149         then: 'cps data service is being called once to get data node'
150             1 * mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
151                     xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
152         and: 'dmi operation is being called to get resource data'
153             1 * mockDmiOperations.getResouceDataOperationalFromDmi('testDmiService',
154                     'testCmHandle',
155                     'testResourceId',
156                     'testFieldQuery',
157                     5,
158                     'testAcceptParam',
159             '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('result-json', HttpStatus.OK)
160         and: 'dmi returns ok response'
161             response == 'result-json'
162     }
163     def 'Get resource data for pass-through operational from dmi threw parsing exception.'() {
164         given: 'xpath'
165             def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
166         and: 'data node'
167             def dataNode = new DataNode()
168             dataNode.leaves = ['dmi-service-name':'testDmiService']
169             def childDataNode = new DataNode()
170             childDataNode.leaves = ['name':'testName','value':'testValue']
171             dataNode.childDataNodes = [childDataNode]
172             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
173                     xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
174         and: 'objectMapper not able to parse object'
175             def mockObjectMapper = Mock(ObjectMapper)
176             objectUnderTest.objectMapper = mockObjectMapper
177             mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException("testException") }
178         when: 'get resource data is called'
179             def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
180                     'testResourceId',
181                     'testAcceptParam',
182                     'testFieldQuery',
183                     5)
184         then: 'exception is thrown'
185             thrown(NcmpException.class)
186     }
187     def 'Get resource data for pass-through operational from dmi return NOK response.'() {
188         given: 'xpath'
189             def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
190         and: 'data node'
191             def dataNode = new DataNode()
192             dataNode.leaves = ['dmi-service-name':'testDmiService']
193             def childDataNode = new DataNode()
194             childDataNode.leaves = ['name':'testName','value':'testValue']
195             dataNode.childDataNodes = [childDataNode]
196             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
197                     xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
198         and: 'dmi returns NOK response'
199             mockDmiOperations.getResouceDataOperationalFromDmi('testDmiService',
200                     'testCmHandle',
201                     'testResourceId',
202                     'testFieldQuery',
203                     5,
204                     'testAcceptParam',
205                     '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
206                     >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
207         when: 'get resource data is called'
208             def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
209                     'testResourceId',
210                     'testAcceptParam',
211                     'testFieldQuery',
212                     5)
213         then: 'exception is thrown'
214             thrown(NcmpException.class)
215     }
216     def 'Get resource data for pass-through running from dmi.'() {
217         given: 'xpath'
218             def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
219         and: 'data node representing cmhandle and its properties'
220             def dataNode = new DataNode()
221             dataNode.leaves = ['dmi-service-name':'testDmiService']
222             def childDataNode = new DataNode()
223             childDataNode.leaves = ['name':'testName','value':'testValue']
224             dataNode.childDataNodes = [childDataNode]
225         and: 'cpsDataService returns valid dataNode'
226             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
227                     xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
228         and: 'dmi returns valid response and data'
229             mockDmiOperations.getResouceDataPassThroughRunningFromDmi('testDmiService',
230                     'testCmHandle',
231                     'testResourceId',
232                     'testFieldQuery',
233                     5,
234                     'testAcceptParam',
235                     '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('{result-json}', HttpStatus.OK)
236         when: 'get resource data is called'
237             def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
238                     'testResourceId',
239                     'testAcceptParam',
240                     'testFieldQuery',
241                     5)
242         then: 'get resource data returns expected response'
243             response == '{result-json}'
244     }
245     def 'Get resource data for pass-through running from dmi threw parsing exception.'() {
246         given: 'xpath'
247             def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
248         and: 'data node representing cmhandle and its properties'
249             def dataNode = new DataNode()
250             dataNode.leaves = ['dmi-service-name':'testDmiService']
251             def childDataNode = new DataNode()
252             childDataNode.leaves = ['name':'testName','value':'testValue']
253             dataNode.childDataNodes = [childDataNode]
254         and: 'cpsDataService returns valid dataNode'
255             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
256                     xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
257         and: 'objectMapper not able to parse object'
258             def mockObjectMapper = Mock(ObjectMapper)
259             objectUnderTest.objectMapper = mockObjectMapper
260             mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException("testException") }
261         when: 'get resource data is called'
262             def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
263                     'testResourceId',
264                     'testAcceptParam',
265                     'testFieldQuery',
266                     5)
267         then: 'exception is thrown'
268             thrown(NcmpException.class)
269     }
270     def 'Get resource data for pass-through running from dmi return NOK response.'() {
271         given: 'xpath'
272             def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
273         and: 'data node representing cmhandle and its properties'
274             def dataNode = new DataNode()
275             dataNode.leaves = ['dmi-service-name':'testDmiService']
276             def childDataNode = new DataNode()
277             childDataNode.leaves = ['name':'testName','value':'testValue']
278             dataNode.childDataNodes = [childDataNode]
279         and: 'cpsDataService returns valid dataNode'
280             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
281                     xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
282         and: 'dmi returns NOK response'
283             mockDmiOperations.getResouceDataPassThroughRunningFromDmi('testDmiService',
284                     'testCmHandle',
285                     'testResourceId',
286                     'testFieldQuery',
287                     5,
288                     'testAcceptParam',
289                     '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
290                     >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
291         when: 'get resource data is called'
292             def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
293                     'testResourceId',
294                     'testAcceptParam',
295                     'testFieldQuery',
296                     5)
297         then: 'exception is thrown'
298             thrown(NcmpException.class)
299     }
300 }