diff options
author | ToineSiebelink <toine.siebelink@est.tech> | 2021-04-30 12:09:44 +0100 |
---|---|---|
committer | ToineSiebelink <toine.siebelink@est.tech> | 2021-04-30 12:10:09 +0100 |
commit | 6c9c100daba10717641a08b6c6dc3ec3b51c56a8 (patch) | |
tree | 8d093337d257cf9ad79b0f80486841df92c9d99f /cps-ri/src/test | |
parent | c718b88511539c3b85d3fcd3d7c84e3baa89b749 (diff) |
Implement cps path query to get ancestor by schema node identifier
Cleaned up some legcy issues in related testware
Issue-ID: CPS-305
Signed-off-by: niamhcore <niamh.core@est.tech>
Change-Id: Ic4b21308478f399e3a454dbcd73943e077b0f3f2
Signed-off-by: ToineSiebelink <toine.siebelink@est.tech>
Diffstat (limited to 'cps-ri/src/test')
4 files changed, 82 insertions, 81 deletions
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy index 8acfe783da..4bebff9f84 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy @@ -20,14 +20,10 @@ */ package org.onap.cps.spi.impl -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.FetchDescendantsOption import org.onap.cps.spi.exceptions.CpsPathException import org.onap.cps.spi.model.DataNode -import org.onap.cps.spi.model.DataNodeBuilder import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.jdbc.Sql @@ -39,42 +35,7 @@ class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase { @Autowired CpsDataPersistenceService objectUnderTest - static final Gson GSON = new GsonBuilder().create() - static final String SET_DATA = '/data/fragment.sql' - static final String XPATH_DATA_NODE_WITH_DESCENDANTS = '/parent-1' - - static DataNode existingDataNode - static DataNode existingChildDataNode - - def expectedLeavesByXpathMap = [ - '/parent-100' : ['parent-leaf': 'parent-leaf value'], - '/parent-100/child-001' : ['first-child-leaf': 'first-child-leaf value'], - '/parent-100/child-002' : ['second-child-leaf': 'second-child-leaf value'], - '/parent-100/child-002/grand-child': ['grand-child-leaf': 'grand-child-leaf value'] - ] - - static { - existingDataNode = createDataNodeTree(XPATH_DATA_NODE_WITH_DESCENDANTS) - existingChildDataNode = createDataNodeTree('/parent-1/child-1') - } - - static def createDataNodeTree(String... xpaths) { - def dataNodeBuilder = new DataNodeBuilder().withXpath(xpaths[0]) - if (xpaths.length > 1) { - def xPathsDescendant = Arrays.copyOfRange(xpaths, 1, xpaths.length) - def childDataNode = createDataNodeTree(xPathsDescendant) - dataNodeBuilder.withChildDataNodes(ImmutableSet.of(childDataNode)) - } - dataNodeBuilder.build() - } - - def static treeToFlatMapByXpath(Map<String, DataNode> flatMap, DataNode dataNodeTree) { - flatMap.put(dataNodeTree.getXpath(), dataNodeTree) - dataNodeTree.getChildDataNodes() - .forEach(childDataNode -> treeToFlatMapByXpath(flatMap, childDataNode)) - return flatMap - } @Sql([CLEAR_DATA, SET_DATA]) def 'Cps Path query for single leaf value with type: #type.'() { @@ -98,10 +59,10 @@ class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase { then: 'no data is returned' result.isEmpty() where: 'following cps queries are performed' - scenario | cpsPath - 'cps path is incomplete' | '/parent-200[@common-leaf-name-int=5]' - 'leaf value does not exist' | '/parent-200/child-202[@common-leaf-name=\'does not exist\']' - 'incomplete end of xpath prefix' | '/parent-200/child-20[@common-leaf-name-int=5]' + scenario | cpsPath + 'cps path is incomplete' | '/parent-200[@common-leaf-name-int=5]' + 'leaf value does not exist' | '/parent-200/child-202[@common-leaf-name=\'does not exist\']' + 'incomplete end of xpath prefix' | '/parent-200/child-20[@common-leaf-name-int=5]' } @Sql([CLEAR_DATA, SET_DATA]) @@ -125,13 +86,13 @@ class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase { then: 'the correct number of data nodes are retrieved' result.size() == expectedXPaths.size() and: 'xpaths of the retrieved data nodes are as expected' - for(int i = 0; i<result.size(); i++) { + for (int i = 0; i < result.size(); i++) { assert result[i].getXpath() == expectedXPaths[i] } where: 'the following data is used' scenario | cpsPath || expectedXPaths 'fully unique descendant name' | '//grand-child-202' || ['/parent-200/child-202/grand-child-202'] - 'descendant name match end of other node' | '//child-202' || ['/parent-200/child-202','/parent-201/child-202'] + 'descendant name match end of other node' | '//child-202' || ['/parent-200/child-202', '/parent-201/child-202'] } @Sql([CLEAR_DATA, SET_DATA]) @@ -141,7 +102,7 @@ class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase { then: 'the correct number of data nodes are retrieved' result.size() == expectedXPaths.size() and: 'xpaths of the retrieved data nodes are as expected' - for(int i = 0; i<result.size(); i++) { + for (int i = 0; i < result.size(); i++) { assert result[i].getXpath() == expectedXPaths[i] } where: 'the following data is used' @@ -180,4 +141,24 @@ class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase { 'one of the leaf without value' | '//child-202[@common-leaf-name-int=5 and @another-attribute"]' 'more than one leaf separated by or' | '//child-202[@common-leaf-name-int=5 or @common-leaf-name="common-leaf value"]' } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Query for attribute by cps path of type ancestor with #scenario.'() { + when: 'the given cps path is parsed' + def result = objectUnderTest.queryDataNodes(DATASPACE_NAME, ANCHOR_NAME1, cpsPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) + then: 'the xpaths of the retrieved data nodes are as expected' + result.size() == expectedXPaths.size() + for (int i = 0; i < result.size(); i++) { + assert result[i].getXpath() == expectedXPaths[i] + } + where: 'the following data is used' + scenario | cpsPath || expectedXPaths + 'multiple list-ancestors' | '//books/ancestor::categories' || ['/bookstore/books/categories[@name="SciFi"]', '/bookstore/magazines/categories[@name="kids"]'] + 'one ancestor value' | '//books/ancestor::books' || ['/bookstore/books'] + 'top ancestor' | '//books/ancestor::bookstore' || ['/bookstore'] + 'list with index value in the xpath prefix' | '//categories[@name="kids"]/books/ancestor::bookstore' || ['/bookstore'] + 'ancestor with parent' | '//books/ancestor::/bookstore/magazines' || ['/bookstore/magazines'] + 'ancestor with parent that does not exist' | '//books/ancestor::/parentDoesNoExist/magazines' || [] + 'ancestor does not exist' | '//books/ancestor::ancestorDoesNotExist' || [] + } } diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy index afd2cd1423..f632e022f0 100755 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy @@ -202,27 +202,6 @@ class CpsDataPersistenceServiceSpec extends CpsPersistenceSpecBase { 'empty xpath' |'' } - def static assertLeavesMaps(actualLeavesMap, expectedLeavesMap) { - expectedLeavesMap.forEach((key, value) -> { - def actualValue = actualLeavesMap[key] - if (value instanceof Collection<?> && actualValue instanceof Collection<?>) { - assert value.size() == actualValue.size() - assert value.containsAll(actualValue) - } else { - assert value == actualValue - } - } - ) - return true - } - - def static treeToFlatMapByXpath(Map<String, DataNode> flatMap, DataNode dataNodeTree) { - flatMap.put(dataNodeTree.getXpath(), dataNodeTree) - dataNodeTree.getChildDataNodes() - .forEach(childDataNode -> treeToFlatMapByXpath(flatMap, childDataNode)) - return flatMap - } - @Sql([CLEAR_DATA, SET_DATA]) def 'Get data node error scenario: #scenario.'() { when: 'attempt to get data node with #scenario' @@ -327,4 +306,25 @@ class CpsDataPersistenceServiceSpec extends CpsPersistenceSpecBase { static Map<String, Object> getLeavesMap(FragmentEntity fragmentEntity) { return GSON.fromJson(fragmentEntity.getAttributes(), Map<String, Object>.class) } + + def static assertLeavesMaps(actualLeavesMap, expectedLeavesMap) { + expectedLeavesMap.forEach((key, value) -> { + def actualValue = actualLeavesMap[key] + if (value instanceof Collection<?> && actualValue instanceof Collection<?>) { + assert value.size() == actualValue.size() + assert value.containsAll(actualValue) + } else { + assert value == actualValue + } + }) + return true + } + + def static treeToFlatMapByXpath(Map<String, DataNode> flatMap, DataNode dataNodeTree) { + flatMap.put(dataNodeTree.getXpath(), dataNodeTree) + dataNodeTree.getChildDataNodes() + .forEach(childDataNode -> treeToFlatMapByXpath(flatMap, childDataNode)) + return flatMap + } + } diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/query/CpsPathQuerySpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/query/CpsPathQuerySpec.groovy index bd0fb44feb..ee641d1029 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/query/CpsPathQuerySpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/query/CpsPathQuerySpec.groovy @@ -38,10 +38,10 @@ class CpsPathQuerySpec extends Specification { result.leafValue == expectedLeafValue where: 'the following data is used' scenario | cpsPath || expectedXpathPrefix | expectedLeafName | expectedLeafValue - 'leaf of type String' | '/parent/child[@common-leaf-name=\'common-leaf-value\']' || '/parent/child' |'common-leaf-name' | 'common-leaf-value' - 'leaf of type Integer' | '/parent/child[@common-leaf-name-int=5]' || '/parent/child' |'common-leaf-name-int' | 5 - 'spaces around =' | '/parent/child[@common-leaf-name-int = 5]' || '/parent/child' |'common-leaf-name-int' | 5 - 'key in top container' | '/parent[@common-leaf-name-int=5]' || '/parent' |'common-leaf-name-int' | 5 + 'leaf of type String' | '/parent/child[@common-leaf-name=\'common-leaf-value\']' || '/parent/child' | 'common-leaf-name' | 'common-leaf-value' + 'leaf of type Integer' | '/parent/child[@common-leaf-name-int=5]' || '/parent/child' | 'common-leaf-name-int' | 5 + 'spaces around =' | '/parent/child[@common-leaf-name-int = 5]' || '/parent/child' | 'common-leaf-name-int' | 5 + 'key in top container' | '/parent[@common-leaf-name-int=5]' || '/parent' | 'common-leaf-name-int' | 5 } def 'Parse cps path of type ends with a #scenario.'() { @@ -52,9 +52,9 @@ class CpsPathQuerySpec extends Specification { and: 'the right ends with parameters are set' result.descendantName == expectedEndsWithValue where: 'the following data is used' - scenario | cpsPath || expectedEndsWithValue - 'yang container' | '//cps-path' || 'cps-path' - 'parent & child' | '//parent/child' || 'parent/child' + scenario | cpsPath || expectedEndsWithValue + 'yang container' | '//cps-path' || 'cps-path' + 'parent & child' | '//parent/child' || 'parent/child' } def 'Parse cps path that ends with a yang list containing #scenario.'() { @@ -67,8 +67,8 @@ class CpsPathQuerySpec extends Specification { result.leavesData.size() == expectedNumberOfLeaves where: 'the following data is used' scenario | cpsPath || expectedNumberOfLeaves - 'one attribute' | '//child[@common-leaf-name-int=5]' || 1 - 'more than one attribute' | '//child[@int-leaf=5 and @leaf-name="leaf value"]' || 2 + 'one attribute' | '//child[@common-leaf-name-int=5]' || 1 + 'more than one attribute' | '//child[@int-leaf=5 and @leaf-name="leaf value"]' || 2 } def 'Parse cps path with #scenario.'() { @@ -86,6 +86,7 @@ class CpsPathQuerySpec extends Specification { 'too many containers' | '/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/41/42/43/44/45/46/47/48/49/50/51/52/53/54/55/56/57/58/59/60/61/62/63/64/65/66/67/68/69/70/71/72/73/74/75/76/77/78/79/80/81/82/83/84/85/86/87/88/89/90/91/92/93/94/95/96/97/98/99/100[@a=1]' 'end with descendant and more than one attribute separated by "or"' | '//child[@int-leaf=5 or @leaf-name="leaf value"]' 'missing attribute value' | '//child[@int-leaf=5 and @name]' + 'incomplete ancestor value' | '//books/ancestor::' } def 'Convert cps leaf value to valid type with leaf of type #scenario.'() { @@ -94,12 +95,22 @@ class CpsPathQuerySpec extends Specification { then: 'the leaf value returned is of the right type' result == expectedLeafOutputValue where: "the following data is used" - scenario | leafValueInputString || expectedLeafOutputValue - 'Integer' | "5" || 5 + scenario | leafValueInputString || expectedLeafOutputValue + 'Integer' | "5" || 5 'String with single quotes' | '\'value in single quotes\'' || 'value in single quotes' 'String with double quotes' | '"value in double quotes"' || 'value in double quotes' 'String containing single quote' | '"value with \'"' || 'value with \'' 'String containing double quote' | '\'value with "\'' || 'value with "' } - -}
\ No newline at end of file + + def 'Parse cps path using ancestor by schema node identifier.'() { + when: 'the given cps path is parsed' + def result = objectUnderTest.createFrom('//someXpath/ancestor::someAncestor') + then: 'the query has the right type' + result.cpsPathQueryType == CpsPathQueryType.XPATH_HAS_DESCENDANT_ANYWHERE + and: 'the correct ancestor schema node identifier is set' + result.ancestorSchemaNodeIdentifier == 'someAncestor' + and: 'the result has ancestor axis' + result.hasAncestorAxis() + } +} diff --git a/cps-ri/src/test/resources/data/fragment.sql b/cps-ri/src/test/resources/data/fragment.sql index 3e2ae8157e..95cb3c79ad 100755 --- a/cps-ri/src/test/resources/data/fragment.sql +++ b/cps-ri/src/test/resources/data/fragment.sql @@ -31,4 +31,13 @@ INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) (4206, 1001, 3003, null, '/parent-201', '{"leaf-value": "original"}'), (4207, 1001, 3003, 4206, '/parent-201/child-202', '{"common-leaf-name": "common-leaf other value", "common-leaf-name-int" : 5}'), (4208, 1001, 3003, 4206, '/parent-201/child-203[@key1="A" and @key2=1]', '{"key1": "A", "key2" : 1, "other-leaf" : "leaf value"}'), - (4209, 1001, 3003, 4206, '/parent-201/child-203[@key1="A" and @key2=2]', '{"key1": "A", "key2" : 2, "other-leaf" : "other value"}');
\ No newline at end of file + (4209, 1001, 3003, 4206, '/parent-201/child-203[@key1="A" and @key2=2]', '{"key1": "A", "key2" : 2, "other-leaf" : "other value"}'); + +INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH) VALUES + (1, 1001, 3001, null, '/bookstore'), + (2, 1001, 3001, 1, '/bookstore/books'), + (3, 1001, 3001, 1, '/bookstore/magazines'), + (4, 1001, 3001, 2, '/bookstore/books/categories[@name="SciFi"]'), + (5, 1001, 3001, 3, '/bookstore/magazines/categories[@name="kids"]'), + (6, 1001, 3001, 4, '/bookstore/books/categories[@name="SciFi"]/books'), + (7, 1001, 3001, 6, '/bookstore/magazines/categories[@name="kids"]/books'); |