diff --git a/community/flamingock-auditstore-couchbase/src/test/java/io/flamingock/store/couchbase/CouchbaseAuditStoreTest.java b/community/flamingock-auditstore-couchbase/src/test/java/io/flamingock/store/couchbase/CouchbaseAuditStoreTest.java index 6fb100269..3736a90f9 100644 --- a/community/flamingock-auditstore-couchbase/src/test/java/io/flamingock/store/couchbase/CouchbaseAuditStoreTest.java +++ b/community/flamingock-auditstore-couchbase/src/test/java/io/flamingock/store/couchbase/CouchbaseAuditStoreTest.java @@ -90,7 +90,7 @@ void happyPath() { CouchbaseTargetSystem couchbaseTargetSystem = new CouchbaseTargetSystem("couchbase", cluster, BUCKET_NAME); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( new Trio<>(io.flamingock.store.couchbase.changes.happyPath._001__create_index.class, Collections.singletonList(Collection.class)), new Trio<>(io.flamingock.store.couchbase.changes.happyPath._002__insert_document.class, Collections.singletonList(Collection.class)), new Trio<>(_003__insert_another_document.class, Collections.singletonList(Collection.class))) @@ -143,7 +143,7 @@ void failedWithRollback() { CouchbaseTargetSystem couchbaseTargetSystem = new CouchbaseTargetSystem("couchbase", cluster, BUCKET_NAME); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( new Trio<>(io.flamingock.store.couchbase.changes.failedWithRollback._001__create_index.class, Collections.singletonList(Collection.class)), new Trio<>(io.flamingock.store.couchbase.changes.failedWithRollback._002__insert_document.class, Collections.singletonList(Collection.class)), new Trio<>(io.flamingock.store.couchbase.changes.failedWithRollback._003__execution_with_exception.class, Collections.singletonList(Collection.class), Collections.singletonList(Collection.class))) @@ -197,7 +197,7 @@ void failedWithoutRollback() { CouchbaseTargetSystem couchbaseTargetSystem = new CouchbaseTargetSystem("couchbase", cluster, BUCKET_NAME); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( new Trio<>(_001__create_index.class, Collections.singletonList(Collection.class)), new Trio<>(_002__insert_document.class, Collections.singletonList(Collection.class)), new Trio<>(_003__execution_with_exception.class, Collections.singletonList(Collection.class))) diff --git a/community/flamingock-auditstore-couchbase/src/test/java/io/flamingock/store/couchbase/PipelineTestHelper.java b/community/flamingock-auditstore-couchbase/src/test/java/io/flamingock/store/couchbase/PipelineTestHelper.java index dfbfa4ea3..cea55e751 100644 --- a/community/flamingock-auditstore-couchbase/src/test/java/io/flamingock/store/couchbase/PipelineTestHelper.java +++ b/community/flamingock-auditstore-couchbase/src/test/java/io/flamingock/store/couchbase/PipelineTestHelper.java @@ -17,6 +17,7 @@ import io.flamingock.api.StageType; import io.flamingock.api.annotations.TargetSystem; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.preview.PreviewConstructor; import io.flamingock.internal.common.core.task.RecoveryDescriptor; import io.flamingock.internal.common.core.task.TargetSystemDescriptor; @@ -70,7 +71,7 @@ private static List getParameterTypes(List> second) { * @return a {@link PreviewPipeline} ready for preview or testing */ @SafeVarargs - public static PreviewPipeline getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { List tasks = Arrays.stream(changeDefinitions) .map(trio -> { @@ -110,11 +111,12 @@ public static PreviewPipeline getPreviewPipeline(String stageName, Trio tasks ); - return new PreviewPipeline(Collections.singletonList(stage)); + PreviewPipeline previewPipeline = new PreviewPipeline(Collections.singletonList(stage)); + return new FlamingockMetadata(previewPipeline, null, null); } @SafeVarargs - public static PreviewPipeline getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { return getPreviewPipeline("default-stage-name", changeDefinitions); } diff --git a/community/flamingock-auditstore-sql/src/test/java/io/flamingock/store/sql/PipelineTestHelper.java b/community/flamingock-auditstore-sql/src/test/java/io/flamingock/store/sql/PipelineTestHelper.java index 7a9b6cd03..6ea16f64c 100644 --- a/community/flamingock-auditstore-sql/src/test/java/io/flamingock/store/sql/PipelineTestHelper.java +++ b/community/flamingock-auditstore-sql/src/test/java/io/flamingock/store/sql/PipelineTestHelper.java @@ -18,6 +18,7 @@ import io.flamingock.api.StageType; import io.flamingock.api.annotations.Change; import io.flamingock.api.annotations.TargetSystem; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.preview.CodePreviewChange; import io.flamingock.internal.common.core.preview.PreviewConstructor; import io.flamingock.internal.common.core.preview.PreviewMethod; @@ -70,7 +71,7 @@ private static List getParameterTypes(List> second) { * @return a {@link PreviewPipeline} ready for preview or testing */ @SafeVarargs - public static PreviewPipeline getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { List tasks = Arrays.stream(changeDefinitions) .map(trio -> { @@ -110,11 +111,12 @@ public static PreviewPipeline getPreviewPipeline(String stageName, Trio tasks ); - return new PreviewPipeline(Collections.singletonList(stage)); + PreviewPipeline previewPipeline = new PreviewPipeline(Collections.singletonList(stage)); + return new FlamingockMetadata(previewPipeline, null, null); } @SafeVarargs - public static PreviewPipeline getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { return getPreviewPipeline("default-stage-name", changeDefinitions); } diff --git a/community/flamingock-auditstore-sql/src/test/java/io/flamingock/store/sql/SqlAuditStoreTest.java b/community/flamingock-auditstore-sql/src/test/java/io/flamingock/store/sql/SqlAuditStoreTest.java index 32edb57f8..192ea6f11 100644 --- a/community/flamingock-auditstore-sql/src/test/java/io/flamingock/store/sql/SqlAuditStoreTest.java +++ b/community/flamingock-auditstore-sql/src/test/java/io/flamingock/store/sql/SqlAuditStoreTest.java @@ -286,7 +286,7 @@ void happyPathWithMockedPipeline(SqlDialect sqlDialect, String dialectName) thro try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { Class[] changeClasses = getChangeClasses(dialectName, "happyPath"); - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( new Trio<>(changeClasses[0], Collections.singletonList(Connection.class), null), new Trio<>(changeClasses[1], Collections.singletonList(Connection.class), null), new Trio<>(changeClasses[2], Collections.singletonList(Connection.class), null) @@ -360,7 +360,7 @@ void failedWithRollback(SqlDialect sqlDialect, String dialectName) throws Except try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { Class[] changeClasses = getChangeClasses(dialectName, "failedWithRollback"); - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( new Trio<>(changeClasses[0], Collections.singletonList(Connection.class), null), new Trio<>(changeClasses[1], Collections.singletonList(Connection.class), Collections.singletonList(Connection.class)), new Trio<>(changeClasses[2], Collections.singletonList(Connection.class), Collections.singletonList(Connection.class)) @@ -447,7 +447,7 @@ void failedWithoutRollback(SqlDialect sqlDialect, String dialectName) throws Exc try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { Class[] changeClasses = getChangeClasses(dialectName, "failedWithoutRollback"); - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( new Trio<>(changeClasses[0], Collections.singletonList(Connection.class), null), new Trio<>(changeClasses[1], Collections.singletonList(Connection.class), null), new Trio<>(changeClasses[2], Collections.singletonList(Connection.class), null) diff --git a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/discover/ChangeDiscoverer.java b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/discover/ChangeDiscoverer.java index a6e58da9a..a7a6fa703 100644 --- a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/discover/ChangeDiscoverer.java +++ b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/discover/ChangeDiscoverer.java @@ -20,8 +20,10 @@ import javax.annotation.processing.RoundEnvironment; import java.util.Collection; +import java.util.Map; public interface ChangeDiscoverer { - Collection findAnnotatedChanges(RoundEnvironment roundEnv, LoggerPreProcessor logger); + //TODO: move configuration properties to another interface + Collection findAnnotatedChanges(RoundEnvironment roundEnv, LoggerPreProcessor logger, Map properties); } diff --git a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/metadata/Constants.java b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/metadata/Constants.java index 7423641d2..b045a7f75 100644 --- a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/metadata/Constants.java +++ b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/metadata/Constants.java @@ -23,6 +23,9 @@ public final class Constants { public static final String DEFAULT_MONGOCK_ORIGIN = "mongockChangeLog"; + public static final String MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY = "internal.mongock.import.origin"; + public static final String MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY = "internal.mongock.import.emptyOriginAllowed"; + private Constants() {} } diff --git a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/metadata/FlamingockMetadata.java b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/metadata/FlamingockMetadata.java index b906db6df..cb5f5e2ce 100644 --- a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/metadata/FlamingockMetadata.java +++ b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/metadata/FlamingockMetadata.java @@ -17,18 +17,22 @@ import io.flamingock.internal.common.core.preview.PreviewPipeline; +import java.util.Map; + public class FlamingockMetadata { private PreviewPipeline pipeline; private String configFile; + private Map properties; private BuilderProviderInfo builderProvider; public FlamingockMetadata() { } - public FlamingockMetadata(PreviewPipeline pipeline, String configFile) { + public FlamingockMetadata(PreviewPipeline pipeline, String configFile, Map properties) { this.pipeline = pipeline; this.configFile = configFile; + this.properties = properties; } public PreviewPipeline getPipeline() { @@ -47,6 +51,14 @@ public void setPipelineFile(String configFile) { this.configFile = configFile; } + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + public BuilderProviderInfo getBuilderProvider() { return builderProvider; } diff --git a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/util/Deserializer.java b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/util/Deserializer.java index 11ff4b2a3..f934aaa29 100644 --- a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/util/Deserializer.java +++ b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/util/Deserializer.java @@ -17,7 +17,6 @@ import io.flamingock.internal.util.JsonObjectMapper; import io.flamingock.internal.common.core.metadata.Constants; -import io.flamingock.internal.common.core.preview.PreviewPipeline; import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.util.log.FlamingockLoggerFactory; import org.slf4j.Logger; @@ -30,7 +29,7 @@ public final class Deserializer { private static final Logger logger = FlamingockLoggerFactory.getLogger("Deserializer"); - private static final ClassLoader CLASS_LOADER = PreviewPipeline.class.getClassLoader(); + private static final ClassLoader CLASS_LOADER = FlamingockMetadata.class.getClassLoader(); private Deserializer() { @@ -42,22 +41,9 @@ public static FlamingockMetadata readMetadataFromFile() { } /** - * Reads the preview pipeline from file. It first tries to load the full pipeline, - * and if not found, falls back to the templated pipeline. + * Attempts to read a file and deserialize it into a FlamingockMetadata. * - * @return PreviewPipeline object if found - * @throws RuntimeException if neither file is found - */ - public static PreviewPipeline readPreviewPipelineFromFile() { - return readMetadataOptional() - .map(FlamingockMetadata::getPipeline) - .orElseThrow(() -> new RuntimeException("Flamingock metadata file not found")); - } - - /** - * Attempts to read a file and deserialize it into a PreviewPipeline. - * - * @return An Optional containing the deserialized PreviewPipeline if successful, otherwise empty + * @return An Optional containing the deserialized FlamingockMetadata if successful, otherwise empty */ private static Optional readMetadataOptional() { try (InputStream inputStream = CLASS_LOADER.getResourceAsStream(Constants.FULL_PIPELINE_FILE_PATH)) { diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/builder/AbstractChangeRunnerBuilder.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/builder/AbstractChangeRunnerBuilder.java index a88c34940..4b0f0aac3 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/builder/AbstractChangeRunnerBuilder.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/builder/AbstractChangeRunnerBuilder.java @@ -20,6 +20,7 @@ import io.flamingock.internal.common.core.context.ContextInjectable; import io.flamingock.internal.common.core.context.ContextResolver; import io.flamingock.internal.common.core.context.Dependency; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.template.ChangeTemplateManager; import io.flamingock.internal.core.configuration.EventLifecycleConfigurator; import io.flamingock.internal.core.configuration.core.CoreConfiguration; @@ -179,7 +180,7 @@ public HOLDER setApplicationArguments(String[] args) { * * * @return A fully configured Runner ready for execution - * @see #buildContext() for context merging details + * @see #buildContext(FlamingockMetadata) for context merging details * @see AuditStore#initialize(ContextResolver) for AuditStore initialization requirements * @see LoadedPipeline#contributeToContext(ContextInjectable) for pipeline contributions */ @@ -193,7 +194,9 @@ public final Runner build() { RunnerId runnerId = generateRunnerId(); - PriorityContext hierarchicalContext = buildContext(); + FlamingockMetadata flamingockMetadata = coreConfiguration.getFlamingockMetadata(); + + PriorityContext hierarchicalContext = buildContext(flamingockMetadata); configureStoreAndTargetSystem(hierarchicalContext); @@ -202,7 +205,7 @@ public final Runner build() { //Loads the pipeline //This contribution to the context is fine after components initialization as it's only used - LoadedPipeline pipeline = loadPipeline(); + LoadedPipeline pipeline = loadPipeline(flamingockMetadata); pipeline.contributeToContext(hierarchicalContext); FlamingockArguments flamingockArgs = FlamingockArguments.parse(applicationArgs); @@ -227,7 +230,7 @@ public final Runner build() { } - private LoadedPipeline loadPipeline() { + private LoadedPipeline loadPipeline(FlamingockMetadata flamingockMetadata) { List taskFiltersFromPlugins = pluginManager.getPlugins() .stream() .map(Plugin::getTaskFilters) @@ -236,14 +239,17 @@ private LoadedPipeline loadPipeline() { return LoadedPipeline.builder() .addFilters(taskFiltersFromPlugins) - .addPreviewPipeline(coreConfiguration.getPreviewPipeline()) + .addPreviewPipeline(flamingockMetadata.getPipeline()) .build(); } - private PriorityContext buildContext() { + private PriorityContext buildContext(FlamingockMetadata flamingockMetadata) { logger.trace("injecting internal configuration"); addDependency(coreConfiguration); addDependency(targetSystemManager); + if (flamingockMetadata != null && flamingockMetadata.getProperties() != null) { + flamingockMetadata.getProperties().forEach(this::setProperty); + } updateContextSpecific(); List dependencyContextsFromPlugins = pluginManager.getPlugins() .stream() diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/configuration/core/CoreConfigurable.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/configuration/core/CoreConfigurable.java index 2e5a08908..6cc0b23e3 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/configuration/core/CoreConfigurable.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/configuration/core/CoreConfigurable.java @@ -15,13 +15,14 @@ */ package io.flamingock.internal.core.configuration.core; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.preview.PreviewPipeline; import java.util.Map; public interface CoreConfigurable { - PreviewPipeline getPreviewPipeline(); + FlamingockMetadata getFlamingockMetadata(); void setLockAcquiredForMillis(long lockAcquiredForMillis); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/configuration/core/CoreConfiguration.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/configuration/core/CoreConfiguration.java index 56a9032d1..46d90f86d 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/configuration/core/CoreConfiguration.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/configuration/core/CoreConfiguration.java @@ -15,8 +15,8 @@ */ package io.flamingock.internal.core.configuration.core; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.util.Deserializer; -import io.flamingock.internal.common.core.preview.PreviewPipeline; import java.util.HashMap; import java.util.Map; @@ -50,8 +50,8 @@ public LockConfiguration getLockConfiguration() { } @Override - public PreviewPipeline getPreviewPipeline() { - return Deserializer.readPreviewPipelineFromFile(); + public FlamingockMetadata getFlamingockMetadata() { + return Deserializer.readMetadataFromFile(); } diff --git a/core/flamingock-processor/src/main/java/io/flamingock/core/processor/FlamingockAnnotationProcessor.java b/core/flamingock-processor/src/main/java/io/flamingock/core/processor/FlamingockAnnotationProcessor.java index 68ec17f7d..83646c775 100644 --- a/core/flamingock-processor/src/main/java/io/flamingock/core/processor/FlamingockAnnotationProcessor.java +++ b/core/flamingock-processor/src/main/java/io/flamingock/core/processor/FlamingockAnnotationProcessor.java @@ -207,7 +207,9 @@ public boolean process(Set annotations, RoundEnvironment AnnotationFinder annotationFinder = new AnnotationFinder(roundEnv, logger, processingEnv); EnableFlamingock flamingockAnnotation = annotationFinder.getPipelineAnnotation() .orElseThrow(() -> new RuntimeException("@EnableFlamingock annotation is mandatory. Please annotate a class with @EnableFlamingock to configure the pipeline.")); - Collection allChanges = annotationFinder.findAnnotatedChanges(); + //TODO: get configuration properties from another interface + Map properties = new HashMap<>(); + Collection allChanges = annotationFinder.findAnnotatedChanges(properties); // Find @FlamingockCliBuilder annotated method Optional builderProvider = annotationFinder.findBuilderProvider(); @@ -228,7 +230,7 @@ public boolean process(Set annotations, RoundEnvironment Serializer serializer = new Serializer(processingEnv, logger); String configFile = flamingockAnnotation.configFile(); - FlamingockMetadata flamingockMetadata = new FlamingockMetadata(pipeline, configFile); + FlamingockMetadata flamingockMetadata = new FlamingockMetadata(pipeline, configFile, properties); builderProvider.ifPresent(flamingockMetadata::setBuilderProvider); serializer.serializeFullPipeline(flamingockMetadata); diff --git a/core/flamingock-processor/src/main/java/io/flamingock/core/processor/discover/FlamingockChangeDiscoverer.java b/core/flamingock-processor/src/main/java/io/flamingock/core/processor/discover/FlamingockChangeDiscoverer.java index 17fb124a7..86cccd17b 100644 --- a/core/flamingock-processor/src/main/java/io/flamingock/core/processor/discover/FlamingockChangeDiscoverer.java +++ b/core/flamingock-processor/src/main/java/io/flamingock/core/processor/discover/FlamingockChangeDiscoverer.java @@ -25,6 +25,7 @@ import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; import java.util.Collection; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -32,7 +33,7 @@ public class FlamingockChangeDiscoverer implements ChangeDiscoverer { @Override - public Collection findAnnotatedChanges(RoundEnvironment roundEnv, LoggerPreProcessor logger) { + public Collection findAnnotatedChanges(RoundEnvironment roundEnv, LoggerPreProcessor logger, Map properties) { logger.info("Searching for code-based changes (Java classes annotated with @Change annotation)"); return roundEnv.getElementsAnnotatedWith(Change.class) .stream() diff --git a/core/flamingock-processor/src/main/java/io/flamingock/core/processor/util/AnnotationFinder.java b/core/flamingock-processor/src/main/java/io/flamingock/core/processor/util/AnnotationFinder.java index 12d48f275..6b306ed58 100644 --- a/core/flamingock-processor/src/main/java/io/flamingock/core/processor/util/AnnotationFinder.java +++ b/core/flamingock-processor/src/main/java/io/flamingock/core/processor/util/AnnotationFinder.java @@ -60,12 +60,12 @@ public Optional getPipelineAnnotation() { .findFirst(); } - public Collection findAnnotatedChanges() { + public Collection findAnnotatedChanges(Map properties) { logger.info("Searching for code-based changes"); return getAllChangeDiscoverers() .stream() .peek(cd -> logger.info(String.format("Using %s for discover changes", cd.getClass().getName()))) - .map(cd -> cd.findAnnotatedChanges(roundEnv, logger)) + .map(cd -> cd.findAnnotatedChanges(roundEnv, logger, properties)) .flatMap(Collection::stream) .collect(Collectors.toList()); } diff --git a/core/flamingock-test-support/src/test/java/io/flamingock/support/integration/FlamingockTestSupportIntegrationTest.java b/core/flamingock-test-support/src/test/java/io/flamingock/support/integration/FlamingockTestSupportIntegrationTest.java index abcc5e467..adf35e60f 100644 --- a/core/flamingock-test-support/src/test/java/io/flamingock/support/integration/FlamingockTestSupportIntegrationTest.java +++ b/core/flamingock-test-support/src/test/java/io/flamingock/support/integration/FlamingockTestSupportIntegrationTest.java @@ -41,7 +41,7 @@ class FlamingockTestSupportIntegrationTest { void shouldExecuteNonTransactionalChange() { try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -63,7 +63,7 @@ void shouldExecuteNonTransactionalChange() { void shouldVerifyMultipleChangesInSequence() { try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_003__MultiTest1NonTransactionalChange.class, Collections.emptyList()), new CodeChangeTestDefinition(_004__MultiTest2TransactionalChange.class, Collections.emptyList()) @@ -89,7 +89,7 @@ void shouldVerifyMultipleChangesInSequence() { void shouldVerifyFailingTransactionalChangeTriggersRollback() { try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_006__FailingTransactionalChange.class, Collections.emptyList(), Collections.emptyList()) ) @@ -116,7 +116,7 @@ void shouldVerifyFailingTransactionalChangeTriggersRollback() { void shouldVerifyAlreadyAppliedChangesAreSkipped() { try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_005__SecondRunNonTransactionalChange.class, Collections.emptyList()) ) @@ -148,7 +148,7 @@ void shouldVerifyDependencyInjectionInRollbackForNonTransactionalChanges() { .addDependency(counter); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_007__SimpleNonTransactionalChangeWithError.class, Collections.singletonList(Counter.class), @@ -177,7 +177,7 @@ void shouldVerifyDependencyInjectionInRollbackForNonTransactionalChanges() { void shouldVerifyTransactionalChangeExecutesSuccessfully() { try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_002__SimpleTransactionalChange.class, Collections.emptyList()) ) diff --git a/core/target-systems/couchbase-target-system/src/main/java/io/flamingock/targetsystem/couchbase/CouchbaseTargetSystem.java b/core/target-systems/couchbase-target-system/src/main/java/io/flamingock/targetsystem/couchbase/CouchbaseTargetSystem.java index b3e908aac..bf7ac4403 100644 --- a/core/target-systems/couchbase-target-system/src/main/java/io/flamingock/targetsystem/couchbase/CouchbaseTargetSystem.java +++ b/core/target-systems/couchbase-target-system/src/main/java/io/flamingock/targetsystem/couchbase/CouchbaseTargetSystem.java @@ -15,7 +15,6 @@ */ package io.flamingock.targetsystem.couchbase; -import com.couchbase.client.core.io.CollectionIdentifier; import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.transactions.TransactionAttemptContext; @@ -25,6 +24,7 @@ import io.flamingock.internal.common.core.audit.AuditReaderType; import io.flamingock.internal.common.core.context.ContextResolver; import io.flamingock.internal.common.core.error.FlamingockException; +import io.flamingock.internal.common.couchbase.CouchbaseUtils; import io.flamingock.internal.core.external.targets.TransactionalTargetSystem; import io.flamingock.internal.core.external.targets.mark.NoOpTargetSystemAuditMarker; import io.flamingock.internal.core.transaction.TransactionManager; @@ -34,14 +34,15 @@ import java.util.Optional; import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY; public class CouchbaseTargetSystem extends TransactionalTargetSystem implements CouchbaseExternalSystem { - private Cluster cluster; + private final Cluster cluster; + private final String bucketName; private Bucket bucket; - private String bucketName; - private String scopeName = CollectionIdentifier.DEFAULT_SCOPE; + private ContextResolver baseContext; private CouchbaseTxWrapper txWrapper; public CouchbaseTargetSystem(String id, Cluster cluster, String bucketName) { @@ -71,6 +72,7 @@ public TransactionManager getTxManager() { @Override public void initialize(ContextResolver baseContext) { + this.baseContext = baseContext; this.validate(); targetSystemContext.addDependency(cluster); bucket = cluster.bucket(bucketName); @@ -106,10 +108,16 @@ public TransactionWrapper getTxWrapper() { @Override public Optional getAuditAuditReader(AuditReaderType type) { if (Objects.requireNonNull(type) == MONGOCK) { - //TODO: Allow scope and collection to be parameterized - return Optional.of(new MongockImporterCouchbase(cluster, bucketName, CollectionIdentifier.DEFAULT_SCOPE, CollectionIdentifier.DEFAULT_COLLECTION)); + CouchbaseUtils.ScopeCollection scopeCollection = CouchbaseUtils.getOriginScopeAndCollection(getOriginPropertyValue()); + return Optional.of(new MongockImporterCouchbase(cluster, bucketName, scopeCollection.getScope(), scopeCollection.getCollection())); } else { return Optional.empty(); } } + + private String getOriginPropertyValue() { + return targetSystemContext.getProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY) + .orElse(baseContext.getProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY) + .orElse(null)); + } } diff --git a/core/target-systems/couchbase-target-system/src/test/java/io/flamingock/targetsystem/couchbase/CouchbaseTargetSystemTest.java b/core/target-systems/couchbase-target-system/src/test/java/io/flamingock/targetsystem/couchbase/CouchbaseTargetSystemTest.java index eb761a39d..1a16167e3 100644 --- a/core/target-systems/couchbase-target-system/src/test/java/io/flamingock/targetsystem/couchbase/CouchbaseTargetSystemTest.java +++ b/core/target-systems/couchbase-target-system/src/test/java/io/flamingock/targetsystem/couchbase/CouchbaseTargetSystemTest.java @@ -165,7 +165,7 @@ void happyPath() { //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__HappyCreateClientsCollectionChange.class, Collections.singletonList(Bucket.class)), new Trio<>(_002__HappyInsertClientsChange.class, Collections.singletonList(Bucket.class)) @@ -218,7 +218,7 @@ void failedTasks() { ).start(); //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__UnhappyCreateClientsCollectionChange.class, Collections.singletonList(Bucket.class)), new Trio<>(_002__UnhappyInsertClientsChange.class, Collections.singletonList(Bucket.class)) @@ -275,7 +275,7 @@ void shouldSendOngoingTaskInExecutionPlan() { //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__HappyCreateClientsCollectionChange.class, Collections.singletonList(Bucket.class)), new Trio<>(_002__HappyInsertClientsChange.class, Collections.singletonList(Bucket.class)) diff --git a/core/target-systems/couchbase-target-system/src/test/java/io/flamingock/targetsystem/couchbase/PipelineTestHelper.java b/core/target-systems/couchbase-target-system/src/test/java/io/flamingock/targetsystem/couchbase/PipelineTestHelper.java index 65c591479..8c996fffe 100644 --- a/core/target-systems/couchbase-target-system/src/test/java/io/flamingock/targetsystem/couchbase/PipelineTestHelper.java +++ b/core/target-systems/couchbase-target-system/src/test/java/io/flamingock/targetsystem/couchbase/PipelineTestHelper.java @@ -18,6 +18,7 @@ import io.flamingock.api.StageType; import io.flamingock.api.annotations.Change; import io.flamingock.api.annotations.TargetSystem; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.preview.CodePreviewChange; import io.flamingock.internal.common.core.preview.PreviewConstructor; import io.flamingock.internal.common.core.preview.PreviewMethod; @@ -71,7 +72,7 @@ private static List getParameterTypes(List> second) { * @return a {@link PreviewPipeline} ready for preview or testing */ @SafeVarargs - public static PreviewPipeline getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { List tasks = Arrays.stream(changeDefinitions) .map(trio -> { @@ -112,11 +113,12 @@ public static PreviewPipeline getPreviewPipeline(String stageName, Trio tasks ); - return new PreviewPipeline(Collections.singletonList(stage)); + PreviewPipeline previewPipeline = new PreviewPipeline(Collections.singletonList(stage)); + return new FlamingockMetadata(previewPipeline, null, null); } @SafeVarargs - public static PreviewPipeline getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { return getPreviewPipeline("default-stage-name", changeDefinitions); } diff --git a/core/target-systems/dynamodb-target-system/src/main/java/io/flamingock/targetsystem/dynamodb/DynamoDBTargetSystem.java b/core/target-systems/dynamodb-target-system/src/main/java/io/flamingock/targetsystem/dynamodb/DynamoDBTargetSystem.java index 757940c0a..bdb391e7d 100644 --- a/core/target-systems/dynamodb-target-system/src/main/java/io/flamingock/targetsystem/dynamodb/DynamoDBTargetSystem.java +++ b/core/target-systems/dynamodb-target-system/src/main/java/io/flamingock/targetsystem/dynamodb/DynamoDBTargetSystem.java @@ -34,11 +34,13 @@ import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK; import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY; public class DynamoDBTargetSystem extends TransactionalTargetSystem implements DynamoDBExternalSystem { - private DynamoDbClient client; + private final DynamoDbClient client; + private ContextResolver baseContext; private DynamoDBTxWrapper txWrapper; public DynamoDBTargetSystem(String id, DynamoDbClient dynamoDBClient) { @@ -57,6 +59,7 @@ public TransactionManager getTxManage @Override public void initialize(ContextResolver baseContext) { + this.baseContext = baseContext; this.validate(); targetSystemContext.addDependency(client); @@ -90,9 +93,15 @@ public TransactionWrapper getTxWrapper() { @Override public Optional getAuditAuditReader(AuditReaderType type) { if (Objects.requireNonNull(type) == MONGOCK) { - return Optional.of(new MongockImporterDynamoDB(client, DEFAULT_MONGOCK_ORIGIN)); + return Optional.of(new MongockImporterDynamoDB(client, getMongockOrigin())); } else { return Optional.empty(); } } + + private String getMongockOrigin() { + return targetSystemContext.getProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY) + .orElse(baseContext.getProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY) + .orElse(DEFAULT_MONGOCK_ORIGIN)); + } } diff --git a/core/target-systems/dynamodb-target-system/src/test/java/io/flamingock/targetsystem/dynamodb/DynamoDBCloudTargetSystemTest.java b/core/target-systems/dynamodb-target-system/src/test/java/io/flamingock/targetsystem/dynamodb/DynamoDBCloudTargetSystemTest.java index 24aa3d0a7..6c51d525b 100644 --- a/core/target-systems/dynamodb-target-system/src/test/java/io/flamingock/targetsystem/dynamodb/DynamoDBCloudTargetSystemTest.java +++ b/core/target-systems/dynamodb-target-system/src/test/java/io/flamingock/targetsystem/dynamodb/DynamoDBCloudTargetSystemTest.java @@ -147,7 +147,7 @@ void happyPath() { DynamoDBTargetSystem dynamoTargetSystem = new DynamoDBTargetSystem("dynamodb-ts", dynamoDBTestHelper.getDynamoDBClient()); //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__HappyCreateTableClientsChange.class, Collections.singletonList(DynamoDbClient.class)), new Trio<>(_002__HappyInsertClientsChange.class, Collections.singletonList(DynamoDbClient.class)) @@ -207,7 +207,7 @@ void failedTasks() { DynamoDBTargetSystem dynamoTargetSystem = new DynamoDBTargetSystem("dynamodb-ts", dynamoDBTestHelper.getDynamoDBClient()); //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__UnhappyCreateTableClientsChange.class, Collections.singletonList(DynamoDbClient.class)), new Trio<>(_002__UnhappyInsertionClientsChange.class, Collections.singletonList(DynamoDbClient.class)) @@ -267,7 +267,7 @@ void shouldSendOngoingTaskInExecutionPlan() { DynamoDBTargetSystem dynamoTargetSystem = new DynamoDBTargetSystem("dynamodb-ts", dynamoDBTestHelper.getDynamoDBClient()); //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__HappyCreateTableClientsChange.class, Collections.singletonList(DynamoDbClient.class)), new Trio<>(_002__HappyInsertClientsChange.class, Collections.singletonList(DynamoDbClient.class)) diff --git a/core/target-systems/dynamodb-target-system/src/test/java/io/flamingock/targetsystem/dynamodb/PipelineTestHelper.java b/core/target-systems/dynamodb-target-system/src/test/java/io/flamingock/targetsystem/dynamodb/PipelineTestHelper.java index 0a9e1d766..edd87da4b 100644 --- a/core/target-systems/dynamodb-target-system/src/test/java/io/flamingock/targetsystem/dynamodb/PipelineTestHelper.java +++ b/core/target-systems/dynamodb-target-system/src/test/java/io/flamingock/targetsystem/dynamodb/PipelineTestHelper.java @@ -17,6 +17,7 @@ import io.flamingock.api.StageType; import io.flamingock.api.annotations.TargetSystem; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.preview.PreviewConstructor; import io.flamingock.internal.common.core.task.RecoveryDescriptor; import io.flamingock.internal.common.core.task.TargetSystemDescriptor; @@ -71,7 +72,7 @@ private static List getParameterTypes(List> second) { * @return a {@link PreviewPipeline} ready for preview or testing */ @SafeVarargs - public static PreviewPipeline getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { List tasks = Arrays.stream(changeDefinitions) .map(trio -> { @@ -112,11 +113,12 @@ public static PreviewPipeline getPreviewPipeline(String stageName, Trio tasks ); - return new PreviewPipeline(Collections.singletonList(stage)); + PreviewPipeline previewPipeline = new PreviewPipeline(Collections.singletonList(stage)); + return new FlamingockMetadata(previewPipeline, null, null); } @SafeVarargs - public static PreviewPipeline getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { return getPreviewPipeline("default-stage-name", changeDefinitions); } diff --git a/core/target-systems/mongodb-springdata-target-system/src/main/java/io/flamingock/targetsystem/mongodb/springdata/MongoDBSpringDataTargetSystem.java b/core/target-systems/mongodb-springdata-target-system/src/main/java/io/flamingock/targetsystem/mongodb/springdata/MongoDBSpringDataTargetSystem.java index e23f6b1a7..ff4505188 100644 --- a/core/target-systems/mongodb-springdata-target-system/src/main/java/io/flamingock/targetsystem/mongodb/springdata/MongoDBSpringDataTargetSystem.java +++ b/core/target-systems/mongodb-springdata-target-system/src/main/java/io/flamingock/targetsystem/mongodb/springdata/MongoDBSpringDataTargetSystem.java @@ -35,6 +35,7 @@ import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK; import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY; public class MongoDBSpringDataTargetSystem extends TransactionalTargetSystem @@ -45,6 +46,7 @@ public class MongoDBSpringDataTargetSystem extends TransactionalTargetSystem getAuditAuditReader(AuditReaderType type) { if (Objects.requireNonNull(type) == MONGOCK) { - return Optional.of(new MongockImporterMongoDB(mongoTemplate.getDb(), DEFAULT_MONGOCK_ORIGIN)); + return Optional.of(new MongockImporterMongoDB(mongoTemplate.getDb(), getMongockOrigin())); } else { return Optional.empty(); } } + + private String getMongockOrigin() { + return targetSystemContext.getProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY) + .orElse(baseContext.getProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY) + .orElse(DEFAULT_MONGOCK_ORIGIN)); + } } diff --git a/core/target-systems/mongodb-springdata-target-system/src/test/java/io/flamingock/targetsystem/mongodb/springdata/MongoDBSpringDataTargetSystemTest.java b/core/target-systems/mongodb-springdata-target-system/src/test/java/io/flamingock/targetsystem/mongodb/springdata/MongoDBSpringDataTargetSystemTest.java index f603092fc..40678de09 100644 --- a/core/target-systems/mongodb-springdata-target-system/src/test/java/io/flamingock/targetsystem/mongodb/springdata/MongoDBSpringDataTargetSystemTest.java +++ b/core/target-systems/mongodb-springdata-target-system/src/test/java/io/flamingock/targetsystem/mongodb/springdata/MongoDBSpringDataTargetSystemTest.java @@ -156,7 +156,7 @@ void happyPath() { //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__HappyCreateClientsCollectionChange.class, Collections.singletonList(MongoDatabase.class)), new Trio<>(_002__HappyInsertClientsChange.class, Collections.singletonList(MongoDatabase.class)) @@ -209,7 +209,7 @@ void failedTasks() { ).start(); //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__UnhappyCreateClientsCollectionChange.class, Collections.singletonList(MongoDatabase.class)), new Trio<>(_002__UnhappyInsertClientsChange.class, Collections.singletonList(MongoDatabase.class)) @@ -270,7 +270,7 @@ void shouldSendOngoingTaskInExecutionPlan() { //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__HappyCreateClientsCollectionChange.class, Collections.singletonList(MongoDatabase.class)), new Trio<>(_002__HappyInsertClientsChange.class, Collections.singletonList(MongoDatabase.class)) diff --git a/core/target-systems/mongodb-springdata-target-system/src/test/java/io/flamingock/targetsystem/mongodb/springdata/PipelineTestHelper.java b/core/target-systems/mongodb-springdata-target-system/src/test/java/io/flamingock/targetsystem/mongodb/springdata/PipelineTestHelper.java index a42df684f..2e986ac53 100644 --- a/core/target-systems/mongodb-springdata-target-system/src/test/java/io/flamingock/targetsystem/mongodb/springdata/PipelineTestHelper.java +++ b/core/target-systems/mongodb-springdata-target-system/src/test/java/io/flamingock/targetsystem/mongodb/springdata/PipelineTestHelper.java @@ -17,6 +17,7 @@ import io.flamingock.api.StageType; import io.flamingock.api.annotations.TargetSystem; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.preview.PreviewConstructor; import io.flamingock.internal.common.core.task.RecoveryDescriptor; import io.flamingock.internal.common.core.task.TargetSystemDescriptor; @@ -71,7 +72,7 @@ private static List getParameterTypes(List> second) { * @return a {@link PreviewPipeline} ready for preview or testing */ @SafeVarargs - public static PreviewPipeline getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { List tasks = Arrays.stream(changeDefinitions) .map(trio -> { @@ -112,11 +113,12 @@ public static PreviewPipeline getPreviewPipeline(String stageName, Trio tasks ); - return new PreviewPipeline(Collections.singletonList(stage)); + PreviewPipeline previewPipeline = new PreviewPipeline(Collections.singletonList(stage)); + return new FlamingockMetadata(previewPipeline, null, null); } @SafeVarargs - public static PreviewPipeline getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { return getPreviewPipeline("default-stage-name", changeDefinitions); } diff --git a/core/target-systems/mongodb-sync-target-system/src/main/java/io/flamingock/targetsystem/mongodb/sync/MongoDBSyncTargetSystem.java b/core/target-systems/mongodb-sync-target-system/src/main/java/io/flamingock/targetsystem/mongodb/sync/MongoDBSyncTargetSystem.java index e93bd561b..20a8fe173 100644 --- a/core/target-systems/mongodb-sync-target-system/src/main/java/io/flamingock/targetsystem/mongodb/sync/MongoDBSyncTargetSystem.java +++ b/core/target-systems/mongodb-sync-target-system/src/main/java/io/flamingock/targetsystem/mongodb/sync/MongoDBSyncTargetSystem.java @@ -37,6 +37,7 @@ import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK; import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY; public class MongoDBSyncTargetSystem extends TransactionalTargetSystem implements MongoDBExternalSystem { @@ -47,6 +48,7 @@ public class MongoDBSyncTargetSystem extends TransactionalTargetSystem getTxManager() { @Override public void initialize(ContextResolver baseContext) { + this.baseContext = baseContext; this.validate(); targetSystemContext.addDependency(mongoClient); database = mongoClient.getDatabase(databaseName) @@ -154,9 +157,15 @@ public TransactionWrapper getTxWrapper() { @Override public Optional getAuditAuditReader(AuditReaderType type) { if (Objects.requireNonNull(type) == MONGOCK) { - return Optional.of(new MongockImporterMongoDB(database, DEFAULT_MONGOCK_ORIGIN)); + return Optional.of(new MongockImporterMongoDB(database, getMongockOrigin())); } else { return Optional.empty(); } } + + private String getMongockOrigin() { + return targetSystemContext.getProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY) + .orElse(baseContext.getProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY) + .orElse(DEFAULT_MONGOCK_ORIGIN)); + } } diff --git a/core/target-systems/mongodb-sync-target-system/src/test/java/io/flamingock/targetsystem/mongodb/sync/MongoDBSyncTargetSystemTest.java b/core/target-systems/mongodb-sync-target-system/src/test/java/io/flamingock/targetsystem/mongodb/sync/MongoDBSyncTargetSystemTest.java index cc860574a..12b004941 100644 --- a/core/target-systems/mongodb-sync-target-system/src/test/java/io/flamingock/targetsystem/mongodb/sync/MongoDBSyncTargetSystemTest.java +++ b/core/target-systems/mongodb-sync-target-system/src/test/java/io/flamingock/targetsystem/mongodb/sync/MongoDBSyncTargetSystemTest.java @@ -154,7 +154,7 @@ void happyPath() { //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__HappyCreateClientsCollectionChange.class, Collections.singletonList(MongoDatabase.class)), new Trio<>(_002__HappyInsertClientsChange.class, Collections.singletonList(MongoDatabase.class)) @@ -211,7 +211,7 @@ void failedTasks() { MongoDBSyncTargetSystem mongoSyncCloudTransactioner = Mockito.spy(mongoTargetSystem); //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__UnhappyCreateClientsCollectionChange.class, Collections.singletonList(MongoDatabase.class)), new Trio<>(_002__UnhappyInsertClientsChange.class, Collections.singletonList(MongoDatabase.class)) @@ -272,7 +272,7 @@ void shouldSendOngoingTaskInExecutionPlan() { //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__HappyCreateClientsCollectionChange.class, Collections.singletonList(MongoDatabase.class)), new Trio<>(_002__HappyInsertClientsChange.class, Collections.singletonList(MongoDatabase.class)) diff --git a/core/target-systems/mongodb-sync-target-system/src/test/java/io/flamingock/targetsystem/mongodb/sync/PipelineTestHelper.java b/core/target-systems/mongodb-sync-target-system/src/test/java/io/flamingock/targetsystem/mongodb/sync/PipelineTestHelper.java index 98efdf232..0e0ae0219 100644 --- a/core/target-systems/mongodb-sync-target-system/src/test/java/io/flamingock/targetsystem/mongodb/sync/PipelineTestHelper.java +++ b/core/target-systems/mongodb-sync-target-system/src/test/java/io/flamingock/targetsystem/mongodb/sync/PipelineTestHelper.java @@ -17,6 +17,7 @@ import io.flamingock.api.StageType; import io.flamingock.api.annotations.TargetSystem; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.preview.PreviewConstructor; import io.flamingock.internal.common.core.task.RecoveryDescriptor; import io.flamingock.internal.common.core.task.TargetSystemDescriptor; @@ -71,7 +72,7 @@ private static List getParameterTypes(List> second) { * @return a {@link PreviewPipeline} ready for preview or testing */ @SafeVarargs - public static PreviewPipeline getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { List tasks = Arrays.stream(changeDefinitions) .map(trio -> { @@ -112,11 +113,12 @@ public static PreviewPipeline getPreviewPipeline(String stageName, Trio tasks ); - return new PreviewPipeline(Collections.singletonList(stage)); + PreviewPipeline previewPipeline = new PreviewPipeline(Collections.singletonList(stage)); + return new FlamingockMetadata(previewPipeline, null, null); } @SafeVarargs - public static PreviewPipeline getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { return getPreviewPipeline("default-stage-name", changeDefinitions); } diff --git a/core/target-systems/sql-target-system/src/test/java/io/flamingock/targetsystem/sql/PipelineTestHelper.java b/core/target-systems/sql-target-system/src/test/java/io/flamingock/targetsystem/sql/PipelineTestHelper.java index 3c3554f81..4fc188eab 100644 --- a/core/target-systems/sql-target-system/src/test/java/io/flamingock/targetsystem/sql/PipelineTestHelper.java +++ b/core/target-systems/sql-target-system/src/test/java/io/flamingock/targetsystem/sql/PipelineTestHelper.java @@ -17,6 +17,7 @@ import io.flamingock.api.StageType; import io.flamingock.api.annotations.TargetSystem; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.preview.PreviewConstructor; import io.flamingock.internal.common.core.task.RecoveryDescriptor; import io.flamingock.internal.common.core.task.TargetSystemDescriptor; @@ -71,7 +72,7 @@ private static List getParameterTypes(List> second) { * @return a {@link PreviewPipeline} ready for preview or testing */ @SafeVarargs - public static PreviewPipeline getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(String stageName, Trio, List>, List>>... changeDefinitions) { List tasks = Arrays.stream(changeDefinitions) .map(trio -> { @@ -112,11 +113,12 @@ public static PreviewPipeline getPreviewPipeline(String stageName, Trio tasks ); - return new PreviewPipeline(Collections.singletonList(stage)); + PreviewPipeline previewPipeline = new PreviewPipeline(Collections.singletonList(stage)); + return new FlamingockMetadata(previewPipeline, null, null); } @SafeVarargs - public static PreviewPipeline getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(Trio, List>, List>>... changeDefinitions) { return getPreviewPipeline("default-stage-name", changeDefinitions); } diff --git a/core/target-systems/sql-target-system/src/test/java/io/flamingock/targetsystem/sql/SqlTargetSystemTest.java b/core/target-systems/sql-target-system/src/test/java/io/flamingock/targetsystem/sql/SqlTargetSystemTest.java index 638f64eb6..0c62eaa04 100644 --- a/core/target-systems/sql-target-system/src/test/java/io/flamingock/targetsystem/sql/SqlTargetSystemTest.java +++ b/core/target-systems/sql-target-system/src/test/java/io/flamingock/targetsystem/sql/SqlTargetSystemTest.java @@ -151,7 +151,7 @@ void happyPath() { ).start(); //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__HappyCreateClientsTableChange.class, Collections.singletonList(Connection.class), null), new Trio<>(_002__HappyInsertClientsChange.class, Collections.singletonList(Connection.class), null) @@ -199,7 +199,7 @@ void failedTasks() { ).start(); //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__UnhappyCreateClientsTableChange.class, Collections.singletonList(Connection.class), null), new Trio<>(_002__UnhappyInsertClientsChange.class, Collections.singletonList(Connection.class), Collections.singletonList(Connection.class)) @@ -248,7 +248,7 @@ void shouldSendOngoingTaskInExecutionPlan() { ).start(); //WHEN - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( + mocked.when(Deserializer::readMetadataFromFile).thenReturn(PipelineTestHelper.getPreviewPipeline( "stage-1", new Trio<>(_001__HappyCreateClientsTableChange.class, Collections.singletonList(Connection.class), null), new Trio<>(_002__HappyInsertClientsChange.class, Collections.singletonList(Connection.class), null) diff --git a/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/AuditPersistenceE2ETest.java b/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/AuditPersistenceE2ETest.java index 05624eb86..a237dfbca 100644 --- a/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/AuditPersistenceE2ETest.java +++ b/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/AuditPersistenceE2ETest.java @@ -75,7 +75,7 @@ void testCompleteAuditFieldPersistence() { LocalDateTime testStart = LocalDateTime.now(); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -121,7 +121,7 @@ void testDefaultTargetSystemIdPersistence() { String changeId = "test1-non-tx-change"; try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -151,7 +151,7 @@ void testCustomTargetSystemIdPersistence() { String changeId = "test-custom-target-change"; try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_002__CustomTargetSystemChange.class, Collections.emptyList()) ) @@ -182,7 +182,7 @@ void testBasicAuditFieldVariations() { String changeId2 = "test-custom-target-change"; try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()), new CodeChangeTestDefinition(_002__CustomTargetSystemChange.class, Collections.emptyList()) diff --git a/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/BuilderE2ETest.java b/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/BuilderE2ETest.java index feb5b6698..2d922a976 100644 --- a/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/BuilderE2ETest.java +++ b/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/BuilderE2ETest.java @@ -54,7 +54,7 @@ void shouldInjectTargetSystemManagerInChange() { .addDependency(counter); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition( _008__TargetSystemManagerInjectionChange.class, @@ -93,7 +93,7 @@ void shouldInjectTargetSystemIdInChange() { .addDependency(counter); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition( _009__TargetSystemIdInjectionChange.class, diff --git a/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/CoreStrategiesE2ETest.java b/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/CoreStrategiesE2ETest.java index 9ad9450b3..8e686999b 100644 --- a/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/CoreStrategiesE2ETest.java +++ b/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/CoreStrategiesE2ETest.java @@ -51,7 +51,7 @@ void testNonTransactionalChangeExecution() { AuditTestHelper auditHelper = testKit.getAuditHelper(); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -85,7 +85,7 @@ void testTransactionalChangeExecution() { AuditTestHelper auditHelper = testKit.getAuditHelper(); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_002__SimpleTransactionalChange.class, Collections.emptyList()) ) @@ -116,7 +116,7 @@ void testMultipleChangesExecution() { AuditTestHelper auditHelper = testKit.getAuditHelper(); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_003__MultiTest1NonTransactionalChange.class, Collections.emptyList()), new CodeChangeTestDefinition(_004__MultiTest2TransactionalChange.class, Collections.emptyList()) @@ -148,7 +148,7 @@ void testFailingTransactionalChangeWithRollback() { AuditTestHelper auditHelper = testKit.getAuditHelper(); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_006__FailingTransactionalChange.class, Collections.emptyList(), Collections.emptyList()) ) @@ -182,7 +182,7 @@ void testAlreadyAppliedChangesSkipping() { AuditTestHelper auditHelper = testKit.getAuditHelper(); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_005__SecondRunNonTransactionalChange.class, Collections.emptyList()) ) @@ -238,7 +238,7 @@ void testDependencyInjectionInRollbackForNonTxChange() { .addDependency(counter); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_007__SimpleNonTransactionalChangeWithError.class, Collections.singletonList(Counter.class), Collections.singletonList(Counter.class)) ) diff --git a/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/RecoveryE2ETest.java b/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/RecoveryE2ETest.java index cf9009583..3ea047b55 100644 --- a/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/RecoveryE2ETest.java +++ b/e2e/core-e2e/src/test/java/io/flamingock/core/e2e/RecoveryE2ETest.java @@ -113,7 +113,7 @@ void testExecutionFailedTxSharedSuccessfulExecution() { testKit.getAuditStorage().addAuditEntry(preExistingEntry); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -146,7 +146,7 @@ void testRolledBackNonTxSuccessfulExecution() { testKit.getAuditStorage().addAuditEntry(preExistingEntry); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -179,7 +179,7 @@ void testRolledBackTxSeparateNoMarkerSuccessfulExecution() { testKit.getAuditStorage().addAuditEntry(preExistingEntry); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -212,7 +212,7 @@ void testRolledBackTxSharedSuccessfulExecution() { testKit.getAuditStorage().addAuditEntry(preExistingEntry); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -245,7 +245,7 @@ void testRollbackFailedNonTxRequiresManualIntervention() { testKit.getAuditStorage().addAuditEntry(preExistingEntry); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -294,7 +294,7 @@ void testAppliedNonTxDoNothing() { testKit.getAuditStorage().addAuditEntry(preExistingEntry); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -325,7 +325,7 @@ void testAppliedTxSeparateNoMarkerDoNothing() { testKit.getAuditStorage().addAuditEntry(preExistingEntry); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -356,7 +356,7 @@ void testAppliedTxSharedDoNothing() { testKit.getAuditStorage().addAuditEntry(preExistingEntry); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(_001__SimpleNonTransactionalChange.class, Collections.emptyList()) ) @@ -466,7 +466,7 @@ private void testForRetry(String changeId, testKit.getAuditStorage().addAuditEntry(preExistingEntry); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(changeClass, Collections.emptyList()) ) @@ -500,7 +500,7 @@ private void testForManualInterventionException(String changeId, testKit.getAuditStorage().addAuditEntry(preExistingEntry); try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline( new CodeChangeTestDefinition(changeClass, Collections.emptyList()) ) diff --git a/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/CouchbaseImporterTest.java b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/CouchbaseImporterTest.java index df6bd126e..dc2101d9e 100644 --- a/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/CouchbaseImporterTest.java +++ b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/CouchbaseImporterTest.java @@ -46,13 +46,12 @@ import java.util.List; import java.util.stream.Collectors; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY; import static io.flamingock.internal.util.constants.AuditEntryFieldConstants.KEY_CREATED_AT; import static io.flamingock.internal.util.constants.AuditEntryFieldConstants.KEY_STATE; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; @Testcontainers @MongockSupport(targetSystem = "couchbase-target-system") @@ -201,10 +200,31 @@ void GIVEN_someChangeUnitsAlreadyExecuted_WHEN_migratingToFlamingockCommunity_TH @Test @DisplayName("GIVEN mongock audit history empty " + + "AND no empty origen allowed value provided " + "WHEN migrating to Flamingock Community" + "THEN should throw exception") - void GIVEN_mongockAuditHistoryEmpty_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { - // Setup Mongock entries + void GIVEN_mongockAuditHistoryEmptyAndNoFailIfEmptyOriginValueProvided_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { + + CouchbaseTargetSystem targetSystem = new CouchbaseTargetSystem("couchbase-target-system", cluster, FLAMINGOCK_BUCKET_NAME); + + Runner flamingock = FlamingockFactory.getCommunityBuilder() + .setAuditStore(CouchbaseAuditStore.from(targetSystem) + .withScopeName(FLAMINGOCK_SCOPE_NAME) + .withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME)) + .addTargetSystem(targetSystem) + .build(); + + FlamingockException ex = assertThrows(FlamingockException.class, flamingock::run); + assertEquals("No audit entries found when importing from 'couchbase-target-system'.", ex.getMessage()); + + } + + @Test + @DisplayName("GIVEN mongock audit history empty " + + "AND explicit empty origin allowed disabled " + + "WHEN migrating to Flamingock Community" + + "THEN should throw exception") + void GIVEN_mongockAuditHistoryEmptyAndFailIfEmptyOriginEnabled_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { CouchbaseTargetSystem targetSystem = new CouchbaseTargetSystem("couchbase-target-system", cluster, FLAMINGOCK_BUCKET_NAME); @@ -213,6 +233,7 @@ void GIVEN_mongockAuditHistoryEmpty_WHEN_migratingToFlamingockCommunity_THEN_sho .withScopeName(FLAMINGOCK_SCOPE_NAME) .withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME)) .addTargetSystem(targetSystem) + .setProperty(MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY, Boolean.FALSE.toString()) .build(); FlamingockException ex = assertThrows(FlamingockException.class, flamingock::run); @@ -220,6 +241,118 @@ void GIVEN_mongockAuditHistoryEmpty_WHEN_migratingToFlamingockCommunity_THEN_sho } + @Test + @DisplayName("GIVEN mongock audit history empty " + + "AND explicit empty origin allowed enabled " + + "WHEN migrating to Flamingock Community " + + "THEN should execute the pending Mongock changeUnits " + + "AND execute the pending flamingock changes") + void GIVEN_mongockAuditHistoryEmptyAndFailIfEmptyOriginDisabled_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { + + CouchbaseTargetSystem targetSystem = new CouchbaseTargetSystem("couchbase-target-system", cluster, FLAMINGOCK_BUCKET_NAME); + + Runner flamingock = FlamingockFactory.getCommunityBuilder() + .setAuditStore(CouchbaseAuditStore.from(targetSystem) + .withScopeName(FLAMINGOCK_SCOPE_NAME) + .withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME)) + .addTargetSystem(targetSystem) + .setProperty(MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY, Boolean.TRUE.toString()) + .build(); + + flamingock.run(); + + + List auditLog = getAuditLog(); + + assertEquals(8, auditLog.size()); + + assertEquals("migration-mongock-to-flamingock-community", auditLog.get(0).getString("changeId")); + assertEquals("STARTED", auditLog.get(0).getString("state")); + + assertEquals("migration-mongock-to-flamingock-community", auditLog.get(1).getString("changeId")); + assertEquals("APPLIED", auditLog.get(1).getString("state")); + + assertEquals("mongock-change-1", auditLog.get(2).getString("changeId")); + assertEquals("STARTED", auditLog.get(2).getString("state")); + + assertEquals("mongock-change-1", auditLog.get(3).getString("changeId")); + assertEquals("APPLIED", auditLog.get(3).getString("state")); + + assertEquals("mongock-change-2", auditLog.get(4).getString("changeId")); + assertEquals("STARTED", auditLog.get(4).getString("state")); + + assertEquals("mongock-change-2", auditLog.get(5).getString("changeId")); + assertEquals("APPLIED", auditLog.get(5).getString("state")); + + assertEquals("flamingock-change", auditLog.get(6).getString("changeId")); + assertEquals("STARTED", auditLog.get(6).getString("state")); + + assertEquals("flamingock-change", auditLog.get(7).getString("changeId")); + assertEquals("APPLIED", auditLog.get(7).getString("state")); + + } + + @Test + @DisplayName("GIVEN all Mongock changeUnits already executed" + + "AND custom origin repository name provided" + + "WHEN migrating to Flamingock Community " + + "THEN should import the entire history " + + "AND execute the pending flamingock changes") + void GIVEN_allMongockChangeUnitsAlreadyExecutedAndCustomOriginProvided_WHEN_migratingToFlamingockCommunity_THEN_shouldImportEntireHistory() { + // Setup Mongock entries + final String customMongockOriginScope = "mongockCustomScope"; + final String customMongockOriginCollection = "mongockCustomOriginCollection"; + final String customMongockOrigin = String.format("%s.%s", customMongockOriginScope, customMongockOriginCollection); + + CouchbaseCollectionHelper.createScopeIfNotExists(cluster, MONGOCK_BUCKET_NAME, customMongockOriginScope); + CouchbaseCollectionHelper.createCollectionIfNotExists(cluster, MONGOCK_BUCKET_NAME, customMongockOriginScope, customMongockOriginCollection); + CouchbaseCollectionHelper.createPrimaryIndexIfNotExists(cluster, MONGOCK_BUCKET_NAME, customMongockOriginScope, customMongockOriginCollection); + + Collection originCollection = cluster.bucket(MONGOCK_BUCKET_NAME).scope(customMongockOriginScope).collection(customMongockOriginCollection); + + originCollection.upsert("mongock-change-1", createAuditObject("mongock-change-1")); + + CouchbaseTargetSystem targetSystem = new CouchbaseTargetSystem("couchbase-target-system", cluster, FLAMINGOCK_BUCKET_NAME); + + Runner flamingock = FlamingockFactory.getCommunityBuilder() + .setAuditStore(CouchbaseAuditStore.from(targetSystem) + .withScopeName(FLAMINGOCK_SCOPE_NAME) + .withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME)) + .addTargetSystem(targetSystem) + .setProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY, customMongockOrigin) + .build(); + + flamingock.run(); + + + + List auditLog = getAuditLog(); + + assertEquals(7, auditLog.size()); + + assertEquals("mongock-change-1", auditLog.get(0).getString("changeId")); + assertEquals("APPLIED", auditLog.get(0).getString("state")); + + assertEquals("migration-mongock-to-flamingock-community", auditLog.get(1).getString("changeId")); + assertEquals("STARTED", auditLog.get(1).getString("state")); + + assertEquals("migration-mongock-to-flamingock-community", auditLog.get(2).getString("changeId")); + assertEquals("APPLIED", auditLog.get(2).getString("state")); + + assertEquals("mongock-change-2", auditLog.get(3).getString("changeId")); + assertEquals("STARTED", auditLog.get(3).getString("state")); + + assertEquals("mongock-change-2", auditLog.get(4).getString("changeId")); + assertEquals("APPLIED", auditLog.get(4).getString("state")); + + assertEquals("flamingock-change", auditLog.get(5).getString("changeId")); + assertEquals("STARTED", auditLog.get(5).getString("state")); + + assertEquals("flamingock-change", auditLog.get(6).getString("changeId")); + assertEquals("APPLIED", auditLog.get(6).getString("state")); + } + + private List getAuditLog() { return CouchbaseCollectionHelper.selectAllDocuments(cluster, FLAMINGOCK_BUCKET_NAME, FLAMINGOCK_SCOPE_NAME, FLAMINGOCK_COLLECTION_NAME) .stream() diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBImporterTest.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBImporterTest.java index 9d326b5ba..b8670217a 100644 --- a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBImporterTest.java +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBImporterTest.java @@ -27,6 +27,7 @@ import io.flamingock.support.mongock.annotations.MongockSupport; import io.flamingock.targetsystem.dynamodb.DynamoDBTargetSystem; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -43,10 +44,14 @@ import software.amazon.awssdk.services.dynamodb.model.KeyType; import java.net.URI; +import java.util.ArrayList; +import java.util.List; import static io.flamingock.core.kit.audit.AuditEntryExpectation.APPLIED; import static io.flamingock.core.kit.audit.AuditEntryExpectation.STARTED; import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -201,9 +206,10 @@ void GIVEN_someChangeUnitsAlreadyExecuted_WHEN_migratingToFlamingockCommunity_TH @Test @DisplayName("GIVEN mongock audit history empty " + + "AND no fail if empty origin value provided " + "WHEN migrating to Flamingock Community" + "THEN should throw exception") - void GIVEN_mongockAuditHistoryEmpty_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { + void GIVEN_mongockAuditHistoryEmptyAndNoFailIfEmptyOriginValueProvided_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { // Setup Mongock entries DynamoDBTargetSystem dynamodbTargetSystem = new DynamoDBTargetSystem("dynamodb-target-system", client); @@ -217,4 +223,129 @@ void GIVEN_mongockAuditHistoryEmpty_WHEN_migratingToFlamingockCommunity_THEN_sho } + @Test + @DisplayName("GIVEN mongock audit history empty " + + "AND explicit empty origin allowed disabled " + + "WHEN migrating to Flamingock Community" + + "THEN should throw exception") + void GIVEN_mongockAuditHistoryEmptyAndFailIfEmptyOriginEnabled_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { + // Setup Mongock entries + + DynamoDBTargetSystem dynamodbTargetSystem = new DynamoDBTargetSystem("dynamodb-target-system", client); + + Runner flamingock = testKit.createBuilder() + .addTargetSystem(dynamodbTargetSystem) + .setProperty(MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY, Boolean.FALSE.toString()) + .build(); + + FlamingockException ex = assertThrows(FlamingockException.class, flamingock::run); + assertEquals("No audit entries found when importing from 'dynamodb-target-system'.", ex.getMessage()); + } + + @Test + @DisplayName("GIVEN mongock audit history empty " + + "AND explicit empty origin allowed enabled " + + "WHEN migrating to Flamingock Community" + + "THEN should execute the pending Mongock changeUnits " + + "AND execute the pending flamingock changes") + void GIVEN_mongockAuditHistoryEmptyAndFailIfEmptyOriginDisabled_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { + // Setup Mongock entries + + DynamoDBTargetSystem dynamodbTargetSystem = new DynamoDBTargetSystem("dynamodb-target-system", client); + + Runner flamingock = testKit.createBuilder() + .addTargetSystem(dynamodbTargetSystem) + .setProperty(MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY, Boolean.TRUE.toString()) + .build(); + + flamingock.run(); + + // Verify audit sequence: 8 total entries as shown in actual execution + auditHelper.verifyAuditSequenceStrict( + // System stage - actual system importer change + STARTED("migration-mongock-to-flamingock-community"), + APPLIED("migration-mongock-to-flamingock-community"), + + // Legacy changes + STARTED("mongock-change-1"), + APPLIED("mongock-change-1"), + STARTED("mongock-change-2"), + APPLIED("mongock-change-2"), + + // Application stage - new changes created by templates + STARTED("create-users-table"), + APPLIED("create-users-table") + ); + + + + // Validate actual table creation + assertTrue(client.listTables().tableNames().contains("users"), "Users table should exist"); + + // Verify table structure + DescribeTableResponse tableDescription = client.describeTable( + DescribeTableRequest.builder().tableName("users").build() + ); + assertEquals("email", tableDescription.table().keySchema().get(0).attributeName()); + assertEquals(KeyType.HASH, tableDescription.table().keySchema().get(0).keyType()); + } + + @Test + @DisplayName("GIVEN all Mongock changeUnits already executed" + + "AND custom origin repository name provided" + + "WHEN migrating to Flamingock Community " + + "THEN should import the entire history " + + "AND execute the pending flamingock changes") + void GIVEN_allMongockChangeUnitsAlreadyExecutedAndCustomOriginProvided_WHEN_migratingToFlamingockCommunity_THEN_shouldImportEntireHistory() { + // Setup Mongock entries + + final String customMongockOrigin = "mongockCustomOriginCollection"; + + // Create custom table + DynamoDBTableFactory.createMongockTable(client, customMongockOrigin); + + DynamoDBMongockTestHelper customOriginMongockTestHelper = + new DynamoDBMongockTestHelper(client, customMongockOrigin); + customOriginMongockTestHelper.setupBasicScenario(); + + DynamoDBTargetSystem dynamodbTargetSystem = new DynamoDBTargetSystem("dynamodb-target-system", client); + + Runner flamingock = testKit.createBuilder() + .addTargetSystem(dynamodbTargetSystem) + .setProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY, customMongockOrigin) + .build(); + + flamingock.run(); + + // Verify audit sequence: 9 total entries as shown in actual execution + // Legacy imports only show APPLIED (imported from Mongock), new changes show STARTED+APPLIED + auditHelper.verifyAuditSequenceStrict( + // Legacy imports from Mongock (APPLIED only - no STARTED for imported changes) + APPLIED("system-change-00001_before"), + APPLIED("system-change-00001"), + APPLIED("mongock-change-1_before"), + APPLIED("mongock-change-1"), + APPLIED("mongock-change-2"), + + // System stage - actual system importer change + STARTED("migration-mongock-to-flamingock-community"), + APPLIED("migration-mongock-to-flamingock-community"), + + // Application stage - new changes created by templates + STARTED("create-users-table"), + APPLIED("create-users-table") + ); + + + + // Validate actual table creation + assertTrue(client.listTables().tableNames().contains("users"), "Users table should exist"); + + // Verify table structure + DescribeTableResponse tableDescription = client.describeTable( + DescribeTableRequest.builder().tableName("users").build() + ); + assertEquals("email", tableDescription.table().keySchema().get(0).attributeName()); + assertEquals(KeyType.HASH, tableDescription.table().keySchema().get(0).keyType()); + } } diff --git a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBImporterTest.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBImporterTest.java index aedb96bdb..8eb3022ae 100644 --- a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBImporterTest.java +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBImporterTest.java @@ -47,6 +47,8 @@ import static io.flamingock.core.kit.audit.AuditEntryExpectation.APPLIED; import static io.flamingock.core.kit.audit.AuditEntryExpectation.STARTED; import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -213,9 +215,10 @@ void GIVEN_someChangeUnitsAlreadyExecuted_WHEN_migratingToFlamingockCommunity_TH @Test @DisplayName("GIVEN mongock audit history empty " + + "AND no fail if empty origin value provided " + "WHEN migrating to Flamingock Community" + "THEN should throw exception") - void GIVEN_mongockAuditHistoryEmpty_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { + void GIVEN_mongockAuditHistoryEmptyAndNoFailIfEmptyOriginValueProvided_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { // Setup Mongock entries MongoDBSyncTargetSystem mongodbTargetSystem = new MongoDBSyncTargetSystem("mongodb-target-system", mongoClient, DATABASE_NAME); @@ -229,4 +232,139 @@ void GIVEN_mongockAuditHistoryEmpty_WHEN_migratingToFlamingockCommunity_THEN_sho } + @Test + @DisplayName("GIVEN mongock audit history empty " + + "AND explicit empty origin allowed disabled " + + "WHEN migrating to Flamingock Community" + + "THEN should throw exception") + void GIVEN_mongockAuditHistoryEmptyAndFailIfEmptyOriginEnabled_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { + // Setup Mongock entries + + MongoDBSyncTargetSystem mongodbTargetSystem = new MongoDBSyncTargetSystem("mongodb-target-system", mongoClient, DATABASE_NAME); + + Runner flamingock = testKit.createBuilder() + .addTargetSystem(mongodbTargetSystem) + .setProperty(MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY, Boolean.FALSE.toString()) + .build(); + + FlamingockException ex = assertThrows(FlamingockException.class, flamingock::run); + assertEquals("No audit entries found when importing from 'mongodb-target-system'.", ex.getMessage()); + + } + + @Test + @DisplayName("GIVEN mongock audit history empty " + + "AND explicit empty origin allowed enabled " + + "WHEN migrating to Flamingock Community " + + "THEN should execute the pending Mongock changeUnits " + + "AND execute the pending flamingock changes") + void GIVEN_mongockAuditHistoryEmptyAndFailIfEmptyOriginDisabled_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() { + // Setup Mongock entries + + MongoDBSyncTargetSystem mongodbTargetSystem = new MongoDBSyncTargetSystem("mongodb-target-system", mongoClient, DATABASE_NAME); + + Runner flamingock = testKit.createBuilder() + .addTargetSystem(mongodbTargetSystem) + .setProperty(MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY, Boolean.TRUE.toString()) + .build(); + + flamingock.run(); + + // Verify audit sequence: 10 total entries as shown in actual execution + auditHelper.verifyAuditSequenceStrict( + // System stage - actual system importer change + STARTED("migration-mongock-to-flamingock-community"), + APPLIED("migration-mongock-to-flamingock-community"), + + // Legacy changes + STARTED("mongock-change-1"), + APPLIED("mongock-change-1"), + STARTED("mongock-change-2"), + APPLIED("mongock-change-2"), + + // Application stage - new changes created by templates + STARTED("create-users-collection-with-index"), + APPLIED("create-users-collection-with-index"), + STARTED("seed-users"), + APPLIED("seed-users") + ); + + + // Validate actual change + List users = database.getCollection("users") + .find() + .into(new ArrayList<>()); + + assertEquals(2, users.size()); + Assertions.assertEquals("Admin", users.get(0).getString("name")); + Assertions.assertEquals("admin@company.com", users.get(0).getString("email")); + Assertions.assertEquals("superuser", users.get(0).getList("roles", String.class).get(0)); + + Assertions.assertEquals("Backup", users.get(1).getString("name")); + Assertions.assertEquals("backup@company.com", users.get(1).getString("email")); + Assertions.assertEquals("readonly", users.get(1).getList("roles", String.class).get(0)); + } + + @Test + @DisplayName("GIVEN all Mongock changeUnits already executed" + + "AND custom origin repository name provided" + + "WHEN migrating to Flamingock Community " + + "THEN should import the entire history " + + "AND execute the pending flamingock changes") + void GIVEN_allMongockChangeUnitsAlreadyExecutedAndCustomOriginProvided_WHEN_migratingToFlamingockCommunity_THEN_shouldImportEntireHistory() { + // Setup Mongock entries + + final String customMongockOrigin = "mongockCustomOriginCollection"; + + MongoDBMongockTestHelper customOriginMongockTestHelper = + new MongoDBMongockTestHelper(database.getCollection(customMongockOrigin)); + customOriginMongockTestHelper.setupBasicScenario(); + + MongoDBSyncTargetSystem mongodbTargetSystem = new MongoDBSyncTargetSystem("mongodb-target-system", mongoClient, DATABASE_NAME); + + Runner flamingock = testKit.createBuilder() + .addTargetSystem(mongodbTargetSystem) + .setProperty(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY, customMongockOrigin) + .build(); + + flamingock.run(); + + // Verify audit sequence: 11 total entries as shown in actual execution + // Legacy imports only show APPLIED (imported from Mongock), new changes show STARTED+APPLIED + auditHelper.verifyAuditSequenceStrict( + // Legacy imports from Mongock (APPLIED only - no STARTED for imported changes) + APPLIED("system-change-00001_before"), + APPLIED("system-change-00001"), + APPLIED("mongock-change-1_before"), + APPLIED("mongock-change-1"), + APPLIED("mongock-change-2"), + + // System stage - actual system importer change + STARTED("migration-mongock-to-flamingock-community"), + APPLIED("migration-mongock-to-flamingock-community"), + + // Application stage - new changes created by templates + STARTED("create-users-collection-with-index"), + APPLIED("create-users-collection-with-index"), + STARTED("seed-users"), + APPLIED("seed-users") + ); + + + + + // Validate actual change + List users = database.getCollection("users") + .find() + .into(new ArrayList<>()); + + assertEquals(2, users.size()); + Assertions.assertEquals("Admin", users.get(0).getString("name")); + Assertions.assertEquals("admin@company.com", users.get(0).getString("email")); + Assertions.assertEquals("superuser", users.get(0).getList("roles", String.class).get(0)); + + Assertions.assertEquals("Backup", users.get(1).getString("name")); + Assertions.assertEquals("backup@company.com", users.get(1).getString("email")); + Assertions.assertEquals("readonly", users.get(1).getList("roles", String.class).get(0)); + } } diff --git a/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/MongockImportChange.java b/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/MongockImportChange.java index dde94c8ff..b8b09ad42 100644 --- a/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/MongockImportChange.java +++ b/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/MongockImportChange.java @@ -16,6 +16,7 @@ package io.flamingock.support.mongock; import io.flamingock.api.annotations.NonLockGuarded; +import io.flamingock.api.annotations.Nullable; import io.flamingock.internal.common.core.pipeline.PipelineHelper; import io.flamingock.internal.common.core.audit.AuditEntry; import io.flamingock.internal.common.core.audit.AuditHistoryReader; @@ -32,6 +33,7 @@ import java.util.List; import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY; /** * This ChangeUnit is intentionally not annotated with @Change, @Apply, or similar, @@ -44,12 +46,13 @@ public class MongockImportChange { public void importHistory(@Named("change.targetSystem.id") String targetSystemId, @NonLockGuarded TargetSystemManager targetSystemManager, @NonLockGuarded AuditWriter auditWriter, - @NonLockGuarded PipelineDescriptor pipelineDescriptor) { + @NonLockGuarded PipelineDescriptor pipelineDescriptor, + @Nullable @Named(MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY) String emptyOriginAllowed) { logger.info("Starting audit log migration from Mongock to Flamingock community audit store"); AuditHistoryReader legacyHistoryReader = getAuditHistoryReader(targetSystemId, targetSystemManager); PipelineHelper pipelineHelper = new PipelineHelper(pipelineDescriptor); List legacyHistory = legacyHistoryReader.getAuditHistory(); - validate(legacyHistory, targetSystemId); + validate(legacyHistory, targetSystemId, emptyOriginAllowed); legacyHistory.forEach(auditEntryFromOrigin -> { //This is the changeId present in the pipeline. If it's a system change or '..._before' won't appear AuditEntry auditEntryWithStageId = auditEntryFromOrigin.copyWithNewIdAndStageId( @@ -77,10 +80,25 @@ private static AuditHistoryReader getAuditHistoryReader(String targetSystemId, T - private void validate(List legacyHistory, String targetSystemId) { + private void validate(List legacyHistory, String targetSystemId, String emptyOriginAllowedPropertyValue) { if (legacyHistory.isEmpty()) { - String message = String.format("No audit entries found when importing from '%s'.", targetSystemId); - throw new FlamingockException(message); + boolean emptyOriginAllowed = resolveEmptyOriginAllowed(emptyOriginAllowedPropertyValue); + if (!emptyOriginAllowed) { + // Note that by default if the flag is null is considered as true + String message = String.format("No audit entries found when importing from '%s'.", targetSystemId); + throw new FlamingockException(message); + } + } + } + + private boolean resolveEmptyOriginAllowed(String raw) { + if (raw == null || raw.trim().isEmpty()) { + return false; // default behaviour } + String v = raw.trim(); + if ("true".equalsIgnoreCase(v)) return true; + if ("false".equalsIgnoreCase(v)) return false; + throw new FlamingockException("Invalid value for emptyOriginAllowed: " + raw + + " (expected \"true\" or \"false\" or empty)"); } } diff --git a/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/annotations/MongockSupport.java b/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/annotations/MongockSupport.java index 481f868d7..6e5feeee7 100644 --- a/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/annotations/MongockSupport.java +++ b/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/annotations/MongockSupport.java @@ -80,4 +80,37 @@ * @return the target system identifier */ String targetSystem(); + + /** + * Defines the origin collection/table name where Mongock audit entries are stored. + *

+ * This value is optional. When empty (default), Flamingock will use Mongock's + * default origin (i.e., the default audit collection/table name used by Mongock + * in the corresponding driver). + *

+ * + *

Examples:

+ *
+     * @MongockSupport(targetSystem = "mongock-target-system", origin = "mongockChangeLog")
+     * public class LegacyMongockSupport { }
+     * 
+ * + * @return the origin collection/table name, or empty to use Mongock defaults + */ + String origin() default ""; + + /** + * Determines whether Flamingock should fail when importing from Mongock and the origin + * collection/table is empty. + *

+ * Expected literal values are {@code "true"} or {@code "false"}. + *

+ * + *

+ * If empty (default), it will be treated as {@code "false"}. + *

+ * + * @return {@code "true"} to allow empty origin, {@code "false"} to fail; empty treated as {@code "false"} + */ + String emptyOriginAllowed() default ""; } diff --git a/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/processor/discover/MongockChangeDiscoverer.java b/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/processor/discover/MongockChangeDiscoverer.java index 4abaeaf58..0dffc7a3d 100644 --- a/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/processor/discover/MongockChangeDiscoverer.java +++ b/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/processor/discover/MongockChangeDiscoverer.java @@ -39,16 +39,20 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY; +import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY; + @SuppressWarnings("deprecation") public class MongockChangeDiscoverer implements ChangeDiscoverer { @Override - public Collection findAnnotatedChanges(RoundEnvironment roundEnv, LoggerPreProcessor logger) { + public Collection findAnnotatedChanges(RoundEnvironment roundEnv, LoggerPreProcessor logger, Map properties) { Optional mongockSupportOpt = this.getMongockSupportAnnotation(roundEnv, logger); final String mongockTargetSystemId = mongockSupportOpt.map(MongockSupport::targetSystem).orElse(null); @@ -68,6 +72,10 @@ public Collection findAnnotatedChanges(RoundEnvironment round .filter(Objects::nonNull) .collect(Collectors.toList()); changes.add(getImporterChange(mongockTargetSystemId)); + + // Adding Mongock specific configuration properties + processConfigurationProperties(mongockSupportOpt.get(), properties); + return changes; } else { throw new FlamingockException("@MongockSupport annotation must be provided when mongock-support module is present."); @@ -109,4 +117,29 @@ private Optional getMongockSupportAnnotation(RoundEnvironment ro private List buildCodePreviewChange(TypeElement typeElement, String mongockTargetSystemId) { return new MongockCodePreviewChangeHelper().getCodePreviewChanges(typeElement, mongockTargetSystemId); } + + private void processConfigurationProperties(MongockSupport mongockSupport, Map properties) { + if (properties == null) { + throw new IllegalArgumentException("properties"); + } + + if (resolveEmptyOriginAllowed(mongockSupport.emptyOriginAllowed())) { + properties.put(MONGOCK_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY, "true"); + } + + if (mongockSupport.origin() != null && !mongockSupport.origin().trim().isEmpty()) { + properties.put(MONGOCK_IMPORT_ORIGIN_PROPERTY_KEY, mongockSupport.origin().trim()); + } + } + + private boolean resolveEmptyOriginAllowed(String raw) { + if (raw == null || raw.trim().isEmpty()) { + return false; // default behaviour + } + String v = raw.trim(); + if ("true".equalsIgnoreCase(v)) return true; + if ("false".equalsIgnoreCase(v)) return false; + throw new FlamingockException("Invalid value for emptyOriginAllowed: " + raw + + " (expected \"true\" or \"false\" or empty)"); + } } diff --git a/platform-plugins/flamingock-springboot-integration/src/main/java/io/flamingock/springboot/SpringbootProperties.java b/platform-plugins/flamingock-springboot-integration/src/main/java/io/flamingock/springboot/SpringbootProperties.java index eaa46f31e..477336294 100644 --- a/platform-plugins/flamingock-springboot-integration/src/main/java/io/flamingock/springboot/SpringbootProperties.java +++ b/platform-plugins/flamingock-springboot-integration/src/main/java/io/flamingock/springboot/SpringbootProperties.java @@ -15,8 +15,8 @@ */ package io.flamingock.springboot; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.util.Deserializer; -import io.flamingock.internal.common.core.preview.PreviewPipeline; import io.flamingock.internal.core.configuration.cloud.CloudConfigurable; import io.flamingock.internal.core.configuration.cloud.CloudConfiguration; import io.flamingock.internal.core.configuration.core.CoreConfigurable; @@ -55,8 +55,8 @@ public CloudConfiguration getCloudProperties() { } @Override - public PreviewPipeline getPreviewPipeline() { - return Deserializer.readPreviewPipelineFromFile(); + public FlamingockMetadata getFlamingockMetadata() { + return Deserializer.readMetadataFromFile(); } @Override diff --git a/utils/couchbase-util/src/main/java/io/flamingock/internal/common/couchbase/CouchbaseUtils.java b/utils/couchbase-util/src/main/java/io/flamingock/internal/common/couchbase/CouchbaseUtils.java index 7f989ba29..973f7ed11 100644 --- a/utils/couchbase-util/src/main/java/io/flamingock/internal/common/couchbase/CouchbaseUtils.java +++ b/utils/couchbase-util/src/main/java/io/flamingock/internal/common/couchbase/CouchbaseUtils.java @@ -17,6 +17,7 @@ import com.couchbase.client.core.io.CollectionIdentifier; import com.couchbase.client.java.json.JsonObject; +import io.flamingock.internal.common.core.error.FlamingockException; import java.util.Date; import java.util.Optional; @@ -62,4 +63,72 @@ public static void addFieldToDocument(JsonObject document, String key, Object va } } } + + public static ScopeCollection getOriginScopeAndCollection(String origin) { + + // Default value + if (origin == null || origin.trim().isEmpty()) { + return new ScopeCollection(CollectionIdentifier.DEFAULT_SCOPE, CollectionIdentifier.DEFAULT_COLLECTION); + } + + String value = origin.trim(); + + // Separator validation (only one '.') + if (hasMoreThanOneDot(value)) { + throw new FlamingockException( + "Invalid origin '" + origin + "'. Only one '.' separator is allowed." + ); + } + + String[] parts = value.split("\\.", 2); + + // Only collection + if (parts.length == 1) { + String collection = parts[0].trim(); + + if (collection.isEmpty()) { + throw new FlamingockException( + "Invalid origin '" + origin + "'. Collection name cannot be empty." + ); + } + + return new ScopeCollection(CollectionIdentifier.DEFAULT_SCOPE, collection); + } + + // Scope + collection + String scope = parts[0].trim(); + String collection = parts[1].trim(); + + if (scope.isEmpty() || collection.isEmpty()) { + throw new IllegalArgumentException( + "Invalid origin '" + origin + "'. Scope and collection must be non-empty." + ); + } + + return new ScopeCollection(scope, collection); + } + + private static boolean hasMoreThanOneDot(String value) { + int first = value.indexOf('.'); + return first != -1 && value.indexOf('.', first + 1) != -1; + } + + public static final class ScopeCollection { + + private final String scope; + private final String collection; + + private ScopeCollection(String scope, String collection) { + this.scope = scope; + this.collection = collection; + } + + public String getScope() { + return scope; + } + + public String getCollection() { + return collection; + } + } } diff --git a/utils/test-util/src/main/java/io/flamingock/common/test/pipeline/PipelineTestHelper.java b/utils/test-util/src/main/java/io/flamingock/common/test/pipeline/PipelineTestHelper.java index 7a4862d13..9e9af6875 100644 --- a/utils/test-util/src/main/java/io/flamingock/common/test/pipeline/PipelineTestHelper.java +++ b/utils/test-util/src/main/java/io/flamingock/common/test/pipeline/PipelineTestHelper.java @@ -16,6 +16,7 @@ package io.flamingock.common.test.pipeline; import io.flamingock.api.StageType; +import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.util.Deserializer; import io.flamingock.internal.common.core.preview.AbstractPreviewTask; import io.flamingock.internal.common.core.preview.PreviewPipeline; @@ -43,7 +44,7 @@ private static List getParameterTypes(List> second) { public static void testWithMockedPipeline(List changeTestDefinitions, Runnable testOperation) { try (MockedStatic mocked = Mockito.mockStatic(Deserializer.class)) { - mocked.when(Deserializer::readPreviewPipelineFromFile).thenReturn( + mocked.when(Deserializer::readMetadataFromFile).thenReturn( PipelineTestHelper.getPreviewPipeline(changeTestDefinitions) ); testOperation.run(); @@ -51,7 +52,7 @@ public static void testWithMockedPipeline(List changeTestD } - public static PreviewPipeline getPreviewPipeline(String stageName, List changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(String stageName, List changeDefinitions) { List tasks = changeDefinitions.stream() .map(ChangeTestDefinition::toPreview) @@ -66,18 +67,20 @@ public static PreviewPipeline getPreviewPipeline(String stageName, List changeDefinitions) { + public static FlamingockMetadata getPreviewPipeline(List changeDefinitions) { return getPreviewPipeline("default-stage-name", changeDefinitions); } } diff --git a/utils/test-util/src/main/java/io/flamingock/core/kit/audit/AuditTestSupport.java b/utils/test-util/src/main/java/io/flamingock/core/kit/audit/AuditTestSupport.java index 1fe3ecf13..35d19a5f4 100644 --- a/utils/test-util/src/main/java/io/flamingock/core/kit/audit/AuditTestSupport.java +++ b/utils/test-util/src/main/java/io/flamingock/core/kit/audit/AuditTestSupport.java @@ -116,7 +116,7 @@ public void run() { try (MockedStatic mockedDeserializer = Mockito.mockStatic(Deserializer.class)) { // Set up the Deserializer mock with the configured changes - mockedDeserializer.when(Deserializer::readPreviewPipelineFromFile) + mockedDeserializer.when(Deserializer::readMetadataFromFile) .thenReturn(PipelineTestHelper.getPreviewPipeline(changes)); // Execute the test code