diff options
author | 2021-09-29 13:44:53 +0100 | |
---|---|---|
committer | 2021-09-29 13:44:53 +0100 | |
commit | 8bf710c85d26ddd4586554868473b070ca68a70c (patch) | |
tree | 28e9dd1dce1410e46618a7e7379f948bee3084c7 /cps-ri/src/test | |
parent | fdcb36fa9db642df3c47637d32f4e7ac5dd347e8 (diff) |
CPS-594: Exception when updating list node PATCH
SQL ConstraintViolationException updating the list node element using PATCH List node API
- Took advantage of replaceDataNodeTree to replace list node children recursively
- Added functionality to exclude the updated dataNodes when removing the list node descendants
Issue-ID: CPS-594
Signed-off-by: lukegleeson <luke.gleeson@est.tech>
Signed-off-by: DylanB95EST <dylan.byrne@est.tech>
Change-Id: Idbf580fab05581513b52327d6895b9e39b4cf470
Signed-off-by: DylanB95EST <dylan.byrne@est.tech>
Diffstat (limited to 'cps-ri/src/test')
-rwxr-xr-x | cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy | 74 | ||||
-rwxr-xr-x | cps-ri/src/test/resources/data/fragment.sql | 9 |
2 files changed, 77 insertions, 6 deletions
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 e2316e863..144b18b53 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 @@ -32,10 +32,12 @@ 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.spockframework.util.CollectionUtil 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 @@ -55,6 +57,8 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { static final long UPDATE_DATA_NODE_SUB_FRAGMENT_ID = 4203L 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 @@ -385,19 +389,79 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { 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) + objectUnderTest.replaceListDataNodes(DATASPACE_NAME, ANCHOR_NAME3, parentXpath, listNodeCollection) then: 'child list elements are updated as expected, non-list element remains as is' - def parentFragment = fragmentRepository.getById(LIST_DATA_NODE_PARENT201_FRAGMENT_ID) + def parentFragment = fragmentRepository.getById(listNodeFragmentID) 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 | listNodeXpaths |parentXpath |listNodeFragmentID || expectedChildXpaths + 'existing list node 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 node 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"]'] + 'existing list node 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"]'] + 'existing list-node 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"]'] + 'existing grandchild list-node' | ['/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"]'] + 'existing list node with two list nodes' | ['/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"]'] + 'existing list node with compounded list node' | ['/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"]'] + 'existing list node with list node 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 that has children with #scenario'() { + given: 'list node data fragment with child data node fragments' + def grandChildDataNodes = buildDataNodeCollection(grandChildXpaths) + def listNode = new DataNodeBuilder().withXpath(childXpath).withChildDataNodes(grandChildDataNodes).build() + when: 'list-node elements replaced within the existing parent node' + objectUnderTest.replaceListDataNodes(DATASPACE_NAME, ANCHOR_NAME3, parentXpath, [ listNode ]) + then: 'child list elements are updated as expected with non-list elements remaining as is' + def parentFragment = fragmentRepository.getById(listNodeFragmentId) + 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()) + 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 | expectedChildXpaths | listNodeFragmentId + 'existing grandchild of list node' | '/parent-203' | '/parent-203/child-204[@key="X"]' | ['/parent-203/child-204/grandchild[@key="2"]'] | ['/parent-203/child-203', '/parent-203/child-204[@key="X"]'] | LIST_DATA_NODE_PARENT203_FRAGMENT_ID + 'existing grandchild of list node with two new nodes' | '/parent-203' | '/parent-203/child-204[@key="X"]' | ['/parent-203/child-204/grandchild[@key="2"]' , '/parent-203/child-204/grandchild[@key="3"]'] | ['/parent-203/child-203', '/parent-203/child-204[@key="X"]'] | LIST_DATA_NODE_PARENT203_FRAGMENT_ID + 'existing grandchild with compound list node' | '/parent-205' | '/parent-205/child-205[@key="X"]' | ['/parent-205/child-205/grand-child-206[@key="Y" and @key2="Z"]'] | ['/parent-205/child-205', '/parent-205/child-205[@key="X"]'] | LIST_DATA_NODE_PARENT205_FRAGMENT_ID + 'two existing list node with a new node' | '/parent-205' | '/parent-205/child-205[@key="X"]' | ['/parent-205/child-205/grandchild[@key="A"]'] | ['/parent-205/child-205', '/parent-205/child-205[@key="X"]'] | LIST_DATA_NODE_PARENT205_FRAGMENT_ID + } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Replace list-node content of #scenario with grandchildren.'() { + 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, parentXpath, listNodeCollection) + then: 'child list elements are updated as expected with non-list elements remaining as is' + def parentFragment = fragmentRepository.getById(listNodeFragmentID) + 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 | listNodeXpaths | parentXpath | listNodeFragmentID || expectedChildXpaths | expectedGrandChildXpaths + 'existing list node 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 node 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 list-node fragment error scenario: #scenario.'() { given: 'list node data fragment as a collection of data nodes' def listNodeCollection = buildDataNodeCollection(listNodeXpaths) diff --git a/cps-ri/src/test/resources/data/fragment.sql b/cps-ri/src/test/resources/data/fragment.sql index 886e6e175..f6e887e01 100755 --- a/cps-ri/src/test/resources/data/fragment.sql +++ b/cps-ri/src/test/resources/data/fragment.sql @@ -61,4 +61,11 @@ INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) (4215, 1001, 3003, 4214, '/parent-203/child-203', '{}'), (4216, 1001, 3003, 4214, '/parent-203/child-204[@key="A"]', '{"key": "A"}'), (4217, 1001, 3003, 4214, '/parent-203/child-204[@key="X"]', '{"key": "X"}'), - (4218, 1001, 3003, 4217, '/parent-203/child-204[@key="X"]/grand-child-204[@key2="Y"]', '{"key": "X", "key2": "Y"}');
\ No newline at end of file + (4218, 1001, 3003, 4217, '/parent-203/child-204[@key="X"]/grand-child-204[@key2="Y"]', '{"key": "X", "key2": "Y"}'), + (4219, 1001, 3003, null, '/parent-204[@key="L"]', '{"key": "L"}'), + (4220, 1001, 3003, 4219, '/parent-204[@key="L"]/child-210[@key="M"]', '{"key": "M"}'), + (4221, 1001, 3003, null, '/parent-205', '{"leaf-value": "original"}'), + (4222, 1001, 3003, 4221, '/parent-205/child-205', '{}'), + (4223, 1001, 3003, 4221, '/parent-205/child-205[@key="X"]', '{"key": "X"}'), + (4224, 1001, 3003, 4223, '/parent-205/child-205[@key="X"]/grand-child-206[@key="Y"]', '{"key": "Y", "key2": "Z"}'), + (4225, 1001, 3003, 4223, '/parent-205/child-205[@key="X"]/grand-child-206[@key="Y" and @key2="Z"]', '{"key": "Y", "key2": "Z"}');
\ No newline at end of file |