X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=cps-ri%2Fsrc%2Ftest%2Fgroovy%2Forg%2Fonap%2Fcps%2Fspi%2Fimpl%2FCpsDataPersistenceServiceIntegrationSpec.groovy;h=69e6aa81c42740f0466ea4dea89deda5eb101ab5;hb=05e7b8a207b1c641468e77d754fe1a5ae9e1a51e;hp=ad8db766f8ca03cab0ec38eb7585ec186aee93a9;hpb=0e210d77ec39915046a95615f5f9d2a2dc65162b;p=cps.git diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy index ad8db766f..69e6aa81c 100755 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021 Nordix Foundation + * Copyright (C) 2021-2022 Nordix Foundation * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2021 Bell Canada. * ================================================================================ @@ -21,14 +21,8 @@ */ package org.onap.cps.spi.impl -import org.onap.cps.spi.exceptions.ConcurrencyException - -import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS -import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS - +import com.fasterxml.jackson.databind.ObjectMapper import com.google.common.collect.ImmutableSet -import com.google.gson.Gson -import com.google.gson.GsonBuilder import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.spi.entities.FragmentEntity import org.onap.cps.spi.exceptions.AlreadyDefinedException @@ -37,17 +31,22 @@ import org.onap.cps.spi.exceptions.DataNodeNotFoundException import org.onap.cps.spi.exceptions.DataspaceNotFoundException import org.onap.cps.spi.model.DataNode import org.onap.cps.spi.model.DataNodeBuilder +import org.onap.cps.utils.JsonObjectMapper import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.jdbc.Sql import javax.validation.ConstraintViolationException +import java.util.stream.Collectors + +import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS +import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { @Autowired CpsDataPersistenceService objectUnderTest - static final Gson GSON = new GsonBuilder().create() + static final JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) static final String SET_DATA = '/data/fragment.sql' static final long ID_DATA_NODE_WITH_DESCENDANTS = 4001 @@ -55,7 +54,12 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { static final String XPATH_DATA_NODE_WITH_LEAVES = '/parent-100' static final long UPDATE_DATA_NODE_FRAGMENT_ID = 4202L static final long UPDATE_DATA_NODE_SUB_FRAGMENT_ID = 4203L - static final long LIST_DATA_NODE_PARENT_FRAGMENT_ID = 4206L + static final long LIST_DATA_NODE_PARENT201_FRAGMENT_ID = 4206L + static final long LIST_DATA_NODE_PARENT203_FRAGMENT_ID = 4214L + static final long LIST_DATA_NODE_PARENT204_FRAGMENT_ID = 4219L + static final long LIST_DATA_NODE_PARENT205_FRAGMENT_ID = 4221L + static final long LIST_DATA_NODE_CHILD202_FRAGMENT_ID = 4204L + static final long LIST_DATA_NODE_PARENT202_FRAGMENT_ID = 4211L static final DataNode newDataNode = new DataNodeBuilder().build() static DataNode existingDataNode @@ -152,29 +156,37 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { } @Sql([CLEAR_DATA, SET_DATA]) - def 'Add list-node fragment with multiple elements.'() { - given: 'list node data fragment as a collection of data nodes' - def listNodeXpaths = ['/parent-201/child-204[@key="B"]', '/parent-201/child-204[@key="C"]'] - def listNodeCollection = buildDataNodeCollection(listNodeXpaths) - when: 'list-node elements added to existing parent node' - objectUnderTest.addListDataNodes(DATASPACE_NAME, ANCHOR_NAME3, '/parent-201', listNodeCollection) + def 'Add multiple list elements including an element with a child datanode.'() { + given: 'two new data nodes for an existing list' + def listElementXpaths = ['/parent-201/child-204[@key="B"]', '/parent-201/child-204[@key="C"]'] + def listElements = toDataNodes(listElementXpaths) + and: 'a child node for one of the new data nodes' + def childDataNode = buildDataNode('/parent-201/child-204[@key="C"]/grand-child-204[@key2="Z"]', [leave:'value'], []) + listElements[0].childDataNodes = [childDataNode] + when: 'the data nodes (list elements) are added to existing parent node' + objectUnderTest.addListElements(DATASPACE_NAME, ANCHOR_NAME3, '/parent-201', listElements) then: 'new entries successfully persisted, parent node now contains 5 children (2 new + 3 existing before)' - def parentFragment = fragmentRepository.getOne(LIST_DATA_NODE_PARENT_FRAGMENT_ID) + def parentFragment = fragmentRepository.getById(LIST_DATA_NODE_PARENT201_FRAGMENT_ID) def allChildXpaths = parentFragment.getChildFragments().collect { it.getXpath() } assert allChildXpaths.size() == 5 - assert allChildXpaths.containsAll(listNodeXpaths) + assert allChildXpaths.containsAll(listElementXpaths) + and: 'the child node of the new list entry is also present' + def dataspaceEntity = dataspaceRepository.getByName(DATASPACE_NAME) + def anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, ANCHOR_NAME3) + def listElementChild = fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, childDataNode.xpath) + assert listElementChild.isPresent() } @Sql([CLEAR_DATA, SET_DATA]) - def 'Add list-node fragment error scenario: #scenario.'() { - given: 'list node data fragment as a collection of data nodes' - def listNodeCollection = buildDataNodeCollection(listNodeXpaths) - when: 'list-node elements added to existing parent node' - objectUnderTest.addListDataNodes(DATASPACE_NAME, ANCHOR_NAME3, parentNodeXpath, listNodeCollection) + def 'Add list element error scenario: #scenario.'() { + given: 'list element as a collection of data nodes' + def listElementCollection = toDataNodes(listElementXpaths) + when: 'attempt to add list elements to parent node' + objectUnderTest.addListElements(DATASPACE_NAME, ANCHOR_NAME3, parentNodeXpath, listElementCollection) then: 'a #expectedException is thrown' thrown(expectedException) where: 'following parameters were used' - scenario | parentNodeXpath | listNodeXpaths || expectedException + scenario | parentNodeXpath | listElementXpaths || expectedException 'parent node does not exist' | '/unknown' | ['irrelevant'] || DataNodeNotFoundException 'already existing fragment' | '/parent-201' | ['/parent-201/child-204[@key="A"]'] || AlreadyDefinedException @@ -253,7 +265,7 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { objectUnderTest.updateDataLeaves(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, "/parent-200/child-201", ['leaf-value': 'new']) then: 'leaves are updated for selected data node' - def updatedFragment = fragmentRepository.getOne(UPDATE_DATA_NODE_FRAGMENT_ID) + def updatedFragment = fragmentRepository.getById(UPDATE_DATA_NODE_FRAGMENT_ID) def updatedLeaves = getLeavesMap(updatedFragment) assert updatedLeaves.size() == 1 assert updatedLeaves.'leaf-value' == 'new' @@ -284,7 +296,7 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { when: 'replace data node tree is performed' objectUnderTest.replaceDataNodeTree(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, submittedDataNode) then: 'leaves have been updated for selected data node' - def updatedFragment = fragmentRepository.getOne(UPDATE_DATA_NODE_FRAGMENT_ID) + def updatedFragment = fragmentRepository.getById(UPDATE_DATA_NODE_FRAGMENT_ID) def updatedLeaves = getLeavesMap(updatedFragment) assert updatedLeaves.size() == 1 assert updatedLeaves.'leaf-value' == 'new' @@ -298,12 +310,12 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { def 'Replace data node tree with descendants.'() { given: 'data node object with leaves updated, having child with old content' def submittedDataNode = buildDataNode("/parent-200/child-201", ['leaf-value': 'new'], [ - buildDataNode("/parent-200/child-201/grand-child", ['leaf-value': 'original'], []) + buildDataNode("/parent-200/child-201/grand-child", ['leaf-value': 'original'], []) ]) when: 'update is performed including descendants' objectUnderTest.replaceDataNodeTree(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, submittedDataNode) then: 'leaves have been updated for selected data node' - def updatedFragment = fragmentRepository.getOne(UPDATE_DATA_NODE_FRAGMENT_ID) + def updatedFragment = fragmentRepository.getById(UPDATE_DATA_NODE_FRAGMENT_ID) def updatedLeaves = getLeavesMap(updatedFragment) assert updatedLeaves.size() == 1 assert updatedLeaves.'leaf-value' == 'new' @@ -323,7 +335,7 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { when: 'update is performed including descendants' objectUnderTest.replaceDataNodeTree(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, submittedDataNode) then: 'leaves have been updated for selected data node' - def updatedFragment = fragmentRepository.getOne(UPDATE_DATA_NODE_FRAGMENT_ID) + def updatedFragment = fragmentRepository.getById(UPDATE_DATA_NODE_FRAGMENT_ID) def updatedLeaves = getLeavesMap(updatedFragment) assert updatedLeaves.size() == 1 assert updatedLeaves.'leaf-value' == 'new' @@ -343,7 +355,7 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { when: 'update is performed including descendants' objectUnderTest.replaceDataNodeTree(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, submittedDataNode) then: 'leaves have been updated for selected data node' - def updatedFragment = fragmentRepository.getOne(UPDATE_DATA_NODE_FRAGMENT_ID) + def updatedFragment = fragmentRepository.getById(UPDATE_DATA_NODE_FRAGMENT_ID) def updatedLeaves = getLeavesMap(updatedFragment) assert updatedLeaves.size() == 1 assert updatedLeaves.'leaf-value' == 'new' @@ -362,7 +374,7 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { def submittedDataNode = buildDataNode(xpath, ['leaf-name': 'leaf-value'], []) when: 'attempt to update data node for #scenario' objectUnderTest.replaceDataNodeTree(dataspaceName, anchorName, submittedDataNode) - then: 'a #expectedException is thrown' + then: 'a #expectedException is thrown' thrown(expectedException) where: 'the following data is used' scenario | dataspaceName | anchorName | xpath || expectedException @@ -372,36 +384,163 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { } @Sql([CLEAR_DATA, SET_DATA]) - def 'Replace list-node content of #scenario.'() { - given: 'list node data fragment as a collection of data nodes' - def listNodeCollection = buildDataNodeCollection(listNodeXpaths) - when: 'list-node elements replaced within the existing parent node' - objectUnderTest.replaceListDataNodes(DATASPACE_NAME, ANCHOR_NAME3, '/parent-201', listNodeCollection) - then: 'child list elements are updated as expected, non-list element remains as is' - def parentFragment = fragmentRepository.getOne(LIST_DATA_NODE_PARENT_FRAGMENT_ID) + def 'Replace list content of #scenario.'() { + given: 'list element as a collection of data nodes' + def listElementCollection = toDataNodes(listElementXpaths) + when: 'list elements are replaced within the existing parent node' + objectUnderTest.replaceListContent(DATASPACE_NAME, ANCHOR_NAME3, parentXpath, listElementCollection) + then: 'list elements are updated as expected, non-list element remains as is' + def parentFragment = fragmentRepository.getById(listElementFragmentID) def allChildXpaths = parentFragment.getChildFragments().collect { it.getXpath() } assert allChildXpaths.size() == expectedChildXpaths.size() assert allChildXpaths.containsAll(expectedChildXpaths) where: 'following parameters were used' - scenario | listNodeXpaths || expectedChildXpaths - 'existing list-node' | ['/parent-201/child-204[@key="B"]'] || ['/parent-201/child-203', '/parent-201/child-204[@key="B"]'] - 'non-existing list-node' | ['/parent-201/child-205[@key="1"]'] || ['/parent-201/child-203', '/parent-201/child-204[@key="A"]', '/parent-201/child-204[@key="X"]', '/parent-201/child-205[@key="1"]'] + scenario | listElementXpaths | parentXpath | listElementFragmentID || expectedChildXpaths + 'existing list element with non existing key' | ['/parent-201/child-204[@key="B"]'] | '/parent-201' | LIST_DATA_NODE_PARENT201_FRAGMENT_ID || ['/parent-201/child-203', '/parent-201/child-204[@key="B"]'] + 'non existing list element with non existing key' | ['/parent-201/child-205[@key="1"]'] | '/parent-201' | LIST_DATA_NODE_PARENT201_FRAGMENT_ID || ['/parent-201/child-203', '/parent-201/child-204[@key="A"]', '/parent-201/child-204[@key="X"]', '/parent-201/child-205[@key="1"]'] + 'list element with 1 existing key' | ['/parent-201/child-204[@key="X"]'] | '/parent-201' | LIST_DATA_NODE_PARENT201_FRAGMENT_ID || ['/parent-201/child-203', '/parent-201/child-204[@key="X"]'] + 'list element with combined keys' | ['/parent-202/child-205[@key="A"]'] | '/parent-202' | LIST_DATA_NODE_PARENT202_FRAGMENT_ID || ['/parent-202/child-206[@key="A"]', '/parent-202/child-205[@key="A"]'] + 'grandchild list element' | ['/parent-200/child-202/grand-child-202[@key="E"]'] | '/parent-200/child-202' | LIST_DATA_NODE_CHILD202_FRAGMENT_ID || ['/parent-200/child-202/grand-child-202[@key="E"]'] + 'list element with two list elements' | ['/parent-201/child-204[@key="new X"]', '/parent-201/child-204[@key="Y"]'] | '/parent-201' | LIST_DATA_NODE_PARENT201_FRAGMENT_ID || ['/parent-201/child-203', '/parent-201/child-204[@key="new X"]', '/parent-201/child-204[@key="Y"]'] + 'list element with compounded list element' | ['/parent-202/child-205[@key="A" and @key2="B"]'] | '/parent-202' | LIST_DATA_NODE_PARENT202_FRAGMENT_ID || ['/parent-202/child-206[@key="A"]', '/parent-202/child-205[@key="A" and @key2="B"]'] + 'list element with list element with parent with key value' | ['/parent-204[@key="L"]/child-210[@key="N"]'] | '/parent-204[@key="L"]' | LIST_DATA_NODE_PARENT204_FRAGMENT_ID || ['/parent-204[@key="L"]/child-210[@key="N"]'] } @Sql([CLEAR_DATA, SET_DATA]) - def 'Replace list-node fragment error scenario: #scenario.'() { - given: 'list node data fragment as a collection of data nodes' - def listNodeCollection = buildDataNodeCollection(listNodeXpaths) - when: 'list-node elements were replaced under existing parent node' - objectUnderTest.replaceListDataNodes(DATASPACE_NAME, ANCHOR_NAME3, parentNodeXpath, listNodeCollection) + def 'Replace list content that has #scenario'() { + given: 'list element with child list element as a collection of data nodes' + def grandChildDataNodes = toDataNodes(grandChildXpaths) + def listElementCollection = new DataNodeBuilder().withXpath(childXpath).withChildDataNodes(grandChildDataNodes).build() + when: 'list elements replaced within the existing parent node' + objectUnderTest.replaceListContent(DATASPACE_NAME, ANCHOR_NAME3, parentXpath, [listElementCollection ]) + then: 'list elements are updated as expected with non-list elements remaining as is' + def parentFragment = fragmentRepository.getById(listElementFragmentId) + def allChildXpaths = parentFragment.getChildFragments().collect { it.getXpath() } + assert allChildXpaths.size() == expectedRemainingChildXpaths.size() + assert allChildXpaths.containsAll(expectedRemainingChildXpaths) + and: 'grandchild list elements are updated as expected' + def allGrandChildXpaths = parentFragment.getChildFragments().collect(){ + it.getChildFragments().collect(){ + it.getXpath()}} + allGrandChildXpaths.removeIf(list -> list.isEmpty()) + def grandChildXpathsToList = allGrandChildXpaths.stream().flatMap(List::stream).collect(Collectors.toList()) + def expectedGrandChildXpaths = grandChildXpaths + assert grandChildXpathsToList.size() == expectedGrandChildXpaths.size() + assert grandChildXpathsToList.containsAll(expectedGrandChildXpaths) + where: 'the following parameters are used' + scenario | parentXpath | childXpath | grandChildXpaths | listElementFragmentId || expectedRemainingChildXpaths + 'grandchild of list' | '/parent-203' | '/parent-203/child-204[@key="X"]' | ['/parent-203/child-204/grandchild[@key="2"]'] | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ['/parent-203/child-203', '/parent-203/child-204[@key="X"]'] + 'grandchild of list with two new element' | '/parent-203' | '/parent-203/child-204[@key="X"]' | ['/parent-203/child-204/grandchild[@key="2"]' , '/parent-203/child-204/grandchild[@key="3"]'] | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ['/parent-203/child-203', '/parent-203/child-204[@key="X"]'] + 'grandchild with compound list elements' | '/parent-205' | '/parent-205/child-205[@key="X"]' | ['/parent-205/child-205/grand-child-206[@key="Y" and @key2="Z"]'] | LIST_DATA_NODE_PARENT205_FRAGMENT_ID || ['/parent-205/child-205', '/parent-205/child-205[@key="X"]'] + } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Replace list content of #scenario with grandchildren.'() { + given: 'list element as a collection of data nodes' + def listElementCollection = toDataNodes(listElementXpaths) + when: 'list elements are replaced within the existing parent node' + objectUnderTest.replaceListContent(DATASPACE_NAME, ANCHOR_NAME3, parentXpath, listElementCollection) + then: 'child list elements are updated as expected with non-list elements remaining as is' + def parentFragment = fragmentRepository.getById(listElementFragmentID) + def allChildXpaths = parentFragment.getChildFragments().collect { it.getXpath() } + assert allChildXpaths.size() == expectedChildXpaths.size() + assert allChildXpaths.containsAll(expectedChildXpaths) + and: 'grandchild list elements are updated as expected' + def allGrandChildXpaths = parentFragment.getChildFragments().collect { + it.getChildFragments().collect { + it.getXpath()}} + allGrandChildXpaths.removeIf(list -> list.isEmpty()) + assert allGrandChildXpaths.size() == expectedGrandChildXpaths.size() + assert allGrandChildXpaths.containsAll(expectedGrandChildXpaths) + where: 'following parameters were used' + scenario | listElementXpaths | parentXpath | listElementFragmentID || expectedChildXpaths | expectedGrandChildXpaths + 'existing list element with existing keys' | ['/parent-203/child-204[@key="X"]'] | '/parent-203' | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ['/parent-203/child-203', '/parent-203/child-204[@key="X"]'] | [] + 'non existing list element with existing keys' | ['/parent-203/child-204[@key="V"]'] | '/parent-203' | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ['/parent-203/child-203', '/parent-203/child-204[@key="V"]'] | [] + } + + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Replace content error scenario: #scenario.'() { + given: 'list element as a collection of data nodes' + def listElementCollection = toDataNodes(listElementXpaths) + when: 'list elements were replaced under existing parent node' + objectUnderTest.replaceListContent(DATASPACE_NAME, ANCHOR_NAME3, parentNodeXpath, listElementCollection) then: 'a #expectedException is thrown' thrown(expectedException) where: 'following parameters were used' - scenario | parentNodeXpath | listNodeXpaths || expectedException + scenario | parentNodeXpath | listElementXpaths || expectedException 'parent node does not exist' | '/unknown' | ['irrelevant'] || DataNodeNotFoundException } - static Collection buildDataNodeCollection(xpaths) { + @Sql([CLEAR_DATA, SET_DATA]) + def 'Delete list scenario: #scenario.'() { + when: 'deleting list is executed for: #scenario.' + objectUnderTest.deleteListDataNode(DATASPACE_NAME, ANCHOR_NAME3, targetXpaths) + then: 'only the expected children remain' + def parentFragment = fragmentRepository.getById(parentFragmentId) + def remainingChildXpaths = parentFragment.getChildFragments().collect { it.getXpath() } + assert remainingChildXpaths.size() == expectedRemainingChildXpaths.size() + assert remainingChildXpaths.containsAll(expectedRemainingChildXpaths) + where: 'following parameters were used' + scenario | targetXpaths | parentFragmentId || expectedRemainingChildXpaths + 'list element with key' | '/parent-203/child-204[@key="A"]' | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ['/parent-203/child-203', '/parent-203/child-204[@key="X"]'] + 'list element with combined keys' | '/parent-202/child-205[@key="A" and @key2="B"]' | LIST_DATA_NODE_PARENT202_FRAGMENT_ID || ['/parent-202/child-206[@key="A"]'] + 'whole list' | '/parent-203/child-204' | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ['/parent-203/child-203'] + 'list element under list element' | '/parent-203/child-204[@key="X"]/grand-child-204[@key2="Y"]' | LIST_DATA_NODE_PARENT203_FRAGMENT_ID || ['/parent-203/child-203', '/parent-203/child-204[@key="X"]', '/parent-203/child-204[@key="A"]'] + } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Delete list error scenario: #scenario.'() { + when: 'attempting to delete scenario: #scenario.' + objectUnderTest.deleteListDataNode(DATASPACE_NAME, ANCHOR_NAME3, targetXpaths) + then: 'a DataNodeNotFoundException is thrown' + thrown(DataNodeNotFoundException) + where: 'following parameters were used' + scenario | targetXpaths + 'whole list, parent node does not exist' | '/unknown/some-child' + 'list element, parent node does not exist' | '/unknown/child-204[@key="A"]' + 'whole list does not exist' | '/parent-200/unknown' + 'list element, list does not exist' | '/parent-200/unknown[@key="C"]' + 'list element, element does not exist' | '/parent-203/child-204[@key="C"]' + 'valid datanode but not a list' | '/parent-200/child-202' + } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Confirm deletion of #scenario.'() { + given: 'a valid data node' + def dataNode + def dataNodeXpath + when: 'data nodes are deleted' + objectUnderTest.deleteDataNode(DATASPACE_NAME, ANCHOR_NAME3, xpathForDeletion) + then: 'verify data nodes are removed' + try { + dataNode = objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_NAME3, getDataNodesXpaths, INCLUDE_ALL_DESCENDANTS) + dataNodeXpath = dataNode.getXpath() + assert dataNodeXpath == expectedXpaths + } catch (DataNodeNotFoundException) { + assert dataNodeXpath == expectedXpaths + } + where: 'following parameters were used' + scenario | xpathForDeletion | getDataNodesXpaths || expectedXpaths + 'child of target' | '/parent-206/child-206' | '/parent-206/child-206' || null + 'child data node, parent still exists' | '/parent-206/child-206' | '/parent-206' || '/parent-206' + 'list element' | '/parent-206/child-206/grand-child-206[@key="A"]' | '/parent-206/child-206/grand-child-206[@key="A"]' || null + 'list element, sibling still exists' | '/parent-206/child-206/grand-child-206[@key="A"]' | '/parent-206/child-206/grand-child-206[@key="X"]' || '/parent-206/child-206/grand-child-206[@key="X"]' + } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Delete data node with #scenario.'() { + when: 'data node is deleted' + objectUnderTest.deleteDataNode(DATASPACE_NAME, ANCHOR_NAME3, datanodeXpath) + then: 'a #expectedException is thrown' + thrown(DataNodeNotFoundException) + where: 'the following parameters were used' + scenario | datanodeXpath + 'valid data node, non existent child node' | '/parent-203/child-non-existent' + 'invalid list element' | '/parent-206/child-206/grand-child-206@key="A"]' + } + + static Collection toDataNodes(xpaths) { return xpaths.collect { new DataNodeBuilder().withXpath(it).build() } } @@ -410,7 +549,7 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { } static Map getLeavesMap(FragmentEntity fragmentEntity) { - return GSON.fromJson(fragmentEntity.getAttributes(), Map.class) + return jsonObjectMapper.convertJsonString(fragmentEntity.getAttributes(), Map.class) } def static assertLeavesMaps(actualLeavesMap, expectedLeavesMap) {