From 4622f69544a089ef1a1062369128ac4fc3c35257 Mon Sep 17 00:00:00 2001 From: Renu Kumari Date: Fri, 11 Mar 2022 08:05:11 -0500 Subject: [PATCH] Return Registration response for updating cmhandles - Added CMHandleRegistrationResponse class for registration response - Send response in the case of success and failure - Each update operation in the request is independent on previous one Issue-ID: CPS-896 Signed-off-by: Renu Kumari Change-Id: Ic6cc69da48bd2078029784cabede4f5965054c03 --- .../NetworkCmProxyDataServicePropertyHandler.java | 26 +++++-- .../api/models/CmHandleRegistrationResponse.java | 86 ++++++++++++++++++++++ ...orkCmProxyDataServicePropertyHandlerSpec.groovy | 59 +++++++++++++-- .../models/CmHandleRegistrationResponseSpec.groovy | 68 +++++++++++++++++ 4 files changed, 227 insertions(+), 12 deletions(-) create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy 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 ca2f578f4..532d8463d 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 @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,15 +29,19 @@ import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DMI import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NO_TIMESTAMP; import com.google.common.collect.ImmutableMap; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsDataService; +import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse; +import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError; import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.exceptions.DataNodeNotFoundException; @@ -61,23 +66,32 @@ public class NetworkCmProxyDataServicePropertyHandler { * * @param ncmpServiceCmHandles collection of ncmpServiceCmHandles */ - public void updateCmHandleProperties(final Collection ncmpServiceCmHandles) + public List updateCmHandleProperties( + final Collection ncmpServiceCmHandles) throws DataNodeNotFoundException { + final List cmHandleRegistrationResponses = new ArrayList<>(); for (final NcmpServiceCmHandle ncmpServiceCmHandle : ncmpServiceCmHandles) { + final String cmHandle = ncmpServiceCmHandle.getCmHandleID(); try { - final String cmHandleXpath = String.format(CM_HANDLE_XPATH_TEMPLATE, - ncmpServiceCmHandle.getCmHandleID()); + final String cmHandleXpath = String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandle); final DataNode existingCmHandleDataNode = cpsDataService.getDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandleXpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); processUpdates(existingCmHandleDataNode, ncmpServiceCmHandle); + cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandle)); } catch (final DataNodeNotFoundException e) { log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", - ncmpServiceCmHandle.getCmHandleID(), - e.getMessage()); - throw e; + cmHandle, e.getMessage()); + cmHandleRegistrationResponses.add(CmHandleRegistrationResponse + .createFailureResponse(cmHandle, RegistrationError.CM_HANDLE_DOES_NOT_EXIST)); + } catch (final Exception exception) { + log.error("Unable to update dataNode for cmHandleId : {} , caused by : {}", + cmHandle, exception.getMessage()); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(cmHandle, exception)); } } + return cmHandleRegistrationResponses; } private void processUpdates(final DataNode existingCmHandleDataNode, final NcmpServiceCmHandle incomingCmHandle) { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java new file mode 100644 index 000000000..e183ed114 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java @@ -0,0 +1,86 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Bell Canada + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.models; + +import lombok.Builder; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +@Data +@Builder +public class CmHandleRegistrationResponse { + + private final String cmHandle; + private final Status status; + private RegistrationError registrationError; + private String errorText; + + /** + * Creates a failure response based on exception. + * + * @param cmHandle cmHandle + * @param exception exception + * @return CmHandleRegistrationResponse + */ + public static CmHandleRegistrationResponse createFailureResponse(final String cmHandle, final Exception exception) { + return CmHandleRegistrationResponse.builder() + .cmHandle(cmHandle) + .status(Status.FAILURE) + .registrationError(RegistrationError.UNKNOWN_ERROR) + .errorText(exception.getMessage()).build(); + } + + /** + * Creates a failure response based on registration error. + * + * @param cmHandle cmHandle + * @param registrationError registrationError + * @return CmHandleRegistrationResponse + */ + public static CmHandleRegistrationResponse createFailureResponse(final String cmHandle, + final RegistrationError registrationError) { + return CmHandleRegistrationResponse.builder().cmHandle(cmHandle) + .status(Status.FAILURE) + .registrationError(registrationError) + .errorText(registrationError.errorText) + .build(); + } + + public static CmHandleRegistrationResponse createSuccessResponse(final String cmHandle) { + return CmHandleRegistrationResponse.builder().cmHandle(cmHandle) + .status(Status.SUCCESS).build(); + } + + public enum Status { + SUCCESS, FAILURE; + } + + @RequiredArgsConstructor + public enum RegistrationError { + UNKNOWN_ERROR("00", "Unknown error"), + CM_HANDLE_ALREADY_EXIST("01", "cm-handle already exists"), + CM_HANDLE_DOES_NOT_EXIST("02", "cm-handle does not exist"); + + public final String errorCode; + public final String errorText; + + } +} \ No newline at end of file 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 9b8d4ada5..b1ca064a3 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 @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +21,15 @@ package org.onap.cps.ncmp.api.impl +import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_DOES_NOT_EXIST +import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.UNKNOWN_ERROR +import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status + import org.onap.cps.api.CpsDataService +import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.exceptions.DataNodeNotFoundException -import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.spi.model.DataNode import org.onap.cps.spi.model.DataNodeBuilder import spock.lang.Specification @@ -117,12 +122,53 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { given: 'cm handles request' def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleID: cmHandleId, publicProperties: [:], dmiProperties: [:])] and: 'data node cannot be found' - mockCpsDataService.getDataNode(*_) >> { throw new DataNodeNotFoundException(dataspaceName, anchorName, cmHandleXpath) } + mockCpsDataService.getDataNode(*_) >> { throw exception } when: 'update data node leaves is called using correct parameters' - objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) - then: 'data validation exception is thrown' - def exceptionThrown = thrown(DataValidationException.class) - assert exceptionThrown.getMessage().contains('DataNode not found') + def response = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) + then: 'one failed registration response' + response.size() == 1 + and: 'it has expected error details' + with(response.get(0)) { + assert it.status == Status.FAILURE + assert it.cmHandle == cmHandleId + assert it.registrationError == expectedError + assert it.errorText == expectedErrorText + } + where: + scenario | exception || expectedError | expectedErrorText + 'cmhandle does not exist' | new DataNodeNotFoundException('NCMP-Admin', 'ncmp-dmi-registry') || CM_HANDLE_DOES_NOT_EXIST | 'cm-handle does not exist' + 'unexpected error' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' + } + + def 'Multiple update operations in a single request'() { + given: 'cm handles request' + def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleID: cmHandleId, publicProperties: ['publicProp1': "value"], dmiProperties: [:]), + new NcmpServiceCmHandle(cmHandleID: cmHandleId, publicProperties: ['publicProp1': "value"], dmiProperties: [:]), + new NcmpServiceCmHandle(cmHandleID: cmHandleId, publicProperties: ['publicProp1': "value"], dmiProperties: [:])] + and: 'data node can be found for 1st and 3rd cm-handle but not for 2nd cm-handle' + mockCpsDataService.getDataNode(*_) >> cmHandleDataNode >> { throw new DataNodeNotFoundException('NCMP-Admin', 'ncmp-dmi-registry') } >> cmHandleDataNode + when: 'update data node leaves is called using correct parameters' + def cmHandleResponseList = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) + then: 'response has 3 values' + cmHandleResponseList.size() == 3 + and: 'the 1st and 3rd requests were processed successfully' + with(cmHandleResponseList.get(0)) { + assert it.status == Status.SUCCESS + assert it.cmHandle == cmHandleId + } + with(cmHandleResponseList.get(2)) { + assert it.status == Status.SUCCESS + assert it.cmHandle == cmHandleId + } + and: 'the 2nd request failed with correct error code' + with(cmHandleResponseList.get(1)) { + assert it.status == Status.FAILURE + assert it.cmHandle == cmHandleId + assert it.registrationError == CM_HANDLE_DOES_NOT_EXIST + assert it.errorText == "cm-handle does not exist" + } + then: 'the replace list method is called twice' + 2 * mockCpsDataService.replaceListContent(*_) } def convertToProperties(expectedPropertiesAfterUpdateAsMap) { @@ -133,4 +179,5 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { })) return properties } + } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy new file mode 100644 index 000000000..902ba4e5d --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy @@ -0,0 +1,68 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Bell Canada + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.models + +import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError +import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status +import spock.lang.Specification + +class CmHandleRegistrationResponseSpec extends Specification { + + def 'Successful CmHandle Registration Response'() { + when: 'CMHandle response is created' + def cmHandleRegistrationResponse = CmHandleRegistrationResponse.createSuccessResponse('cmHandle') + then: 'a success response is returned' + with(cmHandleRegistrationResponse) { + assert it.cmHandle == 'cmHandle' + assert it.status == Status.SUCCESS + } + and: 'error details are null' + cmHandleRegistrationResponse.registrationError == null + cmHandleRegistrationResponse.errorText == null + } + + def 'Failed Cm Handle Registration Response: for unexpected exception'() { + when: 'CMHandle response is created for an unexpected exception' + def cmHandleRegistrationResponse = + CmHandleRegistrationResponse.createFailureResponse('cmHandle', new RuntimeException('unexpected error')) + then: 'the response is created with expected value' + with(cmHandleRegistrationResponse) { + assert it.registrationError == RegistrationError.UNKNOWN_ERROR + assert it.cmHandle == 'cmHandle' + assert errorText == 'unexpected error' + } + } + + def 'Failed Cm Handle Registration Response: for known error'() { + when: 'CMHandle response is created for known error' + def cmHandleRegistrationResponse = + CmHandleRegistrationResponse.createFailureResponse('cmHandle', RegistrationError.CM_HANDLE_ALREADY_EXIST) + then: 'the response is created with expected value' + with(cmHandleRegistrationResponse) { + assert it.registrationError == RegistrationError.CM_HANDLE_ALREADY_EXIST + assert it.cmHandle == 'cmHandle' + assert it.status == Status.FAILURE + assert errorText == RegistrationError.CM_HANDLE_ALREADY_EXIST.errorText + } + + } + +} -- 2.16.6