summaryrefslogtreecommitdiffstats
path: root/cps-ncmp-rest
diff options
context:
space:
mode:
Diffstat (limited to 'cps-ncmp-rest')
-rw-r--r--cps-ncmp-rest/docs/openapi/components.yaml75
-rwxr-xr-xcps-ncmp-rest/docs/openapi/ncmp-inventory.yml60
-rwxr-xr-xcps-ncmp-rest/docs/openapi/ncmp.yml43
-rwxr-xr-xcps-ncmp-rest/docs/openapi/openapi.yml5
-rw-r--r--cps-ncmp-rest/pom.xml2
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java2
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java87
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java61
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java24
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy2
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy107
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy87
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy17
-rw-r--r--cps-ncmp-rest/src/test/resources/dmi_registration_all_singing_and_dancing.json6
-rw-r--r--cps-ncmp-rest/src/test/resources/dmi_registration_updates_only.json2
-rw-r--r--cps-ncmp-rest/src/test/resources/dmi_registration_without_properties.json2
16 files changed, 506 insertions, 76 deletions
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml
index 69225aed2d..7ed2efe52a 100644
--- a/cps-ncmp-rest/docs/openapi/components.yaml
+++ b/cps-ncmp-rest/docs/openapi/components.yaml
@@ -1,6 +1,7 @@
# ============LICENSE_START=======================================================
# Copyright (C) 2021-2022 Nordix Foundation
# Modifications Copyright (C) 2021 Pantheon.tech
+# 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.
@@ -30,7 +31,23 @@ components:
type: string
details:
type: string
-
+ # DMI Server Exception Schema
+ DmiErrorMessage:
+ title: DMI Error Message
+ type: object
+ properties:
+ message:
+ type: string
+ example: "Bad Gateway Error Message NCMP"
+ dmi-response:
+ type: object
+ properties:
+ http-code:
+ type: integer
+ example: 400
+ body:
+ type: string
+ example: Bad Request
# Request Schemas
RestDmiPluginRegistration:
type: object
@@ -70,6 +87,33 @@ components:
items:
type: string
example: [my-cm-handle1, my-cm-handle2, my-cm-handle3]
+ DmiPluginRegistrationErrorResponse:
+ type: object
+ properties:
+ failedCreatedCmHandles:
+ type: array
+ items:
+ $ref: '#/components/schemas/CmHandlerRegistrationErrorResponse'
+ failedUpdatedCmHandles:
+ type: array
+ items:
+ $ref: '#/components/schemas/CmHandlerRegistrationErrorResponse'
+ failedRemovedCmHandles:
+ type: array
+ items:
+ $ref: '#/components/schemas/CmHandlerRegistrationErrorResponse'
+ CmHandlerRegistrationErrorResponse:
+ type: object
+ properties:
+ cmHandle:
+ type: string
+ example: my-cm-handle
+ errorCode:
+ type: string
+ example: '00'
+ errorText:
+ type: string
+ example: 'Unknown error. <error-details>'
RestInputCmHandle:
required:
@@ -146,6 +190,16 @@ components:
type: string
example: my-module-revision
+ CmHandleQueryRestParameters:
+ type: object
+ title: Cm Handle query parameters for executing cm handle search
+ properties:
+ publicCmHandleProperties:
+ type: object
+ additionalProperties:
+ type: string
+ example: Book Type
+
RestOutputCmHandle:
type: object
title: CM handle Details
@@ -303,14 +357,6 @@ components:
sample 3:
value:
resourceIdentifier: parent=shops,child=bookstore
- acceptParamInHeader:
- name: Accept
- in: header
- required: false
- description: Accept parameter for response, if accept parameter is null, that means client can accept any format.
- schema:
- type: string
- enum: [ application/json, application/yang-data+json ]
optionsParamInQuery:
name: options
in: query
@@ -434,3 +480,14 @@ components:
status: 500
message: Internal Server Error
details: Internal Server Error occurred
+ BadGateway:
+ description: Bad Gateway
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/DmiErrorMessage"
+ example:
+ message: "Bad Gateway Error Message NCMP"
+ dmi-response:
+ http-code: 400
+ body: "Bad Request"
diff --git a/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml b/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml
index 3cd8e8baf2..0a408c2413 100755
--- a/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml
+++ b/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml
@@ -31,7 +31,7 @@ updateDmiRegistration:
schema:
$ref: 'components.yaml#/components/schemas/RestDmiPluginRegistration'
responses:
- 204:
+ 200:
$ref: 'components.yaml#/components/responses/NoContent'
400:
$ref: 'components.yaml#/components/responses/BadRequest'
@@ -40,4 +40,60 @@ updateDmiRegistration:
403:
$ref: 'components.yaml#/components/responses/Forbidden'
500:
- $ref: 'components.yaml#/components/responses/InternalServerError'
+ description: Partial or Complete failure. The error details are provided in the response body and all supported error codes are documented in the example.
+ content:
+ application/json:
+ schema:
+ $ref: 'components.yaml#/components/schemas/DmiPluginRegistrationErrorResponse'
+ example:
+ failedCreatedCmHandles: [
+ {
+ "cmHandle": "my-cm-handle-01",
+ "errorCode": "00",
+ "errorText": "Unknown error. <error-details>"
+ },
+ {
+ "cmHandle": "my-cm-handle-02",
+ "errorCode": "01",
+ "errorText": "cm-handle already exists"
+ },
+ {
+ "cmHandle": "my-cm-handle-03",
+ "errorCode": "03",
+ "errorText": "cm-handle has an invalid character(s) in id"
+ }
+ ]
+ failedUpdatedCmHandles: [
+ {
+ "cmHandle": "my-cm-handle-01",
+ "errorCode": "00",
+ "errorText": "Unknown error. <error-details>"
+ },
+ {
+ "cmHandle": "my-cm-handle-02",
+ "errorCode": "02",
+ "errorText": "cm-handle does not exist"
+ },
+ {
+ "cmHandle": "my-cm-handle-03",
+ "errorCode": "03",
+ "errorText": "cm-handle has an invalid character(s) in id"
+ }
+ ]
+ failedRemovedCmHandles: [
+ {
+ "cmHandle": "my-cm-handle-01",
+ "errorCode": "00",
+ "errorText": "Unknown error. <error-details>"
+ },
+ {
+ "cmHandle": "my-cm-handle-02",
+ "errorCode": "02",
+ "errorText": "cm-handle does not exists"
+ },
+ {
+ "cmHandle": "my-cm-handle-03",
+ "errorCode": "03",
+ "errorText": "cm-handle has an invalid character(s) in id"
+ }
+ ]
diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml
index a9d08b7951..05e4b84853 100755
--- a/cps-ncmp-rest/docs/openapi/ncmp.yml
+++ b/cps-ncmp-rest/docs/openapi/ncmp.yml
@@ -1,7 +1,7 @@
# ============LICENSE_START=======================================================
# Copyright (C) 2021-2022 Nordix Foundation
# Modifications Copyright (C) 2021 Pantheon.tech
-# Modifications Copyright (C) 2021 Bell Canada
+# Modifications Copyright (C) 2021-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.
@@ -27,7 +27,6 @@ getResourceDataForPassthroughOperational:
parameters:
- $ref: 'components.yaml#/components/parameters/cmHandleInPath'
- $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
- - $ref: 'components.yaml#/components/parameters/acceptParamInHeader'
- $ref: 'components.yaml#/components/parameters/optionsParamInQuery'
- $ref: 'components.yaml#/components/parameters/topicParamInQuery'
responses:
@@ -48,6 +47,8 @@ getResourceDataForPassthroughOperational:
$ref: 'components.yaml#/components/responses/Forbidden'
500:
$ref: 'components.yaml#/components/responses/InternalServerError'
+ 502:
+ $ref: 'components.yaml#/components/responses/BadGateway'
resourceDataForPassthroughRunning:
get:
@@ -59,7 +60,6 @@ resourceDataForPassthroughRunning:
parameters:
- $ref: 'components.yaml#/components/parameters/cmHandleInPath'
- $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
- - $ref: 'components.yaml#/components/parameters/acceptParamInHeader'
- $ref: 'components.yaml#/components/parameters/optionsParamInQuery'
- $ref: 'components.yaml#/components/parameters/topicParamInQuery'
responses:
@@ -80,6 +80,8 @@ resourceDataForPassthroughRunning:
$ref: 'components.yaml#/components/responses/Forbidden'
500:
$ref: 'components.yaml#/components/responses/InternalServerError'
+ 502:
+ $ref: 'components.yaml#/components/responses/BadGateway'
post:
tags:
- network-cm-proxy
@@ -116,6 +118,8 @@ resourceDataForPassthroughRunning:
$ref: 'components.yaml#/components/responses/Forbidden'
500:
$ref: 'components.yaml#/components/responses/InternalServerError'
+ 502:
+ $ref: 'components.yaml#/components/responses/BadGateway'
put:
tags:
@@ -153,6 +157,8 @@ resourceDataForPassthroughRunning:
$ref: 'components.yaml#/components/responses/Forbidden'
500:
$ref: 'components.yaml#/components/responses/InternalServerError'
+ 502:
+ $ref: 'components.yaml#/components/responses/BadGateway'
patch:
tags:
@@ -184,6 +190,8 @@ resourceDataForPassthroughRunning:
$ref: 'components.yaml#/components/responses/Forbidden'
500:
$ref: 'components.yaml#/components/responses/InternalServerError'
+ 502:
+ $ref: 'components.yaml#/components/responses/BadGateway'
delete:
tags:
@@ -208,6 +216,8 @@ resourceDataForPassthroughRunning:
$ref: 'components.yaml#/components/responses/NotFound'
500:
$ref: 'components.yaml#/components/responses/InternalServerError'
+ 502:
+ $ref: 'components.yaml#/components/responses/BadGateway'
fetchModuleReferencesByCmHandle:
get:
@@ -281,6 +291,33 @@ retrieveCmHandleDetailsById:
application/json:
schema:
$ref: 'components.yaml#/components/schemas/RestOutputCmHandle'
+ 404:
+ $ref: 'components.yaml#/components/responses/NotFound'
+ 500:
+ $ref: 'components.yaml#/components/responses/InternalServerError'
+
+queryCmHandles:
+ post:
+ description: Execute cm handle query search
+ tags:
+ - network-cm-proxy
+ summary: Execute cm handle query upon a given set of query parameters
+ operationId: queryCmHandles
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: 'components.yaml#/components/schemas/CmHandleQueryRestParameters'
+ responses:
+ 200:
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
400:
$ref: 'components.yaml#/components/responses/BadRequest'
401:
diff --git a/cps-ncmp-rest/docs/openapi/openapi.yml b/cps-ncmp-rest/docs/openapi/openapi.yml
index 12a8318efb..935b657e1f 100755
--- a/cps-ncmp-rest/docs/openapi/openapi.yml
+++ b/cps-ncmp-rest/docs/openapi/openapi.yml
@@ -39,4 +39,7 @@ paths:
$ref: 'ncmp.yml#/executeCmHandleSearch'
/v1/ch/{cm-handle}:
- $ref: 'ncmp.yml#/retrieveCmHandleDetailsById' \ No newline at end of file
+ $ref: 'ncmp.yml#/retrieveCmHandleDetailsById'
+
+ /v1/data/ch/searches:
+ $ref: 'ncmp.yml#/queryCmHandles'
diff --git a/cps-ncmp-rest/pom.xml b/cps-ncmp-rest/pom.xml
index 97305cfe98..6a700c3e12 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.0.0-SNAPSHOT</version>
+ <version>3.1.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java
index 4c8fafea5f..a9ec863d53 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java
@@ -45,7 +45,7 @@ public interface NcmpRestInputMapper {
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
DmiPluginRegistration toDmiPluginRegistration(final RestDmiPluginRegistration restDmiPluginRegistration);
- @Mapping(source = "cmHandle", target = "cmHandleID")
+ @Mapping(source = "cmHandle", target = "cmHandleId")
@Mapping(source = "cmHandleProperties", target = "dmiProperties")
@Mapping(source = "publicCmHandleProperties", target = "publicProperties")
NcmpServiceCmHandle toNcmpServiceCmHandle(final RestInputCmHandle restInputCmHandle);
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 0201fad2b5..5c1f8704da 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
@@ -3,7 +3,7 @@
* Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2021-2022 Nordix Foundation
* Modification Copyright (C) 2021 highstreet technologies GmbH
- * Modifications (C) 2021 Bell Canada
+ * Modifications (C) 2021-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.
@@ -31,18 +31,25 @@ import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
import java.util.stream.Collectors;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
+import org.onap.cps.ncmp.api.impl.exception.InvalidTopicException;
+import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi;
import org.onap.cps.ncmp.rest.model.CmHandleProperties;
import org.onap.cps.ncmp.rest.model.CmHandleProperty;
import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties;
+import org.onap.cps.ncmp.rest.model.CmHandleQueryRestParameters;
import org.onap.cps.ncmp.rest.model.CmHandles;
import org.onap.cps.ncmp.rest.model.ConditionProperties;
import org.onap.cps.ncmp.rest.model.Conditions;
@@ -50,6 +57,7 @@ import org.onap.cps.ncmp.rest.model.ModuleNameAsJsonObject;
import org.onap.cps.ncmp.rest.model.ModuleNamesAsJsonArray;
import org.onap.cps.ncmp.rest.model.RestModuleReference;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandle;
+import org.onap.cps.utils.CpsValidator;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -63,6 +71,9 @@ import org.springframework.web.bind.annotation.RestController;
public class NetworkCmProxyController implements NetworkCmProxyApi {
private static final String NO_BODY = null;
+ private static final String NO_REQUEST_ID = null;
+ private static final String NO_TOPIC = null;
+ public static final String ASYNC_REQUEST_ID = "requestId";
private final NetworkCmProxyDataService networkCmProxyDataService;
private final JsonObjectMapper jsonObjectMapper;
@@ -73,7 +84,6 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
*
* @param cmHandle cm handle identifier
* @param resourceIdentifier resource identifier
- * @param acceptParamInHeader accept header parameter
* @param optionsParamInQuery options query parameter
* @param topicParamInQuery topic query parameter
* @return {@code ResponseEntity} response from dmi plugin
@@ -81,15 +91,21 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
@Override
public ResponseEntity<Object> getResourceDataOperationalForCmHandle(final String cmHandle,
final @NotNull @Valid String resourceIdentifier,
- final String acceptParamInHeader,
final @Valid String optionsParamInQuery,
final @Valid String topicParamInQuery) {
+ final ResponseEntity<Map<String, Object>> asyncResponse = populateAsyncResponse(topicParamInQuery);
+ final Map<String, Object> asyncResponseData = asyncResponse.getBody();
+
final Object responseObject = networkCmProxyDataService.getResourceDataOperationalForCmHandle(cmHandle,
resourceIdentifier,
- acceptParamInHeader,
optionsParamInQuery,
- topicParamInQuery);
- return ResponseEntity.ok(responseObject);
+ asyncResponseData == null ? NO_TOPIC : topicParamInQuery,
+ asyncResponseData == null ? NO_REQUEST_ID : asyncResponseData.get(ASYNC_REQUEST_ID).toString());
+
+ if (asyncResponseData == null) {
+ return ResponseEntity.ok(responseObject);
+ }
+ return ResponseEntity.ok(asyncResponse);
}
/**
@@ -97,7 +113,6 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
*
* @param cmHandle cm handle identifier
* @param resourceIdentifier resource identifier
- * @param acceptParamInHeader accept header parameter
* @param optionsParamInQuery options query parameter
* @param topicParamInQuery topic query parameter
* @return {@code ResponseEntity} response from dmi plugin
@@ -105,15 +120,21 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
@Override
public ResponseEntity<Object> getResourceDataRunningForCmHandle(final String cmHandle,
final @NotNull @Valid String resourceIdentifier,
- final String acceptParamInHeader,
final @Valid String optionsParamInQuery,
final @Valid String topicParamInQuery) {
+ final ResponseEntity<Map<String, Object>> asyncResponse = populateAsyncResponse(topicParamInQuery);
+ final Map<String, Object> asyncResponseData = asyncResponse.getBody();
+
final Object responseObject = networkCmProxyDataService.getResourceDataPassThroughRunningForCmHandle(cmHandle,
resourceIdentifier,
- acceptParamInHeader,
optionsParamInQuery,
- topicParamInQuery);
- return ResponseEntity.ok(responseObject);
+ asyncResponseData == null ? NO_TOPIC : topicParamInQuery,
+ asyncResponseData == null ? NO_REQUEST_ID : asyncResponseData.get(ASYNC_REQUEST_ID).toString());
+
+ if (asyncResponseData == null) {
+ return ResponseEntity.ok(responseObject);
+ }
+ return ResponseEntity.ok(asyncResponse);
}
@Override
@@ -195,6 +216,19 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
}
/**
+ * Query and return cm handles that match the given query parameters.
+ *
+ * @param cmHandleQueryRestParameters the cm handle query parameters
+ * @return collection of cm handle ids
+ */
+ public ResponseEntity<List<String>> queryCmHandles(
+ final CmHandleQueryRestParameters cmHandleQueryRestParameters) {
+ final Set<String> cmHandleIds = networkCmProxyDataService.queryCmHandles(
+ jsonObjectMapper.convertToValueType(cmHandleQueryRestParameters, CmHandleQueryApiParameters.class));
+ return ResponseEntity.ok(List.copyOf(cmHandleIds));
+ }
+
+ /**
* Search for Cm Handle and Properties by Name.
* @param cmHandleId cm-handle identifier
* @return cm handle and its properties
@@ -258,9 +292,38 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
private RestOutputCmHandle toRestOutputCmHandle(final NcmpServiceCmHandle ncmpServiceCmHandle) {
final RestOutputCmHandle restOutputCmHandle = new RestOutputCmHandle();
final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties();
- restOutputCmHandle.setCmHandle(ncmpServiceCmHandle.getCmHandleID());
+ restOutputCmHandle.setCmHandle(ncmpServiceCmHandle.getCmHandleId());
cmHandlePublicProperties.add(ncmpServiceCmHandle.getPublicProperties());
restOutputCmHandle.setPublicCmHandleProperties(cmHandlePublicProperties);
return restOutputCmHandle;
}
+
+ private ResponseEntity<Map<String, Object>> populateAsyncResponse(final String topicParamInQuery) {
+ final boolean processAsynchronously = hasTopicParameter(topicParamInQuery);
+ final Map<String, Object> responseData;
+ if (processAsynchronously) {
+ responseData = getAsyncResponseData();
+ } else {
+ responseData = null;
+ }
+ return ResponseEntity.ok().body(responseData);
+ }
+
+ private static boolean hasTopicParameter(final String topicName) {
+ if (topicName == null) {
+ return false;
+ }
+ if (CpsValidator.validateTopicName(topicName)) {
+ return true;
+ }
+ throw new InvalidTopicException("Topic name " + topicName + " is invalid", "invalid topic");
+ }
+
+ private Map<String, Object> getAsyncResponseData() {
+ final Map<String, Object> asyncResponseData = new HashMap<>(1);
+ final String resourceDataRequestId = UUID.randomUUID().toString();
+ asyncResponseData.put(ASYNC_REQUEST_ID, resourceDataRequestId);
+ return asyncResponseData;
+ }
+
}
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
index c9d26f2a54..105a6a559c 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021 Bell Canada
+ * Copyright (C) 2021-2022 Bell Canada
* Modifications Copyright (C) 2022 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,10 +21,17 @@
package org.onap.cps.ncmp.rest.controller;
+import java.util.List;
+import java.util.stream.Collectors;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
+import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
+import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status;
+import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse;
import org.onap.cps.ncmp.rest.api.NetworkCmProxyInventoryApi;
+import org.onap.cps.ncmp.rest.model.CmHandlerRegistrationErrorResponse;
+import org.onap.cps.ncmp.rest.model.DmiPluginRegistrationErrorResponse;
import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -41,14 +48,58 @@ public class NetworkCmProxyInventoryController implements NetworkCmProxyInventor
/**
* Update DMI Plugin Registration (used for first registration also).
+ *
* @param restDmiPluginRegistration the registration data
*/
@Override
- public ResponseEntity<Void> updateDmiPluginRegistration(
+ public ResponseEntity updateDmiPluginRegistration(
final @Valid RestDmiPluginRegistration restDmiPluginRegistration) {
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
- ncmpRestInputMapper.toDmiPluginRegistration(restDmiPluginRegistration));
- return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse =
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
+ ncmpRestInputMapper.toDmiPluginRegistration(restDmiPluginRegistration));
+ final DmiPluginRegistrationErrorResponse failedRegistrationErrorResponse =
+ getFailureRegistrationResponse(dmiPluginRegistrationResponse);
+ return allRegistrationsSuccessful(failedRegistrationErrorResponse)
+ ? new ResponseEntity<>(HttpStatus.OK)
+ : new ResponseEntity<>(failedRegistrationErrorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+
+ private boolean allRegistrationsSuccessful(
+ final DmiPluginRegistrationErrorResponse dmiPluginRegistrationErrorResponse) {
+ return dmiPluginRegistrationErrorResponse.getFailedCreatedCmHandles().isEmpty()
+ && dmiPluginRegistrationErrorResponse.getFailedUpdatedCmHandles().isEmpty()
+ && dmiPluginRegistrationErrorResponse.getFailedRemovedCmHandles().isEmpty();
+
+ }
+
+ private DmiPluginRegistrationErrorResponse getFailureRegistrationResponse(
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
+ final DmiPluginRegistrationErrorResponse dmiPluginRegistrationErrorResponse =
+ new DmiPluginRegistrationErrorResponse();
+ dmiPluginRegistrationErrorResponse.setFailedCreatedCmHandles(
+ getFailedResponses(dmiPluginRegistrationResponse.getCreatedCmHandles()));
+ dmiPluginRegistrationErrorResponse.setFailedUpdatedCmHandles(
+ getFailedResponses(dmiPluginRegistrationResponse.getUpdatedCmHandles()));
+ dmiPluginRegistrationErrorResponse.setFailedRemovedCmHandles(
+ getFailedResponses(dmiPluginRegistrationResponse.getRemovedCmHandles()));
+
+ return dmiPluginRegistrationErrorResponse;
+ }
+
+ private List<CmHandlerRegistrationErrorResponse> getFailedResponses(
+ final List<CmHandleRegistrationResponse> cmHandleRegistrationResponseList) {
+ return cmHandleRegistrationResponseList.stream()
+ .filter(cmHandleRegistrationResponse -> cmHandleRegistrationResponse.getStatus() == Status.FAILURE)
+ .map(this::toCmHandleRegistrationErrorResponse)
+ .collect(Collectors.toList());
+ }
+
+ private CmHandlerRegistrationErrorResponse toCmHandleRegistrationErrorResponse(
+ final CmHandleRegistrationResponse registrationResponse) {
+ return new CmHandlerRegistrationErrorResponse()
+ .cmHandle(registrationResponse.getCmHandle())
+ .errorCode(registrationResponse.getRegistrationError().errorCode)
+ .errorText(registrationResponse.getErrorText());
}
}
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 0843e9741e..c72373344d 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,11 +24,14 @@ 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.HttpClientRequestException;
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;
import org.onap.cps.ncmp.rest.controller.NetworkCmProxyInventoryController;
+import org.onap.cps.ncmp.rest.model.DmiErrorMessage;
+import org.onap.cps.ncmp.rest.model.DmiErrorMessageDmiresponse;
import org.onap.cps.ncmp.rest.model.ErrorMessage;
import org.onap.cps.spi.exceptions.CpsException;
import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
@@ -66,6 +69,12 @@ public class NetworkCmProxyRestExceptionHandler {
return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception);
}
+ @ExceptionHandler({HttpClientRequestException.class})
+ public static ResponseEntity<Object> handleClientRequestExceptions(
+ final HttpClientRequestException httpClientRequestException) {
+ return wrapDmiErrorResponse(HttpStatus.BAD_GATEWAY, httpClientRequestException);
+ }
+
@ExceptionHandler({DmiRequestException.class, DataValidationException.class, HttpMessageNotReadableException.class,
InvalidTopicException.class})
public static ResponseEntity<Object> handleDmiRequestExceptions(final Exception exception) {
@@ -91,8 +100,19 @@ public class NetworkCmProxyRestExceptionHandler {
} else {
errorMessage.setDetails(CHECK_LOGS_FOR_DETAILS);
}
- errorMessage.setDetails(exception instanceof CpsException ? ((CpsException) exception).getDetails() :
- CHECK_LOGS_FOR_DETAILS);
+ errorMessage.setDetails(
+ exception instanceof CpsException ? ((CpsException) exception).getDetails() : CHECK_LOGS_FOR_DETAILS);
return new ResponseEntity<>(errorMessage, status);
}
+
+ private static ResponseEntity<Object> wrapDmiErrorResponse(final HttpStatus httpStatus,
+ final HttpClientRequestException httpClientRequestException) {
+ final var dmiErrorMessage = new DmiErrorMessage();
+ final var dmiErrorResponse = new DmiErrorMessageDmiresponse();
+ dmiErrorResponse.setHttpCode(httpClientRequestException.getHttpStatus());
+ dmiErrorResponse.setBody(httpClientRequestException.getDetails());
+ dmiErrorMessage.setMessage(httpClientRequestException.getMessage());
+ dmiErrorMessage.setDmiResponse(dmiErrorResponse);
+ return new ResponseEntity<>(dmiErrorMessage, httpStatus);
+ }
}
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy
index 3d54a0b089..bb762080d2 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy
@@ -43,7 +43,7 @@ class NcmpRestInputMapperSpec extends Specification {
then: 'the result returns the correct number of cm handles'
result.createdCmHandles.size() == 1
and: 'the converted cm handle has the same id'
- result.createdCmHandles[0].cmHandleID == 'example-id'
+ result.createdCmHandles[0].cmHandleId == 'example-id'
and: '(empty) properties are converted correctly'
result.createdCmHandles[0].dmiProperties == expectedDmiProperties
result.createdCmHandles[0].publicProperties == expectedPublicProperties
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
index d5c3cd9f37..b34b0fff38 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
@@ -3,7 +3,7 @@
* Copyright (C) 2021 Pantheon.tech
* Modification Copyright (C) 2021 highstreet technologies GmbH
* Modification Copyright (C) 2021-2022 Nordix Foundation
- * Modification Copyright (C) 2021 Bell Canada.
+ * Modification Copyright (C) 2021-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.
@@ -60,7 +60,10 @@ class NetworkCmProxyControllerSpec extends Specification {
NetworkCmProxyDataService mockNetworkCmProxyDataService = Mock()
@SpringBean
- JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ ObjectMapper objectMapper = new ObjectMapper()
+
+ @SpringBean
+ JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(objectMapper)
@SpringBean
NcmpRestInputMapper ncmpRestInputMapper = Mappers.getMapper(NcmpRestInputMapper)
@@ -72,6 +75,7 @@ class NetworkCmProxyControllerSpec extends Specification {
@Shared
def NO_TOPIC = null
+ def NO_REQUEST_ID = null
def 'Get Resource Data from pass-through operational.'() {
given: 'resource data url'
@@ -81,43 +85,51 @@ class NetworkCmProxyControllerSpec extends Specification {
def response = mvc.perform(
get(getUrl)
.contentType(MediaType.APPLICATION_JSON)
- .accept(MediaType.APPLICATION_JSON_VALUE)
).andReturn().response
then: 'the NCMP data service is called with getResourceDataOperationalForCmHandle'
1 * mockNetworkCmProxyDataService.getResourceDataOperationalForCmHandle('testCmHandle',
'parent/child',
- 'application/json',
'(a=1,b=2)',
- NO_TOPIC)
+ NO_TOPIC,
+ NO_REQUEST_ID)
and: 'response status is Ok'
response.status == HttpStatus.OK.value()
}
- def 'Get Resource Data from pass-through operational with #scenario.'() {
+ def 'Get Resource Data from #datastoreInUrl with #scenario.'() {
given: 'resource data url'
- def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-operational" +
+ def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:${datastoreInUrl}" +
"?resourceIdentifier=parent/child&options=(a=1,b=2)${topicQueryParam}"
when: 'get data resource request is performed'
def response = mvc.perform(
get(getUrl)
.contentType(MediaType.APPLICATION_JSON)
- .accept(MediaType.APPLICATION_JSON_VALUE)
).andReturn().response
then: 'the NCMP data service is called with operational data for cm handle'
- 1 * mockNetworkCmProxyDataService.getResourceDataOperationalForCmHandle('testCmHandle',
+ expectedNumberOfMethodExecutions
+ * mockNetworkCmProxyDataService."${expectedMethodName}"('testCmHandle',
'parent/child',
- 'application/json',
'(a=1,b=2)',
- expectedTopicName)
- and: 'response status is Ok'
- response.status == HttpStatus.OK.value()
+ expectedTopicName,
+ _)
+ then: 'response status is expected'
+ response.status == expectedHttpStatus
where: 'the following parameters are used'
- scenario | topicQueryParam || expectedTopicName
- 'Url with valid topic' | "&topic=my-topic-name" || "my-topic-name"
- 'No topic in url' | '' || NO_TOPIC
- 'Null topic in url' | "&topic=null" || "null"
- 'Empty topic in url' | "&topic=\"\"" || "\"\""
- 'Missing topic in url' | "&topic=" || ""
+ scenario | datastoreInUrl | topicQueryParam || expectedTopicName | expectedMethodName | expectedNumberOfMethodExecutions | expectedHttpStatus
+ 'url with valid topic' | 'passthrough-operational' | '&topic=my-topic-name' || 'my-topic-name' | 'getResourceDataOperationalForCmHandle' | 1 | HttpStatus.OK.value()
+ 'no topic in url' | 'passthrough-operational' | '' || NO_TOPIC | 'getResourceDataOperationalForCmHandle' | 1 | HttpStatus.OK.value()
+ 'null topic in url' | 'passthrough-operational' | '&topic=null' || 'null' | 'getResourceDataOperationalForCmHandle' | 1 | HttpStatus.OK.value()
+ 'empty topic in url' | 'passthrough-operational' | '&topic=\"\"' || null | 'getResourceDataOperationalForCmHandle' | 0 | HttpStatus.BAD_REQUEST.value()
+ 'missing topic in url' | 'passthrough-operational' | '&topic=' || null | 'getResourceDataOperationalForCmHandle' | 0 | HttpStatus.BAD_REQUEST.value()
+ 'blank topic value in url' | 'passthrough-operational' | '&topic=\" \"' || null | 'getResourceDataOperationalForCmHandle' | 0 | HttpStatus.BAD_REQUEST.value()
+ 'invalid non-empty topic value in url' | 'passthrough-operational' | '&topic=1_5_*_#' || null | 'getResourceDataOperationalForCmHandle' | 0 | HttpStatus.BAD_REQUEST.value()
+ 'url with valid topic' | 'passthrough-running' | '&topic=my-topic-name' || 'my-topic-name' | 'getResourceDataPassThroughRunningForCmHandle' | 1 | HttpStatus.OK.value()
+ 'no topic in url' | 'passthrough-running' | '' || NO_TOPIC | 'getResourceDataPassThroughRunningForCmHandle' | 1 | HttpStatus.OK.value()
+ 'null topic in url' | 'passthrough-running' | '&topic=null' || 'null' | 'getResourceDataPassThroughRunningForCmHandle' | 1 | HttpStatus.OK.value()
+ 'empty topic in url' | 'passthrough-running' | '&topic=\"\"' || null | 'getResourceDataPassThroughRunningForCmHandle' | 0 | HttpStatus.BAD_REQUEST.value()
+ 'missing topic in url' | 'passthrough-running' | '&topic=' || null | 'getResourceDataPassThroughRunningForCmHandle' | 0 | HttpStatus.BAD_REQUEST.value()
+ 'blank topic value in url' | 'passthrough-running' | '&topic=\" \"' || null | 'getResourceDataPassThroughRunningForCmHandle' | 0 | HttpStatus.BAD_REQUEST.value()
+ 'invalid non-empty topic value in url' | 'passthrough-running' | '&topic=1_5_*_#' || null | 'getResourceDataPassThroughRunningForCmHandle' | 0 | HttpStatus.BAD_REQUEST.value()
}
def 'Get Resource Data from pass-through running with #scenario value in resource identifier param.'() {
@@ -127,14 +139,13 @@ class NetworkCmProxyControllerSpec extends Specification {
and: 'ncmp service returns json object'
mockNetworkCmProxyDataService.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
resourceIdentifier,
- 'application/json',
'(a=1,b=2)',
- NO_TOPIC) >> '{valid-json}'
+ NO_TOPIC,
+ NO_REQUEST_ID) >> '{valid-json}'
when: 'get data resource request is performed'
def response = mvc.perform(
get(getUrl)
.contentType(MediaType.APPLICATION_JSON)
- .accept(MediaType.APPLICATION_JSON_VALUE)
).andReturn().response
then: 'response status is Ok'
response.status == HttpStatus.OK.value()
@@ -157,8 +168,7 @@ class NetworkCmProxyControllerSpec extends Specification {
when: 'update data resource request is performed'
def response = mvc.perform(
put(updateUrl)
- .contentType(MediaType.APPLICATION_JSON_VALUE)
- .accept(MediaType.APPLICATION_JSON_VALUE).content(requestBody)
+ .contentType(MediaType.APPLICATION_JSON_VALUE).content(requestBody)
).andReturn().response
then: 'ncmp service method to update resource is called'
1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
@@ -175,8 +185,7 @@ class NetworkCmProxyControllerSpec extends Specification {
when: 'create resource request is performed'
def response = mvc.perform(
post(url)
- .contentType(MediaType.APPLICATION_JSON_VALUE)
- .accept(MediaType.APPLICATION_JSON_VALUE).content(requestBody)
+ .contentType(MediaType.APPLICATION_JSON_VALUE).content(requestBody)
).andReturn().response
then: 'ncmp service method to create resource called'
1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
@@ -222,7 +231,7 @@ class NetworkCmProxyControllerSpec extends Specification {
def cmHandleId = 'Some-Cm-Handle'
def dmiProperties = [ prop:'some DMI property' ]
def publicProperties = [ "public prop":'some public property' ]
- def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleID: cmHandleId, dmiProperties: dmiProperties, publicProperties: publicProperties)
+ def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dmiProperties: dmiProperties, publicProperties: publicProperties)
and: 'the service method is invoked with the cm handle id'
1 * mockNetworkCmProxyDataService.getNcmpServiceCmHandle('Some-Cm-Handle') >> ncmpServiceCmHandle
when: 'the cm handle details api is invoked'
@@ -249,6 +258,31 @@ class NetworkCmProxyControllerSpec extends Specification {
response.contentAsString == '{"cmHandles":[]}'
}
+ def 'Query for cm handles matching query parameters'() {
+ given: 'an endpoint and json data'
+ def searchesEndpoint = "$ncmpBasePathV1/data/ch/searches"
+ String jsonString = '{"publicCmHandleProperties": {"name": "Contact", "value": "newemailforstore@bookstore.com"}}'
+ and: 'the service method is invoked with module names and returns cm handle ids'
+ 1 * mockNetworkCmProxyDataService.queryCmHandles(_) >> ['some-cmhandle-id1', 'some-cmhandle-id2']
+ when: 'the searches api is invoked'
+ def response = mvc.perform(post(searchesEndpoint)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(jsonString)).andReturn().response
+ then: 'cm handle ids are returned'
+ response.contentAsString == '["some-cmhandle-id1","some-cmhandle-id2"]'
+ }
+
+ def 'Query for cm handles with invalid request payload'() {
+ when: 'the searches api is invoked'
+ def searchesEndpoint = "$ncmpBasePathV1/data/ch/searches"
+ def invalidInputData = '{invalidJson}'
+ def response = mvc.perform(post(searchesEndpoint)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(invalidInputData)).andReturn().response
+ then: 'BAD_REQUEST is returned'
+ response.getStatus() == 400
+ }
+
def 'Patch resource data in pass-through running datastore.' () {
given: 'patch resource data url'
def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" +
@@ -279,5 +313,24 @@ class NetworkCmProxyControllerSpec extends Specification {
and: 'the response is No Content'
response.status == HttpStatus.NO_CONTENT.value()
}
+
+ def 'Get resource data from DMI with valid topic i.e. async request for #scenario'() {
+ given: 'resource data url'
+ def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:${datastoreInUrl}" +
+ "?resourceIdentifier=parent/child&options=(a=1,b=2)&topic=my-topic-name"
+ when: 'get data resource request is performed'
+ def response = mvc.perform(
+ get(getUrl)
+ .contentType(MediaType.APPLICATION_JSON)
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ ).andReturn().response
+ then: 'async request id is generated'
+ assert response.contentAsString.contains("requestId")
+ where: 'the following parameters are used'
+ scenario | datastoreInUrl
+ ':passthrough-operational' | 'passthrough-operational'
+ ':passthrough-running' | 'passthrough-running'
+ }
+
}
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
index 9b1c2e87c0..30b6beb379 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021 Bell Canada
+ * Copyright (C) 2021-2022 Bell Canada
* Modifications Copyright (C) 2021-2022 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,7 +24,11 @@ package org.onap.cps.ncmp.rest.controller
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.TestUtils
import org.onap.cps.ncmp.api.NetworkCmProxyDataService
+import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
import org.onap.cps.ncmp.api.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse
+import org.onap.cps.ncmp.rest.model.CmHandlerRegistrationErrorResponse
+import org.onap.cps.ncmp.rest.model.DmiPluginRegistrationErrorResponse
import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
@@ -36,6 +40,9 @@ import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Specification
+
+import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_ALREADY_EXIST
+import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_DOES_NOT_EXIST
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
@WebMvcTest(NetworkCmProxyInventoryController)
@@ -58,7 +65,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
@Value('${rest.api.ncmp-inventory-base-path}/v1')
def ncmpBasePathV1
- def 'Dmi plugin registration #scenario' () {
+ def 'Dmi plugin registration #scenario'() {
given: 'a dmi plugin registration with #scenario'
def jsonData = TestUtils.getResourceFileContent(dmiRegistrationJson)
and: 'the expected rest input as an object'
@@ -72,9 +79,9 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
.content(jsonData)
).andReturn().response
then: 'the converted object is forwarded to the registration service'
- 1 * mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(mockDmiPluginRegistration)
+ 1 * mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(mockDmiPluginRegistration) >> new DmiPluginRegistrationResponse()
and: 'response status is no content'
- response.status == HttpStatus.NO_CONTENT.value()
+ response.status == HttpStatus.OK.value()
where: 'the following registration json is used'
scenario | dmiRegistrationJson
'multiple services, added, updated and removed cm handles and many properties' | 'dmi_registration_all_singing_and_dancing.json'
@@ -82,7 +89,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
'without any properties' | 'dmi_registration_without_properties.json'
}
- def 'Dmi plugin registration with invalid json' () {
+ def 'Dmi plugin registration with invalid json'() {
given: 'a dmi plugin registration with #scenario'
def jsonDataWithUndefinedDataLabel = '{"notAdmiPlugin":""}'
when: 'post request is performed & registration is called with correct DMI plugin information'
@@ -95,4 +102,74 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
response.status == HttpStatus.BAD_REQUEST.value()
}
+ def 'DMI Registration: All cm-handles operations processed successfully.'() {
+ given: 'a dmi plugin registration'
+ def dmiRegistrationRequest = '{}'
+ and: 'service can register cm-handles successfully'
+ def dmiRegistrationResponse = new DmiPluginRegistrationResponse(
+ createdCmHandles: [CmHandleRegistrationResponse.createSuccessResponse('cm-handle-1')],
+ updatedCmHandles: [CmHandleRegistrationResponse.createSuccessResponse('cm-handle-2')],
+ removedCmHandles: [CmHandleRegistrationResponse.createSuccessResponse('cm-handle-3')]
+ )
+ mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(*_) >> dmiRegistrationResponse
+ when: 'registration endpoint is invoked'
+ def response = mvc.perform(
+ post("$ncmpBasePathV1/ch")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(dmiRegistrationRequest)
+ ).andReturn().response
+ then: 'response status is ok'
+ response.status == HttpStatus.OK.value()
+ and: 'the response body is empty'
+ response.getContentAsString() == ''
+
+ }
+
+ def 'DMI Registration Error Handling: #scenario.'() {
+ given: 'a dmi plugin registration'
+ def dmiRegistrationRequest = '{}'
+ and: '#scenario: service failed to register few cm-handle'
+ def dmiRegistrationResponse = new DmiPluginRegistrationResponse(
+ createdCmHandles: [createCmHandleResponse],
+ updatedCmHandles: [updateCmHandleResponse],
+ removedCmHandles: [removeCmHandleResponse]
+ )
+ mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(*_) >> dmiRegistrationResponse
+ when: 'registration endpoint is invoked'
+ def response = mvc.perform(
+ post("$ncmpBasePathV1/ch")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(dmiRegistrationRequest)
+ ).andReturn().response
+ then: 'request status is internal server error'
+ response.status == HttpStatus.INTERNAL_SERVER_ERROR.value()
+ and: 'the response body is in the expected format'
+ def responseBody = jsonObjectMapper.convertJsonString(response.getContentAsString(), DmiPluginRegistrationErrorResponse)
+ and: 'contains only the failure responses'
+ responseBody.getFailedCreatedCmHandles() == expectedFailedCreatedCmHandle
+ responseBody.getFailedUpdatedCmHandles() == expectedFailedUpdateCmHandle
+ responseBody.getFailedRemovedCmHandles() == expectedFailedRemovedCmHandle
+ where:
+ scenario | createCmHandleResponse | updateCmHandleResponse | removeCmHandleResponse || expectedFailedCreatedCmHandle | expectedFailedUpdateCmHandle | expectedFailedRemovedCmHandle
+ 'only create failed' | failedResponse('cm-handle-1') | successResponse('cm-handle-2') | successResponse('cm-handle-3') || [failedRestResponse('cm-handle-1')] | [] | []
+ 'only update failed' | successResponse('cm-handle-1') | failedResponse('cm-handle-2') | successResponse('cm-handle-3') || [] | [failedRestResponse('cm-handle-2')] | []
+ 'only delete failed' | successResponse('cm-handle-1') | successResponse('cm-handle-2') | failedResponse('cm-handle-3') || [] | [] | [failedRestResponse('cm-handle-3')]
+ 'all three failed' | failedResponse('cm-handle-1') | failedResponse('cm-handle-2') | failedResponse('cm-handle-3') || [failedRestResponse('cm-handle-1')] | [failedRestResponse('cm-handle-2')] | [failedRestResponse('cm-handle-3')]
+ 'create update failed' | failedResponse('cm-handle-1') | failedResponse('cm-handle-2') | successResponse('cm-handle-3') || [failedRestResponse('cm-handle-1')] | [failedRestResponse('cm-handle-2')] | []
+ 'create delete failed' | failedResponse('cm-handle-1') | successResponse('cm-handle-2') | failedResponse('cm-handle-3') || [failedRestResponse('cm-handle-1')] | [] | [failedRestResponse('cm-handle-3')]
+ 'update delete failed' | successResponse('cm-handle-1') | failedResponse('cm-handle-2') | failedResponse('cm-handle-3') || [] | [failedRestResponse('cm-handle-2')] | [failedRestResponse('cm-handle-3')]
+ }
+
+ def failedRestResponse(cmHandle) {
+ return new CmHandlerRegistrationErrorResponse('cmHandle': cmHandle, 'errorCode': '00', 'errorText': 'Failed')
+ }
+
+ def failedResponse(cmHandle) {
+ return CmHandleRegistrationResponse.createFailureResponse(cmHandle, new RuntimeException("Failed"))
+ }
+
+ def successResponse(cmHandle) {
+ return CmHandleRegistrationResponse.createSuccessResponse(cmHandle)
+ }
+
}
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
index b642370154..1f6c38428b 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
@@ -21,14 +21,13 @@
package org.onap.cps.ncmp.rest.exceptions
-import com.fasterxml.jackson.databind.ObjectMapper
import groovy.json.JsonSlurper
import org.mapstruct.factory.Mappers
import org.onap.cps.TestUtils
import org.onap.cps.ncmp.api.NetworkCmProxyDataService
import org.onap.cps.ncmp.api.impl.exception.DmiRequestException
+import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException
import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.rest.controller.NcmpRestInputMapper
import org.onap.cps.spi.exceptions.CpsException
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
@@ -38,6 +37,7 @@ import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
+import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Shared
@@ -111,6 +111,19 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
assertTestResponse(response, BAD_REQUEST, sampleErrorMessage, sampleErrorDetails)
}
+ def 'Failing DMI Request - passthrough scenario'() {
+ given: 'failing DMI request'
+ mockNetworkCmProxyDataService.getResourceDataPassThroughRunningForCmHandle(*_) >> { throw new HttpClientRequestException('Error Message Details NCMP', 'Bad Request from DMI', 400) }
+ when: 'the DMI request is executed'
+ def response = mvc.perform(get("$dataNodeBaseEndpointNcmp/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=stores:bookstore/categories=100"))
+ .andReturn().response
+ then: 'NCMP service responds with 502 Bad Gateway status'
+ response.status == HttpStatus.BAD_GATEWAY.value()
+ and: 'the NCMP response also contains the original DMI response details'
+ response.contentAsString.contains('400')
+ response.contentAsString.contains('Bad Request from DMI')
+ }
+
def setupTestException(exception, apiType) {
if (NCMP == apiType) {
mockNetworkCmProxyDataService.getYangResourcesModuleReferences(*_) >> { throw exception }
diff --git a/cps-ncmp-rest/src/test/resources/dmi_registration_all_singing_and_dancing.json b/cps-ncmp-rest/src/test/resources/dmi_registration_all_singing_and_dancing.json
index fd8b56b02d..c2a307db26 100644
--- a/cps-ncmp-rest/src/test/resources/dmi_registration_all_singing_and_dancing.json
+++ b/cps-ncmp-rest/src/test/resources/dmi_registration_all_singing_and_dancing.json
@@ -3,7 +3,7 @@
"dmiModelPlugin":"service3",
"createdCmHandles":[
{
- "cmHandle":"ch1(new)",
+ "cmHandle":"ch1-new",
"cmHandleProperties":{
"dmiProp1":"ch1-dmi1",
"dmiProp2":"ch1-dmi2"
@@ -14,7 +14,7 @@
}
},
{
- "cmHandle":"ch2(new)",
+ "cmHandle":"ch2-new",
"cmHandleProperties":{
"dmiProp1":"ch2-dmi1",
"dmiProp2":"ch2-dmi2"
@@ -27,7 +27,7 @@
],
"updatedCmHandles":[
{
- "cmHandle":"ch3(upd)",
+ "cmHandle":"ch3-upd",
"cmHandleProperties":{
"dmiProp1":"ch3-dmi1"
},
diff --git a/cps-ncmp-rest/src/test/resources/dmi_registration_updates_only.json b/cps-ncmp-rest/src/test/resources/dmi_registration_updates_only.json
index 58a1a9836b..26acdbdcbe 100644
--- a/cps-ncmp-rest/src/test/resources/dmi_registration_updates_only.json
+++ b/cps-ncmp-rest/src/test/resources/dmi_registration_updates_only.json
@@ -2,7 +2,7 @@
"dmiPlugin": "service1",
"updatedCmHandles":[
{
- "cmHandle":"ch3(upd)",
+ "cmHandle":"ch3-upd",
"cmHandleProperties":{
"dmiProp1":"ch3-dmi1",
"dmiProp2":null
diff --git a/cps-ncmp-rest/src/test/resources/dmi_registration_without_properties.json b/cps-ncmp-rest/src/test/resources/dmi_registration_without_properties.json
index 395c098d21..a5dd7b0aad 100644
--- a/cps-ncmp-rest/src/test/resources/dmi_registration_without_properties.json
+++ b/cps-ncmp-rest/src/test/resources/dmi_registration_without_properties.json
@@ -4,7 +4,7 @@
"dmiModelPlugin":"service3",
"createdCmHandles":[
{
- "cmHandle": "ch1(new)"
+ "cmHandle": "ch1-new"
}
]
}