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