summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRudrangi Anupriya <ra00745022@techmahindra.com>2024-11-27 23:49:42 +0530
committerRudrangi Anupriya <ra00745022@techmahindra.com>2024-11-28 12:30:33 +0530
commitdfcc95236daf7d45687fa42446a7d236ac12637e (patch)
treeca81405d08597548b80c844a7eb12aa46598d736
parent05e97441ad192b69051fbb67263284eb99ee1c41 (diff)
XML content support on Replace list content
Here to bring Support for XML Response Entity in Replace List content - Add ContentTypeInheadr in cpsData.yml to support application/xml - Add contentTypeInHeader parameter to accept xml in DataRestController.java - Modify the code return xml Data - written testcase for above changes made Issue-ID: CPS-2411 Change-Id: Ibb7ffb66ccdd03703266123c6d5c2eade0e7cb4a Signed-off-by: Rudrangi Anupriya <ra00745022@techmahindra.com>
-rw-r--r--cps-rest/docs/openapi/cpsData.yml11
-rwxr-xr-xcps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java10
-rw-r--r--cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java2
-rwxr-xr-xcps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy23
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsDataService.java7
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java4
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy36
-rw-r--r--docs/api/swagger/cps/openapi.yaml19
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy8
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy4
10 files changed, 103 insertions, 21 deletions
diff --git a/cps-rest/docs/openapi/cpsData.yml b/cps-rest/docs/openapi/cpsData.yml
index daf59bbfbf..36000fd7d8 100644
--- a/cps-rest/docs/openapi/cpsData.yml
+++ b/cps-rest/docs/openapi/cpsData.yml
@@ -71,15 +71,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:
'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 dda88e019c..3efb6b421c 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
@@ -173,9 +173,11 @@ public class DataRestController implements CpsDataApi {
@Override
public ResponseEntity<Object> replaceListContent(final String apiVersion, final String dataspaceName,
final String anchorName, final String parentNodeXpath,
- final Object jsonData, final String observedTimestamp) {
+ final String nodeData, final String observedTimestamp,
+ final String contentTypeInHeader) {
+ final ContentType contentType = ContentType.fromString(contentTypeInHeader);
cpsDataService.replaceListContent(dataspaceName, anchorName, parentNodeXpath,
- jsonObjectMapper.asJsonString(jsonData), toOffsetDateTime(observedTimestamp));
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
return new ResponseEntity<>(HttpStatus.OK);
}
@@ -225,10 +227,10 @@ public class DataRestController implements CpsDataApi {
return new ResponseEntity<>(jsonObjectMapper.asJsonString(deltaBetweenAnchors), HttpStatus.OK);
}
- ResponseEntity<Object> buildResponseEntity(final List<Map<String, Object>> dataMaps,
+ private ResponseEntity<Object> buildResponseEntity(final List<Map<String, Object>> dataMaps,
final ContentType contentType) {
final String responseData;
- if (contentType == ContentType.XML) {
+ if (ContentType.XML.equals(contentType)) {
responseData = XmlFileUtils.convertDataMapsToXml(dataMaps);
} else {
responseData = jsonObjectMapper.asJsonString(dataMaps);
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 b425333f9e..c419a81245 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
@@ -160,7 +160,7 @@ public class QueryRestController implements CpsQueryApi {
private ResponseEntity<Object> buildResponseEntity(final List<Map<String, Object>> dataNodesAsListOfMaps,
final ContentType contentType) {
final String responseData;
- if (contentType == ContentType.XML) {
+ if (ContentType.XML.equals(contentType)) {
responseData = XmlFileUtils.convertDataMapsToXml(dataNodesAsListOfMaps);
} else {
responseData = jsonObjectMapper.asJsonString(dataNodesAsListOfMaps);
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 72ae4c7f91..892963c827 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
@@ -576,7 +576,28 @@ class DataRestControllerSpec extends Specification {
response.status == expectedHttpStatus.value()
and: 'the java API was called with the correct parameters'
expectedApiCount * mockCpsDataService.replaceListContent(dataspaceName, anchorName, 'parent xpath', expectedJsonData,
- { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) })
+ { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.JSON)
+ where:
+ scenario | observedTimestamp || expectedApiCount | expectedHttpStatus
+ 'with observed-timestamp' | '2021-03-03T23:59:59.999-0400' || 1 | HttpStatus.OK
+ 'without observed-timestamp' | null || 1 | HttpStatus.OK
+ 'with invalid observed-timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST
+ }
+
+ def 'Replace list XML content #scenario.'() {
+ when: 'list-nodes endpoint is invoked with put (update) operation'
+ def putRequestBuilder = put("$dataNodeBaseEndpointV1/anchors/$anchorName/list-nodes")
+ .contentType(MediaType.APPLICATION_XML)
+ .param('xpath', 'parent xpath')
+ .content(requestBodyXml)
+ if (observedTimestamp != null)
+ putRequestBuilder.param('observed-timestamp', observedTimestamp)
+ def response = mvc.perform(putRequestBuilder).andReturn().response
+ then: 'a success response is returned'
+ response.status == expectedHttpStatus.value()
+ and: 'the java API was called with the correct parameters'
+ expectedApiCount * mockCpsDataService.replaceListContent(dataspaceName, anchorName, 'parent xpath', expectedXmlData,
+ { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.XML)
where:
scenario | observedTimestamp || expectedApiCount | expectedHttpStatus
'with observed-timestamp' | '2021-03-03T23:59:59.999-0400' || 1 | HttpStatus.OK
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 b3eff8eb26..29c8ad0168 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
@@ -172,11 +172,12 @@ public interface CpsDataService {
* @param dataspaceName dataspace name
* @param anchorName anchor name
* @param parentNodeXpath parent node xpath
- * @param jsonData json data representing the new list elements
+ * @param nodeData node data representing the new list elements
* @param observedTimestamp observedTimestamp
+ * @param contentType JSON/XML content type
*/
- void replaceListContent(String dataspaceName, String anchorName, String parentNodeXpath, String jsonData,
- OffsetDateTime observedTimestamp);
+ void replaceListContent(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
+ OffsetDateTime observedTimestamp, ContentType contentType);
/**
* Replaces list content by removing all existing elements and inserting the given new elements as data nodes
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 b1b545be68..a63b3e5360 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
@@ -281,11 +281,11 @@ public class CpsDataServiceImpl implements CpsDataService {
@Timed(value = "cps.data.service.list.update",
description = "Time taken to update a list")
public void replaceListContent(final String dataspaceName, final String anchorName, final String parentNodeXpath,
- final String jsonData, final OffsetDateTime observedTimestamp) {
+ final String nodeData, final OffsetDateTime observedTimestamp, final ContentType contentType) {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
final Collection<DataNode> newListElements =
- buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, jsonData, ContentType.JSON);
+ buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, nodeData, contentType);
replaceListContent(dataspaceName, anchorName, parentNodeXpath, newListElements, observedTimestamp);
}
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 8c208a1cf8..1543fb931b 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
@@ -448,12 +448,12 @@ class CpsDataServiceImplSpec extends Specification {
assert thrownUp == originalException
}
- def 'Replace list content data fragment under parent node.'() {
+ def 'Replace list content data fragment JSON under parent node.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
when: 'replace list data method is invoked with list element json data'
def jsonData = '{"branch": [{"name": "A"}, {"name": "B"}]}'
- objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', jsonData, observedTimestamp)
+ objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', jsonData, observedTimestamp, ContentType.JSON)
then: 'the persistence service method is invoked with correct parameters'
1 * mockCpsDataPersistenceService.replaceListContent(dataspaceName, anchorName, '/test-tree',
{ dataNodeCollection ->
@@ -468,12 +468,42 @@ class CpsDataServiceImplSpec extends Specification {
2 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
}
+ def 'Replace list content data fragment XML under parent node.'() {
+ given: 'schema set for given anchor and dataspace references test-tree model'
+ setupSchemaSetMocks('test-tree.yang')
+ when: 'replace list data method is invoked with list element xml data'
+ def nodeData = '<branch><name>A</name></branch>'
+ objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', nodeData, observedTimestamp, ContentType.XML)
+ then: 'the persistence service method is invoked with correct parameters'
+ 1 * mockCpsDataPersistenceService.replaceListContent(dataspaceName, anchorName, '/test-tree',
+ { dataNodeCollection ->
+ {
+ assert dataNodeCollection.size() == 1
+ assert dataNodeCollection.collect { it.getXpath() }
+ .containsAll(['/test-tree/branch[@name=\'A\']'])
+ }
+ }
+ )
+ and: 'the CpsValidator is called on the dataspaceName and AnchorName twice'
+ 2 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
+ }
+
def 'Replace whole list content with empty list element.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
when: 'replace list data method is invoked with empty list'
def jsonData = '{"branch": []}'
- objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', jsonData, observedTimestamp)
+ objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', jsonData, observedTimestamp, ContentType.JSON)
+ then: 'invalid data exception is thrown'
+ thrown(DataValidationException)
+ }
+
+ def 'Replace whole list content XML with empty list element.'() {
+ given: 'schema set for given anchor and dataspace references test-tree model'
+ setupSchemaSetMocks('test-tree.yang')
+ when: 'replace list data method is invoked with xml empty list'
+ def nodeData = '[]'
+ objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', nodeData, observedTimestamp, ContentType.XML)
then: 'invalid data exception is thrown'
thrown(DataValidationException)
}
diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml
index 812a2e4e60..fea68480ab 100644
--- a/docs/api/swagger/cps/openapi.yaml
+++ b/docs/api/swagger/cps/openapi.yaml
@@ -1927,6 +1927,16 @@ paths:
schema:
example: 2021-03-21T00:10:34.030-0100
type: string
+ - description: Content type in header
+ in: header
+ name: Content-Type
+ required: false
+ schema:
+ default: application/json
+ enum:
+ - application/json
+ - application/xml
+ type: string
requestBody:
content:
application/json:
@@ -1935,7 +1945,16 @@ paths:
$ref: '#/components/examples/dataSample'
value: null
schema:
+ type: string
+ application/xml:
+ examples:
+ dataSample:
+ $ref: '#/components/examples/dataSampleXml'
+ value: null
+ schema:
type: object
+ xml:
+ name: stores
required: true
responses:
"200":
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 d49931eb7e..6c68a37f81 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
@@ -310,9 +310,9 @@ class DataServiceIntegrationSpec extends FunctionalSpecBase {
def 'Attempt to add empty lists.'() {
when: 'the batches of new list element(s) are saved'
- objectUnderTest.replaceListContent(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', [ ], now)
- then: 'an admin exception is thrown'
- thrown(CpsAdminException)
+ objectUnderTest.replaceListContent(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', [ ] as String, now, ContentType.JSON)
+ then: 'an data exception is thrown'
+ thrown(DataValidationException)
}
def 'Add child error scenario: #scenario.'() {
@@ -344,7 +344,7 @@ class DataServiceIntegrationSpec extends FunctionalSpecBase {
assert countDataNodesInTree(objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="2"]', DIRECT_CHILDREN_ONLY)) > 1
when: 'the categories list is replaced with just category "1" and without child nodes (books)'
def json = '{"categories": [ {"code":"' +categoryCode + '"' + childJson + '} ] }'
- objectUnderTest.replaceListContent(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', json, now)
+ objectUnderTest.replaceListContent(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', json, now, ContentType.JSON)
then: 'the new replaced category can be retrieved but has no children anymore'
assert expectedNumberOfDataNodes == countDataNodesInTree(objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="' +categoryCode + '"]', DIRECT_CHILDREN_ONLY))
when: 'attempt to retrieve a category (code) not in the new list'
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 03abdb4b3f..d764029f02 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
@@ -94,7 +94,7 @@ class UpdatePerfTest extends CpsPerfTestBase {
def jsonListData = generateJsonForOpenRoadmDevices(startId, totalNodes, changeLeaves)
when: 'the container node is updated'
resourceMeter.start()
- objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now)
+ objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now, ContentType.JSON)
resourceMeter.stop()
then: 'there are the expected number of total nodes'
assert totalNodes == countDataNodes('/openroadm-devices/openroadm-device')
@@ -118,7 +118,7 @@ class UpdatePerfTest extends CpsPerfTestBase {
def 'Update leaves for 100 data nodes.'() {
given: 'there are 200 existing data nodes'
def jsonListData = generateJsonForOpenRoadmDevices(1, 200, false)
- objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now)
+ objectUnderTest.replaceListContent(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/openroadm-devices', jsonListData, now, ContentType.JSON)
and: 'JSON for updated data leaves of 100 nodes'
def jsonDataUpdated = "{'openroadm-device':[" + (1..100).collect {"{'device-id':'C201-7-1A-" + it + "','status':'fail','ne-state':'jeopardy'}" }.join(",") + "]}"
when: 'update is performed for leaves'