From ad61e283f7d981c3c8e307af871fb3a63e0cf4f9 Mon Sep 17 00:00:00 2001 From: Rudrangi Anupriya Date: Mon, 17 Jul 2023 20:20:34 +0530 Subject: Persisting a list element to a parent list (ep2) Post List Element does not allow for create List Element, only appends onto existing node as children -Add a check in saveListElements to see if the parent xpath is a root path ("/").If root node store list element as top node. Else add passed list element to parent xpath node. -Add test for scenario for above -Add test scenario Saving list element data fragment under Root node -Add Integration Tests Add and Delete top-level list (element) data nodes with root node -Update bookstore model with TopLevelList datanode Issue-ID: CPS-1586 Change-Id: Iaa7f59fbeebb03703626132c6d5c2afde0e7ab4b Signed-off-by: Rudrangi Anupriya --- .../org/onap/cps/api/impl/CpsDataServiceImpl.java | 12 ++++++++-- .../cps/api/impl/CpsDataServiceImplSpec.groovy | 22 +++++++++++++++++ cps-service/src/test/resources/bookstore.json | 8 +++++++ cps-service/src/test/resources/bookstore.yang | 28 ++++++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) (limited to 'cps-service') 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 6e7c1649d7..7db87e87ea 100755 --- 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 @@ -116,8 +116,12 @@ public class CpsDataServiceImpl implements CpsDataService { final Anchor anchor = cpsAdminService.getAnchor(dataspaceName, anchorName); final Collection listElementDataNodeCollection = buildDataNodes(anchor, parentNodeXpath, jsonData, ContentType.JSON); - cpsDataPersistenceService.addListElements(dataspaceName, anchorName, parentNodeXpath, - listElementDataNodeCollection); + if (isRootNodeXpath(parentNodeXpath)) { + cpsDataPersistenceService.storeDataNodes(dataspaceName, anchorName, listElementDataNodeCollection); + } else { + cpsDataPersistenceService.addListElements(dataspaceName, anchorName, parentNodeXpath, + listElementDataNodeCollection); + } processDataUpdatedEventAsync(anchor, parentNodeXpath, UPDATE, observedTimestamp); } @@ -391,6 +395,10 @@ public class CpsDataServiceImpl implements CpsDataService { .get(anchor.getDataspaceName(), anchor.getSchemaSetName()).getSchemaContext(); } + private static boolean isRootNodeXpath(final String xpath) { + return ROOT_NODE_XPATH.equals(xpath); + } + private void processDataNodeUpdate(final Anchor anchor, final DataNode dataNodeUpdate) { cpsDataPersistenceService.batchUpdateDataLeaves(anchor.getDataspaceName(), anchor.getName(), Collections.singletonMap(dataNodeUpdate.getXpath(), dataNodeUpdate.getLeaves())); 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 db8664042a..ba438496fd 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 @@ -110,6 +110,28 @@ class CpsDataServiceImplSpec extends Specification { noExceptionThrown() } + def 'Saving list element data fragment under Root node.'() { + given: 'schema set for given anchor and dataspace references bookstore model' + setupSchemaSetMocks('bookstore.yang') + when: 'save data method is invoked with list element json data' + def jsonData = '{"multiple-data-tree:invoice": [{"ProductID": "2","ProductName": "Banana","price": "100","stock": True}]}' + objectUnderTest.saveListElements(dataspaceName, anchorName, '/', jsonData, observedTimestamp) + then: 'the persistence service method is invoked with correct parameters' + 1 * mockCpsDataPersistenceService.storeDataNodes(dataspaceName, anchorName, + { dataNodeCollection -> + { + assert dataNodeCollection.size() == 1 + assert dataNodeCollection.collect { it.getXpath() } + .containsAll(['/invoice[@ProductID=\'2\']']) + } + } + ) + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) + and: 'data updated event is sent to notification service' + 1 * mockNotificationService.processDataUpdatedEvent(anchor, '/', Operation.UPDATE, observedTimestamp) + } + def 'Saving child data fragment under existing node.'() { given: 'schema set for given anchor and dataspace references test-tree model' setupSchemaSetMocks('test-tree.yang') diff --git a/cps-service/src/test/resources/bookstore.json b/cps-service/src/test/resources/bookstore.json index 459908bd63..4b8ed3dab1 100644 --- a/cps-service/src/test/resources/bookstore.json +++ b/cps-service/src/test/resources/bookstore.json @@ -1,4 +1,12 @@ { + "multiple-data-tree:invoice": [ + { + "ProductID": "1", + "ProductName": "Apple", + "price": "100", + "stock": false + } + ], "test:bookstore":{ "bookstore-name": "Chapters/Easons", "categories": [ diff --git a/cps-service/src/test/resources/bookstore.yang b/cps-service/src/test/resources/bookstore.yang index 2179fb93d9..b7a52e2c8c 100644 --- a/cps-service/src/test/resources/bookstore.yang +++ b/cps-service/src/test/resources/bookstore.yang @@ -15,6 +15,34 @@ module stores { } } + list invoice { + key "ProductID"; + leaf ProductID { + type uint64; + mandatory "true"; + description + "Unique product ID. Example: 001"; + } + leaf ProductName { + type string; + mandatory "true"; + description + "Name of the Product"; + } + leaf price { + type uint64; + mandatory "true"; + description + "Price of book"; + } + leaf stock { + type boolean; + default "false"; + description + "Book in stock or not. Example value: true"; + } + } + container bookstore { leaf bookstore-name { -- cgit 1.2.3-korg