From ea01d09861289ff162dff318713d1c24eba89259 Mon Sep 17 00:00:00 2001 From: sourabh_sourabh Date: Mon, 28 Mar 2022 13:21:55 +0100 Subject: Async: NCMP Rest impl. including Request ID generation - Restructured code and moved some of them at controller and service layer. - Unit is fixed and organized to it's belonging classes. Issue-ID: CPS-828 Signed-off-by: sourabh_sourabh Change-Id: I0919218e35b1d11cb579d707f376b76de80409da --- .../cps/ncmp/api/NetworkCmProxyDataService.java | 10 ++- .../api/impl/NetworkCmProxyDataServiceImpl.java | 59 ++++------------ .../impl/NetworkCmProxyDataServiceImplSpec.groovy | 82 +++------------------- 3 files changed, 32 insertions(+), 119 deletions(-) (limited to 'cps-ncmp-service') 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 d50b8c5ea8..cbd0756c09 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 @@ -52,12 +52,14 @@ public interface NetworkCmProxyDataService { * @param resourceIdentifier resource identifier * @param optionsParamInQuery options query * @param topicParamInQuery topic name for (triggering) async responses + * @param requestId unique requestId for async request * @return {@code Object} resource data */ Object getResourceDataOperationalForCmHandle(String cmHandleId, String resourceIdentifier, String optionsParamInQuery, - String topicParamInQuery); + String topicParamInQuery, + String requestId); /** * Get resource data for data store pass-through running @@ -66,13 +68,15 @@ public interface NetworkCmProxyDataService { * @param cmHandleId cm handle identifier * @param resourceIdentifier resource identifier * @param optionsParamInQuery options query - * @param topicParamInQuery topic query + * @param topicParamInQuery topic name for (triggering) async responses + * @param requestId unique requestId for async request * @return {@code Object} resource data */ Object getResourceDataPassThroughRunningForCmHandle(String cmHandleId, String resourceIdentifier, String optionsParamInQuery, - String topicParamInQuery); + String topicParamInQuery, + String requestId); /** * Write resource data for data store pass-through running 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 81c060eb3b..696bb0a37c 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 @@ -37,8 +37,6 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.UUID; -import java.util.regex.Pattern; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -47,7 +45,6 @@ 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.HttpClientRequestException; -import org.onap.cps.ncmp.api.impl.exception.InvalidTopicException; import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations; import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations; import org.onap.cps.ncmp.api.impl.operations.DmiOperations; @@ -65,7 +62,6 @@ import org.onap.cps.spi.exceptions.SchemaSetNotFoundException; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.utils.CpsValidator; import org.onap.cps.utils.JsonObjectMapper; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -90,12 +86,6 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService private final YangModelCmHandleRetriever yangModelCmHandleRetriever; - // valid kafka topic name regex - private static final Pattern TOPIC_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9]([._-](?![._-])|" - + "[a-zA-Z0-9]){0,120}[a-zA-Z0-9]$"); - private static final String NO_REQUEST_ID = null; - private static final String NO_TOPIC = null; - @Override public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule( final DmiPluginRegistration dmiPluginRegistration) { @@ -119,20 +109,22 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService public Object getResourceDataOperationalForCmHandle(final String cmHandleId, final String resourceIdentifier, final String optionsParamInQuery, - final String topicParamInQuery) { + final String topicParamInQuery, + final String requestId) { CpsValidator.validateNameCharacters(cmHandleId); - return validateTopicNameAndGetResourceData(cmHandleId, resourceIdentifier, - DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL, optionsParamInQuery, topicParamInQuery); + return getResourceDataResponse(cmHandleId, resourceIdentifier, + DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL, optionsParamInQuery, topicParamInQuery, requestId); } @Override public Object getResourceDataPassThroughRunningForCmHandle(final String cmHandleId, final String resourceIdentifier, final String optionsParamInQuery, - final String topicParamInQuery) { + final String topicParamInQuery, + final String requestId) { CpsValidator.validateNameCharacters(cmHandleId); - return validateTopicNameAndGetResourceData(cmHandleId, resourceIdentifier, - DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING, optionsParamInQuery, topicParamInQuery); + return getResourceDataResponse(cmHandleId, resourceIdentifier, + DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING, optionsParamInQuery, topicParamInQuery, requestId); } @Override @@ -329,35 +321,14 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService yangModelCmHandle.getId()); } - 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) { - final Map dmiResponseMap = new HashMap<>(); - dmiResponseMap.put("requestId", requestId); - return dmiResponseMap; - } - - private Object validateTopicNameAndGetResourceData(final String cmHandleId, - final String resourceIdentifier, - final DmiOperations.DataStoreEnum dataStore, - final String optionsParamInQuery, - final String topicParamInQuery) { - final boolean processAsynchronously = hasTopicParameter(topicParamInQuery); - if (processAsynchronously) { - final String resourceDataRequestId = UUID.randomUUID().toString(); - return ResponseEntity.status(HttpStatus.OK) - .body(buildDmiResponse(resourceDataRequestId)); - } + private Object getResourceDataResponse(final String cmHandleId, + final String resourceIdentifier, + final DmiOperations.DataStoreEnum dataStore, + final String optionsParamInQuery, + final String topicParamInQuery, + final String requestId) { final ResponseEntity responseEntity = dmiDataOperations.getResourceDataFromDmi( - cmHandleId, resourceIdentifier, optionsParamInQuery, dataStore, NO_REQUEST_ID, NO_TOPIC); + cmHandleId, resourceIdentifier, optionsParamInQuery, dataStore, requestId, topicParamInQuery); return handleResponse(responseEntity, OperationEnum.READ); } } \ No newline at end of file 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 489c71c0e9..2d01dba522 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 @@ -23,7 +23,6 @@ package org.onap.cps.ncmp.api.impl import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException -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 @@ -119,7 +118,8 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle', 'testResourceId', OPTIONS_PARAM, - NO_TOPIC) + NO_TOPIC, + NO_REQUEST_ID) then: 'DMI returns a json response' response == 'dmi-response' } @@ -137,7 +137,8 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle', 'testResourceId', OPTIONS_PARAM, - NO_TOPIC) + NO_TOPIC, + NO_REQUEST_ID) then: 'exception is thrown with the expected response code and details' def exceptionThrown = thrown(HttpClientRequestException.class) exceptionThrown.details.contains('NOK-json') @@ -160,7 +161,8 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle', 'testResourceId', OPTIONS_PARAM, - NO_TOPIC) + NO_TOPIC, + NO_REQUEST_ID) then: 'exception is thrown' def exceptionThrown = thrown(HttpClientRequestException.class) and: 'details contain the original response' @@ -183,7 +185,8 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle', 'testResourceId', OPTIONS_PARAM, - NO_TOPIC) + NO_TOPIC, + NO_REQUEST_ID) then: 'get resource data returns expected response' response == '{dmi-response}' } @@ -204,7 +207,8 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle', 'testResourceId', OPTIONS_PARAM, - NO_TOPIC) + NO_TOPIC, + NO_REQUEST_ID) then: 'exception is thrown' def exceptionThrown = thrown(HttpClientRequestException.class) and: 'details contain the original response' @@ -212,72 +216,6 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { exceptionThrown.httpStatus == HttpStatus.NOT_FOUND.value() } - 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 - and: 'dmi data operation returns valid response and data' - mockDmiDataOperations.getResourceDataFromDmi(_, _, _, _, _, NO_REQUEST_ID, NO_TOPIC) - >> new ResponseEntity<>('{dmi-response}', HttpStatus.OK) - when: 'get resource data is called data operational with blank topic' - def responseData = objectUnderTest.getResourceDataOperationalForCmHandle('', '', - '', emptyTopic) - then: 'a invalid topic exception is thrown' - thrown(InvalidTopicException) - where: 'the following parameters are used' - 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.'() { - given: 'cps data service returns valid data node' - mockCpsDataService.getDataNode(*_) >> dataNode - and: 'dmi data operation returns valid response and data' - mockDmiDataOperations.getResourceDataFromDmi(_, _, _, _, _, 'my-topic-name') - >> new ResponseEntity<>('{dmi-response}', HttpStatus.OK) - when: 'get resource data is called for data operational with valid topic' - def responseData = objectUnderTest.getResourceDataOperationalForCmHandle('', '', '', 'my-topic-name') - then: 'non empty request id is generated' - assert responseData.body.requestId.length() > 0 - } - - def 'Get resource data for pass through running from DMI with valid topic async request.'() { - given: 'cps data service returns valid data node' - mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', - cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode - and: 'dmi data operation returns valid response and data' - mockDmiDataOperations.getResourceDataFromDmi(_, _, _, _, _, 'my-topic-name') - >> new ResponseEntity<>('{dmi-response}', HttpStatus.OK) - when: 'get resource data is called for data operational with valid topic' - def responseData = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('', - '', OPTIONS_PARAM, 'my-topic-name') - then: 'non empty request id is generated' - assert responseData.body.requestId.length() > 0 - } - - 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 - and: 'dmi data operation returns valid response and data' - mockDmiDataOperations.getResourceDataFromDmi(_, _, _, _, NO_REQUEST_ID, NO_TOPIC) - >> new ResponseEntity<>('{dmi-response}', HttpStatus.OK) - when: 'get resource data is called for data operational with valid topic' - def responseData = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('', - '', '', emptyTopic) - then: 'a invalid topic exception is thrown' - thrown(InvalidTopicException) - where: 'the following parameters are used' - 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.'() { when: 'yang resources is called' objectUnderTest.getYangResourcesModuleReferences('some-cm-handle') -- cgit 1.2.3-korg