diff options
author | 2022-01-28 16:33:56 +0530 | |
---|---|---|
committer | 2022-02-16 13:31:29 +0000 | |
commit | a15c0e5b58f16c3ab4a7c7610ac8c4a191e5e051 (patch) | |
tree | e71d9c9f2c4570e645c96a69212146276792e49d /cps-ncmp-service/src/test/groovy | |
parent | 4e1d5e0a179857bfe14296ae1153b2c1173278c8 (diff) |
Core logic to update,add or remove cmHandle properties
Issue-ID: CPS-837
Change-Id: Ia078b6a0291ae916931259a309dd592b0554da28
Signed-off-by: mpriyank <priyank.maheshwari@est.tech>
Diffstat (limited to 'cps-ncmp-service/src/test/groovy')
4 files changed, 172 insertions, 18 deletions
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy index 67108a5fe..3af4fc00e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy @@ -32,14 +32,16 @@ import spock.lang.Specification class NetworkCmProxyDataServiceImplModelSyncSpec extends Specification { + def nullCpsDataService = null def mockJsonObjectMapper = Mock(JsonObjectMapper) def mockCpsModuleService = Mock(CpsModuleService) def mockCpsAdminService = Mock(CpsAdminService) def mockDmiModelOperations = Mock(DmiModelOperations) def mockDmiDataOperations = Mock(DmiDataOperations) + def nullNetworkCmProxyDataServicePropertyHandler = null - def objectUnderTest = new NetworkCmProxyDataServiceImpl(null, mockJsonObjectMapper, mockDmiDataOperations, mockDmiModelOperations, - mockCpsModuleService, mockCpsAdminService) + def objectUnderTest = new NetworkCmProxyDataServiceImpl(nullCpsDataService, mockJsonObjectMapper, mockDmiDataOperations, mockDmiModelOperations, + mockCpsModuleService, mockCpsAdminService, nullNetworkCmProxyDataServicePropertyHandler) def expectedDataspaceName = 'NFP-Operational' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy index 9f1203d64..00fda149f 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy @@ -26,7 +26,6 @@ import org.onap.cps.api.CpsAdminService import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsModuleService import org.onap.cps.ncmp.api.impl.exception.DmiRequestException -import org.onap.cps.ncmp.api.impl.exception.NcmpException import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations import org.onap.cps.ncmp.api.models.CmHandle @@ -53,16 +52,17 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def mockCpsAdminService = Mock(CpsAdminService) def mockDmiModelOperations = Mock(DmiModelOperations) def mockDmiDataOperations = Mock(DmiDataOperations) + def mockNetworkCmProxyDataServicePropertyHandler = Mock(NetworkCmProxyDataServicePropertyHandler) def noTimestamp = null def 'Register or re-register a DMI Plugin for the given cm-handle(s) with #scenario process.'() { given: 'a registration' def objectUnderTest = getObjectUnderTestWithModelSyncDisabled() - def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'my-server') + def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server') persistenceCmHandle.cmHandleID = '123' persistenceCmHandle.dmiProperties = [dmiProp1: 'dmiValue1', dmiProp2: 'dmiValue2'] - persistenceCmHandle.publicProperties = [publicProp1: 'publicValue1', publicProp2: 'publicValue2' ] + persistenceCmHandle.publicProperties = [publicProp1: 'publicValue1', publicProp2: 'publicValue2'] dmiPluginRegistration.createdCmHandles = createdCmHandles dmiPluginRegistration.updatedCmHandles = updatedCmHandles dmiPluginRegistration.removedCmHandles = removedCmHandles @@ -74,22 +74,21 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) then: 'save list elements is invoked with the expected parameters' expectedCallsToSaveNode * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry', - '/dmi-registry', expectedJsonData, noTimestamp) - and: 'update node and child data nodes is invoked with correct parameters' - expectedCallsToUpdateNode * mockCpsDataService.updateNodeLeavesAndExistingDescendantLeaves('NCMP-Admin', - 'ncmp-dmi-registry', '/dmi-registry', expectedJsonData, noTimestamp) + '/dmi-registry', expectedJsonData, noTimestamp) + and: 'update data node leaves is called with correct parameters' + expectedCallsToPropertyHandler * mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(updatedCmHandles) and: 'delete schema set is invoked with the correct parameters' expectedCallsToDeleteSchemaSetAndListElement * mockCpsModuleService.deleteSchemaSet('NFP-Operational', 'cmHandle001', CASCADE_DELETE_ALLOWED) and: 'delete list or list element is invoked with the correct parameters' expectedCallsToDeleteSchemaSetAndListElement * mockCpsDataService.deleteListOrListElement('NCMP-Admin', - 'ncmp-dmi-registry', "/dmi-registry/cm-handles[@id='cmHandle001']", noTimestamp) + 'ncmp-dmi-registry', "/dmi-registry/cm-handles[@id='cmHandle001']", noTimestamp) where: - scenario | createdCmHandles | updatedCmHandles | removedCmHandles || expectedCallsToSaveNode | expectedCallsToUpdateNode | expectedCallsToDeleteSchemaSetAndListElement - 'create' | [persistenceCmHandle] | [] | [] || 1 | 0 | 0 - 'update' | [] | [persistenceCmHandle] | [] || 0 | 1 | 0 - 'delete' | [] | [] | cmHandlesArray || 0 | 0 | 1 - 'create, update and delete' | [persistenceCmHandle] | [persistenceCmHandle] | cmHandlesArray || 1 | 1 | 1 - 'no valid data' | null | null | null || 0 | 0 | 0 + scenario | createdCmHandles | updatedCmHandles | removedCmHandles || expectedCallsToSaveNode | expectedCallsToDeleteSchemaSetAndListElement | expectedCallsToPropertyHandler + 'create' | [persistenceCmHandle] | [] | [] || 1 | 0 | 1 + 'update' | [] | [persistenceCmHandle] | [] || 0 | 0 | 1 + 'delete' | [] | [] | cmHandlesArray || 0 | 1 | 1 + 'create, update and delete' | [persistenceCmHandle] | [persistenceCmHandle] | cmHandlesArray || 1 | 1 | 1 + 'no valid data' | null | null | null || 0 | 0 | 0 } def 'Register a DMI Plugin for the given cm-handle(s) without DMI properties.'() { @@ -194,9 +193,25 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { 'only data DMI plugin' | '' | '' | 'service1' || 'Cannot register just a Data or Model plugin service name' } + def 'Exception thrown on CM-Handle registration update request'() { + given: 'a CM-handle registration' + def objectUnderTest = getObjectUnderTestWithModelSyncDisabled() + and: 'dmi plugin registration input update request' + def dmiPluginReg = new DmiPluginRegistration(); + dmiPluginReg.dmiPlugin = 'onap.dmap.plugin'; + dmiPluginReg.updatedCmHandles = [new CmHandle(cmHandleID: 'unknownHandle')] + and: 'update data node leaves is unable to find data node' + mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_) >> { throw new DataNodeNotFoundException('NCMP-Admin', 'ncmp-dmi-registry') } + when: 'update dmi registration is called' + objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginReg) + then: 'data validation exception is thrown' + def exceptionThrown = thrown(DataValidationException.class) + assert exceptionThrown.getDetails().contains('DataNode not found') + } + def getObjectUnderTestWithModelSyncDisabled() { def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations, mockDmiModelOperations, - mockCpsModuleService, mockCpsAdminService)) + mockCpsModuleService, mockCpsAdminService, mockNetworkCmProxyDataServicePropertyHandler)) objectUnderTest.syncModulesAndCreateAnchor(*_) >> null return objectUnderTest } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy index 9c79d4fcf..6d7bdefb8 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy @@ -51,9 +51,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) def mockDmiModelOperations = Mock(DmiModelOperations) def mockDmiDataOperations = Mock(DmiDataOperations) + def nullNetworkCmProxyDataServicePropertyHandler = null def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations, mockDmiModelOperations, - mockCpsModuleService, mockCpsAdminService) + mockCpsModuleService, mockCpsAdminService, nullNetworkCmProxyDataServicePropertyHandler) def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']" diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy new file mode 100644 index 000000000..5bdb744b2 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy @@ -0,0 +1,136 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl + +import org.onap.cps.api.CpsDataService +import org.onap.cps.ncmp.api.models.CmHandle +import org.onap.cps.spi.FetchDescendantsOption +import org.onap.cps.spi.exceptions.DataNodeNotFoundException +import org.onap.cps.spi.exceptions.DataValidationException +import org.onap.cps.spi.model.DataNode +import org.onap.cps.spi.model.DataNodeBuilder +import spock.lang.Specification + +class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { + + def mockCpsDataService = Mock(CpsDataService) + + def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockCpsDataService) + def dataspaceName = 'NCMP-Admin' + def anchorName = 'ncmp-dmi-registry' + def static cmHandleId = 'myHandle1' + def static cmHandleXpath = "/dmi-registry/cm-handles[@id='${cmHandleId}']" + def noTimeStamp = null + + def static propertyDataNodes = [new DataNodeBuilder().withXpath("/dmi-registry/cm-handles[@id='${cmHandleId}']/additional-properties[@name='additionalProp1']").withLeaves(['name': 'additionalProp1', 'value': 'additionalValue1']).build(), + new DataNodeBuilder().withXpath("/dmi-registry/cm-handles[@id='${cmHandleId}']/additional-properties[@name='additionalProp2']").withLeaves(['name': 'additionalProp2', 'value': 'additionalValue2']).build(), + new DataNodeBuilder().withXpath("/dmi-registry/cm-handles[@id='${cmHandleId}']/public-properties[@name='publicProp3']").withLeaves(['name': 'publicProp3', 'value': 'publicValue3']).build(), + new DataNodeBuilder().withXpath("/dmi-registry/cm-handles[@id='${cmHandleId}']/public-properties[@name='publicProp4']").withLeaves(['name': 'publicProp4', 'value': 'publicValue4']).build()] + def static cmHandleDataNode = new DataNode(xpath: cmHandleXpath, childDataNodes: propertyDataNodes) + + def 'Update CM Handle Public Properties: #scenario'() { + given: 'the CPS service return a CM handle' + mockCpsDataService.getDataNode(dataspaceName, anchorName, cmHandleXpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode + and: 'an update cm handle request with public properties updates' + def cmHandleUpdateRequest = [new CmHandle(cmHandleID: cmHandleId, publicProperties: updatedPublicProperties)] + when: 'update data node leaves is called with the update request' + objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) + then: 'the replace list method is called with correct params' + 1 * mockCpsDataService.replaceListContent(dataspaceName, anchorName, cmHandleXpath, _, noTimeStamp) >> { args -> + { + assert args[3].leaves.size() == expectedPropertiesAfterUpdate.size() + assert args[3].leaves.containsAll(convertToProperties(expectedPropertiesAfterUpdate)) + } + } + where: 'following public properties updates are made' + scenario | updatedPublicProperties || expectedPropertiesAfterUpdate + 'property added' | ['newPubProp1': 'pub-val'] || [['publicProp3': 'publicValue3'], ['publicProp4': 'publicValue4'], ['newPubProp1': 'pub-val']] + 'property updated' | ['publicProp4': 'newPubVal'] || [['publicProp3': 'publicValue3'], ['publicProp4': 'newPubVal']] + 'property removed' | ['publicProp4': null] || [['publicProp3': 'publicValue3']] + 'property ignored(value is null)' | ['pub-prop': null] || [['publicProp3': 'publicValue3'], ['publicProp4': 'publicValue4']] + } + + def 'Update DMI Properties: #scenario'() { + given: 'the CPS service return a CM handle' + mockCpsDataService.getDataNode(dataspaceName, anchorName, cmHandleXpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode + and: 'an update cm handle request with DMI properties updates' + def cmHandleUpdateRequest = [new CmHandle(cmHandleID: cmHandleId, dmiProperties: updatedDmiProperties)] + when: 'update data node leaves is called with the update request' + objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) + then: 'replace list method should is called with correct params' + expectedCallsToReplaceMethod * mockCpsDataService.replaceListContent(dataspaceName, anchorName, cmHandleXpath, _, noTimeStamp) >> { args -> + { + assert args[3].leaves.size() == expectedPropertiesAfterUpdate.size() + assert args[3].leaves.containsAll(convertToProperties(expectedPropertiesAfterUpdate)) + } + } + where: 'following DMI properties updates are made' + scenario | updatedDmiProperties || expectedPropertiesAfterUpdate | expectedCallsToReplaceMethod + 'property added' | ['newAdditionalProp1': 'add-value'] || [['additionalProp1': 'additionalValue1'], ['additionalProp2': 'additionalValue2'], ['newAdditionalProp1': 'add-value']] | 1 + 'property updated' | ['additionalProp1': 'newValue'] || [['additionalProp2': 'additionalValue2'], ['additionalProp1': 'newValue']] | 1 + 'property removed' | ['additionalProp1': null] || [['additionalProp2': 'additionalValue2']] | 1 + 'property ignored(value is null)' | ['new-prop': null] || [['additionalProp1': 'additionalValue1'], ['additionalProp2': 'additionalValue2']] | 1 + 'no property changes' | [:] || [['additionalProp1': 'additionalValue1'], ['additionalProp2': 'additionalValue2']] | 0 + } + + def 'Update CM Handle Properties, remove all properties: #scenario'() { + given: 'the CPS service return a CM handle' + def cmHandleDataNode = new DataNode(xpath: cmHandleXpath, childDataNodes: originalPropertyDataNodes) + mockCpsDataService.getDataNode(dataspaceName, anchorName, cmHandleXpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode + and: 'an update cm handle request that removes all public properties(existing and non-existing)' + def cmHandleUpdateRequest = [new CmHandle(cmHandleID: cmHandleId, publicProperties: ['publicProp3': null, 'publicProp4': null])] + when: 'update data node leaves is called with the update request' + objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) + then: 'the replace list method is not called' + 0 * mockCpsDataService.replaceListContent(*_) + then: 'delete data node will be called for any existing property' + expectedCallsToDeleteDataNode * mockCpsDataService.deleteDataNode(dataspaceName, anchorName, _, noTimeStamp) >> { arg -> + { + assert arg[2].contains("@name='publicProp") + } + } + where: 'following public properties updates are made' + scenario | originalPropertyDataNodes || expectedCallsToDeleteDataNode + '2 original properties, both removed' | propertyDataNodes || 2 + 'no original properties' | [] || 0 + } + + def 'Exception thrown when we try to update cmHandle'() { + given: 'cm handles request' + def cmHandleUpdateRequest = [new CmHandle(cmHandleID: cmHandleId, publicProperties: [:], dmiProperties: [:])] + and: 'data node cannot be found' + mockCpsDataService.getDataNode(*_) >> { throw new DataNodeNotFoundException(dataspaceName, anchorName, cmHandleXpath) } + when: 'update data node leaves is called using correct parameters' + objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) + then: 'data validation exception is thrown' + def exceptionThrown = thrown(DataValidationException.class) + assert exceptionThrown.getMessage().contains('DataNode not found') + } + + def convertToProperties(expectedPropertiesAfterUpdateAsMap) { + def properties = [].withDefault { [:] } + expectedPropertiesAfterUpdateAsMap.forEach(property -> + property.forEach((key, val) -> { + properties.add(['name': key, 'value': val]) + })) + return properties + } +} |