From 048350463a68b774f42e80e94afe16a541711ae4 Mon Sep 17 00:00:00 2001 From: ToineSiebelink Date: Thu, 23 Feb 2023 15:49:40 +0000 Subject: 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 ++++-- .../cps/integration/CpsIntegrationSpecBase.groovy | 112 ------------------- .../onap/cps/integration/CpsPersistenceSpec.groovy | 62 ----------- .../org/onap/cps/integration/TestConfig.groovy | 120 --------------------- .../cps/integration/base/BookstoreSpecBase.groovy | 49 +++++++++ .../integration/base/CpsIntegrationSpecBase.groovy | 95 ++++++++++++++++ .../onap/cps/integration/base/TestConfig.groovy | 120 +++++++++++++++++++++ .../CpsAdminServiceIntegrationSpec.groovy | 109 +++++++++++++++++++ .../CpsDataServiceIntegrationSpec.groovy | 48 +++++++++ 13 files changed, 467 insertions(+), 314 deletions(-) delete mode 100644 integration-test/src/test/groovy/org/onap/cps/integration/CpsIntegrationSpecBase.groovy delete mode 100644 integration-test/src/test/groovy/org/onap/cps/integration/CpsPersistenceSpec.groovy delete mode 100644 integration-test/src/test/groovy/org/onap/cps/integration/TestConfig.groovy create mode 100644 integration-test/src/test/groovy/org/onap/cps/integration/base/BookstoreSpecBase.groovy create mode 100644 integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy create mode 100644 integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy 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/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/CpsIntegrationSpecBase.groovy deleted file mode 100644 index 960483270..000000000 --- a/integration-test/src/test/groovy/org/onap/cps/integration/CpsIntegrationSpecBase.groovy +++ /dev/null @@ -1,112 +0,0 @@ -/* - * ============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 - -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.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 -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.context.annotation.ComponentScan -import org.springframework.context.annotation.Lazy -import org.springframework.data.jpa.repository.config.EnableJpaRepositories -import org.testcontainers.spock.Testcontainers -import spock.lang.Shared -import spock.lang.Specification - -import java.time.OffsetDateTime - -@SpringBootTest(classes = [TestConfig, CpsAdminServiceImpl, CpsValidatorImpl]) -@Testcontainers -@EnableAutoConfiguration -@EnableJpaRepositories(basePackageClasses = [DataspaceRepository]) -@ComponentScan(basePackages = ["org.onap.cps.api", "org.onap.cps.spi.repository"]) -@EntityScan("org.onap.cps.spi.entities") -class CpsIntegrationSpecBase extends Specification { - - @Shared - DatabaseTestContainer databaseTestContainer = DatabaseTestContainer.getInstance() - - @Autowired - @Lazy - CpsAdminServiceImpl cpsAdminService - - @Autowired - @Lazy - CpsDataServiceImpl cpsDataService - - @Autowired - @Lazy - CpsModuleServiceImpl cpsModuleService - - - def static TEST_DATASPACE = 'testDataspace' - def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet' - def static TEST_ANCHOR = 'testAnchor' - - def createDataspaceSchemaSetAnchor(String dataspaceName, String schemaSetName, String schemaSetFileName, String anchorName) { - cpsAdminService.createDataspace(dataspaceName) - createSchemaSetAnchor(dataspaceName, schemaSetName, schemaSetFileName, anchorName) - } - - 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 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 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 readResourceFile(String 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/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/TestConfig.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/TestConfig.groovy deleted file mode 100644 index 0673f7eb4..000000000 --- a/integration-test/src/test/groovy/org/onap/cps/integration/TestConfig.groovy +++ /dev/null @@ -1,120 +0,0 @@ -/* - * ============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 - -import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.notification.NotificationService -import org.onap.cps.spi.CpsDataPersistenceService -import org.onap.cps.spi.CpsModulePersistenceService -import org.onap.cps.spi.impl.CpsAdminPersistenceServiceImpl -import org.onap.cps.spi.impl.CpsDataPersistenceServiceImpl -import org.onap.cps.spi.impl.CpsModulePersistenceServiceImpl -import org.onap.cps.spi.repository.AnchorRepository -import org.onap.cps.spi.repository.DataspaceRepository -import org.onap.cps.spi.repository.FragmentRepository -import org.onap.cps.spi.repository.ModuleReferenceRepository -import org.onap.cps.spi.repository.SchemaSetRepository -import org.onap.cps.spi.repository.YangResourceRepository -import org.onap.cps.spi.utils.SessionManager -import org.onap.cps.utils.JsonObjectMapper -import org.onap.cps.utils.TimedYangParser -import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.Lazy -import spock.lang.Specification - -@Configuration -class TestConfig extends Specification{ - @Autowired - @Lazy - DataspaceRepository dataspaceRepository - - @Autowired - @Lazy - AnchorRepository anchorRepository - - @Autowired - @Lazy - SchemaSetRepository schemaSetRepository - - @Autowired - @Lazy - YangResourceRepository yangResourceRepository - - @Autowired - @Lazy - FragmentRepository fragmentRepository - - @Autowired - @Lazy - ModuleReferenceRepository moduleReferenceRepository - - @Autowired - @Lazy - JsonObjectMapper jsonObjectMapper - - @Autowired - @Lazy - SessionManager stubbedSessionManager - - @Bean - CpsAdminPersistenceServiceImpl cpsAdminPersistenceService() { - new CpsAdminPersistenceServiceImpl(dataspaceRepository, anchorRepository, schemaSetRepository, yangResourceRepository) - } - - @Bean - CpsDataPersistenceService cpsDataPersistenceService() { - return (CpsDataPersistenceService) new CpsDataPersistenceServiceImpl(dataspaceRepository, anchorRepository, fragmentRepository, jsonObjectMapper, stubbedSessionManager) - } - - @Bean - CpsModulePersistenceService cpsModulePersistenceService() { - return (CpsModulePersistenceService) new CpsModulePersistenceServiceImpl(yangResourceRepository, schemaSetRepository, dataspaceRepository, cpsAdminPersistenceService(), moduleReferenceRepository) - } - - @Bean - JsonObjectMapper jsonObjectMapper() { - return new JsonObjectMapper(new ObjectMapper()) - } - - @Bean - NotificationService notificationService() { - return Stub(NotificationService) - } - - @Bean - SessionManager sessionManager() { - return Stub(SessionManager) - } - - @Bean - TimedYangParser timedYangParser() { - return new TimedYangParser() - } - - @Bean - TimedYangTextSchemaSourceSetBuilder textSchemaSourceSetBuilder() { - return new TimedYangTextSchemaSourceSetBuilder() - } - -} 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/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy new file mode 100644 index 000000000..567b33cb4 --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy @@ -0,0 +1,95 @@ +/* + * ============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 org.onap.cps.api.impl.CpsAdminServiceImpl +import org.onap.cps.api.impl.CpsDataServiceImpl +import org.onap.cps.api.impl.CpsModuleServiceImpl +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.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Lazy +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.testcontainers.spock.Testcontainers +import spock.lang.Shared +import spock.lang.Specification + +@SpringBootTest(classes = [TestConfig, CpsAdminServiceImpl, CpsValidatorImpl]) +@Testcontainers +@EnableAutoConfiguration +@EnableJpaRepositories(basePackageClasses = [DataspaceRepository]) +@ComponentScan(basePackages = ["org.onap.cps.api", "org.onap.cps.spi.repository"]) +@EntityScan("org.onap.cps.spi.entities") +class CpsIntegrationSpecBase extends Specification { + + @Shared + DatabaseTestContainer databaseTestContainer = DatabaseTestContainer.getInstance() + + @Autowired + @Lazy + CpsAdminServiceImpl cpsAdminService + + @Autowired + @Lazy + CpsDataServiceImpl cpsDataService + + @Autowired + @Lazy + CpsModuleServiceImpl cpsModuleService + + def static GENERAL_TEST_DATASPACE = 'generalTestDataSpace' + def static BOOKSTORE_DATASPACE = 'bookstoreDataspace' + def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet' + def static BOOKSTORE_ANCHOR = 'bookstoreAnchor' + + def static initialized = false + + 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 static countDataNodesInTree(DataNode dataNode) { + return 1 + countDataNodesInTree(dataNode.getChildDataNodes()) + } + + def static countDataNodesInTree(Collection dataNodes) { + int nodeCount = 0 + for (DataNode parent : dataNodes) { + nodeCount += countDataNodesInTree(parent) + } + return nodeCount + } + + def static readResourceFile(filename) { + return new File('src/test/resources/data/' + filename).text + } +} diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy new file mode 100644 index 000000000..18a294161 --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy @@ -0,0 +1,120 @@ +/* + * ============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 com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.notification.NotificationService +import org.onap.cps.spi.CpsDataPersistenceService +import org.onap.cps.spi.CpsModulePersistenceService +import org.onap.cps.spi.impl.CpsAdminPersistenceServiceImpl +import org.onap.cps.spi.impl.CpsDataPersistenceServiceImpl +import org.onap.cps.spi.impl.CpsModulePersistenceServiceImpl +import org.onap.cps.spi.repository.AnchorRepository +import org.onap.cps.spi.repository.DataspaceRepository +import org.onap.cps.spi.repository.FragmentRepository +import org.onap.cps.spi.repository.ModuleReferenceRepository +import org.onap.cps.spi.repository.SchemaSetRepository +import org.onap.cps.spi.repository.YangResourceRepository +import org.onap.cps.spi.utils.SessionManager +import org.onap.cps.utils.JsonObjectMapper +import org.onap.cps.utils.TimedYangParser +import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Lazy +import spock.lang.Specification + +@Configuration +class TestConfig extends Specification{ + @Autowired + @Lazy + DataspaceRepository dataspaceRepository + + @Autowired + @Lazy + AnchorRepository anchorRepository + + @Autowired + @Lazy + SchemaSetRepository schemaSetRepository + + @Autowired + @Lazy + YangResourceRepository yangResourceRepository + + @Autowired + @Lazy + FragmentRepository fragmentRepository + + @Autowired + @Lazy + ModuleReferenceRepository moduleReferenceRepository + + @Autowired + @Lazy + JsonObjectMapper jsonObjectMapper + + @Autowired + @Lazy + SessionManager stubbedSessionManager + + @Bean + CpsAdminPersistenceServiceImpl cpsAdminPersistenceService() { + new CpsAdminPersistenceServiceImpl(dataspaceRepository, anchorRepository, schemaSetRepository, yangResourceRepository) + } + + @Bean + CpsDataPersistenceService cpsDataPersistenceService() { + return (CpsDataPersistenceService) new CpsDataPersistenceServiceImpl(dataspaceRepository, anchorRepository, fragmentRepository, jsonObjectMapper, stubbedSessionManager) + } + + @Bean + CpsModulePersistenceService cpsModulePersistenceService() { + return (CpsModulePersistenceService) new CpsModulePersistenceServiceImpl(yangResourceRepository, schemaSetRepository, dataspaceRepository, cpsAdminPersistenceService(), moduleReferenceRepository) + } + + @Bean + JsonObjectMapper jsonObjectMapper() { + return new JsonObjectMapper(new ObjectMapper()) + } + + @Bean + NotificationService notificationService() { + return Stub(NotificationService) + } + + @Bean + SessionManager sessionManager() { + return Stub(SessionManager) + } + + @Bean + TimedYangParser timedYangParser() { + return new TimedYangParser() + } + + @Bean + TimedYangTextSchemaSourceSetBuilder textSchemaSourceSetBuilder() { + return new TimedYangTextSchemaSourceSetBuilder() + } + +} 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 + } + +} -- cgit 1.2.3-korg