diff options
author | rajesh.kumar <rk00747546@techmahindra.com> | 2023-04-25 11:58:35 +0530 |
---|---|---|
committer | rajesh.kumar <rk00747546@techmahindra.com> | 2023-08-02 18:15:16 +0530 |
commit | f248b5d9b794d5bdff59145406e0398d6fdcafa4 (patch) | |
tree | f99670f0911b4c6e5f13ec5590fe15eb205f0dc3 /integration-test/src | |
parent | 7fcffe5ae6753bfb6746d18d41ec536092603a76 (diff) |
Support pagination in query across all anchors(ep4)
Add pagination query parameters in query across all anchors API
pagination parameters (pageIndex and pageSize) are optional
default is to query all fragments
each pageSize represents number of records(number of anchors)
TotalRecords is returned in response header to find number of pages.
- If pagination option is provided in request then query number of
anchors equal to pageSize. pageIndex is used for setting offset.
- return number of records(one anchor per record) as per pagesize
and pageSize
Issue-ID: CPS-1605
Change-ID: I73f97f986a817d423f93a8d922dcd9647b2504bc
Signed-off-by: rajesh.kumar <rk00747546@techmahindra.com>
Diffstat (limited to 'integration-test/src')
4 files changed, 70 insertions, 24 deletions
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy index a1e03529c3..4780e36428 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy @@ -117,7 +117,7 @@ class CpsIntegrationSpecBase extends Specification { def addAnchorsWithData(numberOfAnchors, dataspaceName, schemaSetName, anchorNamePrefix, data) { (1..numberOfAnchors).each { cpsAdminService.createAnchor(dataspaceName, schemaSetName, anchorNamePrefix + it) - cpsDataService.saveData(dataspaceName, anchorNamePrefix + it, data, OffsetDateTime.now()) + cpsDataService.saveData(dataspaceName, anchorNamePrefix + it, data.replace("Easons", "Easons-"+it.toString()), OffsetDateTime.now()) } } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/FunctionalSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/FunctionalSpecBase.groovy index 89a5e4074b..327a39ee4f 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/base/FunctionalSpecBase.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/FunctionalSpecBase.groovy @@ -58,7 +58,7 @@ class FunctionalSpecBase extends CpsIntegrationSpecBase { def anchorName = 'bookstoreAnchor' + anchorNumber cpsAdminService.deleteAnchor(FUNCTIONAL_TEST_DATASPACE_1, anchorName) cpsAdminService.createAnchor(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_SCHEMA_SET, anchorName) - cpsDataService.saveData(FUNCTIONAL_TEST_DATASPACE_1, anchorName, bookstoreJsonData, OffsetDateTime.now()) + cpsDataService.saveData(FUNCTIONAL_TEST_DATASPACE_1, anchorName, bookstoreJsonData.replace("Easons", "Easons-"+anchorNumber.toString()), OffsetDateTime.now()) } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy index a3f14397c2..ebaf9093cb 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy @@ -58,7 +58,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase { then: 'the tree consist ouf of #expectNumberOfDataNodes data nodes' assert countDataNodesInTree(result) == expectNumberOfDataNodes and: 'the top level data node has the expected attribute and value' - assert result.leaves['bookstore-name'] == ['Easons'] + assert result.leaves['bookstore-name'] == ['Easons-1'] and: 'they are from the correct dataspace' assert result.dataspace == [FUNCTIONAL_TEST_DATASPACE_1] and: 'they are from the correct anchor' @@ -74,9 +74,9 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase { def 'Read bookstore top-level container(s) using "root" path variations.'() { when: 'get data nodes for bookstore container' def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, root, OMIT_DESCENDANTS) - then: 'the tree consist ouf of one data node' + then: 'the tree consist correct number of data nodes' assert countDataNodesInTree(result) == 2 - and: 'the top level data node has the expected attribute and value' + and: 'the top level data node has the expected number of leaves' assert result.leaves.size() == 2 where: 'the following variations of "root" are used' root << [ '/', '' ] @@ -324,20 +324,6 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase { 'new code, new child' | 'new' | ', "books" : [ { "title": "New Book" } ]' || 2 } - def 'Update multiple data node leaves.'() { - given: 'Updated json for bookstore data' - def jsonData = "{'book-store:books':{'lang':'English/French','price':100,'title':'Matilda'}}" - when: 'update is performed for leaves' - objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code='1']", jsonData, now) - then: 'the updated data nodes are retrieved' - def result = cpsDataService.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code=1]/books[@title='Matilda']", INCLUDE_ALL_DESCENDANTS) - and: 'the leaf values are updated as expected' - assert result.leaves['lang'] == ['English/French'] - assert result.leaves['price'] == [100] - cleanup: - restoreBookstoreDataAnchor(2) - } - def 'Update data node leaves for node that has no leaves (yet).'() { given: 'new (webinfo) datanode without leaves' def json = '{"webinfo": {} }' @@ -382,6 +368,20 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase { restoreBookstoreDataAnchor(1) } + def 'Update multiple data node leaves.'() { + given: 'Updated json for bookstore data' + def jsonData = "{'book-store:books':{'lang':'English/French','price':100,'title':'Matilda'}}" + when: 'update is performed for leaves' + objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code='1']", jsonData, now) + then: 'the updated data nodes are retrieved' + def result = cpsDataService.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code=1]/books[@title='Matilda']", INCLUDE_ALL_DESCENDANTS) + and: 'the leaf values are updated as expected' + assert result.leaves['lang'] == ['English/French'] + assert result.leaves['price'] == [100] + cleanup: + restoreBookstoreDataAnchor(2) + } + def countDataNodesInBookstore() { return countDataNodesInTree(objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', INCLUDE_ALL_DESCENDANTS)) } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy index 74496d3016..146ea95e8b 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy @@ -25,11 +25,13 @@ import java.time.OffsetDateTime import org.onap.cps.api.CpsQueryService import org.onap.cps.integration.base.FunctionalSpecBase import org.onap.cps.spi.FetchDescendantsOption +import org.onap.cps.spi.PaginationOption import org.onap.cps.spi.exceptions.CpsPathException import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS +import static org.onap.cps.spi.PaginationOption.NO_PAGINATION class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { @@ -249,7 +251,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Cps Path query across anchors with #scenario.'() { when: 'a query is executed to get a data nodes across anchors by the given CpsPath' - def result = objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, cpsPath, OMIT_DESCENDANTS) + def result = objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, cpsPath, OMIT_DESCENDANTS, NO_PAGINATION) then: 'the correct dataspace is queried' assert result.dataspace.toSet() == [FUNCTIONAL_TEST_DATASPACE_1].toSet() and: 'correct anchors are queried' @@ -262,7 +264,6 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { scenario | cpsPath || expectedXpathsPerAnchor 'container node' | '/bookstore' || ["/bookstore"] 'list node' | '/bookstore/categories' || ["/bookstore/categories[@code='1']", "/bookstore/categories[@code='2']", "/bookstore/categories[@code='3']", "/bookstore/categories[@code='4']", "/bookstore/categories[@code='5']"] - 'string leaf-condition' | '/bookstore[@bookstore-name="Easons"]' || ["/bookstore"] 'integer leaf-condition' | '/bookstore/categories[@code="1"]/books[@price=15]' || ["/bookstore/categories[@code='1']/books[@title='The Gruffalo']"] 'multiple list-ancestors' | '//books/ancestor::categories' || ["/bookstore/categories[@code='1']", "/bookstore/categories[@code='2']", "/bookstore/categories[@code='3']", "/bookstore/categories[@code='4']", "/bookstore/categories[@code='5']"] 'one ancestor with list value' | '//books/ancestor::categories[@code="1"]' || ["/bookstore/categories[@code='1']"] @@ -274,7 +275,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Cps Path query across anchors with #scenario descendants.'() { when: 'a query is executed to get a data node by the given cps path' - def result = objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, '/bookstore', fetchDescendantsOption) + def result = objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, '/bookstore', fetchDescendantsOption, NO_PAGINATION) then: 'the correct dataspace was queried' assert result.dataspace.toSet() == [FUNCTIONAL_TEST_DATASPACE_1].toSet() and: 'correct number of datanodes are returned' @@ -288,7 +289,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Cps Path query across anchors with ancestors and #scenario descendants.'() { when: 'a query is executed to get a data node by the given cps path' - def result = objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, '//books/ancestor::bookstore', fetchDescendantsOption) + def result = objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, '//books/ancestor::bookstore', fetchDescendantsOption, NO_PAGINATION) then: 'the correct dataspace was queried' assert result.dataspace.toSet() == [FUNCTIONAL_TEST_DATASPACE_1].toSet() and: 'correct number of datanodes are returned' @@ -302,7 +303,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Cps Path query across anchors with syntax error throws a CPS Path Exception.'() { when: 'trying to execute a query with a syntax (parsing) error' - objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, 'cpsPath that cannot be parsed' , OMIT_DESCENDANTS) + objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, 'cpsPath that cannot be parsed' , OMIT_DESCENDANTS, NO_PAGINATION) then: 'a cps path exception is thrown' thrown(CpsPathException) } @@ -375,4 +376,49 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { 'text-condition' || "/bookstore/categories[@code='1']/books/title[text()='I''m escaping']" 'contains-condition' || "/bookstore/categories[@code='1']/books[contains(@title, 'I''m escaping')]" } + + def 'Cps Path query across anchors using pagination option with #scenario.'() { + when: 'a query is executed to get a data nodes across anchors by the given CpsPath and pagination option' + def result = objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, '/bookstore', OMIT_DESCENDANTS, new PaginationOption(pageIndex, pageSize)) + then: 'correct bookstore names are queried' + def bookstoreNames = result.collect { it.getLeaves().get('bookstore-name') } + assert bookstoreNames.toList() == expectedBookstoreNames + and: 'the correct number of page size is returned' + assert result.size() == expectedPageSize + and: 'the queried nodes have expected anchor names' + assert result.anchorName.toSet() == expectedAnchors.toSet() + where: 'the following data is used' + scenario | pageIndex | pageSize || expectedPageSize || expectedAnchors || expectedBookstoreNames + '1st page with one anchor' | 1 | 1 || 1 || [BOOKSTORE_ANCHOR_1] || ['Easons-1'] + '1st page with two anchor' | 1 | 2 || 2 || [BOOKSTORE_ANCHOR_1, BOOKSTORE_ANCHOR_2] || ['Easons-1', 'Easons-2'] + '2nd page' | 2 | 1 || 1 || [BOOKSTORE_ANCHOR_2] || ['Easons-2'] + 'no 2nd page due to page size' | 2 | 2 || 0 || [] || [] + } + + def 'Cps Path query across anchors using pagination option for ancestor axis.'() { + when: 'a query is executed to get a data nodes across anchors by the given CpsPath and pagination option' + def result = objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, '//books/ancestor::categories', INCLUDE_ALL_DESCENDANTS, new PaginationOption(1, 2)) + then: 'correct category codes are queried' + def categoryNames = result.collect { it.getLeaves().get('name') } + assert categoryNames.toSet() == ['Discount books', 'Computing', 'Comedy', 'Thriller', 'Children'].toSet() + and: 'the queried nodes have expected anchors' + assert result.anchorName.toSet() == [BOOKSTORE_ANCHOR_1, BOOKSTORE_ANCHOR_2].toSet() + } + + def 'Count number of anchors for given dataspace name and cps path'() { + expect: '/bookstore is present in two anchors' + assert objectUnderTest.countAnchorsForDataspaceAndCpsPath(FUNCTIONAL_TEST_DATASPACE_1, '/bookstore') == 2 + } + + def 'Cps Path query across anchors using no pagination'() { + when: 'a query is executed to get a data nodes across anchors by the given CpsPath and pagination option' + def result = objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, '/bookstore', OMIT_DESCENDANTS, NO_PAGINATION) + then: 'all bookstore names are queried' + def bookstoreNames = result.collect { it.getLeaves().get('bookstore-name') } + assert bookstoreNames.toSet() == ['Easons-1', 'Easons-2'].toSet() + and: 'the correct number of page size is returned' + assert result.size() == 2 + and: 'the queried nodes have expected bookstore names' + assert result.anchorName.toSet() == [BOOKSTORE_ANCHOR_1, BOOKSTORE_ANCHOR_2].toSet() + } } |