diff options
30 files changed, 373 insertions, 38 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index d5500b8d7..d26a59b05 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -393,7 +393,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService } private void batchDeleteCmHandlesFromDbAndModuleSyncMap(final Collection<String> tobeRemovedCmHandles) { - tobeRemovedCmHandles.forEach(inventoryPersistence::deleteSchemaSetWithCascade); + inventoryPersistence.deleteSchemaSetsWithCascade(tobeRemovedCmHandles); inventoryPersistence.deleteDataNodes(mapCmHandleIdsToXpaths(tobeRemovedCmHandles)); tobeRemovedCmHandles.forEach(this::removeDeletedCmHandleFromModuleSyncMap); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java index d22cf0e16..cbd30a8fe 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java @@ -115,6 +115,13 @@ public interface InventoryPersistence { void deleteSchemaSetWithCascade(String schemaSetName); /** + * Method to delete multiple schema sets. + * + * @param schemaSetNames schema set names + */ + void deleteSchemaSetsWithCascade(Collection<String> schemaSetNames); + + /** * Get data node via xpath. * * @param xpath xpath diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImpl.java index 1c799c6b2..c8d6c05f9 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImpl.java @@ -169,6 +169,14 @@ public class InventoryPersistenceImpl implements InventoryPersistence { } @Override + @Timed(value = "cps.ncmp.inventory.persistence.schemaset.delete.batch", + description = "Time taken to delete multiple schemaset") + public void deleteSchemaSetsWithCascade(final Collection<String> schemaSetNames) { + cpsValidator.validateNameCharacters(schemaSetNames); + cpsModuleService.deleteSchemaSetsWithCascade(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetNames); + } + + @Override @Timed(value = "cps.ncmp.inventory.persistence.datanode.get", description = "Time taken to get a data node (from ncmp dmi registry)") public Collection<DataNode> getDataNode(final String xpath) { @@ -239,4 +247,4 @@ public class InventoryPersistenceImpl implements InventoryPersistence { private static String createCmHandleJsonData(final String cmHandleId) { return "{\"cm-handles\":[" + cmHandleId + "]}"; } -}
\ No newline at end of file +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy index cf3454991..272030b11 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy @@ -249,14 +249,14 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', removedCmHandles: ['cmhandle']) and: '#scenario' - mockCpsModuleService.deleteSchemaSet(_, 'cmhandle', CASCADE_DELETE_ALLOWED) >> + mockCpsModuleService.deleteSchemaSetsWithCascade(_, ['cmhandle']) >> { if (!schemaSetExist) { throw new SchemaSetNotFoundException("", "") } } when: 'registration is updated to delete cmhandle' def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) then: 'the cmHandle state is updated to "DELETING"' 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) and: 'method to delete relevant schema set is called once' - 1 * mockInventoryPersistence.deleteSchemaSetWithCascade(_) + 1 * mockInventoryPersistence.deleteSchemaSetsWithCascade(_) and: 'method to delete relevant list/list element is called once' 1 * mockInventoryPersistence.deleteDataNodes(_) and: 'successful response is received' @@ -322,7 +322,9 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { addPersistedYangModelCmHandles(['cmhandle']) def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', removedCmHandles: ['cmhandle']) - and: 'schema set deletion failed with unknown error' + and: 'schema set batch deletion failed with unknown error' + mockInventoryPersistence.deleteSchemaSetsWithCascade(_) >> { throw new RuntimeException('Failed') } + and: 'schema set single deletion failed with unknown error' mockInventoryPersistence.deleteSchemaSetWithCascade(_) >> { throw new RuntimeException('Failed') } when: 'registration is updated to delete cmhandle' def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImplSpec.groovy index 4a98526b4..efe6f00bc 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImplSpec.groovy @@ -243,10 +243,19 @@ class InventoryPersistenceImplSpec extends Specification { objectUnderTest.deleteSchemaSetWithCascade('validSchemaSetName') then: 'the module service to delete schemaSet is invoked once' 1 * mockCpsModuleService.deleteSchemaSet('NFP-Operational', 'validSchemaSetName', CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED) - and: 'the CM Handle ID is validated' + and: 'the schema set name is validated' 1 * mockCpsValidator.validateNameCharacters('validSchemaSetName') } + def 'Delete multiple schema sets with valid schema set names'() { + when: 'the method to delete schema sets is called with valid schema set names' + objectUnderTest.deleteSchemaSetsWithCascade(['validSchemaSetName1', 'validSchemaSetName2']) + then: 'the module service to delete schema sets is invoked once' + 1 * mockCpsModuleService.deleteSchemaSetsWithCascade('NFP-Operational', ['validSchemaSetName1', 'validSchemaSetName2']) + and: 'the schema set names are validated' + 1 * mockCpsValidator.validateNameCharacters(['validSchemaSetName1', 'validSchemaSetName2']) + } + def 'Get data node via xPath'() { when: 'the method to get data nodes is called' objectUnderTest.getDataNode('sample xPath') diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java index 2cebfc72c..162b268d8 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2022 Nordix Foundation. + * Copyright (C) 2020-2023 Nordix Foundation. * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 TechMahindra Ltd. @@ -131,6 +131,13 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic } @Override + public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> schemaSetNames) { + final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); + return anchorRepository.findAllByDataspaceAndSchemaSetNameIn(dataspaceEntity, schemaSetNames) + .stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet()); + } + + @Override public Collection<Anchor> queryAnchors(final String dataspaceName, final Collection<String> inputModuleNames) { try { validateDataspaceAndModuleNames(dataspaceName, inputModuleNames); @@ -157,6 +164,13 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic anchorRepository.delete(anchorEntity); } + @Transactional + @Override + public void deleteAnchors(final String dataspaceName, final Collection<String> anchorNames) { + final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName); + anchorRepository.deleteAllByDataspaceAndNameIn(dataspaceEntity, anchorNames); + } + private AnchorEntity getAnchorEntity(final String dataspaceName, final String anchorName) { final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName); return anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName); diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java index 46439fdb3..2fba30ee2 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java @@ -612,6 +612,15 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService @Override @Transactional + public void deleteDataNodes(final String dataspaceName, final Collection<String> anchorNames) { + final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); + final Collection<AnchorEntity> anchorEntities = + anchorRepository.findAllByDataspaceAndNameIn(dataspaceEntity, anchorNames); + fragmentRepository.deleteByAnchorIn(anchorEntities); + } + + @Override + @Transactional public void deleteDataNodes(final String dataspaceName, final String anchorName, final Collection<String> xpathsToDelete) { final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java index c9f9a78ef..b4366de75 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2022 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 TechMahindra Ltd. @@ -193,6 +193,13 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ @Override @Transactional + public void deleteSchemaSets(final String dataspaceName, final Collection<String> schemaSetNames) { + final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName); + schemaSetRepository.deleteByDataspaceAndNameIn(dataspaceEntity, schemaSetNames); + } + + @Override + @Transactional public void deleteUnusedYangResourceModules() { yangResourceRepository.deleteOrphans(); } diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/utils/CpsValidatorImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/utils/CpsValidatorImpl.java index 064583142..1f61ee3c5 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/utils/CpsValidatorImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/utils/CpsValidatorImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-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. @@ -21,6 +21,7 @@ package org.onap.cps.spi.impl.utils; import com.google.common.collect.Lists; +import java.util.Arrays; import java.util.Collection; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -37,13 +38,18 @@ public class CpsValidatorImpl implements CpsValidator { @Override public void validateNameCharacters(final String... names) { + validateNameCharacters(Arrays.asList(names)); + } + + @Override + public void validateNameCharacters(final Iterable<String> names) { for (final String name : names) { final Collection<Character> charactersOfName = Lists.charactersOf(name); for (final char unsupportedCharacter : UNSUPPORTED_NAME_CHARACTERS) { if (charactersOfName.contains(unsupportedCharacter)) { throw new DataValidationException("Name or ID Validation Error.", - name + " invalid token encountered at position " - + (name.indexOf(unsupportedCharacter) + 1)); + name + " invalid token encountered at position " + + (name.indexOf(unsupportedCharacter) + 1)); } } } diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java index 3dbd578c7..46b0fec1c 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java @@ -47,6 +47,12 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Integer> { Collection<AnchorEntity> findAllBySchemaSet(@NotNull SchemaSetEntity schemaSetEntity); + Collection<AnchorEntity> findAllByDataspaceAndNameIn(@NotNull DataspaceEntity dataspaceEntity, + @NotNull Collection<String> anchorNames); + + Collection<AnchorEntity> findAllByDataspaceAndSchemaSetNameIn(@NotNull DataspaceEntity dataspaceEntity, + @NotNull Collection<String> schemaSetNames); + Integer countByDataspace(@NotNull DataspaceEntity dataspaceEntity); @Query(value = "SELECT anchor.* FROM yang_resource\n" @@ -58,4 +64,7 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Integer> { + "HAVING COUNT(DISTINCT module_name) = :sizeOfModuleNames", nativeQuery = true) Collection<AnchorEntity> getAnchorsByDataspaceIdAndModuleNames(@Param("dataspaceId") int dataspaceId, @Param("moduleNames") Collection<String> moduleNames, @Param("sizeOfModuleNames") int sizeOfModuleNames); -}
\ No newline at end of file + + void deleteAllByDataspaceAndNameIn(@NotNull DataspaceEntity dataspaceEntity, + @NotNull Collection<String> anchorNames); +} diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java index 8cecb0a8e..98d442010 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java @@ -2,6 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2020 Pantheon.tech * Modifications Copyright (C) 2022 TechMahindra Ltd. + * Modifications 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. @@ -29,6 +30,9 @@ import org.onap.cps.spi.entities.DataspaceEntity; import org.onap.cps.spi.entities.SchemaSetEntity; import org.onap.cps.spi.exceptions.SchemaSetNotFoundException; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository @@ -70,4 +74,14 @@ public interface SchemaSetRepository extends JpaRepository<SchemaSetEntity, Inte default List<SchemaSetEntity> getByDataspace(@NotNull final DataspaceEntity dataspaceEntity) { return findByDataspace(dataspaceEntity).stream().collect(Collectors.toList()); } + + /** + * Delete multiple schema sets in a given dataspace. + * @param dataspaceEntity dataspace entity + * @param schemaSetNames schema set names + */ + @Modifying + @Query("DELETE FROM SchemaSetEntity s WHERE s.dataspace = :dataspaceEntity AND s.name IN (:schemaSetNames)") + void deleteByDataspaceAndNameIn(@NotNull @Param("dataspaceEntity") final DataspaceEntity dataspaceEntity, + @NotNull @Param("schemaSetNames") final Collection<String> schemaSetNames); } diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy index 99d44aac8..28d3bcfa4 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 Bell Canada * Modifications Copyright (C) 2022 TechMahindra Ltd. @@ -142,7 +142,8 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { where: 'the following data is used' dataspaceName || expectedAnchors DATASPACE_NAME || [Anchor.builder().name(ANCHOR_NAME1).schemaSetName(SCHEMA_SET_NAME1).dataspaceName(DATASPACE_NAME).build(), - Anchor.builder().name(ANCHOR_NAME2).schemaSetName(SCHEMA_SET_NAME2).dataspaceName(DATASPACE_NAME).build()] + Anchor.builder().name(ANCHOR_NAME2).schemaSetName(SCHEMA_SET_NAME2).dataspaceName(DATASPACE_NAME).build(), + Anchor.builder().name(ANCHOR_NAME3).schemaSetName(SCHEMA_SET_NAME2).dataspaceName(DATASPACE_NAME).build()] DATASPACE_WITH_NO_DATA || [] } @@ -179,6 +180,17 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { } @Sql([CLEAR_DATA, SET_DATA]) + def 'Get all anchors associated with multiple schemasets in a dataspace.'() { + when: 'anchors are retrieved by dataspace and schema-sets' + def anchors = objectUnderTest.getAnchors('DATASPACE-001', ['SCHEMA-SET-001', 'SCHEMA-SET-002']) + then: ' the response contains expected anchors' + anchors == Set.of( + new Anchor('ANCHOR-001', 'DATASPACE-001', 'SCHEMA-SET-001'), + new Anchor('ANCHOR-002', 'DATASPACE-001', 'SCHEMA-SET-002'), + new Anchor('ANCHOR-003', 'DATASPACE-001', 'SCHEMA-SET-002')) + } + + @Sql([CLEAR_DATA, SET_DATA]) def 'Delete anchor'() { when: 'delete anchor action is invoked' objectUnderTest.deleteAnchor(DATASPACE_NAME, ANCHOR_NAME2) @@ -198,6 +210,15 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { 'anchor does not exists' | DATASPACE_NAME | 'unknown' || AnchorNotFoundException } + @Sql([CLEAR_DATA, SET_DATA]) + def 'Delete multiple anchors'() { + when: 'delete anchors action is invoked' + objectUnderTest.deleteAnchors(DATASPACE_NAME, ['ANCHOR-002', 'ANCHOR-003']) + then: 'anchors are deleted' + anchorRepository.findById(3002).isEmpty() + anchorRepository.findById(3003).isEmpty() + } + @Sql([CLEAR_DATA, SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES]) def 'Query anchors that have #scenario.'() { when: 'all anchor are retrieved for the given dataspace name and module names' @@ -236,7 +257,7 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { where: 'the following data is used' scenario | dataspaceName || expectedException | expectedMessageDetails 'dataspace name does not exist' | 'unknown' || DataspaceNotFoundException | 'unknown does not exist' - 'dataspace contains an anchor' | 'DATASPACE-001' || DataspaceInUseException | 'contains 2 anchor(s)' + 'dataspace contains an anchor' | 'DATASPACE-001' || DataspaceInUseException | 'contains 3 anchor(s)' 'dataspace contains schemasets' | 'DATASPACE-003' || DataspaceInUseException | 'contains 1 schemaset(s)' } } diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy index 336d6035a..bb80a1320 100755 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy @@ -55,8 +55,6 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { static DataNodeBuilder dataNodeBuilder = new DataNodeBuilder() static final String SET_DATA = '/data/fragment.sql' - static int DATASPACE_1001_ID = 1001L - static int ANCHOR_3003_ID = 3003L static long ID_DATA_NODE_WITH_DESCENDANTS = 4001 static String XPATH_DATA_NODE_WITH_DESCENDANTS = '/parent-1' static String XPATH_DATA_NODE_WITH_LEAVES = '/parent-207' @@ -666,11 +664,23 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { @Sql([CLEAR_DATA, SET_DATA]) def 'Delete data node for an anchor.'() { given: 'a data-node exists for an anchor' - assert fragmentsExistInDB(DATASPACE_1001_ID, ANCHOR_3003_ID) + assert fragmentsExistInDB(1001, 3003) when: 'data nodes are deleted ' objectUnderTest.deleteDataNodes(DATASPACE_NAME, ANCHOR_NAME3) then: 'all data-nodes are deleted successfully' - assert !fragmentsExistInDB(DATASPACE_1001_ID, ANCHOR_3003_ID) + assert !fragmentsExistInDB(1001, 3003) + } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Delete data node for multiple anchors.'() { + given: 'a data-node exists for an anchor' + assert fragmentsExistInDB(1001, 3001) + assert fragmentsExistInDB(1001, 3003) + when: 'data nodes are deleted ' + objectUnderTest.deleteDataNodes(DATASPACE_NAME, ['ANCHOR-001', 'ANCHOR-003']) + then: 'all data-nodes are deleted successfully' + assert !fragmentsExistInDB(1001, 3001) + assert !fragmentsExistInDB(1001, 3003) } def fragmentsExistInDB(dataSpaceId, anchorId) { diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy index 4c67f7e97..864b3e3b6 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation * Modifications Copyright (C) 2021-2022 Bell Canada. * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ @@ -223,7 +223,16 @@ class CpsModulePersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase when: 'a schema set is deleted with cascade-prohibited option' objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NO_ANCHORS) then: 'the schema set has been deleted' - schemaSetRepository.findByDataspaceAndName(dataspaceEntity, SCHEMA_SET_NAME_NO_ANCHORS).isPresent() == false + !schemaSetRepository.findByDataspaceAndName(dataspaceEntity, SCHEMA_SET_NAME_NO_ANCHORS).isPresent() + } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Delete schema sets'() { + when: 'schema sets are deleted' + objectUnderTest.deleteSchemaSets(DATASPACE_NAME, ['SCHEMA-SET-001', 'SCHEMA-SET-002']) + then: 'the schema sets have been deleted' + !schemaSetRepository.findByDataspaceAndName(dataspaceEntity, 'SCHEMA-SET-001').isPresent() + !schemaSetRepository.findByDataspaceAndName(dataspaceEntity, 'SCHEMA-SET-002').isPresent() } @Sql([CLEAR_DATA, SET_DATA]) diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/utils/CpsValidatorSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/utils/CpsValidatorSpec.groovy index ae2ff16bc..345089c93 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/utils/CpsValidatorSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/utils/CpsValidatorSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-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. @@ -46,4 +46,22 @@ class CpsValidatorSpec extends Specification { 'position 5' | 'name with spaces' || 'name with spaces invalid token encountered at position 5' 'position 9' | 'nameWith Space' || 'nameWith Space invalid token encountered at position 9' } + + def 'Validating a list of valid names.'() { + given: 'a list of valid names' + def names = ['valid-name', 'another-valid-name'] + when: 'a list of strings is validated' + objectUnderTest.validateNameCharacters(names) + then: 'no exception is thrown' + noExceptionThrown() + } + + def 'Validating a list of names with invalid names.'() { + given: 'a list of names with an invalid name' + def names = ['valid-name', 'name with spaces'] + when: 'a list of strings is validated' + objectUnderTest.validateNameCharacters(names) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + } } diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy index 3b9338ce4..706b35ebb 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy @@ -212,7 +212,7 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase } @Sql([CLEAR_DATA, PERF_TEST_DATA]) - def 'Delete data nodes for an anchor'() {212 + def 'Delete data nodes for an anchor'() { given: 'a node with a large number of descendants is created' createLineage(objectUnderTest, 50, 50, false) createLineage(objectUnderTest, 50, 50, true) @@ -225,4 +225,18 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase recordAndAssertPerformance('Delete data nodes for anchor', 300, deleteDurationInMillis) } + @Sql([CLEAR_DATA, PERF_TEST_DATA]) + def 'Delete data nodes for multiple anchors'() { + given: 'a node with a large number of descendants is created' + createLineage(objectUnderTest, 50, 50, false) + createLineage(objectUnderTest, 50, 50, true) + when: 'data nodes are deleted' + stopWatch.start() + objectUnderTest.deleteDataNodes(PERF_DATASPACE, [PERF_ANCHOR]) + stopWatch.stop() + def deleteDurationInMillis = stopWatch.getTotalTimeMillis() + then: 'delete duration is under 300 milliseconds' + recordAndAssertPerformance('Delete data nodes for anchor', 300, deleteDurationInMillis) + } + } diff --git a/cps-ri/src/test/resources/data/anchor.sql b/cps-ri/src/test/resources/data/anchor.sql index 40fc44c0a..2ab7966e1 100644 --- a/cps-ri/src/test/resources/data/anchor.sql +++ b/cps-ri/src/test/resources/data/anchor.sql @@ -1,7 +1,7 @@ /* ============LICENSE_START======================================================= Copyright (C) 2020 Pantheon.tech - Modifications Copyright (C) 2020 Nordix Foundation. + Modifications Copyright (C) 2020-2023 Nordix Foundation. Modifications Copyright (C) 2021-2022 Bell Canada. ================================================================================ Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,8 @@ INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES (3001, 'ANCHOR-001', 1001, 2001), - (3002, 'ANCHOR-002', 1001, 2002); + (3002, 'ANCHOR-002', 1001, 2002), + (3003, 'ANCHOR-003', 1001, 2002); INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES (4001, 1001, 3001, null, '/xpath', '{}'); diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java index b0e68cf8f..fcf3f54cc 100755 --- a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2022 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 TechMahindra Ltd. @@ -84,7 +84,7 @@ public interface CpsAdminService { Collection<Anchor> getAnchors(String dataspaceName); /** - * Read all anchors associated the given schema-set in the given dataspace. + * Read all anchors associated with the given schema-set in the given dataspace. * * @param dataspaceName dataspace name * @param schemaSetName schema-set name @@ -93,6 +93,15 @@ public interface CpsAdminService { Collection<Anchor> getAnchors(String dataspaceName, String schemaSetName); /** + * Read all anchors associated with the given schema-sets in the given dataspace. + * + * @param dataspaceName dataspace name + * @param schemaSetNames schema-set names + * @return a collection of anchors + */ + Collection<Anchor> getAnchors(String dataspaceName, Collection<String> schemaSetNames); + + /** * Get an anchor in the given dataspace using the anchor name. * * @param dataspaceName dataspace name @@ -110,6 +119,14 @@ public interface CpsAdminService { void deleteAnchor(String dataspaceName, String anchorName); /** + * Delete anchors by name in given dataspace. + * + * @param dataspaceName dataspace name + * @param anchorNames anchor names + */ + void deleteAnchors(String dataspaceName, Collection<String> anchorNames); + + /** * Query anchor names for the given module names in the provided dataspace. * * @param dataspaceName dataspace name diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java index 9f96df2e4..39fa45ac1 100644 --- a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java @@ -230,6 +230,15 @@ public interface CpsDataService { void deleteDataNodes(String dataspaceName, String anchorName, OffsetDateTime observedTimestamp); /** + * Deletes all data nodes for multiple anchors in a dataspace. + * + * @param dataspaceName dataspace name + * @param anchorNames anchor names + * @param observedTimestamp observed timestamp + */ + void deleteDataNodes(String dataspaceName, Collection<String> anchorNames, OffsetDateTime observedTimestamp); + + /** * Deletes a list or a list-element under given anchor and dataspace. * * @param dataspaceName dataspace name diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java index b1f90d686..5ff08c9ac 100644 --- a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2022 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation * Modifications Copyright (C) 2020-2021 Pantheon.tech * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ @@ -80,13 +80,21 @@ public interface CpsModuleService { * @param dataspaceName dataspace name * @param schemaSetName schema set name * @param cascadeDeleteAllowed indicates the allowance to remove associated anchors and data if exist - * @throws DataInUseException if cascadeDeleteAllowed is set to CASCADE_DELETE_PROHIBITED and there - * is associated anchor record exists in database + * @throws DataInUseException if cascadeDeleteAllowed is set to CASCADE_DELETE_PROHIBITED and there + * is associated anchor record exists in database */ void deleteSchemaSet(String dataspaceName, String schemaSetName, CascadeDeleteAllowed cascadeDeleteAllowed); /** + * Deletes Schema Sets with cascade. + * + * @param dataspaceName dataspace name + * @param schemaSetNames schema set names + */ + void deleteSchemaSetsWithCascade(String dataspaceName, Collection<String> schemaSetNames); + + /** * Retrieve module references for the given dataspace name. * * @param dataspaceName dataspace name diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java index ece3eb95c..e286eea17 100755 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2022 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 TechMahindra Ltd. @@ -87,6 +87,13 @@ public class CpsAdminServiceImpl implements CpsAdminService { } @Override + public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> schemaSetNames) { + cpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(schemaSetNames); + return cpsAdminPersistenceService.getAnchors(dataspaceName, schemaSetNames); + } + + @Override public Anchor getAnchor(final String dataspaceName, final String anchorName) { cpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsAdminPersistenceService.getAnchor(dataspaceName, anchorName); @@ -100,6 +107,14 @@ public class CpsAdminServiceImpl implements CpsAdminService { } @Override + public void deleteAnchors(final String dataspaceName, final Collection<String> anchorNames) { + cpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(anchorNames); + cpsDataService.deleteDataNodes(dataspaceName, anchorNames, OffsetDateTime.now()); + cpsAdminPersistenceService.deleteAnchors(dataspaceName, anchorNames); + } + + @Override public Collection<String> queryAnchorNames(final String dataspaceName, final Collection<String> moduleNames) { cpsValidator.validateNameCharacters(dataspaceName); final Collection<Anchor> anchors = cpsAdminPersistenceService.queryAnchors(dataspaceName, moduleNames); diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java index b149d426e..721d4a9fb 100755 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java @@ -274,8 +274,8 @@ public class CpsDataServiceImpl implements CpsDataService { } @Override - @Timed(value = "cps.data.service.datanode.all.delete", - description = "Time taken to delete all datanodes") + @Timed(value = "cps.data.service.datanode.delete.anchor", + description = "Time taken to delete all datanodes for an anchor") public void deleteDataNodes(final String dataspaceName, final String anchorName, final OffsetDateTime observedTimestamp) { cpsValidator.validateNameCharacters(dataspaceName, anchorName); @@ -284,6 +284,19 @@ public class CpsDataServiceImpl implements CpsDataService { } @Override + @Timed(value = "cps.data.service.datanode.delete.anchor.batch", + description = "Time taken to delete all datanodes for multiple anchors") + public void deleteDataNodes(final String dataspaceName, final Collection<String> anchorNames, + final OffsetDateTime observedTimestamp) { + cpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(anchorNames); + for (final String anchorName : anchorNames) { + processDataUpdatedEventAsync(dataspaceName, anchorName, ROOT_NODE_XPATH, DELETE, observedTimestamp); + } + cpsDataPersistenceService.deleteDataNodes(dataspaceName, anchorNames); + } + + @Override @Timed(value = "cps.data.service.list.delete", description = "Time taken to delete a list or list element") public void deleteListOrListElement(final String dataspaceName, final String anchorName, final String listNodeXpath, diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java index ccd0fcc28..d6c01f7a9 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java @@ -26,6 +26,7 @@ package org.onap.cps.api.impl; import io.micrometer.core.annotation.Timed; import java.util.Collection; import java.util.Map; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.onap.cps.api.CpsAdminService; import org.onap.cps.api.CpsModuleService; @@ -95,7 +96,7 @@ public class CpsModuleServiceImpl implements CpsModuleService { @Override @Transactional public void deleteSchemaSet(final String dataspaceName, final String schemaSetName, - final CascadeDeleteAllowed cascadeDeleteAllowed) { + final CascadeDeleteAllowed cascadeDeleteAllowed) { cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); final Collection<Anchor> anchors = cpsAdminService.getAnchors(dataspaceName, schemaSetName); if (!anchors.isEmpty() && isCascadeDeleteProhibited(cascadeDeleteAllowed)) { @@ -110,6 +111,21 @@ public class CpsModuleServiceImpl implements CpsModuleService { } @Override + @Transactional + public void deleteSchemaSetsWithCascade(final String dataspaceName, final Collection<String> schemaSetNames) { + cpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(schemaSetNames); + final Collection<String> anchorNames = cpsAdminService.getAnchors(dataspaceName, schemaSetNames) + .stream().map(Anchor::getName).collect(Collectors.toSet()); + cpsAdminService.deleteAnchors(dataspaceName, anchorNames); + cpsModulePersistenceService.deleteUnusedYangResourceModules(); + cpsModulePersistenceService.deleteSchemaSets(dataspaceName, schemaSetNames); + for (final String schemaSetName : schemaSetNames) { + yangTextSchemaSourceSetCache.removeFromCache(dataspaceName, schemaSetName); + } + } + + @Override public Collection<ModuleReference> getYangResourceModuleReferences(final String dataspaceName) { cpsValidator.validateNameCharacters(dataspaceName); return cpsModulePersistenceService.getYangResourceModuleReferences(dataspaceName); diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java index 6bcb69844..1c1e80a20 100755 --- a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java +++ b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java @@ -73,7 +73,7 @@ public interface CpsAdminPersistenceService { void createAnchor(String dataspaceName, String schemaSetName, String anchorName); /** - * Read all anchors associated the given schema-set in the given dataspace. + * Read all anchors associated with the given schema-set in the given dataspace. * * @param dataspaceName dataspace name * @param schemaSetName schema-set name @@ -82,6 +82,15 @@ public interface CpsAdminPersistenceService { Collection<Anchor> getAnchors(String dataspaceName, String schemaSetName); /** + * Read all anchors associated with multiple schema-sets in the given dataspace. + * + * @param dataspaceName dataspace name + * @param schemaSetNames schema-set names + * @return a collection of anchors + */ + Collection<Anchor> getAnchors(String dataspaceName, Collection<String> schemaSetNames); + + /** * Read all anchors in the given a dataspace. * * @param dataspaceName dataspace name @@ -116,4 +125,12 @@ public interface CpsAdminPersistenceService { * @param anchorName anchor name */ void deleteAnchor(String dataspaceName, String anchorName); + + /** + * Delete anchors by name in given dataspace. + * + * @param dataspaceName dataspace name + * @param anchorNames anchor names + */ + void deleteAnchors(String dataspaceName, Collection<String> anchorNames); } diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java index 0b2cef9bd..90e6ec761 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java +++ b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java @@ -194,6 +194,14 @@ public interface CpsDataPersistenceService { void deleteDataNodes(String dataspaceName, String anchorName); /** + * Deletes all dataNodes in multiple anchors. + * + * @param dataspaceName dataspace name + * @param anchorNames anchor names + */ + void deleteDataNodes(String dataspaceName, Collection<String> anchorNames); + + /** * Deletes a single existing list element or the whole list. * * @param dataspaceName dataspace name diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java index f5dc8ac3a..40d4002b9 100755 --- a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java +++ b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2022 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ @@ -70,6 +70,14 @@ public interface CpsModulePersistenceService { void deleteSchemaSet(String dataspaceName, String schemaSetName); /** + * Deletes Schema Sets. + * + * @param dataspaceName dataspace name + * @param schemaSetNames schema set names + */ + void deleteSchemaSets(String dataspaceName, Collection<String> schemaSetNames); + + /** * Returns YANG resources per specific dataspace / schemaSetName. * * @param dataspaceName dataspace name diff --git a/cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java b/cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java index c7ce8fc92..231094cf1 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java +++ b/cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-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. @@ -28,4 +28,11 @@ public interface CpsValidator { * @param names names of data to be validated */ void validateNameCharacters(final String... names); + + /** + * Validate characters in names within cps. + * + * @param names names of data to be validated + */ + void validateNameCharacters(final Iterable<String> names); } diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy index e7d4e4ddb..4e0349d2b 100755 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2022 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 TechMahindra Ltd. @@ -79,6 +79,19 @@ class CpsAdminServiceImplSpec extends Specification { 1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someSchemaSet') } + def 'Retrieve all anchors for multiple schema-sets.'() { + given: 'that anchor is associated with the dataspace and schemasets' + def anchors = [new Anchor(), new Anchor()] + mockCpsAdminPersistenceService.getAnchors('someDataspace', _ as Collection<String>) >> anchors + when: 'get anchors is called for a dataspace name and schema set names' + def result = objectUnderTest.getAnchors('someDataspace', ['schemaSet1', 'schemaSet2']) + then: 'the collection provided by persistence service is returned as result' + result == anchors + and: 'the CpsValidator is called on the dataspace name and schema-set names' + 1 * mockCpsValidator.validateNameCharacters('someDataspace') + 1 * mockCpsValidator.validateNameCharacters(_) + } + def 'Retrieve anchor for dataspace and provided anchor name.'() { given: 'that anchor name is associated with the dataspace' Anchor anchor = new Anchor() @@ -118,6 +131,18 @@ class CpsAdminServiceImplSpec extends Specification { 1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someAnchor') } + def 'Delete multiple anchors.'() { + when: 'delete anchors is invoked' + objectUnderTest.deleteAnchors('someDataspace', ['anchor1', 'anchor2']) + then: 'delete data nodes is invoked on the data service with expected parameters' + 1 * mockCpsDataService.deleteDataNodes('someDataspace', _ as Collection<String>, _ as OffsetDateTime) + and: 'the persistence service method is invoked with same parameters to delete anchor' + 1 * mockCpsAdminPersistenceService.deleteAnchors('someDataspace',_ as Collection<String>) + and: 'the CpsValidator is called on the dataspace name and anchor names' + 1 * mockCpsValidator.validateNameCharacters('someDataspace') + 1 * mockCpsValidator.validateNameCharacters(_) + } + def 'Query all anchor identifiers for a dataspace and module names.'() { given: 'the persistence service is invoked with the expected parameters and returns a list of anchors' mockCpsAdminPersistenceService.queryAnchors('some-dataspace-name', ['some-module-name']) >> [new Anchor(name:'some-anchor-identifier')] diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy index 5a74d073a..e304d28d8 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy @@ -378,6 +378,19 @@ class CpsDataServiceImplSpec extends Specification { 1 * mockCpsDataPersistenceService.deleteDataNodes(dataspaceName, anchorName) } + def 'Delete all data nodes for given dataspace and multiple anchors.'() { + given: 'schema set for given anchors and dataspace references test tree model' + setupSchemaSetMocks('test-tree.yang') + when: 'delete data node method is invoked with correct parameters' + objectUnderTest.deleteDataNodes(dataspaceName, ['anchor1', 'anchor2'], observedTimestamp) + then: 'data updated events are sent to notification service before the delete' + 2 * mockNotificationService.processDataUpdatedEvent(dataspaceName, _, '/', Operation.DELETE, observedTimestamp) + and: 'the CpsValidator is called on the dataspace name and the anchor names' + 2 * mockCpsValidator.validateNameCharacters(_) + and: 'the persistence service method is invoked with the correct parameters' + 1 * mockCpsDataPersistenceService.deleteDataNodes(dataspaceName, _ as Collection<String>) + } + def setupSchemaSetMocks(String... yangResources) { def mockYangTextSchemaSourceSet = Mock(YangTextSchemaSourceSet) mockYangTextSchemaSourceSetCache.get(dataspaceName, schemaSetName) >> mockYangTextSchemaSourceSet diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy index 2bb0e63ab..3884eda66 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy @@ -167,6 +167,27 @@ class CpsModuleServiceImplSpec extends Specification { return anchors } + def 'Delete multiple schema-sets when cascade is allowed.'() { + given: '#numberOfAnchors anchors are associated with each schemaset' + mockCpsAdminService.getAnchors('my-dataspace', ['my-schemaset1', 'my-schemaset2']) >> createAnchors(numberOfAnchors * 2) + when: 'schema set deletion is requested with cascade allowed' + objectUnderTest.deleteSchemaSetsWithCascade('my-dataspace', ['my-schemaset1', 'my-schemaset2']) + then: 'anchor deletion is called #numberOfAnchors times' + mockCpsAdminService.deleteAnchors('my-dataspace', _) + and: 'persistence service method is invoked with same parameters' + mockCpsModulePersistenceService.deleteSchemaSets('my-dataspace', _) + and: 'schema sets will be removed from the cache' + 2 * mockYangTextSchemaSourceSetCache.removeFromCache('my-dataspace', _) + and: 'orphan yang resources are deleted' + 1 * mockCpsModulePersistenceService.deleteUnusedYangResourceModules() + and: 'the CpsValidator is called on the dataspaceName' + 1 * mockCpsValidator.validateNameCharacters('my-dataspace') + and: 'the CpsValidator is called on the schemaSetNames' + 1 * mockCpsValidator.validateNameCharacters(_) + where: 'following parameters are used' + numberOfAnchors << [0, 3] + } + def 'Get all yang resources module references.'() { given: 'an already present module reference' def moduleReferences = [new ModuleReference('some module name','some revision name')] |