2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021-2024 Nordix Foundation
4 * Modifications Copyright (C) 2021 Pantheon.tech
5 * Modifications Copyright (C) 2021-2022 Bell Canada
6 * Modifications Copyright (C) 2023 TechMahindra Ltd.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
20 * SPDX-License-Identifier: Apache-2.0
21 * ============LICENSE_END=========================================================
24 package org.onap.cps.ncmp.api.impl
26 import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse
28 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
29 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
30 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
31 import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL
32 import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
33 import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
34 import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
35 import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
37 import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker
38 import com.hazelcast.map.IMap
39 import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
40 import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler
41 import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
42 import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager
43 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
44 import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries
45 import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
46 import org.onap.cps.ncmp.api.impl.inventory.CompositeState
47 import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
48 import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
49 import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
50 import org.onap.cps.ncmp.api.models.DataOperationDefinition
51 import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters
52 import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters
53 import org.onap.cps.ncmp.api.models.ConditionApiProperties
54 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
55 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
56 import org.onap.cps.ncmp.api.models.DataOperationRequest
57 import org.onap.cps.spi.exceptions.CpsException
58 import org.onap.cps.spi.model.ConditionProperties
60 import java.util.stream.Collectors
61 import org.onap.cps.utils.JsonObjectMapper
62 import com.fasterxml.jackson.databind.ObjectMapper
63 import org.onap.cps.api.CpsDataService
64 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
65 import org.onap.cps.spi.FetchDescendantsOption
66 import org.onap.cps.spi.model.DataNode
67 import org.springframework.http.HttpStatus
68 import org.springframework.http.ResponseEntity
69 import spock.lang.Specification
71 class NetworkCmProxyDataServiceImplSpec extends Specification {
73 def mockCpsDataService = Mock(CpsDataService)
74 def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
75 def mockDmiDataOperations = Mock(DmiDataOperations)
76 def nullNetworkCmProxyDataServicePropertyHandler = null
77 def mockInventoryPersistence = Mock(InventoryPersistence)
78 def mockCmHandleQueries = Mock(CmHandleQueries)
79 def mockDmiPluginRegistration = Mock(DmiPluginRegistration)
80 def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandleQueryService)
81 def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler)
82 def stubModuleSyncStartedOnCmHandles = Stub(IMap<String, Object>)
83 def stubTrustLevelPerDmiPlugin = Stub(Map<String, TrustLevel>)
84 def mockTrustLevelManager = Mock(TrustLevelManager)
85 def mockAlternateIdChecker = Mock(AlternateIdChecker)
88 def NO_REQUEST_ID = null
89 def OPTIONS_PARAM = '(a=1,b=2)'
90 def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'test-cm-handle-id')
92 def objectUnderTest = new NetworkCmProxyDataServiceImpl(
93 spiedJsonObjectMapper,
94 mockDmiDataOperations,
95 nullNetworkCmProxyDataServicePropertyHandler,
96 mockInventoryPersistence,
98 mockCpsCmHandlerQueryService,
99 mockLcmEventsCmHandleStateHandler,
101 stubModuleSyncStartedOnCmHandles,
102 stubTrustLevelPerDmiPlugin,
103 mockTrustLevelManager,
104 mockAlternateIdChecker)
106 def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
108 def dataNode = [new DataNode(leaves: ['id': 'some-cm-handle', 'dmi-service-name': 'testDmiService'])]
110 def 'Write resource data for pass-through running from DMI using POST.'() {
111 given: 'cpsDataService returns valid datanode'
113 when: 'write resource data is called'
114 objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
115 'testResourceId', CREATE,
116 '{some-json}', 'application/json')
117 then: 'DMI called with correct data'
118 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
119 CREATE, '{some-json}', 'application/json')
120 >> { new ResponseEntity<>(HttpStatus.CREATED) }
123 def 'Get resource data for pass-through operational from DMI.'() {
124 given: 'cpsDataService returns valid data node'
126 and: 'get resource data from DMI is called'
127 mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_OPERATIONAL.datastoreName,'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) >>
128 new ResponseEntity<>('dmi-response', HttpStatus.OK)
129 when: 'get resource data operational for cm-handle is called'
130 def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID)
131 then: 'DMI returns a json response'
132 assert response == 'dmi-response'
135 def 'Get resource data for pass-through running from DMI.'() {
136 given: 'cpsDataService returns valid data node'
138 and: 'DMI returns valid response and data'
139 mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) >>
140 new ResponseEntity<>('{dmi-response}', HttpStatus.OK)
141 when: 'get resource data is called'
142 def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID)
143 then: 'get resource data returns expected response'
144 assert response == '{dmi-response}'
147 def 'Get resource data for operational (cached) data.'() {
148 given: 'CPS Data service returns some object(s)'
149 mockCpsDataService.getDataNodes(OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', FetchDescendantsOption.OMIT_DESCENDANTS) >> ['First Object', 'other Object']
150 when: 'get resource data is called'
151 def response = objectUnderTest.getResourceDataForCmHandle(OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', FetchDescendantsOption.OMIT_DESCENDANTS)
152 then: 'get resource data returns teh first object from the data service'
153 assert response == 'First Object'
156 def 'Execute (async) data operation for #datastoreName from DMI.'() {
157 given: 'cpsDataService returns valid data node'
158 def dataOperationRequest = getDataOperationRequest(datastoreName)
159 when: 'request resource data for data operation is called'
160 objectUnderTest.executeDataOperationForCmHandles('some topic', dataOperationRequest, 'requestId')
161 then: 'request resource data for data operation returns expected response'
162 1 * mockDmiDataOperations.requestResourceDataFromDmi('some topic', dataOperationRequest, 'requestId')
163 where: 'the following data stores are used'
164 datastoreName << [PASSTHROUGH_RUNNING.datastoreName, PASSTHROUGH_OPERATIONAL.datastoreName]
167 def 'Getting Yang Resources.'() {
168 when: 'yang resources is called'
169 objectUnderTest.getYangResourcesModuleReferences('some-cm-handle')
170 then: 'CPS module services is invoked for the correct dataspace and cm handle'
171 1 * mockInventoryPersistence.getYangResourcesModuleReferences('some-cm-handle')
174 def 'Get a cm handle.'() {
175 given: 'the system returns a yang modelled cm handle'
176 def dmiServiceName = 'some service name'
177 def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
178 lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
179 lastUpdateTime: 'some-timestamp',
180 dataSyncEnabled: false,
181 dataStores: dataStores())
182 def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')]
183 def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')]
184 def moduleSetTag = 'some-module-set-tag'
185 def alternateId = 'some-alternate-id'
186 def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName,
187 dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState,
188 moduleSetTag: moduleSetTag, alternateId: alternateId)
189 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
190 when: 'getting cm handle details for a given cm handle id from ncmp service'
191 def result = objectUnderTest.getNcmpServiceCmHandle('some-cm-handle')
192 then: 'the result is a ncmpServiceCmHandle'
193 result.class == NcmpServiceCmHandle.class
194 and: 'the cm handle contains the cm handle id'
195 result.cmHandleId == 'some-cm-handle'
196 and: 'the cm handle contains the alternate id'
197 result.alternateId == 'some-alternate-id'
198 and: 'the cm handle contains the module-set-tag'
199 result.moduleSetTag == 'some-module-set-tag'
200 and: 'the cm handle contains the DMI Properties'
201 result.dmiProperties ==[ Book:'Romance Novel' ]
202 and: 'the cm handle contains the public Properties'
203 result.publicProperties == [ "Public Book":'Public Romance Novel' ]
204 and: 'the cm handle contains the cm handle composite state'
205 result.compositeState == compositeState
208 def 'Get cm handle public properties'() {
209 given: 'a yang modelled cm handle'
210 def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
211 def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
212 def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties)
213 and: 'the system returns this yang modelled cm handle'
214 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
215 when: 'getting cm handle public properties for a given cm handle id from ncmp service'
216 def result = objectUnderTest.getCmHandlePublicProperties('some-cm-handle')
217 then: 'the result returns the correct data'
218 result == [ 'public prop' : 'some public prop' ]
221 def 'Execute cm handle id search for inventory'() {
222 given: 'a ConditionApiProperties object'
223 def conditionProperties = new ConditionProperties()
224 conditionProperties.conditionName = 'hasAllProperties'
225 conditionProperties.conditionParameters = [ [ 'some-key' : 'some-value' ] ]
226 def conditionServiceProps = new CmHandleQueryServiceParameters()
227 conditionServiceProps.cmHandleQueryParameters = [conditionProperties] as List<ConditionProperties>
228 and: 'the system returns an set of cmHandle ids'
229 mockCpsCmHandlerQueryService.queryCmHandleIdsForInventory(*_) >> [ 'cmHandle1', 'cmHandle2' ]
230 when: 'getting cm handle id set for a given dmi property'
231 def result = objectUnderTest.executeCmHandleIdSearchForInventory(conditionServiceProps)
232 then: 'the result returns the correct 2 elements'
233 assert result.size() == 2
234 assert result.contains('cmHandle1')
235 assert result.contains('cmHandle2')
238 def 'Get cm handle composite state'() {
239 given: 'a yang modelled cm handle'
240 def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
241 lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
242 lastUpdateTime: 'some-timestamp',
243 dataSyncEnabled: false,
244 dataStores: dataStores())
245 def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
246 def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
247 def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
248 and: 'the system returns this yang modelled cm handle'
249 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
250 when: 'getting cm handle composite state for a given cm handle id from ncmp service'
251 def result = objectUnderTest.getCmHandleCompositeState('some-cm-handle')
252 then: 'the result returns the correct data'
253 result == compositeState
256 def 'Update resource data for pass-through running from dmi using POST #scenario DMI properties.'() {
257 given: 'cpsDataService returns valid datanode'
258 mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
259 when: 'get resource data is called'
260 objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
261 'testResourceId', UPDATE,
262 '{some-json}', 'application/json')
263 then: 'DMI called with correct data'
264 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
265 UPDATE, '{some-json}', 'application/json')
266 >> { new ResponseEntity<>(HttpStatus.OK) }
269 def 'Verify modules and create anchor params.'() {
270 given: 'dmi plugin registration return created cm handles'
271 def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'service1', dmiModelPlugin: 'service1',
272 dmiDataPlugin: 'service2')
273 dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle]
274 mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle]
275 and: 'no rejected cm handles because of alternate ids'
276 mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> []
277 when: 'parse and create cm handle in dmi registration then sync module'
278 mockDmiPluginRegistration.createdCmHandles = ['test-cm-handle-id']
279 objectUnderTest.processCreatedCmHandles(mockDmiPluginRegistration, new DmiPluginRegistrationResponse())
280 then: 'system persists the cm handle state'
281 1 * mockLcmEventsCmHandleStateHandler.initiateStateAdvised(_) >> {
283 def cmHandleStatePerCmHandle = (args[0] as Collection)
284 cmHandleStatePerCmHandle.each {
285 assert it.id == 'test-cm-handle-id'
291 def 'Execute cm handle id search'() {
292 given: 'valid CmHandleQueryApiParameters input'
293 def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
294 def conditionApiProperties = new ConditionApiProperties()
295 conditionApiProperties.conditionName = 'hasAllModules'
296 conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
297 cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
298 and: 'query cm handle method return with a data node list'
299 mockCpsCmHandlerQueryService.queryCmHandleIds(
300 spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
301 >> ['cm-handle-id-1']
302 when: 'execute cm handle search is called'
303 def result = objectUnderTest.executeCmHandleIdSearch(cmHandleQueryApiParameters)
304 then: 'result is the same collection as returned by the CPS Data Service'
305 assert result == ['cm-handle-id-1']
308 def 'Getting module definitions by module'() {
309 when: 'get module definitions is performed with module name'
310 objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
311 then: 'ncmp inventory persistence service is invoked once with correct parameters'
312 1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
315 def 'Getting module definitions by cm handle id'() {
316 when: 'get module definitions is performed with cm handle id'
317 objectUnderTest.getModuleDefinitionsByCmHandleId('some-cm-handle')
318 then: 'ncmp inventory persistence service is invoked once with correct parameter'
319 1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleId('some-cm-handle')
322 def 'Execute cm handle search'() {
323 given: 'valid CmHandleQueryApiParameters input'
324 def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
325 def conditionApiProperties = new ConditionApiProperties()
326 conditionApiProperties.conditionName = 'hasAllModules'
327 conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
328 cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
329 and: 'query cm handle method return with a data node list'
330 mockCpsCmHandlerQueryService.queryCmHandles(
331 spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
332 >> [new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1')]
333 when: 'execute cm handle search is called'
334 def result = objectUnderTest.executeCmHandleSearch(cmHandleQueryApiParameters)
335 then: 'result is the same collection as returned by the CPS Data Service'
336 assert result.stream().map(d -> d.cmHandleId).collect(Collectors.toSet()) == ['cm-handle-id-1'] as Set
339 def 'Set Cm Handle Data Sync Enabled Flag where data sync flag is #scenario'() {
340 given: 'an existing cm handle composite state'
341 def compositeState = new CompositeState(cmHandleState: CmHandleState.READY, dataSyncEnabled: initialDataSyncEnabledFlag,
342 dataStores: CompositeState.DataStores.builder()
343 .operationalDataStore(CompositeState.Operational.builder()
344 .dataStoreSyncState(initialDataSyncState)
346 and: 'get cm handle state returns the composite state for the given cm handle id'
347 mockInventoryPersistence.getCmHandleState('some-cm-handle-id') >> compositeState
348 when: 'set data sync enabled is called with the data sync enabled flag set to #dataSyncEnabledFlag'
349 objectUnderTest.setDataSyncEnabled('some-cm-handle-id', dataSyncEnabledFlag)
350 then: 'the data sync enabled flag is set to #dataSyncEnabled'
351 compositeState.dataSyncEnabled == dataSyncEnabledFlag
352 and: 'the data store sync state is set to #expectedDataStoreSyncState'
353 compositeState.dataStores.operationalDataStore.dataStoreSyncState == expectedDataStoreSyncState
354 and: 'the cps data service to delete data nodes is invoked the expected number of times'
355 deleteDataNodeExpectedNumberOfInvocation * mockCpsDataService.deleteDataNode(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'some-cm-handle-id', '/netconf-state', _)
356 and: 'the inventory persistence service to update node leaves is called with the correct values'
357 saveCmHandleStateExpectedNumberOfInvocations * mockInventoryPersistence.saveCmHandleState('some-cm-handle-id', compositeState)
358 where: 'the following data sync enabled flag is used'
359 scenario | dataSyncEnabledFlag | initialDataSyncEnabledFlag | initialDataSyncState || expectedDataStoreSyncState | deleteDataNodeExpectedNumberOfInvocation | saveCmHandleStateExpectedNumberOfInvocations
360 'enabled' | true | false | DataStoreSyncState.NONE_REQUESTED || DataStoreSyncState.UNSYNCHRONIZED | 0 | 1
361 'disabled' | false | true | DataStoreSyncState.UNSYNCHRONIZED || DataStoreSyncState.NONE_REQUESTED | 0 | 1
362 'disabled where sync-state is currently SYNCHRONIZED' | false | true | DataStoreSyncState.SYNCHRONIZED || DataStoreSyncState.NONE_REQUESTED | 1 | 1
363 'is set to existing flag state' | true | true | DataStoreSyncState.UNSYNCHRONIZED || DataStoreSyncState.UNSYNCHRONIZED | 0 | 0
366 def 'Set cm Handle Data Sync Enabled flag with following cm handle not in ready state exception' () {
367 given: 'a cm handle composite state'
368 def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED, dataSyncEnabled: false)
369 and: 'get cm handle state returns the composite state for the given cm handle id'
370 mockInventoryPersistence.getCmHandleState('some-cm-handle-id') >> compositeState
371 when: 'set data sync enabled is called with the data sync enabled flag set to true'
372 objectUnderTest.setDataSyncEnabled('some-cm-handle-id', true)
373 then: 'the expected exception is thrown'
375 and: 'the inventory persistence service to update node leaves is not invoked'
376 0 * mockInventoryPersistence.saveCmHandleState(_, _)
379 def 'Get all cm handle IDs by DMI plugin identifier.' () {
380 given: 'cm handle queries service returns cm handles'
381 1 * mockCmHandleQueries.getCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier') >> ['cm-handle-1','cm-handle-2']
382 when: 'cm handle Ids are requested with dmi plugin identifier'
383 def result = objectUnderTest.getAllCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier')
384 then: 'the result size is correct'
385 assert result.size() == 2
386 and: 'the result returns the correct details'
387 assert result.containsAll('cm-handle-1','cm-handle-2')
391 CompositeState.DataStores.builder()
392 .operationalDataStore(CompositeState.Operational.builder()
393 .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED)
394 .lastSyncTime('some-timestamp').build()).build()
398 mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
401 def getDataOperationRequest(datastore) {
402 def dataOperationRequest = new DataOperationRequest()
403 def dataOperationDefinitions = new ArrayList()
404 dataOperationDefinitions.add(getDataOperationDefinition(datastore))
405 dataOperationRequest.setDataOperationDefinitions(dataOperationDefinitions)
406 return dataOperationRequest
409 def getDataOperationDefinition(datastore) {
410 def dataOperationDefinition = new DataOperationDefinition()
411 dataOperationDefinition.setOperation("read")
412 dataOperationDefinition.setOperationId("operational-12")
413 dataOperationDefinition.setDatastore(datastore)
414 def targetIds = new ArrayList()
415 targetIds.add("some-cm-handle")
416 dataOperationDefinition.setCmHandleIds(targetIds)
417 return dataOperationDefinition