diff options
author | 2025-02-20 11:16:11 +0000 | |
---|---|---|
committer | 2025-02-27 11:35:18 +0000 | |
commit | b3dfa9ba4771b3d98bbfbdb870b8ed063d4dd2ce (patch) | |
tree | d5981045a29094f191164797b6a0d1f243c7b851 | |
parent | 138cae7d9d060c0f194eccb213fa2aa4cbac7105 (diff) |
Change order of CM Handle Reference lookup depending on special character
- implemented new algorithm using validator to rule out standard id / prefer alternate id
- moved validator imp to cps-service (not in RI) TBC!!!
- changed order of characters tested in validator to fail fast (on '=')
- added Boolean variation validator method to reduce overhead and prevent logic based on exceptions
- improved integration test to cover all scenarios
- add performance test for alternate id look up (report only)
- ensured all performance test use alternate ids it '='
- added small groovy tests to restore cps-ri code coverage to 0.31
Issue-ID: CPS-2605
Change-Id: Id9c22bb69904b7f5d376b7f8319332428435333e
Signed-off-by: ToineSiebelink <toine.siebelink@est.tech>
Signed-off-by: seanbeirne <sean.beirne@est.tech>
12 files changed, 193 insertions, 95 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java index 189239ceb2..7cb1c44526 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation + * Copyright (C) 2021-2025 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,7 +34,6 @@ import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.onap.cps.api.exceptions.CpsException; -import org.onap.cps.api.exceptions.DataValidationException; import org.onap.cps.ncmp.api.NcmpResponseStatus; import org.onap.cps.ncmp.api.data.models.CmResourceAddress; import org.onap.cps.ncmp.api.data.models.DataOperationRequest; @@ -79,7 +78,7 @@ public class DmiDataOperations { * This method fetches the resource data from the operational data store for a given CM handle * identifier on the specified resource using the DMI client. * - * @param cmResourceAddress Target datastore, CM handle, and resource identifier. + * @param cmResourceAddress Target datastore, CM handle reference, and resource identifier. * @param options Options query string. * @param topic Topic name for triggering asynchronous responses. * @param requestId Request ID for asynchronous responses. @@ -94,7 +93,8 @@ public class DmiDataOperations { final String topic, final String requestId, final String authorization) { - final YangModelCmHandle yangModelCmHandle = resolveYangModelCmHandleFromCmHandleReference(cmResourceAddress); + final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle( + cmResourceAddress.resolveCmHandleReferenceToId()); final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle); @@ -157,22 +157,22 @@ public class DmiDataOperations { * This method creates the resource data from pass-through running data store for given cm handle * identifier on given resource using dmi client. * - * @param cmHandleId network resource identifier - * @param resourceId resource identifier - * @param operationType operation enum - * @param requestData the request data - * @param dataType data type - * @param authorization contents of Authorization header, or null if not present + * @param cmHandleReference network resource identifier + * @param resourceId resource identifier + * @param operationType operation enum + * @param requestData the request data + * @param dataType data type + * @param authorization contents of Authorization header, or null if not present * @return {@code ResponseEntity} response entity */ - public ResponseEntity<Object> writeResourceDataPassThroughRunningFromDmi(final String cmHandleId, + public ResponseEntity<Object> writeResourceDataPassThroughRunningFromDmi(final String cmHandleReference, final String resourceId, final OperationType operationType, final String requestData, final String dataType, final String authorization) { final CmResourceAddress cmResourceAddress = - new CmResourceAddress(PASSTHROUGH_RUNNING.getDatastoreName(), cmHandleId, resourceId); + new CmResourceAddress(PASSTHROUGH_RUNNING.getDatastoreName(), cmHandleReference, resourceId); final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmResourceAddress.resolveCmHandleReferenceToId()); @@ -281,16 +281,6 @@ public class DmiDataOperations { }).subscribe(); } - private YangModelCmHandle resolveYangModelCmHandleFromCmHandleReference(final CmResourceAddress cmResourceAddress) { - String cmHandleId = cmResourceAddress.getCmHandleReference(); - try { - return getYangModelCmHandle(cmHandleId); - } catch (final DataValidationException ignored) { - cmHandleId = cmResourceAddress.resolveCmHandleReferenceToId(); - return getYangModelCmHandle(cmHandleId); - } - } - private String createDmiDataOperationRequestAsJsonString( final List<DmiDataOperation> dmiDataOperationRequestBodies) { final DmiDataOperationRequest dmiDataOperationRequest = DmiDataOperationRequest.builder() diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java index b97da2977a..750a5050f2 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import org.onap.cps.ncmp.api.exceptions.CmHandleNotFoundException; import org.onap.cps.ncmp.exceptions.NoAlternateIdMatchFoundException; import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.utils.CpsValidator; import org.springframework.stereotype.Service; @Service @@ -33,6 +34,7 @@ import org.springframework.stereotype.Service; public class AlternateIdMatcher { private final InventoryPersistence inventoryPersistence; + private final CpsValidator cpsValidator; /** * Get yang model cm handle that matches longest alternate id by removing elements @@ -64,11 +66,22 @@ public class AlternateIdMatcher { * @return cm handle id string */ public String getCmHandleId(final String cmHandleReference) { + if (cpsValidator.isValidName(cmHandleReference)) { + return getCmHandleIdTryingStandardIdFirst(cmHandleReference); + } + return getCmHandleIdByAlternateId(cmHandleReference); + } + + private String getCmHandleIdByAlternateId(final String cmHandleReference) { + // Please note: because of cm handle id validation rules this case does NOT need to try by (standard) id + return inventoryPersistence.getYangModelCmHandleByAlternateId(cmHandleReference).getId(); + } + + private String getCmHandleIdTryingStandardIdFirst(final String cmHandleReference) { if (inventoryPersistence.isExistingCmHandleId(cmHandleReference)) { return cmHandleReference; - } else { - return inventoryPersistence.getYangModelCmHandleByAlternateId(cmHandleReference).getId(); } + return inventoryPersistence.getYangModelCmHandleByAlternateId(cmHandleReference).getId(); } private String getParentPath(final String path, final String separator) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy index 01a08e7bb5..3dd2eabe21 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation + * Copyright (C) 2021-2025 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,8 +22,6 @@ package org.onap.cps.ncmp.impl.data import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.api.exceptions.DataNodeNotFoundException -import org.onap.cps.api.exceptions.DataValidationException import org.onap.cps.events.EventsPublisher import org.onap.cps.ncmp.api.data.models.CmResourceAddress import org.onap.cps.ncmp.api.data.models.DataOperationRequest @@ -86,6 +84,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { def 'call get resource data for #expectedDataStore from DMI without topic #scenario.'() { given: 'a cm handle for #cmHandleId' + alternateIdMatcher.getCmHandleId(cmHandleId) >> cmHandleId mockYangModelCmHandleRetrieval(dmiProperties) and: 'a positive response from DMI service when it is called with the expected parameters' def responseFromDmi = Mono.just(new ResponseEntity<Object>('{some-key:some-value}', HttpStatus.OK)) @@ -206,33 +205,6 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { CmHandleState.ADVISED || true } - def 'Resolving cm handle references with cm handle id.'() { - given: 'a resource address with a cm handle id' - def cmResourceAddress = new CmResourceAddress('some store', 'cm-handle-id', 'some resource') - and: 'the given cm handle id is available in the inventory' - mockInventoryPersistence.getYangModelCmHandle('cm-handle-id') >> yangModelCmHandle - expect: 'resolving the cm handle id returns the cm handle' - assert objectUnderTest.resolveYangModelCmHandleFromCmHandleReference(cmResourceAddress) == yangModelCmHandle - } - - def 'Resolving cm handle references with alternate id #scenario.'() { - given: 'a resource with a alternate id' - def cmResourceAddress = new CmResourceAddress('some store', alternateId, 'some resource') - and: 'the alternate id cannot be found in the inventory directly and that results in an exception' - mockInventoryPersistence.getYangModelCmHandle(alternateId) >> { throw errorThrownDuringCmHandleIdSearch } - and: 'the alternate id can be matched to a cm handle id' - alternateIdMatcher.getCmHandleId(alternateId) >> 'cm-handle-id' - and: 'that cm handle id is available in the inventory' - mockInventoryPersistence.getYangModelCmHandle('cm-handle-id') >> yangModelCmHandle - expect: 'resolving that cm handle id returns the cm handle' - assert objectUnderTest.resolveYangModelCmHandleFromCmHandleReference(cmResourceAddress) == yangModelCmHandle - where: 'the following alternate ids are used' - scenario | alternateId | errorThrownDuringCmHandleIdSearch - 'alternate id with no special characters' | 'alternate-id' | new DataNodeNotFoundException('','') - 'alternate id with special characters' | 'alternate#id' | new DataValidationException('','') - } - - def extractDataValue(actualDataOperationCloudEvent) { return toTargetEvent(actualDataOperationCloudEvent, DataOperationEvent).data.responses[0] } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy index a6d21afd30..fe7c5e3817 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -24,12 +24,20 @@ import org.onap.cps.ncmp.api.exceptions.CmHandleNotFoundException import org.onap.cps.ncmp.exceptions.NoAlternateIdMatchFoundException import org.onap.cps.ncmp.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import org.onap.cps.utils.CpsValidatorImpl +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.ContextConfiguration import spock.lang.Specification +@SpringBootTest +@ContextConfiguration(classes = [InventoryPersistence, CpsValidatorImpl]) class AlternateIdMatcherSpec extends Specification { def mockInventoryPersistence = Mock(InventoryPersistence) - def objectUnderTest = new AlternateIdMatcher(mockInventoryPersistence) + + def mockCpsValidator = Mock(CpsValidatorImpl) + + def objectUnderTest = new AlternateIdMatcher(mockInventoryPersistence, mockCpsValidator) def setup() { given: 'cm handle in the registry with alternate id /a/b' @@ -72,13 +80,14 @@ class AlternateIdMatcherSpec extends Specification { when: 'a cmHandleCmReference is passed in' def result = objectUnderTest.getCmHandleId(cmHandleReference) then: 'the inventory persistence service returns a cm handle (or not)' - mockInventoryPersistence.isExistingCmHandleId(cmHandleReference) >> existingCmHandleIdResponse + mockCpsValidator.isValidName(cmHandleReference) >> existingCmHandleIdAndValidatorResponse + mockInventoryPersistence.isExistingCmHandleId(cmHandleReference) >> existingCmHandleIdAndValidatorResponse mockInventoryPersistence.getYangModelCmHandleByAlternateId(cmHandleReference) >> alternateIdGetResponse and: 'correct result is returned' assert result == cmHandleReference where: 'the following parameters are used' - cmHandleReference | existingCmHandleIdResponse | alternateIdGetResponse - 'ch-1' | true | '' - 'alt-1' | false | new YangModelCmHandle(id: 'alt-1') + cmHandleReference | existingCmHandleIdAndValidatorResponse | alternateIdGetResponse + 'ch-1' | true | null + 'alt=1' | false | new YangModelCmHandle(id: 'alt=1') } } diff --git a/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceImplSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceImplSpec.groovy index 9abfdbeb33..4bf8c7ca09 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceImplSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceImplSpec.groovy @@ -1,7 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (c) 2021 Bell Canada. - * Modifications Copyright (C) 2022-2023 Nordix Foundation + * Modifications Copyright (C) 2022-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package org.onap.cps.ri import org.hibernate.exception.ConstraintViolationException +import org.onap.cps.ri.models.DataspaceEntity import org.onap.cps.ri.models.SchemaSetEntity import org.onap.cps.ri.repository.DataspaceRepository import org.onap.cps.ri.repository.ModuleReferenceRepository @@ -30,7 +31,6 @@ import org.onap.cps.api.exceptions.DuplicatedYangResourceException import org.onap.cps.api.model.ModuleReference import org.springframework.dao.DataIntegrityViolationException import spock.lang.Specification - import java.sql.SQLException /** @@ -101,4 +101,32 @@ class CpsModulePersistenceServiceImplSpec extends Specification { noExceptionThrown() } + def 'Get yang schema resources.' () { + given: 'mocked methods for dataspace and schema set repositories' + mockDataspaceRepository.getByName('someDataspaceName') >> new DataspaceEntity() + mockSchemaSetRepository.getByDataspaceAndName(_,_) >> new SchemaSetEntity(yangResources: []) + when: 'the get yang schema resources method is called' + def result = objectUnderTest.getYangSchemaResources('someDataspaceName', 'someSchemaSetName') + then: 'an empty map is returned' + assert result.isEmpty() + } + + def 'Get yang module references with just dataspace name.' () { + given: 'mocked method return yang resource repository' + mockYangResourceRepository.findAllModuleReferencesByDataspace('someDataspaceName') >> [] + when: 'the get yang resource module reference method is called with 1 parameter' + def result = objectUnderTest.getYangResourceModuleReferences('someDataspaceName') + then: 'an empty collection is returned' + assert result.isEmpty() + } + + def 'Get yang module references with dataspace name and anchor.' () { + given: 'mocked method return yang resource repository' + mockYangResourceRepository.findAllModuleReferencesByDataspaceAndAnchor('someDataspaceName', 'someAnchorName') >> [] + when: 'the get yang resource module reference method is called with 2 parameters' + def result = objectUnderTest.getYangResourceModuleReferences('someDataspaceName','someAnchorName') + then: 'an empty collection is returned' + assert result.isEmpty() + } + } diff --git a/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java b/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java index 93f51ee58d..2244ea729b 100644 --- a/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java +++ b/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022-2023 Nordix Foundation + * Copyright (C) 2022-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,21 +20,32 @@ package org.onap.cps.utils; +import org.onap.cps.api.exceptions.DataValidationException; import org.onap.cps.api.parameters.PaginationOption; public interface CpsValidator { /** + * Validate characters in name within cps. + * + * @param name name to be validated + * @return true if name is valid + */ + boolean isValidName(final String name); + + /** * Validate characters in names within cps. * - * @param names names of data to be validated + * @param names names to be validated + * @throws DataValidationException for any name that is not valid. */ void validateNameCharacters(final String... names); /** * Validate characters in names within cps. * - * @param names names of data to be validated + * @param names names to be validated + * @throws DataValidationException for any name that is not valid. */ void validateNameCharacters(final Iterable<String> names); diff --git a/cps-ri/src/main/java/org/onap/cps/ri/utils/CpsValidatorImpl.java b/cps-service/src/main/java/org/onap/cps/utils/CpsValidatorImpl.java index 9e89c8aed9..e1c81bfaf5 100644 --- a/cps-ri/src/main/java/org/onap/cps/ri/utils/CpsValidatorImpl.java +++ b/cps-service/src/main/java/org/onap/cps/utils/CpsValidatorImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022-2023 Nordix Foundation + * Copyright (C) 2022-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,24 +18,32 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ri.utils; +package org.onap.cps.utils; import com.google.common.collect.Lists; import java.util.Arrays; import java.util.Collection; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.exceptions.DataValidationException; import org.onap.cps.api.parameters.PaginationOption; -import org.onap.cps.utils.CpsValidator; import org.springframework.stereotype.Component; -@Slf4j @Component @RequiredArgsConstructor public class CpsValidatorImpl implements CpsValidator { - private static final char[] UNSUPPORTED_NAME_CHARACTERS = "!\" #$%&'()*+,./\\:;<=>?@[]^`{|}~".toCharArray(); + private static final char[] UNSUPPORTED_NAME_CHARACTERS = "=!\" #$%&'()*+,./\\:;<>?@[]^`{|}~".toCharArray(); + + @Override + public boolean isValidName(final String name) { + final Collection<Character> charactersOfName = Lists.charactersOf(name); + for (final char unsupportedCharacter : UNSUPPORTED_NAME_CHARACTERS) { + if (charactersOfName.contains(unsupportedCharacter)) { + return false; + } + } + return true; + } @Override public void validateNameCharacters(final String... names) { diff --git a/cps-ri/src/test/groovy/org/onap/cps/ri/utils/CpsValidatorImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/CpsValidatorImplSpec.groovy index f7c4798772..df257c9028 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/ri/utils/CpsValidatorImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/utils/CpsValidatorImplSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022-2023 Nordix Foundation + * Copyright (C) 2022-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,10 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ri.utils +package org.onap.cps.utils - -import org.onap.cps.api.parameters.PaginationOption import org.onap.cps.api.exceptions.DataValidationException +import org.onap.cps.api.parameters.PaginationOption import spock.lang.Specification class CpsValidatorImplSpec extends Specification { @@ -60,19 +59,38 @@ class CpsValidatorImplSpec extends Specification { def 'Validating a list of names with invalid names.'() { given: 'a list of names with an invalid name' - def names = ['valid-name', 'name with spaces'] + def names = ['valid-name', 'invalid name with spaces'] when: 'a list of strings is validated' objectUnderTest.validateNameCharacters(names) then: 'a data validation exception is thrown' thrown(DataValidationException) } - def 'Validate Pagination option with invalid page index and size.'() { + def 'Validate valid pagination options'() { + when: 'the pagination option is validated' + objectUnderTest.validatePaginationOption(option) + then: 'no exception occurs' + noExceptionThrown() + where: 'the following pagination options are used' + option << [null, new PaginationOption(1,2)] + } + + def 'Validate invalid pagination.'() { when: 'the pagination option is validated using invalid options' objectUnderTest.validatePaginationOption(new PaginationOption(-5, -2)) then: 'a data validation exception is thrown' def exceptionThrown = thrown(DataValidationException) and: 'the error was encountered at the following index in #scenario' - assert exceptionThrown.getDetails().contains("Invalid page index or size") + assert exceptionThrown.getDetails().contains('Invalid page index or size') + } + + + def 'Validation with boolean result.'() { + expect: 'validation returns expected boolean result' + assert objectUnderTest.isValidName(name) == expectedResult + where: 'following names are used' + name || expectedResult + 'valid-name' || true + 'invalid name' || false } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy index 693cf992ee..9b79af95ff 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy @@ -281,7 +281,7 @@ abstract class CpsIntegrationSpecBase extends Specification { def modulePrefix = moduleNameStrategy.OVERLAPPING.equals(moduleNameStrategy) ? 'same' : moduleSetTag def moduleReferences = (1..200).collect { "${modulePrefix}Module${it}" } (1..numberOfCmHandles).each { - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: "ch-${id}", moduleSetTag: moduleSetTag, alternateId: NO_ALTERNATE_ID) + def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: "ch-${id}", moduleSetTag: moduleSetTag, alternateId: "alt=${id}") cmHandles.add(ncmpServiceCmHandle) dmiDispatcher1.moduleNamesPerCmHandleId[ncmpServiceCmHandle.cmHandleId] = moduleReferences dmiDispatcher2.moduleNamesPerCmHandleId[ncmpServiceCmHandle.cmHandleId] = moduleReferences diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy index 222b3c0f6f..b1b777c79f 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -30,16 +30,13 @@ class AlternateIdSpec extends CpsIntegrationSpecBase { def setup() { dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2'] - registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, 'alternateId') } - def cleanup() { - deregisterCmHandle(DMI1_URL, 'ch-1') - } - - def 'AlternateId in pass-through data operations should return OK status.'() { - given: 'the URL for the pass-through data request' - def url = '/ncmp/v1/ch/alternateId/data/ds/ncmp-datastore:passthrough-running' + def 'Pass-through data operations using #scenario as reference.'() { + given: 'a cm handle with an alternate id' + registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, alternateId) + and: 'the URL for the pass-through data request' + def url = "/ncmp/v1/ch/${cmHandleReference}/data/ds/ncmp-datastore:passthrough-running" when: 'a pass-through data request is sent to NCMP' def response = mvc.perform(get(url) .queryParam('resourceIdentifier', 'my-resource-id') @@ -47,8 +44,13 @@ class AlternateIdSpec extends CpsIntegrationSpecBase { .andReturn().response then: 'response status is Ok' assert response.status == HttpStatus.OK.value() + cleanup: 'remove the test cm handle' + deregisterCmHandle(DMI1_URL, 'ch-1') + where: 'the following ids are used' + scenario | alternateId | cmHandleReference + 'standard id' | 'dont care' | 'ch-1' + 'alt-id with =' | 'alt=1' | 'alt=1' + 'alt-id without =' | 'alt-1' | 'alt-1' } - - } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/AlternateIdPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/AlternateIdPerfTest.groovy new file mode 100644 index 0000000000..b9d57cf14d --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/AlternateIdPerfTest.groovy @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2025 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.integration.performance.ncmp + +import org.onap.cps.integration.ResourceMeter +import org.onap.cps.integration.base.CpsIntegrationSpecBase + +/** + * This test does not depend on common performance test data. Hence it just extends the integration spec base. + */ +class AlternateIdPerfTest extends CpsIntegrationSpecBase { + + def resourceMeter = new ResourceMeter() + + def 'Alternate Id Lookup Performance.'() { + given: 'register 1,000 cm handles (with alternative ids)' + registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(DMI1_URL, 'tagA', 1000, 1) + when: 'perform a 1,000 lookups by alternate id' + resourceMeter.start() + (1..1000).each { + networkCmProxyInventoryFacade.getNcmpServiceCmHandle("alt=${it}") + } + resourceMeter.stop() + then: 'record the result. Not asserted, just recorded in See https://lf-onap.atlassian.net/browse/CPS-2605' + println "*** CPS-2605 Execution time: ${resourceMeter.totalTimeInSeconds} ms" + cleanup: 'deregister test cm handles' + deregisterSequenceOfCmHandles(DMI1_URL, 1000, 1) + } +} diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy index 5389732181..dbf7e71710 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation + * Copyright (C) 2023-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase { cpsDataService.getDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@id="cm-' + it + '"]', OMIT_DESCENDANTS) objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, - '/dmi-registry/cm-handles[@alternate-id="alt-' + it + '"]', OMIT_DESCENDANTS) + '/dmi-registry/cm-handles[@alternate-id="alt=' + it + '"]', OMIT_DESCENDANTS) } resourceMeter.stop() then: 'resource usage is as expected' @@ -100,7 +100,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase { resourceMeter.start() (1..100).each { count += cpsQueryService.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, - '/dmi-registry/cm-handles[@alternate-id="alt-' + it + '"]', OMIT_DESCENDANTS).size() + '/dmi-registry/cm-handles[@alternate-id="alt=' + it + '"]', OMIT_DESCENDANTS).size() } resourceMeter.stop() then: @@ -116,7 +116,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase { def 'A batch of CM-handles is looked up by alternate-id.'() { given: 'a CPS Path Query to look up 100 alternate-ids in a single operation' - def cpsPathQuery = '/dmi-registry/cm-handles[' + (1..100).collect { "@alternate-id='alt-${it}'" }.join(' or ') + ']' + def cpsPathQuery = '/dmi-registry/cm-handles[' + (1..100).collect { "@alternate-id='alt=${it}'" }.join(' or ') + ']' when: 'CM-handles are looked up by alternate-ids in a single query' resourceMeter.start() def count = cpsQueryService.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, cpsPathQuery, OMIT_DESCENDANTS).size() |