Add test for missing code covereage
[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  *  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 com.fasterxml.jackson.core.JsonProcessingException
26 import com.fasterxml.jackson.databind.ObjectMapper
27 import org.onap.cps.api.CpsAdminService
28 import org.onap.cps.api.CpsDataService
29 import org.onap.cps.api.CpsModuleService
30 import org.onap.cps.api.CpsQueryService
31 import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
32 import org.onap.cps.ncmp.api.impl.exception.NcmpException
33 import org.onap.cps.ncmp.api.impl.operation.DmiOperations
34 import org.onap.cps.ncmp.api.models.CmHandle
35 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
36 import org.onap.cps.ncmp.api.models.PersistenceCmHandle
37 import org.onap.cps.ncmp.utils.TestUtils
38 import org.onap.cps.spi.FetchDescendantsOption
39 import org.onap.cps.spi.exceptions.DataNodeNotFoundException
40 import org.onap.cps.spi.exceptions.DataValidationException
41 import org.onap.cps.spi.model.DataNode
42 import org.onap.cps.spi.model.ModuleReference
43 import org.springframework.http.HttpStatus
44 import org.springframework.http.ResponseEntity
45 import spock.lang.Shared
46 import spock.lang.Specification
47
48 class NetworkCmProxyDataServiceImplSpec extends Specification {
49
50     @Shared
51     def persistenceCmHandle = new CmHandle()
52     @Shared
53     def cmHandlesArray = ['cmHandle001']
54
55     def mockCpsDataService = Mock(CpsDataService)
56     def mockCpsQueryService = Mock(CpsQueryService)
57     def mockDmiOperations = Mock(DmiOperations)
58     def mockCpsModuleService = Mock(CpsModuleService)
59     def mockCpsAdminService = Mock(CpsAdminService)
60     def mockDmiProperties = Mock(NcmpConfiguration.DmiProperties)
61     def spyObjectMapper = Spy(ObjectMapper)
62
63     def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsModuleService,
64             mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper)
65
66     def cmHandle = 'some handle'
67     def noTimestamp = null
68     def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
69     def cmHandleForModelSync = new PersistenceCmHandle(id:'some cm handle', dmiServiceName: 'some service name')
70
71     def expectedDataspaceName = 'NFP-Operational'
72     def 'Query data nodes by cps path with #fetchDescendantsOption.'() {
73         given: 'a cm Handle and a cps path'
74             def cpsPath = '/cps-path'
75         when: 'queryDataNodes is invoked'
76             objectUnderTest.queryDataNodes(cmHandle, cpsPath, fetchDescendantsOption)
77         then: 'the persistence service is called once with the correct parameters'
78             1 * mockCpsQueryService.queryDataNodes(expectedDataspaceName, cmHandle, cpsPath, fetchDescendantsOption)
79         where: 'all fetch descendants options are supported'
80             fetchDescendantsOption << FetchDescendantsOption.values()
81     }
82
83     def 'Create full data node: #scenario.'() {
84         given: 'a cm handle and root xpath'
85             def jsonData = 'some json'
86         when: 'createDataNode is invoked'
87             objectUnderTest.createDataNode(cmHandle, xpath, jsonData)
88         then: 'the CPS service method is invoked once with the expected parameters'
89             1 * mockCpsDataService.saveData(expectedDataspaceName, cmHandle, jsonData, noTimestamp)
90         where: 'following parameters were used'
91             scenario           | xpath
92             'no xpath'         | ''
93             'root level xpath' | '/'
94     }
95
96     def 'Create child data node.'() {
97         given: 'a cm handle and parent node xpath'
98             def jsonData = 'some json'
99             def xpath = '/test-node'
100         when: 'createDataNode is invoked'
101             objectUnderTest.createDataNode(cmHandle, xpath, jsonData)
102         then: 'the CPS service method is invoked once with the expected parameters'
103             1 * mockCpsDataService.saveData(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
104     }
105
106     def 'Add list-node elements.'() {
107         given: 'a cm handle and parent node xpath'
108             def jsonData = 'some json'
109             def xpath = '/test-node'
110         when: 'addListNodeElements is invoked'
111             objectUnderTest.addListNodeElements(cmHandle, xpath, jsonData)
112         then: 'the CPS service method is invoked once with the expected parameters'
113             1 * mockCpsDataService.saveListNodeData(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
114     }
115
116     def 'Update data node leaves.'() {
117         given: 'a cm Handle and a cps path'
118             def xpath = '/xpath'
119             def jsonData = 'some json'
120         when: 'updateNodeLeaves is invoked'
121             objectUnderTest.updateNodeLeaves(cmHandle, xpath, jsonData)
122         then: 'the persistence service is called once with the correct parameters'
123             1 * mockCpsDataService.updateNodeLeaves(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
124     }
125
126     def 'Replace data node tree.'() {
127         given: 'a cm Handle and a cps path'
128             def xpath = '/xpath'
129             def jsonData = 'some json'
130         when: 'replaceNodeTree is invoked'
131             objectUnderTest.replaceNodeTree(cmHandle, xpath, jsonData)
132         then: 'the persistence service is called once with the correct parameters'
133             1 * mockCpsDataService.replaceNodeTree(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
134     }
135
136     def 'Register or re-register a DMI Plugin with #scenario cm handles.'() {
137         given: 'a registration '
138             NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
139             def dmiPluginRegistration = new DmiPluginRegistration()
140             dmiPluginRegistration.dmiPlugin = 'my-server'
141             persistenceCmHandle.cmHandleID = '123'
142             persistenceCmHandle.cmHandleProperties = [name1: 'value1', name2: 'value2']
143             dmiPluginRegistration.createdCmHandles = createdCmHandles
144             dmiPluginRegistration.updatedCmHandles = updatedCmHandles
145             dmiPluginRegistration.removedCmHandles = removedCmHandles
146             def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","additional-properties":[{"name":"name1","value":"value1"},{"name":"name2","value":"value2"}]}]}'
147         when: 'registration is updated'
148             objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
149         then: 'the CPS save list node data is invoked with the expected parameters'
150             expectedCallsToSaveNode * mockCpsDataService.saveListNodeData('NCMP-Admin', 'ncmp-dmi-registry',
151                 '/dmi-registry', expectedJsonData, noTimestamp)
152         and: 'update Node and Child Data Nodes is invoked with correct parameters'
153             expectedCallsToUpdateNode * mockCpsDataService.updateNodeLeavesAndExistingDescendantLeaves('NCMP-Admin',
154                 'ncmp-dmi-registry', '/dmi-registry', expectedJsonData, noTimestamp)
155         and : 'delete list data node is invoked with the correct parameters'
156             expectedCallsToDeleteListDataNode * mockCpsDataService.deleteListNodeData('NCMP-Admin',
157                 'ncmp-dmi-registry', "/dmi-registry/cm-handles[@id='cmHandle001']", noTimestamp)
158
159         where:
160             scenario                        | createdCmHandles      | updatedCmHandles      | removedCmHandles || expectedCallsToSaveNode   | expectedCallsToUpdateNode | expectedCallsToDeleteListDataNode
161             'create'                        | [persistenceCmHandle] | []                    | []               || 1                         | 0                         | 0
162             'update'                        | []                    | [persistenceCmHandle] | []               || 0                         | 1                         | 0
163             'delete'                        | []                    | []                    | cmHandlesArray   || 0                         | 0                         | 1
164             'create, update and delete'     | [persistenceCmHandle] | [persistenceCmHandle] | cmHandlesArray   || 1                         | 1                         | 1
165             'no valid data'                 | null                  | null                  |  null            || 0                         | 0                         | 0
166     }
167
168     def 'Register a DMI Plugin for the given cmHandle without additional properties.'() {
169         given: 'a registration without cmHandle properties '
170             NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
171             def dmiPluginRegistration = new DmiPluginRegistration()
172             dmiPluginRegistration.dmiPlugin = 'my-server'
173             persistenceCmHandle.cmHandleID = '123'
174             persistenceCmHandle.cmHandleProperties = null
175             dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
176             def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","additional-properties":[]}]}'
177         when: 'registration is updated'
178             objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
179         then: 'the CPS save list node data is invoked with the expected parameters'
180             1 * mockCpsDataService.saveListNodeData('NCMP-Admin', 'ncmp-dmi-registry',
181                 '/dmi-registry', expectedJsonData, noTimestamp)
182     }
183
184     def 'Register a DMI Plugin with JSON processing errors during #scenario.'() {
185         given: 'a registration without cmHandle properties '
186             NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
187             def dmiPluginRegistration = new DmiPluginRegistration()
188             dmiPluginRegistration.createdCmHandles = createdCmHandles
189             dmiPluginRegistration.updatedCmHandles = updatedCmHandles
190         and: 'an JSON processing exception occurs'
191             spyObjectMapper.writeValueAsString(_) >> { throw (new JsonProcessingException('')) }
192         when: 'registration is updated'
193             objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
194         then: 'a data validation exception is thrown'
195             thrown(DataValidationException)
196         where:
197             scenario | createdCmHandles      | updatedCmHandles
198             'create' | [persistenceCmHandle] | []
199             'update' | []                    | [persistenceCmHandle]
200     }
201
202     def 'Register a DMI Plugin with no data found during delete.'() {
203         given: 'a registration without cmHandle properties '
204             NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
205             def dmiPluginRegistration = new DmiPluginRegistration()
206             dmiPluginRegistration.removedCmHandles = ['some cm handle']
207         and: 'an JSON processing exception occurs'
208             mockCpsDataService.deleteListNodeData(*_) >>  { throw (new DataNodeNotFoundException('','')) }
209         when: 'registration is updated'
210             objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
211         then: 'no exception is thrown'
212             noExceptionThrown()
213     }
214
215     def 'Get resource data for pass-through operational from dmi.'() {
216         given: 'data node representing cmHandle and its properties'
217             def cmHandleDataNode = getCmHandleDataNodeForTest()
218         and: 'data node is got from data service'
219             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
220                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
221         and: 'resource data is got from DMI'
222             mockDmiOperations.getResourceDataOperationalFromDmi('testDmiService',
223                 'testCmHandle',
224                 'testResourceId',
225                 'testFieldQuery',
226                 5,
227                 'testAcceptParam',
228                 '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('result-json', HttpStatus.OK)
229         when: 'get resource data is called'
230             def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
231             'testResourceId',
232             'testAcceptParam',
233             'testFieldQuery',
234             5)
235         then: 'dmi returns ok response'
236             response == 'result-json'
237     }
238
239     def 'Get resource data for pass-through operational from dmi threw parsing exception.'() {
240         given: 'data node representing cmHandle and its properties'
241             def cmHandleDataNode = getCmHandleDataNodeForTest()
242         and: 'cps data service returns valid cmHandle data node'
243             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
244                     cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
245         and: 'objectMapper not able to parse object'
246             def mockObjectMapper = Mock(ObjectMapper)
247             objectUnderTest.objectMapper = mockObjectMapper
248             mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
249         when: 'get resource data is called'
250             def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
251                     'testResourceId',
252                     'testAcceptParam',
253                     'testFieldQuery',
254                     5)
255         then: 'exception is thrown with the expected details'
256             def exceptionThrown = thrown(NcmpException.class)
257             exceptionThrown.details == 'testException'
258     }
259
260     def 'Get resource data for pass-through operational from dmi return NOK response.'() {
261         given: 'data node representing cmHandle and its properties'
262             def cmHandleDataNode = getCmHandleDataNodeForTest()
263         and: 'cps data service returns valid cmHandle data node'
264             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
265                     cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
266         and: 'dmi returns NOK response'
267             mockDmiOperations.getResourceDataOperationalFromDmi('testDmiService',
268                     'testCmHandle',
269                     'testResourceId',
270                     'testFieldQuery',
271                     5,
272                     'testAcceptParam',
273                     '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
274                     >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
275         when: 'get resource data is called'
276             def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
277                     'testResourceId',
278                     'testAcceptParam',
279                     'testFieldQuery',
280                     5)
281         then: 'exception is thrown'
282             def exceptionThrown = thrown(NcmpException.class)
283         and: 'details contains the original response'
284             exceptionThrown.details.contains('NOK-json')
285     }
286
287     def 'Get resource data for pass-through running from dmi.'() {
288         given: 'data node representing cmHandle and its properties'
289             def cmHandleDataNode = getCmHandleDataNodeForTest()
290         and: 'cpsDataService returns valid dataNode'
291             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
292                     cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
293         and: 'dmi returns valid response and data'
294             mockDmiOperations.getResourceDataPassThroughRunningFromDmi('testDmiService',
295                     'testCmHandle',
296                     'testResourceId',
297                     'testFieldQuery',
298                     5,
299                     'testAcceptParam',
300                     '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('{result-json}', HttpStatus.OK)
301         when: 'get resource data is called'
302             def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
303                     'testResourceId',
304                     'testAcceptParam',
305                     'testFieldQuery',
306                     5)
307         then: 'get resource data returns expected response'
308             response == '{result-json}'
309     }
310
311     def 'Get resource data for pass-through running from dmi threw parsing exception.'() {
312         given: 'data node representing cmHandle and its properties'
313             def cmHandleDataNode = getCmHandleDataNodeForTest()
314         and: 'cpsDataService returns valid dataNode'
315             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
316                     cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
317         and: 'objectMapper not able to parse object'
318             def mockObjectMapper = Mock(ObjectMapper)
319             objectUnderTest.objectMapper = mockObjectMapper
320             mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
321         when: 'get resource data is called'
322             def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
323                     'testResourceId',
324                     'testAcceptParam',
325                     'testFieldQuery',
326                     5)
327         then: 'exception is thrown with the expected details'
328             def exceptionThrown = thrown(NcmpException.class)
329             exceptionThrown.details == 'testException'
330     }
331
332     def 'Get resource data for pass-through running from dmi return NOK response.'() {
333         given: 'data node representing cmHandle and its properties'
334             def cmHandleDataNode = getCmHandleDataNodeForTest()
335         and: 'cpsDataService returns valid dataNode'
336             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
337                     cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
338         and: 'dmi returns NOK response'
339             mockDmiOperations.getResourceDataPassThroughRunningFromDmi('testDmiService',
340                     'testCmHandle',
341                     'testResourceId',
342                     'testFieldQuery',
343                     5,
344                     'testAcceptParam',
345                     '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
346                     >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
347         when: 'get resource data is called'
348             def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
349                     'testResourceId',
350                     'testAcceptParam',
351                     'testFieldQuery',
352                     5)
353         then: 'exception is thrown'
354             def exceptionThrown = thrown(NcmpException.class)
355         and: 'details contains the original response'
356             exceptionThrown.details.contains('NOK-json')
357     }
358
359     def 'Write resource data for pass-through running from dmi using POST.'() {
360         given: 'data node representing cmHandle and its properties'
361             def cmHandleDataNode = getCmHandleDataNodeForTest()
362         and: 'cpsDataService returns valid cm-handle datanode'
363             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
364                     cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
365         when: 'get resource data is called'
366             objectUnderTest.createResourceDataPassThroughRunningForCmHandle('testCmHandle',
367                     'testResourceId',
368                     '{some-json}', 'application/json')
369         then: 'dmi called with correct data'
370             1 * mockDmiOperations.createResourceDataPassThroughRunningFromDmi('testDmiService',
371                 'testCmHandle',
372                 'testResourceId',
373                 '{"operation":"create","dataType":"application/json","data":"{some-json}","cmHandleProperties":{"testName":"testValue"}}')
374                 >> { new ResponseEntity<>(HttpStatus.OK) }
375     }
376
377     def 'Write resource data for pass-through running from dmi using POST "not found" response (from DMI).'() {
378         given: 'data node representing cmHandle and its properties'
379             def cmHandleDataNode = getCmHandleDataNodeForTest()
380         and: 'cpsDataService returns valid dataNode'
381             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
382                     cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
383         and: 'dmi throws exception'
384             mockDmiOperations.createResourceDataPassThroughRunningFromDmi(_ as String, _ as String, _ as String, _ as String)
385                     >> { new ResponseEntity<>(HttpStatus.NOT_FOUND) }
386         when: 'get resource data is called'
387             objectUnderTest.createResourceDataPassThroughRunningForCmHandle('testCmHandle',
388                     'testResourceId',
389                     '{some-json}', 'application/json')
390         then: 'exception is thrown'
391             def exceptionThrown = thrown(NcmpException.class)
392         and: 'details contains (not found) error code: 404'
393             exceptionThrown.details.contains('404')
394     }
395
396     def 'Sync model for a (new) cm handle with #scenario'() {
397         given: 'DMI PLug-in returns a list of module references'
398             getModulesForCmHandle()
399             def knownModule1 = new ModuleReference('module1', '1')
400             def knownOtherModule = new ModuleReference('some other module', 'some revision')
401         and: 'CPS-Core returns list of known modules'
402             mockCpsModuleService.getYangResourceModuleReferences(_) >> [knownModule1, knownOtherModule]
403         and: 'DMI-Plugin returns resource(s) for "new" module(s)'
404             def moduleResources = new ResponseEntity<String>(sdncReponseBody, HttpStatus.OK)
405             mockDmiOperations.getResourceFromDmiWithJsonData(_, _, _, 'moduleResources') >> moduleResources
406         when: 'module Sync is triggered'
407             objectUnderTest.createAnchorAndSyncModel(cmHandleForModelSync)
408         then: 'the CPS module service is called once with the correct parameters'
409             1 * mockCpsModuleService.createSchemaSetFromModules(expectedDataspaceName, cmHandleForModelSync.getId(), expectedYangResourceToContentMap, [knownModule1])
410         and: 'admin service create anchor method has been called with correct parameters'
411             1 * mockCpsAdminService.createAnchor(expectedDataspaceName, cmHandleForModelSync.getId(), cmHandleForModelSync.getId())
412         where: 'the following responses are recieved from SDNC'
413             scenario             | sdncReponseBody                                                                        || expectedYangResourceToContentMap
414             'one unknown module' | '[{"moduleName" : "someModule", "revision" : "1","yangSource": "[some yang source]"}]' || [someModule: 'some yang source']
415             'no unknown module'  | '[]'                                                                                   || [:]
416     }
417
418     def 'Getting Yang Resources.'() {
419         when: 'yang resources is called'
420             objectUnderTest.getYangResourcesModuleReferences('some cm handle')
421         then: 'CPS module services is invoked for the correct dataspace and cm handle'
422             1 * mockCpsModuleService.getYangResourcesModuleReferences('NFP-Operational','some cm handle')
423     }
424
425     def getModulesForCmHandle() {
426         def jsonData = TestUtils.getResourceFileContent('cmHandleModules.json')
427         mockDmiProperties.getAuthUsername() >> 'someUser'
428         mockDmiProperties.getAuthPassword() >> 'somePassword'
429         mockDmiProperties.getDmiPluginBasePath() >> 'someUrl'
430         def moduleReferencesFromCmHandleAsJson = new ResponseEntity<String>(jsonData, HttpStatus.OK)
431         mockDmiOperations.getResourceFromDmi(_, cmHandleForModelSync.getId(), 'modules') >> moduleReferencesFromCmHandleAsJson
432     }
433
434     def getObjectUnderTestWithModelSyncDisabled() {
435         def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsModuleService,
436                 mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper))
437         objectUnderTest.createAnchorAndSyncModel(_) >> null
438         return objectUnderTest
439     }
440
441     def getCmHandleDataNodeForTest() {
442         def cmHandleDataNode = new DataNode()
443         cmHandleDataNode.leaves = ['dmi-service-name': 'testDmiService']
444         def cmHandlePropertyDataNode = new DataNode()
445         cmHandlePropertyDataNode.leaves = ['name': 'testName', 'value': 'testValue']
446         cmHandleDataNode.childDataNodes = [cmHandlePropertyDataNode]
447         return cmHandleDataNode
448     }
449
450 }