diff options
Diffstat (limited to 'cps-rest')
9 files changed, 162 insertions, 75 deletions
diff --git a/cps-rest/docs/openapi/components.yml b/cps-rest/docs/openapi/components.yml index a2587eb56d..40f0e170ff 100644 --- a/cps-rest/docs/openapi/components.yml +++ b/cps-rest/docs/openapi/components.yml @@ -141,17 +141,17 @@ components: name: kids deltaReportSample: value: - - action: "ADD" + - action: "create" xpath: "/bookstore/categories/[@code=3]" target-data: code: 3, name: "kidz" - - action: "REMOVE" + - action: "remove" xpath: "/bookstore/categories/[@code=1]" source-data: code: 1, name: "Fiction" - - action: "UPDATE" + - action: "replace" xpath: "/bookstore/categories/[@code=2]" source-data: name: "Funny" @@ -183,6 +183,14 @@ components: schema: type: string example: my-anchor + sourceAnchorNameInPath: + name: source-anchor-name + in: path + description: source-anchor-name + required: true + schema: + type: string + example: my-anchor schemaSetNameInQuery: name: schema-set-name in: query @@ -312,6 +320,15 @@ components: schema: type: integer example: 10 + dryRunInQuery: + name: dry-run + in: query + description: Boolean flag to validate data, without persisting it. Default value is set to false. + required: false + schema: + type: boolean + default: false + example: false responses: NotFound: diff --git a/cps-rest/docs/openapi/cpsData.yml b/cps-rest/docs/openapi/cpsData.yml index 1e70ef60c8..daf59bbfbf 100644 --- a/cps-rest/docs/openapi/cpsData.yml +++ b/cps-rest/docs/openapi/cpsData.yml @@ -32,15 +32,24 @@ listElementByDataspaceAndAnchor: - $ref: 'components.yml#/components/parameters/anchorNameInPath' - $ref: 'components.yml#/components/parameters/requiredXpathInQuery' - $ref: 'components.yml#/components/parameters/observedTimestampInQuery' + - $ref: 'components.yml#/components/parameters/contentTypeInHeader' requestBody: required: true content: application/json: schema: - type: object + type: string examples: dataSample: $ref: 'components.yml#/components/examples/dataSample' + application/xml: + schema: + type: object + xml: + name: stores + examples: + dataSample: + $ref: 'components.yml#/components/examples/dataSampleXml' responses: '201': $ref: 'components.yml#/components/responses/Created' @@ -93,6 +102,7 @@ nodesByDataspaceAndAnchor: - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' - $ref: 'components.yml#/components/parameters/anchorNameInPath' - $ref: 'components.yml#/components/parameters/xpathInQuery' + - $ref: 'components.yml#/components/parameters/dryRunInQuery' - $ref: 'components.yml#/components/parameters/observedTimestampInQuery' - $ref: 'components.yml#/components/parameters/contentTypeInHeader' requestBody: diff --git a/cps-rest/docs/openapi/cpsDataV2.yml b/cps-rest/docs/openapi/cpsDataV2.yml index a1433badf6..d5a8ef3891 100644 --- a/cps-rest/docs/openapi/cpsDataV2.yml +++ b/cps-rest/docs/openapi/cpsDataV2.yml @@ -46,7 +46,7 @@ nodeByDataspaceAndAnchor: $ref: 'components.yml#/components/responses/InternalServerError' x-codegen-request-body-name: xpath -deltaByDataspaceAndAnchors: +delta: get: description: Get delta between two anchors within a given dataspace tags: @@ -55,7 +55,7 @@ deltaByDataspaceAndAnchors: operationId: getDeltaByDataspaceAndAnchors parameters: - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' - - $ref: 'components.yml#/components/parameters/anchorNameInPath' + - $ref: 'components.yml#/components/parameters/sourceAnchorNameInPath' - $ref: 'components.yml#/components/parameters/targetAnchorNameInQuery' - $ref: 'components.yml#/components/parameters/xpathInQuery' - $ref: 'components.yml#/components/parameters/descendantsInQuery' @@ -76,8 +76,6 @@ deltaByDataspaceAndAnchors: '500': $ref: 'components.yml#/components/responses/InternalServerError' x-codegen-request-body-name: xpath - -deltaByDataspaceAnchorAndPayload: post: description: Get delta between an anchor in a dataspace and JSON payload tags: @@ -86,7 +84,7 @@ deltaByDataspaceAnchorAndPayload: operationId: getDeltaByDataspaceAnchorAndPayload parameters: - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' - - $ref: 'components.yml#/components/parameters/anchorNameInPath' + - $ref: 'components.yml#/components/parameters/sourceAnchorNameInPath' - $ref: 'components.yml#/components/parameters/xpathInQuery' requestBody: content: diff --git a/cps-rest/docs/openapi/openapi.yml b/cps-rest/docs/openapi/openapi.yml index b4e0b70408..95c32312cf 100644 --- a/cps-rest/docs/openapi/openapi.yml +++ b/cps-rest/docs/openapi/openapi.yml @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (C) 2021-2023 Nordix Foundation +# Copyright (C) 2021-2024 Nordix Foundation # Modifications Copyright (C) 2021 Pantheon.tech # Modifications Copyright (C) 2021 Bell Canada. # Modifications Copyright (C) 2022-2024 TechMahindra Ltd. @@ -23,7 +23,7 @@ openapi: 3.0.3 info: title: ONAP Open API v3 Configuration Persistence Service description: Configuration Persistence Service is a Model Driven Generic Database - version: "1.0.0" + version: "3.5.4" contact: name: ONAP url: "https://onap.readthedocs.io" @@ -31,10 +31,6 @@ info: license: name: "Apache 2.0" url: "http://www.apache.org/licenses/LICENSE-2.0" - x-planned-retirement-date: "202212" - x-component: "Modeling" - x-logo: - url: "cps_logo.png" servers: - url: /cps/api @@ -104,11 +100,8 @@ paths: /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes: $ref: 'cpsData.yml#/listElementByDataspaceAndAnchor' - /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/deltaAnchors: - $ref: 'cpsDataV2.yml#/deltaByDataspaceAndAnchors' - - /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/deltaPayload: - $ref: 'cpsDataV2.yml#/deltaByDataspaceAnchorAndPayload' + /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta: + $ref: 'cpsDataV2.yml#/delta' /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query: $ref: 'cpsQueryV1Deprecated.yml#/nodesByDataspaceAndAnchorAndCpsPath' diff --git a/cps-rest/pom.xml b/cps-rest/pom.xml index 7f25ebc472..71395c2f0d 100644 --- a/cps-rest/pom.xml +++ b/cps-rest/pom.xml @@ -27,7 +27,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.5.2-SNAPSHOT</version> + <version>3.5.5-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> @@ -196,6 +196,25 @@ </resources> </configuration> </execution> + <execution> + <id>copy-to-doc-folder</id> + <phase>compile</phase> + <goals> + <goal>copy-resources</goal> + </goals> + <configuration> + <outputDirectory>${project.basedir}/../docs/api/swagger/cps</outputDirectory> + <overwrite>true</overwrite> + <resources> + <resource> + <directory>${project.basedir}/target/generated-sources/openapi/</directory> + <includes> + <include>openapi.yaml</include> + </includes> + </resource> + </resources> + </configuration> + </execution> </executions> </plugin> </plugins> diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java index 6100b7edd9..7390afcf98 100755 --- a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech - * Modifications Copyright (C) 2021-2023 Nordix Foundation + * Modifications Copyright (C) 2021-2024 Nordix Foundation * Modifications Copyright (C) 2022-2024 TechMahindra Ltd. * Modifications Copyright (C) 2022 Deutsche Telekom AG * ================================================================================ @@ -37,9 +37,11 @@ import java.util.List; import java.util.Map; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; +import org.onap.cps.api.CpsAnchorService; import org.onap.cps.api.CpsDataService; import org.onap.cps.rest.api.CpsDataApi; import org.onap.cps.spi.FetchDescendantsOption; +import org.onap.cps.spi.model.Anchor; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.DeltaReport; import org.onap.cps.utils.ContentType; @@ -63,6 +65,7 @@ public class DataRestController implements CpsDataApi { private static final DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_FORMAT); private final CpsDataService cpsDataService; + private final CpsAnchorService cpsAnchorService; private final JsonObjectMapper jsonObjectMapper; private final PrefixResolver prefixResolver; @@ -71,16 +74,21 @@ public class DataRestController implements CpsDataApi { final String dataspaceName, final String anchorName, final String contentTypeInHeader, final String nodeData, final String parentNodeXpath, - final String observedTimestamp) { + final Boolean dryRunEnabled, final String observedTimestamp) { final ContentType contentType = getContentTypeFromHeader(contentTypeInHeader); - if (isRootXpath(parentNodeXpath)) { - cpsDataService.saveData(dataspaceName, anchorName, nodeData, - toOffsetDateTime(observedTimestamp), contentType); + if (Boolean.TRUE.equals(dryRunEnabled)) { + cpsDataService.validateData(dataspaceName, anchorName, parentNodeXpath, nodeData, contentType); + return ResponseEntity.ok().build(); } else { - cpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath, - nodeData, toOffsetDateTime(observedTimestamp), contentType); + if (isRootXpath(parentNodeXpath)) { + cpsDataService.saveData(dataspaceName, anchorName, nodeData, + toOffsetDateTime(observedTimestamp), contentType); + } else { + cpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath, + nodeData, toOffsetDateTime(observedTimestamp), contentType); + } + return ResponseEntity.status(HttpStatus.CREATED).build(); } - return new ResponseEntity<>(HttpStatus.CREATED); } @Override @@ -95,9 +103,11 @@ public class DataRestController implements CpsDataApi { @Override public ResponseEntity<String> addListElements(final String apiVersion, final String dataspaceName, final String anchorName, final String parentNodeXpath, - final Object jsonData, final String observedTimestamp) { + final String contentTypeInHeader, final String nodeData, + final String observedTimestamp) { + final ContentType contentType = getContentTypeFromHeader(contentTypeInHeader); cpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath, - jsonObjectMapper.asJsonString(jsonData), toOffsetDateTime(observedTimestamp)); + nodeData, toOffsetDateTime(observedTimestamp), contentType); return new ResponseEntity<>(HttpStatus.CREATED); } @@ -110,7 +120,8 @@ public class DataRestController implements CpsDataApi { ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS; final DataNode dataNode = cpsDataService.getDataNodes(dataspaceName, anchorName, xpath, fetchDescendantsOption).iterator().next(); - final String prefix = prefixResolver.getPrefix(dataspaceName, anchorName, dataNode.getXpath()); + final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName); + final String prefix = prefixResolver.getPrefix(anchor, dataNode.getXpath()); return new ResponseEntity<>(DataMapUtils.toDataMapWithIdentifier(dataNode, prefix), HttpStatus.OK); } @@ -125,8 +136,9 @@ public class DataRestController implements CpsDataApi { final Collection<DataNode> dataNodes = cpsDataService.getDataNodes(dataspaceName, anchorName, xpath, fetchDescendantsOption); final List<Map<String, Object>> dataMaps = new ArrayList<>(dataNodes.size()); + final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName); for (final DataNode dataNode: dataNodes) { - final String prefix = prefixResolver.getPrefix(dataspaceName, anchorName, dataNode.getXpath()); + final String prefix = prefixResolver.getPrefix(anchor, dataNode.getXpath()); final Map<String, Object> dataMap = DataMapUtils.toDataMapWithIdentifier(dataNode, prefix); dataMaps.add(dataMap); } diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java index 5334b48143..547be669ae 100644 --- a/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2024 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada. * Modifications Copyright (C) 2022-2023 TechMahindra Ltd. * ================================================================================ @@ -29,10 +29,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import lombok.RequiredArgsConstructor; +import org.onap.cps.api.CpsAnchorService; import org.onap.cps.api.CpsQueryService; import org.onap.cps.rest.api.CpsQueryApi; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.PaginationOption; +import org.onap.cps.spi.model.Anchor; import org.onap.cps.spi.model.DataNode; import org.onap.cps.utils.DataMapUtils; import org.onap.cps.utils.JsonObjectMapper; @@ -48,6 +50,7 @@ import org.springframework.web.bind.annotation.RestController; public class QueryRestController implements CpsQueryApi { private final CpsQueryService cpsQueryService; + private final CpsAnchorService cpsAnchorService; private final JsonObjectMapper jsonObjectMapper; private final PrefixResolver prefixResolver; @@ -87,14 +90,15 @@ public class QueryRestController implements CpsQueryApi { cpsPath, fetchDescendantsOption, paginationOption); final List<Map<String, Object>> dataNodesAsListOfMaps = new ArrayList<>(dataNodes.size()); String prefix = null; - final Map<String, List<DataNode>> anchorDataNodeListMap = prepareDataNodesForAnchor(dataNodes); - for (final Map.Entry<String, List<DataNode>> anchorDataNodesMapEntry : anchorDataNodeListMap.entrySet()) { + final Map<String, List<DataNode>> dataNodesPerAnchor = groupDataNodesPerAnchor(dataNodes); + for (final Map.Entry<String, List<DataNode>> dataNodesPerAnchorEntry : dataNodesPerAnchor.entrySet()) { + final String anchorName = dataNodesPerAnchorEntry.getKey(); if (prefix == null) { - prefix = prefixResolver.getPrefix(dataspaceName, anchorDataNodesMapEntry.getKey(), - anchorDataNodesMapEntry.getValue().get(0).getXpath()); + final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName); + prefix = prefixResolver.getPrefix(anchor, dataNodesPerAnchorEntry.getValue().get(0).getXpath()); } final Map<String, Object> dataMap = DataMapUtils.toDataMapWithIdentifierAndAnchor( - anchorDataNodesMapEntry.getValue(), anchorDataNodesMapEntry.getKey(), prefix); + dataNodesPerAnchorEntry.getValue(), anchorName, prefix); dataNodesAsListOfMaps.add(dataMap); } final Integer totalPages = getTotalPages(dataspaceName, cpsPath, paginationOption); @@ -112,7 +116,7 @@ public class QueryRestController implements CpsQueryApi { : (int) Math.ceil((double) totalAnchors / paginationOption.getPageSize()); } - private Map<String, List<DataNode>> prepareDataNodesForAnchor(final Collection<DataNode> dataNodes) { + private Map<String, List<DataNode>> groupDataNodesPerAnchor(final Collection<DataNode> dataNodes) { final Map<String, List<DataNode>> dataNodesMapForAnchor = new HashMap<>(); for (final DataNode dataNode : dataNodes) { List<DataNode> dataNodesInAnchor = dataNodesMapForAnchor.get(dataNode.getAnchorName()); @@ -130,10 +134,11 @@ public class QueryRestController implements CpsQueryApi { final Collection<DataNode> dataNodes = cpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption); final List<Map<String, Object>> dataNodesAsListOfMaps = new ArrayList<>(dataNodes.size()); + final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName); String prefix = null; for (final DataNode dataNode : dataNodes) { if (prefix == null) { - prefix = prefixResolver.getPrefix(dataspaceName, anchorName, dataNode.getXpath()); + prefix = prefixResolver.getPrefix(anchor, dataNode.getXpath()); } final Map<String, Object> dataMap = DataMapUtils.toDataMapWithIdentifier(dataNode, prefix); dataNodesAsListOfMaps.add(dataMap); diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy index 205d85dc26..705c2fee91 100755 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2024 Nordix Foundation * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2021-2022 Bell Canada. * Modifications Copyright (C) 2022 Deutsche Telekom AG @@ -26,6 +26,7 @@ package org.onap.cps.rest.controller import com.fasterxml.jackson.databind.ObjectMapper import groovy.json.JsonSlurper +import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsDataService import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.model.DataNode @@ -63,6 +64,9 @@ class DataRestControllerSpec extends Specification { CpsDataService mockCpsDataService = Mock() @SpringBean + CpsAnchorService mockCpsAnchorService = Mock() + + @SpringBean JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) @SpringBean @@ -160,6 +164,26 @@ class DataRestControllerSpec extends Specification { 'with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_JSON | requestBodyJson || 0 | HttpStatus.BAD_REQUEST | expectedJsonData | ContentType.JSON } + def 'Validate data using create a node API'() { + given: 'an endpoint to create a node' + def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes" + def parentNodeXpath = '/' + def dryRunEnabled = 'true' + when: 'post is invoked with json data and dry-run flag enabled' + def response = + mvc.perform( + post(endpoint) + .contentType(MediaType.APPLICATION_JSON) + .param('xpath', parentNodeXpath) + .param('dry-run', dryRunEnabled) + .content(requestBodyJson) + ).andReturn().response + then: 'a 200 OK response is returned' + response.status == HttpStatus.OK.value() + then: 'the service was called with correct parameters' + 1 * mockCpsDataService.validateData(dataspaceName, anchorName, parentNodeXpath, requestBodyJson, ContentType.JSON) + } + def 'Create a child node #scenario'() { given: 'endpoint to create a node' def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes" @@ -192,22 +216,25 @@ class DataRestControllerSpec extends Specification { def rootNodeXpath = '/' when: 'list-node endpoint is invoked with post (create) operation' def postRequestBuilder = post("$dataNodeBaseEndpointV1/anchors/$anchorName/list-nodes") - .contentType(MediaType.APPLICATION_JSON) + .contentType(contentType) .param('xpath', rootNodeXpath ) - .content(requestBodyJson) + .content(requestBody) if (observedTimestamp != null) postRequestBuilder.param('observed-timestamp', observedTimestamp) def response = mvc.perform(postRequestBuilder).andReturn().response then: 'a created response is returned' response.status == expectedHttpStatus.value() then: 'the java API was called with the correct parameters' - expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, rootNodeXpath, expectedJsonData, - { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }) + expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, rootNodeXpath, expectedData, + { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, expectedContentType) where: - scenario | observedTimestamp || expectedApiCount | expectedHttpStatus - 'with observed-timestamp' | '2021-03-03T23:59:59.999-0400' || 1 | HttpStatus.CREATED - 'without observed-timestamp' | null || 1 | HttpStatus.CREATED - 'with invalid observed-timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST + scenario | observedTimestamp | contentType | requestBody || expectedApiCount | expectedHttpStatus | expectedData | expectedContentType + 'Content type JSON with observed-timestamp' | '2021-03-03T23:59:59.999-0400' | MediaType.APPLICATION_JSON | requestBodyJson || 1 | HttpStatus.CREATED | expectedJsonData | ContentType.JSON + 'Content type JSON without observed-timestamp' | null | MediaType.APPLICATION_JSON | requestBodyJson || 1 | HttpStatus.CREATED | expectedJsonData | ContentType.JSON + 'Content type JSON with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_JSON | requestBodyJson || 0 | HttpStatus.BAD_REQUEST | expectedJsonData | ContentType.JSON + 'Content type XML with observed-timestamp' | '2021-03-03T23:59:59.999-0400' | MediaType.APPLICATION_XML | requestBodyXml || 1 | HttpStatus.CREATED | expectedXmlData | ContentType.XML + 'Content type XML without observed-timestamp' | null | MediaType.APPLICATION_XML | requestBodyXml || 1 | HttpStatus.CREATED | expectedXmlData | ContentType.XML + 'Content type XML with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_XML | requestBodyXml || 0 | HttpStatus.BAD_REQUEST | expectedXmlData | ContentType.XML } def 'Save list elements #scenario.'() { @@ -215,22 +242,25 @@ class DataRestControllerSpec extends Specification { def parentNodeXpath = 'parent node xpath' when: 'list-node endpoint is invoked with post (create) operation' def postRequestBuilder = post("$dataNodeBaseEndpointV1/anchors/$anchorName/list-nodes") - .contentType(MediaType.APPLICATION_JSON) + .contentType(contentType) .param('xpath', parentNodeXpath) - .content(requestBodyJson) + .content(requestBody) if (observedTimestamp != null) postRequestBuilder.param('observed-timestamp', observedTimestamp) def response = mvc.perform(postRequestBuilder).andReturn().response then: 'a created response is returned' response.status == expectedHttpStatus.value() then: 'the java API was called with the correct parameters' - expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath, expectedJsonData, - { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }) + expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath, expectedData, + { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, expectedContentType) where: - scenario | observedTimestamp || expectedApiCount | expectedHttpStatus - 'with observed-timestamp' | '2021-03-03T23:59:59.999-0400' || 1 | HttpStatus.CREATED - 'without observed-timestamp' | null || 1 | HttpStatus.CREATED - 'with invalid observed-timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST + scenario | observedTimestamp | contentType | requestBody || expectedApiCount | expectedHttpStatus | expectedData | expectedContentType + 'Content type JSON with observed-timestamp' | '2021-03-03T23:59:59.999-0400' | MediaType.APPLICATION_JSON | requestBodyJson || 1 | HttpStatus.CREATED | expectedJsonData | ContentType.JSON + 'Content type JSON without observed-timestamp' | null | MediaType.APPLICATION_JSON | requestBodyJson || 1 | HttpStatus.CREATED | expectedJsonData | ContentType.JSON + 'Content type JSON with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_JSON | requestBodyJson || 0 | HttpStatus.BAD_REQUEST | expectedJsonData | ContentType.JSON + 'Content type XML with observed-timestamp' | '2021-03-03T23:59:59.999-0400' | MediaType.APPLICATION_XML | requestBodyXml || 1 | HttpStatus.CREATED | expectedXmlData | ContentType.XML + 'Content type XML without observed-timestamp' | null | MediaType.APPLICATION_XML | requestBodyXml || 1 | HttpStatus.CREATED | expectedXmlData | ContentType.XML + 'Content type XML with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_XML | requestBodyXml || 0 | HttpStatus.BAD_REQUEST | expectedXmlData | ContentType.XML } def 'Get data node with leaves'() { @@ -344,9 +374,9 @@ class DataRestControllerSpec extends Specification { def 'Get delta between two anchors'() { given: 'the service returns a list containing delta reports' - def deltaReports = new DeltaReportBuilder().actionUpdate().withXpath('some xpath').withSourceData('some key': 'some value').withTargetData('some key': 'some value').build() + def deltaReports = new DeltaReportBuilder().actionReplace().withXpath('some xpath').withSourceData('some key': 'some value').withTargetData('some key': 'some value').build() def xpath = 'some xpath' - def endpoint = "$dataNodeBaseEndpointV2/anchors/sourceAnchor/deltaAnchors" + def endpoint = "$dataNodeBaseEndpointV2/anchors/sourceAnchor/delta" mockCpsDataService.getDeltaByDataspaceAndAnchors(dataspaceName, 'sourceAnchor', 'targetAnchor', xpath, OMIT_DESCENDANTS) >> [deltaReports] when: 'get delta request is performed using REST API' def response = @@ -357,14 +387,14 @@ class DataRestControllerSpec extends Specification { then: 'expected response code is returned' assert response.status == HttpStatus.OK.value() and: 'the response contains expected value' - assert response.contentAsString.contains("[{\"action\":\"update\",\"xpath\":\"some xpath\",\"sourceData\":{\"some key\":\"some value\"},\"targetData\":{\"some key\":\"some value\"}}]") + assert response.contentAsString.contains("[{\"action\":\"replace\",\"xpath\":\"some xpath\",\"sourceData\":{\"some key\":\"some value\"},\"targetData\":{\"some key\":\"some value\"}}]") } def 'Get delta between anchor and JSON payload with multipart file'() { given: 'sample delta report, xpath, yang model file and json payload' - def deltaReports = new DeltaReportBuilder().actionAdd().withXpath('some xpath').build() + def deltaReports = new DeltaReportBuilder().actionCreate().withXpath('some xpath').build() def xpath = 'some xpath' - def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/deltaPayload" + def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/delta" and: 'the service layer returns a list containing delta reports' mockCpsDataService.getDeltaByDataspaceAnchorAndPayload(dataspaceName, anchorName, xpath, ['filename.yang':'content'], expectedJsonData, INCLUDE_ALL_DESCENDANTS) >> [deltaReports] when: 'get delta request is performed using REST API' @@ -378,14 +408,14 @@ class DataRestControllerSpec extends Specification { then: 'expected response code is returned' assert response.status == HttpStatus.OK.value() and: 'the response contains expected value' - assert response.contentAsString.contains("[{\"action\":\"add\",\"xpath\":\"some xpath\"}]") + assert response.contentAsString.contains("[{\"action\":\"create\",\"xpath\":\"some xpath\"}]") } def 'Get delta between anchor and JSON payload without multipart file'() { given: 'sample delta report, xpath, and json payload' def deltaReports = new DeltaReportBuilder().actionRemove().withXpath('some xpath').build() def xpath = 'some xpath' - def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/deltaPayload" + def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/delta" and: 'the service layer returns a list containing delta reports' mockCpsDataService.getDeltaByDataspaceAnchorAndPayload(dataspaceName, anchorName, xpath, [:], expectedJsonData, INCLUDE_ALL_DESCENDANTS) >> [deltaReports] when: 'get delta request is performed using REST API' diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy index c30a63fd46..80b287cda8 100644 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2024 Nordix Foundation * Modifications Copyright (C) 2021-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022-2023 TechMahindra Ltd. @@ -23,18 +23,13 @@ package org.onap.cps.rest.controller -import org.onap.cps.spi.PaginationOption -import org.onap.cps.utils.PrefixResolver - -import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY -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 com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.utils.JsonObjectMapper +import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsQueryService +import org.onap.cps.spi.PaginationOption import org.onap.cps.spi.model.DataNodeBuilder +import org.onap.cps.utils.JsonObjectMapper +import org.onap.cps.utils.PrefixResolver import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value @@ -43,6 +38,11 @@ import org.springframework.http.HttpStatus import org.springframework.test.web.servlet.MockMvc import spock.lang.Specification +import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY +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 + @WebMvcTest(QueryRestController) class QueryRestControllerSpec extends Specification { @@ -50,6 +50,9 @@ class QueryRestControllerSpec extends Specification { CpsQueryService mockCpsQueryService = Mock() @SpringBean + CpsAnchorService mockCpsAnchorService = Mock() + + @SpringBean JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) @SpringBean |