aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Hanrahan <daniel.hanrahan@est.tech>2024-07-16 19:26:48 +0000
committerGerrit Code Review <gerrit@onap.org>2024-07-16 19:26:48 +0000
commitb08422d2d060d8b866eb245947c4334301c80bdb (patch)
treee730c3994a9f4ed7fdc4f76bc216261728535fbf
parentfea2f673abe2586e62a8790ffb71efff5a01744d (diff)
parent760dd950e6f6fcb6f49c6f9d92a33f538adffd24 (diff)
Merge "XML content support on replace a node with descendants"
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java7
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy7
-rw-r--r--cps-rest/docs/openapi/components.yml4
-rw-r--r--cps-rest/docs/openapi/cpsData.yml15
-rwxr-xr-xcps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java28
-rwxr-xr-xcps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy19
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsDataService.java20
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java19
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy45
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy4
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy4
11 files changed, 112 insertions, 60 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java
index 2930d4f87c..cd1237b884 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2022-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,6 +47,7 @@ import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleDefinition;
import org.onap.cps.spi.model.ModuleReference;
import org.onap.cps.spi.utils.CpsValidator;
+import org.onap.cps.utils.ContentType;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Component;
@@ -95,7 +96,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
public void saveCmHandleState(final String cmHandleId, final CompositeState compositeState) {
final String cmHandleJsonData = createStateJsonData(jsonObjectMapper.asJsonString(compositeState));
cpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- getXPathForCmHandleById(cmHandleId), cmHandleJsonData, OffsetDateTime.now());
+ getXPathForCmHandleById(cmHandleId), cmHandleJsonData, OffsetDateTime.now(), ContentType.JSON);
}
@Override
@@ -105,7 +106,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
getXPathForCmHandleById(cmHandleId),
createStateJsonData(jsonObjectMapper.asJsonString(compositeState))));
cpsDataService.updateDataNodesAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- cmHandlesJsonDataMap, OffsetDateTime.now());
+ cmHandlesJsonDataMap, OffsetDateTime.now(), ContentType.JSON);
}
@Override
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy
index d58a1dfa06..e098fb81d7 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2022-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@ import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.ModuleDefinition
import org.onap.cps.spi.model.ModuleReference
import org.onap.cps.spi.utils.CpsValidator
+import org.onap.cps.utils.ContentType
import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Shared
import spock.lang.Specification
@@ -166,7 +167,7 @@ class InventoryPersistenceImplSpec extends Specification {
when: 'update cm handle state is invoked with the #scenario state'
objectUnderTest.saveCmHandleState(cmHandleId, compositeState)
then: 'update node leaves is invoked with the correct params'
- 1 * mockCpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']', expectedJsonData, _ as OffsetDateTime)
+ 1 * mockCpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']', expectedJsonData, _ as OffsetDateTime, ContentType.JSON)
where: 'the following states are used'
scenario | cmHandleState || expectedJsonData
'READY' | CmHandleState.READY || '{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}'
@@ -182,7 +183,7 @@ class InventoryPersistenceImplSpec extends Specification {
def cmHandleStateMap = ['Some-Cm-Handle1' : compositeState1, 'Some-Cm-Handle2' : compositeState2]
objectUnderTest.saveCmHandleStateBatch(cmHandleStateMap)
then: 'update node leaves is invoked with the correct params'
- 1 * mockCpsDataService.updateDataNodesAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandlesJsonDataMap, _ as OffsetDateTime)
+ 1 * mockCpsDataService.updateDataNodesAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandlesJsonDataMap, _ as OffsetDateTime, ContentType.JSON)
where: 'the following states are used'
scenario | cmHandleState || cmHandlesJsonDataMap
'READY' | CmHandleState.READY || ['/dmi-registry/cm-handles[@id=\'Some-Cm-Handle1\']':'{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle2\']':'{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}']
diff --git a/cps-rest/docs/openapi/components.yml b/cps-rest/docs/openapi/components.yml
index 01375f503d..99502e3083 100644
--- a/cps-rest/docs/openapi/components.yml
+++ b/cps-rest/docs/openapi/components.yml
@@ -279,10 +279,10 @@ components:
type: string
enum: [v1, v2]
default: v2
- contentTypeHeader:
+ contentTypeInHeader:
name: Content-Type
in: header
- description: Content type header
+ description: Content type in header
schema:
type: string
example: 'application/json'
diff --git a/cps-rest/docs/openapi/cpsData.yml b/cps-rest/docs/openapi/cpsData.yml
index d13c285817..80d07c806b 100644
--- a/cps-rest/docs/openapi/cpsData.yml
+++ b/cps-rest/docs/openapi/cpsData.yml
@@ -94,7 +94,7 @@ nodesByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/xpathInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
- - $ref: 'components.yml#/components/parameters/contentTypeHeader'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
required: true
content:
@@ -137,7 +137,7 @@ nodesByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/xpathInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
- - $ref: 'components.yml#/components/parameters/contentTypeHeader'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
required: true
content:
@@ -197,15 +197,24 @@ nodesByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/xpathInQuery'
- $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:
'200':
$ref: 'components.yml#/components/responses/Ok'
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 f579c82d25..6100b7edd9 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
@@ -49,7 +49,6 @@ import org.onap.cps.utils.PrefixResolver;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -70,11 +69,10 @@ public class DataRestController implements CpsDataApi {
@Override
public ResponseEntity<String> createNode(final String apiVersion,
final String dataspaceName, final String anchorName,
- @RequestHeader(value = "Content-Type") final String contentTypeHeader,
+ final String contentTypeInHeader,
final String nodeData, final String parentNodeXpath,
final String observedTimestamp) {
- final ContentType contentType = contentTypeHeader.contains(MediaType.APPLICATION_XML_VALUE) ? ContentType.XML
- : ContentType.JSON;
+ final ContentType contentType = getContentTypeFromHeader(contentTypeInHeader);
if (isRootXpath(parentNodeXpath)) {
cpsDataService.saveData(dataspaceName, anchorName, nodeData,
toOffsetDateTime(observedTimestamp), contentType);
@@ -137,23 +135,23 @@ public class DataRestController implements CpsDataApi {
@Override
public ResponseEntity<Object> updateNodeLeaves(final String apiVersion, final String dataspaceName,
- final String anchorName, final String contentTypeHeader,
+ final String anchorName, final String contentTypeInHeader,
final String nodeData, final String parentNodeXpath,
final String observedTimestamp) {
- final ContentType contentType = contentTypeHeader.contains(MediaType.APPLICATION_XML_VALUE) ? ContentType.XML
- : ContentType.JSON;
+ final ContentType contentType = getContentTypeFromHeader(contentTypeInHeader);
cpsDataService.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath,
nodeData, toOffsetDateTime(observedTimestamp), contentType);
return new ResponseEntity<>(HttpStatus.OK);
}
@Override
- public ResponseEntity<Object> replaceNode(final String apiVersion,
- final String dataspaceName, final String anchorName,
- final Object jsonData, final String parentNodeXpath, final String observedTimestamp) {
- cpsDataService
- .updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath,
- jsonObjectMapper.asJsonString(jsonData), toOffsetDateTime(observedTimestamp));
+ public ResponseEntity<Object> replaceNode(final String apiVersion, final String dataspaceName,
+ final String anchorName, final String contentTypeInHeader,
+ final String nodeData, final String parentNodeXpath,
+ final String observedTimestamp) {
+ final ContentType contentType = getContentTypeFromHeader(contentTypeInHeader);
+ cpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath,
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
return new ResponseEntity<>(HttpStatus.OK);
}
@@ -213,6 +211,10 @@ public class DataRestController implements CpsDataApi {
return new ResponseEntity<>(jsonObjectMapper.asJsonString(deltaBetweenAnchors), HttpStatus.OK);
}
+ private static ContentType getContentTypeFromHeader(final String contentTypeInHeader) {
+ return contentTypeInHeader.contains(MediaType.APPLICATION_XML_VALUE) ? ContentType.XML : ContentType.JSON;
+ }
+
private static boolean isRootXpath(final String xpath) {
return ROOT_XPATH.equals(xpath);
}
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 317b9c5b7c..205d85dc26 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
@@ -456,19 +456,22 @@ class DataRestControllerSpec extends Specification {
def response =
mvc.perform(
put(endpoint)
- .contentType(MediaType.APPLICATION_JSON)
- .content(requestBodyJson)
+ .contentType(contentType)
+ .content(requestBody)
.param('xpath', inputXpath))
.andReturn().response
then: 'the service method is invoked with expected parameters'
- 1 * mockCpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, xpathServiceParameter, expectedJsonData, noTimestamp)
+ 1 * mockCpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, xpathServiceParameter, expectedData, noTimestamp, expectedContentType)
and: 'response status indicates success'
response.status == HttpStatus.OK.value()
where:
- scenario | inputXpath || xpathServiceParameter
- 'root node by default' | '' || '/'
- 'root node by choice' | '/' || '/'
- 'some xpath by parent' | '/some/xpath' || '/some/xpath'
+ scenario | inputXpath | contentType || xpathServiceParameter | requestBody | expectedData | expectedContentType
+ 'JSON content: root node by default' | '' | MediaType.APPLICATION_JSON || '/' | requestBodyJson | expectedJsonData | ContentType.JSON
+ 'JSON content: root node by choice' | '/' | MediaType.APPLICATION_JSON || '/' | requestBodyJson | expectedJsonData | ContentType.JSON
+ 'JSON content: some xpath by parent' | '/some/xpath' | MediaType.APPLICATION_JSON || '/some/xpath' | requestBodyJson | expectedJsonData | ContentType.JSON
+ 'XML content: root node by default' | '' | MediaType.APPLICATION_XML || '/' | requestBodyXml | expectedXmlData | ContentType.XML
+ 'XML content: root node by choice' | '/' | MediaType.APPLICATION_XML || '/' | requestBodyXml | expectedXmlData | ContentType.XML
+ 'XML content: some xpath by parent' | '/some/xpath' | MediaType.APPLICATION_XML || '/some/xpath' | requestBodyXml | expectedXmlData | ContentType.XML
}
def 'Update data node and descendants with observedTimestamp.'() {
@@ -485,7 +488,7 @@ class DataRestControllerSpec extends Specification {
.andReturn().response
then: 'the service method is invoked with expected parameters'
expectedApiCount * mockCpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, '/', expectedJsonData,
- { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) })
+ { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.JSON)
and: 'response status indicates success'
response.status == expectedHttpStatus.value()
where:
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
index f396b49e6b..cfa5f2de20 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
@@ -55,7 +55,7 @@ public interface CpsDataService {
* @param anchorName anchor name
* @param nodeData node data
* @param observedTimestamp observedTimestamp
- * @param contentType node data content type
+ * @param contentType JSON/XML content type
*/
void saveData(String dataspaceName, String anchorName, String nodeData, OffsetDateTime observedTimestamp,
ContentType contentType);
@@ -80,7 +80,7 @@ public interface CpsDataService {
* @param parentNodeXpath parent node xpath
* @param nodeData node data
* @param observedTimestamp observedTimestamp
- * @param contentType node data content type
+ * @param contentType JSON/XML content type
*
*/
void saveData(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
@@ -134,7 +134,7 @@ public interface CpsDataService {
* @param parentNodeXpath xpath to parent node
* @param nodeData node data
* @param observedTimestamp observedTimestamp
- * @param contentType node data content type
+ * @param contentType JSON/XML content type
*/
void updateNodeLeaves(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
OffsetDateTime observedTimestamp, ContentType contentType);
@@ -145,22 +145,24 @@ public interface CpsDataService {
* @param dataspaceName dataspace name
* @param anchorName anchor name
* @param parentNodeXpath xpath to parent node
- * @param jsonData json data
+ * @param nodeData node data
* @param observedTimestamp observedTimestamp
+ * @param contentType JSON/XML content type
*/
- void updateDataNodeAndDescendants(String dataspaceName, String anchorName, String parentNodeXpath, String jsonData,
- OffsetDateTime observedTimestamp);
+ void updateDataNodeAndDescendants(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
+ OffsetDateTime observedTimestamp, ContentType contentType);
/**
* Replaces multiple existing data nodes' content including descendants in a batch operation.
*
* @param dataspaceName dataspace name
* @param anchorName anchor name
- * @param nodesJsonData map of xpath and node JSON data
+ * @param nodeDataPerXPath map of xpath and node JSON/XML data
* @param observedTimestamp observedTimestamp
+ * @param contentType JSON/XML content type
*/
- void updateDataNodesAndDescendants(String dataspaceName, String anchorName, Map<String, String> nodesJsonData,
- OffsetDateTime observedTimestamp);
+ void updateDataNodesAndDescendants(String dataspaceName, String anchorName, Map<String, String> nodeDataPerXPath,
+ OffsetDateTime observedTimestamp, ContentType contentType);
/**
* Replaces list content by removing all existing elements and inserting the given new elements as json
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
index 5a48428772..c65bc5e0e9 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
@@ -251,12 +251,12 @@ public class CpsDataServiceImpl implements CpsDataService {
@Timed(value = "cps.data.service.datanode.descendants.update",
description = "Time taken to update a data node and descendants")
public void updateDataNodeAndDescendants(final String dataspaceName, final String anchorName,
- final String parentNodeXpath, final String jsonData,
- final OffsetDateTime observedTimestamp) {
+ final String parentNodeXpath, final String nodeData,
+ final OffsetDateTime observedTimestamp, final ContentType contentType) {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
final Collection<DataNode> dataNodes =
- buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, jsonData, ContentType.JSON);
+ buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, nodeData, contentType);
cpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName, dataNodes);
sendDataUpdatedEvent(anchor, parentNodeXpath, Operation.UPDATE, observedTimestamp);
}
@@ -265,13 +265,13 @@ public class CpsDataServiceImpl implements CpsDataService {
@Timed(value = "cps.data.service.datanode.descendants.batch.update",
description = "Time taken to update a batch of data nodes and descendants")
public void updateDataNodesAndDescendants(final String dataspaceName, final String anchorName,
- final Map<String, String> nodesJsonData,
- final OffsetDateTime observedTimestamp) {
+ final Map<String, String> nodeDataPerXPath,
+ final OffsetDateTime observedTimestamp, final ContentType contentType) {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
- final Collection<DataNode> dataNodes = buildDataNodesWithParentNodeXpath(anchor, nodesJsonData);
+ final Collection<DataNode> dataNodes = buildDataNodesWithParentNodeXpath(anchor, nodeDataPerXPath, contentType);
cpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName, dataNodes);
- nodesJsonData.keySet().forEach(nodeXpath ->
+ nodeDataPerXPath.keySet().forEach(nodeXpath ->
sendDataUpdatedEvent(anchor, nodeXpath, Operation.UPDATE, observedTimestamp));
}
@@ -408,11 +408,12 @@ public class CpsDataServiceImpl implements CpsDataService {
}
private Collection<DataNode> buildDataNodesWithParentNodeXpath(final Anchor anchor,
- final Map<String, String> nodesJsonData) {
+ final Map<String, String> nodesJsonData,
+ final ContentType contentType) {
final Collection<DataNode> dataNodes = new ArrayList<>();
for (final Map.Entry<String, String> nodeJsonData : nodesJsonData.entrySet()) {
dataNodes.addAll(buildDataNodesWithParentNodeXpath(anchor, nodeJsonData.getKey(),
- nodeJsonData.getValue(), ContentType.JSON));
+ nodeJsonData.getValue(), contentType));
}
return dataNodes;
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
index 4e5807ec84..2e38d797d9 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
@@ -362,11 +362,11 @@ class CpsDataServiceImplSpec extends Specification {
1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
}
- def 'Replace data node using singular data node: #scenario.'() {
+ def 'Replace data node using singular JSON data node: #scenario.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
when: 'replace data method is invoked with json data #jsonData and parent node xpath #parentNodeXpath'
- objectUnderTest.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath, jsonData, observedTimestamp)
+ objectUnderTest.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath, jsonData, observedTimestamp, ContentType.JSON)
then: 'the persistence service method is invoked with correct parameters'
1 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName,
{ dataNode -> dataNode.xpath == expectedNodeXpath})
@@ -379,30 +379,63 @@ class CpsDataServiceImplSpec extends Specification {
'json list' | '/test-tree' | '{"branch": [{"name":"Name1"}, {"name":"Name2"}]}' || ["/test-tree/branch[@name='Name1']", "/test-tree/branch[@name='Name2']"]
}
- def 'Replace data node using multiple data nodes: #scenario.'() {
+ def 'Replace data node using singular XML data node: #scenario.'() {
+ given: 'schema set for given anchor and dataspace references test-tree model'
+ setupSchemaSetMocks('test-tree.yang')
+ when: 'replace data method is invoked with XML data #xmlData and parent node xpath #parentNodeXpath'
+ objectUnderTest.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath, xmlData, observedTimestamp, ContentType.XML)
+ then: 'the persistence service method is invoked with correct parameters'
+ 1 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName,
+ { dataNode -> dataNode.xpath == expectedNodeXpath })
+ and: 'the CpsValidator is called on the dataspaceName and AnchorName'
+ 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
+ where: 'following parameters were used'
+ scenario | parentNodeXpath | xmlData || expectedNodeXpath
+ 'level 2 node' | '/test-tree' | '<branch><name>Name</name></branch>' || ['/test-tree/branch[@name=\'Name\']']
+ 'xml list' | '/test-tree' | '<test-tree xmlns="org:onap:cps:test:test-tree"><branch><name>Name1</name></branch>' + '<branch><name>Name2</name></branch></test-tree>' || ["/test-tree/branch[@name='Name1']", "/test-tree/branch[@name='Name2']"]
+ }
+
+ def 'Replace data node using multiple JSON data nodes: #scenario.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
when: 'replace data method is invoked with a map of xpaths and json data'
- objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, nodesJsonData, observedTimestamp)
+ objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, nodeDataPerXPath, observedTimestamp, ContentType.JSON)
then: 'the persistence service method is invoked with correct parameters'
1 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName,
{ dataNode -> dataNode.xpath == expectedNodeXpath})
and: 'the CpsValidator is called on the dataspaceName and AnchorName'
1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
where: 'following parameters were used'
- scenario | nodesJsonData || expectedNodeXpath
+ scenario | nodeDataPerXPath || expectedNodeXpath
'top level node' | ['/' : '{"test-tree": {"branch": []}}', '/test-tree' : '{"branch": [{"name":"Name"}]}'] || ["/test-tree", "/test-tree/branch[@name='Name']"]
'level 2 node' | ['/test-tree' : '{"branch": [{"name":"Name"}]}', '/test-tree/branch[@name=\'Name\']':'{"nest":{"name":"nestName"}}'] || ["/test-tree/branch[@name='Name']", "/test-tree/branch[@name='Name']/nest"]
'json list' | ['/test-tree' : '{"branch": [{"name":"Name1"}, {"name":"Name2"}]}'] || ["/test-tree/branch[@name='Name1']", "/test-tree/branch[@name='Name2']"]
}
+ def 'Replace data node using multiple XML data nodes: #scenario.'() {
+ given: 'schema set for given anchor and dataspace references test-tree model'
+ setupSchemaSetMocks('test-tree.yang')
+ when: 'replace data method is invoked with a map of xpaths and XML data'
+ objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, nodeXmlDataPerXPath, observedTimestamp, ContentType.XML)
+ then: 'the persistence service method is invoked with correct parameters'
+ 1 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName,
+ { dataNode -> dataNode.xpath == expectedNodeXpath })
+ and: 'the CpsValidator is called on the dataspaceName and AnchorName'
+ 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
+ where: 'following parameters were used'
+ scenario | nodeXmlDataPerXPath || expectedNodeXpath
+ 'top level node' | ['/test-tree': '<branch><name>Name</name></branch>'] || ["/test-tree/branch[@name='Name']"]
+ 'level 2 node' | ['/test-tree': '<branch><name>Name</name></branch>', '/test-tree/branch[@name=\'Name\']': '<nest><name>nestName</name></nest>'] || ["/test-tree/branch[@name='Name']", "/test-tree/branch[@name='Name']/nest"]
+ 'xml list' | ['/test-tree': '<test-tree xmlns="org:onap:cps:test:test-tree"><branch><name>Name1</name></branch>' + '<branch><name>Name2</name></branch></test-tree>'] || ["/test-tree/branch[@name='Name1']", "/test-tree/branch[@name='Name2']"]
+ }
+
def 'Replace data node with concurrency exception in persistence layer.'() {
given: 'the persistence layer throws an concurrency exception'
def originalException = new ConcurrencyException('message', 'details')
mockCpsDataPersistenceService.updateDataNodesAndDescendants(*_) >> { throw originalException }
setupSchemaSetMocks('test-tree.yang')
when: 'attempt to replace data node'
- objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, ['/' : '{"test-tree": {}}'] , observedTimestamp)
+ objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, ['/' : '{"test-tree": {}}'] , observedTimestamp, ContentType.JSON)
then: 'the same exception is thrown up'
def thrownUp = thrown(ConcurrencyException)
assert thrownUp == originalException
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy
index a488b3b836..869b72d8ce 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy
@@ -396,7 +396,7 @@ class DataServiceIntegrationSpec extends FunctionalSpecBase {
objectUnderTest.saveData(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now)
when: 'the webinfo (container) is updated'
json = '{"webinfo": {"domain-name":"newdomain.com" ,"contact-email":"info@newdomain.com" }}'
- objectUnderTest.updateDataNodeAndDescendants(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', json, now)
+ objectUnderTest.updateDataNodeAndDescendants(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', json, now, ContentType.JSON)
then: 'webinfo has been updated with teh new details'
def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/webinfo', DIRECT_CHILDREN_ONLY)
result.leaves.'domain-name'[0] == 'newdomain.com'
@@ -408,7 +408,7 @@ class DataServiceIntegrationSpec extends FunctionalSpecBase {
def 'Update bookstore top-level container data node.'() {
when: 'the bookstore top-level container is updated'
def json = '{ "bookstore": { "bookstore-name": "new bookstore" }}'
- objectUnderTest.updateDataNodeAndDescendants(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/', json, now)
+ objectUnderTest.updateDataNodeAndDescendants(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/', json, now, ContentType.JSON)
then: 'bookstore name has been updated'
def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', DIRECT_CHILDREN_ONLY)
result.leaves.'bookstore-name'[0] == 'new bookstore'
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
index 7bcec968e5..03abdb4b3f 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
@@ -50,7 +50,7 @@ class UpdatePerfTest extends CpsPerfTestBase {
given: 'replacement JSON for node containing list of device nodes'
def jsonData = '{ "openroadm-devices": ' + generateJsonForOpenRoadmDevices(startId, totalNodes, changeLeaves) + '}'
when: 'the container node is updated'
- objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now)
+ objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now, ContentType.JSON)
then: 'there are the expected number of total nodes'
assert totalNodes == countDataNodes('/openroadm-devices/openroadm-device')
where:
@@ -68,7 +68,7 @@ class UpdatePerfTest extends CpsPerfTestBase {
def jsonData = '{ "openroadm-devices": ' + generateJsonForOpenRoadmDevices(startId, totalNodes, changeLeaves) + '}'
when: 'the container node is updated'
resourceMeter.start()
- objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now)
+ objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now, ContentType.JSON)
resourceMeter.stop()
then: 'there are the expected number of total nodes'
assert totalNodes == countDataNodes('/openroadm-devices/openroadm-device')