diff options
author | Priyank Maheshwari <priyank.maheshwari@est.tech> | 2024-11-11 11:59:46 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@onap.org> | 2024-11-11 11:59:46 +0000 |
commit | 38cea5882ab71f23eddd3ffc9fd56c5d6540f28e (patch) | |
tree | 83939cfe8e8835f91b2320df0a0b032865f74cc3 | |
parent | 76b4ff600dfefd2bea79a43431e36698e86c4a5a (diff) | |
parent | a1a71f782f2db1b50a41f095d49c981f5095b4fb (diff) |
Merge "Support Alternate-Id for CPS-E05 data batch interface"
18 files changed, 149 insertions, 72 deletions
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml index 99072c43e5..a8da6937a3 100644 --- a/cps-ncmp-rest/docs/openapi/components.yaml +++ b/cps-ncmp-rest/docs/openapi/components.yaml @@ -366,7 +366,7 @@ components: type: array items: type: string - description: targeted cm handles, maximum of 50 supported. If this limit is exceeded the request wil be refused. + description: targeted cm handle references, maximum of 200 supported. If this limit is exceeded the request wil be refused. example: [ "da310eecdb8d44c2acc0ddaae01174b1","c748c58f8e0b438f9fd1f28370b17d47" ] examples: @@ -516,7 +516,7 @@ components: outputAlternateIdOptionInQuery: name: outputAlternateId in: query - description: Boolean parameter to determine if returned value(s) will be cmHandle Ids or Alternate Ids for a given query + description: Boolean parameter to determine if returned value(s) will be cm handle references for a given query required: false schema: type: boolean diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml index a3ddc3fb3b..4624bc1060 100755 --- a/cps-ncmp-rest/docs/openapi/ncmp.yml +++ b/cps-ncmp-rest/docs/openapi/ncmp.yml @@ -193,7 +193,7 @@ dataOperationForCmHandle: post: tags: - network-cm-proxy - summary: Execute a data operation for group of cm handle ids + summary: Execute a data operation for group of cm handle references description: This request will be handled asynchronously using messaging to the supplied topic. The rest response will be an acknowledge with a requestId to identify the relevant messages. A maximum of 200 cm handles per operation is supported. operationId: executeDataOperationForCmHandles parameters: diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DataOperationRequestMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DataOperationRequestMapper.java index 42622a2ca2..1e73aca158 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DataOperationRequestMapper.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DataOperationRequestMapper.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-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. @@ -35,7 +35,7 @@ public interface DataOperationRequestMapper { DataOperationRequest toDataOperationRequest( org.onap.cps.ncmp.rest.model.DataOperationRequest dataOperationRequest); - @Mapping(source = "targetIds", target = "cmHandleIds") + @Mapping(source = "targetIds", target = "cmHandleReferences") DataOperationDefinition toDataOperationDefinition( org.onap.cps.ncmp.rest.model.DataOperationDefinition dataOperationDefinition); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationDefinition.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationDefinition.java index d1ff1a5815..79da44af8f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationDefinition.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationDefinition.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-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. @@ -45,5 +45,5 @@ public class DataOperationDefinition { @JsonProperty("targetIds") @Valid - private List<String> cmHandleIds = new ArrayList<>(); + private List<String> cmHandleReferences = new ArrayList<>(); } 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 301b8195e4..c4bdc1cf1b 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 @@ -139,10 +139,10 @@ public class DmiDataOperations { final String requestId, final String authorization) { - final Set<String> cmHandlesIds = getDistinctCmHandleIds(dataOperationRequest); + final Set<String> cmHandlesReferences = getDistinctCmHandleReferences(dataOperationRequest); final Collection<YangModelCmHandle> yangModelCmHandles - = inventoryPersistence.getYangModelCmHandles(cmHandlesIds); + = inventoryPersistence.getYangModelCmHandlesFromCmHandleReferences(cmHandlesReferences); final Map<String, List<DmiDataOperation>> operationsOutPerDmiServiceName = DmiDataOperationsHelper.processPerDefinitionInDataOperationsRequest(topicParamInQuery, @@ -246,10 +246,10 @@ public class DmiDataOperations { } } - private static Set<String> getDistinctCmHandleIds(final DataOperationRequest dataOperationRequest) { + private static Set<String> getDistinctCmHandleReferences(final DataOperationRequest dataOperationRequest) { return dataOperationRequest.getDataOperationDefinitions().stream() .flatMap(dataOperationDefinition -> - dataOperationDefinition.getCmHandleIds().stream()).collect(Collectors.toSet()); + dataOperationDefinition.getCmHandleReferences().stream()).collect(Collectors.toSet()); } private void asyncSendMultipleRequest(final String requestId, final String topicParamInQuery, diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java index a21210c376..8920839cd5 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java @@ -91,10 +91,10 @@ public class NcmpPassthroughResourceRequestHandler extends NcmpDatastoreRequestH throw new InvalidDatastoreException(dataOperationDefinition.getDatastore() + " datastore is not supported"); } - if (dataOperationDefinition.getCmHandleIds().size() > MAXIMUM_CM_HANDLES_PER_OPERATION) { + if (dataOperationDefinition.getCmHandleReferences().size() > MAXIMUM_CM_HANDLES_PER_OPERATION) { final String errorMessage = String.format(PAYLOAD_TOO_LARGE_TEMPLATE, dataOperationDefinition.getOperationId(), - dataOperationDefinition.getCmHandleIds().size()); + dataOperationDefinition.getCmHandleReferences().size()); throw new PayloadTooLargeException(errorMessage); } }); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java index 3104be5539..f1dc9af09d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java @@ -31,7 +31,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -71,8 +70,9 @@ public class DmiDataOperationsHelper { final Map<String, List<DmiDataOperation>> dmiDataOperationsOutPerDmiServiceName = new HashMap<>(); final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus, - List<String>>> cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>(); - final Set<String> nonReadyCmHandleIdsLookup = filterAndGetNonReadyCmHandleIds(yangModelCmHandles); + List<String>>> cmHandleReferencesPerResponseCodesPerOperation = new LinkedMultiValueMap<>(); + final Map<String, String> nonReadyCmHandleReferencesLookup = + filterAndGetNonReadyCmHandleReferences(yangModelCmHandles); final Map<String, Map<String, Map<String, String>>> dmiPropertiesPerCmHandleIdPerServiceName = DmiServiceNameOrganizer.getDmiPropertiesPerCmHandleIdPerServiceName(yangModelCmHandles); @@ -84,17 +84,19 @@ public class DmiDataOperationsHelper { for (final DataOperationDefinition dataOperationDefinitionIn : dataOperationRequestIn.getDataOperationDefinitions()) { - final List<String> nonExistingCmHandleIds = new ArrayList<>(); - final List<String> nonReadyCmHandleIds = new ArrayList<>(); - for (final String cmHandleId : dataOperationDefinitionIn.getCmHandleIds()) { - if (nonReadyCmHandleIdsLookup.contains(cmHandleId)) { - nonReadyCmHandleIds.add(cmHandleId); + final List<String> nonExistingCmHandleReferences = new ArrayList<>(); + final List<String> nonReadyCmHandleReferences = new ArrayList<>(); + for (final String cmHandleReference : dataOperationDefinitionIn.getCmHandleReferences()) { + if (nonReadyCmHandleReferencesLookup.containsKey(cmHandleReference) + || nonReadyCmHandleReferencesLookup.containsValue(cmHandleReference)) { + nonReadyCmHandleReferences.add(cmHandleReference); } else { + final String cmHandleId = getCmHandleId(cmHandleReference, yangModelCmHandles); final String dmiServiceName = dmiServiceNamesPerCmHandleId.get(cmHandleId); final Map<String, String> cmHandleIdProperties = dmiPropertiesPerCmHandleIdPerServiceName.get(dmiServiceName).get(cmHandleId); if (cmHandleIdProperties == null) { - nonExistingCmHandleIds.add(cmHandleId); + nonExistingCmHandleReferences.add(cmHandleReference); } else { final DmiDataOperation dmiBatchOperationOut = getOrAddDmiBatchOperation(dmiServiceName, dataOperationDefinitionIn, dmiDataOperationsOutPerDmiServiceName); @@ -105,14 +107,14 @@ public class DmiDataOperationsHelper { } } } - populateCmHandleIdsPerOperationIdPerResponseCode(cmHandleIdsPerResponseCodesPerOperation, + populateCmHandleIdsPerOperationIdPerResponseCode(cmHandleReferencesPerResponseCodesPerOperation, DmiDataOperation.buildDmiDataOperationRequestBodyWithoutCmHandles(dataOperationDefinitionIn), - CM_HANDLES_NOT_FOUND, nonExistingCmHandleIds); - populateCmHandleIdsPerOperationIdPerResponseCode(cmHandleIdsPerResponseCodesPerOperation, + CM_HANDLES_NOT_FOUND, nonExistingCmHandleReferences); + populateCmHandleIdsPerOperationIdPerResponseCode(cmHandleReferencesPerResponseCodesPerOperation, DmiDataOperation.buildDmiDataOperationRequestBodyWithoutCmHandles(dataOperationDefinitionIn), - CM_HANDLES_NOT_READY, nonReadyCmHandleIds); + CM_HANDLES_NOT_READY, nonReadyCmHandleReferences); } - publishErrorMessageToClientTopic(topicParamInQuery, requestId, cmHandleIdsPerResponseCodesPerOperation); + publishErrorMessageToClientTopic(topicParamInQuery, requestId, cmHandleReferencesPerResponseCodesPerOperation); return dmiDataOperationsOutPerDmiServiceName; } @@ -182,10 +184,26 @@ public class DmiDataOperationsHelper { return dmiBatchOperationsOut.get(dmiBatchOperationsOut.size() - 1); } - private static Set<String> filterAndGetNonReadyCmHandleIds(final Collection<YangModelCmHandle> yangModelCmHandles) { - return yangModelCmHandles.stream() - .filter(yangModelCmHandle -> yangModelCmHandle.getCompositeState().getCmHandleState() - != CmHandleState.READY).map(YangModelCmHandle::getId).collect(Collectors.toSet()); + private static Map<String, String> filterAndGetNonReadyCmHandleReferences( + final Collection<YangModelCmHandle> yangModelCmHandles) { + final Map<String, String> cmHandleReferenceMap = new HashMap<>(yangModelCmHandles.size()); + for (final YangModelCmHandle yangModelCmHandle: yangModelCmHandles) { + if (yangModelCmHandle.getCompositeState().getCmHandleState() != CmHandleState.READY) { + cmHandleReferenceMap.put(yangModelCmHandle.getId(), yangModelCmHandle.getAlternateId()); + } + } + return cmHandleReferenceMap; + } + + private static String getCmHandleId(final String cmHandleReference, + final Collection<YangModelCmHandle> yangModelCmHandles) { + for (final YangModelCmHandle yangModelCmHandle: yangModelCmHandles) { + if (cmHandleReference.equals(yangModelCmHandle.getId()) + || cmHandleReference.equals(yangModelCmHandle.getAlternateId())) { + return yangModelCmHandle.getId(); + } + } + return cmHandleReference; } private static void populateCmHandleIdsPerOperationIdPerResponseCode(final MultiValueMap<DmiDataOperation, diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java index 850edf7d57..de8e8e80a7 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java @@ -72,6 +72,14 @@ public interface InventoryPersistence extends NcmpPersistence { Collection<YangModelCmHandle> getYangModelCmHandles(Collection<String> cmHandleIds); /** + * This method retrieves DMI service name, DMI properties and the state for a given list of cm handle references. + * + * @param cmHandleReferences a list of the ids of the cm handles + * @return collection of yang model cm handles + */ + Collection<YangModelCmHandle> getYangModelCmHandlesFromCmHandleReferences(Collection<String> cmHandleReferences); + + /** * Method to return module definitions by cmHandleId. * * @param cmHandleId cm handle ID diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java index 655d8437b1..d73fae9fbc 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java @@ -22,6 +22,7 @@ package org.onap.cps.ncmp.impl.inventory; +import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS; import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS; import com.google.common.collect.Lists; @@ -33,6 +34,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsAnchorService; import org.onap.cps.api.CpsDataService; @@ -133,6 +135,19 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv } @Override + public Collection<YangModelCmHandle> getYangModelCmHandlesFromCmHandleReferences( + final Collection<String> cmHandleReferences) { + + final String cpsPathForCmHandlesByReferences = getCpsPathForCmHandlesByReferences(cmHandleReferences); + + final Collection<DataNode> cmHandlesAsDataNodes = + cmHandleQueryService.queryNcmpRegistryByCpsPath( + cpsPathForCmHandlesByReferences, INCLUDE_ALL_DESCENDANTS); + + return YangDataConverter.toYangModelCmHandles(cmHandlesAsDataNodes); + } + + @Override public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleId(final String cmHandleId) { return cpsModuleService.getModuleDefinitionsByAnchorName(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId); } @@ -190,7 +205,8 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv return Collections.emptyList(); } final String cpsPathForCmHandlesByAlternateIds = getCpsPathForCmHandlesByAlternateIds(alternateIds); - return cmHandleQueryService.queryNcmpRegistryByCpsPath(cpsPathForCmHandlesByAlternateIds, OMIT_DESCENDANTS); + return cmHandleQueryService.queryNcmpRegistryByCpsPath(cpsPathForCmHandlesByAlternateIds, + INCLUDE_ALL_DESCENDANTS); } @Override @@ -234,6 +250,12 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@alternate-id='", "']")); } + private String getCpsPathForCmHandlesByReferences(final Collection<String> cmHandleReferences) { + return cmHandleReferences.stream() + .flatMap(id -> Stream.of("@id='" + id + "'", "@alternate-id='" + id + "'")) + .collect(Collectors.joining(" or ", NCMP_DMI_REGISTRY_PARENT + "/cm-handles[", "]")); + } + private static String createStateJsonData(final String state) { return "{\"state\":" + state + "}"; } 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 fd76abb581..b046c12387 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 @@ -112,7 +112,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { mockYangModelCmHandleCollectionRetrieval([yangModelCmHandleProperty]) def dataOperationBatchRequestJsonData = TestUtils.getResourceFileContent('dataOperationRequest.json') def dataOperationRequest = spiedJsonObjectMapper.convertJsonString(dataOperationBatchRequestJsonData, DataOperationRequest.class) - dataOperationRequest.dataOperationDefinitions[0].cmHandleIds = [cmHandleId] + dataOperationRequest.dataOperationDefinitions[0].cmHandleReferences = [cmHandleId] and: 'a positive response from DMI service when it is called with valid request parameters' def responseFromDmi = Mono.just(new ResponseEntity<Object>(HttpStatus.ACCEPTED)) def expectedUrlTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/data?requestId={requestId}&topic={topic}', ['requestId': 'requestId', 'topic': 'my-topic-name']) @@ -129,7 +129,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { mockYangModelCmHandleCollectionRetrieval([yangModelCmHandleProperty]) def dataOperationBatchRequestJsonData = TestUtils.getResourceFileContent('dataOperationRequest.json') def dataOperationRequest = spiedJsonObjectMapper.convertJsonString(dataOperationBatchRequestJsonData, DataOperationRequest.class) - dataOperationRequest.dataOperationDefinitions[0].cmHandleIds = [cmHandleId] + dataOperationRequest.dataOperationDefinitions[0].cmHandleReferences = [cmHandleId] and: 'the published cloud event will be captured' def actualDataOperationCloudEvent = null eventsPublisher.publishCloudEvent('my-topic-name', 'my-request-id', _) >> { args -> actualDataOperationCloudEvent = args[2] } @@ -143,7 +143,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { assert eventDataValue.statusMessage == UNKNOWN_ERROR.message and: 'the event contains the correct operation details' assert eventDataValue.operationId == dataOperationRequest.dataOperationDefinitions[0].operationId - assert eventDataValue.ids == dataOperationRequest.dataOperationDefinitions[0].cmHandleIds + assert eventDataValue.ids == dataOperationRequest.dataOperationDefinitions[0].cmHandleReferences } def 'call get all resource data.'() { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy index d5db24cc33..d5f705f2fd 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy @@ -73,7 +73,7 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { and: 'notification feature is turned on/off' objectUnderTest.notificationFeatureEnabled = notificationFeatureEnabled when: 'data operation request is executed' - def dataOperationDefinition = new DataOperationDefinition(operation: 'read', datastore: 'ncmp-datastore:passthrough-running', cmHandleIds: ['ch']) + def dataOperationDefinition = new DataOperationDefinition(operation: 'read', datastore: 'ncmp-datastore:passthrough-running', cmHandleReferences: ['ch']) def result = objectUnderTest.executeAsynchronousRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition]), NO_AUTH_HEADER) then: 'the task is executed in an async fashion or not' expectedCalls * dmiDataOperations.requestResourceDataFromDmi('someTopic', _, _, NO_AUTH_HEADER) @@ -120,7 +120,7 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { given: 'a data operation definition with too many cm handles' def tooMany = objectUnderTest.MAXIMUM_CM_HANDLES_PER_OPERATION + 1 def cmHandleIds = new String[tooMany] - def dataOperationDefinition = new DataOperationDefinition(operationId: 'abc', operation: 'read', datastore: 'ncmp-datastore:passthrough-running', cmHandleIds: cmHandleIds) + def dataOperationDefinition = new DataOperationDefinition(operationId: 'abc', operation: 'read', datastore: 'ncmp-datastore:passthrough-running', cmHandleReferences: cmHandleIds) when: 'data operation request is executed' objectUnderTest.executeAsynchronousRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition]), NO_AUTH_HEADER) then: 'a payload too large exception is thrown' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy index 84eafb0da3..77e2c4fa25 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy @@ -74,15 +74,16 @@ class DmiDataOperationsHelperSpec extends MessagingBaseSpec { assert dmiDataOperationRequestBodyAsJsonNode.get('operationId').asText() == expectedOperationId assert dmiDataOperationRequestBodyAsJsonNode.get('datastore').asText() == expectedDatastore and: 'the correct cm handles (just for #serviceName)' - assert dmiDataOperationRequestBodyAsJsonNode.get('cmHandles').size() == expectedCmHandleIds.size() - expectedCmHandleIds.each { + assert dmiDataOperationRequestBodyAsJsonNode.get('cmHandles').size() == expectedCmHandleReferences.size() + expectedCmHandleReferences.each { dmiDataOperationRequestBodyAsJsonNode.get('cmHandles').toString().contains(it) } where: 'the following dmi service and operations are checked' - serviceName | operationIndex || expectedOperationId | expectedDatastore | expectedCmHandleIds + serviceName | operationIndex || expectedOperationId | expectedDatastore | expectedCmHandleReferences 'dmi1' | 0 || 'operational-14' | 'ncmp-datastore:passthrough-operational' | ['ch6-dmi1'] 'dmi1' | 1 || 'running-12' | 'ncmp-datastore:passthrough-running' | ['ch1-dmi1', 'ch2-dmi1'] 'dmi1' | 2 || 'operational-15' | 'ncmp-datastore:passthrough-operational' | ['ch6-dmi1'] + 'dmi1' | 3 || 'operational-16' | 'ncmp-datastore:passthrough-operational' | ['alt6-dmi1'] 'dmi2' | 0 || 'operational-14' | 'ncmp-datastore:passthrough-operational' | ['ch3-dmi2'] 'dmi2' | 1 || 'running-12' | 'ncmp-datastore:passthrough-running' | ['ch7-dmi2'] 'dmi2' | 2 || 'operational-15' | 'ncmp-datastore:passthrough-operational' | ['ch4-dmi2'] @@ -137,14 +138,14 @@ class DmiDataOperationsHelperSpec extends MessagingBaseSpec { def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')] def readyState = new CompositeStateBuilder().withCmHandleState(READY).withLastUpdatedTimeNow().build() def advisedState = new CompositeStateBuilder().withCmHandleState(ADVISED).withLastUpdatedTimeNow().build() - return [new YangModelCmHandle(id: 'ch1-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState), - new YangModelCmHandle(id: 'ch2-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState), - new YangModelCmHandle(id: 'ch6-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState), - new YangModelCmHandle(id: 'ch8-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState), - new YangModelCmHandle(id: 'ch3-dmi2', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: readyState), - new YangModelCmHandle(id: 'ch4-dmi2', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: readyState), - new YangModelCmHandle(id: 'ch7-dmi2', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: readyState), - new YangModelCmHandle(id: 'non-ready-cm-handle', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: advisedState) + return [new YangModelCmHandle(id: 'ch1-dmi1', 'alternateId': 'alt1-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState), + new YangModelCmHandle(id: 'ch2-dmi1', 'alternateId': 'alt2-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState), + new YangModelCmHandle(id: 'ch6-dmi1', 'alternateId': 'alt6-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState), + new YangModelCmHandle(id: 'ch8-dmi1', 'alternateId': 'alt8-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState), + new YangModelCmHandle(id: 'ch3-dmi2', 'alternateId': 'alt3-dmi2', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: readyState), + new YangModelCmHandle(id: 'ch4-dmi2', 'alternateId': 'alt4-dmi2', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: readyState), + new YangModelCmHandle(id: 'ch7-dmi2', 'alternateId': 'alt7-dmi2', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: readyState), + new YangModelCmHandle(id: 'non-ready-cm-handle', 'alternateId': 'non-ready-alternate', dmiServiceName: 'dmi2', dmiProperties: dmiProperties, compositeState: advisedState) ] } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiOperationsBaseSpec.groovy index 65fda8718c..d00d3ab8f6 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiOperationsBaseSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiOperationsBaseSpec.groovy @@ -61,7 +61,7 @@ abstract class DmiOperationsBaseSpec extends Specification { def mockYangModelCmHandleCollectionRetrieval(dmiProperties) { populateYangModelCmHandle(dmiProperties, '') - mockInventoryPersistence.getYangModelCmHandles(_) >> [yangModelCmHandle] + mockInventoryPersistence.getYangModelCmHandlesFromCmHandleReferences(_) >> [yangModelCmHandle] } def populateYangModelCmHandle(dmiProperties, moduleSetTag) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy index e2261f4b7c..34d9374f78 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy @@ -38,7 +38,6 @@ import org.onap.cps.spi.model.ModuleDefinition import org.onap.cps.spi.model.ModuleReference import org.onap.cps.utils.ContentType import org.onap.cps.utils.JsonObjectMapper -import org.testcontainers.shaded.com.fasterxml.jackson.databind.introspect.BasicClassIntrospector import spock.lang.Shared import spock.lang.Specification @@ -75,12 +74,16 @@ class InventoryPersistenceImplSpec extends Specification { .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC)) def cmHandleId = 'some-cm-handle' - def leaves = ["id":cmHandleId,"dmi-service-name":"common service name","dmi-data-service-name":"data service name","dmi-model-service-name":"model service name"] + def alternateId = 'some-alternate-id' + 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"] def xpath = "/dmi-registry/cm-handles[@id='some-cm-handle']" def cmHandleId2 = 'another-cm-handle' + def alternateId2 = 'another-alternate-id' def xpath2 = "/dmi-registry/cm-handles[@id='another-cm-handle']" + def dataNode = new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/additional-properties[@name='name1']", leaves: ["name":"name1", "value":"value1"]) + @Shared def childDataNodesForCmHandleWithAllProperties = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/additional-properties[@name='name1']", leaves: ["name":"name1", "value":"value1"]), new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/public-properties[@name='name2']", leaves: ["name":"name2","value":"value2"])] @@ -135,7 +138,7 @@ class InventoryPersistenceImplSpec extends Specification { 1 * mockCpsValidator.validateNameCharacters(cmHandleId) } - def "Retrieve multiple YangModelCmHandles"() { + def "Retrieve multiple YangModelCmHandles using cm handle ids"() { given: 'the cps data service returns 2 data nodes from the DMI registry' def dataNodes = [new DataNode(xpath: xpath, leaves: ['id': cmHandleId]), new DataNode(xpath: xpath2, leaves: ['id': cmHandleId2])] mockCpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, [xpath, xpath2] , INCLUDE_ALL_DESCENDANTS) >> dataNodes @@ -146,6 +149,17 @@ class InventoryPersistenceImplSpec extends Specification { assert results.id.containsAll([cmHandleId, cmHandleId2]) } + def "Retrieve multiple YangModelCmHandles using cm handle references"() { + given: 'the cps data service returns 2 data nodes from the DMI registry' + def dataNodes = [new DataNode(xpath: xpath, leaves: ['id': cmHandleId, 'alternate-id':alternateId]), new DataNode(xpath: xpath2, leaves: ['id': cmHandleId2,'alternate-id':alternateId2])] + mockCmHandleQueries.queryNcmpRegistryByCpsPath(_, INCLUDE_ALL_DESCENDANTS) >> dataNodes + when: 'retrieving the yang modelled cm handle' + def results = objectUnderTest.getYangModelCmHandlesFromCmHandleReferences([cmHandleId, cmHandleId2]) + then: 'verify both have returned and cmhandleIds are correct' + assert results.size() == 2 + assert results.id.containsAll([cmHandleId, cmHandleId2]) + } + def 'Get a Cm Handle Composite State'() { given: 'a valid cm handle id' def cmHandleId = 'Some-Cm-Handle' @@ -317,15 +331,6 @@ class InventoryPersistenceImplSpec extends Specification { assert thrownException.getMessage().contains('DataNode not found') } - def 'Get multiple cm handle data nodes by alternate ids'() { - given: 'expected xPath to get cmHandle data node' - def expectedXPath = "/dmi-registry/cm-handles[@alternate-id='A' or @alternate-id='B']" - when: 'getting the cm handle data node' - objectUnderTest.getCmHandleDataNodesByAlternateIds(['A', 'B']) - then: 'query service is invoked with expected xpath' - 1 * mockCmHandleQueries.queryNcmpRegistryByCpsPath(expectedXPath, OMIT_DESCENDANTS) - } - def 'Get multiple cm handle data nodes by alternate ids, passing empty collection'() { when: 'getting the cm handle data node for no alternate ids' objectUnderTest.getCmHandleDataNodesByAlternateIds([]) @@ -372,4 +377,13 @@ class InventoryPersistenceImplSpec extends Specification { then: 'the cps data service method to delete data nodes is invoked once with the same xPaths' 1 * mockCpsDataService.deleteDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, ['xpath1', 'xpath2'], NO_TIMESTAMP); } + + def 'Check if cm handle exists for a given cm handle id'() { + given: 'data service returns a datanode with correct cm handle id' + mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode] + when: 'method is called to check if cm handle exists from cm handle id' + def result = objectUnderTest.isExistingCmHandleId('some-cm-handle') + then: 'check if cm handle id in datanode is equal to given cm handle id' + assert result == true + } } diff --git a/cps-ncmp-service/src/test/resources/dataOperationRequest.json b/cps-ncmp-service/src/test/resources/dataOperationRequest.json index f69b87631f..3faaf2b0dc 100644 --- a/cps-ncmp-service/src/test/resources/dataOperationRequest.json +++ b/cps-ncmp-service/src/test/resources/dataOperationRequest.json @@ -36,6 +36,17 @@ "ch4-dmi2", "ch6-dmi1" ] + }, + { + "operation": "read", + "operationId": "operational-16", + "datastore": "ncmp-datastore:passthrough-operational", + "options": "some option", + "resourceIdentifier": "some resource identifier", + "targetIds": [ + "ch4-dmi2", + "alt6-dmi1" + ] } ] } diff --git a/docs/api/swagger/ncmp/openapi-inventory.yaml b/docs/api/swagger/ncmp/openapi-inventory.yaml index 8552ad53e3..c72f47a428 100644 --- a/docs/api/swagger/ncmp/openapi-inventory.yaml +++ b/docs/api/swagger/ncmp/openapi-inventory.yaml @@ -136,8 +136,8 @@ paths: \ plugin)." operationId: searchCmHandleIds parameters: - - description: Boolean parameter to determine if returned value(s) will be cmHandle - Ids or Alternate Ids for a given query + - description: Boolean parameter to determine if returned value(s) will be cm + handle references for a given query in: query name: outputAlternateId required: false diff --git a/docs/api/swagger/ncmp/openapi.yaml b/docs/api/swagger/ncmp/openapi.yaml index aa732c8566..024aed681c 100644 --- a/docs/api/swagger/ncmp/openapi.yaml +++ b/docs/api/swagger/ncmp/openapi.yaml @@ -698,7 +698,7 @@ paths: schema: $ref: '#/components/schemas/DmiErrorMessage' description: Bad Gateway - summary: Execute a data operation for group of cm handle ids + summary: Execute a data operation for group of cm handle references tags: - network-cm-proxy /v1/ch/{cm-handle}/data/ds/{datastore-name}/query: @@ -1141,8 +1141,8 @@ paths: this query. operationId: searchCmHandleIds parameters: - - description: Boolean parameter to determine if returned value(s) will be cmHandle - Ids or Alternate Ids for a given query + - description: Boolean parameter to determine if returned value(s) will be cm + handle references for a given query in: query name: outputAlternateId required: false @@ -1618,8 +1618,8 @@ components: example: 2024-01-22 type: string outputAlternateIdOptionInQuery: - description: Boolean parameter to determine if returned value(s) will be cmHandle - Ids or Alternate Ids for a given query + description: Boolean parameter to determine if returned value(s) will be cm + handle references for a given query in: query name: outputAlternateId required: false @@ -1789,8 +1789,8 @@ components: type: string targetIds: items: - description: "targeted cm handles, maximum of 50 supported. If this limit\ - \ is exceeded the request wil be refused." + description: "targeted cm handle references, maximum of 200 supported.\ + \ If this limit is exceeded the request wil be refused." example: "[\"da310eecdb8d44c2acc0ddaae01174b1\",\"c748c58f8e0b438f9fd1f28370b17d47\"\ ]" type: string diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/BearerTokenPassthroughSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/BearerTokenPassthroughSpec.groovy index 99e80323c2..a81058fbd6 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/BearerTokenPassthroughSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/BearerTokenPassthroughSpec.groovy @@ -37,11 +37,14 @@ class BearerTokenPassthroughSpec extends CpsIntegrationSpecBase { def setup() { dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2'] - registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG) + dmiDispatcher1.moduleNamesPerCmHandleId['ch-2'] = ['M1', 'M3'] + registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, 'alt-1') + registerCmHandle(DMI1_URL, 'ch-2', NO_MODULE_SET_TAG, 'alt-2') } def cleanup() { deregisterCmHandle(DMI1_URL, 'ch-1') + deregisterCmHandle(DMI1_URL, 'ch-2') } def 'Bearer token is passed from NCMP to DMI in pass-through data operations.'() { @@ -83,7 +86,7 @@ class BearerTokenPassthroughSpec extends CpsIntegrationSpecBase { "operationId": "operational-1", "datastore": "ncmp-datastore:passthrough-running", "resourceIdentifier": "my-resource-id", - "targetIds": ["ch-1"] + "targetIds": ["ch-1","alt-2"] }]}""" mvc.perform(request(POST, '/ncmp/v1/data') .queryParam('topic', 'my-topic') |