From 048350463a68b774f42e80e94afe16a541711ae4 Mon Sep 17 00:00:00 2001 From: ToineSiebelink Date: Thu, 23 Feb 2023 15:49:40 +0000 Subject: [PATCH] Expand CPS Service Integration Test (framework) - Created package structure - Created several test bases - Created complete test set for Admin service - Created first test for Data service - Added human-readable toString() to FetchDescendantsOption for test reporting and debuging purposes - Renamed fetch descendants (enum) direct children option for consistency with others options - TODO: Add sample performance test (and base) Issue-ID: CPS-475 Signed-off-by: ToineSiebelink Change-Id: I75317686161be41662b6bf81314a9cd425ddd6eb --- .../NetworkCmProxyCmHandlerQueryServiceImpl.java | 6 +- .../NetworkCmProxyCmHandlerQueryServiceSpec.groovy | 4 +- .../org/onap/cps/spi/FetchDescendantsOption.java | 22 ++++- .../cps/api/impl/CpsQueryServiceImplSpec.groovy | 4 +- .../onap/cps/spi/FetchDescendantsOptionSpec.groovy | 30 ++++-- .../onap/cps/integration/CpsPersistenceSpec.groovy | 62 ------------ .../cps/integration/base/BookstoreSpecBase.groovy | 49 +++++++++ .../{ => base}/CpsIntegrationSpecBase.groovy | 61 +++++------- .../cps/integration/{ => base}/TestConfig.groovy | 2 +- .../CpsAdminServiceIntegrationSpec.groovy | 109 +++++++++++++++++++++ .../CpsDataServiceIntegrationSpec.groovy | 48 +++++++++ 11 files changed, 275 insertions(+), 122 deletions(-) delete mode 100644 integration-test/src/test/groovy/org/onap/cps/integration/CpsPersistenceSpec.groovy create mode 100644 integration-test/src/test/groovy/org/onap/cps/integration/base/BookstoreSpecBase.groovy rename integration-test/src/test/groovy/org/onap/cps/integration/{ => base}/CpsIntegrationSpecBase.groovy (54%) rename integration-test/src/test/groovy/org/onap/cps/integration/{ => base}/TestConfig.groovy (99%) create mode 100644 integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy create mode 100644 integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java index a98c6008c..f6f042dc1 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,7 @@ package org.onap.cps.ncmp.api.impl; import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.validateCpsPathConditionProperties; import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.validateModuleNameConditionProperties; import static org.onap.cps.ncmp.api.impl.utils.YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle; -import static org.onap.cps.spi.FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY; +import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY; import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS; import java.util.ArrayList; @@ -304,7 +304,7 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm } private Set getAllCmHandleIds() { - final DataNode dataNodes = inventoryPersistence.getDataNode("/dmi-registry", FETCH_DIRECT_CHILDREN_ONLY) + final DataNode dataNodes = inventoryPersistence.getDataNode("/dmi-registry", DIRECT_CHILDREN_ONLY) .iterator().next(); return dataNodes.getChildDataNodes().stream().map(dataNode -> dataNode.getLeaves().get("id").toString()) .collect(Collectors.toSet()); diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy index 5cd702a6b..f2494e6fc 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -158,7 +158,7 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { given: 'We use an empty query' def cmHandleQueryParameters = new CmHandleQueryServiceParameters() and: 'the inventory persistence returns the dmi registry datanode with just ids' - mockInventoryPersistence.getDataNode("/dmi-registry", FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY) >> [dmiRegistry] + mockInventoryPersistence.getDataNode("/dmi-registry", FetchDescendantsOption.DIRECT_CHILDREN_ONLY) >> [dmiRegistry] and: 'the inventory persistence returns the dmi registry datanode with data' mockInventoryPersistence.getDataNode("/dmi-registry") >> [dmiRegistry] when: 'the query is executed for both cm handle ids and details' diff --git a/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java b/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java index 0c8cddcd7..cf5e04dc4 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java +++ b/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java @@ -1,7 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2021 Pantheon.tech - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,15 +30,24 @@ import org.onap.cps.spi.exceptions.DataValidationException; @RequiredArgsConstructor public class FetchDescendantsOption { - public static final FetchDescendantsOption FETCH_DIRECT_CHILDREN_ONLY = new FetchDescendantsOption(1); - public static final FetchDescendantsOption OMIT_DESCENDANTS = new FetchDescendantsOption(0); - public static final FetchDescendantsOption INCLUDE_ALL_DESCENDANTS = new FetchDescendantsOption(-1); + public static final FetchDescendantsOption DIRECT_CHILDREN_ONLY + = new FetchDescendantsOption(1, "DirectChildrenOnly"); + public static final FetchDescendantsOption OMIT_DESCENDANTS + = new FetchDescendantsOption(0, "OmitDescendants"); + public static final FetchDescendantsOption INCLUDE_ALL_DESCENDANTS + = new FetchDescendantsOption(-1, "IncludeAllDescendants"); + + FetchDescendantsOption(final int depth) { + this(depth, "Depth=" + depth); + } private static final Pattern FETCH_DESCENDANTS_OPTION_PATTERN = Pattern.compile("^$|^all$|^none$|^[0-9]+$|^-1$"); private final int depth; + private final String optionName; + /** * Has next depth. * @@ -85,6 +94,11 @@ public class FetchDescendantsOption { } } + @Override + public String toString() { + return optionName; + } + private static void validateFetchDescendantsOption(final String fetchDescendantsOptionAsString) { if (Strings.isNullOrEmpty(fetchDescendantsOptionAsString)) { return; diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy index 60286b664..56c43d163 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,7 +45,7 @@ class CpsQueryServiceImplSpec extends Specification { 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) where: 'all fetch descendants options are supported' fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS, - FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY, new FetchDescendantsOption(10)] + FetchDescendantsOption.DIRECT_CHILDREN_ONLY, new FetchDescendantsOption(10)] } } diff --git a/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy index c4d3dd8b7..24f3487d1 100644 --- a/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,15 +21,15 @@ package org.onap.cps.spi -import org.onap.cps.spi.exceptions.DataValidationException import spock.lang.Specification class FetchDescendantsOptionSpec extends Specification { - def 'Check has next descendant for fetch descendant option: #scenario'() { + + def 'Has next descendant for fetch descendant option: #scenario'() { when: 'fetch descendant option with #depth depth' def fetchDescendantsOption = new FetchDescendantsOption(depth) then: 'next level descendants available: #expectedHasNext' - fetchDescendantsOption.hasNext() == expectedHasNext + assert fetchDescendantsOption.hasNext() == expectedHasNext where: 'following parameters are used' scenario | depth || expectedHasNext 'omit descendants' | 0 || false @@ -38,7 +38,7 @@ class FetchDescendantsOptionSpec extends Specification { 'include all descendants' | -1 || true } - def 'Check has next descendant for fetch descendant option: invalid depth'() { + def 'Has next descendant for fetch descendant option: invalid depth'() { given: 'fetch descendant option with -2 depth' def fetchDescendantsOption = new FetchDescendantsOption(-2) when: 'next level descendants not available' @@ -47,7 +47,7 @@ class FetchDescendantsOptionSpec extends Specification { thrown IllegalArgumentException } - def 'Get next descendant for fetch descendant option: #scenario'() { + def 'Next descendant for fetch descendant option: #scenario.'() { when: 'fetch descendant option with #depth depth' def fetchDescendantsOption = new FetchDescendantsOption(depth) then: 'the next level of depth is as expected' @@ -58,14 +58,14 @@ class FetchDescendantsOptionSpec extends Specification { 'second child' | 2 } - def 'Get next descendant for fetch descendant option: include all descendants'() { + def 'Next descendant for fetch descendant option: include all descendants.'() { when: 'fetch descendant option with -1 depth' def fetchDescendantsOption = new FetchDescendantsOption(-1) then: 'the next level of depth is as expected' fetchDescendantsOption.next().depth == -1 } - def 'Get next descendant for fetch descendant option: omit descendants'() { + def 'Next descendant for fetch descendant option: omit descendants.'() { given: 'fetch descendant option with 0 depth' def fetchDescendantsOption = new FetchDescendantsOption(0) when: 'the next level of depth is not allowed' @@ -74,7 +74,7 @@ class FetchDescendantsOptionSpec extends Specification { thrown IllegalArgumentException } - def 'Create fetch descendant option with descendant using #scenario'() { + def 'Create fetch descendant option with descendant using #scenario.'() { when: 'the next level of depth is not allowed' def FetchDescendantsOption fetchDescendantsOption = FetchDescendantsOption.getFetchDescendantsOption(fetchDescendantsOptionAsString) then: 'fetch descendant object created' @@ -87,4 +87,16 @@ class FetchDescendantsOptionSpec extends Specification { 'No descendants using none' | 'none' || 0 'til 10th descendants using number' | '10' || 10 } + + def 'String values.'() { + expect: 'each fetch descendant option has the correct String value' + assert fetchDescendantsOption.toString() == expectedStringValue + where: 'the following option is used' + fetchDescendantsOption || expectedStringValue + FetchDescendantsOption.OMIT_DESCENDANTS || 'OmitDescendants' + FetchDescendantsOption.DIRECT_CHILDREN_ONLY || 'DirectChildrenOnly' + FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS || 'IncludeAllDescendants' + new FetchDescendantsOption(2) || 'Depth=2' + } + } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/CpsPersistenceSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/CpsPersistenceSpec.groovy deleted file mode 100644 index 349f0854e..000000000 --- a/integration-test/src/test/groovy/org/onap/cps/integration/CpsPersistenceSpec.groovy +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * 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.integration - -import org.onap.cps.spi.FetchDescendantsOption - -class CpsPersistenceSpec extends CpsIntegrationSpecBase{ - - def 'Test creation of test data'() { - when: 'A dataspace, schema set and anchor are persisted' - createDataspaceSchemaSetAnchor(TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, 'bookstore.yang', TEST_ANCHOR) - and: 'data nodes are persisted under the created anchor' - saveDataNodes(TEST_DATASPACE, TEST_ANCHOR, '/', 'BookstoreDataNodes.json') - then: 'The dataspace has been persisted successfully' - cpsAdminService.getDataspace(TEST_DATASPACE).getName() == TEST_DATASPACE - and: 'The schema set has been persisted successfully' - cpsModuleService.getSchemaSet(TEST_DATASPACE, BOOKSTORE_SCHEMA_SET).getName() == BOOKSTORE_SCHEMA_SET - and: 'The anchor has been persisted successfully' - cpsAdminService.getAnchor(TEST_DATASPACE, TEST_ANCHOR).getName() == TEST_ANCHOR - and: 'The data nodes have been persisted successfully' - cpsDataService.getDataNodes(TEST_DATASPACE, TEST_ANCHOR, '/bookstore', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS).iterator().next().xpath == '/bookstore' - } - - def 'Test deletion of all test data'() { - when: 'delete all from test dataspace method is called' - deleteAllFromTestDataspace() - and: 'the test dataspace is deleted' - cpsAdminService.deleteDataspace(TEST_DATASPACE) - then: 'there is no test dataspace' - !cpsAdminService.getAllDataspaces().contains(TEST_DATASPACE) - } - - def 'Read test for persisted data nodes'() { - given:'There is a test dataspace created' - cpsAdminService.createDataspace(TEST_DATASPACE) - and: 'There is a schema set and anchor for the test dataspace' - createSchemaSetAnchor(TEST_DATASPACE, 'bookstoreSchemaSet', 'bookstore.yang', TEST_ANCHOR) - when: 'data is persisted to the database' - saveDataNodes(TEST_DATASPACE, TEST_ANCHOR, "/", "BookstoreDataNodes.json") - then: 'the correct data is saved' - cpsDataService.getDataNodes(TEST_DATASPACE, TEST_ANCHOR, '/bookstore', FetchDescendantsOption.OMIT_DESCENDANTS).iterator().next().leaves['bookstore-name'] == 'Easons' - } -} diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/BookstoreSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/BookstoreSpecBase.groovy new file mode 100644 index 000000000..7eb47b35a --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/BookstoreSpecBase.groovy @@ -0,0 +1,49 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * 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.integration.base + +import java.time.OffsetDateTime + +class BookstoreSpecBase extends CpsIntegrationSpecBase { + + def static initialized = false + + def setup() { + if (!initialized) { + setupBookstoreInfraStructure() + addBookstoreData() + initialized = true + } + } + + def setupBookstoreInfraStructure() { + cpsAdminService.createDataspace(BOOKSTORE_DATASPACE) + def bookstoreYangModelAsString = readResourceFile('bookstore.yang') + cpsModuleService.createSchemaSet(BOOKSTORE_DATASPACE, BOOKSTORE_SCHEMA_SET, [bookstore : bookstoreYangModelAsString]) + cpsAdminService.createAnchor(BOOKSTORE_DATASPACE, BOOKSTORE_SCHEMA_SET, BOOKSTORE_ANCHOR) + } + + def addBookstoreData() { + def bookstoreJsonData = readResourceFile('BookstoreDataNodes.json') + cpsDataService.saveData(BOOKSTORE_DATASPACE, BOOKSTORE_ANCHOR, bookstoreJsonData, OffsetDateTime.now()) + } + +} diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy similarity index 54% rename from integration-test/src/test/groovy/org/onap/cps/integration/CpsIntegrationSpecBase.groovy rename to integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy index 960483270..567b33cb4 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/CpsIntegrationSpecBase.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy @@ -18,15 +18,15 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.integration +package org.onap.cps.integration.base import org.onap.cps.api.impl.CpsAdminServiceImpl import org.onap.cps.api.impl.CpsDataServiceImpl import org.onap.cps.api.impl.CpsModuleServiceImpl -import org.onap.cps.spi.CascadeDeleteAllowed +import org.onap.cps.integration.DatabaseTestContainer +import org.onap.cps.spi.model.DataNode import org.onap.cps.spi.repository.DataspaceRepository import org.onap.cps.spi.impl.utils.CpsValidatorImpl -import org.onap.cps.utils.ContentType import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.EnableAutoConfiguration import org.springframework.boot.autoconfigure.domain.EntityScan @@ -38,8 +38,6 @@ import org.testcontainers.spock.Testcontainers import spock.lang.Shared import spock.lang.Specification -import java.time.OffsetDateTime - @SpringBootTest(classes = [TestConfig, CpsAdminServiceImpl, CpsValidatorImpl]) @Testcontainers @EnableAutoConfiguration @@ -63,50 +61,35 @@ class CpsIntegrationSpecBase extends Specification { @Lazy CpsModuleServiceImpl cpsModuleService - - def static TEST_DATASPACE = 'testDataspace' + def static GENERAL_TEST_DATASPACE = 'generalTestDataSpace' + def static BOOKSTORE_DATASPACE = 'bookstoreDataspace' def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet' - def static TEST_ANCHOR = 'testAnchor' + def static BOOKSTORE_ANCHOR = 'bookstoreAnchor' - def createDataspaceSchemaSetAnchor(String dataspaceName, String schemaSetName, String schemaSetFileName, String anchorName) { - cpsAdminService.createDataspace(dataspaceName) - createSchemaSetAnchor(dataspaceName, schemaSetName, schemaSetFileName, anchorName) - } + def static initialized = false - def createSchemaSetAnchor(String dataspaceName, String schemaSetName, String schemaSetFileName, String anchorName) { - def bookstoreFileContent = readResourceFile(schemaSetFileName) - cpsModuleService.createSchemaSet(dataspaceName, schemaSetName, [(schemaSetFileName) : bookstoreFileContent]) - cpsAdminService.createAnchor(dataspaceName, schemaSetName, anchorName) + def setup() { + if (!initialized) { + cpsAdminService.createDataspace(GENERAL_TEST_DATASPACE) + def bookstoreModelFileContent = readResourceFile('bookstore.yang') + cpsModuleService.createSchemaSet(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, [bookstore : bookstoreModelFileContent]) + initialized = true; + } } - def saveDataNodes(String dataspaceName, String anchorName, String parentNodeXpath, String dataNodesFileName) { - def dataNodesAsJSON = readResourceFile(dataNodesFileName) - if (isRootXpath(parentNodeXpath)) { - cpsDataService.saveData(dataspaceName, anchorName, dataNodesAsJSON, - OffsetDateTime.now(), ContentType.JSON); - } else { - cpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath, - dataNodesAsJSON, OffsetDateTime.now(), ContentType.JSON); - } + def static countDataNodesInTree(DataNode dataNode) { + return 1 + countDataNodesInTree(dataNode.getChildDataNodes()) } - def deleteAllFromTestDataspace() { - def anchors = cpsAdminService.getAnchors(TEST_DATASPACE) - for(anchor in anchors) { - cpsDataService.deleteDataNodes(TEST_DATASPACE, anchor.getName(), OffsetDateTime.now()) - cpsAdminService.deleteAnchor(TEST_DATASPACE, anchor.getName()) - } - def schemaSets = cpsModuleService.getSchemaSets(TEST_DATASPACE) - for(schemaSet in schemaSets) { - cpsModuleService.deleteSchemaSet(TEST_DATASPACE, schemaSet.getName(), CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED) + def static countDataNodesInTree(Collection dataNodes) { + int nodeCount = 0 + for (DataNode parent : dataNodes) { + nodeCount += countDataNodesInTree(parent) } + return nodeCount } - def static readResourceFile(String filename) { + def static readResourceFile(filename) { return new File('src/test/resources/data/' + filename).text } - - def static isRootXpath(final String xpath) { - return "/".equals(xpath); - } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/TestConfig.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy similarity index 99% rename from integration-test/src/test/groovy/org/onap/cps/integration/TestConfig.groovy rename to integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy index 0673f7eb4..18a294161 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/TestConfig.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.integration +package org.onap.cps.integration.base import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.notification.NotificationService diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy new file mode 100644 index 000000000..d504a9e0d --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy @@ -0,0 +1,109 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * 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.integration.functional + +import org.onap.cps.integration.base.CpsIntegrationSpecBase +import org.onap.cps.spi.exceptions.AlreadyDefinedException +import org.onap.cps.spi.exceptions.AnchorNotFoundException +import org.onap.cps.spi.exceptions.DataspaceNotFoundException + +class CpsAdminServiceIntegrationSpec extends CpsIntegrationSpecBase { + + def objectUnderTest + + def setup() { objectUnderTest = cpsAdminService } + + def 'Dataspace CRUD operations.'() { + when: 'a dataspace is created' + objectUnderTest.createDataspace('newDataspace') + then: 'the dataspace can be read' + assert objectUnderTest.getDataspace('newDataspace').name == 'newDataspace' + and: 'it can be deleted' + objectUnderTest.deleteDataspace('newDataspace') + then: 'the dataspace no longer exists i.e. an exception is thrown if an attempt is made to retrieve it' + def thrown = null + try { + objectUnderTest.getDataspace('newDataspace') + } catch(Exception e) { + thrown = e + } + assert thrown instanceof DataspaceNotFoundException + } + + def 'Retrieve all dataspaces (depends on total test suite).'() { + given: 'two addtional dataspaces are created' + objectUnderTest.createDataspace('dataspace1') + objectUnderTest.createDataspace('dataspace2') + when: 'all datespaces are retreived' + def result = objectUnderTest.getAllDataspaces() + then: 'there are at least 3 dataspaces (2 new ones plus the general test dataspace)' + result.size() >= 3 + assert result.name.containsAll([GENERAL_TEST_DATASPACE, 'dataspace1', 'dataspace2']) + } + + def 'Duplicate dataspaces.'() { + when: 'attempting to create a dataspace with the same name as an existing one' + objectUnderTest.createDataspace(GENERAL_TEST_DATASPACE) + then: 'an exception is thrown indicating the dataspace already exists' + thrown(AlreadyDefinedException) + } + + def 'Anchor CRUD operations.'() { + when: 'a anchor is created' + objectUnderTest.createAnchor(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, 'newAnchor') + then: 'the anchor be read' + assert objectUnderTest.getAnchor(GENERAL_TEST_DATASPACE, 'newAnchor').name == 'newAnchor' + and: 'it can be deleted' + objectUnderTest.deleteAnchor(GENERAL_TEST_DATASPACE,'newAnchor') + then: 'the anchor no longer exists i.e. an exception is thrown if an attempt is made to retrieve it' + def thrown = null + try { + objectUnderTest.getAnchor(GENERAL_TEST_DATASPACE, 'newAnchor') + } catch(Exception e) { + thrown = e + } + assert thrown instanceof AnchorNotFoundException + } + + def 'Filtering multiple anchors.'() { + when: '2 anchors with bookstore schema set are created' + objectUnderTest.createAnchor(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, 'anchor1') + objectUnderTest.createAnchor(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, 'anchor2') + and: '1 anchor with "other" schema set is created' + def bookstoreModelFileContent = readResourceFile('bookstore.yang') + cpsModuleService.createSchemaSet(GENERAL_TEST_DATASPACE, 'otherSchemaSet', [someFileName: bookstoreModelFileContent]) + objectUnderTest.createAnchor(GENERAL_TEST_DATASPACE, 'otherSchemaSet', 'anchor3') + then: 'there are 3 anchors in the general test database' + assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE).size() == 3 + and: 'there are 2 anchors associated with bookstore schema set' + assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET).size() == 2 + and: 'there is 1 anchor associated with other schema set' + assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE, 'otherSchemaSet').size() == 1 + } + + def 'Querying anchor(name)s (depends on previous test!).'() { + expect: 'there are now 3 anchors using the "stores" module (both schema sets use the same modules) ' + assert objectUnderTest.queryAnchorNames(GENERAL_TEST_DATASPACE, ['stores']).size() == 3 + and: 'there are no anchors using both "stores" and a "unused-model"' + assert objectUnderTest.queryAnchorNames(GENERAL_TEST_DATASPACE, ['stores', 'unused-model']).size() == 0 + } + +} 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 new file mode 100644 index 000000000..5e839f27a --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * 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.integration.functional + +import org.onap.cps.integration.base.BookstoreSpecBase +import org.onap.cps.spi.FetchDescendantsOption + +class CpsDataServiceIntegrationSpec extends BookstoreSpecBase { + + def objectUnderTest + + def setup() { objectUnderTest = cpsDataService } + + def 'Read bookstore top-level container(s) using #fetchDescendantsOption.'() { + when: 'get data nodes for bookstore container' + def result = objectUnderTest.getDataNodes(BOOKSTORE_DATASPACE, BOOKSTORE_ANCHOR, '/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' + assert result.leaves['bookstore-name'] == ['Easons'] + where: 'the following option is used' + fetchDescendantsOption || expectNumberOfDataNodes + FetchDescendantsOption.OMIT_DESCENDANTS || 1 + FetchDescendantsOption.DIRECT_CHILDREN_ONLY || 4 + FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS || 8 + new FetchDescendantsOption(2) || 8 + } + +} -- 2.16.6