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