From 79e41e0794035ea8dd3ae3064f8d368b5345df95 Mon Sep 17 00:00:00 2001 From: niamhcore Date: Fri, 20 Aug 2021 11:24:06 +0100 Subject: Write data for cm handle passthrough:running Issue-ID: CPS-574 Signed-off-by: niamhcore Change-Id: I15e2ad500d2bbf7a1d408b8a852287e55bddbecb --- docs/openapi/components.yml | 17 +++- docs/openapi/openapi.yml | 30 ++++++- .../dmi/rest/controller/DmiRestController.java | 99 +++++++++++++--------- .../org/onap/cps/ncmp/dmi/service/DmiService.java | 70 ++++++++------- .../onap/cps/ncmp/dmi/service/DmiServiceImpl.java | 76 +++++++++++------ .../dmi/service/client/SdncRestconfClient.java | 18 ++-- .../ncmp/dmi/service/operation/SdncOperations.java | 63 +++++++++----- .../rest/controller/DmiRestControllerSpec.groovy | 29 +++++-- .../cps/ncmp/dmi/service/DmiServiceImplSpec.groovy | 43 ++++++++-- .../service/client/SdncRestconfClientSpec.groovy | 2 +- .../service/operation/SdncOperationsSpec.groovy | 11 ++- src/test/resources/WriteDataForCmHandle.json | 10 +++ 12 files changed, 317 insertions(+), 151 deletions(-) create mode 100644 src/test/resources/WriteDataForCmHandle.json diff --git a/docs/openapi/components.yml b/docs/openapi/components.yml index cb39fa4e..ba2a0ece 100644 --- a/docs/openapi/components.yml +++ b/docs/openapi/components.yml @@ -58,7 +58,7 @@ components: namespace: type: string - OperationalRequest: + DataAccessReadRequest: type: object properties: operation: @@ -69,6 +69,21 @@ components: additionalProperties: type: string + DataAccessWriteRequest: + type: object + properties: + operation: + type: string + enum: [ create ] + dataType: + type: string + data: + type: object + cmHandleProperties: + type: object + additionalProperties: + type: string + responses: NotFound: description: The specified resource was not found diff --git a/docs/openapi/openapi.yml b/docs/openapi/openapi.yml index af285f4e..f169efd0 100644 --- a/docs/openapi/openapi.yml +++ b/docs/openapi/openapi.yml @@ -136,7 +136,7 @@ paths: content: application/json: schema: - $ref: 'components.yml#/components/schemas/OperationalRequest' + $ref: 'components.yml#/components/schemas/DataAccessReadRequest' responses: '200': $ref: 'components.yml#/components/responses/Ok' @@ -165,7 +165,7 @@ paths: content: application/json: schema: - $ref: 'components.yml#/components/schemas/OperationalRequest' + $ref: 'components.yml#/components/schemas/DataAccessReadRequest' responses: '200': $ref: 'components.yml#/components/responses/Ok' @@ -175,3 +175,29 @@ paths: $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' + + post: + description: Write data for a cmHandle using passthrough-running + tags: + - dmi-plugin + summary: Write data for a cmHandle + operationId: writeDataByPassthroughRunningForCmHandle + parameters: + - $ref: 'components.yml#/components/parameters/cmHandleInPath' + - $ref: 'components.yml#/components/parameters/resourceIdentifierInPath' + requestBody: + required: true + content: + application/json: + schema: + $ref: 'components.yml#/components/schemas/DataAccessWriteRequest' + responses: + '200': + $ref: 'components.yml#/components/responses/Ok' + '400': + $ref: 'components.yml#/components/responses/BadRequest' + '401': + $ref: 'components.yml#/components/responses/Unauthorized' + '403': + $ref: 'components.yml#/components/responses/Forbidden' + diff --git a/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java b/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java index 79c11a4e..32651e4d 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java @@ -27,14 +27,16 @@ import javax.validation.Valid; import javax.validation.constraints.Min; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.dmi.model.CmHandles; +import org.onap.cps.ncmp.dmi.model.DataAccessReadRequest; +import org.onap.cps.ncmp.dmi.model.DataAccessWriteRequest; import org.onap.cps.ncmp.dmi.model.ModuleReference; import org.onap.cps.ncmp.dmi.model.ModuleRequestParent; import org.onap.cps.ncmp.dmi.model.ModuleSet; -import org.onap.cps.ncmp.dmi.model.OperationalRequest; import org.onap.cps.ncmp.dmi.rest.api.DmiPluginApi; import org.onap.cps.ncmp.dmi.rest.api.DmiPluginInternalApi; import org.onap.cps.ncmp.dmi.service.DmiService; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -61,7 +63,7 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { @Override public ResponseEntity retrieveModuleResources(@Valid final ModuleRequestParent moduleRequestParent, - final String cmHandle) { + final String cmHandle) { if (moduleRequestParent.getOperation().toString().equals("read")) { final var moduleReferenceList = convertRestObjectToJavaApiObject(moduleRequestParent); final var response = dmiService.getModuleResources(cmHandle, moduleReferenceList); @@ -73,6 +75,25 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { return new ResponseEntity<>("Unsupported operation", HttpStatus.CONFLICT); } + /** + * Write data using passthrough for the given cmHandle. + * + * @param dataAccessWriteRequest pass through request + * @param cmHandle cmHandle + * @param resourceIdentifier resource identifier + * @return (@ code ResponseEntity) response entity + */ + @Override + public ResponseEntity writeDataByPassthroughRunningForCmHandle( + final DataAccessWriteRequest dataAccessWriteRequest, + final String cmHandle, final String resourceIdentifier) { + final String response = dmiService.writeResourceDataPassthroughForCmHandle(cmHandle, + resourceIdentifier, + MediaType.APPLICATION_JSON_VALUE, + dataAccessWriteRequest.getData()); + return new ResponseEntity<>(response, HttpStatus.OK); + } + /** * This method register given list of cm-handles to ncmp. * @@ -89,60 +110,58 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { } /** - * This method fetches the resource for given cm handle using pass - * through operational. It filters the response on the basis of depth and field - * query parameters and returns response. + * This method fetches the resource for given cm handle using pass through operational. It filters the response on + * the basis of depth and field query parameters and returns response. * - * @param cmHandle cm handle identifier - * @param resourceIdentifier resource identifier to fetch data - * @param body operational body - * @param accept accept header parameter - * @param fields fields to filter the response data - * @param depth depth parameter for the response + * @param cmHandle cm handle identifier + * @param resourceIdentifier resource identifier to fetch data + * @param dataAccessReadRequest data Access Read Request + * @param accept accept header parameter + * @param fields fields to filter the response data + * @param depth depth parameter for the response * @return {@code ResponseEntity} response entity */ @Override public ResponseEntity getResourceDataOperationalForCmHandle(final String cmHandle, - final String resourceIdentifier, - final @Valid OperationalRequest body, - final String accept, - final @Valid String fields, - final @Min(1) @Valid Integer depth) { + final String resourceIdentifier, + final @Valid DataAccessReadRequest dataAccessReadRequest, + final String accept, + final @Valid String fields, + final @Min(1) @Valid Integer depth) { final var modulesListAsJson = dmiService.getResourceDataOperationalForCmHandle(cmHandle, - resourceIdentifier, - accept, - fields, - depth, - body.getCmHandleProperties()); + resourceIdentifier, + accept, + fields, + depth, + dataAccessReadRequest.getCmHandleProperties()); return ResponseEntity.ok(modulesListAsJson); } /** - * This method fetches the resource for given cm handle using pass - * through running. It filters the response on the basis of depth and field - * query parameters and returns response. + * This method fetches the resource for given cm handle using pass through running. It filters the response on the + * basis of depth and field query parameters and returns response. * - * @param cmHandle cm handle identifier - * @param resourceIdentifier resource identifier to fetch data - * @param body operational body - * @param accept accept header parameter - * @param fields fields to filter the response data - * @param depth depth parameter for the response + * @param cmHandle cm handle identifier + * @param resourceIdentifier resource identifier to fetch data + * @param dataAccessReadRequest data Access Read Request + * @param accept accept header parameter + * @param fields fields to filter the response data + * @param depth depth parameter for the response * @return {@code ResponseEntity} response entity */ @Override public ResponseEntity getResourceDataPassthroughRunningForCmHandle(final String cmHandle, - final String resourceIdentifier, - final @Valid OperationalRequest body, - final String accept, - final @Valid String fields, - final @Min(1) @Valid Integer depth) { + final String resourceIdentifier, + final @Valid DataAccessReadRequest dataAccessReadRequest, + final String accept, + final @Valid String fields, + final @Min(1) @Valid Integer depth) { final var modulesListAsJson = dmiService.getResourceDataPassThroughRunningForCmHandle(cmHandle, - resourceIdentifier, - accept, - fields, - depth, - body.getCmHandleProperties()); + resourceIdentifier, + accept, + fields, + depth, + dataAccessReadRequest.getCmHandleProperties()); return ResponseEntity.ok(modulesListAsJson); } diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java index 83301270..f1446084 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java @@ -42,8 +42,8 @@ public interface DmiService { ModuleSet getModulesForCmHandle(String cmHandle) throws DmiException; /** - * This method used to register the given {@code CmHandles} - * which contains list of {@code CmHandle} to cps repository. + * This method used to register the given {@code CmHandles} which contains list of {@code CmHandle} to cps + * repository. * * @param cmHandles list of cm-handles */ @@ -53,50 +53,58 @@ public interface DmiService { * Get module resources for the given cm handle and modules. * * @param cmHandle cmHandle - * @param modules a list of module data + * @param modules a list of module data * @return returns all module resources */ String getModuleResources(String cmHandle, List modules); /** - * This method use to fetch the resource data from cm handle - * for datastore pass-through operational and resource Identifier. Fields and depths query - * parameter are used to filter the response from network resource. + * This method use to fetch the resource data from cm handle for datastore pass-through operational and resource + * Identifier. Fields and depths query parameter are used to filter the response from network resource. * - * @param cmHandle cm handle identifier - * @param resourceIdentifier resource identifier - * @param acceptParam accept header parameter - * @param fieldsQuery fields query parameter - * @param depthQuery depth query parameter + * @param cmHandle cm handle identifier + * @param resourceIdentifier resource identifier + * @param acceptParam accept header parameter + * @param fieldsQuery fields query parameter + * @param depthQuery depth query parameter * @param cmHandlePropertyMap cm handle properties - * * @return {@code Object} response from network function */ Object getResourceDataOperationalForCmHandle(@NotNull String cmHandle, - @NotNull String resourceIdentifier, - String acceptParam, - String fieldsQuery, - Integer depthQuery, - Map cmHandlePropertyMap); + @NotNull String resourceIdentifier, + String acceptParam, + String fieldsQuery, + Integer depthQuery, + Map cmHandlePropertyMap); /** - * This method use to fetch the resource data from cm handle - * for datastore pass-through running and resource Identifier. Fields and depths query - * parameter are used to filter the response from network resource. + * This method use to fetch the resource data from cm handle for datastore pass-through running and resource + * Identifier. Fields and depths query parameter are used to filter the response from network resource. * - * @param cmHandle cm handle identifier - * @param resourceIdentifier resource identifier - * @param acceptParam accept header parameter - * @param fieldsQuery fields query parameter - * @param depthQuery depth query parameter + * @param cmHandle cm handle identifier + * @param resourceIdentifier resource identifier + * @param acceptParam accept header parameter + * @param fieldsQuery fields query parameter + * @param depthQuery depth query parameter * @param cmHandlePropertyMap cm handle properties - * * @return {@code Object} response from network function */ Object getResourceDataPassThroughRunningForCmHandle(@NotNull String cmHandle, - @NotNull String resourceIdentifier, - String acceptParam, - String fieldsQuery, - Integer depthQuery, - Map cmHandlePropertyMap); + @NotNull String resourceIdentifier, + String acceptParam, + String fieldsQuery, + Integer depthQuery, + Map cmHandlePropertyMap); + + /** + * Write resource data to sdnc using passthrough running. + * + * @param cmHandle cmHandle + * @param resourceIdentifier resource identifier + * @param dataType accept header parameter + * @param data request data + * @return response from sdnc + */ + String writeResourceDataPassthroughForCmHandle(String cmHandle, String resourceIdentifier, String dataType, + Object data); } \ No newline at end of file diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java index 62f93e63..a139f7be 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java @@ -69,8 +69,8 @@ public class DmiServiceImpl implements DmiService { * @param objectMapper objectMapper */ public DmiServiceImpl(final DmiPluginProperties dmiPluginProperties, - final NcmpRestClient ncmpRestClient, - final SdncOperations sdncOperations, final ObjectMapper objectMapper) { + final NcmpRestClient ncmpRestClient, + final SdncOperations sdncOperations, final ObjectMapper objectMapper) { this.dmiPluginProperties = dmiPluginProperties; this.ncmpRestClient = ncmpRestClient; this.objectMapper = objectMapper; @@ -88,7 +88,7 @@ public class DmiServiceImpl implements DmiService { return createModuleSchema(responseBody); } else { throw new DmiException("SDNC is not able to process request.", - "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody()); + "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody()); } } @@ -103,7 +103,7 @@ public class DmiServiceImpl implements DmiService { } else { log.error("SDNC did not return a module resource for the given cmHandle {}", cmHandle); throw new ModuleResourceNotFoundException(cmHandle, - "SDNC did not return a module resource for the given cmHandle."); + "SDNC did not return a module resource for the given cmHandle."); } } return getModuleResponses.toJSONString(); @@ -126,7 +126,7 @@ public class DmiServiceImpl implements DmiService { } catch (final JsonProcessingException e) { log.error("Parsing error occurred while converting cm-handles to JSON {}", cmHandles); throw new DmiException("Internal Server Error.", - "Parsing error occurred while converting given cm-handles object list to JSON "); + "Parsing error occurred while converting given cm-handles object list to JSON "); } final ResponseEntity responseEntity = ncmpRestClient.registerCmHandlesWithNcmp(cmHandlesJson); if ((responseEntity.getStatusCode() != HttpStatus.CREATED)) { @@ -166,44 +166,66 @@ public class DmiServiceImpl implements DmiService { @Override public Object getResourceDataOperationalForCmHandle(final @NotNull String cmHandle, - final @NotNull String resourceIdentifier, - final String acceptParam, - final String fieldsQuery, - final Integer depthQuery, - final Map cmHandlePropertyMap) { + final @NotNull String resourceIdentifier, + final String acceptParam, + final String fieldsQuery, + final Integer depthQuery, + final Map cmHandlePropertyMap) { // not using cmHandlePropertyMap of onap dmi impl , other dmi impl might use this. final ResponseEntity responseEntity = sdncOperations.getResouceDataForOperationalAndRunning(cmHandle, - resourceIdentifier, - fieldsQuery, - depthQuery, - acceptParam, + resourceIdentifier, + fieldsQuery, + depthQuery, + acceptParam, CONTENT_QUERY_PASSTHROUGH_OPERATIONAL); return prepareAndSendResponse(responseEntity, cmHandle); } @Override public Object getResourceDataPassThroughRunningForCmHandle(final @NotNull String cmHandle, - final @NotNull String resourceIdentifier, - final String acceptParam, - final String fieldsQuery, - final Integer depthQuery, - final Map cmHandlePropertyMap) { + final @NotNull String resourceIdentifier, + final String acceptParam, + final String fieldsQuery, + final Integer depthQuery, + final Map cmHandlePropertyMap) { // not using cmHandlePropertyMap of onap dmi impl , other dmi impl might use this. final ResponseEntity responseEntity = sdncOperations.getResouceDataForOperationalAndRunning(cmHandle, - resourceIdentifier, - fieldsQuery, - depthQuery, - acceptParam, - CONTENT_QUERY_PASSTHROUGH_RUNNING); + resourceIdentifier, + fieldsQuery, + depthQuery, + acceptParam, + CONTENT_QUERY_PASSTHROUGH_RUNNING); return prepareAndSendResponse(responseEntity, cmHandle); } + @Override + public String writeResourceDataPassthroughForCmHandle(final String cmHandle, final String resourceIdentifier, + final String dataType, final Object data) { + final String jsonData; + try { + jsonData = objectMapper.writeValueAsString(data); + } catch (final JsonProcessingException e) { + log.error("JSON exception occurred when processing pass through request data for the given cmHandle {}", + cmHandle); + throw new DmiException("Unable to process incoming JSON from the request body.", + "JSON exception occurred when writing data for the given cmHandle " + cmHandle, e); + } + final ResponseEntity responseEntity = + sdncOperations.writeResourceDataPassthroughRunning(cmHandle, resourceIdentifier, dataType, jsonData); + if (responseEntity.getStatusCode() == HttpStatus.CREATED) { + return responseEntity.getBody(); + } else { + throw new DmiException(cmHandle, + "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody()); + } + } + private String prepareAndSendResponse(final ResponseEntity responseEntity, final String cmHandle) { if (responseEntity.getStatusCode() == HttpStatus.OK) { return responseEntity.getBody(); } else { throw new ResourceDataNotFound(cmHandle, - "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody()); + "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody()); } } @@ -217,9 +239,9 @@ public class DmiServiceImpl implements DmiService { moduleRequest = writer.writeValueAsString(ietfNetconfModuleReferences); } catch (final JsonProcessingException e) { log.error("JSON exception occurred when creating the module request for the given module reference {}", - moduleReference.getName()); + moduleReference.getName()); throw new DmiException("Unable to process JSON.", - "JSON exception occurred when creating the module request.", e); + "JSON exception occurred when creating the module request.", e); } return moduleRequest; } diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java b/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java index 499033d3..fe13a38d 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java @@ -23,7 +23,6 @@ package org.onap.cps.ncmp.dmi.service.client; import org.onap.cps.ncmp.dmi.config.DmiConfiguration.SdncProperties; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; @@ -43,7 +42,6 @@ public class SdncRestconfClient { * restconf get operation on sdnc. * * @param getResourceUrl sdnc get url - * * @return the response entity */ public ResponseEntity getOperation(final String getResourceUrl) { @@ -54,8 +52,7 @@ public class SdncRestconfClient { * Overloaded restconf get operation on sdnc with http headers. * * @param getResourceUrl sdnc get url - * @param httpHeaders http headers - * + * @param httpHeaders http headers * @return the response entity */ public ResponseEntity getOperation(final String getResourceUrl, final HttpHeaders httpHeaders) { @@ -71,20 +68,15 @@ public class SdncRestconfClient { * * @param postResourceUrl sdnc post resource url * @param jsonData json data + * @param httpHeaders HTTP headers * @return the response entity */ public ResponseEntity postOperationWithJsonData(final String postResourceUrl, - final String jsonData) { + final String jsonData, final HttpHeaders httpHeaders) { final var sdncBaseUrl = sdncProperties.getBaseUrl(); final var sdncRestconfUrl = sdncBaseUrl.concat(postResourceUrl); - final var httpEntity = new HttpEntity<>(jsonData, configureHttpHeaders()); - return restTemplate.postForEntity(sdncRestconfUrl, httpEntity, String.class); - } - - private HttpHeaders configureHttpHeaders() { - final var httpHeaders = new HttpHeaders(); httpHeaders.setBasicAuth(sdncProperties.getAuthUsername(), sdncProperties.getAuthPassword()); - httpHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - return httpHeaders; + final var httpEntity = new HttpEntity<>(jsonData, httpHeaders); + return restTemplate.postForEntity(sdncRestconfUrl, httpEntity, String.class); } } \ No newline at end of file diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java b/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java index ab9c7e1d..73503d23 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java @@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull; import org.onap.cps.ncmp.dmi.config.DmiConfiguration.SdncProperties; import org.onap.cps.ncmp.dmi.service.client.SdncRestconfClient; import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @@ -34,9 +35,9 @@ import org.springframework.stereotype.Component; public class SdncOperations { private static final String TOPOLOGY_URL_TEMPLATE_DATA = - "/rests/data/network-topology:network-topology/topology={topologyId}"; + "/rests/data/network-topology:network-topology/topology={topologyId}"; private static final String TOPOLOGY_URL_TEMPLATE_OPERATIONAL = - "/rests/operations/network-topology:network-topology/topology={topologyId}"; + "/rests/operations/network-topology:network-topology/topology={topologyId}"; private static final String MOUNT_URL_TEMPLATE = "/node={nodeId}/yang-ext:mount"; private static final String GET_SCHEMA_URL = "/ietf-netconf-monitoring:netconf-state/schemas"; private static final String GET_SCHEMA_SOURCES_URL = "/ietf-netconf-monitoring:get-schema"; @@ -56,7 +57,7 @@ public class SdncOperations { this.sdncProperties = sdncProperties; this.sdncRestconfClient = sdncRestconfClient; topologyUrlOperational = - TOPOLOGY_URL_TEMPLATE_OPERATIONAL.replace("{topologyId}", this.sdncProperties.getTopologyId()); + TOPOLOGY_URL_TEMPLATE_OPERATIONAL.replace("{topologyId}", this.sdncProperties.getTopologyId()); topologyUrlData = TOPOLOGY_URL_TEMPLATE_DATA.replace("{topologyId}", this.sdncProperties.getTopologyId()); } @@ -79,30 +80,32 @@ public class SdncOperations { * @return response entity */ public ResponseEntity getModuleResource(final String nodeId, final String moduleProperties) { - final String getYangResourceUrl = prepareGetOperationSchemaUrl(nodeId); - return sdncRestconfClient.postOperationWithJsonData(getYangResourceUrl, moduleProperties); + final var getYangResourceUrl = prepareGetOperationSchemaUrl(nodeId); + final var httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + return sdncRestconfClient + .postOperationWithJsonData(getYangResourceUrl, moduleProperties, httpHeaders); } /** - * This method fetches the resource data for given node identifier on given resource - * using sdnc client. + * This method fetches the resource data for given node identifier on given resource using sdnc client. * - * @param nodeId network resource identifier - * @param resourceId resource identifier + * @param nodeId network resource identifier + * @param resourceId resource identifier * @param fieldsValue fields query - * @param depthValue depth query + * @param depthValue depth query * @param acceptParam accept parameter * @return {@code ResponseEntity} response entity */ public ResponseEntity getResouceDataForOperationalAndRunning(final String nodeId, - final String resourceId, - final String fieldsValue, - final Integer depthValue, - final String acceptParam, + final String resourceId, + final String fieldsValue, + final Integer depthValue, + final String acceptParam, final String contentQuery) { final String getResourceDataUrl = prepareResourceDataUrl(nodeId, - resourceId, - getQueryList(fieldsValue, depthValue, contentQuery)); + resourceId, + getQueryList(fieldsValue, depthValue, contentQuery)); final HttpHeaders httpHeaders = new HttpHeaders(); if (!StringUtils.isEmpty(acceptParam)) { httpHeaders.set(HttpHeaders.ACCEPT, acceptParam); @@ -110,6 +113,23 @@ public class SdncOperations { return sdncRestconfClient.getOperation(getResourceDataUrl, httpHeaders); } + /** + * Write resource data using passthrough running. + * + * @param nodeId network resource identifier + * @param resourceId resource identifier + * @param contentType http content type + * @param requestData request data + * @return {@code ResponseEntity} response entity + */ + public ResponseEntity writeResourceDataPassthroughRunning(final String nodeId, + final String resourceId, final String contentType, final String requestData) { + final var getResourceDataUrl = preparePassthroughRunningUrl(nodeId, resourceId); + final var httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.parseMediaType(contentType)); + return sdncRestconfClient.postOperationWithJsonData(getResourceDataUrl, requestData, httpHeaders); + } + @NotNull private List getQueryList(final String fieldsValue, final Integer depthValue, final String contentQuery) { final List queryList = new LinkedList<>(); @@ -131,6 +151,10 @@ public class SdncOperations { return addResource(addTopologyDataUrlwithNode(nodeId), GET_SCHEMA_URL); } + private String preparePassthroughRunningUrl(final String nodeId, final String resourceId) { + return addResource(addTopologyDataUrlwithNode(nodeId), "/" + resourceId); + } + private String prepareGetOperationSchemaUrl(final String nodeId) { final var topologyMountUrl = topologyUrlOperational + MOUNT_URL_TEMPLATE; final var topologyMountUrlWithNodeId = topologyMountUrl.replace("{nodeId}", nodeId); @@ -139,8 +163,8 @@ public class SdncOperations { @NotNull private String prepareResourceDataUrl(final String nodeId, - final String resourceId, - final List queryList) { + final String resourceId, + final List queryList) { return addQuery(addResource(addTopologyDataUrlwithNode(nodeId), resourceId), queryList); } @@ -152,7 +176,7 @@ public class SdncOperations { return url.concat("/" + resourceId); } } - + @NotNull private String addQuery(final String url, final List queryList) { if (queryList.isEmpty()) { @@ -173,5 +197,4 @@ public class SdncOperations { final String topologyMountUrl = topologyUrlData + MOUNT_URL_TEMPLATE; return topologyMountUrl.replace("{nodeId}", nodeId); } - } \ No newline at end of file diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy index b1528c71..e08870fd 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy @@ -26,7 +26,8 @@ import org.onap.cps.ncmp.dmi.TestUtils import org.onap.cps.ncmp.dmi.exception.DmiException import org.onap.cps.ncmp.dmi.exception.ModuleResourceNotFoundException import org.onap.cps.ncmp.dmi.exception.ModulesNotFoundException - +import org.onap.cps.ncmp.dmi.model.DataAccessReadRequest +import org.onap.cps.ncmp.dmi.model.DataAccessWriteRequest import org.onap.cps.ncmp.dmi.model.ModuleReference import org.onap.cps.ncmp.dmi.model.ModuleSchemaList import org.onap.cps.ncmp.dmi.model.ModuleSchemaProperties @@ -44,7 +45,6 @@ import org.springframework.http.MediaType import org.springframework.test.web.servlet.MockMvc import spock.lang.Specification -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put @@ -121,7 +121,7 @@ class DmiRestControllerSpec extends Specification { def 'Register given list of cm handles.'() { given: 'register cm handle url and cm handles json' def registerCmhandlesPost = "${basePathV1}/inventory/cmHandles" - def cmHandleJson = '{"cmHandles":["node1", "node2"]}' + def cmHandleJson = '{"cmHandles":["node1", "node2"]}' when: 'post register cm handles api is invoked' def response = mvc.perform( post(registerCmhandlesPost) @@ -161,12 +161,12 @@ class DmiRestControllerSpec extends Specification { moduleReference2.name = 'nc-notifications' moduleReference2.revision = '2008-07-14' def moduleReferences = [moduleReference1, moduleReference2] - mockDmiService.getModuleResources('some-cm-handle', moduleReferences ) >> '{some-json}' + mockDmiService.getModuleResources('some-cm-handle', moduleReferences) >> '{some-json}' when: 'get module resource api is invoked' def response = mvc.perform(post(getModulesEndpoint) .contentType(MediaType.APPLICATION_JSON) .content(jsonData)).andReturn().response - then:'a OK status is returned' + then: 'a OK status is returned' response.status == HttpStatus.OK.value() and: 'the expected response is returned' response.getContentAsString() == '{some-json}' @@ -204,7 +204,24 @@ class DmiRestControllerSpec extends Specification { 'application/json', 'myfields', 5, - ['prop1':'value1', 'prop2':'value2']) + ['prop1': 'value1', 'prop2': 'value2']) + } + + def 'Write data using passthrough running for a cm handle.'() { + given: 'write data for cmHandle url and jsonData' + def writeDataforCmHandlePassthroughRunning = "${basePathV1}/ch/some-cmHandle/data/ds/ncmp-datastore:passthrough-running/some-resourceIdentifier" + def jsonData = TestUtils.getResourceFileContent('WriteDataForCmHandle.json') + and: 'dmi service is called' + mockDmiService.writeResourceDataPassthroughForCmHandle('some-cmHandle', 'some-resourceIdentifier', 'application/json', ['some-data': 'some-value']) >> '{some-json}' + when: 'write cmHandle passthrough running post api is invoked with json data' + def response = mvc.perform( + post(writeDataforCmHandlePassthroughRunning).contentType(MediaType.APPLICATION_JSON) + .content(jsonData) + ).andReturn().response + then: 'response status is ok' + response.status == HttpStatus.OK.value() + and: 'the data in the request body is as expected' + response.getContentAsString() == '{some-json}' } def 'Get resource data for pass-through running from cm handle.'() { diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy index 31b60a7c..e3703020 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy @@ -68,7 +68,7 @@ class DmiServiceImplSpec extends Specification { when: 'get modules for cm-handle is called' def result = objectUnderTest.getModulesForCmHandle(cmHandle) then: 'a dmi exception is thrown' - thrown(DmiException) + thrown(DmiException) } def 'Call get modules for cm-handle and SDNC returns "bad request" status.'() { @@ -149,8 +149,8 @@ class DmiServiceImplSpec extends Specification { when: 'get module resources is invoked with the given cm handle and a module list' def response = objectUnderTest.getModuleResources(cmHandle, moduleList) then: 'then get modules resources called correctly' - 1 * mockSdncOperations.getModuleResource(cmHandle,excpectedModulesJson1) >> new ResponseEntity('response-body1', HttpStatus.OK) - 1 * mockSdncOperations.getModuleResource(cmHandle,excpectedModulesJson2) >> new ResponseEntity('response-body2', HttpStatus.OK) + 1 * mockSdncOperations.getModuleResource(cmHandle, excpectedModulesJson1) >> new ResponseEntity('response-body1', HttpStatus.OK) + 1 * mockSdncOperations.getModuleResource(cmHandle, excpectedModulesJson2) >> new ResponseEntity('response-body2', HttpStatus.OK) and: 'the response equals to the expected response body' response == '["response-body1","response-body2"]' } @@ -159,7 +159,7 @@ class DmiServiceImplSpec extends Specification { given: 'get module schema is invoked and returns not found' mockSdncOperations.getModuleResource(_ as String, _ as String) >> new ResponseEntity('some-response-body', HttpStatus.BAD_REQUEST) when: 'get module resources is invoked with the given cm handle and a module list' - objectUnderTest.getModuleResources('some-cmHandle', [new ModuleReference()] as LinkedList ) + objectUnderTest.getModuleResources('some-cmHandle', [new ModuleReference()] as LinkedList) then: 'ModuleResourceNotFoundException is thrown' thrown(ModuleResourceNotFoundException) } @@ -173,8 +173,7 @@ class DmiServiceImplSpec extends Specification { def depthParam = 10 def contentQuery = 'content=all' and: 'sdnc operation returns OK response' - mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam, - depthParam, acceptHeaderParam, contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK) + mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam, depthParam, acceptHeaderParam, contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK) when: 'get resource data from cm handles service method invoked' def response = objectUnderTest.getResourceDataOperationalForCmHandle(cmHandle, resourceId, acceptHeaderParam, @@ -191,8 +190,7 @@ class DmiServiceImplSpec extends Specification { def fieldsParam = 'testFields' def depthParam = 10 and: 'sdnc operation returns "NOT_FOUND" response' - mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam, - depthParam, acceptHeaderParam, _ as String) >> new ResponseEntity<>(HttpStatus.NOT_FOUND) + mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam, depthParam, acceptHeaderParam, _ as String) >> new ResponseEntity<>(HttpStatus.NOT_FOUND) when: 'get resource data from cm handles service method invoked' objectUnderTest.getResourceDataOperationalForCmHandle(cmHandle, resourceId, acceptHeaderParam, @@ -211,7 +209,7 @@ class DmiServiceImplSpec extends Specification { def contentQuery = 'content=config' and: 'sdnc operation returns OK response' mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam, - depthParam, acceptHeaderParam, contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK) + depthParam, acceptHeaderParam, contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK) when: 'get resource data from cm handles service method invoked' def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle(cmHandle, resourceId, acceptHeaderParam, @@ -219,4 +217,31 @@ class DmiServiceImplSpec extends Specification { then: 'response have expected json' response == 'response json' } + + def 'Write resource data using for passthrough running for the given cm handle.'() { + given: 'sdnc returns a created response' + mockSdncOperations.writeResourceDataPassthroughRunning(_, _, _, _) >> new ResponseEntity('response json', HttpStatus.CREATED) + when: 'write resource data from cm handles service method invoked' + def response = objectUnderTest.writeResourceDataPassthroughForCmHandle('some-cmHandle', + 'some-resourceIdentifier', 'some-dataType', '{some-data}') + then: 'response have expected json' + response == 'response json' + } + + def 'Write resource data for passthrough running with a #scenario.'() { + given: 'sdnc returns a response for the write operation' + mockSdncOperations.writeResourceDataPassthroughRunning(_, _, _, _) >> new ResponseEntity('response json', httpStatus) + and: 'the data provided in the request body is written as a string' + objectUnderTest.objectMapper = mockObjectMapper + mockObjectMapper.writeValueAsString(_) >> jsonString + when: 'write resource data for pass through method is invoked' + objectUnderTest.writeResourceDataPassthroughForCmHandle('some-cmHandle', + 'some-resourceIdentifier', 'some-dataType', new Object()) + then: 'a dmi exception is thrown' + thrown(DmiException.class) + where: 'the following combinations are tested' + scenario | httpStatus | jsonString + '500 response from sdnc' | HttpStatus.INTERNAL_SERVER_ERROR | '{some-json-data}' + 'json processing exception ' | HttpStatus.OK | { throw new JsonProcessingException('some error.') } + } } \ No newline at end of file diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClientSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClientSpec.groovy index e2621e47..9a7ed180 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClientSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClientSpec.groovy @@ -57,7 +57,7 @@ class SdncRestconfClientSpec extends Specification { and: 'the rest template returns a valid response entity' def mockResponseEntity = Mock(ResponseEntity) when: 'get module resources is invoked' - def result = objectUnderTest.postOperationWithJsonData(getModuleResourceUrl, jsonData) + def result = objectUnderTest.postOperationWithJsonData(getModuleResourceUrl, jsonData, new HttpHeaders()) then: 'the rest template is called with the correct uri and json in the body' 1 * mockRestTemplate.postForEntity({ it.toString() == 'http://some-uri/getModuleResourceUrl' }, { it.body.contains(jsonData) }, String.class) >> mockResponseEntity diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy index 3557bc1b..c9d7d1b8 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy @@ -56,7 +56,7 @@ class SdncOperationsSpec extends Specification { when: 'get module resources is called with the expected parameters' objectUnderTest.getModuleResource(nodeId, 'some-json-data') then: 'the SDNC Rest client is invoked with the correct URL and json data' - 1 * mockSdncRestClient.postOperationWithJsonData(expectedUrl, 'some-json-data') + 1 * mockSdncRestClient.postOperationWithJsonData(expectedUrl, 'some-json-data', _ as HttpHeaders) } def 'Get resource data from node to SDNC.'() { @@ -68,4 +68,13 @@ class SdncOperationsSpec extends Specification { then: 'the get operation is executed with the correct URL' 1 * mockSdncRestClient.getOperation(expectedUrl, _ as HttpHeaders) } + + def 'Write resource data to SDNC.'() { + given: 'excpected url, topology-id, sdncOperation object' + def expectedUrl = '/rests/data/network-topology:network-topology/topology=test-topology/node=node1/yang-ext:mount/testResourceId' + when: 'write resource data for pass through running is called' + objectUnderTest.writeResourceDataPassthroughRunning('node1', 'testResourceId', 'application/json','testData') + then: 'the post operation is executed with the correct URL' + 1 * mockSdncRestClient.postOperationWithJsonData(expectedUrl, _ as String, _ as HttpHeaders) + } } \ No newline at end of file diff --git a/src/test/resources/WriteDataForCmHandle.json b/src/test/resources/WriteDataForCmHandle.json new file mode 100644 index 00000000..8eb19599 --- /dev/null +++ b/src/test/resources/WriteDataForCmHandle.json @@ -0,0 +1,10 @@ +{ + "operation": "create", + "dataType": "application/json", + "data": { + "some-data": "some-value" + }, + "cmHandleProperties": { + "some-property": "some-property-value" + } +} \ No newline at end of file -- cgit 1.2.3-korg