diff options
9 files changed, 112 insertions, 223 deletions
diff --git a/cps-ri/pom.xml b/cps-ri/pom.xml index 6ee2d21833..e9b2abb3f3 100644 --- a/cps-ri/pom.xml +++ b/cps-ri/pom.xml @@ -33,7 +33,7 @@ <artifactId>cps-ri</artifactId>
<properties>
- <minimum-coverage>0.94</minimum-coverage>
+ <minimum-coverage>0.82</minimum-coverage>
</properties>
<dependencies>
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 deleted file mode 100644 index f025206c3f..0000000000 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy +++ /dev/null @@ -1,69 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation - * Modifications Copyright (C) 2021 Pantheon.tech - * Modifications Copyright (C) 2021 Bell Canada. - * Modifications Copyright (C) 2023 TechMahindra Ltd. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ -package org.onap.cps.spi.impl - -import org.onap.cps.spi.CpsDataPersistenceService -import org.onap.cps.spi.exceptions.CpsPathException -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.test.context.jdbc.Sql - -import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS -import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS - -class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase { - - @Autowired - CpsDataPersistenceService objectUnderTest - - static final String SET_DATA = '/data/cps-path-query.sql' - - @Sql([CLEAR_DATA, SET_DATA]) - def 'Cps Path query across anchors for leaf value(s) with : #scenario.'() { - when: 'a query is executed to get a data node by the given cps path' - def result = objectUnderTest.queryDataNodesAcrossAnchors(DATASPACE_NAME, cpsPath, includeDescendantsOption) - then: 'the correct number of queried nodes are returned' - assert result.size() == expectedNumberOfQueriedNodes - and : 'correct anchors are queried' - assert result.anchorName.containsAll(expectedAnchors) - where: 'the following data is used' - scenario | cpsPath | includeDescendantsOption || expectedNumberOfQueriedNodes || expectedAnchors - 'String and no descendants' | '/shops/shop[@id=1]/categories[@code=1]/book[@title="Dune"]' | OMIT_DESCENDANTS || 2 || ['ANCHOR-004', 'ANCHOR-005'] - 'Integer and descendants' | '/shops/shop[@id=1]/categories[@code=1]/book[@price=5]' | INCLUDE_ALL_DESCENDANTS || 3 || ['ANCHOR-004', 'ANCHOR-005'] - 'No condition no descendants' | '/shops/shop[@id=1]/categories' | OMIT_DESCENDANTS || 6 || ['ANCHOR-004', 'ANCHOR-005'] - 'multiple list-ancestors' | '//book/ancestor::categories' | INCLUDE_ALL_DESCENDANTS || 4 || ['ANCHOR-004', 'ANCHOR-005'] - 'one ancestor with list value' | '//book/ancestor::categories[@code=1]' | INCLUDE_ALL_DESCENDANTS || 2 || ['ANCHOR-004', 'ANCHOR-005'] - 'list with index value in the xpath prefix' | '//categories[@code=1]/book/ancestor::shop[@id=1]' | INCLUDE_ALL_DESCENDANTS || 2 || ['ANCHOR-004', 'ANCHOR-005'] - 'ancestor with parent list' | '//book/ancestor::shop[@id=1]/categories[@code=2]' | INCLUDE_ALL_DESCENDANTS || 2 || ['ANCHOR-004', 'ANCHOR-005'] - 'ancestor with parent' | '//phonenumbers[@type="mob"]/ancestor::info/contact' | INCLUDE_ALL_DESCENDANTS || 5 || ['ANCHOR-004', 'ANCHOR-005'] - 'ancestor combined with text condition' | '//book/title[text()="Dune"]/ancestor::shop' | INCLUDE_ALL_DESCENDANTS || 10 || ['ANCHOR-004', 'ANCHOR-005'] - 'ancestor with parent that does not exist' | '//book/ancestor::parentDoesNoExist/categories' | INCLUDE_ALL_DESCENDANTS || 0 || [] - 'ancestor does not exist' | '//book/ancestor::ancestorDoesNotExist' | INCLUDE_ALL_DESCENDANTS || 0 || [] - } - - 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(DATASPACE_NAME, 'cpsPath that cannot be parsed' , OMIT_DESCENDANTS) - then: 'a cps path exception is thrown' - thrown(CpsPathException) - } -} diff --git a/cps-ri/src/test/resources/data/cps-path-query.sql b/cps-ri/src/test/resources/data/cps-path-query.sql deleted file mode 100644 index 5fe927bc09..0000000000 --- a/cps-ri/src/test/resources/data/cps-path-query.sql +++ /dev/null @@ -1,109 +0,0 @@ -/* - ============LICENSE_START======================================================= - Copyright (C) 2021-2022 Nordix Foundation. - Modifications Copyright (C) 2021 Bell Canada. - Modifications Copyright (C) 2023 TechMahindra Ltd. - ================================================================================ - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - SPDX-License-Identifier: Apache-2.0 - ============LICENSE_END========================================================= -*/ - -INSERT INTO DATASPACE (ID, NAME) VALUES - (1001, 'DATASPACE-001'); - -INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES - (2001, 'SCHEMA-SET-001', 1001); - -INSERT INTO YANG_RESOURCE (ID, FILE_NAME, CONTENT, CHECKSUM, MODULE_NAME, REVISION) VALUES - (4001, 'TEST','', 'SAMPLECHECKSUM','TESTMODULENAME', 'SAMPLEREVISION'); - -UPDATE YANG_RESOURCE SET -content = 'module stores { - yang-version 1.1; - namespace "org:onap:ccsdk:sample"; - - prefix book-store; - - revision "2020-09-15" { - description - "Sample Model"; - } - } -' -where ID = 4001; - - -INSERT INTO SCHEMA_SET_YANG_RESOURCES (SCHEMA_SET_ID, YANG_RESOURCE_ID) VALUES - (2001, 4001); - -INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES - (1003, 'ANCHOR-004', 1001, 2001); - -INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES - (1004, 'ANCHOR-005', 1001, 2001); - -INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES - (1, 1001, 1003, null, '/shops', null), - (2, 1001, 1003, 1, '/shops/shop[@id=''1'']', '{"id" : 1, "type" : "bookstore"}'), - (3, 1001, 1003, 2, '/shops/shop[@id=''1'']/categories[@code=''1'']', '{"code" : 1, "type" : "bookstore", "name": "SciFi"}'), - (4, 1001, 1003, 2, '/shops/shop[@id=''1'']/categories[@code=''2'']', '{"code" : 2, "type" : "bookstore", "name": "Fiction"}'), - (31, 1001, 1003, 2, '/shops/shop[@id=''1'']/categories[@code=''string/with/slash/'']', '{"code" : "string/with/slash", "type" : "text/with/slash", "name": "Fiction"}'), - (5, 1001, 1003, 3, '/shops/shop[@id=''1'']/categories[@code=''1'']/book', '{"price" : 5, "title" : "Dune", "labels" : ["special offer","classics",""]}'), - (6, 1001, 1003, 4, '/shops/shop[@id=''1'']/categories[@code=''2'']/book', '{"price" : 15, "title" : "Chapters", "editions" : [2000,2010,2020]}'), - (7, 1001, 1003, 5, '/shops/shop[@id=''1'']/categories[@code=''1'']/book/author[@FirstName=''Joe'' and @Surname=''Bloggs'']', '{"FirstName" : "Joe", "Surname": "Bloggs","title": "Dune"}'), - (8, 1001, 1003, 6, '/shops/shop[@id=''1'']/categories[@code=''2'']/book/author[@FirstName=''Joe'' and @Surname=''Smith'']', '{"FirstName" : "Joe", "Surname": "Smith","title": "Chapters"}'), - (32, 1001, 1003, 6, '/shops/shop[@id=''1'']/categories[@code=''2'']/book/author[@FirstName=''Joe'' and @Address=''string[with]square[brackets]'']', '{"FirstName" : "Joe", "Address": "string[with]square[brackets]","title": "Chapters"}'); - - INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES - (9, 1001, 1003, 1, '/shops/shop[@id=''2'']', '{"type" : "bookstore"}'), - (10, 1001, 1003, 9, '/shops/shop[@id=''2'']/categories[@code=''1'']', '{"code" : 2, "type" : "bookstore", "name": "Kids"}'), - (11, 1001, 1003, 10, '/shops/shop[@id=''2'']/categories[@code=''2'']', '{"code" : 2, "type" : "bookstore", "name": "Fiction"}'); - - INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES - (12, 1001, 1003, 1, '/shops/shop[@id=''3'']', '{"type" : "garden centre"}'), - (13, 1001, 1003, 12, '/shops/shop[@id=''3'']/categories[@code=''1'']', '{"id" : 1, "type" : "garden centre", "name": "indoor plants"}'), - (14, 1001, 1003, 12, '/shops/shop[@id=''3'']/categories[@code=''2'']', '{"id" : 2, "type" : "garden centre", "name": "outdoor plants"}'), - (16, 1001, 1003, 1, '/shops/shop[@id=''3'']/info', null), - (17, 1001, 1003, 1, '/shops/shop[@id=''3'']/info/contact', null), - (18, 1001, 1003, 17, '/shops/shop[@id=''3'']/info/contact/website', '{"address" : "myshop.ie"}'), - (19, 1001, 1003, 17, '/shops/shop[@id=''3'']/info/contact/phonenumbers[@type=''mob'']', '{"type" : "mob", "number" : "123123456"}'), - (20, 1001, 1003, 17, '/shops/shop[@id=''3'']/info/contact/phonenumbers[@type=''landline'']', '{"type" : "landline", "number" : "012123456"}'); - - INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES - (41, 1001, 1004, null, '/shops', null), - (42, 1001, 1004, 1, '/shops/shop[@id=''1'']', '{"id" : 1, "type" : "bookstore"}'), - (43, 1001, 1004, 2, '/shops/shop[@id=''1'']/categories[@code=''1'']', '{"code" : 1, "type" : "bookstore", "name": "SciFi"}'), - (44, 1001, 1004, 2, '/shops/shop[@id=''1'']/categories[@code=''2'']', '{"code" : 2, "type" : "bookstore", "name": "Fiction"}'), - (71, 1001, 1004, 2, '/shops/shop[@id=''1'']/categories[@code=''string/with/slash/'']', '{"code" : "string/with/slash", "type" : "text/with/slash", "name": "Fiction"}'), - (45, 1001, 1004, 3, '/shops/shop[@id=''1'']/categories[@code=''1'']/book', '{"price" : 5, "title" : "Dune", "labels" : ["special offer","classics",""]}'), - (46, 1001, 1004, 4, '/shops/shop[@id=''1'']/categories[@code=''2'']/book', '{"price" : 15, "title" : "Chapters", "editions" : [2000,2010,2020]}'), - (47, 1001, 1004, 5, '/shops/shop[@id=''1'']/categories[@code=''1'']/book/author[@FirstName=''Joe'' and @Surname=''Bloggs'']', '{"FirstName" : "Joe", "Surname": "Bloggs","title": "Dune"}'), - (48, 1001, 1004, 6, '/shops/shop[@id=''1'']/categories[@code=''2'']/book/author[@FirstName=''Joe'' and @Surname=''Smith'']', '{"FirstName" : "Joe", "Surname": "Smith","title": "Chapters"}'), - (72, 1001, 1004, 6, '/shops/shop[@id=''1'']/categories[@code=''2'']/book/author[@FirstName=''Joe'' and @Address=''string[with]square[brackets]'']', '{"FirstName" : "Joe", "Address": "string[with]square[brackets]","title": "Chapters"}'); - - INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES - (49, 1001, 1004, 1, '/shops/shop[@id=''2'']', '{"type" : "bookstore"}'), - (50, 1001, 1004, 9, '/shops/shop[@id=''2'']/categories[@code=''1'']', '{"code" : 2, "type" : "bookstore", "name": "Kids"}'), - (51, 1001, 1004, 10, '/shops/shop[@id=''2'']/categories[@code=''2'']', '{"code" : 2, "type" : "bookstore", "name": "Fiction"}'); - - INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES - (52, 1001, 1004, 1, '/shops/shop[@id=''3'']', '{"type" : "garden centre"}'), - (53, 1001, 1004, 12, '/shops/shop[@id=''3'']/categories[@code=''1'']', '{"id" : 1, "type" : "garden centre", "name": "indoor plants"}'), - (54, 1001, 1004, 12, '/shops/shop[@id=''3'']/categories[@code=''2'']', '{"id" : 2, "type" : "garden centre", "name": "outdoor plants"}'), - (56, 1001, 1004, 1, '/shops/shop[@id=''3'']/info', null), - (57, 1001, 1004, 1, '/shops/shop[@id=''3'']/info/contact', null), - (58, 1001, 1004, 17, '/shops/shop[@id=''3'']/info/contact/website', '{"address" : "myshop.ie"}'), - (59, 1001, 1004, 17, '/shops/shop[@id=''3'']/info/contact/phonenumbers[@type=''mob'']', '{"type" : "mob", "number" : "123123456"}'), - (60, 1001, 1004, 17, '/shops/shop[@id=''3'']/info/contact/phonenumbers[@type=''landline'']', '{"type" : "landline", "number" : "012123456"}'); 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 866fef4f24..b942a43af2 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 @@ -40,6 +40,8 @@ import org.testcontainers.spock.Testcontainers import spock.lang.Shared import spock.lang.Specification +import java.time.OffsetDateTime + @SpringBootTest(classes = [TestConfig, CpsAdminServiceImpl, CpsValidatorImpl]) @Testcontainers @EnableAutoConfiguration @@ -68,9 +70,7 @@ class CpsIntegrationSpecBase extends Specification { CpsQueryService cpsQueryService def static GENERAL_TEST_DATASPACE = 'generalTestDataspace' - def static FUNCTIONAL_TEST_DATASPACE = 'functionalTestDataspace' def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet' - def static BOOKSTORE_ANCHOR = 'bookstoreAnchor' def static initialized = false @@ -107,4 +107,11 @@ class CpsIntegrationSpecBase extends Specification { } return true } + + def addAnchorsWithData(numberOfAnchors, dataspaceName, schemaSetName, anchorNamePrefix, data) { + (1..numberOfAnchors).each { + cpsAdminService.createAnchor(dataspaceName, schemaSetName, anchorNamePrefix + it) + cpsDataService.saveData(dataspaceName, anchorNamePrefix + it, data, 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 5e5269114e..b7a6030d80 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 @@ -20,10 +20,14 @@ package org.onap.cps.integration.base -import java.time.OffsetDateTime - class FunctionalSpecBase extends CpsIntegrationSpecBase { + def static FUNCTIONAL_TEST_DATASPACE_1 = 'functionalTestDataspace1' + def static FUNCTIONAL_TEST_DATASPACE_2 = 'functionalTestDataspace2' + def static NUMBER_OF_ANCHORS_PER_DATASPACE_WITH_BOOKSTORE_DATA = 2 + def static BOOKSTORE_ANCHOR_1 = 'bookstoreAnchor1' + def static BOOKSTORE_ANCHOR_2 = 'bookstoreAnchor2' + def static initialized = false def setup() { @@ -35,15 +39,17 @@ class FunctionalSpecBase extends CpsIntegrationSpecBase { } def setupBookstoreInfraStructure() { - cpsAdminService.createDataspace(FUNCTIONAL_TEST_DATASPACE) + cpsAdminService.createDataspace(FUNCTIONAL_TEST_DATASPACE_1) + cpsAdminService.createDataspace(FUNCTIONAL_TEST_DATASPACE_2) def bookstoreYangModelAsString = readResourceDataFile('bookstore/bookstore.yang') - cpsModuleService.createSchemaSet(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, [bookstore: bookstoreYangModelAsString]) - cpsAdminService.createAnchor(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, BOOKSTORE_ANCHOR) + cpsModuleService.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_SCHEMA_SET, [bookstore: bookstoreYangModelAsString]) + cpsModuleService.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_2, BOOKSTORE_SCHEMA_SET, [bookstore: bookstoreYangModelAsString]) } def addBookstoreData() { def bookstoreJsonData = readResourceDataFile('bookstore/bookstoreData.json') - cpsDataService.saveData(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, bookstoreJsonData, OffsetDateTime.now()) + addAnchorsWithData(NUMBER_OF_ANCHORS_PER_DATASPACE_WITH_BOOKSTORE_DATA, FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_SCHEMA_SET, 'bookstoreAnchor', bookstoreJsonData) + addAnchorsWithData(NUMBER_OF_ANCHORS_PER_DATASPACE_WITH_BOOKSTORE_DATA, FUNCTIONAL_TEST_DATASPACE_2, BOOKSTORE_SCHEMA_SET, 'bookstoreAnchor', bookstoreJsonData) } } 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 25e71f18d6..f609ba00e0 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 @@ -33,7 +33,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase { def 'Read bookstore top-level container(s) using #fetchDescendantsOption.'() { when: 'get data nodes for bookstore container' - def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, '/bookstore', fetchDescendantsOption) + def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', fetchDescendantsOption) 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' @@ -48,11 +48,11 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase { def 'Read bookstore top-level container(s) has correct dataspace and anchor.'() { when: 'get data nodes for bookstore container' - def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, '/bookstore', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) + def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) then: 'the correct dataspace was queried' - assert result.dataspace.toSet() == [FUNCTIONAL_TEST_DATASPACE].toSet() + assert result.dataspace.toSet() == [FUNCTIONAL_TEST_DATASPACE_1].toSet() and: 'the correct anchor was queried' - assert result.anchorName.toSet() == [BOOKSTORE_ANCHOR].toSet() + assert result.anchorName.toSet() == [BOOKSTORE_ANCHOR_1].toSet() } } 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 1a31cdde3a..47027e4636 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 @@ -24,6 +24,7 @@ import org.onap.cps.api.CpsQueryService import org.onap.cps.integration.base.FunctionalSpecBase import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.exceptions.CpsPathException +import spock.lang.Ignore import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS @@ -37,7 +38,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Query bookstore using CPS path where #scenario.'() { when: 'query data nodes for bookstore container' - def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, cpsPath, INCLUDE_ALL_DESCENDANTS) + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, INCLUDE_ALL_DESCENDANTS) then: 'the result contains expected number of nodes' assert result.size() == expectedResultSize and: 'the result contains the expected leaf values' @@ -54,7 +55,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Cps Path query for leaf value(s) with #scenario.'() { when: 'a query is executed to get a data node by the given cps path' - def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, cpsPath, fetchDescendantsOption) + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, fetchDescendantsOption) then: 'the correct number of parent nodes are returned' assert result.size() == expectedNumberOfParentNodes and: 'the correct total number of data nodes are returned' @@ -70,7 +71,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Query for attribute by cps path with cps paths that return no data because of #scenario.'() { when: 'a query is executed to get data nodes for the given cps path' - def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, cpsPath, OMIT_DESCENDANTS) + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, OMIT_DESCENDANTS) then: 'no data is returned' assert result.isEmpty() where: 'following cps queries are performed' @@ -82,7 +83,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Cps Path query using descendant anywhere and #type (further) descendants.'() { when: 'a query is executed to get a data node by the given cps path' - def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, '/bookstore/categories[@code="1"]', fetchDescendantsOption) + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="1"]', fetchDescendantsOption) then: 'the data node has the correct number of children' assert result[0].childDataNodes.xpath.sort() == expectedChildNodes.sort() where: 'the following data is used' @@ -94,14 +95,14 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Cps Path query for all books.'() { when: 'a query is executed to get all books' - def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, '//books', OMIT_DESCENDANTS) + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '//books', OMIT_DESCENDANTS) then: 'the expected number of books are returned' assert result.size() == 9 } def 'Cps Path query using descendant anywhere with #scenario.'() { when: 'a query is executed to get a data node by the given cps path' - def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, cpsPath, OMIT_DESCENDANTS) + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, OMIT_DESCENDANTS) then: 'xpaths of the retrieved data nodes are as expected' def bookTitles = result.collect { it.getLeaves().get('title') } assert bookTitles.sort() == expectedBookTitles.sort() @@ -123,7 +124,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Cps Path query using descendant anywhere with #scenario condition for a container element.'() { when: 'a query is executed to get a data node by the given cps path' - def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, cpsPath, OMIT_DESCENDANTS) + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, OMIT_DESCENDANTS) then: 'book titles from the retrieved data nodes are as expected' def bookTitles = result.collect { it.getLeaves().get('title') } assert bookTitles.sort() == expectedBookTitles.sort() @@ -138,7 +139,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Cps Path query using descendant anywhere with #scenario condition(s) for a list element.'() { when: 'a query is executed to get a data node by the given cps path' - def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, cpsPath, INCLUDE_ALL_DESCENDANTS) + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, INCLUDE_ALL_DESCENDANTS) then: 'xpaths of the retrieved data nodes are as expected' result.xpath.toList() == ["/bookstore/premises/addresses[@house-number='2' and @street='Main Street']"] where: 'the following data is used' @@ -151,7 +152,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Query for attribute by cps path of type ancestor with #scenario.'() { when: 'the given cps path is parsed' - def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, cpsPath, OMIT_DESCENDANTS) + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, OMIT_DESCENDANTS) then: 'the xpaths of the retrieved data nodes are as expected' assert result.xpath.sort() == expectedXPaths.sort() where: 'the following data is used' @@ -169,7 +170,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Query for attribute by cps path of type ancestor with #scenario descendants.'() { when: 'the given cps path is parsed' - def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, '//books/ancestor::bookstore', fetchDescendantsOption) + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '//books/ancestor::bookstore', fetchDescendantsOption) then: 'the xpaths of the retrieved data nodes are as expected' assert countDataNodesInTree(result) == expectedNumberOfNodes where: 'the following data is used' @@ -181,7 +182,70 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { def 'Cps Path query with syntax error throws a CPS Path Exception.'() { when: 'trying to execute a query with a syntax (parsing) error' - objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE, BOOKSTORE_ANCHOR, 'cpsPath that cannot be parsed' , OMIT_DESCENDANTS) + objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, 'cpsPath that cannot be parsed' , OMIT_DESCENDANTS) + then: 'a cps path exception is thrown' + thrown(CpsPathException) + } + + @Ignore + 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) + then: 'the correct dataspace is queried' + assert result.dataspace.toSet() == [FUNCTIONAL_TEST_DATASPACE_1].toSet() + and: 'correct anchors are queried' + assert result.anchorName.toSet() == [BOOKSTORE_ANCHOR_1, BOOKSTORE_ANCHOR_2].toSet() + and: 'the correct number of nodes is returned' + assert result.size() == expectedXpathsPerAnchor.size() * NUMBER_OF_ANCHORS_PER_DATASPACE_WITH_BOOKSTORE_DATA + and: 'the queried nodes have expected xpaths' + assert result.xpath.toSet() == expectedXpathsPerAnchor.toSet() + where: 'the following data is used' + 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']"] + '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']"] + 'one ancestor with list value' | '//books/ancestor::categories[@code="1"]' || ["/bookstore/categories[@code='1']"] + 'list with index value in the xpath prefix' | '//categories[@code="1"]/books/ancestor::bookstore' || ["/bookstore"] + 'ancestor with parent list' | '//books/ancestor::bookstore/categories' || ["/bookstore/categories[@code='1']", "/bookstore/categories[@code='2']", "/bookstore/categories[@code='3']", "/bookstore/categories[@code='4']"] + 'ancestor with parent list element' | '//books/ancestor::bookstore/categories[@code="2"]' || ["/bookstore/categories[@code='2']"] + 'ancestor combined with text condition' | '//books/title[text()="Matilda"]/ancestor::bookstore' || ["/bookstore"] + } + + @Ignore + 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) + then: 'the correct dataspace was queried' + assert result.dataspace.toSet() == [FUNCTIONAL_TEST_DATASPACE_1].toSet() + and: 'correct number of datanodes are returned' + assert countDataNodesInTree(result) == expectedNumberOfNodesPerAnchor * NUMBER_OF_ANCHORS_PER_DATASPACE_WITH_BOOKSTORE_DATA + where: 'the following data is used' + scenario | fetchDescendantsOption || expectedNumberOfNodesPerAnchor + 'no' | OMIT_DESCENDANTS || 1 + 'direct' | DIRECT_CHILDREN_ONLY || 6 + 'all' | INCLUDE_ALL_DESCENDANTS || 17 + } + + @Ignore + 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) + then: 'the correct dataspace was queried' + assert result.dataspace.toSet() == [FUNCTIONAL_TEST_DATASPACE_1].toSet() + and: 'correct number of datanodes are returned' + assert countDataNodesInTree(result) == expectedNumberOfNodesPerAnchor * NUMBER_OF_ANCHORS_PER_DATASPACE_WITH_BOOKSTORE_DATA + where: 'the following data is used' + scenario | fetchDescendantsOption || expectedNumberOfNodesPerAnchor + 'no' | OMIT_DESCENDANTS || 1 + 'direct' | DIRECT_CHILDREN_ONLY || 6 + 'all' | INCLUDE_ALL_DESCENDANTS || 17 + } + + 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) then: 'a cps path exception is thrown' thrown(CpsPathException) } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/CpsPerfTestBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/CpsPerfTestBase.groovy index 3b5f69c6e0..d339f6ddcf 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/CpsPerfTestBase.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/CpsPerfTestBase.groovy @@ -20,11 +20,8 @@ package org.onap.cps.integration.performance.base -import org.onap.cps.spi.FetchDescendantsOption - -import java.time.OffsetDateTime -import org.onap.cps.integration.base.CpsIntegrationSpecBase import org.onap.cps.rest.utils.MultipartFileUtil +import org.onap.cps.spi.FetchDescendantsOption import org.springframework.web.multipart.MultipartFile class CpsPerfTestBase extends PerfTestBase { @@ -41,8 +38,8 @@ class CpsPerfTestBase extends PerfTestBase { def setupPerformanceInfraStructure() { cpsAdminService.createDataspace(CPS_PERFORMANCE_TEST_DATASPACE) - def modelAsString = CpsIntegrationSpecBase.readResourceDataFile('bookstore/bookstore.yang') - cpsModuleService.createSchemaSet(CPS_PERFORMANCE_TEST_DATASPACE, CpsIntegrationSpecBase.BOOKSTORE_SCHEMA_SET, [bookstore: modelAsString]) + def modelAsString = readResourceDataFile('bookstore/bookstore.yang') + cpsModuleService.createSchemaSet(CPS_PERFORMANCE_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, [bookstore: modelAsString]) } def createInitialData() { @@ -55,16 +52,16 @@ class CpsPerfTestBase extends PerfTestBase { def createWarmupData() { def data = "{\"bookstore\":{}}" stopWatch.start() - addAnchorsWithData(1, CpsIntegrationSpecBase.BOOKSTORE_SCHEMA_SET, 'warmup', data) + addAnchorsWithData(1, CPS_PERFORMANCE_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, 'warmup', data) stopWatch.stop() def durationInMillis = stopWatch.getTotalTimeMillis() recordAndAssertPerformance('Creating warmup anchor with tiny data tree', 500, durationInMillis) } def createLargeBookstoresData() { - def data = CpsIntegrationSpecBase.readResourceDataFile('bookstore/largeModelData.json') + def data = readResourceDataFile('bookstore/largeModelData.json') stopWatch.start() - addAnchorsWithData(5, CpsIntegrationSpecBase.BOOKSTORE_SCHEMA_SET, 'bookstore', data) + addAnchorsWithData(5, CPS_PERFORMANCE_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, 'bookstore', data) stopWatch.stop() def durationInMillis = stopWatch.getTotalTimeMillis() recordAndAssertPerformance('Creating bookstore anchors with large data tree', 3_000, durationInMillis) @@ -75,32 +72,25 @@ class CpsPerfTestBase extends PerfTestBase { def multipartFile = Mock(MultipartFile) multipartFile.getOriginalFilename() >> file.getName() multipartFile.getInputStream() >> new FileInputStream(file) - cpsModuleService.createSchemaSet(CPS_PERFORMANCE_TEST_DATASPACE, PerfTestBase.LARGE_SCHEMA_SET, MultipartFileUtil.extractYangResourcesMap(multipartFile)) + cpsModuleService.createSchemaSet(CPS_PERFORMANCE_TEST_DATASPACE, LARGE_SCHEMA_SET, MultipartFileUtil.extractYangResourcesMap(multipartFile)) } def addOpenRoadData() { def data = generateOpenRoadData(50) stopWatch.start() - addAnchorsWithData(5, PerfTestBase.LARGE_SCHEMA_SET, 'openroadm', data) + addAnchorsWithData(5, CPS_PERFORMANCE_TEST_DATASPACE, LARGE_SCHEMA_SET, 'openroadm', data) stopWatch.stop() def durationInMillis = stopWatch.getTotalTimeMillis() recordAndAssertPerformance('Creating openroadm anchors with large data tree', 25_000, durationInMillis) } def generateOpenRoadData(numberOfNodes) { - def innerNode = CpsIntegrationSpecBase.readResourceDataFile('openroadm/innerNode.json') + def innerNode = readResourceDataFile('openroadm/innerNode.json') return '{ "openroadm-devices": { "openroadm-device": [' + (1..numberOfNodes).collect { innerNode.replace('NODE_ID_HERE', it.toString()) }.join(',') + ']}}' } - def addAnchorsWithData(numberOfAnchors, schemaSetName, anchorNamePrefix, data) { - (1..numberOfAnchors).each { - cpsAdminService.createAnchor(CPS_PERFORMANCE_TEST_DATASPACE, schemaSetName, anchorNamePrefix + it) - cpsDataService.saveData(CPS_PERFORMANCE_TEST_DATASPACE, anchorNamePrefix + it, data, OffsetDateTime.now()) - } - } - def 'Warm the database'() { when: 'get data nodes for warmup anchor' stopWatch.start() diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpRegistryPerfTestBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpRegistryPerfTestBase.groovy index adece2ebf5..d169bd7571 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpRegistryPerfTestBase.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpRegistryPerfTestBase.groovy @@ -40,12 +40,12 @@ class NcmpRegistryPerfTestBase extends PerfTestBase { def setupPerformanceInfraStructure() { cpsAdminService.createDataspace(NCMP_PERFORMANCE_TEST_DATASPACE) - def modelAsString = CpsIntegrationSpecBase.readResourceDataFile('ncmp-registry/dmi-registry@2022-05-10.yang') + def modelAsString = readResourceDataFile('ncmp-registry/dmi-registry@2022-05-10.yang') cpsModuleService.createSchemaSet(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_SCHEMA_SET, [registry: modelAsString]) } def createInitialData() { - def data = CpsIntegrationSpecBase.readResourceDataFile('ncmp-registry/1000-cmhandles.json') + def data = readResourceDataFile('ncmp-registry/1000-cmhandles.json') cpsAdminService.createAnchor(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_SCHEMA_SET, REGISTRY_ANCHOR) cpsDataService.saveData(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, data, OffsetDateTime.now()) } |