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