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 mockCpsDataService = Mock(CpsDataService)
45 def mockCpsQueryService = Mock(CpsQueryService)
46 def mockDmiOperations = Mock(DmiOperations)
47 def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsDataService, mockCpsQueryService, new ObjectMapper())
49 def cmHandle = 'some handle'
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()
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'
72 'root level xpath' | '/'
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)
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)
92 def 'Update data node leaves.'() {
93 given: 'a cm Handle and a cps path'
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)
101 def 'Replace data node tree.'() {
102 given: 'a cm Handle and a cps path'
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)
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)
128 scenario | createdCmHandles | updatedCmHandles || expectedCallsToSaveNode | expectedCallsToUpdateNode
129 'create' | [persistenceCmHandle ] | [] || 1 | 0
130 'update' | [] | [persistenceCmHandle ] || 0 | 1
131 'create and update' | [persistenceCmHandle ] | [persistenceCmHandle ] || 1 | 1
134 def 'Get resource data for pass-through operational from dmi.'() {
136 def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
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',
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',
159 '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('result-json', HttpStatus.OK)
160 and: 'dmi returns ok response'
161 response == 'result-json'
163 def 'Get resource data for pass-through operational from dmi threw parsing exception.'() {
165 def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
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',
184 then: 'exception is thrown'
185 thrown(NcmpException.class)
187 def 'Get resource data for pass-through operational from dmi return NOK response.'() {
189 def xpath = "/dmi-registry/cm-handles[@id='testCmHandle']"
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',
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',
213 then: 'exception is thrown'
214 thrown(NcmpException.class)
216 def 'Get resource data for pass-through running from dmi.'() {
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',
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',
242 then: 'get resource data returns expected response'
243 response == '{result-json}'
245 def 'Get resource data for pass-through running from dmi threw parsing exception.'() {
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',
267 then: 'exception is thrown'
268 thrown(NcmpException.class)
270 def 'Get resource data for pass-through running from dmi return NOK response.'() {
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',
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',
297 then: 'exception is thrown'
298 thrown(NcmpException.class)