From: ToineSiebelink Date: Thu, 30 Oct 2025 12:52:58 +0000 (+0000) Subject: Fix Modelloader failure when migration to new model is enabled X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F28%2F142328%2F1;p=cps.git Fix Modelloader failure when migration to new model is enabled - Ensure database not found exception is handled correctly when check for anchor exist - Consistent logging for all model loaders: starting with 'Model Loader#' (for easy tracing/demo) - Simplified names: remove 'coordinator' part in final model loader and associated lock - Cleaned up slogans of affect test class (no expectations is slogans!) Issue-ID: CPS-3030 Change-Id: If37fe22b22916df06e12892af82961364ff8eb86 Signed-off-by: ToineSiebelink --- diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java index 893d94ea47..2991e77f65 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java @@ -28,7 +28,7 @@ import org.onap.cps.api.CpsDataService; import org.onap.cps.api.CpsDataspaceService; import org.onap.cps.api.CpsModuleService; import org.onap.cps.init.AbstractModelLoader; -import org.onap.cps.init.ModelLoaderCoordinatorLock; +import org.onap.cps.init.ModelLoaderLock; import org.onap.cps.init.actuator.ReadinessManager; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; @@ -43,13 +43,13 @@ public class CmDataSubscriptionModelLoader extends AbstractModelLoader { private static final String ANCHOR_NAME = "cm-data-job-subscriptions"; private static final String REGISTRY_DATA_NODE_NAME = "dataJob"; - public CmDataSubscriptionModelLoader(final ModelLoaderCoordinatorLock modelLoaderCoordinatorLock, + public CmDataSubscriptionModelLoader(final ModelLoaderLock modelLoaderLock, final CpsDataspaceService cpsDataspaceService, final CpsModuleService cpsModuleService, final CpsAnchorService cpsAnchorService, final CpsDataService cpsDataService, final ReadinessManager readinessManager) { - super(modelLoaderCoordinatorLock, cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService, + super(modelLoaderLock, cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService, readinessManager); } @@ -68,7 +68,7 @@ public class CmDataSubscriptionModelLoader extends AbstractModelLoader { createSchemaSet(NCMP_DATASPACE_NAME, SCHEMA_SET_NAME, MODEL_FILE_NAME); createAnchor(NCMP_DATASPACE_NAME, SCHEMA_SET_NAME, ANCHOR_NAME); createTopLevelDataNode(NCMP_DATASPACE_NAME, ANCHOR_NAME, REGISTRY_DATA_NODE_NAME); - log.info("NCMP CM Data Notification Subscription Models onboarded successfully"); + log.info("Model Loader #3: NCMP CM Data Notification Subscription Models onboarded successfully"); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java index b64612b469..f20c1c53e7 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java @@ -30,7 +30,7 @@ import org.onap.cps.api.CpsDataService; import org.onap.cps.api.CpsDataspaceService; import org.onap.cps.api.CpsModuleService; import org.onap.cps.init.AbstractModelLoader; -import org.onap.cps.init.ModelLoaderCoordinatorLock; +import org.onap.cps.init.ModelLoaderLock; import org.onap.cps.init.actuator.ReadinessManager; import org.onap.cps.ncmp.utils.events.NcmpInventoryModelOnboardingFinishedEvent; import org.springframework.beans.factory.annotation.Value; @@ -56,14 +56,14 @@ public class InventoryModelLoader extends AbstractModelLoader { * Creates a new {@code InventoryModelLoader} instance responsible for onboarding or upgrading * the NCMP inventory model schema sets and managing readiness state during migration. */ - public InventoryModelLoader(final ModelLoaderCoordinatorLock modelLoaderCoordinatorLock, + public InventoryModelLoader(final ModelLoaderLock modelLoaderLock, final CpsDataspaceService cpsDataspaceService, final CpsModuleService cpsModuleService, final CpsAnchorService cpsAnchorService, final CpsDataService cpsDataService, final ApplicationEventPublisher applicationEventPublisher, final ReadinessManager readinessManager) { - super(modelLoaderCoordinatorLock, cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService, + super(modelLoaderLock, cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService, readinessManager); this.applicationEventPublisher = applicationEventPublisher; } @@ -78,10 +78,12 @@ public class InventoryModelLoader extends AbstractModelLoader { if (isModuleRevisionInstalled(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, INVENTORY_YANG_MODULE_NAME, moduleRevision)) { - log.info("Revision {} is already installed.", moduleRevision); + log.info("Model Loader #2: Revision {} is already installed.", moduleRevision); } else if (newRevisionEnabled && doesAnchorExist(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR)) { + log.info("Model Loader #2: Upgrading already installed inventory to revision {}.", moduleRevision); upgradeAndMigrateInventoryModel(); } else { + log.info("Model Loader #2: New installation using inventory model revision {}.", moduleRevision); installInventoryModel(schemaToInstall); } applicationEventPublisher.publishEvent(new NcmpInventoryModelOnboardingFinishedEvent(this)); @@ -99,7 +101,7 @@ public class InventoryModelLoader extends AbstractModelLoader { createAnchor(NCMP_DATASPACE_NAME, schemaSetName, NCMP_DMI_REGISTRY_ANCHOR); createTopLevelDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, INVENTORY_YANG_MODULE_NAME); deleteOldButNotThePreviousSchemaSets(); - log.info("Inventory model {} installed successfully,", schemaSetName); + log.info("Model Loader #2: Inventory model {} installed successfully,", schemaSetName); } private void deleteOldButNotThePreviousSchemaSets() { @@ -113,13 +115,14 @@ public class InventoryModelLoader extends AbstractModelLoader { createSchemaSet(NCMP_DATASPACE_NAME, NEW_INVENTORY_SCHEMA_SET_NAME, yangFileName); cpsAnchorService.updateAnchorSchemaSet(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NEW_INVENTORY_SCHEMA_SET_NAME); - log.info("Inventory upgraded successfully to model {}", NEW_INVENTORY_SCHEMA_SET_NAME); + log.info("Model Loader #2: Inventory upgraded successfully to model {}", NEW_INVENTORY_SCHEMA_SET_NAME); } private void performInventoryDataMigration() { + //1. Load all the cm handles (in batch) //2. Copy the state and known properties - log.info("Inventory module data migration is completed successfully."); + log.info("Model Loader #2: Inventory module data migration is completed successfully."); } private static String toYangFileName(final String schemaSetName) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy index 425dfb86b6..da06c178bb 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy @@ -28,7 +28,7 @@ import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsDataspaceService import org.onap.cps.api.CpsModuleService import org.onap.cps.api.model.Dataspace -import org.onap.cps.init.ModelLoaderCoordinatorLock +import org.onap.cps.init.ModelLoaderLock import org.onap.cps.init.actuator.ReadinessManager import org.slf4j.LoggerFactory import org.springframework.context.annotation.AnnotationConfigApplicationContext @@ -38,13 +38,13 @@ import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NA class CmDataSubscriptionModelLoaderSpec extends Specification { - def mockModelLoaderCoordinatorLock = Mock(ModelLoaderCoordinatorLock) + def mockModelLoaderLock = Mock(ModelLoaderLock) def mockCpsDataspaceService = Mock(CpsDataspaceService) def mockCpsModuleService = Mock(CpsModuleService) def mockCpsDataService = Mock(CpsDataService) def mockCpsAnchorService = Mock(CpsAnchorService) def mockReadinessManager = Mock(ReadinessManager) - def objectUnderTest = new CmDataSubscriptionModelLoader(mockModelLoaderCoordinatorLock, mockCpsDataspaceService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService, mockReadinessManager) + def objectUnderTest = new CmDataSubscriptionModelLoader(mockModelLoaderLock, mockCpsDataspaceService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService, mockReadinessManager) def applicationContext = new AnnotationConfigApplicationContext() diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy index b000099405..092ef2c363 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy @@ -30,7 +30,7 @@ import org.onap.cps.api.CpsModuleService import org.onap.cps.api.exceptions.AnchorNotFoundException import org.onap.cps.api.model.Dataspace import org.onap.cps.api.model.ModuleDefinition -import org.onap.cps.init.ModelLoaderCoordinatorLock +import org.onap.cps.init.ModelLoaderLock import org.onap.cps.init.actuator.ReadinessManager import org.slf4j.LoggerFactory import org.springframework.boot.context.event.ApplicationReadyEvent @@ -43,14 +43,14 @@ import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY class InventoryModelLoaderSpec extends Specification { - def mockModelLoaderCoordinatorLock = Mock(ModelLoaderCoordinatorLock) + def mockModelLoaderLock = Mock(ModelLoaderLock) def mockCpsAdminService = Mock(CpsDataspaceService) def mockCpsModuleService = Mock(CpsModuleService) def mockCpsDataService = Mock(CpsDataService) def mockCpsAnchorService = Mock(CpsAnchorService) def mockApplicationEventPublisher = Mock(ApplicationEventPublisher) def mockReadinessManager = Mock(ReadinessManager) - def objectUnderTest = new InventoryModelLoader(mockModelLoaderCoordinatorLock, mockCpsAdminService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService, mockApplicationEventPublisher, mockReadinessManager) + def objectUnderTest = new InventoryModelLoader(mockModelLoaderLock, mockCpsAdminService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService, mockApplicationEventPublisher, mockReadinessManager) def applicationContext = new AnnotationConfigApplicationContext() diff --git a/cps-service/src/main/java/org/onap/cps/init/AbstractModelLoader.java b/cps-service/src/main/java/org/onap/cps/init/AbstractModelLoader.java index 47f4701cab..b2391b9453 100644 --- a/cps-service/src/main/java/org/onap/cps/init/AbstractModelLoader.java +++ b/cps-service/src/main/java/org/onap/cps/init/AbstractModelLoader.java @@ -36,6 +36,7 @@ import org.onap.cps.api.CpsDataspaceService; import org.onap.cps.api.CpsModuleService; import org.onap.cps.api.exceptions.AlreadyDefinedException; import org.onap.cps.api.exceptions.AnchorNotFoundException; +import org.onap.cps.api.exceptions.DataspaceNotFoundException; import org.onap.cps.api.exceptions.DuplicatedYangResourceException; import org.onap.cps.api.exceptions.ModelOnboardingException; import org.onap.cps.api.model.ModuleDefinition; @@ -49,7 +50,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; @RequiredArgsConstructor public abstract class AbstractModelLoader implements ModelLoader { - protected final ModelLoaderCoordinatorLock modelLoaderCoordinatorLock; + protected final ModelLoaderLock modelLoaderLock; protected final CpsDataspaceService cpsDataspaceService; private final CpsModuleService cpsModuleService; protected final CpsAnchorService cpsAnchorService; @@ -133,12 +134,15 @@ public abstract class AbstractModelLoader implements ModelLoader { * * @param dataspaceName the name of the dataspace * @param anchorName the name of the anchor within the dataspace - * @return {@code true} if the anchor exists, {@code false} otherwise + * @return {@code true} if the dataspace and anchor exists, {@code false} otherwise */ public boolean doesAnchorExist(final String dataspaceName, final String anchorName) { try { cpsAnchorService.getAnchor(dataspaceName, anchorName); return true; + } catch (final DataspaceNotFoundException dataspaceNotFoundException) { + log.debug("Dataspace '{}' does not exist", dataspaceName); + return false; } catch (final AnchorNotFoundException anchorNotFoundException) { log.debug("Anchor '{}' not found in dataspace '{}'", anchorName, dataspaceName); return false; @@ -223,7 +227,7 @@ public abstract class AbstractModelLoader implements ModelLoader { } void checkIfThisInstanceIsMaster() { - isMaster = isMaster || modelLoaderCoordinatorLock.tryLock(); + isMaster = isMaster || modelLoaderLock.tryLock(); if (isMaster) { log.info("This instance is model loader master"); } else { diff --git a/cps-service/src/main/java/org/onap/cps/init/CpsNotificationSubscriptionModelLoader.java b/cps-service/src/main/java/org/onap/cps/init/CpsNotificationSubscriptionModelLoader.java index a9f2e820bf..d2c51c6bfa 100644 --- a/cps-service/src/main/java/org/onap/cps/init/CpsNotificationSubscriptionModelLoader.java +++ b/cps-service/src/main/java/org/onap/cps/init/CpsNotificationSubscriptionModelLoader.java @@ -41,13 +41,13 @@ public class CpsNotificationSubscriptionModelLoader extends AbstractModelLoader private static final String CPS_DATASPACE_NAME = "CPS-Admin"; private static final String REGISTRY_DATANODE_NAME = "dataspaces"; - public CpsNotificationSubscriptionModelLoader(final ModelLoaderCoordinatorLock modelLoaderCoordinatorLock, + public CpsNotificationSubscriptionModelLoader(final ModelLoaderLock modelLoaderLock, final CpsDataspaceService cpsDataspaceService, final CpsModuleService cpsModuleService, final CpsAnchorService cpsAnchorService, final CpsDataService cpsDataService, final ReadinessManager readinessManager) { - super(modelLoaderCoordinatorLock, cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService, + super(modelLoaderLock, cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService, readinessManager); } @@ -67,7 +67,7 @@ public class CpsNotificationSubscriptionModelLoader extends AbstractModelLoader createSchemaSet(CPS_DATASPACE_NAME, SCHEMA_SET_NAME, MODEL_FILENAME); createAnchor(CPS_DATASPACE_NAME, SCHEMA_SET_NAME, ANCHOR_NAME); createTopLevelDataNode(CPS_DATASPACE_NAME, ANCHOR_NAME, REGISTRY_DATANODE_NAME); - log.info("CPS Data Notification Subscription models onboarded successfully"); + log.info("Model Loader #1: CPS Data Notification Subscription models onboarded successfully"); } } diff --git a/cps-service/src/main/java/org/onap/cps/init/ModelLoaderCoordinatorLock.java b/cps-service/src/main/java/org/onap/cps/init/ModelLoaderLock.java similarity index 97% rename from cps-service/src/main/java/org/onap/cps/init/ModelLoaderCoordinatorLock.java rename to cps-service/src/main/java/org/onap/cps/init/ModelLoaderLock.java index dfccc0d49a..dd414a5b02 100644 --- a/cps-service/src/main/java/org/onap/cps/init/ModelLoaderCoordinatorLock.java +++ b/cps-service/src/main/java/org/onap/cps/init/ModelLoaderLock.java @@ -29,7 +29,7 @@ import org.springframework.stereotype.Service; @Slf4j @Service @RequiredArgsConstructor -public class ModelLoaderCoordinatorLock { +public class ModelLoaderLock { @Qualifier("cpsCommonLocks") private final IMap cpsCommonLocks; diff --git a/cps-service/src/main/java/org/onap/cps/init/ModelLoaderCoordinatorEnd.java b/cps-service/src/main/java/org/onap/cps/init/ModelLoadersCompletedCheck.java similarity index 64% rename from cps-service/src/main/java/org/onap/cps/init/ModelLoaderCoordinatorEnd.java rename to cps-service/src/main/java/org/onap/cps/init/ModelLoadersCompletedCheck.java index baf3fa2da9..f1fa6808bb 100644 --- a/cps-service/src/main/java/org/onap/cps/init/ModelLoaderCoordinatorEnd.java +++ b/cps-service/src/main/java/org/onap/cps/init/ModelLoadersCompletedCheck.java @@ -35,14 +35,14 @@ import org.springframework.stereotype.Service; @Slf4j @Service @Order(LOWEST_PRECEDENCE) -public class ModelLoaderCoordinatorEnd extends AbstractModelLoader { +public class ModelLoadersCompletedCheck extends AbstractModelLoader { final Sleeper sleeper; /** * Constructor. * - * @param modelLoaderCoordinatorLock the modelLoaderCoordinatorLock + * @param modelLoaderLock the modelLoaderCoordinatorLock * @param cpsDataspaceService the cpsDataspaceService * @param cpsModuleService the cpsModuleService * @param cpsAnchorService the cpsAnchorService @@ -50,39 +50,39 @@ public class ModelLoaderCoordinatorEnd extends AbstractModelLoader { * @param readinessManager the readinessManager * @param sleeper the sleeper */ - public ModelLoaderCoordinatorEnd(final ModelLoaderCoordinatorLock modelLoaderCoordinatorLock, - final CpsDataspaceService cpsDataspaceService, - final CpsModuleService cpsModuleService, - final CpsAnchorService cpsAnchorService, - final CpsDataService cpsDataService, - final ReadinessManager readinessManager, - final Sleeper sleeper) { - super(modelLoaderCoordinatorLock, cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService, + public ModelLoadersCompletedCheck(final ModelLoaderLock modelLoaderLock, + final CpsDataspaceService cpsDataspaceService, + final CpsModuleService cpsModuleService, + final CpsAnchorService cpsAnchorService, + final CpsDataService cpsDataService, + final ReadinessManager readinessManager, + final Sleeper sleeper) { + super(modelLoaderLock, cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService, readinessManager); this.sleeper = sleeper; } @Override public void onboardOrUpgradeModel() { - log.info("Model Loader #999 Started: Coordinator End, check model loaders are completed"); + log.info("Model Loader #LAST Started: Completion Check"); if (isMaster) { releaseLock(); - log.info("This instance is model loader master. Model loading completed"); + log.info("Model Loader #LAST: This instance is model loader master. Model loading completed"); } else { - log.info("Wait for model loader master to finish"); + log.info("Model Loader #LAST: Wait for model loading on master to finish"); waitForMasterToFinish(); } - log.info("Model Loader #999 Completed"); + log.info("Model Loader #LAST Completed"); } private void releaseLock() { - modelLoaderCoordinatorLock.forceUnlock(); - log.info("Model loading (on master) finished"); + modelLoaderLock.forceUnlock(); + log.info("Model Loader #LAST: Model loading (on master) finished"); } private void waitForMasterToFinish() { - while (modelLoaderCoordinatorLock.isLocked()) { - log.info("Still waiting for model loader master to finish"); + while (modelLoaderLock.isLocked()) { + log.info("Model Loader #LAST: Still waiting for model loading on master to finish"); try { sleeper.haveALittleRest(100); } catch (final InterruptedException e) { diff --git a/cps-service/src/test/groovy/org/onap/cps/init/AbstractModelLoaderSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/init/AbstractModelLoaderSpec.groovy index 1620b1a3be..f228262dab 100644 --- a/cps-service/src/test/groovy/org/onap/cps/init/AbstractModelLoaderSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/init/AbstractModelLoaderSpec.groovy @@ -30,6 +30,7 @@ import org.onap.cps.api.CpsDataspaceService import org.onap.cps.api.CpsModuleService import org.onap.cps.api.exceptions.AlreadyDefinedException import org.onap.cps.api.exceptions.AnchorNotFoundException +import org.onap.cps.api.exceptions.DataspaceNotFoundException import org.onap.cps.api.exceptions.DuplicatedYangResourceException import org.onap.cps.api.exceptions.ModelOnboardingException import org.onap.cps.api.model.ModuleDefinition @@ -43,13 +44,13 @@ import spock.lang.Specification class AbstractModelLoaderSpec extends Specification { - def mockModelLoaderCoordinatorLock = Mock(ModelLoaderCoordinatorLock) + def mockModelLoaderLock = Mock(ModelLoaderLock) def mockCpsDataspaceService = Mock(CpsDataspaceService) def mockCpsModuleService = Mock(CpsModuleService) def mockCpsDataService = Mock(CpsDataService) def mockCpsAnchorService = Mock(CpsAnchorService) def mockReadinessManager = Mock(ReadinessManager) - def objectUnderTest = Spy(new TestModelLoader(mockModelLoaderCoordinatorLock, mockCpsDataspaceService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService, mockReadinessManager)) + def objectUnderTest = Spy(new TestModelLoader(mockModelLoaderLock, mockCpsDataspaceService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService, mockReadinessManager)) def applicationContext = new AnnotationConfigApplicationContext() @@ -70,14 +71,14 @@ class AbstractModelLoaderSpec extends Specification { loggingListAppender.stop() } - def 'Application ready event triggers onboarding/upgrade'() { - when: 'Application (ready) event is triggered' + def 'Application ready.'() { + when: 'Application ready event is triggered' objectUnderTest.onApplicationEvent(Mock(ApplicationReadyEvent)) then: 'the onboard/upgrade method is executed' 1 * objectUnderTest.onboardOrUpgradeModel() } - def 'Application ready event handles startup exception'() { + def 'Application ready event with exception.'() { given: 'a startup exception is thrown during model onboarding' objectUnderTest.onboardOrUpgradeModel() >> { throw new ModelOnboardingException('test message','details are not logged') } when: 'Application (ready) event is triggered' @@ -87,14 +88,14 @@ class AbstractModelLoaderSpec extends Specification { assert logs.contains('test message') } - def 'Creating a dataspace delegates to the service.'() { + def 'Creating a dataspace.'() { when: 'creating a dataspace' objectUnderTest.createDataspace('some dataspace') then: 'the operation is delegated to the dataspace service' 1 * mockCpsDataspaceService.createDataspace('some dataspace') } - def 'Creating a dataspace handles already defined exception.'() { + def 'Creating a dataspace that already exists.'() { given: 'dataspace service throws an already defined exception' mockCpsDataspaceService.createDataspace(*_) >> { throw AlreadyDefinedException.forDataNodes([], 'some context') } when: 'creating a dataspace' @@ -105,7 +106,7 @@ class AbstractModelLoaderSpec extends Specification { assert logContains('Dataspace already exists') } - def 'Creating a dataspace handles other exception.'() { + def 'Attempt to create a dataspace with other exception.'() { given: 'dataspace service throws a runtime exception' mockCpsDataspaceService.createDataspace(*_) >> { throw new RuntimeException('test message') } when: 'creating a dataspace' @@ -116,14 +117,14 @@ class AbstractModelLoaderSpec extends Specification { assert thrown.details.contains('test message') } - def 'Creating a schema set delegates to the service.'() { + def 'Creating a schema set.'() { when: 'creating a schema set' objectUnderTest.createSchemaSet('some dataspace','new name','cps-notification-subscriptions@2024-07-03.yang') then: 'the operation is delegated to the module service' 1 * mockCpsModuleService.createSchemaSet('some dataspace','new name',_) } - def 'Creating a schema set handles duplicated yang resource exception'() { + def 'Creating a schema set with duplicated yang resource.'() { given: 'module service throws duplicated yang resource exception' mockCpsModuleService.createSchemaSet(*_) >> { throw new DuplicatedYangResourceException('my-yang-resource', 'my-yang-resource-checksum', null) } when: 'attempt to create a schema set' @@ -133,7 +134,7 @@ class AbstractModelLoaderSpec extends Specification { assert logContains('Ignoring yang resource duplication exception. Assuming model was created by another instance') } - def 'Creating a schema set handles already defined exception.'() { + def 'Creating a schema that already exists.'() { given: 'the module service throws an already defined exception' mockCpsModuleService.createSchemaSet(*_) >> { throw AlreadyDefinedException.forSchemaSet('name','context',null) } when: 'attempt to create a schema set' @@ -143,7 +144,7 @@ class AbstractModelLoaderSpec extends Specification { assert logContains('Creating new schema set failed as schema set already exists') } - def 'Creating a schema set from a non-existing YANG file.'() { + def 'Attempt to creating a schema set from a non-existing YANG file.'() { when: 'attempting to create a schema set from a non-existing file' objectUnderTest.createSchemaSet('some dataspace','some name','no such yang file') then: 'a startup exception with correct message and details is thrown' @@ -152,14 +153,14 @@ class AbstractModelLoaderSpec extends Specification { assert thrown.details.contains('unable to read file') } - def 'Creating an anchor delegates to the service.'() { + def 'Creating an anchor.'() { when: 'creating an anchor' objectUnderTest.createAnchor('some dataspace','some schema set','new name') then: 'the operation is delegated to the anchor service' 1 * mockCpsAnchorService.createAnchor('some dataspace','some schema set', 'new name') } - def 'Creating an anchor handles already defined exception.'() { + def 'Creating an anchor that already exists.'() { given: 'the anchor service throws an already defined exception' mockCpsAnchorService.createAnchor(*_)>> { throw AlreadyDefinedException.forAnchor('name','context',null) } when: 'attempting to create an anchor' @@ -169,7 +170,7 @@ class AbstractModelLoaderSpec extends Specification { assert logContains('Creating new anchor failed as anchor already exists') } - def 'Creating an anchor handles other exceptions.'() { + def 'Attempt to create an anchor with other exception.'() { given: 'the anchor service throws a runtime exception' mockCpsAnchorService.createAnchor(*_)>> { throw new RuntimeException('test message') } when: 'attempt to create anchor' @@ -180,14 +181,14 @@ class AbstractModelLoaderSpec extends Specification { assert thrown.details.contains('test message') } - def 'Creating a top-level data node delegates to the service.'() { + def 'Creating a top-level data node.'() { when: 'top-level node is created' objectUnderTest.createTopLevelDataNode('dataspace','anchor','new node') then: 'the correct JSON is saved using the data service' 1 * mockCpsDataService.saveData('dataspace','anchor', '{"new node":{}}',_) } - def 'Creating a top-level node handles already defined exception.'() { + def 'Creating a top-level node that already exists.'() { given: 'the data service throws an Already Defined exception' mockCpsDataService.saveData(*_) >> { throw AlreadyDefinedException.forDataNodes([], 'some context') } when: 'attempting to create a top-level node' @@ -197,7 +198,7 @@ class AbstractModelLoaderSpec extends Specification { assert logContains('failed as data node already exists') } - def 'Create a top-level node with any other exception.'() { + def 'Attempt to create a top-level node with other exception.'() { given: 'the data service throws a runtime exception' mockCpsDataService.saveData(*_) >> { throw new RuntimeException('test message') } when: 'attempt to create a top-level node' @@ -208,7 +209,7 @@ class AbstractModelLoaderSpec extends Specification { assert thrown.details.contains('test message') } - def 'Delete unused schema sets delegates to the service.'() { + def 'Delete unused schema sets.'() { when: 'unused schema sets get deleted' objectUnderTest.deleteUnusedSchemaSets('some dataspace','schema set 1', 'schema set 2') then: 'a request to delete each (without cascade) is delegated to the module service' @@ -247,7 +248,7 @@ class AbstractModelLoaderSpec extends Specification { assert thrown.details.contains('test message') } - def 'Checking if an anchor exists'() { + def 'Checking if an anchor exists.'() { given: 'the anchor service returns an anchor without throwing an exception' mockCpsAnchorService.getAnchor('my-dataspace', 'my-anchor') >> {} when: 'checking if the anchor exists' @@ -256,8 +257,8 @@ class AbstractModelLoaderSpec extends Specification { assert result == true } - def 'Checking if an anchor exists with unknown anchor'() { - given: 'the anchor service throws an exception' + def 'Checking if an anchor exists with unknown anchor.'() { + given: 'the anchor service throws an anchor not found exception' def anchorNotFoundException = new AnchorNotFoundException('my-dataspace', 'missing-anchor') mockCpsAnchorService.getAnchor('my-dataspace', 'missing-anchor') >> {throw anchorNotFoundException} when: 'checking if the anchor exists' @@ -266,7 +267,17 @@ class AbstractModelLoaderSpec extends Specification { assert result == false } - def 'Checking if module revision is installed when: #scenario'() { + def 'Checking if an anchor exists with unknown dataspace.'() { + given: 'the anchor service throws a dataspace not fond exception' + def dataspaceNotFoundException = new DataspaceNotFoundException ('missing-dataspace') + mockCpsAnchorService.getAnchor('missing-dataspace', 'some anchor') >> {throw dataspaceNotFoundException} + when: 'checking if the anchor exists' + def result = objectUnderTest.doesAnchorExist('missing-dataspace', 'some anchor') + then: 'the expected boolean value is returned' + assert result == false + } + + def 'Checking if module revision is installed when: #scenario.'() { given: 'the module service returns module definitions' mockCpsModuleService.getModuleDefinitionsByAnchorAndModule('some-dataspace', 'some-anchor', 'some-module', 'my-revision') >> moduleDefinitions when: 'checking if a module revision is installed' @@ -281,7 +292,7 @@ class AbstractModelLoaderSpec extends Specification { def 'Check if this instance is master when: #scenario.'() { given: 'the lock acquisition returns #lockAcquired' - mockModelLoaderCoordinatorLock.tryLock() >> lockAcquired + mockModelLoaderLock.tryLock() >> lockAcquired when: 'checking if this instance is master' objectUnderTest.checkIfThisInstanceIsMaster() then: 'the master status is set correctly' @@ -302,7 +313,7 @@ class AbstractModelLoaderSpec extends Specification { then: 'instance remains remains master' assert objectUnderTest.@isMaster == true and: 'no attempt is made to lock' - 0 * mockModelLoaderCoordinatorLock.tryLock() + 0 * mockModelLoaderLock.tryLock() and: 'log reports this instance is master' assert logContains('This instance is model loader master') } @@ -313,13 +324,13 @@ class AbstractModelLoaderSpec extends Specification { class TestModelLoader extends AbstractModelLoader { - TestModelLoader(final ModelLoaderCoordinatorLock modelLoaderCoordinatorLock, + TestModelLoader(final ModelLoaderLock modelLoaderLock, final CpsDataspaceService cpsDataspaceService, final CpsModuleService cpsModuleService, final CpsAnchorService cpsAnchorService, final CpsDataService cpsDataService, final ReadinessManager readinessManager) { - super(modelLoaderCoordinatorLock, cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService, readinessManager) + super(modelLoaderLock, cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService, readinessManager) } @Override diff --git a/cps-service/src/test/groovy/org/onap/cps/init/CpsNotificationSubscriptionModelLoaderSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/init/CpsNotificationSubscriptionModelLoaderSpec.groovy index 75c23c095a..01d4bccae1 100644 --- a/cps-service/src/test/groovy/org/onap/cps/init/CpsNotificationSubscriptionModelLoaderSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/init/CpsNotificationSubscriptionModelLoaderSpec.groovy @@ -40,8 +40,8 @@ class CpsNotificationSubscriptionModelLoaderSpec extends Specification { def mockCpsDataService = Mock(CpsDataService) def mockCpsAnchorService = Mock(CpsAnchorService) def mockReadinessManager = Mock(ReadinessManager) - def mockModelLoaderCoordinatorLock = Mock(ModelLoaderCoordinatorLock) - def objectUnderTest = new CpsNotificationSubscriptionModelLoader(mockModelLoaderCoordinatorLock, mockCpsDataspaceService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService, mockReadinessManager) + def mockModelLoaderLock = Mock(ModelLoaderLock) + def objectUnderTest = new CpsNotificationSubscriptionModelLoader(mockModelLoaderLock, mockCpsDataspaceService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService, mockReadinessManager) def applicationContext = new AnnotationConfigApplicationContext() diff --git a/cps-service/src/test/groovy/org/onap/cps/init/ModelLoaderCoordinatorLockSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/init/ModelLoaderLockSpec.groovy similarity index 90% rename from cps-service/src/test/groovy/org/onap/cps/init/ModelLoaderCoordinatorLockSpec.groovy rename to cps-service/src/test/groovy/org/onap/cps/init/ModelLoaderLockSpec.groovy index 37605f6583..b1a9e00342 100644 --- a/cps-service/src/test/groovy/org/onap/cps/init/ModelLoaderCoordinatorLockSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/init/ModelLoaderLockSpec.groovy @@ -25,16 +25,16 @@ import com.hazelcast.core.Hazelcast import com.hazelcast.instance.impl.HazelcastInstanceFactory import spock.lang.Specification -class ModelLoaderCoordinatorLockSpec extends Specification { +class ModelLoaderLockSpec extends Specification { def cpsCommonLocks = HazelcastInstanceFactory.getOrCreateHazelcastInstance(new Config('hazelcastInstanceName')).getMap('cpsCommonLocks') - def objectUnderTest = new ModelLoaderCoordinatorLock(cpsCommonLocks) + def objectUnderTest = new ModelLoaderLock(cpsCommonLocks) def cleanupSpec() { Hazelcast.getHazelcastInstanceByName('hazelcastInstanceName').shutdown() } - def 'Locking and unlocking the coordinator lock.'() { + def 'Locking and unlocking the model loader lock.'() { when: 'try to get a lock' assert objectUnderTest.tryLock() == true then: 'the lock is acquired' diff --git a/cps-service/src/test/groovy/org/onap/cps/init/ModelLoaderCoordinatorEndSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/init/ModelLoadersCompletedCheckSpec.groovy similarity index 72% rename from cps-service/src/test/groovy/org/onap/cps/init/ModelLoaderCoordinatorEndSpec.groovy rename to cps-service/src/test/groovy/org/onap/cps/init/ModelLoadersCompletedCheckSpec.groovy index 3ed95a66ca..2f1b28147e 100644 --- a/cps-service/src/test/groovy/org/onap/cps/init/ModelLoaderCoordinatorEndSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/init/ModelLoadersCompletedCheckSpec.groovy @@ -24,41 +24,41 @@ import org.onap.cps.init.actuator.ReadinessManager import org.onap.cps.utils.Sleeper import spock.lang.Specification -class ModelLoaderCoordinatorEndSpec extends Specification { +class ModelLoadersCompletedCheckSpec extends Specification { - def mockModelLoaderCoordinatorLock = Mock(ModelLoaderCoordinatorLock) + def mockModelLoaderLock = Mock(ModelLoaderLock) def spiedSleeper = Spy(new Sleeper()) def mockReadinessManager = Mock(ReadinessManager) - def objectUnderTest = new ModelLoaderCoordinatorEnd(mockModelLoaderCoordinatorLock, null, null, null, null, mockReadinessManager, spiedSleeper) + def objectUnderTest = new ModelLoadersCompletedCheck(mockModelLoaderLock, null, null, null, null, mockReadinessManager, spiedSleeper) - def 'Model Loader Coordinator End for master instance.'() { + def 'Model Loaders Completed Check for master instance.'() { given: 'instance is master' objectUnderTest.isMaster = true when: 'model loader is started' objectUnderTest.onboardOrUpgradeModel() - then: 'the model loader coordinator lock is released' - 1 * mockModelLoaderCoordinatorLock.forceUnlock() + then: 'the model loader lock is released' + 1 * mockModelLoaderLock.forceUnlock() and: 'no checks for locked are made' - 0 * mockModelLoaderCoordinatorLock.isLocked() + 0 * mockModelLoaderLock.isLocked() } - def 'Model Loader Coordinator End for non-master instance.'() { + def 'Model Loaders Completed Check for non-master instance.'() { given: 'instance is NOT master' objectUnderTest.isMaster = false and: 'the lock will be unlocked upon the third time checking (so expect 3 calls)' - 3 * mockModelLoaderCoordinatorLock.isLocked() >>> [ true, true, false ] + 3 * mockModelLoaderLock.isLocked() >>> [true, true, false ] when: 'model loader is started' objectUnderTest.onboardOrUpgradeModel() then: 'the system sleeps twice' 2 * spiedSleeper.haveALittleRest(_) } - def 'Model Loader Coordinator End for non-master with exception during sleep.'() { + def 'Model Loaders Completed Check for non-master with exception during sleep.'() { given: 'instance is NOT master' objectUnderTest.isMaster = false and: 'attempting the get the lock will succeed on the second attempt' - mockModelLoaderCoordinatorLock.isLocked() >>> [ true, false ] + mockModelLoaderLock.isLocked() >>> [true, false ] when: 'model loader is started' objectUnderTest.onboardOrUpgradeModel() then: 'the system sleeps once (but is interrupted)'