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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.cps.ncmp.api.impl
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
39 class NetworkCmProxyDataServiceImplSpec extends Specification {
42 def persistenceCmHandle = new CmHandle()
44 def cmHandlesArray = ['cmHandle001']
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())
51 def cmHandle = 'some handle'
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()
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'
74 'root level xpath' | '/'
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)
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)
94 def 'Update data node leaves.'() {
95 given: 'a cm Handle and a cps path'
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)
103 def 'Replace data node tree.'() {
104 given: 'a cm Handle and a cps path'
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)
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']")
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
139 def 'Get resource data for pass-through operational from dmi.'() {
141 def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
143 def dataNode = new DataNode()
144 dataNode.leaves = ['dmi-service-name':'testDmiService']
145 def childDataNode = new DataNode()
146 childDataNode.leaves = ['name':'testName','value':'testValue']
147 dataNode.childDataNodes = [childDataNode]
148 when: 'get resource data is called'
149 def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
154 then: 'cps data service is being called once to get data node'
155 1 * mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
156 xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
157 and: 'dmi operation is being called to get resource data'
158 1 * mockDmiOperations.getResouceDataOperationalFromDmi('testDmiService',
164 '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('result-json', HttpStatus.OK)
165 and: 'dmi returns ok response'
166 response == 'result-json'
168 def 'Get resource data for pass-through operational from dmi threw parsing exception.'() {
170 def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
172 def dataNode = new DataNode()
173 dataNode.leaves = ['dmi-service-name':'testDmiService']
174 def childDataNode = new DataNode()
175 childDataNode.leaves = ['name':'testName','value':'testValue']
176 dataNode.childDataNodes = [childDataNode]
177 mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
178 xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
179 and: 'objectMapper not able to parse object'
180 def mockObjectMapper = Mock(ObjectMapper)
181 objectUnderTest.objectMapper = mockObjectMapper
182 mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException("testException") }
183 when: 'get resource data is called'
184 def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
189 then: 'exception is thrown'
190 thrown(NcmpException.class)
192 def 'Get resource data for pass-through operational from dmi return NOK response.'() {
194 def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
196 def dataNode = new DataNode()
197 dataNode.leaves = ['dmi-service-name':'testDmiService']
198 def childDataNode = new DataNode()
199 childDataNode.leaves = ['name':'testName','value':'testValue']
200 dataNode.childDataNodes = [childDataNode]
201 mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
202 xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
203 and: 'dmi returns NOK response'
204 mockDmiOperations.getResouceDataOperationalFromDmi('testDmiService',
210 '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
211 >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
212 when: 'get resource data is called'
213 def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
218 then: 'exception is thrown'
219 thrown(NcmpException.class)
221 def 'Get resource data for pass-through running from dmi.'() {
223 def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
224 and: 'data node representing cmhandle and its properties'
225 def dataNode = new DataNode()
226 dataNode.leaves = ['dmi-service-name':'testDmiService']
227 def childDataNode = new DataNode()
228 childDataNode.leaves = ['name':'testName','value':'testValue']
229 dataNode.childDataNodes = [childDataNode]
230 and: 'cpsDataService returns valid dataNode'
231 mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
232 xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
233 and: 'dmi returns valid response and data'
234 mockDmiOperations.getResouceDataPassThroughRunningFromDmi('testDmiService',
240 '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('{result-json}', HttpStatus.OK)
241 when: 'get resource data is called'
242 def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
247 then: 'get resource data returns expected response'
248 response == '{result-json}'
250 def 'Get resource data for pass-through running from dmi threw parsing exception.'() {
252 def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
253 and: 'data node representing cmhandle and its properties'
254 def dataNode = new DataNode()
255 dataNode.leaves = ['dmi-service-name':'testDmiService']
256 def childDataNode = new DataNode()
257 childDataNode.leaves = ['name':'testName','value':'testValue']
258 dataNode.childDataNodes = [childDataNode]
259 and: 'cpsDataService returns valid dataNode'
260 mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
261 xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
262 and: 'objectMapper not able to parse object'
263 def mockObjectMapper = Mock(ObjectMapper)
264 objectUnderTest.objectMapper = mockObjectMapper
265 mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException("testException") }
266 when: 'get resource data is called'
267 def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
272 then: 'exception is thrown'
273 thrown(NcmpException.class)
275 def 'Get resource data for pass-through running from dmi return NOK response.'() {
277 def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
278 and: 'data node representing cmhandle and its properties'
279 def dataNode = new DataNode()
280 dataNode.leaves = ['dmi-service-name':'testDmiService']
281 def childDataNode = new DataNode()
282 childDataNode.leaves = ['name':'testName','value':'testValue']
283 dataNode.childDataNodes = [childDataNode]
284 and: 'cpsDataService returns valid dataNode'
285 mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
286 xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
287 and: 'dmi returns NOK response'
288 mockDmiOperations.getResouceDataPassThroughRunningFromDmi('testDmiService',
294 '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
295 >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
296 when: 'get resource data is called'
297 def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
302 then: 'exception is thrown'
303 thrown(NcmpException.class)