From ebfa4077b2e462237301e93566fed6ef2f56674c Mon Sep 17 00:00:00 2001 From: "puthuparambil.aditya" Date: Mon, 14 Feb 2022 10:56:35 +0000 Subject: [PATCH] Align JSON DataNode for Get and Post/Put API in CPS Issue-ID: CPS-865 Signed-off-by: puthuparambil.aditya Change-Id: I60b1f9c94e79bdd66d60fe6a68f5fc4adc718d35 --- .../cps/rest/controller/DataRestController.java | 4 +-- .../cps/rest/controller/QueryRestController.java | 6 ++--- .../rest/controller/DataRestControllerSpec.groovy | 16 +++++++----- .../rest/controller/QueryRestControllerSpec.groovy | 4 +-- .../notification/CpsDataUpdatedEventFactory.java | 2 +- .../main/java/org/onap/cps/utils/DataMapUtils.java | 13 +++++++++- .../CpsDataUpdateEventFactorySpec.groovy | 6 ++--- .../org/onap/cps/utils/DataMapUtilsSpec.groovy | 30 ++++++++++++++++++---- csit/tests/cps-data/cps-data.robot | 3 ++- 9 files changed, 60 insertions(+), 24 deletions(-) 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 fc2818b6f..b78d38339 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 @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2021 Bell Canada. + * Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2021-2022 Nordix Foundation * ================================================================================ @@ -86,7 +86,7 @@ public class DataRestController implements CpsDataApi { ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS; final var dataNode = cpsDataService.getDataNode(dataspaceName, anchorName, xpath, fetchDescendantsOption); - return new ResponseEntity<>(DataMapUtils.toDataMap(dataNode), HttpStatus.OK); + return new ResponseEntity<>(DataMapUtils.toDataMapWithIdentifier(dataNode), HttpStatus.OK); } @Override 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 eb422dc69..7a96cffff 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,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2021-2022 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,9 +54,8 @@ public class QueryRestController implements CpsQueryApi { final Collection dataNodes = cpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption); final List> dataNodeList = new ArrayList<>(); - for (final DataNode dataNode : dataNodes) { - dataNodeList.add(DataMapUtils.toDataMap(dataNode)); - } + dataNodes.stream() + .forEach(dataNode -> dataNodeList.add(DataMapUtils.toDataMapWithIdentifier(dataNode))); return new ResponseEntity<>(jsonObjectMapper.asJsonString(dataNodeList), HttpStatus.OK); } } 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 4d75848cf..6f415bd45 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 @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2021-2022 Nordix Foundation * Modifications Copyright (C) 2021 Pantheon.tech - * Modifications Copyright (C) 2021 Bell Canada. + * Modifications Copyright (C) 2021-2022 Bell Canada. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -174,7 +174,7 @@ class DataRestControllerSpec extends Specification { def 'Get data node with leaves'() { given: 'the service returns data node leaves' - def xpath = 'some xPath' + def xpath = 'xpath' def endpoint = "$dataNodeBaseEndpoint/anchors/$anchorName/node" mockCpsDataService.getDataNode(dataspaceName, anchorName, xpath, OMIT_DESCENDANTS) >> dataNodeWithLeavesNoChildren when: 'get request is performed through REST API' @@ -183,6 +183,8 @@ class DataRestControllerSpec extends Specification { .andReturn().response then: 'a success response is returned' response.status == HttpStatus.OK.value() + then: 'the response contains the the datanode in json format' + response.getContentAsString() == '{"xpath":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}' and: 'response contains expected leaf and value' response.contentAsString.contains('"leaf":"value"') and: 'response contains expected leaf-list and values' @@ -203,13 +205,15 @@ class DataRestControllerSpec extends Specification { .andReturn().response then: 'a success response is returned' response.status == HttpStatus.OK.value() + and: 'the response contains the root node identifier: #expectedRootidentifier' + response.contentAsString.contains(expectedRootidentifier) and: 'the response contains child is #expectChildInResponse' response.contentAsString.contains('"child"') == expectChildInResponse where: - scenario | dataNode | includeDescendantsOption || expectedCpsDataServiceOption | expectChildInResponse - 'no descendants by default' | dataNodeWithLeavesNoChildren | '' || OMIT_DESCENDANTS | false - 'no descendant explicitly' | dataNodeWithLeavesNoChildren | 'false' || OMIT_DESCENDANTS | false - 'with descendants' | dataNodeWithChild | 'true' || INCLUDE_ALL_DESCENDANTS | true + scenario | dataNode | includeDescendantsOption || expectedCpsDataServiceOption | expectChildInResponse | expectedRootidentifier + 'no descendants by default' | dataNodeWithLeavesNoChildren | '' || OMIT_DESCENDANTS | false | 'xpath' + 'no descendant explicitly' | dataNodeWithLeavesNoChildren | 'false' || OMIT_DESCENDANTS | false | 'xpath' + 'with descendants' | dataNodeWithChild | 'true' || INCLUDE_ALL_DESCENDANTS | true | 'parent' } def 'Update data node leaves: #scenario.'() { 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 1e42a0060..0e55285be 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,7 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2021-2022 Nordix Foundation - * Modifications Copyright (C) 2021 Bell Canada. + * Modifications Copyright (C) 2021-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -72,7 +72,7 @@ class QueryRestControllerSpec extends Specification { .andReturn().response then: 'the response contains the the datanode in json format' response.status == HttpStatus.OK.value() - response.getContentAsString() == '[{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]},{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}]' + response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}') where: 'the following options for include descendants are provided in the request' scenario | includeDescendantsOption || expectedCpsDataServiceOption 'no descendants by default' | '' || OMIT_DESCENDANTS diff --git a/cps-service/src/main/java/org/onap/cps/notification/CpsDataUpdatedEventFactory.java b/cps-service/src/main/java/org/onap/cps/notification/CpsDataUpdatedEventFactory.java index e7b639d48..1013c13b7 100644 --- a/cps-service/src/main/java/org/onap/cps/notification/CpsDataUpdatedEventFactory.java +++ b/cps-service/src/main/java/org/onap/cps/notification/CpsDataUpdatedEventFactory.java @@ -89,7 +89,7 @@ public class CpsDataUpdatedEventFactory { private Data createData(final DataNode dataNode) { final var data = new Data(); - DataMapUtils.toDataMap(dataNode).forEach(data::setAdditionalProperty); + DataMapUtils.toDataMapWithIdentifier(dataNode).forEach(data::setAdditionalProperty); return data; } diff --git a/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java b/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java index 71a95f1ca..42719d9b3 100644 --- a/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java +++ b/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java @@ -36,13 +36,24 @@ import org.onap.cps.spi.model.DataNode; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class DataMapUtils { + /** + * Converts DataNode structure into a map including the root node identifier for a JSON response. + * + * @param dataNode data node object + * @return a map representing same data with the root node identifier + */ + public static Map toDataMapWithIdentifier(final DataNode dataNode) { + return ImmutableMap.builder() + .put(getNodeIdentifier(dataNode.getXpath()), toDataMap(dataNode)) + .build(); + } + /** * Converts DataNode structure into a map for a JSON response. * * @param dataNode data node object * @return a map representing same data */ - public static Map toDataMap(final DataNode dataNode) { return ImmutableMap.builder() .putAll(dataNode.getLeaves()) diff --git a/cps-service/src/test/groovy/org/onap/cps/notification/CpsDataUpdateEventFactorySpec.groovy b/cps-service/src/test/groovy/org/onap/cps/notification/CpsDataUpdateEventFactorySpec.groovy index 5b13fa516..682197d51 100644 --- a/cps-service/src/test/groovy/org/onap/cps/notification/CpsDataUpdateEventFactorySpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/notification/CpsDataUpdateEventFactorySpec.groovy @@ -45,10 +45,10 @@ class CpsDataUpdateEventFactorySpec extends Specification { given: 'an anchor which has been updated' def anchor = new Anchor('my-anchorname', 'my-dataspace', 'my-schemaset-name') and: 'cps data service returns the data node details' - def xpath = '/' + def xpath = '/xpath' def dataNode = new DataNodeBuilder().withXpath(xpath).withLeaves(['leafName': 'leafValue']).build() mockCpsDataService.getDataNode( - 'my-dataspace', 'my-anchorname', xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode + 'my-dataspace', 'my-anchorname', '/', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode when: 'CPS data updated event is created' def cpsDataUpdatedEvent = objectUnderTest.createCpsDataUpdatedEvent(anchor, DateTimeUtility.toOffsetDateTime(inputObservedTimestamp), Operation.CREATE) @@ -72,7 +72,7 @@ class CpsDataUpdateEventFactorySpec extends Specification { assert dataspaceName == 'my-dataspace' assert schemaSetName == 'my-schemaset-name' assert operation == Content.Operation.CREATE - assert data == new Data().withAdditionalProperty('leafName', 'leafValue') + assert data == new Data().withAdditionalProperty('xpath', ['leafName': 'leafValue']) } where: scenario | inputObservedTimestamp diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy index 429ab40b9..90563c0c1 100644 --- a/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy @@ -2,6 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2020 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,7 +43,10 @@ class DataMapUtilsSpec extends Specification { def 'Data node structure conversion to map.'() { when: 'data node structure is converted to a map' - Map result = DataMapUtils.toDataMap(dataNode) + def result = DataMapUtils.toDataMap(dataNode) + + then: 'root node identifier is null' + result.parent == null then: 'root node leaves are top level elements' result.parentLeaf == 'parentLeafValue' @@ -53,12 +57,28 @@ class DataMapUtilsSpec extends Specification { ['listElementLeaf': 'listElement2leafValue']) and: 'leaves for child element is populated under its node identifier' - Map childObjectData = result.'child-object' - childObjectData.childLeaf == 'childLeafValue' + result.'child-object'.childLeaf == 'childLeafValue' and: 'leaves for grandchild element is populated under its node identifier' - Map grandChildObjectData = childObjectData.'grand-child-object' - grandChildObjectData.grandChildLeaf == 'grandChildLeafValue' + result.'child-object'.'grand-child-object'.grandChildLeaf == 'grandChildLeafValue' } + def 'Data node structure conversion to map with root node identifier.'() { + when: 'data node structure is converted to a map with root node identifier' + def result = DataMapUtils.toDataMapWithIdentifier(dataNode) + + then: 'root node identifier is not null' + result.parent != null + + then: 'root node leaves are populated under its node identifier' + def parentNode = result.parent + parentNode.parentLeaf == 'parentLeafValue' + parentNode.parentLeafList == ['parentLeafListEntry1','parentLeafListEntry2'] + + and: 'leaves for child element is populated under its node identifier' + parentNode.'child-object'.childLeaf == 'childLeafValue' + + and: 'leaves for grandchild element is populated under its node identifier' + parentNode.'child-object'.'grand-child-object'.grandChildLeaf == 'grandChildLeafValue' + } } diff --git a/csit/tests/cps-data/cps-data.robot b/csit/tests/cps-data/cps-data.robot index 1c48e0069..55667c3c1 100644 --- a/csit/tests/cps-data/cps-data.robot +++ b/csit/tests/cps-data/cps-data.robot @@ -1,5 +1,6 @@ # ============LICENSE_START======================================================= # Copyright (c) 2021 Pantheon.tech. +# Modifications Copyright (C) 2022 Bell Canada. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -45,7 +46,7 @@ Get Data Node by XPath ${params}= Create Dictionary xpath=/test-tree/branch[@name='Left']/nest ${headers}= Create Dictionary Authorization=${auth} ${response}= Get On Session CPS_URL ${uri} params=${params} headers=${headers} expected_status=200 - ${responseJson}= Set Variable ${response.json()} + ${responseJson}= Set Variable ${response.json()['nest']} Should Be Equal As Strings ${responseJson['name']} Small -- 2.16.6