Merge "Set resource limits of docker-compose containers"
[cps.git] / cps-ncmp-service / src / test / groovy / org / onap / cps / ncmp / api / impl / NetworkCmProxyDataServiceImplSpec.groovy
1 /*
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
11  *
12  *        http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  *  SPDX-License-Identifier: Apache-2.0
21  *  ============LICENSE_END=========================================================
22  */
23
24 package org.onap.cps.ncmp.api.impl
25
26 import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper
27
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
36
37 import com.hazelcast.map.IMap
38 import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
39 import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler
40 import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
41 import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager
42 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
43 import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries
44 import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
45 import org.onap.cps.ncmp.api.impl.inventory.CompositeState
46 import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
47 import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
48 import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
49 import org.onap.cps.ncmp.api.models.DataOperationDefinition
50 import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters
51 import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters
52 import org.onap.cps.ncmp.api.models.ConditionApiProperties
53 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
54 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
55 import org.onap.cps.ncmp.api.models.DataOperationRequest
56 import org.onap.cps.spi.exceptions.CpsException
57 import org.onap.cps.spi.model.ConditionProperties
58 import spock.lang.Shared
59 import java.util.stream.Collectors
60 import org.onap.cps.utils.JsonObjectMapper
61 import com.fasterxml.jackson.databind.ObjectMapper
62 import org.onap.cps.api.CpsDataService
63 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
64 import org.onap.cps.spi.FetchDescendantsOption
65 import org.onap.cps.spi.model.DataNode
66 import org.springframework.http.HttpStatus
67 import org.springframework.http.ResponseEntity
68 import spock.lang.Specification
69
70 class NetworkCmProxyDataServiceImplSpec extends Specification {
71
72     def mockCpsDataService = Mock(CpsDataService)
73     def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
74     def mockDmiDataOperations = Mock(DmiDataOperations)
75     def nullNetworkCmProxyDataServicePropertyHandler = null
76     def mockInventoryPersistence = Mock(InventoryPersistence)
77     def mockCmHandleQueries = Mock(CmHandleQueries)
78     def mockDmiPluginRegistration = Mock(DmiPluginRegistration)
79     def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandleQueryService)
80     def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler)
81     def stubModuleSyncStartedOnCmHandles = Stub(IMap<String, Object>)
82     def stubTrustLevelPerDmiPlugin = Stub(Map<String, TrustLevel>)
83     def mockTrustLevelManager = Mock(TrustLevelManager)
84     def mockCmHandleIdMapper = Mock(CmHandleIdMapper)
85
86     def NO_TOPIC = null
87     def NO_REQUEST_ID = null
88     @Shared
89     def OPTIONS_PARAM = '(a=1,b=2)'
90     @Shared
91     def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'test-cm-handle-id')
92
93     def objectUnderTest = new NetworkCmProxyDataServiceImpl(
94             spiedJsonObjectMapper,
95             mockDmiDataOperations,
96             nullNetworkCmProxyDataServicePropertyHandler,
97             mockInventoryPersistence,
98             mockCmHandleQueries,
99             mockCpsCmHandlerQueryService,
100             mockLcmEventsCmHandleStateHandler,
101             mockCpsDataService,
102             stubModuleSyncStartedOnCmHandles,
103             stubTrustLevelPerDmiPlugin,
104             mockTrustLevelManager,
105             mockCmHandleIdMapper
106     )
107
108     def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
109
110     def dataNode = [new DataNode(leaves: ['id': 'some-cm-handle', 'dmi-service-name': 'testDmiService'])]
111
112     def 'Write resource data for pass-through running from DMI using POST.'() {
113         given: 'cpsDataService returns valid datanode'
114             mockDataNode()
115         when: 'write resource data is called'
116             objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
117                 'testResourceId', CREATE,
118                 '{some-json}', 'application/json')
119         then: 'DMI called with correct data'
120             1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
121                     CREATE, '{some-json}', 'application/json')
122                 >> { new ResponseEntity<>(HttpStatus.CREATED) }
123     }
124
125     def 'Get resource data for pass-through operational from DMI.'() {
126         given: 'cpsDataService returns valid data node'
127             mockDataNode()
128         and: 'get resource data from DMI is called'
129             mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_OPERATIONAL.datastoreName,'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) >>
130                     new ResponseEntity<>('dmi-response', HttpStatus.OK)
131         when: 'get resource data operational for cm-handle is called'
132             def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID)
133         then: 'DMI returns a json response'
134             assert response == 'dmi-response'
135     }
136
137     def 'Get resource data for pass-through running from DMI.'() {
138         given: 'cpsDataService returns valid data node'
139             mockDataNode()
140         and: 'DMI returns valid response and data'
141             mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) >>
142                     new ResponseEntity<>('{dmi-response}', HttpStatus.OK)
143         when: 'get resource data is called'
144             def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID)
145         then: 'get resource data returns expected response'
146             assert response == '{dmi-response}'
147     }
148
149     def 'Get resource data for operational (cached) data.'() {
150         given: 'CPS Data service returns some object(s)'
151             mockCpsDataService.getDataNodes(OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', FetchDescendantsOption.OMIT_DESCENDANTS) >> ['First Object', 'other Object']
152         when: 'get resource data is called'
153             def response = objectUnderTest.getResourceDataForCmHandle(OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', FetchDescendantsOption.OMIT_DESCENDANTS)
154         then: 'get resource data returns teh first object from the data service'
155             assert response == 'First Object'
156     }
157
158     def 'Execute (async) data operation for #datastoreName from DMI.'() {
159         given: 'cpsDataService returns valid data node'
160             def dataOperationRequest = getDataOperationRequest(datastoreName)
161         when: 'request resource data for data operation is called'
162             objectUnderTest.executeDataOperationForCmHandles('some topic', dataOperationRequest, 'requestId')
163         then: 'request resource data for data operation returns expected response'
164             1 * mockDmiDataOperations.requestResourceDataFromDmi('some topic', dataOperationRequest, 'requestId')
165         where: 'the following data stores are used'
166             datastoreName << [PASSTHROUGH_RUNNING.datastoreName, PASSTHROUGH_OPERATIONAL.datastoreName]
167     }
168
169     def 'Getting Yang Resources.'() {
170         when: 'yang resources is called'
171             objectUnderTest.getYangResourcesModuleReferences('some-cm-handle')
172         then: 'CPS module services is invoked for the correct dataspace and cm handle'
173             1 * mockInventoryPersistence.getYangResourcesModuleReferences('some-cm-handle')
174     }
175
176     def 'Get a cm handle.'() {
177         given: 'the system returns a yang modelled cm handle'
178             def dmiServiceName = 'some service name'
179             def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
180                 lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
181                 lastUpdateTime: 'some-timestamp',
182                 dataSyncEnabled: false,
183                 dataStores: dataStores())
184             def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')]
185             def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')]
186             def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName,
187                 dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
188             1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
189         when: 'getting cm handle details for a given cm handle id from ncmp service'
190             def result = objectUnderTest.getNcmpServiceCmHandle('some-cm-handle')
191         then: 'the result is a ncmpServiceCmHandle'
192             result.class == NcmpServiceCmHandle.class
193         and: 'the cm handle contains the cm handle id'
194             result.cmHandleId == 'some-cm-handle'
195         and: 'the cm handle contains the DMI Properties'
196             result.dmiProperties ==[ Book:'Romance Novel' ]
197         and: 'the cm handle contains the public Properties'
198             result.publicProperties == [ "Public Book":'Public Romance Novel' ]
199         and: 'the cm handle contains the cm handle composite state'
200             result.compositeState == compositeState
201
202     }
203
204     def 'Get cm handle public properties'() {
205         given: 'a yang modelled cm handle'
206             def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
207             def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
208             def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties)
209         and: 'the system returns this yang modelled cm handle'
210             1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
211         when: 'getting cm handle public properties for a given cm handle id from ncmp service'
212             def result = objectUnderTest.getCmHandlePublicProperties('some-cm-handle')
213         then: 'the result returns the correct data'
214             result == [ 'public prop' : 'some public prop' ]
215     }
216
217     def 'Execute cm handle id search for inventory'() {
218         given: 'a ConditionApiProperties object'
219             def conditionProperties = new ConditionProperties()
220             conditionProperties.conditionName = 'hasAllProperties'
221             conditionProperties.conditionParameters = [ [ 'some-key' : 'some-value' ] ]
222             def conditionServiceProps = new CmHandleQueryServiceParameters()
223             conditionServiceProps.cmHandleQueryParameters = [conditionProperties] as List<ConditionProperties>
224         and: 'the system returns an set of cmHandle ids'
225             mockCpsCmHandlerQueryService.queryCmHandleIdsForInventory(*_) >> [ 'cmHandle1', 'cmHandle2' ]
226         when: 'getting cm handle id set for a given dmi property'
227             def result = objectUnderTest.executeCmHandleIdSearchForInventory(conditionServiceProps)
228         then: 'the result returns the correct 2 elements'
229             assert result.size() == 2
230             assert result.contains('cmHandle1')
231             assert result.contains('cmHandle2')
232     }
233
234     def 'Get cm handle composite state'() {
235         given: 'a yang modelled cm handle'
236             def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
237                 lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
238                 lastUpdateTime: 'some-timestamp',
239                 dataSyncEnabled: false,
240                 dataStores: dataStores())
241             def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
242             def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
243             def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
244         and: 'the system returns this yang modelled cm handle'
245             1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
246         when: 'getting cm handle composite state for a given cm handle id from ncmp service'
247             def result = objectUnderTest.getCmHandleCompositeState('some-cm-handle')
248         then: 'the result returns the correct data'
249             result == compositeState
250     }
251
252     def 'Update resource data for pass-through running from dmi using POST #scenario DMI properties.'() {
253         given: 'cpsDataService returns valid datanode'
254             mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
255         when: 'get resource data is called'
256             objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
257                 'testResourceId', UPDATE,
258                 '{some-json}', 'application/json')
259         then: 'DMI called with correct data'
260             1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
261                     UPDATE, '{some-json}', 'application/json')
262                 >> { new ResponseEntity<>(HttpStatus.OK) }
263     }
264
265     def 'Verify modules and create anchor params.'() {
266         given: 'dmi plugin registration return created cm handles'
267             def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'service1', dmiModelPlugin: 'service1',
268                     dmiDataPlugin: 'service2')
269             dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle]
270             mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle]
271         when: 'parse and create cm handle in dmi registration then sync module'
272             objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(mockDmiPluginRegistration)
273         then: 'system persists the cm handle state'
274             1 * mockLcmEventsCmHandleStateHandler.initiateStateAdvised(_) >> {
275                 args -> {
276                           def cmHandleStatePerCmHandle = (args[0] as Collection)
277                           cmHandleStatePerCmHandle.each {
278                             assert it.id == 'test-cm-handle-id'
279                           }
280                     }
281             }
282     }
283     
284     def 'Execute cm handle id search'() {
285         given: 'valid CmHandleQueryApiParameters input'
286             def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
287             def conditionApiProperties = new ConditionApiProperties()
288             conditionApiProperties.conditionName = 'hasAllModules'
289             conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
290             cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
291         and: 'query cm handle method return with a data node list'
292             mockCpsCmHandlerQueryService.queryCmHandleIds(
293                     spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
294                     >> ['cm-handle-id-1']
295         when: 'execute cm handle search is called'
296             def result = objectUnderTest.executeCmHandleIdSearch(cmHandleQueryApiParameters)
297         then: 'result is the same collection as returned by the CPS Data Service'
298             assert result == ['cm-handle-id-1']
299     }
300
301     def 'Getting module definitions by module'() {
302         when: 'get module definitions is performed with module name'
303             objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
304         then: 'ncmp inventory persistence service is invoked once with correct parameters'
305             1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
306     }
307
308     def 'Getting module definitions by cm handle id'() {
309         when: 'get module definitions is performed with cm handle id'
310             objectUnderTest.getModuleDefinitionsByCmHandleId('some-cm-handle')
311         then: 'ncmp inventory persistence service is invoked once with correct parameter'
312             1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleId('some-cm-handle')
313     }
314
315     def 'Execute cm handle search'() {
316         given: 'valid CmHandleQueryApiParameters input'
317             def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
318             def conditionApiProperties = new ConditionApiProperties()
319             conditionApiProperties.conditionName = 'hasAllModules'
320             conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
321             cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
322         and: 'query cm handle method return with a data node list'
323             mockCpsCmHandlerQueryService.queryCmHandles(
324                     spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
325                     >> [new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1')]
326         when: 'execute cm handle search is called'
327             def result = objectUnderTest.executeCmHandleSearch(cmHandleQueryApiParameters)
328         then: 'result is the same collection as returned by the CPS Data Service'
329             assert result.stream().map(d -> d.cmHandleId).collect(Collectors.toSet()) == ['cm-handle-id-1'] as Set
330     }
331
332     def 'Set Cm Handle Data Sync Enabled Flag where data sync flag is  #scenario'() {
333         given: 'an existing cm handle composite state'
334             def compositeState = new CompositeState(cmHandleState: CmHandleState.READY, dataSyncEnabled: initialDataSyncEnabledFlag,
335                 dataStores: CompositeState.DataStores.builder()
336                     .operationalDataStore(CompositeState.Operational.builder()
337                         .dataStoreSyncState(initialDataSyncState)
338                         .build()).build())
339         and: 'get cm handle state returns the composite state for the given cm handle id'
340             mockInventoryPersistence.getCmHandleState('some-cm-handle-id') >> compositeState
341         when: 'set data sync enabled is called with the data sync enabled flag set to #dataSyncEnabledFlag'
342             objectUnderTest.setDataSyncEnabled('some-cm-handle-id', dataSyncEnabledFlag)
343         then: 'the data sync enabled flag is set to #dataSyncEnabled'
344             compositeState.dataSyncEnabled == dataSyncEnabledFlag
345         and: 'the data store sync state is set to #expectedDataStoreSyncState'
346             compositeState.dataStores.operationalDataStore.dataStoreSyncState == expectedDataStoreSyncState
347         and: 'the cps data service to delete data nodes is invoked the expected number of times'
348             deleteDataNodeExpectedNumberOfInvocation * mockCpsDataService.deleteDataNode(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'some-cm-handle-id', '/netconf-state', _)
349         and: 'the inventory persistence service to update node leaves is called with the correct values'
350             saveCmHandleStateExpectedNumberOfInvocations * mockInventoryPersistence.saveCmHandleState('some-cm-handle-id', compositeState)
351         where: 'the following data sync enabled flag is used'
352             scenario                                              | dataSyncEnabledFlag | initialDataSyncEnabledFlag | initialDataSyncState               || expectedDataStoreSyncState         | deleteDataNodeExpectedNumberOfInvocation | saveCmHandleStateExpectedNumberOfInvocations
353             'enabled'                                             | true                | false                      | DataStoreSyncState.NONE_REQUESTED  || DataStoreSyncState.UNSYNCHRONIZED  | 0                                        | 1
354             'disabled'                                            | false               | true                       | DataStoreSyncState.UNSYNCHRONIZED  || DataStoreSyncState.NONE_REQUESTED  | 0                                        | 1
355             'disabled where sync-state is currently SYNCHRONIZED' | false               | true                       | DataStoreSyncState.SYNCHRONIZED    || DataStoreSyncState.NONE_REQUESTED  | 1                                        | 1
356             'is set to existing flag state'                       | true                | true                       | DataStoreSyncState.UNSYNCHRONIZED  || DataStoreSyncState.UNSYNCHRONIZED  | 0                                        | 0
357     }
358
359     def 'Set cm Handle Data Sync Enabled flag with following cm handle not in ready state exception' () {
360         given: 'a cm handle composite state'
361             def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED, dataSyncEnabled: false)
362         and: 'get cm handle state returns the composite state for the given cm handle id'
363             mockInventoryPersistence.getCmHandleState('some-cm-handle-id') >> compositeState
364         when: 'set data sync enabled is called with the data sync enabled flag set to true'
365             objectUnderTest.setDataSyncEnabled('some-cm-handle-id', true)
366         then: 'the expected exception is thrown'
367             thrown(CpsException)
368         and: 'the inventory persistence service to update node leaves is not invoked'
369             0 * mockInventoryPersistence.saveCmHandleState(_, _)
370     }
371
372     def 'Get all cm handle IDs by DMI plugin identifier.' () {
373         given: 'cm handle queries service returns cm handles'
374             1 * mockCmHandleQueries.getCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier') >> ['cm-handle-1','cm-handle-2']
375         when: 'cm handle Ids are requested with dmi plugin identifier'
376             def result = objectUnderTest.getAllCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier')
377         then: 'the result size is correct'
378             assert result.size() == 2
379         and: 'the result returns the correct details'
380             assert result.containsAll('cm-handle-1','cm-handle-2')
381     }
382
383     def dataStores() {
384         CompositeState.DataStores.builder()
385             .operationalDataStore(CompositeState.Operational.builder()
386                 .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED)
387                 .lastSyncTime('some-timestamp').build()).build()
388     }
389
390     def mockDataNode() {
391         mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
392     }
393
394     def getDataOperationRequest(datastore) {
395         def dataOperationRequest = new DataOperationRequest()
396         def dataOperationDefinitions = new ArrayList()
397         dataOperationDefinitions.add(getDataOperationDefinition(datastore))
398         dataOperationRequest.setDataOperationDefinitions(dataOperationDefinitions)
399         return dataOperationRequest
400     }
401
402     def getDataOperationDefinition(datastore) {
403         def dataOperationDefinition = new DataOperationDefinition()
404         dataOperationDefinition.setOperation("read")
405         dataOperationDefinition.setOperationId("operational-12")
406         dataOperationDefinition.setDatastore(datastore)
407         def targetIds = new ArrayList()
408         targetIds.add("some-cm-handle")
409         dataOperationDefinition.setCmHandleIds(targetIds)
410         return dataOperationDefinition
411     }
412 }