From e1f41c3e6591b572a75021f4b51538f8fdbfc88d Mon Sep 17 00:00:00 2001 From: sourabh_sourabh Date: Sat, 12 Mar 2022 22:41:10 +0530 Subject: [PATCH] Async: NCMP Rest impl. including Request ID generation - In case of invalid topic return http status 400 with error message - Unit test is modified to handle/validate InvalidTopicException Issue-ID: CPS-828 Signed-off-by: sourabh_sourabh Change-Id: I05645c92ccebb8aa422a47f6edcde7b64088a118 --- .../NetworkCmProxyRestExceptionHandler.java | 4 ++- .../api/impl/NetworkCmProxyDataServiceImpl.java | 14 +++++--- .../api/impl/exception/InvalidTopicException.java | 40 ++++++++++++++++++++++ .../impl/NetworkCmProxyDataServiceImplSpec.groovy | 33 +++++++++--------- 4 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidTopicException.java diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java index 2495f3642..0843e9741 100755 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java @@ -24,6 +24,7 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.impl.exception.DmiRequestException; +import org.onap.cps.ncmp.api.impl.exception.InvalidTopicException; import org.onap.cps.ncmp.api.impl.exception.NcmpException; import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException; import org.onap.cps.ncmp.rest.controller.NetworkCmProxyController; @@ -65,7 +66,8 @@ public class NetworkCmProxyRestExceptionHandler { return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception); } - @ExceptionHandler({DmiRequestException.class, DataValidationException.class, HttpMessageNotReadableException.class}) + @ExceptionHandler({DmiRequestException.class, DataValidationException.class, HttpMessageNotReadableException.class, + InvalidTopicException.class}) public static ResponseEntity handleDmiRequestExceptions(final Exception exception) { return buildErrorResponse(HttpStatus.BAD_REQUEST, exception); } 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 e923ce414..76d4cef9e 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 @@ -42,11 +42,11 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.logging.log4j.util.Strings; import org.onap.cps.api.CpsAdminService; import org.onap.cps.api.CpsDataService; import org.onap.cps.api.CpsModuleService; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; +import org.onap.cps.ncmp.api.impl.exception.InvalidTopicException; import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException; import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations; import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations; @@ -303,8 +303,14 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService yangModelCmHandle.getId()); } - private static boolean isValidTopicName(final String topicName) { - return Strings.isNotEmpty(topicName) && TOPIC_NAME_PATTERN.matcher(topicName).matches(); + private static boolean hasTopicParameter(final String topicName) { + if (topicName == null) { + return false; + } + if (TOPIC_NAME_PATTERN.matcher(topicName).matches()) { + return true; + } + throw new InvalidTopicException("Topic name " + topicName + " is invalid", "invalid topic"); } private Map buildDmiResponse(final String requestId) { @@ -319,7 +325,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final DmiOperations.DataStoreEnum dataStore, final String optionsParamInQuery, final String topicParamInQuery) { - final boolean processAsynchronously = isValidTopicName(topicParamInQuery); + final boolean processAsynchronously = hasTopicParameter(topicParamInQuery); if (processAsynchronously) { final String resourceDataRequestId = UUID.randomUUID().toString(); return ResponseEntity.status(HttpStatus.OK) diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidTopicException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidTopicException.java new file mode 100644 index 000000000..b56ca7b8c --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidTopicException.java @@ -0,0 +1,40 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.exception; + +import lombok.Getter; + +public class InvalidTopicException extends RuntimeException { + + @Getter + final String details; + + /** + * Constructor. + * + * @param message the error message + * @param details the error details + */ + public InvalidTopicException(final String message, final String details) { + super(message); + this.details = details; + } +} 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 e6d18d915..c21d7e774 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 @@ -22,6 +22,7 @@ package org.onap.cps.ncmp.api.impl +import org.onap.cps.ncmp.api.impl.exception.InvalidTopicException import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import spock.lang.Shared @@ -217,7 +218,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { exceptionThrown.details.contains('NOK-json') } - def 'Get resource data for operational from DMI with empty topic sync request.'() { + def 'DMI Operational data request with #scenario'() { given: 'cps data service returns valid data node' mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode @@ -227,14 +228,14 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { when: 'get resource data is called data operational with blank topic' def responseData = objectUnderTest.getResourceDataOperationalForCmHandle('', '', '', '', emptyTopic) - then: '(synchronous) the dmi response is expected' - assert responseData == '{dmi-response}' + then: 'a invalid topic exception is thrown' + thrown(InvalidTopicException) where: 'the following parameters are used' - scenario | emptyTopic - 'No topic in url' | '' - 'Null topic in url' | null - 'Empty topic in url' | '\"\"' - 'Blank topic in url' | ' ' + scenario | emptyTopic + 'no topic value in url' | '' + 'empty topic value in url' | '\"\"' + 'blank topic value in url' | ' ' + 'invalid non-empty topic value in url' | '1_5_*_#' } def 'Get resource data for data operational from DMI with valid topic i.e. async request.'() { @@ -263,7 +264,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { assert responseData.body.requestId.length() > 0 } - def 'Get resource data for pass through running from DMI sync request where #scenario.'() { + def 'DMI pass through running data request with #scenario'() { given: 'cps data service returns valid data node' mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode @@ -273,14 +274,14 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { when: 'get resource data is called for data operational with valid topic' def responseData = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('', '', '', '', emptyTopic) - then: '(synchronous) the dmi response is expected' - assert responseData == '{dmi-response}' + then: 'a invalid topic exception is thrown' + thrown(InvalidTopicException) where: 'the following parameters are used' - scenario | emptyTopic - 'No topic in url' | '' - 'Null topic in url' | null - 'Empty topic in url' | '\"\"' - 'Blank topic in url' | ' ' + scenario | emptyTopic + 'no topic value in url' | '' + 'empty topic value in url' | '\"\"' + 'blank topic value in url' | ' ' + 'invalid non-empty topic value in url' | '1_5_*_#' } def 'Getting Yang Resources.'() { -- 2.16.6