diff options
46 files changed, 440 insertions, 672 deletions
diff --git a/checkstyle/pom.xml b/checkstyle/pom.xml index 2676dcbc2c..83f112056c 100644 --- a/checkstyle/pom.xml +++ b/checkstyle/pom.xml @@ -26,7 +26,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.onap.cps</groupId> <artifactId>checkstyle</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <profiles> <profile> diff --git a/cps-application/pom.xml b/cps-application/pom.xml index 4c231a6d4e..ac75c0b8e8 100644 --- a/cps-application/pom.xml +++ b/cps-application/pom.xml @@ -28,7 +28,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-bom/pom.xml b/cps-bom/pom.xml index fb6bdbd1bb..3e88be72b9 100644 --- a/cps-bom/pom.xml +++ b/cps-bom/pom.xml @@ -25,7 +25,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.onap.cps</groupId> <artifactId>cps-bom</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <packaging>pom</packaging> <description>This artifact contains dependencyManagement declarations of all published CPS components.</description> diff --git a/cps-dependencies/pom.xml b/cps-dependencies/pom.xml index 032b7ec264..69ea85917f 100644 --- a/cps-dependencies/pom.xml +++ b/cps-dependencies/pom.xml @@ -27,7 +27,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.onap.cps</groupId> <artifactId>cps-dependencies</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <packaging>pom</packaging> <name>${project.groupId}:${project.artifactId}</name> diff --git a/cps-events/pom.xml b/cps-events/pom.xml index ec62b62e63..fd75c2c87b 100644 --- a/cps-events/pom.xml +++ b/cps-events/pom.xml @@ -24,7 +24,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ncmp-events/pom.xml b/cps-ncmp-events/pom.xml index a6b80e563d..89785caab8 100644 --- a/cps-ncmp-events/pom.xml +++ b/cps-ncmp-events/pom.xml @@ -23,7 +23,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml index e10039995e..9d306927af 100644 --- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml +++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml @@ -22,7 +22,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-ncmp-rest-stub</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> </parent> <artifactId>cps-ncmp-rest-stub-app</artifactId> diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml index a21f96138f..350bb00ffa 100644 --- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml +++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml @@ -21,7 +21,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-ncmp-rest-stub</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> </parent> <artifactId>cps-ncmp-rest-stub-service</artifactId> diff --git a/cps-ncmp-rest-stub/pom.xml b/cps-ncmp-rest-stub/pom.xml index ee76f0a594..3df8fa9db6 100644 --- a/cps-ncmp-rest-stub/pom.xml +++ b/cps-ncmp-rest-stub/pom.xml @@ -22,7 +22,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ncmp-rest/pom.xml b/cps-ncmp-rest/pom.xml index fc3bd8cb92..7e03120c6e 100644 --- a/cps-ncmp-rest/pom.xml +++ b/cps-ncmp-rest/pom.xml @@ -27,7 +27,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java index 1c6aaf2262..b567ba2e73 100755 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java @@ -116,7 +116,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { final DataOperationRequest dataOperationRequest, final String authorization) { return ncmpPassthroughResourceRequestHandler.executeRequest(topicParamInQuery, - dataOperationRequestMapper.toDataOperationRequest(dataOperationRequest)); + dataOperationRequestMapper.toDataOperationRequest(dataOperationRequest), authorization); } /** diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java index 5da8c91207..430b749eff 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java @@ -61,17 +61,19 @@ public class NcmpPassthroughResourceRequestHandler extends NcmpDatastoreRequestH * * @param topicParamInQuery the topic param in query * @param dataOperationRequest data operation request details for resource data + * @param authorization contents of Authorization header, or null if not present * @return the response entity */ public ResponseEntity<Object> executeRequest(final String topicParamInQuery, - final DataOperationRequest - dataOperationRequest) { + final DataOperationRequest dataOperationRequest, + final String authorization) { validateDataOperationRequest(topicParamInQuery, dataOperationRequest); if (!notificationFeatureEnabled) { return ResponseEntity.ok(Map.of("status", "Asynchronous request is unavailable as notification feature is currently disabled.")); } - return getRequestIdAndSendDataOperationRequestToDmiService(topicParamInQuery, dataOperationRequest); + return getRequestIdAndSendDataOperationRequestToDmiService(topicParamInQuery, dataOperationRequest, + authorization); } @Override @@ -89,12 +91,13 @@ public class NcmpPassthroughResourceRequestHandler extends NcmpDatastoreRequestH authorization); } - private ResponseEntity<Object> getRequestIdAndSendDataOperationRequestToDmiService(final String topicParamInQuery, - final DataOperationRequest - dataOperationRequest) { + private ResponseEntity<Object> getRequestIdAndSendDataOperationRequestToDmiService( + final String topicParamInQuery, + final DataOperationRequest dataOperationRequest, + final String authorization) { final String requestId = UUID.randomUUID().toString(); cpsNcmpTaskExecutor.executeTask( - getTaskSupplierForDataOperationRequest(topicParamInQuery, dataOperationRequest, requestId), + getTaskSupplierForDataOperationRequest(topicParamInQuery, dataOperationRequest, requestId, authorization), timeOutInMilliSeconds); return ResponseEntity.ok(Map.of("requestId", requestId)); } @@ -116,11 +119,13 @@ public class NcmpPassthroughResourceRequestHandler extends NcmpDatastoreRequestH private Supplier<Object> getTaskSupplierForDataOperationRequest(final String topicParamInQuery, final DataOperationRequest dataOperationRequest, - final String requestId) { + final String requestId, + final String authorization) { return () -> { networkCmProxyDataService.executeDataOperationForCmHandles(topicParamInQuery, dataOperationRequest, - requestId); + requestId, + authorization); return noReturn; }; } diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy index 328a85e714..ddeac519c3 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy @@ -74,7 +74,7 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { and: 'notification feature is turned on/off' objectUnderTest.notificationFeatureEnabled = notificationFeatureEnabled when: 'data operation request is executed' - objectUnderTest.executeRequest('someTopic', new DataOperationRequest()) + objectUnderTest.executeRequest('someTopic', new DataOperationRequest(), NO_AUTH_HEADER) then: 'the task is executed in an async fashion or not' expectedCalls * spiedCpsNcmpTaskExecutor.executeTask(*_) where: 'the following parameters are used' @@ -92,11 +92,11 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { and: ' a flag to track the network service call' def networkServiceMethodCalled = false and: 'the (mocked) service will use the flag to indicate it is called' - mockNetworkCmProxyDataService.executeDataOperationForCmHandles('myTopic', dataOperationRequest, _) >> { + mockNetworkCmProxyDataService.executeDataOperationForCmHandles('myTopic', dataOperationRequest, _, NO_AUTH_HEADER) >> { networkServiceMethodCalled = true } when: 'data operation request is executed' - objectUnderTest.executeRequest('myTopic', dataOperationRequest) + objectUnderTest.executeRequest('myTopic', dataOperationRequest, NO_AUTH_HEADER) then: 'the task is executed in an async fashion' 1 * spiedCpsNcmpTaskExecutor.executeTask(*_) and: 'the network service is invoked' @@ -114,7 +114,7 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { def dataOperationDefinition = new DataOperationDefinition(operation: 'read', datastore: datastore) when: 'data operation request is executed' def dataOperationRequest = new DataOperationRequest(dataOperationDefinitions: [dataOperationDefinition]) - objectUnderTest.executeRequest('myTopic', dataOperationRequest) + objectUnderTest.executeRequest('myTopic', dataOperationRequest, NO_AUTH_HEADER) then: 'the correct error is thrown' def thrown = thrown(InvalidDatastoreException) assert thrown.message.contains(expectedErrorMessage) @@ -130,7 +130,7 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { and: 'a data operation definition with operation: #operation' def dataOperationDefinition = new DataOperationDefinition(operation: operation, datastore: 'ncmp-datastore:passthrough-running') when: 'bulk request is executed' - objectUnderTest.executeRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition])) + objectUnderTest.executeRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition]), NO_AUTH_HEADER) then: 'the expected type of exception is thrown' thrown(expectedException) where: 'the following operations are used' diff --git a/cps-ncmp-service/pom.xml b/cps-ncmp-service/pom.xml index bdc23046ec..4feb676444 100644 --- a/cps-ncmp-service/pom.xml +++ b/cps-ncmp-service/pom.xml @@ -27,7 +27,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java index dbfeca1804..4230140d26 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java @@ -89,10 +89,13 @@ public interface NetworkCmProxyDataService { * * @param topicParamInQuery topic name for (triggering) async responses * @param dataOperationRequest contains a list of operation definitions(multiple operations) + * @param requestId request ID + * @param authorization contents of Authorization header, or null if not present */ void executeDataOperationForCmHandles(String topicParamInQuery, DataOperationRequest dataOperationRequest, - String requestId); + String requestId, + String authorization); /** diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index 3e304a4fd0..4c905bf90f 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -154,10 +154,11 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService @Override public void executeDataOperationForCmHandles(final String topicParamInQuery, - final DataOperationRequest - dataOperationRequest, - final String requestId) { - dmiDataOperations.requestResourceDataFromDmi(topicParamInQuery, dataOperationRequest, requestId); + final DataOperationRequest dataOperationRequest, + final String requestId, + final String authorization) { + dmiDataOperations.requestResourceDataFromDmi(topicParamInQuery, dataOperationRequest, requestId, + authorization); } @Override @@ -423,7 +424,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final List<NcmpServiceCmHandle> cmHandlesToBeCreated, final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses) { final Collection<String> rejectedCmHandleIds = alternateIdChecker - .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated); + .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated, AlternateIdChecker.Operation.CREATE); cmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponses( rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED)); return rejectedCmHandleIds; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java index f5d22af281..3d15291633 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java @@ -22,6 +22,7 @@ package org.onap.cps.ncmp.api.impl; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED; 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.impl.NetworkCmProxyDataServicePropertyHandler.PropertyType.DMI_PROPERTY; @@ -46,8 +47,6 @@ import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsDataService; import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker; -import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse; import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; import org.onap.cps.spi.exceptions.DataNodeNotFoundException; @@ -70,67 +69,76 @@ public class NetworkCmProxyDataServicePropertyHandler { private final AlternateIdChecker alternateIdChecker; /** - * Iterates over incoming ncmpServiceCmHandles and update the dataNodes based on the updated attributes. + * Iterates over incoming updatedNcmpServiceCmHandles and update the dataNodes based on the updated attributes. * The attributes which are not passed will remain as is. * - * @param ncmpServiceCmHandles collection of ncmpServiceCmHandles + * @param updatedNcmpServiceCmHandles collection of CmHandles */ public List<CmHandleRegistrationResponse> updateCmHandleProperties( - final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles) { - final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses - = new ArrayList<>(ncmpServiceCmHandles.size()); - for (final NcmpServiceCmHandle ncmpServiceCmHandle : ncmpServiceCmHandles) { - final String cmHandleId = ncmpServiceCmHandle.getCmHandleId(); - try { - final DataNode existingCmHandleDataNode = inventoryPersistence - .getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next(); - updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle); - processUpdates(existingCmHandleDataNode, ncmpServiceCmHandle); - cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)); - } catch (final DataNodeNotFoundException e) { - log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", cmHandleId, e.getMessage()); - cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND)); - } catch (final DataValidationException e) { - log.error("Unable to update cm handle : {}, caused by : {}", cmHandleId, e.getMessage()); - cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID)); - } catch (final Exception exception) { - log.error("Unable to update cmHandle : {} , caused by : {}", cmHandleId, exception.getMessage()); - cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception)); + final Collection<NcmpServiceCmHandle> updatedNcmpServiceCmHandles) { + final Collection<String> rejectedCmHandleIds = alternateIdChecker + .getIdsOfCmHandlesWithRejectedAlternateId(updatedNcmpServiceCmHandles, AlternateIdChecker.Operation.UPDATE); + final List<CmHandleRegistrationResponse> failureResponses = + CmHandleRegistrationResponse.createFailureResponses(rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED); + final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(failureResponses); + for (final NcmpServiceCmHandle updatedNcmpServiceCmHandle : updatedNcmpServiceCmHandles) { + final String cmHandleId = updatedNcmpServiceCmHandle.getCmHandleId(); + if (!rejectedCmHandleIds.contains(cmHandleId)) { + try { + final DataNode existingCmHandleDataNode = inventoryPersistence + .getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next(); + processUpdates(existingCmHandleDataNode, updatedNcmpServiceCmHandle); + cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)); + } catch (final DataNodeNotFoundException e) { + log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", cmHandleId, + e.getMessage()); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND)); + } catch (final DataValidationException e) { + log.error("Unable to update cm handle : {}, caused by : {}", cmHandleId, e.getMessage()); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID)); + } catch (final Exception exception) { + log.error("Unable to update cmHandle : {} , caused by : {}", cmHandleId, exception.getMessage()); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception)); + } } } return cmHandleRegistrationResponses; } - private void updateAlternateId(final DataNode existingCmHandleDataNode, - final NcmpServiceCmHandle ncmpServiceCmHandle) { - final YangModelCmHandle yangModelCmHandle = - YangDataConverter.convertCmHandleToYangModel(existingCmHandleDataNode); - final String currentAlternateId = yangModelCmHandle.getAlternateId(); - final String newAlternateId = ncmpServiceCmHandle.getAlternateId(); - if (alternateIdChecker.canApplyAlternateId(ncmpServiceCmHandle.getCmHandleId(), - currentAlternateId, newAlternateId)) { - setAndUpdateAlternateId(yangModelCmHandle, newAlternateId); + private void processUpdates(final DataNode existingCmHandleDataNode, + final NcmpServiceCmHandle updatedNcmpServiceCmHandle) { + updateAlternateId(updatedNcmpServiceCmHandle); + if (!updatedNcmpServiceCmHandle.getPublicProperties().isEmpty()) { + updateProperties(existingCmHandleDataNode, PUBLIC_PROPERTY, + updatedNcmpServiceCmHandle.getPublicProperties()); + } + if (!updatedNcmpServiceCmHandle.getDmiProperties().isEmpty()) { + updateProperties(existingCmHandleDataNode, DMI_PROPERTY, updatedNcmpServiceCmHandle.getDmiProperties()); } } - private void processUpdates(final DataNode existingCmHandleDataNode, final NcmpServiceCmHandle incomingCmHandle) { - if (!incomingCmHandle.getPublicProperties().isEmpty()) { - updateProperties(existingCmHandleDataNode, PUBLIC_PROPERTY, incomingCmHandle.getPublicProperties()); - } - if (!incomingCmHandle.getDmiProperties().isEmpty()) { - updateProperties(existingCmHandleDataNode, DMI_PROPERTY, incomingCmHandle.getDmiProperties()); - } + private void updateAlternateId(final NcmpServiceCmHandle updatedNcmpServiceCmHandle) { + final String updatedAlternateId = updatedNcmpServiceCmHandle.getAlternateId(); + final String cmHandleId = updatedNcmpServiceCmHandle.getCmHandleId(); + final Map<String, String> cmHandleProperties = new HashMap<>(2); + cmHandleProperties.put("id", cmHandleId); + cmHandleProperties.put("alternate-id", updatedAlternateId); + final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1); + dmiRegistryProperties.put("cm-handles", cmHandleProperties); + cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT, + jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now()); + log.debug("Updating alternateId for cmHandle {} with value : {})", cmHandleId, updatedAlternateId); } private void updateProperties(final DataNode existingCmHandleDataNode, final PropertyType propertyType, - final Map<String, String> incomingProperties) { + final Map<String, String> updatedProperties) { final Collection<DataNode> replacementPropertyDataNodes = - getReplacementDataNodes(existingCmHandleDataNode, propertyType, incomingProperties); + getReplacementDataNodes(existingCmHandleDataNode, propertyType, updatedProperties); replacementPropertyDataNodes.addAll( - getUnchangedPropertyDataNodes(existingCmHandleDataNode, propertyType, incomingProperties)); + getUnchangedPropertyDataNodes(existingCmHandleDataNode, propertyType, updatedProperties)); if (replacementPropertyDataNodes.isEmpty()) { removeAllProperties(existingCmHandleDataNode, propertyType); } else { @@ -149,13 +157,14 @@ public class NetworkCmProxyDataServicePropertyHandler { } private Collection<DataNode> getUnchangedPropertyDataNodes(final DataNode existingCmHandleDataNode, - final PropertyType propertyType, final Map<String, String> incomingProperties) { + final PropertyType propertyType, + final Map<String, String> updatedProperties) { final Collection<DataNode> unchangedPropertyDataNodes = new HashSet<>(); for (final DataNode existingPropertyDataNode : existingCmHandleDataNode.getChildDataNodes()) { final Matcher matcher = propertyType.propertyXpathPattern.matcher(existingPropertyDataNode.getXpath()); if (matcher.find()) { final String keyName = matcher.group(2); - if (!incomingProperties.containsKey(keyName)) { + if (!updatedProperties.containsKey(keyName)) { unchangedPropertyDataNodes.add(existingPropertyDataNode); } } @@ -164,9 +173,10 @@ public class NetworkCmProxyDataServicePropertyHandler { } private Collection<DataNode> getReplacementDataNodes(final DataNode existingCmHandleDataNode, - final PropertyType propertyType, final Map<String, String> incomingProperties) { + final PropertyType propertyType, + final Map<String, String> updatedProperties) { final Collection<DataNode> replacementPropertyDataNodes = new HashSet<>(); - incomingProperties.forEach((updatedAttributeKey, updatedAttributeValue) -> { + updatedProperties.forEach((updatedAttributeKey, updatedAttributeValue) -> { final String propertyXpath = getAttributeXpath(existingCmHandleDataNode, propertyType, updatedAttributeKey); if (updatedAttributeValue != null) { log.info("Creating a new DataNode with xpath {} , key : {} and value : {}", propertyXpath, @@ -179,7 +189,7 @@ public class NetworkCmProxyDataServicePropertyHandler { } private String getAttributeXpath(final DataNode cmHandle, final PropertyType propertyType, - final String attributeKey) { + final String attributeKey) { return cmHandle.getXpath() + "/" + propertyType.xpathPrefix + String.format("[@name='%s']", attributeKey); } @@ -192,17 +202,6 @@ public class NetworkCmProxyDataServicePropertyHandler { return new DataNodeBuilder().withXpath(xpath).withLeaves(ImmutableMap.copyOf(updatedLeaves)).build(); } - private void setAndUpdateAlternateId(final YangModelCmHandle upgradedCmHandle, final String alternateId) { - final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1); - final Map<String, String> cmHandleProperties = new HashMap<>(2); - cmHandleProperties.put("id", upgradedCmHandle.getId()); - cmHandleProperties.put("alternate-id", alternateId); - dmiRegistryProperties.put("cm-handles", cmHandleProperties); - cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT, - jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now()); - log.info("Updating alternateId for cmHandle {} with value : {})", upgradedCmHandle.getId(), alternateId); - } - enum PropertyType { DMI_PROPERTY("additional-properties"), PUBLIC_PROPERTY("public-properties"); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java index 05b6ec3001..a77e78a2e2 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java @@ -132,10 +132,12 @@ public class DmiDataOperations extends DmiOperations { * @param topicParamInQuery topic name for (triggering) async responses * @param dataOperationRequest data operation request to execute operations * @param requestId requestId for as a response + * @param authorization contents of Authorization header, or null if not present */ public void requestResourceDataFromDmi(final String topicParamInQuery, final DataOperationRequest dataOperationRequest, - final String requestId) { + final String requestId, + final String authorization) { final Set<String> cmHandlesIds = getDistinctCmHandleIdsFromDataOperationRequest(dataOperationRequest); @@ -147,7 +149,8 @@ public class DmiDataOperations extends DmiOperations { = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(topicParamInQuery, requestId, dataOperationRequest, yangModelCmHandles); - buildDataOperationRequestUrlAndSendToDmiService(topicParamInQuery, requestId, operationsOutPerDmiServiceName); + buildDataOperationRequestUrlAndSendToDmiService(topicParamInQuery, requestId, operationsOutPerDmiServiceName, + authorization); } /** @@ -238,23 +241,26 @@ public class DmiDataOperations extends DmiOperations { private void buildDataOperationRequestUrlAndSendToDmiService(final String topicParamInQuery, final String requestId, final Map<String, List<DmiDataOperation>> - groupsOutPerDmiServiceName) { + groupsOutPerDmiServiceName, + final String authorization) { groupsOutPerDmiServiceName.forEach((dmiServiceName, dmiDataOperationRequestBodies) -> { final String dmiDataOperationResourceUrl = getDmiServiceDataOperationRequestUrl(dmiServiceName, topicParamInQuery, requestId); - sendDataOperationRequestToDmiService(dmiDataOperationResourceUrl, dmiDataOperationRequestBodies); + sendDataOperationRequestToDmiService(dmiDataOperationResourceUrl, dmiDataOperationRequestBodies, + authorization); }); } private void sendDataOperationRequestToDmiService(final String dataOperationResourceUrl, - final List<DmiDataOperation> dmiDataOperationRequestBodies) { + final List<DmiDataOperation> dmiDataOperationRequestBodies, + final String authorization) { final DmiDataOperationRequest dmiDataOperationRequest = DmiDataOperationRequest.builder() .operations(dmiDataOperationRequestBodies).build(); final String dmiDataOperationRequestAsJsonString = jsonObjectMapper.asJsonString(dmiDataOperationRequest); TaskExecutor.executeTask(() -> dmiRestClient.postOperationWithJsonData(dataOperationResourceUrl, - dmiDataOperationRequestAsJsonString, READ, null), + dmiDataOperationRequestAsJsonString, READ, authorization), DEFAULT_ASYNC_TASK_EXECUTOR_TIMEOUT_IN_MILLISECONDS) .whenCompleteAsync((response, throwable) -> handleTaskCompletionException(throwable, dataOperationResourceUrl, dmiDataOperationRequestBodies)); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java index 4ac6537494..f14439f690 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java @@ -38,6 +38,10 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class AlternateIdChecker { + public enum Operation { + CREATE, UPDATE + } + private final InventoryPersistence inventoryPersistence; private static final String NO_CURRENT_ALTERNATE_ID = ""; @@ -96,15 +100,16 @@ public class AlternateIdChecker { } /** - * Check all alternate ids of a batch of NEW cm handles. + * Check all alternate ids of a batch of cm handles. * Includes cross-checks in the batch itself for duplicates. Only the first entry encountered wil be accepted. - * This method can only be used for NEW cm handle registrations NOT for updating existing ones * * @param newNcmpServiceCmHandles the proposed new cm handles + * @param operation type of operation being executed * @return collection of cm handles ids which are acceptable */ public Collection<String> getIdsOfCmHandlesWithRejectedAlternateId( - final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles) { + final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles, + final Operation operation) { final Set<String> acceptedAlternateIds = new HashSet<>(newNcmpServiceCmHandles.size()); final Collection<String> rejectedCmHandleIds = new ArrayList<>(); for (final NcmpServiceCmHandle ncmpServiceCmHandle : newNcmpServiceCmHandles) { @@ -119,7 +124,11 @@ public class AlternateIdChecker { log.warn("Alternate id update ignored, cannot update cm handle {}, alternate id is already " + "assigned to a different cm handle (in this batch)", cmHandleId); } else { - isAcceptable = canApplyAlternateId(cmHandleId, NO_CURRENT_ALTERNATE_ID, proposedAlternateId); + if (Operation.CREATE.equals(operation)) { + isAcceptable = canApplyAlternateId(cmHandleId, NO_CURRENT_ALTERNATE_ID, proposedAlternateId); + } else { + isAcceptable = canApplyAlternateId(cmHandleId, proposedAlternateId); + } } } if (isAcceptable) { 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 cb7e1ef8a9..fbfbac59e0 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 @@ -78,7 +78,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def setup() { // always accept all cm handles - mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> [] + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [] // always can find all cm handles in DB mockInventoryPersistence.getYangModelCmHandles(_) >> { args -> args[0].collect { new YangModelCmHandle(id:it) } } @@ -418,14 +418,4 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { 'an unexpected exception' | 'cmhandle' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' } - def 'Adding data to alternate id caches.'() { - given: 'a registration with three CM Handles to be created' - 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 * mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(ncmpServiceCmHandles) >> ['cmhandle1'] - } - } 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 71380d46a6..74016e4c0c 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 @@ -158,9 +158,9 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { given: 'cpsDataService returns valid data node' def dataOperationRequest = getDataOperationRequest(datastoreName) when: 'request resource data for data operation is called' - objectUnderTest.executeDataOperationForCmHandles('some topic', dataOperationRequest, 'requestId') + objectUnderTest.executeDataOperationForCmHandles('some topic', dataOperationRequest, 'requestId', NO_AUTH_HEADER) then: 'request resource data for data operation returns expected response' - 1 * mockDmiDataOperations.requestResourceDataFromDmi('some topic', dataOperationRequest, 'requestId') + 1 * mockDmiDataOperations.requestResourceDataFromDmi('some topic', dataOperationRequest, 'requestId', NO_AUTH_HEADER) where: 'the following data stores are used' datastoreName << [PASSTHROUGH_RUNNING.datastoreName, PASSTHROUGH_OPERATIONAL.datastoreName] } @@ -274,7 +274,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle] mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle] and: 'no rejected cm handles because of alternate ids' - mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> [] + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [] when: 'parse and create cm handle in dmi registration then sync module' mockDmiPluginRegistration.createdCmHandles = ['test-cm-handle-id'] objectUnderTest.processCreatedCmHandles(mockDmiPluginRegistration, new DmiPluginRegistrationResponse()) 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 e00a42674b..cbed4177bd 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 @@ -49,6 +49,12 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { def mockAlternateIdChecker = Mock(AlternateIdChecker) def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper, mockAlternateIdChecker) + + def setup() { + // Always accept all alternate IDs + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [] + } + def static cmHandleId = 'myHandle1' def static cmHandleXpath = "/dmi-registry/cm-handles[@id='${cmHandleId}']" @@ -66,7 +72,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { when: 'update data node leaves is called with the update request' objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) then: 'the replace list method is called with correct params' - 1 * mockInventoryPersistence.replaceListContent(cmHandleXpath,_) >> { args -> + 1 * mockInventoryPersistence.replaceListContent(cmHandleXpath, _) >> { args -> { assert args[1].leaves.size() == expectedPropertiesAfterUpdate.size() assert args[1].leaves.containsAll(convertToProperties(expectedPropertiesAfterUpdate)) @@ -142,10 +148,10 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { assert it.errorText == expectedErrorText } where: - scenario | cmHandleId | exception || expectedError | expectedErrorText - 'Cm Handle does not exist' | 'cmHandleId' | new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR) || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found' - 'Unknown' | 'cmHandleId' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' - 'Invalid cm handle id' | 'cmHandleId with spaces' | new DataValidationException('Name Validation Error.', cmHandleId + 'contains an invalid character') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id' + scenario | cmHandleId | exception || expectedError | expectedErrorText + 'Cm Handle does not exist' | 'cmHandleId' | new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR) || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found' + 'Unknown' | 'cmHandleId' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' + 'Invalid cm handle id' | 'cmHandleId with spaces' | new DataValidationException('Name Validation Error.', cmHandleId + 'contains an invalid character') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id' } def 'Multiple update operations in a single request'() { @@ -177,42 +183,44 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { assert it.errorText == 'cm handle id(s) not found' } then: 'the replace list method is called twice' - 2 * mockInventoryPersistence.replaceListContent(cmHandleXpath,_) + 2 * mockInventoryPersistence.replaceListContent(cmHandleXpath, _) } - def 'Update CM Handle Alternate ID with #scenario'() { - given: 'an existing cm handle' - DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId]) - and: 'an update request with an alternate id' - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1') - when: 'update alternate id method is called with the update request' - objectUnderTest.updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle) - then: 'the update node leaves method is invoked as many times as expected' - callsToDataService * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >> + def 'Update alternate id of existing CM Handle.'() { + given: 'cm handles request' + def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')] + and: 'a data node found' + def dataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': 'alt-1']) + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> [dataNode] + when: 'cm handle properties is updated' + def response = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) + then: 'the update is delegated to cps data service with correct parameters' + 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >> { args -> assert args[3].contains('alt-1') } - mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> isNewMapping - where: 'following updates are attempted' - scenario | isNewMapping || callsToDataService - 'new alternate id ' | true || 1 - 'existing alternate id' | false || 0 + and: 'one successful registration response' + response.size() == 1 + and: 'the response shows success for the given cm handle id' + assert response[0].status == Status.SUCCESS + assert response[0].cmHandle == cmHandleId } - def 'Alternate ID removed from cache when persisting fails.'() { - 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: ['id': cmHandleId, 'alternate-id': null]) - 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 } - when: 'updating of alternate id called' - objectUnderTest.updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle) - then: 'the original exception is thrown up' - def thrownException = thrown(NullPointerException) - assert thrownException == originalException + def 'Update with rejected alternate id.'() { + given: 'cm handles request' + def updatedNcmpServiceCmHandles = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')] + and: 'a data node found' + def dataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': 'alt-1']) + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> [dataNode] + when: 'attempt to update the cm handle' + def response = objectUnderTest.updateCmHandleProperties(updatedNcmpServiceCmHandles) + then: 'the update is NOT delegated to cps data service' + 0 * mockCpsDataService.updateNodeLeaves(*_) + and: 'the alternate id checker rejects the given cm handle (override default setup behavior)' + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [cmHandleId] + and: 'the response shows a failure for the given cm handle id' + assert response[0].status == Status.FAILURE + assert response[0].cmHandle == cmHandleId } def convertToProperties(expectedPropertiesAfterUpdateAsMap) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy index 26d44f28b3..7d8ac7485b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy @@ -114,7 +114,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { postOperationWithJsonDataMethodCalled = true } when: 'get resource data for group of cm handles are invoked' - objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId') + objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId', NO_AUTH_HEADER) then: 'validate the post operation was called and ncmp generated dmi request body json args' new PollingConditions().within(1) { assert postOperationWithJsonDataMethodCalled == true 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 index aaa034437c..0eabaa1d28 100644 --- 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 @@ -20,7 +20,6 @@ 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 @@ -68,25 +67,41 @@ class AlternateIdCheckerSpec extends Specification { 'other alternate id' || false } - def 'Check a batch of NEW cm handles with #scenario.'() { + def 'Check a batch of created 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' + and: 'the database already contains cm handle(s) with these alternate ids: #altAlreadyInDb' mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >> { args -> altAlreadyInDb.contains(args[0]) ? new DataNode() : throwDataNodeNotFoundException() } when: 'the batch of new cm handles is checked' - def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch) - then: 'the result only contains the ids of the acceptable cm handles' - assert result.contains('ch-1') == rejectCh1 - assert result.contains('ch-2') == rejectCh2 + def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.CREATE) + then: 'the result contains ids of the rejected cm handles' + assert result == expectedRejectedCmHandleIds where: 'the following alternate ids are used' - scenario | alt1 | alt2 | altAlreadyInDb || rejectCh1 | rejectCh2 - 'no alternate ids' | '' | '' | ['dont matter'] || false | false - 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || false | false - 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || true | false - 'two already used alternate ids' | 'fdn1' | 'fdn2' | ['fdn1','fdn2'] || true | true - 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || false | true + scenario | alt1 | alt2 | altAlreadyInDb || expectedRejectedCmHandleIds + 'no alternate ids' | '' | '' | ['dont matter'] || [] + 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || [] + 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || ['ch-1'] + 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || ['ch-2'] + } + + def 'Check a batch of updates to existing cm handles with #scenario.'() { + given: 'a batch of 1 existing cm handle update alternate id to #proposedAlt' + def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: proposedAlt)] + and: 'the database already contains a cm handle with alternate id: #altAlreadyInDb' + mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >> + { args -> altAlreadyInDb.equals(args[0]) ? new DataNode() : throwDataNodeNotFoundException() } + mockInventoryPersistenceService.getYangModelCmHandle(_) >> new YangModelCmHandle(alternateId: altAlreadyInDb) + when: 'the batch of cm handle updates is checked' + def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.UPDATE) + then: 'the result contains ids of the rejected cm handles' + assert result == expectedRejectedCmHandleIds + where: 'the following parameters are used' + scenario | proposedAlt | altAlreadyInDb || expectedRejectedCmHandleIds + 'no alternate id' | 'fdn1' | '' || [] + 'used the same alternate id' | 'fdn1' | 'fdn1' || [] + 'used different alternate id' | 'otherFdn' | 'fdn1' || ['ch-1'] } def throwDataNodeNotFoundException() { diff --git a/cps-parent/pom.xml b/cps-parent/pom.xml index 40cd186703..699bf3c9ac 100644 --- a/cps-parent/pom.xml +++ b/cps-parent/pom.xml @@ -32,7 +32,7 @@ <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <packaging>pom</packaging> <properties> diff --git a/cps-path-parser/pom.xml b/cps-path-parser/pom.xml index 023ab19696..fb161c7d56 100644 --- a/cps-path-parser/pom.xml +++ b/cps-path-parser/pom.xml @@ -23,7 +23,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-rest/pom.xml b/cps-rest/pom.xml index 0af6a360e3..9e484afccc 100644 --- a/cps-rest/pom.xml +++ b/cps-rest/pom.xml @@ -28,7 +28,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ri/pom.xml b/cps-ri/pom.xml index b0f3220bc4..a6e1e10e45 100644 --- a/cps-ri/pom.xml +++ b/cps-ri/pom.xml @@ -26,7 +26,7 @@ <parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.6-SNAPSHOT</version>
+ <version>3.4.7-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-service/pom.xml b/cps-service/pom.xml index 0da2b3ab81..58716f3f16 100644 --- a/cps-service/pom.xml +++ b/cps-service/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml index 0637c30a91..9b424a5ef0 100644 --- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml +++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml @@ -22,7 +22,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>dmi-plugin-demo-and-csit-stub</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> </parent> <artifactId>dmi-plugin-demo-and-csit-stub-app</artifactId> diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml index bddeab1872..ac9eeada5c 100644 --- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml +++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml @@ -21,7 +21,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>dmi-plugin-demo-and-csit-stub</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> </parent> <artifactId>dmi-plugin-demo-and-csit-stub-service</artifactId> diff --git a/dmi-plugin-demo-and-csit-stub/pom.xml b/dmi-plugin-demo-and-csit-stub/pom.xml index ede50da81a..4cec8e6ac4 100644 --- a/dmi-plugin-demo-and-csit-stub/pom.xml +++ b/dmi-plugin-demo-and-csit-stub/pom.xml @@ -22,7 +22,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml index bade85ef1a..2798b78643 100644 --- a/docs/api/swagger/cps/openapi.yaml +++ b/docs/api/swagger/cps/openapi.yaml @@ -55,16 +55,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -134,16 +124,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -202,16 +182,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -279,16 +249,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -351,16 +311,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -429,16 +379,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -511,16 +451,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -595,16 +525,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -671,16 +591,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -749,16 +659,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -826,16 +726,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -907,16 +797,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -991,16 +871,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1067,16 +937,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1155,16 +1015,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1250,16 +1100,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1347,16 +1187,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1444,16 +1274,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1556,16 +1376,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1680,16 +1490,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1801,16 +1601,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1886,16 +1676,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1994,16 +1774,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2103,16 +1873,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2205,16 +1965,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2300,16 +2050,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2396,16 +2136,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2502,16 +2232,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2766,16 +2486,6 @@ components: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - Unauthorized: - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized Forbidden: content: application/json: diff --git a/docs/api/swagger/ncmp/openapi-inventory.yaml b/docs/api/swagger/ncmp/openapi-inventory.yaml index 53f51f3f8b..ff9f4ba683 100644 --- a/docs/api/swagger/ncmp/openapi-inventory.yaml +++ b/docs/api/swagger/ncmp/openapi-inventory.yaml @@ -32,16 +32,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -115,16 +105,6 @@ paths: type: string type: array description: OK - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -169,16 +149,6 @@ paths: type: string type: array description: OK - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -226,16 +196,6 @@ components: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - Unauthorized: - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized Forbidden: content: application/json: diff --git a/docs/api/swagger/ncmp/openapi.yaml b/docs/api/swagger/ncmp/openapi.yaml index a1cc5d9ba7..9203b6d4ca 100644 --- a/docs/api/swagger/ncmp/openapi.yaml +++ b/docs/api/swagger/ncmp/openapi.yaml @@ -56,6 +56,12 @@ paths: default: application/json example: application/yang-data+json type: string + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string responses: "204": content: {} @@ -70,16 +76,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -199,6 +195,12 @@ paths: schema: default: false type: boolean + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string responses: "200": content: @@ -220,16 +222,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -312,6 +304,12 @@ paths: default: application/json example: application/yang-data+json type: string + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string requestBody: content: '*/*': @@ -339,16 +337,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -430,6 +418,12 @@ paths: default: application/json example: application/yang-data+json type: string + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string requestBody: content: application/json: @@ -461,16 +455,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -553,6 +537,12 @@ paths: default: application/json example: application/yang-data+json type: string + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string requestBody: content: application/json: @@ -587,16 +577,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -649,6 +629,12 @@ paths: required: true schema: type: string + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string requestBody: content: application/json: @@ -672,16 +658,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -806,16 +782,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -883,16 +849,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -954,16 +910,6 @@ paths: $ref: '#/components/schemas/RestModuleDefinition' type: array description: OK - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1041,16 +987,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1104,16 +1040,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "404": content: application/json: @@ -1167,16 +1093,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "404": content: application/json: @@ -1254,16 +1170,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1327,16 +1233,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "404": content: application/json: @@ -1399,16 +1295,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1645,6 +1531,13 @@ components: schema: default: false type: boolean + authorizationParamInHeader: + description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string contentParamInHeader: description: "Content parameter for request, if content parameter is null, default\ \ value is application/json." @@ -1716,16 +1609,6 @@ components: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - Unauthorized: - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized Forbidden: content: application/json: diff --git a/docs/release-notes.rst b/docs/release-notes.rst index a134d0d944..e79a188ef5 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -16,6 +16,33 @@ CPS Release Notes .. * * * NEW DELHI * * * .. ========================= +Version: 3.4.7 +============== + +Release Data +------------ + ++--------------------------------------+--------------------------------------------------------+ +| **CPS Project** | | +| | | ++--------------------------------------+--------------------------------------------------------+ +| **Docker images** | onap/cps-and-ncmp:3.4.7 | +| | | ++--------------------------------------+--------------------------------------------------------+ +| **Release designation** | 3.4.7 New Delhi | +| | | ++--------------------------------------+--------------------------------------------------------+ +| **Release date** | Not yet released | +| | | ++--------------------------------------+--------------------------------------------------------+ + +Bug Fixes +--------- +3.4.7 + +Features +-------- + Version: 3.4.6 ============== @@ -32,17 +59,27 @@ Release Data | **Release designation** | 3.4.6 New Delhi | | | | +--------------------------------------+--------------------------------------------------------+ -| **Release date** | Not yet released | +| **Release date** | 2024 February 29 | | | | +--------------------------------------+--------------------------------------------------------+ Bug Fixes --------- 3.4.6 + - `CPS-2126 <https://jira.onap.org/browse/CPS-2126>`_ Passing HTTP Authorization Bearer Token to DMI Plugins. Features -------- + - `CPS-2133 <https://jira.onap.org/browse/CPS-2133>`_ Revert Uplift of Spring Boot version from 3.2.2 to 3.1.2 + +Notes +----- +This release brings improvements to compatibility with Service Mesh and for that below measures are been taken. + +Basic authorization provided using Spring security is been removed from CPS-Core and NCMP and hence authorization is no longer enforced.(basic auth header will be ignored, but is still allowed). +NCMP will propagate a bearer token to DMI conditionally. +401 Unauthorized will not be returned. Best effort has been made to ensure backwards compatibility. Version: 3.4.5 ============== diff --git a/integration-test/pom.xml b/integration-test/pom.xml index 04280b9b3d..b379e9ff19 100644 --- a/integration-test/pom.xml +++ b/integration-test/pom.xml @@ -23,7 +23,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> 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 23504e49cd..1577524f2c 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 @@ -41,12 +41,14 @@ import org.onap.cps.spi.utils.SessionManager import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.EnableAutoConfiguration import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest import org.springframework.context.annotation.ComponentScan import org.springframework.data.jpa.repository.config.EnableJpaRepositories import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.test.web.client.MockRestServiceServer +import org.springframework.test.web.servlet.MockMvc import org.springframework.web.client.RestTemplate import org.testcontainers.spock.Testcontainers import spock.lang.Shared @@ -56,9 +58,10 @@ import spock.util.concurrent.PollingConditions import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus -@SpringBootTest(classes = [CpsDataspaceService]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = [CpsDataspaceService]) @Testcontainers @EnableAutoConfiguration +@AutoConfigureMockMvc @EnableJpaRepositories(basePackageClasses = [DataspaceRepository]) @ComponentScan(basePackages = ['org.onap.cps']) @EntityScan('org.onap.cps.spi.entities') @@ -68,6 +71,9 @@ abstract class CpsIntegrationSpecBase extends Specification { DatabaseTestContainer databaseTestContainer = DatabaseTestContainer.getInstance() @Autowired + MockMvc mvc; + + @Autowired CpsDataspaceService cpsDataspaceService @Autowired diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy new file mode 100644 index 0000000000..0dabbf30a4 --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy @@ -0,0 +1,124 @@ +/* + * ============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.integration.functional + +import java.time.Duration +import org.onap.cps.integration.base.CpsIntegrationSpecBase +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.test.web.client.match.MockRestRequestMatchers + +import static org.springframework.http.HttpMethod.GET +import static org.springframework.http.HttpMethod.DELETE +import static org.springframework.http.HttpMethod.PATCH +import static org.springframework.http.HttpMethod.POST +import static org.springframework.http.HttpMethod.PUT +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status + +class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase { + + static final NO_MODULE_SET_TAG = '' + static final MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json') + static final MODULE_RESOURCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json') + + def setup() { + registerCmHandle(DMI_URL, 'ch-1', NO_MODULE_SET_TAG, MODULE_REFERENCES_RESPONSE, MODULE_RESOURCES_RESPONSE) + } + + def cleanup() { + deregisterCmHandle(DMI_URL, 'ch-1') + } + + def 'Bearer token is passed from NCMP to DMI in pass-through data operations.'() { + given: 'DMI will expect to receive a request with a bearer token' + def targetDmiUrl = "$DMI_URL/dmi/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=my-resource-id" + mockDmiServer.expect(requestTo(targetDmiUrl)) + .andExpect(MockRestRequestMatchers.header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token')) + .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)) + + when: 'a pass-through data request is sent to NCMP with a bearer token' + mvc.perform(request(httpMethod, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running') + .queryParam('resourceIdentifier', 'my-resource-id') + .contentType(MediaType.APPLICATION_JSON) + .content('{ "some-json": "data" }') + .header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token')) + .andExpect(status().is2xxSuccessful()) + + then: 'DMI has received request with bearer token' + mockDmiServer.verify() + + where: 'all HTTP operations are applied' + httpMethod << [GET, POST, PUT, PATCH, DELETE] + } + + def 'Basic auth header is NOT passed from NCMP to DMI in pass-through data operations.'() { + given: 'DMI will expect to receive a request with no authorization header' + def targetDmiUrl = "$DMI_URL/dmi/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=my-resource-id" + mockDmiServer.expect(requestTo(targetDmiUrl)) + .andExpect(MockRestRequestMatchers.headerDoesNotExist(HttpHeaders.AUTHORIZATION)) + .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)) + + when: 'a pass-through data request is sent to NCMP with basic authentication' + mvc.perform(request(httpMethod, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running') + .queryParam('resourceIdentifier', 'my-resource-id') + .contentType(MediaType.APPLICATION_JSON) + .content('{ "some-json": "data" }') + .header(HttpHeaders.AUTHORIZATION, 'Basic Y3BzdXNlcjpjcHNyMGNrcyE=')) + .andExpect(status().is2xxSuccessful()) + + then: 'DMI has received request with no authorization header' + mockDmiServer.verify() + + where: 'all HTTP operations are applied' + httpMethod << [GET, POST, PUT, PATCH, DELETE] + } + + def 'Bearer token is passed from NCMP to DMI in async batch pass-through data operation.'() { + given: 'DMI will expect to receive a request with a bearer token' + mockDmiServer.expect(method(POST)) + .andExpect(MockRestRequestMatchers.header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token')) + .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)) + + when: 'a pass-through async data request is sent to NCMP with a bearer token' + def requestBody = """{"operations": [{ + "operation": "read", + "operationId": "operational-1", + "datastore": "ncmp-datastore:passthrough-running", + "resourceIdentifier": "my-resource-id", + "targetIds": ["ch-1"] + }]}""" + mvc.perform(request(POST, '/ncmp/v1/data') + .queryParam('topic', 'my-topic') + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token')) + .andExpect(status().is2xxSuccessful()) + + then: 'DMI will receive the async request with bearer token' + mockDmiServer.verify(Duration.ofSeconds(1)) + } + +} diff --git a/integration-test/src/test/resources/application.yml b/integration-test/src/test/resources/application.yml index f77cb02f7a..3d61bdbea6 100644 --- a/integration-test/src/test/resources/application.yml +++ b/integration-test/src/test/resources/application.yml @@ -112,7 +112,7 @@ app: topic: ${DMI_DEVICE_HEARTBEAT_TOPIC:dmi-device-heartbeat} notification: - enabled: false + enabled: true async: executor: core-pool-size: 2 diff --git a/jacoco-report/pom.xml b/jacoco-report/pom.xml index 99ddaa84b9..9e2f8b438c 100644 --- a/jacoco-report/pom.xml +++ b/jacoco-report/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,7 +32,7 @@ <groupId>org.onap.cps</groupId>
<artifactId>cps-aggregator</artifactId>
- <version>3.4.6-SNAPSHOT</version>
+ <version>3.4.7-SNAPSHOT</version>
<packaging>pom</packaging>
<name>cps</name>
diff --git a/releases/3.4.6-container.yaml b/releases/3.4.6-container.yaml new file mode 100644 index 0000000000..72ba08b023 --- /dev/null +++ b/releases/3.4.6-container.yaml @@ -0,0 +1,8 @@ +distribution_type: container +container_release_tag: 3.4.6 +project: cps +log_dir: cps-maven-docker-stage-master/938/ +ref: 4a978d3c66da16bc96b54cba807138fc9b0c79fa +containers: + - name: 'cps-and-ncmp' + version: '3.4.6-20240229T165311Z' diff --git a/releases/3.4.6.yaml b/releases/3.4.6.yaml new file mode 100644 index 0000000000..b3a9a3599b --- /dev/null +++ b/releases/3.4.6.yaml @@ -0,0 +1,4 @@ +distribution_type: maven +log_dir: cps-maven-stage-master/946/ +project: cps +version: 3.4.6
\ No newline at end of file diff --git a/spotbugs/pom.xml b/spotbugs/pom.xml index ef7c2f0f75..bbaf5fe6fb 100644 --- a/spotbugs/pom.xml +++ b/spotbugs/pom.xml @@ -25,7 +25,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.onap.cps</groupId> <artifactId>spotbugs</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <properties> <nexusproxy>https://nexus.onap.org</nexusproxy> diff --git a/version.properties b/version.properties index dbf29f3288..b3ec5707ce 100644 --- a/version.properties +++ b/version.properties @@ -22,7 +22,7 @@ major=3 minor=4 -patch=6 +patch=7 base_version=${major}.${minor}.${patch} |