From 5427ef054effb1aadfaaab300282545c99c37a61 Mon Sep 17 00:00:00 2001 From: Renu Kumari Date: Thu, 20 Jan 2022 12:07:38 -0500 Subject: Refactored Delete SchemaSet functionality - Added get anchors by schemaset in cpsAdminService - Changed DeleteSchemaSet functionality - Use CPSAdminService to getAnchors associated with schemaset - Use CPSAdminService to delete Anchors - Moved Cascade allowed validation into Service from Persistence Issue-ID: CPS-791 Signed-off-by: Renu Kumari Change-Id: Ife7644551183cb8c3eb686a654b0a43a427ac1e5 --- .../spi/impl/CpsAdminPersistenceServiceImpl.java | 19 +++++++-- .../spi/impl/CpsModulePersistenceServiceImpl.java | 25 +++++------ .../spi/impl/CpsAdminPersistenceServiceSpec.groovy | 43 +++++++++++++++---- ...sModulePersistenceServiceIntegrationSpec.groovy | 49 ++++++++-------------- cps-ri/src/test/resources/data/anchor.sql | 6 +-- 5 files changed, 80 insertions(+), 62 deletions(-) (limited to 'cps-ri/src') 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 9c69006ec..51b248295 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,7 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020 Nordix Foundation. - * Modifications Copyright (C) 2020 Bell Canada. + * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,6 +30,7 @@ import javax.transaction.Transactional; import org.onap.cps.spi.CpsAdminPersistenceService; import org.onap.cps.spi.entities.AnchorEntity; import org.onap.cps.spi.entities.DataspaceEntity; +import org.onap.cps.spi.entities.SchemaSetEntity; import org.onap.cps.spi.entities.YangResourceModuleReference; import org.onap.cps.spi.exceptions.AlreadyDefinedException; import org.onap.cps.spi.exceptions.DataspaceInUseException; @@ -77,12 +78,12 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic final int numberOfAssociatedAnchors = anchorRepository.countByDataspace(dataspaceEntity); if (numberOfAssociatedAnchors != 0) { throw new DataspaceInUseException(dataspaceName, - String.format("Dataspace contains %d anchor(s)", numberOfAssociatedAnchors)); + String.format("Dataspace contains %d anchor(s)", numberOfAssociatedAnchors)); } final int numberOfAssociatedSchemaSets = schemaSetRepository.countByDataspace(dataspaceEntity); if (numberOfAssociatedSchemaSets != 0) { throw new DataspaceInUseException(dataspaceName, - String.format("Dataspace contains %d schemaset(s)", numberOfAssociatedSchemaSets)); + String.format("Dataspace contains %d schemaset(s)", numberOfAssociatedSchemaSets)); } dataspaceRepository.delete(dataspaceEntity); } @@ -108,7 +109,17 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic public Collection getAnchors(final String dataspaceName) { final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName); final Collection anchorEntities = anchorRepository.findAllByDataspace(dataspaceEntity); - return anchorEntities.stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toList()); + return anchorEntities.stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet()); + } + + @Override + public Collection getAnchors(final String dataspaceName, final String schemaSetName) { + final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); + final SchemaSetEntity schemaSetEntity = schemaSetRepository.getByDataspaceAndName( + dataspaceEntity, schemaSetName); + return anchorRepository.findAllBySchemaSet(schemaSetEntity) + .stream().map(CpsAdminPersistenceServiceImpl::toAnchor) + .collect(Collectors.toSet()); } @Override 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 e0f54265a..3e39a05c5 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,7 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020 Nordix Foundation - * Modifications Copyright (C) 2020-2021 Bell Canada. + * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,17 +44,14 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.hibernate.exception.ConstraintViolationException; -import org.onap.cps.spi.CascadeDeleteAllowed; import org.onap.cps.spi.CpsAdminPersistenceService; import org.onap.cps.spi.CpsModulePersistenceService; -import org.onap.cps.spi.entities.AnchorEntity; import org.onap.cps.spi.entities.SchemaSetEntity; import org.onap.cps.spi.entities.YangResourceEntity; import org.onap.cps.spi.entities.YangResourceModuleReference; import org.onap.cps.spi.exceptions.AlreadyDefinedException; import org.onap.cps.spi.exceptions.DuplicatedYangResourceException; import org.onap.cps.spi.exceptions.ModelValidationException; -import org.onap.cps.spi.exceptions.SchemaSetInUseException; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.spi.repository.AnchorRepository; import org.onap.cps.spi.repository.DataspaceRepository; @@ -172,21 +169,16 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ @Override @Transactional - public void deleteSchemaSet(final String dataspaceName, final String schemaSetName, - final CascadeDeleteAllowed cascadeDeleteAllowed) { + public void deleteSchemaSet(final String dataspaceName, final String schemaSetName) { final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName); final var schemaSetEntity = schemaSetRepository.getByDataspaceAndName(dataspaceEntity, schemaSetName); - - final Collection anchorEntities = anchorRepository.findAllBySchemaSet(schemaSetEntity); - if (!anchorEntities.isEmpty()) { - if (cascadeDeleteAllowed != CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED) { - throw new SchemaSetInUseException(dataspaceName, schemaSetName); - } - fragmentRepository.deleteByAnchorIn(anchorEntities); - anchorRepository.deleteAll(anchorEntities); - } schemaSetRepository.delete(schemaSetEntity); + } + + @Override + @Transactional + public void deleteUnusedYangResourceModules() { yangResourceRepository.deleteOrphans(); } @@ -277,6 +269,7 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ /** * Convert the specified data integrity violation exception into a CPS duplicated Yang resource exception * if the cause of the error is a yang checksum database constraint violation. + * * @param originalException the original db exception. * @param yangResourceEntities the collection of Yang resources involved in the db failure. * @return an optional converted CPS duplicated Yang resource exception. The optional is empty if the original @@ -307,6 +300,7 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ /** * Get the name of the yang resource having the specified checksum. + * * @param checksum the checksum. Null is supported. * @param yangResourceEntities the list of yang resources to search among. * @return the name found or null if none. @@ -323,6 +317,7 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ /** * Get the checksum that caused the constraint violation exception. + * * @param exception the exception having the checksum in error. * @return the checksum in error or null if not found. */ 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 4b5b116f4..2218014ec 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 @@ -2,6 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2021 Nordix Foundation * Modifications Copyright (C) 2021 Pantheon.tech + * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +40,7 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { static final String SET_DATA = '/data/anchor.sql' static final String SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES = '/data/anchors-schemaset-modules.sql' - static final String DATASPACE_WITH_NO_DATA = 'DATASPACE-002' + static final String DATASPACE_WITH_NO_DATA = 'DATASPACE-002-NO-DATA' static final Integer DELETED_ANCHOR_ID = 3001 static final Long DELETED_FRAGMENT_ID = 4001 @@ -108,12 +109,36 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { result.size() == expectedAnchors.size() result.containsAll(expectedAnchors) 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()] + 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()] DATASPACE_WITH_NO_DATA || [] } + @Sql([CLEAR_DATA, SET_DATA]) + def 'Get all anchors associated with schemaset in a dataspace.'() { + when: 'anchors are retrieved by dataspace and schema-set' + def anchors = objectUnderTest.getAnchors(dataspace, schemasetName) + then: ' the response contains expected anchors' + anchors == expectedAnchors + where: + scenario | dataspace | schemasetName || expectedAnchors + 'no-anchors' | 'DATASPACE-003' | 'SCHEMA-SET-002-NO-ANCHORS' || Collections.emptySet() + 'one-anchor' | 'DATASPACE-001' | 'SCHEMA-SET-001' || Set.of(new Anchor('ANCHOR-001', 'DATASPACE-001', 'SCHEMA-SET-001')) + } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Error Handling: Get all anchors associated with schemaset in a dataspace.'() { + when: 'anchors are retrieved by dataspace and schema-set' + def anchors = objectUnderTest.getAnchors(dataspace, schemasetName) + then: ' an expected expception is thrown' + thrown(expectedException) + where: + scenario | dataspace | schemasetName || expectedException + 'unknown-dataspace' | 'unknown' | 'SCHEMA-SET-002-NO-ANCHORS' || DataspaceNotFoundException + 'unknown-schemaset' | 'DATASPACE-001' | 'unknown-schema-set' || SchemaSetNotFoundException + } + @Sql(CLEAR_DATA) def 'Get all anchors in unknown dataspace.'() { when: 'attempt to get all anchors in an unknown dataspace' @@ -132,7 +157,7 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { } @Sql([CLEAR_DATA, SET_DATA]) - def 'delete anchor error scenario: #scenario'(){ + def 'delete anchor error scenario: #scenario'() { when: 'delete anchor attempt is performed' objectUnderTest.deleteAnchor(dataspaceName, anchorName) then: 'an #expectedException is thrown' @@ -190,10 +215,10 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { def thrownException = thrown(expectedException) thrownException.details.contains(expectedMessageDetails) 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 schemasets' | 'DATASPACE-003' || DataspaceInUseException | 'contains 1 schemaset(s)' + 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 schemasets' | 'DATASPACE-003' || DataspaceInUseException | 'contains 1 schemaset(s)' } } 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 a223e7135..75d633026 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,7 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2021 Nordix Foundation - * Modifications Copyright (C) 2021 Bell Canada. + * Modifications Copyright (C) 2021-2022 Bell Canada. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -176,50 +176,37 @@ class CpsModulePersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase } @Sql([CLEAR_DATA, SET_DATA]) - def 'Delete schema set with cascade delete prohibited but no anchors using it'() { + def 'Delete schema set'() { when: 'a schema set is deleted with cascade-prohibited option' - objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NO_ANCHORS, - CASCADE_DELETE_PROHIBITED) + 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 - and: 'any orphaned (not used by any schema set anymore) yang resources are deleted' - def orphanedResourceId = 3100L - yangResourceRepository.findById(orphanedResourceId).isPresent() == false - and: 'any shared (still in use by other schema set) yang resources still persists' - def sharedResourceId = 3003L - yangResourceRepository.findById(sharedResourceId).isPresent() - } - - @Sql([CLEAR_DATA, SET_DATA]) - def 'Delete schema set with cascade allowed.'() { - when: 'a schema set is deleted with cascade-allowed option' - objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA, - CASCADE_DELETE_ALLOWED) - then: 'the schema set has been deleted' - schemaSetRepository - .findByDataspaceAndName(dataspaceEntity, SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA).isPresent() == false - and: 'the associated anchors are removed' - def associatedAnchorsIds = [ 6001, 6002 ] - associatedAnchorsIds.each {anchorRepository.findById(it).isPresent() == false } - and: 'the fragment(s) under those anchors are removed' - def fragmentUnderAnchor1Id = 7001L - fragmentRepository.findById(fragmentUnderAnchor1Id).isPresent() == false - and: 'the shared resources still persist' - def sharedResourceIds = [ 3003L, 3004L ] - sharedResourceIds.each {yangResourceRepository.findById(it).isPresent() } } @Sql([CLEAR_DATA, SET_DATA]) def 'Delete schema set error scenario: #scenario.'() { when: 'attempt to delete a schema set where #scenario' - objectUnderTest.deleteSchemaSet(dataspaceName, schemaSetName, CASCADE_DELETE_PROHIBITED) + objectUnderTest.deleteSchemaSet(dataspaceName, schemaSetName) then: 'an #expectedException is thrown' thrown(expectedException) where: 'the following data is used' scenario | dataspaceName | schemaSetName || expectedException 'dataspace does not exist' | 'unknown' | 'not-relevant' || DataspaceNotFoundException 'schema set does not exists' | DATASPACE_NAME | 'unknown' || SchemaSetNotFoundException - 'cascade prohibited but schema set in use' | DATASPACE_NAME | SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA || SchemaSetInUseException + } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Delete only orphan Yang Resources'() { + given: 'a schema set is deleted and and yang resource is not used anymore' + objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NO_ANCHORS) + when: 'orphan yang resources are deleted' + objectUnderTest.deleteUnusedYangResourceModules() + then: 'any orphaned (not used by any schema set anymore) yang resources are deleted' + def orphanedResourceId = 3100L + yangResourceRepository.findById(orphanedResourceId).isPresent() == false + and: 'any shared (still in use by other schema set) yang resources still persists' + def sharedResourceId = 3003L + yangResourceRepository.findById(sharedResourceId).isPresent() } def assertSchemaSetPersisted(expectedDataspaceName, diff --git a/cps-ri/src/test/resources/data/anchor.sql b/cps-ri/src/test/resources/data/anchor.sql index c9240f7fd..40fc44c0a 100644 --- a/cps-ri/src/test/resources/data/anchor.sql +++ b/cps-ri/src/test/resources/data/anchor.sql @@ -2,7 +2,7 @@ ============LICENSE_START======================================================= Copyright (C) 2020 Pantheon.tech Modifications Copyright (C) 2020 Nordix Foundation. - Modifications Copyright (C) 2021 Bell Canada. + Modifications Copyright (C) 2021-2022 Bell Canada. ================================================================================ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,13 +22,13 @@ INSERT INTO DATASPACE (ID, NAME) VALUES (1001, 'DATASPACE-001'), - (1002, 'DATASPACE-002'), + (1002, 'DATASPACE-002-NO-DATA'), (1003, 'DATASPACE-003'); INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES (2001, 'SCHEMA-SET-001', 1001), (2002, 'SCHEMA-SET-002', 1001), - (2003, 'SCHEMA-SET-002', 1003); + (2003, 'SCHEMA-SET-002-NO-ANCHORS', 1003); INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES (3001, 'ANCHOR-001', 1001, 2001), -- cgit 1.2.3-korg