From: Ruslan Kashapov Date: Tue, 20 Apr 2021 08:14:30 +0000 (+0300) Subject: Create child data node (part 2): NCMP service + REST X-Git-Tag: 1.1.0~78 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=d07ebc86b474e0eb8e8f2f2ba24db4ef46f13b79;p=cps.git Create child data node (part 2): NCMP service + REST Issue-ID: CPS-337 Change-Id: Icf703f6f375e5f280058d58c781eac081f3dd161 Signed-off-by: Ruslan Kashapov --- diff --git a/cps-ncmp-rest/docs/openapi/ncmproxy.yml b/cps-ncmp-rest/docs/openapi/ncmproxy.yml index 2a70d70a6..1bbc096f0 100644 --- a/cps-ncmp-rest/docs/openapi/ncmproxy.yml +++ b/cps-ncmp-rest/docs/openapi/ncmproxy.yml @@ -1,5 +1,6 @@ # ============LICENSE_START======================================================= # Modification (C) 2021 Nordix Foundation +# Modification (C) 2021 Pantheon.tech # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -64,6 +65,33 @@ nodesByCmHandleAndCpsPath: $ref: 'components.yaml#/components/responses/NotFound' nodesByCmHandleAndXpath: + post: + description: Create a node with descendants for the given CM Handle; top level or under existing node (requires xpath) + tags: + - network-cm-proxy + summary: Create a node with descendants + operationId: createNode + parameters: + - $ref: 'components.yaml#/components/parameters/cmHandleInPath' + - $ref: 'components.yaml#/components/parameters/xpathInQuery' + requestBody: + required: true + content: + application/json: + schema: + type: string + responses: + 201: + $ref: 'components.yaml#/components/responses/Created' + 400: + $ref: 'components.yaml#/components/responses/BadRequest' + 401: + $ref: 'components.yaml#/components/responses/Unauthorized' + 403: + $ref: 'components.yaml#/components/responses/Forbidden' + 404: + $ref: 'components.yaml#/components/responses/NotFound' + patch: description: Update node leaves for the given cps path and cm Handle tags: 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 acbbdd939..fccfb712a 100644 --- 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 @@ -47,6 +47,13 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { @Autowired private NetworkCmProxyDataService networkCmProxyDataService; + @Override + public ResponseEntity createNode(final String jsonData, final String cmHandle, + final String parentNodeXpath) { + networkCmProxyDataService.createDataNode(cmHandle, parentNodeXpath, jsonData); + return new ResponseEntity<>(HttpStatus.CREATED); + } + @Override public ResponseEntity getNodeByCmHandleAndXpath(final String cmHandle, @Valid final String xpath, @Valid final Boolean includeDescendants) { 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 aa9fa86d1..f0a3d09c2 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 @@ -21,6 +21,12 @@ package org.onap.cps.ncmp.rest.controller +import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS +import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put import com.google.gson.Gson import org.onap.cps.ncmp.api.NetworkCmProxyDataService @@ -35,10 +41,6 @@ import org.springframework.test.web.servlet.MockMvc import spock.lang.Specification import spock.lang.Unroll -import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS -import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.* - @WebMvcTest class NetworkCmProxyControllerSpec extends Specification { @@ -78,10 +80,32 @@ class NetworkCmProxyControllerSpec extends Specification { def expectedJsonContent = new Gson().toJson(dataNode) response.getContentAsString().contains(expectedJsonContent) where: 'the following options for include descendants are provided in the request' - scenario | includeDescendantsOption || expectedCpsDataServiceOption - 'no descendants by default'| '' || OMIT_DESCENDANTS - 'no descendant explicitly' | 'false' || OMIT_DESCENDANTS - 'descendants' | 'true' || INCLUDE_ALL_DESCENDANTS + scenario | includeDescendantsOption || expectedCpsDataServiceOption + 'no descendants by default' | '' || OMIT_DESCENDANTS + 'no descendant explicitly' | 'false' || OMIT_DESCENDANTS + 'descendants' | 'true' || INCLUDE_ALL_DESCENDANTS + } + + @Unroll + def 'Create data node: #scenario.'() { + given: 'json data' + def jsonData = 'json data' + when: 'post request is performed' + def response = mvc.perform( + post("$dataNodeBaseEndpoint/cm-handles/$cmHandle/nodes") + .contentType(MediaType.APPLICATION_JSON) + .content(jsonData) + .param('xpath', reqXpath) + ).andReturn().response + then: 'the service method is invoked once with expected parameters' + 1 * mockNetworkCmProxyDataService.createDataNode(cmHandle, usedXpath, jsonData) + and: 'response status indicates success' + response.status == HttpStatus.CREATED.value() + where: 'following parameters were used' + scenario | reqXpath || usedXpath + 'no xpath parameter' | '' || '/' + 'root xpath' | '/' || '/' + 'parent node xpath' | '/xpath' || '/xpath' } def 'Update data node leaves.'() { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java index 158f20ef9..8176ea50f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java @@ -2,6 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2021 highstreet technologies GmbH * Copyright (C) 2021 Nordix Foundation + * Modifications Copyright (C) 2021 Pantheon.tech * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,6 +57,16 @@ public interface NetworkCmProxyDataService { Collection queryDataNodes(@NonNull String cmHandle, @NonNull String cpsPath, @NonNull FetchDescendantsOption fetchDescendantsOption); + /** + * Creates data node with descendants at root level or under existing node (if parent node xpath is provided). + * + * @param cmHandle The identifier for a network function, network element, subnetwork or any other cm + * object managed by Network CM Proxy + * @param parentNodeXpath xpath to parent node or '/' for root level + * @param jsonData data as JSON string + */ + void createDataNode(@NonNull String cmHandle, @NonNull String parentNodeXpath, @NonNull String jsonData); + /** * Updates data node for given cm handle using xpath to parent node. * diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index 9e013145d..56f4cf8dc 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -2,6 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2021 highstreet technologies GmbH * Copyright (C) 2021 Nordix Foundation + * Modifications Copyright (C) 2021 Pantheon.tech * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +29,7 @@ import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; @Service public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService { @@ -40,25 +42,38 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService @Autowired private CpsQueryService cpsQueryService; + private String getDataspaceName() { + return NF_PROXY_DATASPACE_NAME; + } + @Override public DataNode getDataNode(final String cmHandle, final String xpath, final FetchDescendantsOption fetchDescendantsOption) { - return cpsDataService.getDataNode(NF_PROXY_DATASPACE_NAME, cmHandle, xpath, fetchDescendantsOption); + return cpsDataService.getDataNode(getDataspaceName(), cmHandle, xpath, fetchDescendantsOption); } @Override public Collection queryDataNodes(final String cmHandle, final String cpsPath, final FetchDescendantsOption fetchDescendantsOption) { - return cpsQueryService.queryDataNodes(NF_PROXY_DATASPACE_NAME, cmHandle, cpsPath, fetchDescendantsOption); + return cpsQueryService.queryDataNodes(getDataspaceName(), cmHandle, cpsPath, fetchDescendantsOption); + } + + @Override + public void createDataNode(final String cmHandle, final String parentNodeXpath, final String jsonData) { + if (StringUtils.isEmpty(parentNodeXpath) || "/".equals(parentNodeXpath)) { + cpsDataService.saveData(getDataspaceName(), cmHandle, jsonData); + } else { + cpsDataService.saveData(getDataspaceName(), cmHandle, parentNodeXpath, jsonData); + } } @Override public void updateNodeLeaves(final String cmHandle, final String parentNodeXpath, final String jsonData) { - cpsDataService.updateNodeLeaves(NF_PROXY_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData); + cpsDataService.updateNodeLeaves(getDataspaceName(), cmHandle, parentNodeXpath, jsonData); } @Override public void replaceNodeTree(final String cmHandle, final String parentNodeXpath, final String jsonData) { - cpsDataService.replaceNodeTree(NF_PROXY_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData); + cpsDataService.replaceNodeTree(getDataspaceName(), cmHandle, parentNodeXpath, jsonData); } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/api/impl/NetworkCmProxyDataServiceImplSpec.groovy index 49028becd..95493bf51 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/api/impl/NetworkCmProxyDataServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/api/impl/NetworkCmProxyDataServiceImplSpec.groovy @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2021 Nordix Foundation + * Modifications Copyright (C) 2021 Pantheon.tech * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +25,7 @@ import org.onap.cps.api.CpsQueryService import org.onap.cps.ncmp.api.impl.NetworkCmProxyDataServiceImpl import org.onap.cps.spi.FetchDescendantsOption import spock.lang.Specification +import spock.lang.Unroll class NetworkCmProxyDataServiceImplSpec extends Specification { def objectUnderTest = new NetworkCmProxyDataServiceImpl() @@ -49,6 +51,30 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { fetchDescendantsOption << FetchDescendantsOption.values() } + @Unroll + def 'Create full data node: #scenario.'() { + given: 'a cm handle and root xpath' + def jsonData = 'some json' + when: 'createDataNode is invoked' + objectUnderTest.createDataNode(cmHandle, xpath, jsonData) + then: 'the CPS service method is invoked once with the expected parameters' + 1 * mockcpsDataService.saveData(expectedDataspaceName, cmHandle, jsonData) + where: 'following parameters were used' + scenario | xpath + 'no xpath' | '' + 'root level xpath' | '/' + } + + def 'Create child data node.'() { + given: 'a cm handle and parent node xpath' + def jsonData = 'some json' + def xpath = '/test-node' + when: 'createDataNode is invoked' + objectUnderTest.createDataNode(cmHandle, xpath, jsonData) + then: 'the CPS service method is invoked once with the expected parameters' + 1 * mockcpsDataService.saveData(expectedDataspaceName, cmHandle, xpath, jsonData) + } + def 'Update data node leaves.'() { given: 'a cm Handle and a cps path' def xpath = '/xpath'