diff options
author | 2024-02-12 11:41:00 +0000 | |
---|---|---|
committer | 2024-02-16 10:10:27 +0000 | |
commit | 9b86bf1fda03ec67b25077cbc208020948c4d042 (patch) | |
tree | 360f9916c5dc80b62e88042e27452b4906816c21 /cps-ncmp-service/src/test/groovy | |
parent | cc8fbf61b3fd0c6828caaa2cb784daacc346c56e (diff) |
Use DB for checking Alternate IDs
- do NOT use hazelcast cache
- introduced AlternateIcChecker
- use checks during Inital registration
- TODO: remvoe Hazalcast Cache (once perf test are OK)
- TODO: use checks during UPDATE registration
- TODO: error reporting during registration
Issue-Id: CPS-2049
Change-Id: I0adcac52a7a49e26301758eafc4684152ddfcaf5
Signed-off-by: halil.cakal <halil.cakal@est.tech>
Diffstat (limited to 'cps-ncmp-service/src/test/groovy')
6 files changed, 174 insertions, 178 deletions
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 c7ac8ab8b..572adb8f0 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 @@ -21,6 +21,8 @@ package org.onap.cps.ncmp.api.impl +import java.util.stream.Collectors + import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST @@ -28,7 +30,7 @@ import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager -import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper +import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker import org.onap.cps.ncmp.api.models.UpgradedCmHandles import com.fasterxml.jackson.databind.ObjectMapper import com.hazelcast.map.IMap @@ -68,10 +70,16 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def mockModuleSyncStartedOnCmHandles = Mock(IMap<String, Object>) def trustLevelPerDmiPlugin = [:] def mockTrustLevelManager = Mock(TrustLevelManager) - def mockCmHandleIdMapper = Mock(CmHandleIdMapper) + def mockAlternateIdChecker = Mock(AlternateIdChecker) def objectUnderTest = getObjectUnderTest() def mockModuleSetTagCache = [:] + def setup() { + // always accept all cm handles + mockAlternateIdChecker.getIdsOfCmHandlesWithAcceptableAlternateId(_) >> + { args -> args[0].stream().map(it -> it.cmHandleId).collect(Collectors.toList()) } + } + def 'DMI Registration: Create, Update, Delete & Upgrade operations are processed in the right order'() { given: 'a registration with operations of all types' def dmiRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server') @@ -160,7 +168,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { when: 'update registration and sync module is called with correct DMI plugin information' objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) then: 'create cm handles registration and sync modules is called with the correct plugin information' - 1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration) + 1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration, _) and: 'dmi is added to the dmi trustLevel map' assert trustLevelPerDmiPlugin.size() == 1 assert trustLevelPerDmiPlugin.containsKey(expectedDmiPluginRegisteredName) @@ -433,19 +441,19 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def 'Adding data to alternate id caches.'() { given: 'a registration with three CM Handles to be created' - def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', - createdCmHandles: [new NcmpServiceCmHandle(cmHandleId: 'cmhandle1', alternateId: 'my-alternate-id-1')]) + def ncmpServiceCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'cmhandle1', alternateId: 'my-alternate-id-1')] + def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', createdCmHandles: ncmpServiceCmHandles) when: 'the DMI plugin registration happens' objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) then: 'the new alternate id is added to the cache' - 1 * mockCmHandleIdMapper.addMapping('cmhandle1', 'my-alternate-id-1') + 1 * mockAlternateIdChecker.getIdsOfCmHandlesWithAcceptableAlternateId(ncmpServiceCmHandles) >> ['cmhandle1'] } def getObjectUnderTest() { return Spy(new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations, mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCmHandleQueries, stubbedNetworkCmProxyCmHandlerQueryService, mockLcmEventsCmHandleStateHandler, mockCpsDataService, - mockModuleSyncStartedOnCmHandles, trustLevelPerDmiPlugin, mockTrustLevelManager, mockCmHandleIdMapper, mockModuleSetTagCache)) + mockModuleSyncStartedOnCmHandles, trustLevelPerDmiPlugin, mockTrustLevelManager, mockAlternateIdChecker, mockModuleSetTagCache)) } def addPersistedYangModelCmHandles(ids) { 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 c835056f3..64bedb8ad 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 @@ -32,7 +32,7 @@ import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RU import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE -import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper +import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker import com.hazelcast.map.IMap import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler @@ -54,7 +54,7 @@ import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle import org.onap.cps.ncmp.api.models.DataOperationRequest import org.onap.cps.spi.exceptions.CpsException import org.onap.cps.spi.model.ConditionProperties -import spock.lang.Shared + import java.util.stream.Collectors import org.onap.cps.utils.JsonObjectMapper import com.fasterxml.jackson.databind.ObjectMapper @@ -80,14 +80,12 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def stubModuleSyncStartedOnCmHandles = Stub(IMap<String, Object>) def stubTrustLevelPerDmiPlugin = Stub(Map<String, TrustLevel>) def mockTrustLevelManager = Mock(TrustLevelManager) - def mockCmHandleIdMapper = Mock(CmHandleIdMapper) + def mockAlternateIdChecker = Mock(AlternateIdChecker) def mockModuleSetTagCache = [:] def NO_TOPIC = null def NO_REQUEST_ID = null - @Shared def OPTIONS_PARAM = '(a=1,b=2)' - @Shared def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'test-cm-handle-id') def objectUnderTest = new NetworkCmProxyDataServiceImpl( @@ -102,7 +100,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { stubModuleSyncStartedOnCmHandles, stubTrustLevelPerDmiPlugin, mockTrustLevelManager, - mockCmHandleIdMapper, + mockAlternateIdChecker, mockModuleSetTagCache) def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']" @@ -269,7 +267,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle] mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle] when: 'parse and create cm handle in dmi registration then sync module' - objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(mockDmiPluginRegistration) + objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(mockDmiPluginRegistration, ['test-cm-handle-id']) then: 'system persists the cm handle state' 1 * mockLcmEventsCmHandleStateHandler.initiateStateAdvised(_) >> { args -> { @@ -280,7 +278,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { } } } - + def 'Execute cm handle id search'() { given: 'valid CmHandleQueryApiParameters input' def cmHandleQueryApiParameters = new CmHandleQueryApiParameters() 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 index f94c34c58..d822f2e63 100644 --- 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 @@ -22,35 +22,33 @@ package org.onap.cps.ncmp.api.impl - import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper - -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR -import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND -import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID -import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR -import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status - import org.onap.cps.api.CpsDataService -import org.onap.cps.utils.JsonObjectMapper import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence -import org.onap.cps.spi.exceptions.DataValidationException +import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle 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 org.onap.cps.utils.JsonObjectMapper import spock.lang.Specification +import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND +import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID +import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR +import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status + class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { def mockInventoryPersistence = Mock(InventoryPersistence) def mockCpsDataService = Mock(CpsDataService) def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) - def mockCmHandleIdMapper = Mock(CmHandleIdMapper) + def mockAlternateIdChecker = Mock(AlternateIdChecker) - def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper, mockCmHandleIdMapper) + def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper, mockAlternateIdChecker) def static cmHandleId = 'myHandle1' def static cmHandleXpath = "/dmi-registry/cm-handles[@id='${cmHandleId}']" @@ -62,7 +60,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { def 'Update CM Handle Public Properties: #scenario'() { given: 'the CPS service return a CM handle' - mockInventoryPersistence.getCmHandleDataNode(cmHandleId) >> cmHandleDataNodeAsCollection + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> cmHandleDataNodeAsCollection and: 'an update cm handle request with public properties updates' def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: updatedPublicProperties)] when: 'update data node leaves is called with the update request' @@ -84,7 +82,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { def 'Update DMI Properties: #scenario'() { given: 'the CPS service return a CM handle' - mockInventoryPersistence.getCmHandleDataNode(cmHandleId) >> cmHandleDataNodeAsCollection + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> cmHandleDataNodeAsCollection and: 'an update cm handle request with DMI properties updates' def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, dmiProperties: updatedDmiProperties)] when: 'update data node leaves is called with the update request' @@ -108,7 +106,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { 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) - mockInventoryPersistence.getCmHandleDataNode(cmHandleId) >> [cmHandleDataNode] + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> [cmHandleDataNode] and: 'an update cm handle request that removes all public properties(existing and non-existing)' def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: ['publicProp3': null, 'publicProp4': null])] when: 'update data node leaves is called with the update request' @@ -131,7 +129,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { given: 'cm handles request' def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: [:], dmiProperties: [:])] and: 'data node cannot be found' - mockInventoryPersistence.getCmHandleDataNode(*_) >> { throw exception } + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(*_) >> { throw exception } when: 'update data node leaves is called using correct parameters' def response = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) then: 'one failed registration response' @@ -156,7 +154,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: ['publicProp1': "value"], dmiProperties: [:]), new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: ['publicProp1': "value"], dmiProperties: [:])] and: 'data node can be found for 1st and 3rd cm-handle but not for 2nd cm-handle' - mockInventoryPersistence.getCmHandleDataNode(*_) >> cmHandleDataNodeAsCollection >> { + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(*_) >> cmHandleDataNodeAsCollection >> { throw new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR) } >> cmHandleDataNodeAsCollection when: 'update data node leaves is called using correct parameters' def cmHandleResponseList = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) @@ -194,7 +192,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { { args -> assert args[3].contains('alt-1') } - mockCmHandleIdMapper.addMapping(cmHandleId, 'alt-1') >> isNewMapping + mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> isNewMapping where: 'following updates are attempted' scenario | isNewMapping || callsToDataService 'new alternate id ' | true || 1 @@ -205,8 +203,8 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { given: 'an existing data node and an update request with an alternate id' def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1') DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['alternate-id': null]) - and: 'a new mapping is added' - mockCmHandleIdMapper.addMapping(cmHandleId, 'alt-1') >> true + and: 'an applicable alternate id for the cm handle' + mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> true and: 'but an exception occurs while saving' def originalException = new NullPointerException('some exception') mockCpsDataService.updateNodeLeaves(*_) >> { throw originalException } @@ -215,8 +213,6 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { then: 'the original exception is thrown up' def thrownException = thrown(NullPointerException) assert thrownException == originalException - and: 'the mapping is removed from the cache' - 1 * mockCmHandleIdMapper.removeMapping(cmHandleId) } def convertToProperties(expectedPropertiesAfterUpdateAsMap) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy index a3b923f93..83acb2238 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy @@ -22,32 +22,34 @@ package org.onap.cps.ncmp.api.impl.inventory -import org.onap.cps.api.CpsAnchorService - -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NO_TIMESTAMP -import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS - import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsModuleService import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.spi.CascadeDeleteAllowed import org.onap.cps.spi.FetchDescendantsOption +import org.onap.cps.spi.exceptions.DataNodeNotFoundException import org.onap.cps.spi.model.DataNode import org.onap.cps.spi.model.ModuleDefinition import org.onap.cps.spi.model.ModuleReference -import org.onap.cps.utils.JsonObjectMapper import org.onap.cps.spi.utils.CpsValidator +import org.onap.cps.utils.JsonObjectMapper import spock.lang.Shared import spock.lang.Specification + import java.time.OffsetDateTime import java.time.ZoneOffset import java.time.format.DateTimeFormatter +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NO_TIMESTAMP +import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS +import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS + class InventoryPersistenceImplSpec extends Specification { def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) @@ -60,8 +62,10 @@ class InventoryPersistenceImplSpec extends Specification { def mockCpsValidator = Mock(CpsValidator) + def mockCmHandleQueries = Mock(CmHandleQueries) + def objectUnderTest = new InventoryPersistenceImpl(spiedJsonObjectMapper, mockCpsDataService, mockCpsModuleService, - mockCpsValidator, mockCpsAnchorService) + mockCpsValidator, mockCpsAnchorService, mockCmHandleQueries) def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ") .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC)) @@ -283,13 +287,32 @@ class InventoryPersistenceImplSpec extends Specification { def 'Get cmHandle data node'() { given: 'expected xPath to get cmHandle data node' - def expectedXPath = '/dmi-registry/cm-handles[@id=\'sample cmHandleId\']'; + def expectedXPath = '/dmi-registry/cm-handles[@id=\'sample cmHandleId\']' when: 'the method to get data nodes is called' - objectUnderTest.getCmHandleDataNode('sample cmHandleId') + objectUnderTest.getCmHandleDataNodeByCmHandleId('sample cmHandleId') then: 'the data persistence service method to get cmHandle data node is invoked once with expected xPath' 1 * mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, expectedXPath, INCLUDE_ALL_DESCENDANTS) } + def 'Get cm handle data node'() { + given: 'expected xPath to get cmHandle data node' + def expectedXPath = '/dmi-registry/cm-handles[@alternate-id=\'alternate id\']' + and: 'query service is invoked with expected xpath' + mockCmHandleQueries.queryNcmpRegistryByCpsPath(expectedXPath, OMIT_DESCENDANTS) >> [new DataNode()] + expect: 'getting the cm handle data node' + assert objectUnderTest.getCmHandleDataNodeByAlternateId('alternate id') == new DataNode() + } + + def 'Attempt to get non existing cm handle data node by alternate id'() { + given: 'query service is invoked and returns empty collection of data nodes' + mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> [] + when: 'getting the cm handle data node' + objectUnderTest.getCmHandleDataNodeByAlternateId('alternate id') + then: 'no data found exception thrown' + def thrownException = thrown(DataNodeNotFoundException) + assert thrownException.getMessage().contains('DataNode not found') + } + def 'Get CM handles that has given module names'() { when: 'the method to get cm handles is called' objectUnderTest.getCmHandleIdsWithGivenModules(['sample-module-name']) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy new file mode 100644 index 000000000..f41fd6cdf --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy @@ -0,0 +1,97 @@ +/* + * ============LICENSE_START======================================================== + * Copyright (c) 2024 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.utils + + +import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle +import org.onap.cps.spi.exceptions.DataNodeNotFoundException +import org.onap.cps.spi.model.DataNode +import org.onap.cps.spi.model.DataNodeBuilder +import spock.lang.Specification + +class AlternateIdCheckerSpec extends Specification { + + def mockInventoryPersistenceService = Mock(InventoryPersistence) + def someDataNode = new DataNodeBuilder().build() + def dataNodeFoundException = new DataNodeNotFoundException('', '') + + def objectUnderTest = new AlternateIdChecker(mockInventoryPersistenceService) + + def 'Check new cm handle with new alternate id.'() { + given: 'inventory persistence can not find cm handle id' + mockInventoryPersistenceService.getYangModelCmHandle('ch 1') >> {throw dataNodeFoundException} + and: 'inventory persistence can not find alternate id' + mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId('alternate id') >> {throw dataNodeFoundException} + expect: 'mapping can be added' + assert objectUnderTest.canApplyAlternateId('ch 1', 'alternate id') + } + + def 'Check new cm handle with used alternate id.'() { + given: 'inventory persistence can not find cm handle id' + mockInventoryPersistenceService.getYangModelCmHandle('ch 1') >> {throw dataNodeFoundException} + and: 'inventory persistence can find alternate id' + mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId('alternate id') >> { someDataNode } + expect: 'mapping can not be added' + assert objectUnderTest.canApplyAlternateId('ch 1', 'alternate id') == false + } + + def 'Check for existing cm handle with #currentAlternateId.'() { + given: 'a cm handle with the #currentAlternateId' + def yangModelCmHandle = new YangModelCmHandle(alternateId: currentAlternateId) + and: 'inventory service finds the cm handle' + mockInventoryPersistenceService.getYangModelCmHandle('my cm handle') >> yangModelCmHandle + expect: 'add mapping returns expected result' + assert canAdd == objectUnderTest.canApplyAlternateId('my cm handle', 'same alternate id') + where: 'following alternate ids is used' + currentAlternateId || canAdd + 'same alternate id' || true + 'other alternate id' || false + } + + def 'Check a batch of NEW cm handles with #scenario.'() { + given: 'a batch of 2 new cm handles alternate id ids #alt1 and #alt2' + def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: alt1), + new NcmpServiceCmHandle(cmHandleId: 'ch-2', alternateId: alt2)] + and: 'the database already contains cm handle(s) with these alternate ids: #alreadyinDb' + mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >> + { args -> altAlreadyInDb.contains(args[0]) ? new DataNode() : throwDataNodeNotFoundException() } + when: 'the batch of new cm handles is checked' + def result = objectUnderTest.getIdsOfCmHandlesWithAcceptableAlternateId(batch) + then: 'the result only contains the ids of the acceptable cm handles' + assert result.contains('ch-1') == acceptCh1 + assert result.contains('ch-2') == acceptCh2 + where: 'the following alternate ids are used' + scenario | alt1 | alt2 | altAlreadyInDb || acceptCh1 | acceptCh2 + 'no alternate ids' | '' | '' | ['dont matter'] || true | true + 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || true | true + 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || false | true + 'two already used alternate ids' | 'fdn1' | 'fdn2' | ['fdn1','fdn2'] || false | false + 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || true | false + } + + def throwDataNodeNotFoundException() { + // cannot 'return' an exception in conditional stub behavior, so hence a method call that will always throw this exception + throw dataNodeFoundException + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapperSpec.groovy deleted file mode 100644 index 55ccdf3be..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapperSpec.groovy +++ /dev/null @@ -1,126 +0,0 @@ -/* - * ============LICENSE_START======================================================== - * Copyright (c) 2024 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.utils - -import ch.qos.logback.classic.Level -import ch.qos.logback.classic.Logger -import ch.qos.logback.classic.spi.ILoggingEvent -import ch.qos.logback.core.read.ListAppender -import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle -import org.slf4j.LoggerFactory -import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService -import spock.lang.Specification - -class CmHandleIdMapperSpec extends Specification { - - def alternateIdPerCmHandle = new HashMap<String, String>() - def cmHandlePerAlternateId = new HashMap<String, String>() - def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandleQueryService) - - def objectUnderTest = new CmHandleIdMapper(alternateIdPerCmHandle, cmHandlePerAlternateId, mockCpsCmHandlerQueryService) - - def logger = Spy(ListAppender<ILoggingEvent>) - - def setup() { - ((Logger) LoggerFactory.getLogger(CmHandleIdMapper.class)).addAppender(logger) - logger.start() - mockCpsCmHandlerQueryService.getAllCmHandles() >> [] - assert objectUnderTest.addMapping('my cmhandle id', 'my alternate id') - } - - void cleanup() { - ((Logger) LoggerFactory.getLogger(CmHandleIdMapper.class)).detachAndStopAllAppenders() - } - - def 'Checking entries in the cache.'() { - expect: 'the alternate id can be converted to cmhandle id' - assert objectUnderTest.alternateIdToCmHandleId('my alternate id') == 'my cmhandle id' - and: 'the cmhandle id can be converted to alternate id' - assert objectUnderTest.cmHandleIdToAlternateId('my cmhandle id') == 'my alternate id' - } - - def 'Attempt adding #scenario alternate id.'() { - expect: 'cmhandle id - alternate id mapping fails' - assert objectUnderTest.addMapping('ch-1', alternateId) == false - and: 'alternate id looked up by cmhandle id unsuccessfully' - assert objectUnderTest.cmHandleIdToAlternateId('ch-1') == null - where: 'alternate id has an invalid value' - scenario | alternateId - 'empty' | '' - 'blank' | ' ' - 'null' | null - } - - def 'Remove an entry from the cache.'() { - when: 'removing an entry' - objectUnderTest.removeMapping('my cmhandle id') - then: 'converting alternate id returns null' - assert objectUnderTest.alternateIdToCmHandleId('my alternate id') == null - and: 'converting cmhandle id returns null' - assert objectUnderTest.cmHandleIdToAlternateId('my cmhandle id') == null - } - - def 'Attempt to remove a non-existing entry from the cache.'() { - when: 'removing an entry that is not cached' - objectUnderTest.removeMapping('non-cached cmhandle id') - then: 'deleting from the cmhandle cache returns null' - assert alternateIdPerCmHandle.remove('non-cached cmhandle id') == null - and: 'removal from the alternate id cache is skipped' - 0 * cmHandlePerAlternateId.remove(_) - } - - def 'Cannot update existing alternate id.'() { - given: 'attempt to update an existing alternate id' - objectUnderTest.addMapping('my cmhandle id', 'other id') - expect: 'still returns the original alternate id' - assert objectUnderTest.cmHandleIdToAlternateId('my cmhandle id') == 'my alternate id' - and: 'converting other alternate id returns null' - assert objectUnderTest.alternateIdToCmHandleId('other id') == null - and: 'a warning is logged with the original alternate id' - def lastLoggingEvent = logger.list[1] - assert lastLoggingEvent.level == Level.WARN - assert lastLoggingEvent.formattedMessage.contains('my alternate id') - } - - def 'Update existing alternate id with the same value.'() { - expect: 'update an existing alternate id with the same value returns false (no update)' - assert objectUnderTest.addMapping('my cmhandle id', 'my alternate id') == false - and: 'conversion still returns the original alternate id' - assert objectUnderTest.cmHandleIdToAlternateId('my cmhandle id') == 'my alternate id' - } - - def 'Initializing cache #scenario.'() { - when: 'the cache is (re-)initialized' - objectUnderTest.cacheIsInitialized = false - objectUnderTest.initializeCache() - then: 'the alternate id can be converted to cmhandle id' - assert objectUnderTest.alternateIdToCmHandleId('alt-1') == convertedCmHandleId - and: 'the cm handle id can be converted to alternate id' - assert objectUnderTest.cmHandleIdToAlternateId('ch-1') == convertedAlternatId - and: 'the query service is called to get the initial data' - 1 * mockCpsCmHandlerQueryService.getAllCmHandles() >> persistedCmHandles - where: 'the initial data has a cm handle #scenario' - scenario | persistedCmHandles || convertedAlternatId | convertedCmHandleId - 'with alternate id' | [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: 'alt-1')] || 'alt-1' | 'ch-1' - 'without alternate id' | [new NcmpServiceCmHandle(cmHandleId: 'ch-1')] || null | null - 'with blank alternate id' | [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: ' ')] || null | null - } -}
\ No newline at end of file |