2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2022-2024 Nordix Foundation
4 * Modifications Copyright (C) 2022 Bell Canada
5 * Modifications Copyright (C) 2024 TechMahindra Ltd.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * SPDX-License-Identifier: Apache-2.0
20 * ============LICENSE_END=========================================================
23 package org.onap.cps.ncmp.impl.inventory
25 import com.fasterxml.jackson.databind.ObjectMapper
26 import org.onap.cps.api.CpsAnchorService
27 import org.onap.cps.api.CpsDataService
28 import org.onap.cps.api.CpsModuleService
29 import org.onap.cps.impl.utils.CpsValidator
30 import org.onap.cps.ncmp.api.exceptions.CmHandleNotFoundException
31 import org.onap.cps.ncmp.api.inventory.models.CompositeState
32 import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
33 import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
34 import org.onap.cps.ncmp.impl.utils.YangDataConverter
35 import org.onap.cps.api.parameters.CascadeDeleteAllowed
36 import org.onap.cps.api.parameters.FetchDescendantsOption
37 import org.onap.cps.api.model.DataNode
38 import org.onap.cps.api.model.ModuleDefinition
39 import org.onap.cps.api.model.ModuleReference
40 import org.onap.cps.utils.ContentType
41 import org.onap.cps.utils.JsonObjectMapper
42 import spock.lang.Shared
43 import spock.lang.Specification
45 import java.time.OffsetDateTime
46 import java.time.ZoneOffset
47 import java.time.format.DateTimeFormatter
49 import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
50 import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
51 import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
52 import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
53 import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NO_TIMESTAMP
54 import static org.onap.cps.api.parameters.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
55 import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
57 class InventoryPersistenceImplSpec extends Specification {
59 def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
61 def mockCpsDataService = Mock(CpsDataService)
63 def mockCpsModuleService = Mock(CpsModuleService)
65 def mockCpsAnchorService = Mock(CpsAnchorService)
67 def mockCpsValidator = Mock(CpsValidator)
69 def mockCmHandleQueries = Mock(CmHandleQueryService)
71 def mockYangDataConverter = Mock(YangDataConverter)
73 def objectUnderTest = new InventoryPersistenceImpl(spiedJsonObjectMapper, mockCpsDataService, mockCpsModuleService,
74 mockCpsValidator, mockCpsAnchorService, mockCmHandleQueries)
76 def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
77 .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC))
79 def cmHandleId = 'some-cm-handle'
80 def alternateId = 'some-alternate-id'
81 def leaves = ["id":cmHandleId, "alternateId":alternateId,"dmi-service-name":"common service name","dmi-data-service-name":"data service name","dmi-model-service-name":"model service name"]
82 def xpath = "/dmi-registry/cm-handles[@id='some-cm-handle']"
84 def cmHandleId2 = 'another-cm-handle'
85 def alternateId2 = 'another-alternate-id'
86 def xpath2 = "/dmi-registry/cm-handles[@id='another-cm-handle']"
88 def dataNode = new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/additional-properties[@name='name1']", leaves: ["name":"name1", "value":"value1"])
91 def childDataNodesForCmHandleWithAllProperties = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/additional-properties[@name='name1']", leaves: ["name":"name1", "value":"value1"]),
92 new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/public-properties[@name='name2']", leaves: ["name":"name2","value":"value2"])]
95 def childDataNodesForCmHandleWithDMIProperties = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='some-cm-handle']/additional-properties[@name='name1']", leaves: ["name":"name1", "value":"value1"])]
98 def childDataNodesForCmHandleWithPublicProperties = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='some-cm-handle']/public-properties[@name='name2']", leaves: ["name":"name2","value":"value2"])]
101 def childDataNodesForCmHandleWithState = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='some-cm-handle']/state", leaves: ['cm-handle-state': 'ADVISED'])]
103 def "Retrieve CmHandle using datanode with #scenario."() {
104 given: 'the cps data service returns a data node from the DMI registry'
105 def dataNode = new DataNode(childDataNodes:childDataNodes, leaves: leaves)
106 mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode]
107 when: 'retrieving the yang modelled cm handle'
108 def result = objectUnderTest.getYangModelCmHandle(cmHandleId)
109 then: 'the result has the correct id and service names'
110 result.id == cmHandleId
111 result.dmiServiceName == 'common service name'
112 result.dmiDataServiceName == 'data service name'
113 result.dmiModelServiceName == 'model service name'
114 and: 'the expected DMI properties'
115 result.dmiProperties == expectedDmiProperties
116 result.publicProperties == expectedPublicProperties
117 and: 'the state details are returned'
118 result.compositeState.cmHandleState == expectedCompositeState
119 and: 'the CM Handle ID is validated'
120 1 * mockCpsValidator.validateNameCharacters(cmHandleId)
121 where: 'the following parameters are used'
122 scenario | childDataNodes || expectedDmiProperties || expectedPublicProperties || expectedCompositeState
123 'no properties' | [] || [] || [] || null
124 'DMI and public properties' | childDataNodesForCmHandleWithAllProperties || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")] || null
125 'just DMI properties' | childDataNodesForCmHandleWithDMIProperties || [new YangModelCmHandle.Property("name1", "value1")] || [] || null
126 'just public properties' | childDataNodesForCmHandleWithPublicProperties || [] || [new YangModelCmHandle.Property("name2", "value2")] || null
127 'with state details' | childDataNodesForCmHandleWithState || [] || [] || CmHandleState.ADVISED
130 def "Handling missing service names as null."() {
131 given: 'the cps data service returns a data node from the DMI registry with empty child and leaf attributes'
132 def dataNode = new DataNode(childDataNodes:[], leaves: ['id':cmHandleId])
133 mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode]
134 when: 'retrieving the yang modelled cm handle'
135 def result = objectUnderTest.getYangModelCmHandle(cmHandleId)
136 then: 'the service names are returned as null'
137 result.dmiServiceName == null
138 result.dmiDataServiceName == null
139 result.dmiModelServiceName == null
140 and: 'the CM Handle ID is validated'
141 1 * mockCpsValidator.validateNameCharacters(cmHandleId)
144 def "Retrieve multiple YangModelCmHandles using cm handle ids"() {
145 given: 'the cps data service returns 2 data nodes from the DMI registry'
146 def dataNodes = [new DataNode(xpath: xpath, leaves: ['id': cmHandleId]), new DataNode(xpath: xpath2, leaves: ['id': cmHandleId2])]
147 mockCpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, [xpath, xpath2] , INCLUDE_ALL_DESCENDANTS) >> dataNodes
148 when: 'retrieving the yang modelled cm handle'
149 def results = objectUnderTest.getYangModelCmHandles([cmHandleId, cmHandleId2])
150 then: 'verify both have returned and cmhandleIds are correct'
151 assert results.size() == 2
152 assert results.id.containsAll([cmHandleId, cmHandleId2])
155 def "Retrieve multiple YangModelCmHandles using cm handle references"() {
156 given: 'the cps data service returns 2 data nodes from the DMI registry'
157 def dataNodes = [new DataNode(xpath: xpath, leaves: ['id': cmHandleId, 'alternate-id':alternateId]), new DataNode(xpath: xpath2, leaves: ['id': cmHandleId2,'alternate-id':alternateId2])]
158 mockCmHandleQueries.queryNcmpRegistryByCpsPath(_, INCLUDE_ALL_DESCENDANTS) >> dataNodes
159 when: 'retrieving the yang modelled cm handle'
160 def results = objectUnderTest.getYangModelCmHandlesFromCmHandleReferences([cmHandleId, cmHandleId2])
161 then: 'verify both have returned and cmhandleIds are correct'
162 assert results.size() == 2
163 assert results.id.containsAll([cmHandleId, cmHandleId2])
166 def 'Get a Cm Handle Composite State'() {
167 given: 'a valid cm handle id'
168 def cmHandleId = 'Some-Cm-Handle'
169 def dataNode = new DataNode(leaves: ['cm-handle-state': 'ADVISED'])
170 and: 'cps data service returns a valid data node'
171 mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
172 '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']/state', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [dataNode]
173 when: 'get cm handle state is invoked'
174 def result = objectUnderTest.getCmHandleState(cmHandleId)
175 then: 'result has returned the correct cm handle state'
176 result.cmHandleState == CmHandleState.ADVISED
177 and: 'the CM Handle ID is validated'
178 1 * mockCpsValidator.validateNameCharacters(cmHandleId)
181 def 'Update Cm Handle with #scenario State'() {
182 given: 'a cm handle and a composite state'
183 def cmHandleId = 'Some-Cm-Handle'
184 def compositeState = new CompositeState(cmHandleState: cmHandleState, lastUpdateTime: formattedDateAndTime)
185 when: 'update cm handle state is invoked with the #scenario state'
186 objectUnderTest.saveCmHandleState(cmHandleId, compositeState)
187 then: 'update node leaves is invoked with the correct params'
188 1 * mockCpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']', expectedJsonData, _ as OffsetDateTime, ContentType.JSON)
189 where: 'the following states are used'
190 scenario | cmHandleState || expectedJsonData
191 'READY' | CmHandleState.READY || '{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}'
192 'LOCKED' | CmHandleState.LOCKED || '{"state":{"cm-handle-state":"LOCKED","last-update-time":"2022-12-31T20:30:40.000+0000"}}'
193 'DELETING' | CmHandleState.DELETING || '{"state":{"cm-handle-state":"DELETING","last-update-time":"2022-12-31T20:30:40.000+0000"}}'
196 def 'Update Cm Handles with #scenario States'() {
197 given: 'a map of cm handles composite states'
198 def compositeState1 = new CompositeState(cmHandleState: cmHandleState, lastUpdateTime: formattedDateAndTime)
199 def compositeState2 = new CompositeState(cmHandleState: cmHandleState, lastUpdateTime: formattedDateAndTime)
200 when: 'update cm handle state is invoked with the #scenario state'
201 def cmHandleStateMap = ['Some-Cm-Handle1' : compositeState1, 'Some-Cm-Handle2' : compositeState2]
202 objectUnderTest.saveCmHandleStateBatch(cmHandleStateMap)
203 then: 'update node leaves is invoked with the correct params'
204 1 * mockCpsDataService.updateDataNodesAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandlesJsonDataMap, _ as OffsetDateTime, ContentType.JSON)
205 where: 'the following states are used'
206 scenario | cmHandleState || cmHandlesJsonDataMap
207 'READY' | CmHandleState.READY || ['/dmi-registry/cm-handles[@id=\'Some-Cm-Handle1\']':'{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle2\']':'{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}']
208 'LOCKED' | CmHandleState.LOCKED || ['/dmi-registry/cm-handles[@id=\'Some-Cm-Handle1\']':'{"state":{"cm-handle-state":"LOCKED","last-update-time":"2022-12-31T20:30:40.000+0000"}}', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle2\']':'{"state":{"cm-handle-state":"LOCKED","last-update-time":"2022-12-31T20:30:40.000+0000"}}']
209 'DELETING' | CmHandleState.DELETING || ['/dmi-registry/cm-handles[@id=\'Some-Cm-Handle1\']':'{"state":{"cm-handle-state":"DELETING","last-update-time":"2022-12-31T20:30:40.000+0000"}}', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle2\']':'{"state":{"cm-handle-state":"DELETING","last-update-time":"2022-12-31T20:30:40.000+0000"}}']
212 def 'Getting module definitions by module'() {
213 given: 'cps module service returns module definition for module name'
214 def moduleDefinitions = [new ModuleDefinition('moduleName','revision','content')]
215 mockCpsModuleService.getModuleDefinitionsByAnchorAndModule(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id', 'some-module', '2024-01-25') >> moduleDefinitions
216 when: 'get module definitions is invoked with module name'
217 def result = objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cmHandle-Id', 'some-module', '2024-01-25')
218 then: 'returned result are the same module definitions as returned from module service'
219 assert result == moduleDefinitions
220 and: 'cm handle id and module name validated'
221 1 * mockCpsValidator.validateNameCharacters('some-cmHandle-Id', 'some-module')
224 def 'Getting module definitions with cm handle id'() {
225 given: 'cps module service returns module definitions for cm handle id'
226 def moduleDefinitions = [new ModuleDefinition('moduleName','revision','content')]
227 mockCpsModuleService.getModuleDefinitionsByAnchorName(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id') >> moduleDefinitions
228 when: 'get module definitions is invoked with cm handle id'
229 def result = objectUnderTest.getModuleDefinitionsByCmHandleId('some-cmHandle-Id')
230 then: 'the returned result are the same module definitions as returned from the module service'
231 assert result == moduleDefinitions
234 def 'Get module references'() {
235 given: 'cps module service returns a collection of module references'
236 def moduleReferences = [new ModuleReference('moduleName','revision','namespace')]
237 mockCpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id') >> moduleReferences
238 when: 'get yang resources module references by cmHandle is invoked'
239 def result = objectUnderTest.getYangResourcesModuleReferences('some-cmHandle-Id')
240 then: 'the returned result is a collection of module definitions'
241 assert result == moduleReferences
242 and: 'the CM Handle ID is validated'
243 1 * mockCpsValidator.validateNameCharacters('some-cmHandle-Id')
246 def 'Save Cmhandle'() {
247 given: 'cmHandle represented as Yang Model'
248 def yangModelCmHandle = new YangModelCmHandle(id: 'cmhandle', dmiProperties: [], publicProperties: [])
249 when: 'the method to save cmhandle is called'
250 objectUnderTest.saveCmHandle(yangModelCmHandle)
251 then: 'the data service method to save list elements is called once'
252 1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
253 _,null, ContentType.JSON) >> {
255 assert args[3].startsWith('{"cm-handles":[{"id":"cmhandle","additional-properties":[],"public-properties":[]}]}')
260 def 'Save Multiple Cmhandles'() {
261 given: 'cm handles represented as Yang Model'
262 def yangModelCmHandle1 = new YangModelCmHandle(id: 'cmhandle1')
263 def yangModelCmHandle2 = new YangModelCmHandle(id: 'cmhandle2')
264 when: 'the cm handles are saved'
265 objectUnderTest.saveCmHandleBatch([yangModelCmHandle1, yangModelCmHandle2])
266 then: 'CPS Data Service persists both cm handles as a batch'
267 1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
268 NCMP_DMI_REGISTRY_PARENT, _,null, ContentType.JSON) >> {
270 def jsonData = (args[3] as String)
271 jsonData.contains('cmhandle1')
272 jsonData.contains('cmhandle2')
277 def 'Delete list or list elements'() {
278 when: 'the method to delete list or list elements is called'
279 objectUnderTest.deleteListOrListElement('sample xPath')
280 then: 'the data service method to save list elements is called once'
281 1 * mockCpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,'sample xPath',null)
284 def 'Delete schema set with a valid schema set name'() {
285 when: 'the method to delete schema set is called with valid schema set name'
286 objectUnderTest.deleteSchemaSetWithCascade('validSchemaSetName')
287 then: 'the module service to delete schemaSet is invoked once'
288 1 * mockCpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'validSchemaSetName', CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED)
289 and: 'the schema set name is validated'
290 1 * mockCpsValidator.validateNameCharacters('validSchemaSetName')
293 def 'Delete multiple schema sets with valid schema set names'() {
294 when: 'the method to delete schema sets is called with valid schema set names'
295 objectUnderTest.deleteSchemaSetsWithCascade(['validSchemaSetName1', 'validSchemaSetName2'])
296 then: 'the module service to delete schema sets is invoked once'
297 1 * mockCpsModuleService.deleteSchemaSetsWithCascade(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, ['validSchemaSetName1', 'validSchemaSetName2'])
298 and: 'the schema set names are validated'
299 1 * mockCpsValidator.validateNameCharacters(['validSchemaSetName1', 'validSchemaSetName2'])
302 def 'Get data node via xPath'() {
303 when: 'the method to get data nodes is called'
304 objectUnderTest.getDataNode('sample xPath')
305 then: 'the data persistence service method to get data node is invoked once'
306 1 * mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,'sample xPath', INCLUDE_ALL_DESCENDANTS)
309 def 'Get cmHandle data node'() {
310 given: 'expected xPath to get cmHandle data node'
311 def expectedXPath = '/dmi-registry/cm-handles[@id=\'sample cmHandleId\']'
312 when: 'the method to get data nodes is called'
313 objectUnderTest.getCmHandleDataNodeByCmHandleId('sample cmHandleId')
314 then: 'the data persistence service method to get cmHandle data node is invoked once with expected xPath'
315 1 * mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, expectedXPath, INCLUDE_ALL_DESCENDANTS)
318 def 'Get yang model cm handle by alternate id'() {
319 given: 'expected xPath to get cmHandle data node'
320 def expectedXPath = '/dmi-registry/cm-handles[@alternate-id=\'alternate id\']'
321 def expectedDataNode = new DataNode(xpath: expectedXPath, leaves: [id: 'id', alternateId: 'alternate id'])
322 and: 'query service is invoked with expected xpath'
323 mockCmHandleQueries.queryNcmpRegistryByCpsPath(expectedXPath, OMIT_DESCENDANTS) >> [expectedDataNode]
324 mockYangDataConverter.toYangModelCmHandle(expectedDataNode) >> new YangModelCmHandle(id: 'id')
325 expect: 'getting the yang model cm handle'
326 assert objectUnderTest.getYangModelCmHandleByAlternateId('alternate id') == new YangModelCmHandle(id: 'id')
329 def 'Attempt to get non existing yang model cm handle by alternate id'() {
330 given: 'query service is invoked and returns empty collection of data nodes'
331 mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> []
332 when: 'getting the yang model cm handle'
333 objectUnderTest.getYangModelCmHandleByAlternateId('alternate id')
334 then: 'no data found exception thrown'
335 def thrownException = thrown(CmHandleNotFoundException)
336 assert thrownException.getMessage().contains('Cm handle not found')
337 assert thrownException.getDetails().contains('No cm handles found with reference alternate id')
340 def 'Get multiple yang model cm handles by alternate ids, passing empty collection'() {
341 when: 'getting the yang model cm handle for no alternate ids'
342 objectUnderTest.getYangModelCmHandleByAlternateIds([])
343 then: 'query service is not invoked'
344 0 * mockCmHandleQueries.queryNcmpRegistryByCpsPath(_, _)
347 def 'Get CM handle ids for CM Handles that has given module names'() {
348 when: 'the method to get cm handles is called'
349 objectUnderTest.getCmHandleReferencesWithGivenModules(['sample-module-name'], false)
350 then: 'the admin persistence service method to query anchors is invoked once with the same parameter'
351 1 * mockCpsAnchorService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, ['sample-module-name'])
354 def 'Get Alternate Ids for CM Handles that has given module names'() {
355 given: 'A Collection of data nodes'
356 def dataNodes = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='ch-1']", leaves: ['id': 'ch-1', 'alternate-id': 'alt-1'])]
357 when: 'the methods to get dataNodes is called and returns correct values'
358 mockCpsAnchorService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, ['sample-module-name']) >> ['ch-1']
359 mockCpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, ["/dmi-registry/cm-handles[@id='ch-1']"], INCLUDE_ALL_DESCENDANTS) >> dataNodes
360 and: 'the method returns a result'
361 def result = objectUnderTest.getCmHandleReferencesWithGivenModules(['sample-module-name'], true)
362 then: 'the result contains the correct alternate Id'
363 assert result == ['alt-1'] as HashSet
366 def 'Replace list content'() {
367 when: 'replace list content method is called with xpath and data nodes collection'
368 objectUnderTest.replaceListContent('sample xpath', [new DataNode()])
369 then: 'the cps data service method to replace list content is invoked once with same parameters'
370 1 * mockCpsDataService.replaceListContent(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,'sample xpath', [new DataNode()], NO_TIMESTAMP);
373 def 'Delete data node via xPath'() {
374 when: 'Delete data node method is called with xpath as parameter'
375 objectUnderTest.deleteDataNode('sample dataNode xpath')
376 then: 'the cps data service method to delete data node is invoked once with the same xPath'
377 1 * mockCpsDataService.deleteDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, 'sample dataNode xpath', NO_TIMESTAMP);
380 def 'Delete multiple data nodes via xPath'() {
381 when: 'Delete data nodes method is called with multiple xpaths as parameters'
382 objectUnderTest.deleteDataNodes(['xpath1', 'xpath2'])
383 then: 'the cps data service method to delete data nodes is invoked once with the same xPaths'
384 1 * mockCpsDataService.deleteDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, ['xpath1', 'xpath2'], NO_TIMESTAMP);
387 def 'Check if cm handle exists for a given cm handle id'() {
388 given: 'data service returns a datanode with correct cm handle id'
389 mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode]
390 expect: 'cm handle exists for given cm handle id'
391 assert true == objectUnderTest.isExistingCmHandleId('some-cm-handle')