From fc4ba9660ba11a31e27d951d1e759283cbdff4eb Mon Sep 17 00:00:00 2001 From: Antonio Perez Dieppa Date: Sat, 22 Nov 2025 14:03:11 +0000 Subject: [PATCH 01/10] feat: Mongock import to FlamingockCommunity(WIP) --- .../api/task/ChangeCategoryAware.java | 19 -- .../common/core/metadata/Constants.java | 1 + .../common/core/pipeline}/PipelineHelper.java | 3 +- .../builder/CodePreviewTaskBuilder.java | 13 +- .../common/core/task/TaskDescriptor.java | 4 + .../loaded/stage/DefaultLoadedStage.java | 18 +- .../loaded/stage/LegacyLoadedStage.java | 17 +- .../loaded/stage/SystemLoadedStage.java | 17 +- .../core/targets/TargetSystemManager.java | 3 +- .../targets/TransactionalTargetSystem.java | 1 + .../TransactionalTargetSystemOps.java | 30 +++ .../TransactionalTargetSystemOpsImpl.java | 8 + .../task/loaded/AbstractLoadedChange.java | 15 -- .../core/task/loaded/AbstractLoadedTask.java | 4 +- .../core/task/loaded/CodeLoadedChange.java | 5 - .../task/loaded/CodeLoadedTaskBuilder.java | 6 +- .../ChangeProcessStrategyFactory.java | 12 +- .../FlamingockAnnotationProcessor.java | 163 ++++++-------- .../discover/FlamingockChangeDiscoverer.java | 2 +- .../processor/PipelinePreProcessorTest.java | 64 +++--- .../mongodb/MongoDBMongockTestHelper.java | 1 - .../flamingock/importer/ImporterAdapter.java | 7 +- .../flamingock/importer/ImporterExecutor.java | 4 +- .../couchbase/CouchbaseChangeEntry.java | 2 +- .../couchbase/CouchbaseImporterAdapter.java | 2 +- .../dynamodb/DynamoDBImporterAdapter.java | 2 +- .../dynamodb/MongockDynamoDBAuditEntry.java | 2 +- .../mongodb/MongoDBImporterAdapter.java | 5 +- .../MongockChangeEntry.java | 2 +- .../MongockChangeState.java | 2 +- .../MongockChangeType.java | 2 +- .../importer/ImporterExecutorTest.java | 7 +- .../couchbase-target-system/build.gradle.kts | 1 + .../dynamodb-target-system/build.gradle.kts | 3 +- .../dynamodb/DynamoDBTargetSystem.java | 19 ++ .../build.gradle.kts | 1 + .../MongoDBSpringDataTargetSystem.java | 17 ++ .../build.gradle.kts | 2 +- .../mongodb/sync/MongoDBSyncTargetSystem.java | 19 +- .../build.gradle.kts | 17 ++ .../couchbase/CouchbaseChangeEntry.java | 104 +++++++++ .../mongock/couchbase/MongockChangeState.java | 33 +++ .../couchbase/MongockImporterCouchbase.java | 62 +++++ .../build.gradle.kts | 16 ++ .../mongock/dynamodb/MongockAuditEntry.java | 213 ++++++++++++++++++ .../dynamodb/MongockImporterDynamoDB.java | 50 ++++ .../mongock-importer-mongodb/build.gradle.kts | 45 ++++ .../mongock/mongodb/MongockAuditEntry.java | 210 +++++++++++++++++ .../mongodb/MongockImporterMongoDB.java | 96 ++++++++ .../mongock/mongodb/MongoDBImporterTest.java | 155 +++++++++++++ .../mongodb/MongoDBMongockTestHelper.java | 65 ++++++ .../_0003__create_users_collections.yaml | 9 + .../mongodb/changes/_0004__seed_users.yaml | 16 ++ .../mongodb/legacy/MongockChange1.java | 29 +++ .../mongodb/legacy/MongockChange2.java | 30 +++ .../support/mongock/MongockImportChange.java | 85 +++++++ .../discover/MongockChangeDiscoverer.java | 40 +++- settings.gradle.kts | 37 ++- .../test/mongock/MongockTestHelper.java | 6 +- 59 files changed, 1567 insertions(+), 256 deletions(-) rename core/{importer/flamingock-importer/src/main/java/io/flamingock/importer/util => flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/pipeline}/PipelineHelper.java (95%) rename core/importer/flamingock-importer/src/main/java/io/flamingock/importer/{mongock => mongodb}/MongockChangeEntry.java (99%) rename core/importer/flamingock-importer/src/main/java/io/flamingock/importer/{mongock => mongodb}/MongockChangeState.java (96%) rename core/importer/flamingock-importer/src/main/java/io/flamingock/importer/{mongock => mongodb}/MongockChangeType.java (95%) create mode 100644 legacy/mongock-importer-couchbase/build.gradle.kts create mode 100644 legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/CouchbaseChangeEntry.java create mode 100644 legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockChangeState.java create mode 100644 legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockImporterCouchbase.java create mode 100644 legacy/mongock-importer-dynamodb/build.gradle.kts create mode 100644 legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java create mode 100644 legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockImporterDynamoDB.java create mode 100644 legacy/mongock-importer-mongodb/build.gradle.kts create mode 100644 legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockAuditEntry.java create mode 100644 legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockImporterMongoDB.java create mode 100644 legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBImporterTest.java create mode 100644 legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java create mode 100644 legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0003__create_users_collections.yaml create mode 100644 legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0004__seed_users.yaml create mode 100644 legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange1.java create mode 100644 legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange2.java create mode 100644 legacy/mongock-support/src/main/java/io/flamingock/support/mongock/MongockImportChange.java diff --git a/core/flamingock-core-api/src/main/java/io/flamingock/api/task/ChangeCategoryAware.java b/core/flamingock-core-api/src/main/java/io/flamingock/api/task/ChangeCategoryAware.java index ebfefc2ff..ffd63a259 100644 --- a/core/flamingock-core-api/src/main/java/io/flamingock/api/task/ChangeCategoryAware.java +++ b/core/flamingock-core-api/src/main/java/io/flamingock/api/task/ChangeCategoryAware.java @@ -17,23 +17,4 @@ public interface ChangeCategoryAware { - boolean hasCategory(ChangeCategory property); - - default boolean hasAnyCategory(ChangeCategory... properties) { - for (ChangeCategory property : properties) { - if (hasCategory(property)) { - return true; - } - } - return false; - } - - default boolean hasAllCategories(ChangeCategory... properties) { - for (ChangeCategory property : properties) { - if (!hasCategory(property)) { - return false; - } - } - return true; - } } 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 1489f8a51..7423641d2 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 @@ -21,6 +21,7 @@ public final class Constants { public static final String FULL_GRAALVM_REFLECT_CLASSES_PATH = "META-INF/flamingock/reflection-classes.txt"; + public static final String DEFAULT_MONGOCK_ORIGIN = "mongockChangeLog"; private Constants() {} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/util/PipelineHelper.java b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/pipeline/PipelineHelper.java similarity index 95% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/util/PipelineHelper.java rename to core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/pipeline/PipelineHelper.java index e861634b7..fb86241ab 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/util/PipelineHelper.java +++ b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/pipeline/PipelineHelper.java @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.util; +package io.flamingock.internal.common.core.pipeline; import io.flamingock.internal.common.core.audit.AuditEntry; -import io.flamingock.internal.common.core.pipeline.PipelineDescriptor; import org.jetbrains.annotations.NotNull; public class PipelineHelper { diff --git a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/preview/builder/CodePreviewTaskBuilder.java b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/preview/builder/CodePreviewTaskBuilder.java index e0c6ffe2f..508e917af 100644 --- a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/preview/builder/CodePreviewTaskBuilder.java +++ b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/preview/builder/CodePreviewTaskBuilder.java @@ -35,16 +35,9 @@ import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeMirror; import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; public class CodePreviewTaskBuilder implements PreviewTaskBuilder { @@ -65,12 +58,12 @@ public class CodePreviewTaskBuilder implements PreviewTaskBuilder { boolean isLegacy(); + default boolean isStandard() { + return !(isLegacy() || isSystem()); + } + default String pretty() { if (getOrder().isPresent()) { return String.format("%s) id: %s ", getOrder().get(), getId()); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/DefaultLoadedStage.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/DefaultLoadedStage.java index 68f5efb2c..6bdbdfd97 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/DefaultLoadedStage.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/DefaultLoadedStage.java @@ -16,9 +16,8 @@ package io.flamingock.internal.core.pipeline.loaded.stage; -import io.flamingock.api.task.ChangeCategory; -import io.flamingock.internal.common.core.error.validation.ValidationError; import io.flamingock.api.StageType; +import io.flamingock.internal.common.core.error.validation.ValidationError; import io.flamingock.internal.core.pipeline.loaded.PipelineValidationContext; import io.flamingock.internal.core.task.loaded.AbstractLoadedChange; import io.flamingock.internal.core.task.loaded.AbstractLoadedTask; @@ -33,6 +32,8 @@ */ public class DefaultLoadedStage extends AbstractLoadedStage { + private final static String INVALID_CHANGE_TYPE_MSG = "Invalid change detected: a non-standard change was found while processing a standard stage"; + private static final StageValidationContext validationContext = StageValidationContext.builder() .setSorted(SEQUENTIAL_FORMATTED) .build(); @@ -46,15 +47,12 @@ public DefaultLoadedStage(String name, @Override public List getValidationErrors(PipelineValidationContext context) { List errors = super.getValidationErrors(context); - String changeCategoryErrorMsg = String.format( - "Change[{}] in default stage cannot have categories %s or %s", - ChangeCategory.SYSTEM, ChangeCategory.IMPORT); - for(AbstractLoadedTask task : getTasks()) { - if(task instanceof AbstractLoadedChange) { + for (AbstractLoadedTask task : getTasks()) { + if (task instanceof AbstractLoadedChange) { AbstractLoadedChange change = (AbstractLoadedChange) task; - if(change.hasAnyCategory(ChangeCategory.SYSTEM, ChangeCategory.IMPORT)) { - errors.add(new ValidationError(changeCategoryErrorMsg, task.getId(), "change")); + if (!change.isStandard()) { + errors.add(new ValidationError(INVALID_CHANGE_TYPE_MSG, task.getId(), "change")); } } else { errors.add(new ValidationError("Task in default stage must be a Change", task.getId(), "change")); @@ -66,6 +64,4 @@ public List getValidationErrors(PipelineValidationContext conte } - - } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/LegacyLoadedStage.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/LegacyLoadedStage.java index 187354bd4..8b6e51630 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/LegacyLoadedStage.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/LegacyLoadedStage.java @@ -16,9 +16,8 @@ package io.flamingock.internal.core.pipeline.loaded.stage; -import io.flamingock.api.task.ChangeCategory; -import io.flamingock.internal.common.core.error.validation.ValidationError; import io.flamingock.api.StageType; +import io.flamingock.internal.common.core.error.validation.ValidationError; import io.flamingock.internal.core.pipeline.loaded.PipelineValidationContext; import io.flamingock.internal.core.task.loaded.AbstractLoadedChange; import io.flamingock.internal.core.task.loaded.AbstractLoadedTask; @@ -32,6 +31,9 @@ * It's the result of adding the loaded task to the ProcessDefinition */ public class LegacyLoadedStage extends AbstractLoadedStage { + + private final static String INVALID_CHANGE_TYPE_MSG = "Invalid change detected: a non-legacy change was found while processing a legacy stage"; + private static final StageValidationContext validationContext = StageValidationContext.builder() .setSorted(SEQUENTIAL_SIMPLE) .build(); @@ -46,15 +48,12 @@ public LegacyLoadedStage(String name, @Override public List getValidationErrors(PipelineValidationContext context) { List errors = super.getValidationErrors(context); - String changeCategoryErrorMsg = String.format( - "ChangeUnit[{}] in legacy stage cannot have categories %s or %s", - ChangeCategory.SYSTEM, ChangeCategory.IMPORT); - for(AbstractLoadedTask task : getTasks()) { - if(task instanceof AbstractLoadedChange) { + for (AbstractLoadedTask task : getTasks()) { + if (task instanceof AbstractLoadedChange) { AbstractLoadedChange change = (AbstractLoadedChange) task; - if(change.hasAnyCategory(ChangeCategory.SYSTEM, ChangeCategory.IMPORT)) { - errors.add(new ValidationError(changeCategoryErrorMsg, task.getId(), "change")); + if (!change.isLegacy()) { + errors.add(new ValidationError(INVALID_CHANGE_TYPE_MSG, task.getId(), "change")); } } else { errors.add(new ValidationError("Task in legacy stage must be a ChangeUnit", task.getId(), "change")); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/SystemLoadedStage.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/SystemLoadedStage.java index bbb787096..506422b18 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/SystemLoadedStage.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/loaded/stage/SystemLoadedStage.java @@ -16,9 +16,8 @@ package io.flamingock.internal.core.pipeline.loaded.stage; -import io.flamingock.api.task.ChangeCategory; -import io.flamingock.internal.common.core.error.validation.ValidationError; import io.flamingock.api.StageType; +import io.flamingock.internal.common.core.error.validation.ValidationError; import io.flamingock.internal.core.pipeline.loaded.PipelineValidationContext; import io.flamingock.internal.core.task.loaded.AbstractLoadedChange; import io.flamingock.internal.core.task.loaded.AbstractLoadedTask; @@ -33,6 +32,9 @@ */ public class SystemLoadedStage extends AbstractLoadedStage { + private static final String INVALID_CHANGE_TYPE_MSG = "Invalid change detected: a non-system change was found while processing a system stage"; + + private static final StageValidationContext validationContext = StageValidationContext.builder() .setSorted(UNSORTED) .build(); @@ -48,15 +50,12 @@ public SystemLoadedStage(String name, @Override public List getValidationErrors(PipelineValidationContext context) { List errors = super.getValidationErrors(context); - String changeCategoryErrorMsg = String.format( - "Change in a system stage must have category %s or %s ", - ChangeCategory.SYSTEM, ChangeCategory.IMPORT); - for(AbstractLoadedTask task : getTasks()) { - if(task instanceof AbstractLoadedChange) { + for (AbstractLoadedTask task : getTasks()) { + if (task instanceof AbstractLoadedChange) { AbstractLoadedChange change = (AbstractLoadedChange) task; - if(!change.hasCategory(ChangeCategory.IMPORT)) { - errors.add(new ValidationError(changeCategoryErrorMsg, task.getId(), "change")); + if (!change.isSystem()) { + errors.add(new ValidationError(INVALID_CHANGE_TYPE_MSG, task.getId(), "change")); } } else { errors.add(new ValidationError("Task in a system stage must of type Change", task.getId(), "change")); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TargetSystemManager.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TargetSystemManager.java index 3c73b74cb..aec85cba9 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TargetSystemManager.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TargetSystemManager.java @@ -96,10 +96,9 @@ public TargetSystemOps getTargetSystem(String id) { if (id == null || !targetSystemMap.containsKey(id)) { String availableTargetSystems = String.join(", ", targetSystemMap.keySet()); String message = String.format( - "Change requires a valid targetSystem. Found: [%s]. Available target systems: [%s]", + "Not found targetSystem [%s] among available target systems: [ %s ]", id, availableTargetSystems ); - logger.debug(message); throw new FlamingockException(message); } else { AbstractTargetSystem targetSystem = targetSystemMap.get(id); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TransactionalTargetSystem.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TransactionalTargetSystem.java index 409ac220f..bf554a2fe 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TransactionalTargetSystem.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TransactionalTargetSystem.java @@ -130,4 +130,5 @@ public Optional getAuditAuditReader(AuditReaderType type) { return Optional.empty(); } + } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOps.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOps.java index e534bc9b8..724e16b17 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOps.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOps.java @@ -15,9 +15,12 @@ */ package io.flamingock.internal.core.targets.operations; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; +import io.flamingock.internal.common.core.audit.AuditReaderType; import io.flamingock.internal.core.runtime.ExecutionRuntime; import io.flamingock.internal.core.targets.mark.TargetSystemAuditMarker; +import java.util.Optional; import java.util.function.Function; /** @@ -51,4 +54,31 @@ public interface TransactionalTargetSystemOps extends TargetSystemOps, TargetSys */ T applyChangeTransactional(Function changeApplier, ExecutionRuntime executionRuntime); + /** + * Returns an audit history reader for importing audit entries from external migration sources. + *

+ * This method enables Flamingock to import audit history from legacy migration tools or other + * Flamingock installations, preventing re-execution of already-applied changes. The returned + * reader provides access to historical audit entries that can be written to Flamingock's audit store. + *

+ * Common use cases include: + *

    + *
  • Mongock migration: Import Mongock change history when migrating from Mongock to Flamingock
  • + *
  • Community to Cloud migration: Import audit history from local database to Flamingock Cloud backend
  • + *
  • Future extensibility: Support for other migration tools (Liquibase, Flyway, etc.)
  • + *
+ *

+ * The default implementation returns {@code Optional.empty()}, indicating no audit reader is available. + * Target system implementations should override this method to provide database-specific readers when + * migration support is needed. + * + * @param type the type of audit reader to retrieve (e.g., {@link AuditReaderType#MONGOCK}) + * @return an {@link Optional} containing the audit history reader if supported for the given type, + * or {@link Optional#empty()} if this target system does not support audit reading for the specified type + * @see AuditHistoryReader + * @see AuditReaderType + * @see io.flamingock.importer.ImporterAdapter + */ + Optional getAuditAuditReader(AuditReaderType type); + } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOpsImpl.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOpsImpl.java index a45ca4877..4552cbf4f 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOpsImpl.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOpsImpl.java @@ -15,12 +15,15 @@ */ package io.flamingock.internal.core.targets.operations; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; +import io.flamingock.internal.common.core.audit.AuditReaderType; import io.flamingock.internal.common.core.targets.OperationType; import io.flamingock.internal.core.runtime.ExecutionRuntime; import io.flamingock.internal.core.targets.AbstractTargetSystem; import io.flamingock.internal.core.targets.TransactionalTargetSystem; import io.flamingock.internal.core.targets.mark.TargetSystemAuditMark; +import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -49,6 +52,11 @@ public final T applyChangeTransactional(Function change return targetSystem.applyChangeTransactional(changeApplier, executionRuntime); } + @Override + public Optional getAuditAuditReader(AuditReaderType type) { + return targetSystem.getAuditAuditReader(type); + } + @Override public String getId() { return targetSystem.getId(); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/AbstractLoadedChange.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/AbstractLoadedChange.java index e1ce6bd22..18bf6e995 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/AbstractLoadedChange.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/AbstractLoadedChange.java @@ -16,11 +16,8 @@ package io.flamingock.internal.core.task.loaded; import io.flamingock.api.annotations.Categories; -import io.flamingock.api.annotations.FlamingockConstructor; import io.flamingock.api.task.ChangeCategory; -import io.flamingock.internal.common.core.error.FlamingockException; import io.flamingock.internal.common.core.error.validation.ValidationError; -import io.flamingock.internal.common.core.preview.PreviewConstructor; import io.flamingock.internal.core.pipeline.loaded.stage.StageValidationContext; import io.flamingock.internal.util.ReflectionUtil; import io.flamingock.internal.common.core.task.RecoveryDescriptor; @@ -51,7 +48,6 @@ public abstract class AbstractLoadedChange extends AbstractReflectionLoadedTask private final static String ORDER_REG_EXP = "^(?=(?:[^a-zA-Z0-9]*[a-zA-Z0-9]){3}).+$"; private final static Pattern ORDER_PATTERN = Pattern.compile(ORDER_REG_EXP); private final Constructor constructor; - private final Set categories; protected AbstractLoadedChange(String fileName, @@ -69,12 +65,6 @@ protected AbstractLoadedChange(String fileName, super(fileName, id, order, author, implementationClass, runAlways, transactional, system, targetSystem, recovery, legacy); this.constructor = constructor; - - this.categories = ReflectionUtil.findAllAnnotations(implementationClass, Categories.class).stream() - .map(Categories::value) - .map(Arrays::asList) - .flatMap(List::stream) - .collect(Collectors.toSet()); } @Override @@ -82,11 +72,6 @@ public Constructor getConstructor() { return constructor; } - @Override - public boolean hasCategory(ChangeCategory property) { - return categories.contains(property); - } - @Override public List getValidationErrors(StageValidationContext context) { List errors = new ArrayList<>(); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/AbstractLoadedTask.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/AbstractLoadedTask.java index 1bd49a490..6209ec68f 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/AbstractLoadedTask.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/AbstractLoadedTask.java @@ -29,7 +29,7 @@ import java.util.Optional; -public abstract class AbstractLoadedTask extends AbstractTaskDescriptor implements Validatable, ChangeCategoryAware { +public abstract class AbstractLoadedTask extends AbstractTaskDescriptor implements Validatable { public AbstractLoadedTask(String id, String order, @@ -50,8 +50,6 @@ public AbstractLoadedTask(String id, public abstract Optional getRollbackMethod(); - @Override - public abstract boolean hasCategory(ChangeCategory property); } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/CodeLoadedChange.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/CodeLoadedChange.java index 20f10a4f7..ca7ff747f 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/CodeLoadedChange.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/CodeLoadedChange.java @@ -57,11 +57,6 @@ public Optional getRollbackMethod() { return this.rollbackMethod; } - @Override - public boolean hasCategory(ChangeCategory property) { - return false; - } - @Override public String pretty() { String fromParent = super.pretty(); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/CodeLoadedTaskBuilder.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/CodeLoadedTaskBuilder.java index 20c90a011..14b06a414 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/CodeLoadedTaskBuilder.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/CodeLoadedTaskBuilder.java @@ -234,7 +234,11 @@ private Constructor getConstructorFromPreview(CodePreviewChange preview) { } private Method getApplyMethodFromPreview(CodePreviewChange preview) { - return getMethodFromNameAndParameters(preview.getSource(), preview.getApplyPreviewMethod().getName(), preview.getApplyPreviewMethod().getParameterTypes()); + try { + return getMethodFromNameAndParameters(preview.getSource(), preview.getApplyPreviewMethod().getName(), preview.getApplyPreviewMethod().getParameterTypes()); + } catch (NullPointerException ex) { + throw ex; + } } private Optional getRollbackMethodFromPreview(CodePreviewChange preview) { diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java index f1924f1e5..2e8f7bb1a 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java @@ -17,6 +17,7 @@ import io.flamingock.internal.common.core.audit.AuditTxType; import io.flamingock.internal.common.core.context.ContextResolver; +import io.flamingock.internal.common.core.error.FlamingockException; import io.flamingock.internal.core.store.audit.LifecycleAuditWriter; import io.flamingock.internal.core.store.lock.Lock; import io.flamingock.internal.core.pipeline.execution.ExecutionContext; @@ -107,7 +108,7 @@ public ChangeProcessStrategy build() { changeLogger.logStartChangeProcessStrategy(change.getId()); - TargetSystemOps targetSystemOps = targetSystemManager.getTargetSystem(change.getTargetSystem()); + TargetSystemOps targetSystemOps = getTargetSystem(change.getId()); // Log target system resolution changeLogger.logTargetSystemResolved(change.getId(), change.getTargetSystem()); @@ -129,6 +130,15 @@ public ChangeProcessStrategy build() { ); } + private TargetSystemOps getTargetSystem(String changeId) { + try { + return targetSystemManager.getTargetSystem(change.getTargetSystem()); + } catch (Exception e) { + String message = String.format("Error in change [%s] : %s", changeId, e.getMessage()); + throw new FlamingockException(message); + } + } + /** * Creates the appropriate change process strategy based on target system characteristics. * 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 f210f00b8..f885b11f9 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 @@ -22,13 +22,14 @@ import io.flamingock.core.processor.util.AnnotationFinder; import io.flamingock.core.processor.util.PathResolver; import io.flamingock.core.processor.util.ProjectRootDetector; -import io.flamingock.internal.common.core.preview.CodePreviewChange; -import io.flamingock.internal.common.core.util.LoggerPreProcessor; -import io.flamingock.internal.common.core.util.Serializer; import io.flamingock.internal.common.core.metadata.FlamingockMetadata; +import io.flamingock.internal.common.core.preview.CodePreviewChange; import io.flamingock.internal.common.core.preview.PreviewPipeline; import io.flamingock.internal.common.core.preview.PreviewStage; import io.flamingock.internal.common.core.preview.SystemPreviewStage; +import io.flamingock.internal.common.core.task.TaskDescriptor; +import io.flamingock.internal.common.core.util.LoggerPreProcessor; +import io.flamingock.internal.common.core.util.Serializer; import org.jetbrains.annotations.NotNull; import org.yaml.snakeyaml.Yaml; @@ -50,6 +51,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.function.BiPredicate; import java.util.stream.Collectors; @@ -202,12 +204,15 @@ public boolean process(Set annotations, RoundEnvironment 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(); + + List systemChanges = allChanges.stream().filter(TaskDescriptor::isSystem).collect(Collectors.toList()); List legacyChanges = allChanges.stream().filter(CodePreviewChange::isLegacy).collect(Collectors.toList()); - List noLegacyChanges = allChanges.stream().filter(c -> !c.isLegacy()).collect(Collectors.toList()); - Map> noLegacyChangesByPackage = getCodeChangesMapByPackage(noLegacyChanges); + List standardChanges = allChanges.stream().filter(TaskDescriptor::isStandard).collect(Collectors.toList()); + PreviewPipeline pipeline = getPipelineFromProcessChanges( + systemChanges, legacyChanges, - noLegacyChangesByPackage, + getCodeChangesMapByPackage(standardChanges), flamingockAnnotation ); @@ -238,10 +243,10 @@ public boolean process(Set annotations, RoundEnvironment private Map> getCodeChangesMapByPackage(Collection changes) { Map> mapByPackage = new HashMap<>(); - for(CodePreviewChange item: changes) { + for (CodePreviewChange item : changes) { mapByPackage.compute(item.getSourcePackage(), (key, descriptors) -> { List newDescriptors; - if(descriptors != null) { + if (descriptors != null) { newDescriptors = descriptors; } else { newDescriptors = new ArrayList<>(); @@ -253,7 +258,10 @@ private Map> getCodeChangesMapByPackage(Collecti return mapByPackage; } - private PreviewPipeline getPipelineFromProcessChanges(List legacyCodedChanges, Map> noLegacyCodedChangesByPackage, EnableFlamingock pipelineAnnotation) { + private PreviewPipeline getPipelineFromProcessChanges(List systemChanges, + List legacyCodedChanges, + Map> noLegacyCodedChangesByPackage, + EnableFlamingock pipelineAnnotation) { if (noLegacyCodedChangesByPackage == null) { noLegacyCodedChangesByPackage = new HashMap<>(); } @@ -267,10 +275,10 @@ private PreviewPipeline getPipelineFromProcessChanges(List le if (hasFileInAnnotation) { logger.info("Reading flamingock pipeline from file specified in @EnableFlamingock annotation: '" + pipelineAnnotation.configFile() + "'"); File specifiedPipelineFile = resolvePipelineFile(pipelineAnnotation.configFile()); - return buildPipelineFromSpecifiedFile(specifiedPipelineFile, legacyCodedChanges, noLegacyCodedChangesByPackage); + return buildPipelineFromSpecifiedFile(specifiedPipelineFile, systemChanges, legacyCodedChanges, noLegacyCodedChangesByPackage); } else { logger.info("Reading flamingock pipeline from @EnableFlamingock annotation stages configuration"); - return buildPipelineFromAnnotation(pipelineAnnotation, legacyCodedChanges, noLegacyCodedChangesByPackage); + return buildPipelineFromAnnotation(pipelineAnnotation, systemChanges, legacyCodedChanges, noLegacyCodedChangesByPackage); } } @@ -296,10 +304,14 @@ private int compareStagesByTypePriority(PreviewStage stage1, PreviewStage stage2 */ private int getStageTypePriority(StageType stageType) { switch (stageType) { - case SYSTEM: return 0; - case LEGACY: return 1; - case DEFAULT: return 2; - default: return 3; + case SYSTEM: + return 0; + case LEGACY: + return 1; + case DEFAULT: + return 2; + default: + return 3; } } @@ -318,7 +330,7 @@ private void validateStageTypes(Stage[] stages) { for (Stage stage : stages) { StageType stageType = stage.type(); - + if (stageType == StageType.SYSTEM) { systemStageCount++; if (systemStageCount > 1) { @@ -348,7 +360,7 @@ private void validateStageTypesFromYaml(List> stageList) { for (Map stageMap : stageList) { StageType stageType = StageType.from(stageMap.get("type")); - + if (stageType == StageType.SYSTEM) { systemStageCount++; if (systemStageCount > 1) { @@ -363,69 +375,48 @@ private void validateStageTypesFromYaml(List> stageList) { } } - private PreviewPipeline buildPipelineFromAnnotation(EnableFlamingock pipelineAnnotation, List legacyCodedChanges, Map> noLegacyCodedChangesByPackage) { + private PreviewPipeline buildPipelineFromAnnotation(EnableFlamingock pipelineAnnotation, + List systemChanges, + List legacyCodedChanges, + Map> standardChangesByPackage) { List stages = new ArrayList<>(); - SystemPreviewStage systemStage = null; - - for (Stage stageAnnotation : pipelineAnnotation.stages()) { - if (stageAnnotation.type() == StageType.SYSTEM) { - // Handle system stage separately to maintain internal architecture - systemStage = mapAnnotationToSystemStage(noLegacyCodedChangesByPackage, stageAnnotation); - } else { - PreviewStage stage = mapAnnotationToStage(noLegacyCodedChangesByPackage, stageAnnotation); - stages.add(stage); - } - } // Legacy Stage - PreviewStage legacyStage = buildLegacyStageIfNeeded(legacyCodedChanges); - if (legacyStage != null) { - stages.add(legacyStage); + buildLegacyStageIfNeeded(legacyCodedChanges) + .ifPresent(stages::add); + + // Standard Stage + for (Stage stageAnnotation : pipelineAnnotation.stages()) { + PreviewStage stage = mapAnnotationToStage(standardChangesByPackage, stageAnnotation); + stages.add(stage); } // Sort stages by type priority: LEGACY stages first, then DEFAULT stages stages.sort(this::compareStagesByTypePriority); - return systemStage != null - ? new PreviewPipeline(systemStage, stages) - : new PreviewPipeline(stages); + return buildSystemStageIfNeeded(systemChanges) + .map(systemPreviewStage -> new PreviewPipeline(systemPreviewStage, stages)) + .orElseGet(() -> new PreviewPipeline(stages)); } - private SystemPreviewStage mapAnnotationToSystemStage(Map> codedChangesByPackage, Stage stageAnnotation) { - String location = stageAnnotation.location(); - - if (location == null || location.trim().isEmpty()) { - throw new RuntimeException("@Stage annotation with type SYSTEM requires a location. Please specify the location field."); - } - - logger.verbose("Building stage: SystemStage"); - - String sourcesPackage = null; - String resourcesDir = null; - Collection changeClasses = null; - - if (PathResolver.isPackageName(location)) { - sourcesPackage = location; - changeClasses = codedChangesByPackage.get(sourcesPackage); - logger.verbose("Sources package: " + sourcesPackage); - if (changeClasses != null) { - logger.verbose("Found " + changeClasses.size() + " code-based changes in " + sourcesPackage); - } + private Optional buildSystemStageIfNeeded(List systemChanges) { + if(!systemChanges.isEmpty()) { + logger.verbose("Building stage: SystemStage"); + // For system stage, use hardcoded name, description, package and resource dir to maintain consistency + SystemPreviewStage systemStage = PreviewStage.systemBuilder() + .setName("SystemStage") + .setDescription("Dedicated stage for system-level changes") + .setSourcesRoots(sourceRoots) + .setSourcesPackage(null) + .setResourcesRoot(resourcesRoot) + .setResourcesDir(null) + .setChanges(systemChanges) + .build(); + return Optional.of(systemStage); } else { - resourcesDir = PathResolver.processResourceLocation(location); - logger.verbose("Resources directory: " + resourcesDir); + return Optional.empty(); } - // For system stage, use hardcoded name and description to maintain consistency - return PreviewStage.systemBuilder() - .setName("SystemStage") - .setDescription("Dedicated stage for system-level changes") - .setSourcesRoots(sourceRoots) - .setSourcesPackage(sourcesPackage) - .setResourcesRoot(resourcesRoot) - .setResourcesDir(resourcesDir) - .setChanges(changeClasses) - .build(); } private PreviewStage mapAnnotationToStage(Map> codedChangesByPackage, Stage stageAnnotation) { @@ -470,9 +461,9 @@ private PreviewStage mapAnnotationToStage(Map> c .build(); } - private PreviewStage buildLegacyStageIfNeeded(List legacyChanges) { + private Optional buildLegacyStageIfNeeded(List legacyChanges) { if (legacyChanges != null && !legacyChanges.isEmpty()) { - return PreviewStage.defaultBuilder(StageType.LEGACY) + PreviewStage flamingockLegacyStage = PreviewStage.defaultBuilder(StageType.LEGACY) .setName("legacy-stage") .setDescription("Flamingock legacy stage") .setSourcesRoots(sourceRoots) @@ -481,8 +472,9 @@ private PreviewStage buildLegacyStageIfNeeded(List legacyChan .setResourcesDir(null) //TODO: .setChanges(legacyChanges) .build(); + return Optional.of(flamingockLegacyStage); } - return null; + return Optional.empty(); } @@ -545,7 +537,10 @@ private File tryResolveFile(File file, String description, List searchedFi return null; } - private PreviewPipeline buildPipelineFromSpecifiedFile(File file, List legacyCodedChanges, Map> noLegacyCodedChangesByPackage) { + private PreviewPipeline buildPipelineFromSpecifiedFile(File file, + List systemChanges, + List legacyCodedChanges, + Map> standardChangesByPackage) { try (InputStream inputStream = Files.newInputStream(file.toPath())) { Yaml yaml = new Yaml(); @@ -559,32 +554,23 @@ private PreviewPipeline buildPipelineFromSpecifiedFile(File file, List stages = new ArrayList<>(); - SystemPreviewStage systemStage = null; + for (Map stageMap : stageList) { - StageType stageType = StageType.from(stageMap.get("type")); - - if (stageType == StageType.SYSTEM) { - // Handle system stage separately to maintain internal architecture - systemStage = mapToSystemStage(noLegacyCodedChangesByPackage, stageMap); - } else { - PreviewStage stage = mapToStage(noLegacyCodedChangesByPackage, stageMap); - stages.add(stage); - } + PreviewStage stage = mapToStage(standardChangesByPackage, stageMap); + stages.add(stage); } // Legacy Stage - PreviewStage legacyStage = buildLegacyStageIfNeeded(legacyCodedChanges); - if (legacyStage != null) { - stages.add(legacyStage); - } + buildLegacyStageIfNeeded(legacyCodedChanges) + .ifPresent(stages::add); // Sort stages by type priority: LEGACY stages first, then DEFAULT stages stages.sort(this::compareStagesByTypePriority); - return systemStage != null - ? new PreviewPipeline(systemStage, stages) - : new PreviewPipeline(stages); + return buildSystemStageIfNeeded(systemChanges) + .map(systemPreviewStage -> new PreviewPipeline(systemPreviewStage, stages)) + .orElseGet(() -> new PreviewPipeline(stages)); } catch (IOException e) { throw new RuntimeException(e); @@ -709,7 +695,6 @@ private String getResourcesRoot() { } - private void validateConfiguration(EnableFlamingock pipelineAnnotation, boolean hasFileInAnnotation, boolean hasStagesInAnnotation) { if (hasFileInAnnotation && hasStagesInAnnotation) { throw new RuntimeException("@EnableFlamingock annotation cannot have both configFile and stages configured. Choose one: either specify configFile OR stages."); 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 904e5d2e9..17fb124a7 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 @@ -44,7 +44,7 @@ public Collection findAnnotatedChanges(RoundEnvironment round } private CodePreviewChange buildCodePreviewChange(TypeElement typeElement) { - return Optional.ofNullable(CodePreviewTaskBuilder.builder(typeElement).build()) + return Optional.ofNullable(CodePreviewTaskBuilder.instance(typeElement).build()) .map(CodePreviewChange.class::cast) .orElse(null); } diff --git a/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java b/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java index ae4414d24..155994aaf 100644 --- a/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java +++ b/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java @@ -75,28 +75,20 @@ void shouldCreateCorrectPipelineStructureForAnnotationConfiguration() throws Exc // Then - verify the pipeline structure assertNotNull(pipeline, "Pipeline should be created"); assertNotNull(pipeline.getStages(), "Pipeline should have stages"); - assertEquals(2, pipeline.getStages().size(), "Should have 2 regular stages"); - + assertEquals(1, pipeline.getStages().size(), "Should have 2 regular stages"); + // Verify system stage PreviewStage systemStage = pipeline.getSystemStage(); - assertNotNull(systemStage, "Should have system stage"); - assertEquals("com.example.system", systemStage.getSourcesPackage()); - assertEquals("SystemStage", systemStage.getName()); + assertNull(systemStage, "Should NOT have system stage"); // Verify regular stages java.util.Collection stagesCollection = pipeline.getStages(); PreviewStage[] stages = stagesCollection.toArray(new PreviewStage[0]); - assertEquals(2, stages.length, "Should have 2 regular stages"); - - PreviewStage firstStage = stages[0]; - assertEquals("init", firstStage.getName()); // Should be derived from location - assertEquals(StageType.LEGACY, firstStage.getType()); - assertEquals("com.example.init", firstStage.getSourcesPackage()); - - PreviewStage secondStage = stages[1]; - assertEquals("migrations", secondStage.getName()); // Should be derived from location - assertEquals(StageType.DEFAULT, secondStage.getType()); - assertEquals("com.example.migrations", secondStage.getSourcesPackage()); + + PreviewStage uniqueStage = stages[0]; + assertEquals("migrations", uniqueStage.getName()); // Should be derived from location + assertEquals(StageType.DEFAULT, uniqueStage.getType()); + assertEquals("com.example.migrations", uniqueStage.getSourcesPackage()); } /** @@ -117,19 +109,21 @@ void shouldCreateCorrectPipelineStructureForFileConfiguration() throws Exception // Then - verify the pipeline structure assertNotNull(pipeline, "Pipeline should be created"); assertNotNull(pipeline.getStages(), "Pipeline should have stages"); - assertEquals(1, pipeline.getStages().size(), "Should have 1 regular stage from file"); + assertEquals(2, pipeline.getStages().size(), "Should have 2 regular stage from file"); // Verify system stage PreviewStage systemStage = pipeline.getSystemStage(); - assertNotNull(systemStage, "Should have system stage"); - assertEquals("com.example.system", systemStage.getSourcesPackage()); - assertEquals("SystemStage", systemStage.getName()); + assertNull(systemStage, "Should NOT have system stage"); // Verify regular stages PreviewStage[] stages = pipeline.getStages().toArray(new PreviewStage[0]); PreviewStage stage = stages[0]; - assertEquals("changes", stage.getName()); // Should be auto-derived from location - assertEquals("com.example.changes", stage.getSourcesPackage()); + assertEquals("migrations", stage.getName()); // Should be auto-derived from location + assertEquals("com.example.migrations", stage.getSourcesPackage()); + + PreviewStage stage2 = stages[1]; + assertEquals("changes", stage2.getName()); // Should be auto-derived from location + assertEquals("com.example.changes", stage2.getSourcesPackage()); } /** @@ -173,16 +167,15 @@ void shouldCreatePipelineWithCorrectObjectStructure() throws Exception { // Then - verify object structure (testing the actual objects, not JSON) assertNotNull(pipeline, "Pipeline should be created"); assertNotNull(pipeline.getStages(), "Pipeline should have stages"); - assertEquals(2, pipeline.getStages().size(), "Pipeline should have 2 regular stages"); + assertEquals(1, pipeline.getStages().size(), "Pipeline should have 1 regular stages"); PreviewStage systemStage = pipeline.getSystemStage(); - assertNotNull(systemStage, "Pipeline should have system stage"); - assertEquals("com.example.system", systemStage.getSourcesPackage()); + assertNull(systemStage, "Pipeline should NOT have system stage"); PreviewStage[] stages = pipeline.getStages().toArray(new PreviewStage[0]); PreviewStage firstStage = stages[0]; - assertEquals("init", firstStage.getName()); - assertEquals(StageType.LEGACY, firstStage.getType()); + assertEquals("migrations", firstStage.getName()); + assertEquals(StageType.DEFAULT, firstStage.getType()); } /** @@ -445,9 +438,9 @@ private PreviewPipeline buildPipelineFromAnnotation(FlamingockAnnotationProcesso setProcessorField(processor, "logger", new LoggerPreProcessor(mockEnv)); java.lang.reflect.Method method = FlamingockAnnotationProcessor.class.getDeclaredMethod( - "buildPipelineFromAnnotation", EnableFlamingock.class, List.class, Map.class); + "buildPipelineFromAnnotation", EnableFlamingock.class, List.class, List.class, Map.class); method.setAccessible(true); - return (PreviewPipeline) method.invoke(processor, annotation, Collections.emptyList(), changes); + return (PreviewPipeline) method.invoke(processor, annotation, Collections.emptyList(), Collections.emptyList(), changes); } private PreviewPipeline callGetPipelineFromProcessChanges(FlamingockAnnotationProcessor processor, Map> changes, EnableFlamingock annotation) throws Exception { @@ -460,9 +453,9 @@ private PreviewPipeline callGetPipelineFromProcessChanges(FlamingockAnnotationPr setProcessorField(processor, "logger", new LoggerPreProcessor(mockEnv)); java.lang.reflect.Method method = FlamingockAnnotationProcessor.class.getDeclaredMethod( - "getPipelineFromProcessChanges", List.class, Map.class, EnableFlamingock.class); + "getPipelineFromProcessChanges", List.class, List.class, Map.class, EnableFlamingock.class); method.setAccessible(true); - return (PreviewPipeline) method.invoke(processor, Collections.emptyList(), changes, annotation); + return (PreviewPipeline) method.invoke(processor, Collections.emptyList(), Collections.emptyList(), changes, annotation); } private PreviewPipeline buildPipelineFromFile(FlamingockAnnotationProcessor processor, EnableFlamingock annotation, Map> changes) throws Exception { @@ -475,11 +468,11 @@ private PreviewPipeline buildPipelineFromFile(FlamingockAnnotationProcessor proc setProcessorField(processor, "logger", new LoggerPreProcessor(mockEnv)); java.lang.reflect.Method method = FlamingockAnnotationProcessor.class.getDeclaredMethod( - "buildPipelineFromSpecifiedFile", File.class, List.class, Map.class); + "buildPipelineFromSpecifiedFile", File.class, List.class, List.class, Map.class); method.setAccessible(true); File configFile = tempDir.resolve("pipeline.yaml").toFile(); - return (PreviewPipeline) method.invoke(processor, configFile, Collections.emptyList(), changes); + return (PreviewPipeline) method.invoke(processor, configFile, Collections.emptyList(), Collections.emptyList(), changes); } private void setProcessorField(FlamingockAnnotationProcessor processor, String fieldName, Object value) throws Exception { @@ -551,8 +544,7 @@ private void createPipelineYamlFile() throws IOException { Path configFile = tempDir.resolve("pipeline.yaml"); String yamlContent = "pipeline:\n" + " stages:\n" + - " - location: com.example.system\n" + - " type: importer\n" + + " - location: com.example.migrations\n" + " - location: com.example.changes\n"; Files.write(configFile, yamlContent.getBytes()); } @@ -581,8 +573,6 @@ private Map> createMockChangesMap() { private EnableFlamingock createMockAnnotationWithStages() { return new MockFlamingockBuilder() .withStages( - createMockStage("", StageType.SYSTEM, "com.example.system"), - createMockStage("", StageType.LEGACY, "com.example.init"), createMockStage("", StageType.DEFAULT, "com.example.migrations") ) .build(); diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java b/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java index dd37ae29f..74012b8b2 100644 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java +++ b/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java @@ -17,7 +17,6 @@ import com.mongodb.client.MongoCollection; import io.flamingock.common.test.mongock.MongockTestHelper; -import io.flamingock.importer.mongock.MongockChangeEntry; import org.bson.Document; import java.util.ArrayList; diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterAdapter.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterAdapter.java index 779a44294..420bf87d3 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterAdapter.java +++ b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterAdapter.java @@ -15,12 +15,9 @@ */ package io.flamingock.importer; -import io.flamingock.internal.common.core.audit.AuditEntry; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; -import java.util.List; -public interface ImporterAdapter { - - List getAuditEntries(); +public interface ImporterAdapter extends AuditHistoryReader { } diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterExecutor.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterExecutor.java index 290ad5f01..01b425054 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterExecutor.java +++ b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterExecutor.java @@ -15,7 +15,7 @@ */ package io.flamingock.importer; -import io.flamingock.importer.util.PipelineHelper; +import io.flamingock.internal.common.core.pipeline.PipelineHelper; import io.flamingock.internal.common.core.audit.AuditEntry; import io.flamingock.internal.common.core.audit.AuditWriter; import io.flamingock.internal.common.core.error.FlamingockException; @@ -53,7 +53,7 @@ public static void runImport(ImporterAdapter importerAdapter, AuditWriter auditWriter, PipelineDescriptor pipelineDescriptor) { PipelineHelper pipelineHelper = new PipelineHelper(pipelineDescriptor); - List auditEntries = importerAdapter.getAuditEntries(); + List auditEntries = importerAdapter.getAuditHistory(); if(importConfiguration.isFailOnEmptyOrigin() && auditEntries.isEmpty()) { throw new FlamingockException( String.format("No audit entries found when importing from '%s'. " + diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java index fb7cf450c..abc68f725 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java +++ b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java @@ -16,7 +16,7 @@ package io.flamingock.importer.couchbase; import com.couchbase.client.java.json.JsonObject; -import io.flamingock.importer.mongock.MongockChangeState; +import io.flamingock.importer.mongodb.MongockChangeState; import io.flamingock.internal.common.core.audit.AuditEntry; import java.time.Instant; diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java index ca7ea5d3f..180728c61 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java +++ b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java @@ -43,7 +43,7 @@ public CouchbaseImporterAdapter(Cluster cluster, String bucketName, String scope } @Override - public List getAuditEntries() { + public List getAuditHistory() { QueryResult result = cluster.query( String.format( "SELECT `%s`.* FROM `%s`.`%s`.`%s` WHERE `_doctype` = $p1", diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java index 202d8daa4..3c7fb2c29 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java +++ b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java @@ -38,7 +38,7 @@ public DynamoDBImporterAdapter(DynamoDbClient client, String tableName) { } @Override - public List getAuditEntries() { + public List getAuditHistory() { List entries = StreamSupport .stream(sourceTable.scan().items().spliterator(), false) .collect(Collectors.toList()); diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/MongockDynamoDBAuditEntry.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/MongockDynamoDBAuditEntry.java index 669a59ad2..f02374dc6 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/MongockDynamoDBAuditEntry.java +++ b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/MongockDynamoDBAuditEntry.java @@ -15,7 +15,7 @@ */ package io.flamingock.importer.dynamodb; -import io.flamingock.importer.mongock.MongockChangeState; +import io.flamingock.importer.mongodb.MongockChangeState; import io.flamingock.internal.common.core.audit.AuditEntry; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java index 83b948a2a..093ffca6a 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java +++ b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java @@ -18,9 +18,6 @@ import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import io.flamingock.importer.ImporterAdapter; -import io.flamingock.importer.mongock.MongockChangeEntry; -import io.flamingock.importer.mongock.MongockChangeState; -import io.flamingock.importer.mongock.MongockChangeType; import io.flamingock.internal.common.core.audit.AuditEntry; import org.bson.Document; @@ -42,7 +39,7 @@ public MongoDBImporterAdapter(MongoDatabase mongoDatabase, String collectionName } @Override - public List getAuditEntries() { + public List getAuditHistory() { return sourceCollection.find() .into(new ArrayList<>()) .stream() diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeEntry.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeEntry.java similarity index 99% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeEntry.java rename to core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeEntry.java index f3fa1b392..7072f7f0a 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeEntry.java +++ b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeEntry.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongock; +package io.flamingock.importer.mongodb; import java.util.Date; diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeState.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeState.java similarity index 96% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeState.java rename to core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeState.java index 2784b98cd..b7a9cc5c6 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeState.java +++ b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeState.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongock; +package io.flamingock.importer.mongodb; import io.flamingock.internal.common.core.audit.AuditEntry; diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeType.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeType.java similarity index 95% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeType.java rename to core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeType.java index a91c663b3..3d5f5a03b 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeType.java +++ b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeType.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongock; +package io.flamingock.importer.mongodb; import io.flamingock.internal.common.core.audit.AuditEntry; diff --git a/core/importer/flamingock-importer/src/test/java/io/flamingock/importer/ImporterExecutorTest.java b/core/importer/flamingock-importer/src/test/java/io/flamingock/importer/ImporterExecutorTest.java index 7c07c3975..63a7e90dc 100644 --- a/core/importer/flamingock-importer/src/test/java/io/flamingock/importer/ImporterExecutorTest.java +++ b/core/importer/flamingock-importer/src/test/java/io/flamingock/importer/ImporterExecutorTest.java @@ -15,9 +15,6 @@ */ package io.flamingock.importer; -import io.flamingock.importer.ImportConfiguration; -import io.flamingock.importer.ImporterAdapter; -import io.flamingock.importer.ImporterExecutor; import io.flamingock.internal.common.core.audit.AuditWriter; import io.flamingock.internal.common.core.error.FlamingockException; import io.flamingock.internal.common.core.pipeline.PipelineDescriptor; @@ -41,7 +38,7 @@ void SHOULD_throwFlamingockException_WHEN_auditEntriesEmpty_IF_defaultImportConf AuditWriter auditWriter = mock(AuditWriter.class); PipelineDescriptor pipelineDescriptor = mock(PipelineDescriptor.class); - when(importerAdapter.getAuditEntries()).thenReturn(Collections.emptyList()); + when(importerAdapter.getAuditHistory()).thenReturn(Collections.emptyList()); // When & Then FlamingockException exception = assertThrows(FlamingockException.class, @@ -60,7 +57,7 @@ void SHOULD_notThrowException_WHEN_auditEntriesEmpty_IF_failOnEmptyOriginFalse() AuditWriter auditWriter = mock(AuditWriter.class); PipelineDescriptor pipelineDescriptor = mock(PipelineDescriptor.class); - when(importerAdapter.getAuditEntries()).thenReturn(Collections.emptyList()); + when(importerAdapter.getAuditHistory()).thenReturn(Collections.emptyList()); // When & Then assertDoesNotThrow(() -> ImporterExecutor.runImport(importerAdapter, importConfiguration, auditWriter, pipelineDescriptor)); diff --git a/core/target-systems/couchbase-target-system/build.gradle.kts b/core/target-systems/couchbase-target-system/build.gradle.kts index 42d3b6068..52eeb1120 100644 --- a/core/target-systems/couchbase-target-system/build.gradle.kts +++ b/core/target-systems/couchbase-target-system/build.gradle.kts @@ -4,6 +4,7 @@ dependencies { //Flamingock api(project(":core:flamingock-core")) implementation(project(":utils:couchbase-util")) + implementation(project(":legacy:mongock-importer-couchbase")) //General compileOnly("com.couchbase.client:java-client:3.6.0") diff --git a/core/target-systems/dynamodb-target-system/build.gradle.kts b/core/target-systems/dynamodb-target-system/build.gradle.kts index ef2cec7b6..410b1c1bf 100644 --- a/core/target-systems/dynamodb-target-system/build.gradle.kts +++ b/core/target-systems/dynamodb-target-system/build.gradle.kts @@ -1,7 +1,8 @@ dependencies { - implementation(project(":utils:dynamodb-util")) api(project(":core:flamingock-core")) + implementation(project(":utils:dynamodb-util")) + implementation(project(":legacy:mongock-importer-dynamodb")) compileOnly("software.amazon.awssdk:dynamodb-enhanced:2.25.29") 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 1d2b90f85..28daa6335 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 @@ -15,6 +15,9 @@ */ package io.flamingock.targetsystem.dynamodb; +import io.flamingock.importer.mongock.dynamodb.MongockImporterDynamoDB; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; +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.core.builder.FlamingockEdition; @@ -25,6 +28,12 @@ import software.amazon.awssdk.enhanced.dynamodb.model.TransactWriteItemsEnhancedRequest; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; +import java.util.Objects; +import java.util.Optional; + +import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK; +import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; + public class DynamoDBTargetSystem extends TransactionalTargetSystem { private DynamoDbClient client; @@ -74,4 +83,14 @@ protected DynamoDBTargetSystem getSelf() { public TransactionWrapper getTxWrapper() { return txWrapper; } + + + @Override + public Optional getAuditAuditReader(AuditReaderType type) { + if (Objects.requireNonNull(type) == MONGOCK) { + return Optional.of(new MongockImporterDynamoDB(client, DEFAULT_MONGOCK_ORIGIN)); + } else { + return Optional.empty(); + } + } } diff --git a/core/target-systems/mongodb-springdata-target-system/build.gradle.kts b/core/target-systems/mongodb-springdata-target-system/build.gradle.kts index 6d4ccb9c4..a4151ec22 100644 --- a/core/target-systems/mongodb-springdata-target-system/build.gradle.kts +++ b/core/target-systems/mongodb-springdata-target-system/build.gradle.kts @@ -10,6 +10,7 @@ dependencies { //Flamingock api(project(":core:flamingock-core")) implementation(project(":utils:mongodb-util")) + implementation(project(":legacy:mongock-importer-mongodb")) //General compileOnly("org.mongodb:mongodb-driver-sync:${versions["mongodb"]}") 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 8541a2b59..cb4650fbb 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 @@ -18,6 +18,9 @@ import com.mongodb.ReadConcern; import com.mongodb.ReadPreference; import com.mongodb.WriteConcern; +import io.flamingock.importer.mongock.mongodb.MongockImporterMongoDB; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; +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.core.targets.mark.NoOpTargetSystemAuditMarker; @@ -25,6 +28,12 @@ import io.flamingock.internal.core.transaction.TransactionWrapper; import org.springframework.data.mongodb.core.MongoTemplate; +import java.util.Objects; +import java.util.Optional; + +import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK; +import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; + public class MongoDBSpringDataTargetSystem extends TransactionalTargetSystem { @@ -113,4 +122,12 @@ public TransactionWrapper getTxWrapper() { return txWrapper; } + @Override + public Optional getAuditAuditReader(AuditReaderType type) { + if (Objects.requireNonNull(type) == MONGOCK) { + return Optional.of(new MongockImporterMongoDB(mongoTemplate.getDb(), DEFAULT_MONGOCK_ORIGIN)); + } else { + return Optional.empty(); + } + } } diff --git a/core/target-systems/mongodb-sync-target-system/build.gradle.kts b/core/target-systems/mongodb-sync-target-system/build.gradle.kts index 6f71f5262..b1f9fc890 100644 --- a/core/target-systems/mongodb-sync-target-system/build.gradle.kts +++ b/core/target-systems/mongodb-sync-target-system/build.gradle.kts @@ -1,9 +1,9 @@ -import org.jetbrains.kotlin.gradle.utils.extendsFrom dependencies { //Flamingock api(project(":core:flamingock-core")) implementation(project(":utils:mongodb-util")) + implementation(project(":legacy:mongock-importer-mongodb")) //General compileOnly("org.mongodb:mongodb-driver-sync:4.0.0") diff --git a/core/target-systems/mongodb-sync-target-system/src/main/java/io/flamingock/targetystem/mongodb/sync/MongoDBSyncTargetSystem.java b/core/target-systems/mongodb-sync-target-system/src/main/java/io/flamingock/targetystem/mongodb/sync/MongoDBSyncTargetSystem.java index 8bcea8c7f..970c6bc78 100644 --- a/core/target-systems/mongodb-sync-target-system/src/main/java/io/flamingock/targetystem/mongodb/sync/MongoDBSyncTargetSystem.java +++ b/core/target-systems/mongodb-sync-target-system/src/main/java/io/flamingock/targetystem/mongodb/sync/MongoDBSyncTargetSystem.java @@ -21,13 +21,21 @@ import com.mongodb.client.ClientSession; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoDatabase; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; +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.core.builder.FlamingockEdition; import io.flamingock.internal.core.transaction.TransactionManager; import io.flamingock.internal.core.targets.mark.NoOpTargetSystemAuditMarker; import io.flamingock.internal.core.targets.TransactionalTargetSystem; import io.flamingock.internal.core.transaction.TransactionWrapper; +import io.flamingock.importer.mongock.mongodb.MongockImporterMongoDB; + +import java.util.Objects; +import java.util.Optional; + +import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK; +import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; public class MongoDBSyncTargetSystem extends TransactionalTargetSystem { @@ -133,4 +141,13 @@ protected MongoDBSyncTargetSystem getSelf() { public TransactionWrapper getTxWrapper() { return txWrapper; } + + @Override + public Optional getAuditAuditReader(AuditReaderType type) { + if (Objects.requireNonNull(type) == MONGOCK) { + return Optional.of(new MongockImporterMongoDB(database, DEFAULT_MONGOCK_ORIGIN)); + } else { + return Optional.empty(); + } + } } diff --git a/legacy/mongock-importer-couchbase/build.gradle.kts b/legacy/mongock-importer-couchbase/build.gradle.kts new file mode 100644 index 000000000..3528e32fd --- /dev/null +++ b/legacy/mongock-importer-couchbase/build.gradle.kts @@ -0,0 +1,17 @@ +dependencies { + implementation(project(":core:flamingock-core-commons")) + implementation(project(":utils:couchbase-util")) + + //General + compileOnly("com.couchbase.client:java-client:3.6.0") +} + + +description = "A MongoDB migration utility that imports Mongock’s execution history into Flamingock-Community’s audit store for smooth project upgrades." + + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(8)) + } +} diff --git a/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/CouchbaseChangeEntry.java b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/CouchbaseChangeEntry.java new file mode 100644 index 000000000..2bf291e84 --- /dev/null +++ b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/CouchbaseChangeEntry.java @@ -0,0 +1,104 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.couchbase; + +import com.couchbase.client.java.json.JsonObject; +import io.flamingock.internal.common.core.audit.AuditEntry; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; + +public class CouchbaseChangeEntry { + private String executionId; + private String changeId; + private String author; + private String timestamp; + private String state; + private String type; + private String changeLogClass; + private String changeSetMethod; + private String metadata; + private Long executionMillis; + private String executionHostName; + private String errorTrace; + private Boolean systemChange; + + public String getExecutionId() { + return executionId; + } + + public void setExecutionId(String executionId) { + this.executionId = executionId; + } + + public static CouchbaseChangeEntry fromJson(JsonObject doc) { + CouchbaseChangeEntry entry = new CouchbaseChangeEntry(); + entry.executionId = doc.getString("executionId"); + entry.changeId = doc.getString("changeId"); + entry.author = doc.getString("author"); + entry.timestamp = doc.getString("timestamp"); + entry.state = doc.getString("state"); + entry.type = doc.getString("type"); + entry.changeLogClass = doc.getString("changeLogClass"); + entry.changeSetMethod = doc.getString("changeSetMethod"); + entry.metadata = doc.getString("metadata"); + entry.executionMillis = parseLong(doc.get("executionMillis")); + entry.executionHostName = doc.getString("executionHostName"); + entry.errorTrace = doc.getString("errorTrace"); + entry.systemChange = doc.getBoolean("systemChange"); + return entry; + } + + private static Long parseLong(Object value) { + if (value == null) return null; + if (value instanceof Number) return ((Number) value).longValue(); + if (value instanceof String) return Long.parseLong((String) value); + throw new IllegalArgumentException("Cannot convert value to Long: " + value); + } + + public AuditEntry toAuditEntry() { + long epochMillis; + try { + epochMillis = Long.parseLong(timestamp); + } catch (NumberFormatException e) { + String ts = timestamp; + if (ts.matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}")) { + ts = ts + "Z"; + } + epochMillis = Instant.parse(ts).toEpochMilli(); + } + LocalDateTime ts = LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()); + + MongockChangeState stateEnum = MongockChangeState.valueOf(state); + return new AuditEntry( + executionId, + null, + changeId, + author, + ts, + stateEnum.toAuditStatus(), + AuditEntry.ExecutionType.valueOf(type), + changeLogClass, + changeSetMethod, + executionMillis, + executionHostName, + metadata, + systemChange != null && systemChange, + errorTrace + ); + } +} \ No newline at end of file diff --git a/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockChangeState.java b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockChangeState.java new file mode 100644 index 000000000..a98287448 --- /dev/null +++ b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockChangeState.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.couchbase; + +import io.flamingock.internal.common.core.audit.AuditEntry; + +public enum MongockChangeState { + EXECUTED, FAILED, ROLLED_BACK, ROLLBACK_FAILED, IGNORED; + + public AuditEntry.Status toAuditStatus() { + switch (this) { + case FAILED: return AuditEntry.Status.FAILED; + case ROLLED_BACK: return AuditEntry.Status.ROLLED_BACK; + case ROLLBACK_FAILED: return AuditEntry.Status.ROLLBACK_FAILED; + case EXECUTED: + default: return AuditEntry.Status.APPLIED; + } + } + +} diff --git a/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockImporterCouchbase.java b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockImporterCouchbase.java new file mode 100644 index 000000000..9780fa9aa --- /dev/null +++ b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockImporterCouchbase.java @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.couchbase; + +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.query.QueryOptions; +import com.couchbase.client.java.query.QueryResult; +import com.couchbase.client.java.query.QueryScanConsistency; +import io.flamingock.internal.common.core.audit.AuditEntry; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; + +import java.util.List; +import java.util.stream.Collectors; + +public class MongockImporterCouchbase implements AuditHistoryReader { + + private static final String MONGOCK_CHANGE_ENTRY_DOCTYPE = "mongockChangeEntry"; + + private final Cluster cluster; + private final String bucketName; + private final String scopeName; + private final String collectionName; + + public MongockImporterCouchbase(Cluster cluster, String bucketName, String scopeName, String collectionName) { + this.cluster = cluster; + this.bucketName = bucketName; + this.scopeName = scopeName; + this.collectionName = collectionName; + } + + @Override + public List getAuditHistory() { + QueryResult result = cluster.query( + String.format( + "SELECT `%s`.* FROM `%s`.`%s`.`%s` WHERE `_doctype` = $p1", + collectionName, bucketName, scopeName, collectionName + ), + QueryOptions.queryOptions() + .scanConsistency(QueryScanConsistency.REQUEST_PLUS) + .parameters(JsonObject.create().put("p1", MONGOCK_CHANGE_ENTRY_DOCTYPE)) + ); + + return result.rowsAsObject().stream() + .map(CouchbaseChangeEntry::fromJson) + .map(CouchbaseChangeEntry::toAuditEntry) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/legacy/mongock-importer-dynamodb/build.gradle.kts b/legacy/mongock-importer-dynamodb/build.gradle.kts new file mode 100644 index 000000000..a01dce096 --- /dev/null +++ b/legacy/mongock-importer-dynamodb/build.gradle.kts @@ -0,0 +1,16 @@ +dependencies { + implementation(project(":core:flamingock-core-commons")) + implementation(project(":utils:dynamodb-util")) + + compileOnly("software.amazon.awssdk:dynamodb-enhanced:2.25.29") +} + + +description = "A MongoDB migration utility that imports Mongock’s execution history into Flamingock-Community’s audit store for smooth project upgrades." + + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(8)) + } +} diff --git a/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java new file mode 100644 index 000000000..9b373a4d9 --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java @@ -0,0 +1,213 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.dynamodb; + +import io.flamingock.importer.mongodb.MongockChangeState; +import io.flamingock.internal.common.core.audit.AuditEntry; +import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; +import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; + + +@DynamoDbBean +public class MongockAuditEntry { + private String executionId; + private String changeId; + private String author; + private String timestamp; + private String state; + private String type; + private String changeLogClass; + private String changeSetMethod; + private String metadata; + private Long executionMillis; + private String executionHostName; + private String errorTrace; + private Boolean systemChange; + + public MongockAuditEntry() { + } + + public MongockAuditEntry( + String executionId, + String changeId, + String author, + String timestamp, + String state, + String type, + String changeLogClass, + String changeSetMethod, + String metadata, + Long executionMillis, + String executionHostName, + String errorTrace, + Boolean systemChange + ) { + this.executionId = executionId; + this.changeId = changeId; + this.author = author; + this.timestamp = timestamp; + this.state = state; + this.type = type; + this.changeLogClass = changeLogClass; + this.changeSetMethod = changeSetMethod; + this.metadata = metadata; + this.executionMillis = executionMillis; + this.executionHostName = executionHostName; + this.errorTrace = errorTrace; + this.systemChange = systemChange; + } + + @DynamoDbPartitionKey + public String getChangeId() { + return changeId; + } + + public void setChangeId(String changeId) { + this.changeId = changeId; + } + + public String getExecutionId() { + return executionId; + } + + public void setExecutionId(String executionId) { + this.executionId = executionId; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getChangeLogClass() { + return changeLogClass; + } + + public void setChangeLogClass(String changeLogClass) { + this.changeLogClass = changeLogClass; + } + + public String getChangeSetMethod() { + return changeSetMethod; + } + + public void setChangeSetMethod(String changeSetMethod) { + this.changeSetMethod = changeSetMethod; + } + + public String getMetadata() { + return metadata; + } + + public void setMetadata(String metadata) { + this.metadata = metadata; + } + + public Long getExecutionMillis() { + return executionMillis; + } + + public void setExecutionMillis(Long executionMillis) { + this.executionMillis = executionMillis; + } + + public String getExecutionHostName() { + return executionHostName; + } + + public void setExecutionHostName(String executionHostName) { + this.executionHostName = executionHostName; + } + + public String getErrorTrace() { + return errorTrace; + } + + public void setErrorTrace(String errorTrace) { + this.errorTrace = errorTrace; + } + + public Boolean getSystemChange() { + return systemChange; + } + + public void setSystemChange(Boolean systemChange) { + this.systemChange = systemChange; + } + + public AuditEntry toAuditEntry() { + long epochMillis; + try { + epochMillis = Long.parseLong(timestamp); + } catch (NumberFormatException e) { + String ts = timestamp; + if (ts.matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}")) { + ts = ts + "Z"; + } + epochMillis = Instant.parse(ts).toEpochMilli(); + } + LocalDateTime ts = LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()); + + MongockChangeState stateEnum = MongockChangeState.valueOf(state); + return new AuditEntry( + executionId, + null, + changeId, + author, + ts, + stateEnum.toAuditStatus(), + AuditEntry.ExecutionType.valueOf(type), + changeLogClass, + changeSetMethod, + executionMillis, + executionHostName, + metadata, + systemChange != null && systemChange, + errorTrace + ); + } +} diff --git a/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockImporterDynamoDB.java b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockImporterDynamoDB.java new file mode 100644 index 000000000..603ec3276 --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockImporterDynamoDB.java @@ -0,0 +1,50 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.dynamodb; + +import io.flamingock.internal.common.core.audit.AuditEntry; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; +import software.amazon.awssdk.enhanced.dynamodb.TableSchema; +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +public class MongockImporterDynamoDB implements AuditHistoryReader { + + private final DynamoDbTable sourceTable; + + public MongockImporterDynamoDB(DynamoDbClient client, String tableName) { + DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() + .dynamoDbClient(client) + .build(); + this.sourceTable = enhancedClient.table(tableName, TableSchema.fromBean(MongockAuditEntry.class)); + } + + @Override + public List getAuditHistory() { + List entries = StreamSupport + .stream(sourceTable.scan().items().spliterator(), false) + .collect(Collectors.toList()); + + return entries.stream() + .map(MongockAuditEntry::toAuditEntry) + .collect(Collectors.toList()); + } +} diff --git a/legacy/mongock-importer-mongodb/build.gradle.kts b/legacy/mongock-importer-mongodb/build.gradle.kts new file mode 100644 index 000000000..d2c8c4e2e --- /dev/null +++ b/legacy/mongock-importer-mongodb/build.gradle.kts @@ -0,0 +1,45 @@ +dependencies { + implementation(project(":core:flamingock-core-commons")) + compileOnly("org.mongodb:mongodb-driver-sync:4.0.0") + + testAnnotationProcessor(project(":core:flamingock-processor")) + testAnnotationProcessor(project(":legacy:mongock-support")) + testImplementation(project(":legacy:mongock-support")) + testImplementation(project(":core:target-systems:mongodb-sync-target-system")) + testImplementation(project(":community:flamingock-auditstore-mongodb-sync")) + testImplementation(project(":templates:flamingock-mongodb-sync-template")) + testImplementation(project(":utils:test-util")) + testImplementation(project(":utils:mongodb-util")) + + testImplementation("org.testcontainers:mongodb:1.18.3") + + testImplementation("org.testcontainers:junit-jupiter:1.18.3") + testImplementation("org.mockito:mockito-inline:4.11.0") + +} + +description = "A MongoDB migration utility that imports Mongock’s execution history into Flamingock-Community’s audit store for smooth project upgrades." + + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(8)) + } +} + +tasks.test { + useJUnitPlatform() +} + + +tasks.withType().configureEach { + if (name.contains("Test", ignoreCase = true)) { + options.compilerArgs.addAll(listOf( + "-Asources=${projectDir}/src/test/java", + "-Aresources=${projectDir}/src/test/resources" + )) + } +} +configurations.testImplementation { + extendsFrom(configurations.compileOnly.get()) +} \ No newline at end of file diff --git a/legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockAuditEntry.java b/legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockAuditEntry.java new file mode 100644 index 000000000..4d9200f4f --- /dev/null +++ b/legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockAuditEntry.java @@ -0,0 +1,210 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.mongodb; + +import io.flamingock.internal.common.core.audit.AuditEntry; + +import java.util.Date; + +public class MongockAuditEntry { + + protected String executionId; + protected String changeId; + protected String author; + protected Date timestamp; + protected MongockChangeState state; + protected MongockChangeType type; + protected String changeLogClass; + protected String changeSetMethod; + protected Object metadata; + protected long executionMillis; + protected String executionHostname; + protected String errorTrace; + protected Boolean systemChange; + protected Date originalTimestamp; + + + public MongockAuditEntry(String executionId, + String changeId, + String author, + Date timestamp, + String state, + String type, + String changeLogClass, + String changeSetMethod, + Object metadata, + long executionMillis, + String executionHostname, + String errorTrace, + Boolean systemChange, + Date originalTimestamp) { + this.executionId = executionId; + this.changeId = changeId; + this.author = author; + this.timestamp = timestamp; + this.state = MongockAuditEntry.MongockChangeState.valueOf(state); + this.type = MongockChangeType.valueOf(type); + this.changeLogClass = changeLogClass; + this.changeSetMethod = changeSetMethod; + this.metadata = metadata; + this.executionMillis = executionMillis; + this.executionHostname = executionHostname; + this.errorTrace = errorTrace; + this.systemChange = systemChange; + this.originalTimestamp = originalTimestamp; + } + + public String getExecutionId() { + return executionId; + } + + public void setExecutionId(String executionId) { + this.executionId = executionId; + } + + public String getChangeId() { + return changeId; + } + + public void setChangeId(String changeId) { + this.changeId = changeId; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public Date getTimestamp() { + return timestamp; + } + + public void setTimestamp(Date timestamp) { + this.timestamp = timestamp; + } + + public AuditEntry.Status getState() { + return state.toAuditStatus(); + } + + public void setState(String state) { + this.state = MongockAuditEntry.MongockChangeState.valueOf(state); + } + + public AuditEntry.ExecutionType getType() { + return type.toAuditType(); + } + + public void setType(String type) { + this.type = MongockChangeType.valueOf(type); + } + + public String getChangeLogClass() { + return changeLogClass; + } + + public void setChangeLogClass(String changeLogClass) { + this.changeLogClass = changeLogClass; + } + + public String getChangeSetMethod() { + return changeSetMethod; + } + + public void setChangeSetMethod(String changeSetMethod) { + this.changeSetMethod = changeSetMethod; + } + + public Object getMetadata() { + return metadata; + } + + public void setMetadata(Object metadata) { + this.metadata = metadata; + } + + public long getExecutionMillis() { + return executionMillis; + } + + public void setExecutionMillis(long executionMillis) { + this.executionMillis = executionMillis; + } + + public String getExecutionHostname() { + return executionHostname; + } + + public void setExecutionHostname(String executionHostname) { + this.executionHostname = executionHostname; + } + + public String getErrorTrace() { + return errorTrace; + } + + public void setErrorTrace(String errorTrace) { + this.errorTrace = errorTrace; + } + + public Boolean getSystemChange() { + return systemChange; + } + + public void setSystemChange(Boolean systemChange) { + this.systemChange = systemChange; + } + + public Date getOriginalTimestamp() { + return originalTimestamp; + } + + public void setOriginalTimestamp(Date originalTimestamp) { + this.originalTimestamp = originalTimestamp; + } + + public boolean shouldBeIgnored() { + return state == MongockAuditEntry.MongockChangeState.IGNORED; + } + + + public enum MongockChangeState { + EXECUTED, FAILED, ROLLED_BACK, ROLLBACK_FAILED, IGNORED; + + public AuditEntry.Status toAuditStatus() { + switch (this) { + case FAILED: return AuditEntry.Status.FAILED; + case ROLLED_BACK: return AuditEntry.Status.ROLLED_BACK; + case ROLLBACK_FAILED: return AuditEntry.Status.ROLLBACK_FAILED; + case EXECUTED: + default: return AuditEntry.Status.APPLIED; + } + } + } + + public enum MongockChangeType { + EXECUTION, BEFORE_EXECUTION; + + public AuditEntry.ExecutionType toAuditType() { + //TODO: remove + return AuditEntry.ExecutionType.EXECUTION; + } + } + +} diff --git a/legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockImporterMongoDB.java b/legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockImporterMongoDB.java new file mode 100644 index 000000000..ee0aae869 --- /dev/null +++ b/legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockImporterMongoDB.java @@ -0,0 +1,96 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.mongodb; + +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import io.flamingock.internal.common.core.audit.AuditEntry; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; +import org.bson.Document; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +public class MongockImporterMongoDB implements AuditHistoryReader { + + private final MongoCollection sourceCollection; + + public MongockImporterMongoDB(MongoDatabase mongoDatabase, String collectionName) { + this.sourceCollection = mongoDatabase.getCollection(collectionName); + } + + @Override + public List getAuditHistory() { + return sourceCollection.find() + .into(new ArrayList<>()) + .stream() + .map(MongockImporterMongoDB::toAuditEntry) + .collect(Collectors.toList()); + } + + + private static AuditEntry toAuditEntry(Document document) { + MongockAuditEntry changeEntry = toChangeEntry(document); + LocalDateTime timestamp = Instant.ofEpochMilli(changeEntry.getTimestamp().getTime()) + .atZone(ZoneId.systemDefault()) + .toLocalDateTime(); + + if (changeEntry.shouldBeIgnored()) { + return null; + } + return new AuditEntry( + changeEntry.getExecutionId(), + null, + changeEntry.getChangeId(), + changeEntry.getAuthor(), + timestamp, + changeEntry.getState(), + changeEntry.getType(), + changeEntry.getChangeLogClass(), + changeEntry.getChangeSetMethod(), + changeEntry.getExecutionMillis(), + changeEntry.getExecutionHostname(), + changeEntry.getMetadata(), + changeEntry.getSystemChange(), + changeEntry.getErrorTrace() + ); + } + + private static MongockAuditEntry toChangeEntry(Document document) { + Date timestamp = document.getDate("timestamp"); + return new MongockAuditEntry( + document.getString("executionId"), + document.getString("changeId"), + document.getString("author"), + timestamp, + document.getString("state"), + document.getString("type"), + document.getString("changeLogClass"), + document.getString("changeSetMethod"), + document.get("metadata"), + document.getLong("executionMillis"), + document.getString("executionHostName"), + document.getString("errorTrace"), + document.getBoolean("systemChange"), + timestamp + ); + } +} 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 new file mode 100644 index 000000000..6d223fb1f --- /dev/null +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBImporterTest.java @@ -0,0 +1,155 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.mongodb; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import io.flamingock.api.annotations.EnableFlamingock; +import io.flamingock.api.annotations.Stage; +import io.flamingock.community.mongodb.sync.driver.MongoDBSyncAuditStore; +import io.flamingock.core.kit.TestKit; +import io.flamingock.core.kit.audit.AuditTestHelper; +import io.flamingock.internal.common.core.error.FlamingockException; +import io.flamingock.internal.core.runner.Runner; +import io.flamingock.mongodb.kit.MongoDBSyncTestKit; +import io.flamingock.support.mongock.annotations.MongockSupport; +import io.flamingock.targetystem.mongodb.sync.MongoDBSyncTargetSystem; +import org.bson.Document; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +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 org.junit.jupiter.api.Assertions.assertEquals; + +@Testcontainers +@MongockSupport(targetSystem = "mongodb-target-system") +@EnableFlamingock(stages = {@Stage(location = "io.flamingock.importer.mongock.mongodb.changes")}) +public class MongoDBImporterTest { + + @Container + private static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); + private static final String DB_NAME = "test"; + private static final String DATABASE_NAME = "test"; + private static MongoClient mongoClient; + private static MongoDatabase database; + private MongoDBMongockTestHelper mongockTestHelper; + private TestKit testKit; + private AuditTestHelper auditHelper; + + + @BeforeEach + void setUp() { + mongoClient = MongoClients.create(MongoClientSettings + .builder() + .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) + .build()); + database = mongoClient.getDatabase(DB_NAME); + + mongockTestHelper = new MongoDBMongockTestHelper(database.getCollection(DEFAULT_MONGOCK_ORIGIN)); + + // Initialize TestKit for unified testing + testKit = MongoDBSyncTestKit.create(new MongoDBSyncAuditStore(mongoClient, DATABASE_NAME), mongoClient, database); + auditHelper = testKit.getAuditHelper(); + + } + + @AfterEach + void tearDown() { + database.drop(); // Clean between tests + mongoClient.close(); + } + + @Test + void testImportMongockChangeLogs() { + //adds the Mongock + mongockTestHelper.setupBasicScenario(); + + + MongoDBSyncTargetSystem mongodbTargetSystem = new MongoDBSyncTargetSystem("mongodb-target-system", mongoClient, DATABASE_NAME); + + Runner flamingock = testKit.createBuilder() + .addTargetSystem(mongodbTargetSystem) + .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("client-initializer_before"), + APPLIED("client-initializer"), + APPLIED("client-updater"), + + // 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)); + } + + + @Test + @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") + void failIfEmptyOrigin() { + //adds the Mongock + + Runner flamingock = testKit.createBuilder() + .build(); + + //TODO should check error message, but currently it return the summary text + Assertions.assertThrows(FlamingockException.class, flamingock::run); + + } + +} diff --git a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java new file mode 100644 index 000000000..d08746de8 --- /dev/null +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.mongodb; + +import com.mongodb.client.MongoCollection; +import io.flamingock.common.test.mongock.MongockTestHelper; +import io.flamingock.importer.mongodb.MongockChangeEntry; +import org.bson.Document; + +import java.util.ArrayList; +import java.util.List; + +public class MongoDBMongockTestHelper implements MongockTestHelper { + + private final MongoCollection changeLogCollection; + + public MongoDBMongockTestHelper(MongoCollection changeLogCollection) { + this.changeLogCollection = changeLogCollection; + } + + public void write(MongockChangeEntry entry) { + changeLogCollection.insertOne(convertToDocument(entry)); + } + + public int writeAll(List entries) { + List documents = new ArrayList<>(entries.size()); + for (MongockChangeEntry entry : entries) { + documents.add(convertToDocument(entry)); + } + changeLogCollection.insertMany(documents); + return documents.size(); + } + + private Document convertToDocument(MongockChangeEntry entry) { + Document document = new Document(); + document.put("executionId", entry.getExecutionId()); + document.put("changeId", entry.getChangeId()); + document.put("author", entry.getAuthor()); + document.put("timestamp", entry.getTimestamp()); + document.put("state", entry.getState() != null ? entry.getState().toString() : null); + document.put("type", entry.getType() != null ? entry.getType().toString() : null); + document.put("changeLogClass", entry.getChangeLogClass()); + document.put("changeSetMethod", entry.getChangeSetMethod()); + document.put("metadata", entry.getMetadata()); + document.put("executionMillis", entry.getExecutionMillis()); + document.put("executionHostname", entry.getExecutionHostname()); + document.put("errorTrace", entry.getErrorTrace()); + document.put("systemChange", entry.getSystemChange()); + document.put("originalTimestamp", entry.getOriginalTimestamp()); + return document; + } +} diff --git a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0003__create_users_collections.yaml b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0003__create_users_collections.yaml new file mode 100644 index 000000000..555e3f317 --- /dev/null +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0003__create_users_collections.yaml @@ -0,0 +1,9 @@ +id: create-users-collection-with-index +#transactional: false +template: MongoChangeTemplate +targetSystem: + id: "mongodb-target-system" +apply: + type: createCollection + collection: users + diff --git a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0004__seed_users.yaml b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0004__seed_users.yaml new file mode 100644 index 000000000..ca5b78b8d --- /dev/null +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0004__seed_users.yaml @@ -0,0 +1,16 @@ +id: seed-users +transactional: true +template: MongoChangeTemplate +targetSystem: + id: "mongodb-target-system" +apply: + type: insert + collection: users + parameters: + documents: + - name: "Admin" + email: "admin@company.com" + roles: [ "superuser" ] + - name: "Backup" + email: "backup@company.com" + roles: [ "readonly" ] \ No newline at end of file diff --git a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange1.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange1.java new file mode 100644 index 000000000..74408630f --- /dev/null +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange1.java @@ -0,0 +1,29 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.mongodb.legacy; + +import io.flamingock.api.annotations.Apply; +import io.mongock.api.annotations.ChangeUnit; +import io.mongock.api.annotations.Execution; + +@ChangeUnit(id = "client-initializer", order = "1", author = "flamingock-team") +public class MongockChange1 { + + @Execution + public void apply() { + System.out.println("Client Initializer"); + } +} diff --git a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange2.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange2.java new file mode 100644 index 000000000..1912a5f0a --- /dev/null +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange2.java @@ -0,0 +1,30 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.mongodb.legacy; + +import io.flamingock.api.annotations.Apply; +import io.flamingock.api.annotations.Change; +import io.mongock.api.annotations.ChangeUnit; +import io.mongock.api.annotations.Execution; + +@ChangeUnit(id = "client-updater", order = "2", author = "flamingock-team") +public class MongockChange2 { + + @Execution + public void apply() { + System.out.println("Client Initializer"); + } +} 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 new file mode 100644 index 000000000..581746b0c --- /dev/null +++ b/legacy/mongock-support/src/main/java/io/flamingock/support/mongock/MongockImportChange.java @@ -0,0 +1,85 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.support.mongock; + +import io.flamingock.api.annotations.NonLockGuarded; +import io.flamingock.internal.common.core.pipeline.PipelineHelper; +import io.flamingock.internal.common.core.audit.AuditEntry; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; +import io.flamingock.internal.common.core.audit.AuditWriter; +import io.flamingock.internal.common.core.error.FlamingockException; +import io.flamingock.internal.common.core.pipeline.PipelineDescriptor; +import io.flamingock.internal.core.targets.TargetSystemManager; +import io.flamingock.internal.core.targets.operations.TargetSystemOps; +import io.flamingock.internal.core.targets.operations.TransactionalTargetSystemOps; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Named; +import java.util.List; + +import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK; + +/** + * This ChangeUnit is intentionally not annotated with @Change, @Apply, or similar, + * because it should not be auto-discovered or included in a standard execution stage. + * Instead, the module injects it programmatically. + */ +public class MongockImportChange { + private static final Logger logger = LoggerFactory.getLogger("MongockImporter"); + + public void importHistory(@Named("change.targetSystem.id") String targetSystemId, + @NonLockGuarded TargetSystemManager targetSystemManager, + @NonLockGuarded AuditWriter auditWriter, + @NonLockGuarded PipelineDescriptor pipelineDescriptor) { + 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); + 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( + pipelineHelper.getStorableTaskId(auditEntryFromOrigin), + pipelineHelper.getStageId(auditEntryFromOrigin)); + auditWriter.writeEntry(auditEntryWithStageId); + }); + } + + private static AuditHistoryReader getAuditHistoryReader(String targetSystemId, TargetSystemManager targetSystemManager) { + TargetSystemOps targetSystemOps = targetSystemManager.getTargetSystem(targetSystemId); + AuditHistoryReader legacyAuditReader; + if (targetSystemOps instanceof TransactionalTargetSystemOps) { + legacyAuditReader = ((TransactionalTargetSystemOps) targetSystemOps).getAuditAuditReader(MONGOCK) + .orElseThrow(() -> { + String message = "TargetSystem[%s], specified in @MongockSupport doesn't provide Mongock importing support"; + return new FlamingockException(message); + }); + } else { + String message = "TargetSystem[%s], specified in @MongockSupport must be a TransactionalTargetSystem"; + throw new FlamingockException(message); + } + return legacyAuditReader; + } + + + + private void validate(List legacyHistory) { + if (legacyHistory.isEmpty()) { + throw new FlamingockException("No audit entries found when importing from '%s'."); + } + } +} 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 92b90a591..2b110dcf3 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 @@ -16,10 +16,19 @@ package io.flamingock.support.mongock.processor.discover; import com.github.cloudyrock.mongock.ChangeLog; +import io.flamingock.internal.common.core.audit.AuditWriter; import io.flamingock.internal.common.core.discover.ChangeDiscoverer; import io.flamingock.internal.common.core.error.FlamingockException; +import io.flamingock.internal.common.core.pipeline.PipelineDescriptor; import io.flamingock.internal.common.core.preview.CodePreviewChange; +import io.flamingock.internal.common.core.preview.PreviewConstructor; +import io.flamingock.internal.common.core.preview.PreviewMethod; +import io.flamingock.internal.common.core.preview.builder.CodePreviewTaskBuilder; +import io.flamingock.internal.common.core.task.RecoveryDescriptor; +import io.flamingock.internal.common.core.task.TargetSystemDescriptor; import io.flamingock.internal.common.core.util.LoggerPreProcessor; +import io.flamingock.internal.core.targets.TargetSystemManager; +import io.flamingock.support.mongock.MongockImportChange; import io.flamingock.support.mongock.annotations.MongockSupport; import io.flamingock.support.mongock.internal.preview.builder.MongockCodePreviewChangeHelper; import io.mongock.api.annotations.ChangeUnit; @@ -27,8 +36,8 @@ import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; +import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -48,7 +57,7 @@ public Collection findAnnotatedChanges(RoundEnvironment round if (mongockSupportOpt.isPresent()) { logger.info("Searching for code-based changes (Java classes annotated with @ChangeUnit or @ChangeLog annotations)"); - return Stream.concat( + List changes = Stream.concat( roundEnv.getElementsAnnotatedWith(ChangeUnit.class).stream(), roundEnv.getElementsAnnotatedWith(ChangeLog.class).stream() ) @@ -58,12 +67,35 @@ public Collection findAnnotatedChanges(RoundEnvironment round .flatMap(List::stream) .filter(Objects::nonNull) .collect(Collectors.toList()); - } - else { + changes.add(getImporterChange(mongockTargetSystemId)); + return changes; + } else { throw new FlamingockException("@MongockSupport annotation must be provided when mongock-support module is present."); } } + private CodePreviewChange getImporterChange(String targetSystemId) { + CodePreviewTaskBuilder builder = CodePreviewTaskBuilder.instance(); + builder.setId("migration-mongock-to-flamingock-community"); + builder.setOrder("00100"); + builder.setAuthor("flamingock-team"); + builder.setTargetSystem(new TargetSystemDescriptor(targetSystemId)); + builder.setTransactional(true); + builder.setSystem(true); + builder.setRecovery(RecoveryDescriptor.getDefault()); + + builder.setSourceClassPath(MongockImportChange.class.getName()); + builder.setConstructor(PreviewConstructor.getDefault()); + List applyParameterTypes = Arrays.asList( + String.class.getName(), + TargetSystemManager.class.getName(), + AuditWriter.class.getName(), + PipelineDescriptor.class.getName() + ); + builder.setApplyMethod(new PreviewMethod("importHistory", applyParameterTypes)); + return builder.build(); + } + private Optional getMongockSupportAnnotation(RoundEnvironment roundEnv, LoggerPreProcessor logger) { return roundEnv.getElementsAnnotatedWith(MongockSupport.class) .stream() diff --git a/settings.gradle.kts b/settings.gradle.kts index 2a5d8d226..590ee1c4f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -53,7 +53,8 @@ project(":community:flamingock-community-bom").projectDir = file("community/flam include("community:flamingock-auditstore-mongodb-sync") project(":community:flamingock-auditstore-mongodb-sync").name = "flamingock-auditstore-mongodb-sync" -project(":community:flamingock-auditstore-mongodb-sync").projectDir = file("community/flamingock-auditstore-mongodb-sync") +project(":community:flamingock-auditstore-mongodb-sync").projectDir = + file("community/flamingock-auditstore-mongodb-sync") include("community:flamingock-auditstore-couchbase") project(":community:flamingock-auditstore-couchbase").name = "flamingock-auditstore-couchbase" @@ -80,15 +81,18 @@ project(":platform-plugins:flamingock-springboot-integration").projectDir = ////////////////////////////////////// include("core:target-systems:nontransactional-target-system") -project(":core:target-systems:nontransactional-target-system").projectDir = file("core/target-systems/nontransactional-target-system") +project(":core:target-systems:nontransactional-target-system").projectDir = + file("core/target-systems/nontransactional-target-system") project(":core:target-systems:nontransactional-target-system").name = "nontransactional-target-system" include("core:target-systems:mongodb-sync-target-system") -project(":core:target-systems:mongodb-sync-target-system").projectDir = file("core/target-systems/mongodb-sync-target-system") +project(":core:target-systems:mongodb-sync-target-system").projectDir = + file("core/target-systems/mongodb-sync-target-system") project(":core:target-systems:mongodb-sync-target-system").name = "mongodb-sync-target-system" include("core:target-systems:mongodb-springdata-target-system") -project(":core:target-systems:mongodb-springdata-target-system").projectDir = file("core/target-systems/mongodb-springdata-target-system") +project(":core:target-systems:mongodb-springdata-target-system").projectDir = + file("core/target-systems/mongodb-springdata-target-system") project(":core:target-systems:mongodb-springdata-target-system").name = "mongodb-springdata-target-system" include("core:target-systems:sql-target-system") @@ -157,25 +161,40 @@ project(":core:importer:flamingock-importer").projectDir = file("core/importer/f include("core:importer:flamingock-importer-mongodb-tests") project(":core:importer:flamingock-importer-mongodb-tests").name = "flamingock-importer-mongodb-tests" -project(":core:importer:flamingock-importer-mongodb-tests").projectDir = file("core/importer/flamingock-importer-mongodb-tests") +project(":core:importer:flamingock-importer-mongodb-tests").projectDir = + file("core/importer/flamingock-importer-mongodb-tests") include("core:importer:flamingock-importer-dynamodb-tests") project(":core:importer:flamingock-importer-dynamodb-tests").name = "flamingock-importer-dynamodb-tests" -project(":core:importer:flamingock-importer-dynamodb-tests").projectDir = file("core/importer/flamingock-importer-dynamodb-tests") +project(":core:importer:flamingock-importer-dynamodb-tests").projectDir = + file("core/importer/flamingock-importer-dynamodb-tests") include("core:importer:flamingock-importer-couchbase-tests") project(":core:importer:flamingock-importer-couchbase-tests").name = "flamingock-importer-couchbase-tests" -project(":core:importer:flamingock-importer-couchbase-tests").projectDir = file("core/importer/flamingock-importer-couchbase-tests") +project(":core:importer:flamingock-importer-couchbase-tests").projectDir = + file("core/importer/flamingock-importer-couchbase-tests") ////////////////////////////////////// -// SUPPORT +// LEGACY ////////////////////////////////////// include("legacy:mongock-support") project(":legacy:mongock-support").name = "mongock-support" project(":legacy:mongock-support").projectDir = file("legacy/mongock-support") +include("legacy:mongock-importer-mongodb") +project(":legacy:mongock-importer-mongodb").name = "mongock-importer-mongodb" +project(":legacy:mongock-importer-mongodb").projectDir = file("legacy/mongock-importer-mongodb") + +include("legacy:mongock-importer-dynamodb") +project(":legacy:mongock-importer-dynamodb").name = "mongock-importer-dynamodb" +project(":legacy:mongock-importer-dynamodb").projectDir = file("legacy/mongock-importer-dynamodb") + +include("legacy:mongock-importer-couchbase") +project(":legacy:mongock-importer-couchbase").name = "mongock-importer-couchbase" +project(":legacy:mongock-importer-couchbase").projectDir = file("legacy/mongock-importer-couchbase") + ////////////////////////////////////// // CLI ////////////////////////////////////// @@ -189,3 +208,5 @@ project(":cli:flamingock-cli").projectDir = file("cli/flamingock-cli") include("e2e:core-e2e") project(":e2e:core-e2e").name = "core-e2e" project(":e2e:core-e2e").projectDir = file("e2e/core-e2e") + + diff --git a/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockTestHelper.java b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockTestHelper.java index ca08df75f..f2312909a 100644 --- a/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockTestHelper.java +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockTestHelper.java @@ -15,9 +15,9 @@ */ package io.flamingock.common.test.mongock; -import io.flamingock.importer.mongock.MongockChangeEntry; -import io.flamingock.importer.mongock.MongockChangeState; -import io.flamingock.importer.mongock.MongockChangeType; +import io.flamingock.importer.mongodb.MongockChangeEntry; +import io.flamingock.importer.mongodb.MongockChangeState; +import io.flamingock.importer.mongodb.MongockChangeType; import java.text.ParseException; import java.text.SimpleDateFormat; From e409f7e31aa08bfc50624d2b0805b746e131d057 Mon Sep 17 00:00:00 2001 From: Antonio Perez Dieppa Date: Sat, 22 Nov 2025 14:38:19 +0000 Subject: [PATCH 02/10] feat: Mongock import to FlamingockCommunity(WIP: dynamodb) --- .../build.gradle.kts | 16 + .../dynamodb/DynamoDBImporterTest.java | 193 +++++++++++ .../mongock/dynamodb/DynamoDBTestHelper.java | 163 +++++++++ .../changes/DynamoDBAuditEntryEntity.java | 308 ++++++++++++++++++ .../dynamodb/changes/DynamoDBConstants.java | 27 ++ .../dynamodb/changes/MongockChange1.java | 28 ++ .../dynamodb/changes/MongockChange2.java | 28 ++ .../_0001__CreateUsersTableChange.java | 52 +++ .../mongock/mongodb/MongoDBImporterTest.java | 4 + .../{legacy => changes}/MongockChange1.java | 3 +- .../{legacy => changes}/MongockChange2.java | 4 +- 11 files changed, 821 insertions(+), 5 deletions(-) create mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBImporterTest.java create mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBTestHelper.java create mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBAuditEntryEntity.java create mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBConstants.java create mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange1.java create mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange2.java create mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java rename legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/{legacy => changes}/MongockChange1.java (90%) rename legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/{legacy => changes}/MongockChange2.java (86%) diff --git a/legacy/mongock-importer-dynamodb/build.gradle.kts b/legacy/mongock-importer-dynamodb/build.gradle.kts index a01dce096..5f3e889ec 100644 --- a/legacy/mongock-importer-dynamodb/build.gradle.kts +++ b/legacy/mongock-importer-dynamodb/build.gradle.kts @@ -3,6 +3,22 @@ dependencies { implementation(project(":utils:dynamodb-util")) compileOnly("software.amazon.awssdk:dynamodb-enhanced:2.25.29") + + testAnnotationProcessor(project(":core:flamingock-processor")) + testAnnotationProcessor(project(":legacy:mongock-support")) + testImplementation(project(":legacy:mongock-support")) + + testImplementation(project(":community:flamingock-auditstore-dynamodb")) + + + testImplementation(project(":utils:test-util")) + + testImplementation("org.testcontainers:junit-jupiter:1.18.3") + testImplementation("org.mockito:mockito-inline:4.11.0") + testImplementation("org.testcontainers:localstack:1.19.7") + testImplementation("software.amazon.awssdk:dynamodb:2.25.61") + + testImplementation("org.mockito:mockito-inline:4.11.0") } 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 new file mode 100644 index 000000000..9690a175b --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBImporterTest.java @@ -0,0 +1,193 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.dynamodb; + +import io.flamingock.api.annotations.EnableFlamingock; +import io.flamingock.api.annotations.Stage; +import io.flamingock.community.dynamodb.driver.DynamoDBAuditStore; +import io.flamingock.importer.dynamodb.MongockDynamoDBAuditEntry; +import io.flamingock.internal.common.core.audit.AuditEntry; +import io.flamingock.internal.common.core.error.FlamingockException; +import io.flamingock.internal.core.builder.FlamingockFactory; +import io.flamingock.internal.core.runner.Runner; +import io.flamingock.support.mongock.annotations.MongockSupport; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; +import software.amazon.awssdk.services.dynamodb.model.ScanRequest; +import software.amazon.awssdk.services.dynamodb.model.ScanResponse; + +import java.net.URI; +import java.time.Instant; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import static io.flamingock.internal.util.constants.CommunityPersistenceConstants.DEFAULT_AUDIT_STORE_NAME; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Testcontainers +@MongockSupport(targetSystem = "dynamodb-target-system") +@EnableFlamingock(stages = {@Stage(location = "io.flamingock.importer.mongock.dynamodb.changes")}) +public class DynamoDBImporterTest { + + @Container + public static final GenericContainer dynamoDBContainer = new GenericContainer<>("amazon/dynamodb-local:latest") + .withExposedPorts(8000); + + public static final String MONGOCK_CHANGE_LOGS = "mongockChangeLogs"; + + + private static DynamoDbClient client; + private DynamoDBTestHelper mongockChangeLogsHelper; + + @BeforeAll + static void beforeAll() { + dynamoDBContainer.start(); + + String endpoint = String.format("http://%s:%d", + dynamoDBContainer.getHost(), + dynamoDBContainer.getMappedPort(8000)); + client = DynamoDbClient.builder() + .endpointOverride(URI.create(endpoint)) + .region(Region.US_EAST_1) + .credentialsProvider( + StaticCredentialsProvider.create( + AwsBasicCredentials.create("dummy", "dummy") + ) + ) + .build(); + } + + @BeforeEach + void setUp() { + mongockChangeLogsHelper = new DynamoDBTestHelper(client, MONGOCK_CHANGE_LOGS); + mongockChangeLogsHelper.ensureTableExists(); + mongockChangeLogsHelper.resetTable(); + + new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).ensureTableExists(); + new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).resetTable(); + } + + @Test + @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") + void testImportDynamoDBChangeLogs() { + List entries = Arrays.asList( + new MongockDynamoDBAuditEntry( + "exec-1", + "client-initializer", + "author1", + String.valueOf(Instant.now().toEpochMilli()), + "EXECUTED", + "EXECUTION", + "io.flamingock.changelog.Class1", + "method1", + new HashMap() {{ + put("meta1", "value1"); + }}.toString(), + 123L, + "host1", + null, + true + ), + new MongockDynamoDBAuditEntry( + "exec-1", + "client-updater", + "author1", + String.valueOf(Instant.now().toEpochMilli()), + "EXECUTED", + "EXECUTION", + "io.flamingock.changelog.Class2", + "method1", + new HashMap() {{ + put("meta1", "value1"); + }}.toString(), + 123L, + "host1", + null, + true + ) + ); + + mongockChangeLogsHelper.insertChangeEntries(entries); + + Runner flamingock = FlamingockFactory.getCommunityBuilder() + .setAuditStore(new DynamoDBAuditStore(client)) + .build(); + + flamingock.run(); + + List auditLog = new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).getAuditEntriesSorted(); + assertEquals(6, auditLog.size()); + + for (AuditEntry entry : auditLog) { + System.out.println("executionId: " + entry.getExecutionId()); + System.out.println("stageId: " + entry.getStageId()); + System.out.println("taskId: " + entry.getTaskId()); + System.out.println("author: " + entry.getAuthor()); + System.out.println("createdAt: " + entry.getCreatedAt()); + System.out.println("state: " + entry.getState()); + System.out.println("type: " + entry.getType()); + System.out.println("className: " + entry.getClassName()); + System.out.println("methodName: " + entry.getMethodName()); + System.out.println("executionMillis: " + entry.getExecutionMillis()); + System.out.println("executionHostname: " + entry.getExecutionHostname()); + System.out.println("metadata: " + entry.getMetadata()); + System.out.println("systemChange: " + entry.getSystemChange()); + System.out.println("errorTrace: " + entry.getErrorTrace()); + System.out.println("txStrategy: " + entry.getTxType()); + System.out.println("targetSystemId: " + entry.getTargetSystemId()); + System.out.println("order: " + entry.getOrder()); + System.out.println("-----"); + } + + AuditEntry entry1 = auditLog.stream() + .filter(e -> "client-updater".equals(e.getTaskId())) + .findFirst() + .orElseThrow(() -> new AssertionError("Entry with changeId 'client-updater' not found")); + + + assertEquals("client-updater", entry1.getTaskId()); + assertEquals("author1", entry1.getAuthor()); + assertEquals("exec-1", entry1.getExecutionId()); + assertTrue(entry1.getSystemChange()); + + ScanResponse scanResponse = client.scan( + ScanRequest.builder().tableName(DEFAULT_AUDIT_STORE_NAME).build() + ); + assertTrue(scanResponse.count() > 0, "Audit table should not be empty"); + } + + @Test + @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") + void failIfEmptyOrigin() { + Runner flamingock = FlamingockFactory.getCommunityBuilder() + .setAuditStore(new DynamoDBAuditStore(client)) + .build(); + + Assertions.assertThrows(FlamingockException.class, flamingock::run); + } +} diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBTestHelper.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBTestHelper.java new file mode 100644 index 000000000..2d3d88f2f --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBTestHelper.java @@ -0,0 +1,163 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.dynamodb; + +import io.flamingock.importer.dynamodb.MongockDynamoDBAuditEntry; +import io.flamingock.importer.dynamodb.dynamodb.DynamoDBAuditEntryEntity; +import io.flamingock.internal.common.core.audit.AuditEntry; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; +import software.amazon.awssdk.enhanced.dynamodb.TableSchema; +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; +import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition; +import software.amazon.awssdk.services.dynamodb.model.AttributeValue; +import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest; +import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest; +import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest; +import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse; +import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement; +import software.amazon.awssdk.services.dynamodb.model.KeyType; +import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse; +import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput; +import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; +import software.amazon.awssdk.services.dynamodb.model.ScanRequest; +import software.amazon.awssdk.services.dynamodb.model.ScanResponse; +import software.amazon.awssdk.services.dynamodb.model.TableStatus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static io.flamingock.internal.util.constants.CommunityPersistenceConstants.DEFAULT_AUDIT_STORE_NAME; + +public class DynamoDBTestHelper { + + private final DynamoDbClient client; + private final String tableName; + private final DynamoDbTable table; + + public DynamoDBTestHelper(DynamoDbClient client, String tableName) { + this.client = client; + this.tableName = tableName; + DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() + .dynamoDbClient(client) + .build(); + + if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { + this.table = enhancedClient.table(tableName, TableSchema.fromBean(DynamoDBAuditEntryEntity.class)); + } else { + this.table = enhancedClient.table(tableName, TableSchema.fromBean(MongockDynamoDBAuditEntry.class)); + } + } + + public void ensureTableExists() { + ListTablesResponse tables = client.listTables(); + if (!tables.tableNames().contains(tableName)) { + if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { + client.createTable(CreateTableRequest.builder() + .tableName(tableName) + .keySchema( + KeySchemaElement.builder().attributeName("partitionKey").keyType(KeyType.HASH).build() + ) + .attributeDefinitions( + AttributeDefinition.builder().attributeName("partitionKey").attributeType(ScalarAttributeType.S).build() + ) + .provisionedThroughput( + ProvisionedThroughput.builder().readCapacityUnits(5L).writeCapacityUnits(5L).build() + ) + .build()); + } else { + client.createTable(CreateTableRequest.builder() + .tableName(tableName) + .keySchema( + KeySchemaElement.builder().attributeName("executionId").keyType(KeyType.HASH).build(), + KeySchemaElement.builder().attributeName("changeId").keyType(KeyType.RANGE).build() + ) + .attributeDefinitions( + AttributeDefinition.builder().attributeName("executionId").attributeType(ScalarAttributeType.S).build(), + AttributeDefinition.builder().attributeName("changeId").attributeType(ScalarAttributeType.S).build() + ) + .provisionedThroughput( + ProvisionedThroughput.builder().readCapacityUnits(5L).writeCapacityUnits(5L).build() + ) + .build()); + } + waitForTableActive(); + } + } + + private void waitForTableActive() { + while (true) { + DescribeTableResponse resp = client.describeTable(DescribeTableRequest.builder().tableName(tableName).build()); + if (resp.table().tableStatus() == TableStatus.ACTIVE) { + break; + } + try { + Thread.sleep(200); + } catch (InterruptedException ignored) {} + } + } + + public void resetTable() { + ScanRequest scanRequest = ScanRequest.builder().tableName(tableName).build(); + ScanResponse scanResponse = client.scan(scanRequest); + for (Map item : scanResponse.items()) { + Map key = new HashMap<>(); + if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { + key.put("partitionKey", item.get("partitionKey")); + } else { + key.put("executionId", item.get("executionId")); + key.put("changeId", item.get("changeId")); + } + client.deleteItem(DeleteItemRequest.builder() + .tableName(tableName) + .key(key) + .build()); + } + } + + public void insertChangeEntries(List entries) { + if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { + throw new UnsupportedOperationException("insertChangeEntries is only for change log tables"); + } + DynamoDbTable changeTable = (DynamoDbTable) table; + for (MongockDynamoDBAuditEntry entry : entries) { + changeTable.putItem(entry); + } + } + + public List getAuditEntriesSorted() { + if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { + DynamoDbTable auditTable = (DynamoDbTable) table; + List entities = new ArrayList<>(); + auditTable.scan().items().forEach(entities::add); + return entities.stream() + .map(DynamoDBAuditEntryEntity::toAuditEntry) + .sorted() + .collect(Collectors.toList()); + } else { + DynamoDbTable changeTable = (DynamoDbTable) table; + List entries = new ArrayList<>(); + changeTable.scan().items().forEach(entries::add); + return entries.stream() + .map(MongockDynamoDBAuditEntry::toAuditEntry) + .sorted() + .collect(Collectors.toList()); + } + } +} diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBAuditEntryEntity.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBAuditEntryEntity.java new file mode 100644 index 000000000..45ba01d50 --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBAuditEntryEntity.java @@ -0,0 +1,308 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.dynamodb.changes; + +import io.flamingock.api.RecoveryStrategy; +import io.flamingock.internal.common.core.audit.AuditEntry; +import io.flamingock.internal.common.core.audit.AuditTxType; +import io.flamingock.internal.util.constants.AuditEntryFieldConstants; +import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute; +import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; +import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; + +import java.time.LocalDateTime; +import java.util.Objects; + +@DynamoDbBean +public class DynamoDBAuditEntryEntity implements Comparable { + + protected Boolean systemChange; + private String partitionKey; + private String taskId; + private String stageId; + private String executionId; + private String author; + private LocalDateTime createdAt; + private AuditEntry.Status state; + private String className; + private String methodName; + private Object metadata; + private Long executionMillis; + private String executionHostname; + private Object errorTrace; + private AuditEntry.ExecutionType type; + private AuditTxType txStrategy; + private String targetSystemId; + private String order; + private String recoveryStrategy; + private Boolean transactionFlag; + + public static DynamoDBAuditEntryEntity fromAuditEntry(AuditEntry auditEntry) { + return new DynamoDBAuditEntryEntity(auditEntry); + } + + public DynamoDBAuditEntryEntity(AuditEntry auditEntry) { + this.partitionKey = partitionKey(auditEntry.getExecutionId(), auditEntry.getTaskId(), auditEntry.getState()); + this.taskId = auditEntry.getTaskId(); + this.stageId = auditEntry.getStageId(); + this.executionId = auditEntry.getExecutionId(); + this.author = auditEntry.getAuthor(); + this.createdAt = auditEntry.getCreatedAt(); + this.state = auditEntry.getState(); + this.className = auditEntry.getClassName(); + this.methodName = auditEntry.getMethodName(); + this.metadata = auditEntry.getMetadata(); + this.executionMillis = auditEntry.getExecutionMillis(); + this.executionHostname = auditEntry.getExecutionHostname(); + this.errorTrace = auditEntry.getErrorTrace(); + this.type = auditEntry.getType(); + this.txStrategy = auditEntry.getTxType(); + this.targetSystemId = auditEntry.getTargetSystemId(); + this.order = auditEntry.getOrder(); + this.systemChange = auditEntry.getSystemChange(); + this.recoveryStrategy = auditEntry.getRecoveryStrategy().name(); + this.transactionFlag = auditEntry.getTransactionFlag(); + } + + public DynamoDBAuditEntryEntity() {} + + public static String partitionKey(String executionId, String taskId, AuditEntry.Status state) { + return executionId + '#' + taskId + '#' + state.name(); + } + + @DynamoDbPartitionKey + @DynamoDbAttribute(DynamoDBConstants.AUDIT_LOG_PK) + public String getPartitionKey() { + return partitionKey; + } + + public void setPartitionKey(String partitionKey) { + this.partitionKey = partitionKey; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_CHANGE_ID) + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_STAGE_ID) + public String getStageId() { + return stageId; + } + + public void setStageId(String stageId) { + this.stageId = stageId; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_EXECUTION_ID) + public String getExecutionId() { + return executionId; + } + + public void setExecutionId(String executionId) { + this.executionId = executionId; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_AUTHOR) + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TIMESTAMP) + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_STATE) + public String getState() { + return state.name(); + } + + public void setState(String state) { + this.state = AuditEntry.Status.valueOf(state); + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_CHANGE_CLASS) + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_INVOKED_METHOD) + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_METADATA) + public String getMetadata() { + return metadata.toString(); + } + + public void setMetadata(Object metadata) { + this.metadata = metadata; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_EXECUTION_MILLIS) + public Long getExecutionMillis() { + return executionMillis; + } + + public void setExecutionMillis(Long executionMillis) { + this.executionMillis = executionMillis; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_EXECUTION_HOSTNAME) + public String getExecutionHostname() { + return executionHostname; + } + + public void setExecutionHostname(String executionHostname) { + this.executionHostname = executionHostname; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_ERROR_TRACE) + public String getErrorTrace() { + return errorTrace.toString(); + } + + public void setErrorTrace(Object errorTrace) { + this.errorTrace = errorTrace; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TYPE) + public String getType() { + return type.name(); + } + + public void setType(String type) { + this.type = AuditEntry.ExecutionType.valueOf(type); + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_SYSTEM_CHANGE) + public Boolean getSystemChange() { + return systemChange; + } + + public void setSystemChange(Boolean systemChange) { + this.systemChange = systemChange; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TX_STRATEGY) + public String getTxType() { + return AuditTxType.safeString(txStrategy); + } + + public void setTxType(String txStrategy) { + this.txStrategy = AuditTxType.fromString(txStrategy); + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TARGET_SYSTEM_ID) + public String getTargetSystemId() { + return targetSystemId; + } + + public void setTargetSystemId(String targetSystemId) { + this.targetSystemId = targetSystemId; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_ORDER) + public String getOrder() { + return order; + } + + public void setOrder(String order) { + this.order = order; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_RECOVERY_STRATEGY) + public String getRecoveryStrategy() { + return recoveryStrategy; + } + + public void setRecoveryStrategy(String recoveryStrategy) { + this.recoveryStrategy = recoveryStrategy; + } + + @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TRANSACTION_FLAG) + public Boolean getTransactionFlag() { + return transactionFlag; + } + + public void setTransactionFlag(Boolean transactionFlag) { + this.transactionFlag = transactionFlag; + } + + @Override + public int compareTo(DynamoDBAuditEntryEntity other) { + if (other == null) { + return 1; + } + int timeComparison = this.createdAt.compareTo(other.createdAt); + if (timeComparison != 0) { + return timeComparison; + } + if (this.order != null && other.order != null) { + int orderComparison = this.order.compareTo(other.order); + if (orderComparison != 0) { + return orderComparison; + } + } + return Integer.compare(this.state.getPriority(), other.state.getPriority()); + } + + public AuditEntry toAuditEntry() { + return new AuditEntry( + executionId, + stageId, + taskId, + author, + createdAt, + state, + type, + className, + methodName, + executionMillis, + executionHostname, + metadata, + systemChange, + Objects.toString(errorTrace, ""), + txStrategy, + targetSystemId, + order, + recoveryStrategy != null ? RecoveryStrategy.valueOf(recoveryStrategy) : RecoveryStrategy.MANUAL_INTERVENTION, + transactionFlag + ); + } +} \ No newline at end of file diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBConstants.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBConstants.java new file mode 100644 index 000000000..997b78d06 --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBConstants.java @@ -0,0 +1,27 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.dynamodb.changes; + +public final class DynamoDBConstants { + + public static final String AUDIT_LOG_PK = "partitionKey"; + + public static final String LOCK_PK = "partitionKey"; + public static final String LOCK_OWNER = "lockOwner"; + + private DynamoDBConstants() { + } +} diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange1.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange1.java new file mode 100644 index 000000000..a4653fde0 --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange1.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.dynamodb.changes; + +import io.mongock.api.annotations.ChangeUnit; +import io.mongock.api.annotations.Execution; + +@ChangeUnit(id = "client-initializer", order = "1", author = "flamingock-team") +public class MongockChange1 { + + @Execution + public void apply() { + System.out.println("Client Initializer"); + } +} diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange2.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange2.java new file mode 100644 index 000000000..3f95234bc --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange2.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.dynamodb.changes; + +import io.mongock.api.annotations.ChangeUnit; +import io.mongock.api.annotations.Execution; + +@ChangeUnit(id = "client-updater", order = "2", author = "flamingock-team") +public class MongockChange2 { + + @Execution + public void apply() { + System.out.println("Client Initializer"); + } +} diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java new file mode 100644 index 000000000..c65271c54 --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java @@ -0,0 +1,52 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.dynamodb.changes; + +import io.flamingock.api.annotations.Apply; +import io.flamingock.api.annotations.Change; +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; +import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition; +import software.amazon.awssdk.services.dynamodb.model.BillingMode; +import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest; +import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement; +import software.amazon.awssdk.services.dynamodb.model.KeyType; +import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException; +import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; + +@Change(id = "create-users-table", author = "importer") +public class _0001__CreateUsersTableChange { + + @Apply + public void apply(DynamoDbClient dynamoDBClient) { + String tableName = "users"; + try { + dynamoDBClient.createTable(CreateTableRequest.builder() + .tableName(tableName) + .keySchema(KeySchemaElement.builder() + .attributeName("email") + .keyType(KeyType.HASH) + .build()) + .attributeDefinitions(AttributeDefinition.builder() + .attributeName("email") + .attributeType(ScalarAttributeType.S) + .build()) + .billingMode(BillingMode.PAY_PER_REQUEST) + .build()); + } catch (ResourceInUseException ignored) { + // Table already exists, ignore + } + } +} 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 6d223fb1f..84e0228e1 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 @@ -123,6 +123,10 @@ void testImportMongockChangeLogs() { ); + + + + // Validate actual change List users = database.getCollection("users") .find() diff --git a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange1.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange1.java similarity index 90% rename from legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange1.java rename to legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange1.java index 74408630f..3f23e4384 100644 --- a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange1.java +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange1.java @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongock.mongodb.legacy; +package io.flamingock.importer.mongock.mongodb.changes; -import io.flamingock.api.annotations.Apply; import io.mongock.api.annotations.ChangeUnit; import io.mongock.api.annotations.Execution; diff --git a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange2.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange2.java similarity index 86% rename from legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange2.java rename to legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange2.java index 1912a5f0a..7fb32f3a7 100644 --- a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/legacy/MongockChange2.java +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange2.java @@ -13,10 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongock.mongodb.legacy; +package io.flamingock.importer.mongock.mongodb.changes; -import io.flamingock.api.annotations.Apply; -import io.flamingock.api.annotations.Change; import io.mongock.api.annotations.ChangeUnit; import io.mongock.api.annotations.Execution; From 0a795d6194cda86d16a9fe053f2b44b44b3082e6 Mon Sep 17 00:00:00 2001 From: Antonio Perez Dieppa Date: Sat, 22 Nov 2025 15:23:02 +0000 Subject: [PATCH 03/10] feat: Mongock import to FlamingockCommunity(WIP: dynamodb test passing) --- .../mongock/dynamodb/MongockAuditEntry.java | 4 +- .../dynamodb/DynamoDBImporterTest.java | 253 +++++++++++------- .../dynamodb/DynamoDBMongockTestHelper.java | 67 +++++ .../mongock/dynamodb/DynamoDBTestHelper.java | 163 ----------- .../_0001__CreateUsersTableChange.java | 2 + 5 files changed, 221 insertions(+), 268 deletions(-) create mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBMongockTestHelper.java delete mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBTestHelper.java diff --git a/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java index 9b373a4d9..129aa7127 100644 --- a/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java +++ b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java @@ -193,6 +193,8 @@ public AuditEntry toAuditEntry() { LocalDateTime ts = LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()); MongockChangeState stateEnum = MongockChangeState.valueOf(state); + // Note: Mongock has BEFORE_EXECUTION and EXECUTION types, but Flamingock only has EXECUTION + // Both Mongock types are mapped to Flamingock EXECUTION type return new AuditEntry( executionId, null, @@ -200,7 +202,7 @@ public AuditEntry toAuditEntry() { author, ts, stateEnum.toAuditStatus(), - AuditEntry.ExecutionType.valueOf(type), + AuditEntry.ExecutionType.EXECUTION, changeLogClass, changeSetMethod, executionMillis, 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 9690a175b..091623679 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 @@ -1,5 +1,5 @@ /* - * Copyright 2023 Flamingock (https://www.flamingock.io) + * Copyright 2025 Flamingock (https://www.flamingock.io) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,15 @@ import io.flamingock.api.annotations.EnableFlamingock; import io.flamingock.api.annotations.Stage; import io.flamingock.community.dynamodb.driver.DynamoDBAuditStore; -import io.flamingock.importer.dynamodb.MongockDynamoDBAuditEntry; -import io.flamingock.internal.common.core.audit.AuditEntry; +import io.flamingock.core.kit.TestKit; +import io.flamingock.core.kit.audit.AuditTestHelper; +import io.flamingock.dynamodb.kit.DynamoDBTestKit; import io.flamingock.internal.common.core.error.FlamingockException; -import io.flamingock.internal.core.builder.FlamingockFactory; import io.flamingock.internal.core.runner.Runner; 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.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -36,16 +37,23 @@ import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; -import software.amazon.awssdk.services.dynamodb.model.ScanRequest; -import software.amazon.awssdk.services.dynamodb.model.ScanResponse; +import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition; +import software.amazon.awssdk.services.dynamodb.model.BillingMode; +import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest; +import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest; +import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse; +import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement; +import software.amazon.awssdk.services.dynamodb.model.KeyType; +import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException; +import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; import java.net.URI; -import java.time.Instant; -import java.util.Arrays; -import java.util.HashMap; -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.util.constants.CommunityPersistenceConstants.DEFAULT_AUDIT_STORE_NAME; +import static io.flamingock.internal.util.constants.CommunityPersistenceConstants.DEFAULT_LOCK_STORE_NAME; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -58,16 +66,13 @@ public class DynamoDBImporterTest { public static final GenericContainer dynamoDBContainer = new GenericContainer<>("amazon/dynamodb-local:latest") .withExposedPorts(8000); - public static final String MONGOCK_CHANGE_LOGS = "mongockChangeLogs"; - - private static DynamoDbClient client; - private DynamoDBTestHelper mongockChangeLogsHelper; - - @BeforeAll - static void beforeAll() { - dynamoDBContainer.start(); + private DynamoDBMongockTestHelper mongockTestHelper; + private TestKit testKit; + private AuditTestHelper auditHelper; + @BeforeEach + void setUp() { String endpoint = String.format("http://%s:%d", dynamoDBContainer.getHost(), dynamoDBContainer.getMappedPort(8000)); @@ -80,112 +85,152 @@ static void beforeAll() { ) ) .build(); + + // Create Mongock origin table for migration + createMongockTable(DEFAULT_MONGOCK_ORIGIN); + + // Create Flamingock audit and lock tables + createAuditTable(DEFAULT_AUDIT_STORE_NAME); + createLockTable(DEFAULT_LOCK_STORE_NAME); + + mongockTestHelper = new DynamoDBMongockTestHelper(client, DEFAULT_MONGOCK_ORIGIN); + + // Initialize TestKit for unified testing + testKit = DynamoDBTestKit.create(client, new DynamoDBAuditStore(client)); + auditHelper = testKit.getAuditHelper(); } - @BeforeEach - void setUp() { - mongockChangeLogsHelper = new DynamoDBTestHelper(client, MONGOCK_CHANGE_LOGS); - mongockChangeLogsHelper.ensureTableExists(); - mongockChangeLogsHelper.resetTable(); + private void createMongockTable(String tableName) { + try { + client.createTable(CreateTableRequest.builder() + .tableName(tableName) + .keySchema( + KeySchemaElement.builder() + .attributeName("executionId") + .keyType(KeyType.HASH) + .build(), + KeySchemaElement.builder() + .attributeName("changeId") + .keyType(KeyType.RANGE) + .build() + ) + .attributeDefinitions( + AttributeDefinition.builder() + .attributeName("executionId") + .attributeType(ScalarAttributeType.S) + .build(), + AttributeDefinition.builder() + .attributeName("changeId") + .attributeType(ScalarAttributeType.S) + .build() + ) + .billingMode(BillingMode.PAY_PER_REQUEST) + .build()); + } catch (ResourceInUseException ignored) { + // Table already exists, ignore + } + } - new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).ensureTableExists(); - new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).resetTable(); + private void createAuditTable(String tableName) { + try { + client.createTable(CreateTableRequest.builder() + .tableName(tableName) + .keySchema( + KeySchemaElement.builder() + .attributeName("partitionKey") + .keyType(KeyType.HASH) + .build() + ) + .attributeDefinitions( + AttributeDefinition.builder() + .attributeName("partitionKey") + .attributeType(ScalarAttributeType.S) + .build() + ) + .billingMode(BillingMode.PAY_PER_REQUEST) + .build()); + } catch (ResourceInUseException ignored) { + // Table already exists, ignore + } + } + + private void createLockTable(String tableName) { + try { + client.createTable(CreateTableRequest.builder() + .tableName(tableName) + .keySchema( + KeySchemaElement.builder() + .attributeName("partitionKey") + .keyType(KeyType.HASH) + .build() + ) + .attributeDefinitions( + AttributeDefinition.builder() + .attributeName("partitionKey") + .attributeType(ScalarAttributeType.S) + .build() + ) + .billingMode(BillingMode.PAY_PER_REQUEST) + .build()); + } catch (ResourceInUseException ignored) { + // Table already exists, ignore + } + } + + @AfterEach + void tearDown() { + // DynamoDB local doesn't need explicit cleanup between tests + // Tables are automatically cleaned by Testcontainers on restart + client.close(); } @Test - @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") void testImportDynamoDBChangeLogs() { - List entries = Arrays.asList( - new MongockDynamoDBAuditEntry( - "exec-1", - "client-initializer", - "author1", - String.valueOf(Instant.now().toEpochMilli()), - "EXECUTED", - "EXECUTION", - "io.flamingock.changelog.Class1", - "method1", - new HashMap() {{ - put("meta1", "value1"); - }}.toString(), - 123L, - "host1", - null, - true - ), - new MongockDynamoDBAuditEntry( - "exec-1", - "client-updater", - "author1", - String.valueOf(Instant.now().toEpochMilli()), - "EXECUTED", - "EXECUTION", - "io.flamingock.changelog.Class2", - "method1", - new HashMap() {{ - put("meta1", "value1"); - }}.toString(), - 123L, - "host1", - null, - true - ) - ); + // Setup Mongock entries + mongockTestHelper.setupBasicScenario(); - mongockChangeLogsHelper.insertChangeEntries(entries); + DynamoDBTargetSystem dynamodbTargetSystem = new DynamoDBTargetSystem("dynamodb-target-system", client); - Runner flamingock = FlamingockFactory.getCommunityBuilder() - .setAuditStore(new DynamoDBAuditStore(client)) + Runner flamingock = testKit.createBuilder() + .addTargetSystem(dynamodbTargetSystem) .build(); flamingock.run(); - List auditLog = new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).getAuditEntriesSorted(); - assertEquals(6, auditLog.size()); - - for (AuditEntry entry : auditLog) { - System.out.println("executionId: " + entry.getExecutionId()); - System.out.println("stageId: " + entry.getStageId()); - System.out.println("taskId: " + entry.getTaskId()); - System.out.println("author: " + entry.getAuthor()); - System.out.println("createdAt: " + entry.getCreatedAt()); - System.out.println("state: " + entry.getState()); - System.out.println("type: " + entry.getType()); - System.out.println("className: " + entry.getClassName()); - System.out.println("methodName: " + entry.getMethodName()); - System.out.println("executionMillis: " + entry.getExecutionMillis()); - System.out.println("executionHostname: " + entry.getExecutionHostname()); - System.out.println("metadata: " + entry.getMetadata()); - System.out.println("systemChange: " + entry.getSystemChange()); - System.out.println("errorTrace: " + entry.getErrorTrace()); - System.out.println("txStrategy: " + entry.getTxType()); - System.out.println("targetSystemId: " + entry.getTargetSystemId()); - System.out.println("order: " + entry.getOrder()); - System.out.println("-----"); - } - - AuditEntry entry1 = auditLog.stream() - .filter(e -> "client-updater".equals(e.getTaskId())) - .findFirst() - .orElseThrow(() -> new AssertionError("Entry with changeId 'client-updater' not found")); - + // Verify audit sequence: 9 total entries + // 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("client-initializer_before"), + APPLIED("client-initializer"), + APPLIED("client-updater"), + + // System stage - actual system importer change + STARTED("migration-mongock-to-flamingock-community"), + APPLIED("migration-mongock-to-flamingock-community"), + + // Application stage - new change created by code + STARTED("create-users-table"), + APPLIED("create-users-table") + ); - assertEquals("client-updater", entry1.getTaskId()); - assertEquals("author1", entry1.getAuthor()); - assertEquals("exec-1", entry1.getExecutionId()); - assertTrue(entry1.getSystemChange()); + // Validate actual table creation + assertTrue(client.listTables().tableNames().contains("users"), "Users table should exist"); - ScanResponse scanResponse = client.scan( - ScanRequest.builder().tableName(DEFAULT_AUDIT_STORE_NAME).build() + // Verify table structure + DescribeTableResponse tableDescription = client.describeTable( + DescribeTableRequest.builder().tableName("users").build() ); - assertTrue(scanResponse.count() > 0, "Audit table should not be empty"); + assertEquals("email", tableDescription.table().keySchema().get(0).attributeName()); + assertEquals(KeyType.HASH, tableDescription.table().keySchema().get(0).keyType()); } @Test @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") void failIfEmptyOrigin() { - Runner flamingock = FlamingockFactory.getCommunityBuilder() - .setAuditStore(new DynamoDBAuditStore(client)) + Runner flamingock = testKit.createBuilder() .build(); Assertions.assertThrows(FlamingockException.class, flamingock::run); diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBMongockTestHelper.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBMongockTestHelper.java new file mode 100644 index 000000000..b2c16780a --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBMongockTestHelper.java @@ -0,0 +1,67 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.dynamodb; + +import io.flamingock.common.test.mongock.MongockTestHelper; +import io.flamingock.importer.dynamodb.MongockDynamoDBAuditEntry; +import io.flamingock.importer.mongodb.MongockChangeEntry; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; +import software.amazon.awssdk.enhanced.dynamodb.TableSchema; +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; + +import java.util.List; + +public class DynamoDBMongockTestHelper implements MongockTestHelper { + + private final DynamoDbTable table; + + public DynamoDBMongockTestHelper(DynamoDbClient client, String tableName) { + DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() + .dynamoDbClient(client) + .build(); + this.table = enhancedClient.table(tableName, TableSchema.fromBean(MongockDynamoDBAuditEntry.class)); + } + + public void write(MongockChangeEntry entry) { + table.putItem(convertToMongockDynamoDBAuditEntry(entry)); + } + + public int writeAll(List entries) { + for (MongockChangeEntry entry : entries) { + table.putItem(convertToMongockDynamoDBAuditEntry(entry)); + } + return entries.size(); + } + + private MongockDynamoDBAuditEntry convertToMongockDynamoDBAuditEntry(MongockChangeEntry entry) { + return new MongockDynamoDBAuditEntry( + entry.getExecutionId(), + entry.getChangeId(), + entry.getAuthor(), + entry.getTimestamp() != null ? String.valueOf(entry.getTimestamp().getTime()) : null, + entry.getState() != null ? entry.getState().toString() : null, + entry.getType() != null ? entry.getType().toString() : null, + entry.getChangeLogClass(), + entry.getChangeSetMethod(), + entry.getMetadata() != null ? entry.getMetadata().toString() : null, + entry.getExecutionMillis(), + entry.getExecutionHostname(), + entry.getErrorTrace(), + entry.getSystemChange() + ); + } +} diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBTestHelper.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBTestHelper.java deleted file mode 100644 index 2d3d88f2f..000000000 --- a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBTestHelper.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.mongock.dynamodb; - -import io.flamingock.importer.dynamodb.MongockDynamoDBAuditEntry; -import io.flamingock.importer.dynamodb.dynamodb.DynamoDBAuditEntryEntity; -import io.flamingock.internal.common.core.audit.AuditEntry; -import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; -import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; -import software.amazon.awssdk.enhanced.dynamodb.TableSchema; -import software.amazon.awssdk.services.dynamodb.DynamoDbClient; -import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition; -import software.amazon.awssdk.services.dynamodb.model.AttributeValue; -import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest; -import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest; -import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest; -import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse; -import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement; -import software.amazon.awssdk.services.dynamodb.model.KeyType; -import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse; -import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput; -import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; -import software.amazon.awssdk.services.dynamodb.model.ScanRequest; -import software.amazon.awssdk.services.dynamodb.model.ScanResponse; -import software.amazon.awssdk.services.dynamodb.model.TableStatus; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static io.flamingock.internal.util.constants.CommunityPersistenceConstants.DEFAULT_AUDIT_STORE_NAME; - -public class DynamoDBTestHelper { - - private final DynamoDbClient client; - private final String tableName; - private final DynamoDbTable table; - - public DynamoDBTestHelper(DynamoDbClient client, String tableName) { - this.client = client; - this.tableName = tableName; - DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() - .dynamoDbClient(client) - .build(); - - if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { - this.table = enhancedClient.table(tableName, TableSchema.fromBean(DynamoDBAuditEntryEntity.class)); - } else { - this.table = enhancedClient.table(tableName, TableSchema.fromBean(MongockDynamoDBAuditEntry.class)); - } - } - - public void ensureTableExists() { - ListTablesResponse tables = client.listTables(); - if (!tables.tableNames().contains(tableName)) { - if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { - client.createTable(CreateTableRequest.builder() - .tableName(tableName) - .keySchema( - KeySchemaElement.builder().attributeName("partitionKey").keyType(KeyType.HASH).build() - ) - .attributeDefinitions( - AttributeDefinition.builder().attributeName("partitionKey").attributeType(ScalarAttributeType.S).build() - ) - .provisionedThroughput( - ProvisionedThroughput.builder().readCapacityUnits(5L).writeCapacityUnits(5L).build() - ) - .build()); - } else { - client.createTable(CreateTableRequest.builder() - .tableName(tableName) - .keySchema( - KeySchemaElement.builder().attributeName("executionId").keyType(KeyType.HASH).build(), - KeySchemaElement.builder().attributeName("changeId").keyType(KeyType.RANGE).build() - ) - .attributeDefinitions( - AttributeDefinition.builder().attributeName("executionId").attributeType(ScalarAttributeType.S).build(), - AttributeDefinition.builder().attributeName("changeId").attributeType(ScalarAttributeType.S).build() - ) - .provisionedThroughput( - ProvisionedThroughput.builder().readCapacityUnits(5L).writeCapacityUnits(5L).build() - ) - .build()); - } - waitForTableActive(); - } - } - - private void waitForTableActive() { - while (true) { - DescribeTableResponse resp = client.describeTable(DescribeTableRequest.builder().tableName(tableName).build()); - if (resp.table().tableStatus() == TableStatus.ACTIVE) { - break; - } - try { - Thread.sleep(200); - } catch (InterruptedException ignored) {} - } - } - - public void resetTable() { - ScanRequest scanRequest = ScanRequest.builder().tableName(tableName).build(); - ScanResponse scanResponse = client.scan(scanRequest); - for (Map item : scanResponse.items()) { - Map key = new HashMap<>(); - if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { - key.put("partitionKey", item.get("partitionKey")); - } else { - key.put("executionId", item.get("executionId")); - key.put("changeId", item.get("changeId")); - } - client.deleteItem(DeleteItemRequest.builder() - .tableName(tableName) - .key(key) - .build()); - } - } - - public void insertChangeEntries(List entries) { - if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { - throw new UnsupportedOperationException("insertChangeEntries is only for change log tables"); - } - DynamoDbTable changeTable = (DynamoDbTable) table; - for (MongockDynamoDBAuditEntry entry : entries) { - changeTable.putItem(entry); - } - } - - public List getAuditEntriesSorted() { - if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { - DynamoDbTable auditTable = (DynamoDbTable) table; - List entities = new ArrayList<>(); - auditTable.scan().items().forEach(entities::add); - return entities.stream() - .map(DynamoDBAuditEntryEntity::toAuditEntry) - .sorted() - .collect(Collectors.toList()); - } else { - DynamoDbTable changeTable = (DynamoDbTable) table; - List entries = new ArrayList<>(); - changeTable.scan().items().forEach(entries::add); - return entries.stream() - .map(MongockDynamoDBAuditEntry::toAuditEntry) - .sorted() - .collect(Collectors.toList()); - } - } -} diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java index c65271c54..82acb60fd 100644 --- a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java @@ -17,6 +17,7 @@ import io.flamingock.api.annotations.Apply; import io.flamingock.api.annotations.Change; +import io.flamingock.api.annotations.TargetSystem; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition; import software.amazon.awssdk.services.dynamodb.model.BillingMode; @@ -27,6 +28,7 @@ import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; @Change(id = "create-users-table", author = "importer") +@TargetSystem(id = "dynamodb-target-system") public class _0001__CreateUsersTableChange { @Apply From 51cc1870f4f0d6bcd0d001b3ff4c70bd75e4200f Mon Sep 17 00:00:00 2001 From: Antonio Perez Dieppa Date: Sat, 22 Nov 2025 16:16:05 +0000 Subject: [PATCH 04/10] feat: Mongock import to FlamingockCommunity(WIP: dynamodb test passing and refactored) --- .../dynamodb/DynamoDBImporterTest.java | 94 +---------- .../dynamodb/kit/DynamoDBTableFactory.java | 150 ++++++++++++++++++ 2 files changed, 155 insertions(+), 89 deletions(-) create mode 100644 utils/dynamodb-util/src/main/java/io/flamingock/dynamodb/kit/DynamoDBTableFactory.java 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 091623679..d4e8c59b6 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 @@ -20,6 +20,7 @@ import io.flamingock.community.dynamodb.driver.DynamoDBAuditStore; import io.flamingock.core.kit.TestKit; import io.flamingock.core.kit.audit.AuditTestHelper; +import io.flamingock.dynamodb.kit.DynamoDBTableFactory; import io.flamingock.dynamodb.kit.DynamoDBTestKit; import io.flamingock.internal.common.core.error.FlamingockException; import io.flamingock.internal.core.runner.Runner; @@ -37,15 +38,9 @@ import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; -import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition; -import software.amazon.awssdk.services.dynamodb.model.BillingMode; -import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest; import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest; import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse; -import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement; import software.amazon.awssdk.services.dynamodb.model.KeyType; -import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException; -import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; import java.net.URI; @@ -86,12 +81,10 @@ void setUp() { ) .build(); - // Create Mongock origin table for migration - createMongockTable(DEFAULT_MONGOCK_ORIGIN); - - // Create Flamingock audit and lock tables - createAuditTable(DEFAULT_AUDIT_STORE_NAME); - createLockTable(DEFAULT_LOCK_STORE_NAME); + // Create required tables using DynamoDBTableFactory + DynamoDBTableFactory.createMongockTable(client, DEFAULT_MONGOCK_ORIGIN); +// DynamoDBTableFactory.createAuditTable(client, DEFAULT_AUDIT_STORE_NAME); +// DynamoDBTableFactory.createLockTable(client, DEFAULT_LOCK_STORE_NAME); mongockTestHelper = new DynamoDBMongockTestHelper(client, DEFAULT_MONGOCK_ORIGIN); @@ -100,83 +93,6 @@ void setUp() { auditHelper = testKit.getAuditHelper(); } - private void createMongockTable(String tableName) { - try { - client.createTable(CreateTableRequest.builder() - .tableName(tableName) - .keySchema( - KeySchemaElement.builder() - .attributeName("executionId") - .keyType(KeyType.HASH) - .build(), - KeySchemaElement.builder() - .attributeName("changeId") - .keyType(KeyType.RANGE) - .build() - ) - .attributeDefinitions( - AttributeDefinition.builder() - .attributeName("executionId") - .attributeType(ScalarAttributeType.S) - .build(), - AttributeDefinition.builder() - .attributeName("changeId") - .attributeType(ScalarAttributeType.S) - .build() - ) - .billingMode(BillingMode.PAY_PER_REQUEST) - .build()); - } catch (ResourceInUseException ignored) { - // Table already exists, ignore - } - } - - private void createAuditTable(String tableName) { - try { - client.createTable(CreateTableRequest.builder() - .tableName(tableName) - .keySchema( - KeySchemaElement.builder() - .attributeName("partitionKey") - .keyType(KeyType.HASH) - .build() - ) - .attributeDefinitions( - AttributeDefinition.builder() - .attributeName("partitionKey") - .attributeType(ScalarAttributeType.S) - .build() - ) - .billingMode(BillingMode.PAY_PER_REQUEST) - .build()); - } catch (ResourceInUseException ignored) { - // Table already exists, ignore - } - } - - private void createLockTable(String tableName) { - try { - client.createTable(CreateTableRequest.builder() - .tableName(tableName) - .keySchema( - KeySchemaElement.builder() - .attributeName("partitionKey") - .keyType(KeyType.HASH) - .build() - ) - .attributeDefinitions( - AttributeDefinition.builder() - .attributeName("partitionKey") - .attributeType(ScalarAttributeType.S) - .build() - ) - .billingMode(BillingMode.PAY_PER_REQUEST) - .build()); - } catch (ResourceInUseException ignored) { - // Table already exists, ignore - } - } - @AfterEach void tearDown() { // DynamoDB local doesn't need explicit cleanup between tests diff --git a/utils/dynamodb-util/src/main/java/io/flamingock/dynamodb/kit/DynamoDBTableFactory.java b/utils/dynamodb-util/src/main/java/io/flamingock/dynamodb/kit/DynamoDBTableFactory.java new file mode 100644 index 000000000..639e87afc --- /dev/null +++ b/utils/dynamodb-util/src/main/java/io/flamingock/dynamodb/kit/DynamoDBTableFactory.java @@ -0,0 +1,150 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.dynamodb.kit; + +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; +import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition; +import software.amazon.awssdk.services.dynamodb.model.BillingMode; +import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest; +import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement; +import software.amazon.awssdk.services.dynamodb.model.KeyType; +import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException; +import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; + +/** + * Factory class for creating DynamoDB tables in test environments. + *

+ * This utility provides methods to create common Flamingock-related tables + * with appropriate schemas for testing purposes. All tables are created with + * PAY_PER_REQUEST billing mode to simplify test setup. + *

+ * All methods are idempotent - they safely handle cases where tables already exist. + */ +public class DynamoDBTableFactory { + + /** + * Creates a Mongock origin table for migration testing. + *

+ * This table uses a composite key structure matching Mongock's audit format: + *

    + *
  • Partition key: executionId (String)
  • + *
  • Sort key: changeId (String)
  • + *
+ * + * @param client the DynamoDB client + * @param tableName the name of the Mongock table to create + */ + public static void createMongockTable(DynamoDbClient client, String tableName) { + createTableSafe(client, CreateTableRequest.builder() + .tableName(tableName) + .keySchema( + KeySchemaElement.builder() + .attributeName("executionId") + .keyType(KeyType.HASH) + .build(), + KeySchemaElement.builder() + .attributeName("changeId") + .keyType(KeyType.RANGE) + .build() + ) + .attributeDefinitions( + AttributeDefinition.builder() + .attributeName("executionId") + .attributeType(ScalarAttributeType.S) + .build(), + AttributeDefinition.builder() + .attributeName("changeId") + .attributeType(ScalarAttributeType.S) + .build() + ) + .billingMode(BillingMode.PAY_PER_REQUEST) + .build()); + } + + /** + * Creates a Flamingock audit table for storing change execution history. + *

+ * This table uses a simple key structure: + *

    + *
  • Partition key: partitionKey (String)
  • + *
+ * + * @param client the DynamoDB client + * @param tableName the name of the audit table to create + */ + public static void createAuditTable(DynamoDbClient client, String tableName) { + createTableSafe(client, CreateTableRequest.builder() + .tableName(tableName) + .keySchema( + KeySchemaElement.builder() + .attributeName("partitionKey") + .keyType(KeyType.HASH) + .build() + ) + .attributeDefinitions( + AttributeDefinition.builder() + .attributeName("partitionKey") + .attributeType(ScalarAttributeType.S) + .build() + ) + .billingMode(BillingMode.PAY_PER_REQUEST) + .build()); + } + + /** + * Creates a Flamingock lock table for distributed locking. + *

+ * This table uses a simple key structure: + *

    + *
  • Partition key: partitionKey (String)
  • + *
+ * + * @param client the DynamoDB client + * @param tableName the name of the lock table to create + */ + public static void createLockTable(DynamoDbClient client, String tableName) { + createTableSafe(client, CreateTableRequest.builder() + .tableName(tableName) + .keySchema( + KeySchemaElement.builder() + .attributeName("partitionKey") + .keyType(KeyType.HASH) + .build() + ) + .attributeDefinitions( + AttributeDefinition.builder() + .attributeName("partitionKey") + .attributeType(ScalarAttributeType.S) + .build() + ) + .billingMode(BillingMode.PAY_PER_REQUEST) + .build()); + } + + /** + * Creates a table safely, ignoring ResourceInUseException if the table already exists. + * + * @param client the DynamoDB client + * @param request the table creation request + */ + private static void createTableSafe(DynamoDbClient client, CreateTableRequest request) { + try { + client.createTable(request); + } catch (ResourceInUseException ignored) { + // Table already exists, which is fine for idempotent test setup + } + } +} From 301af7ec7390a49f0763928b69699f9038a8d7f8 Mon Sep 17 00:00:00 2001 From: Antonio Perez Dieppa Date: Mon, 24 Nov 2025 18:18:24 +0000 Subject: [PATCH 05/10] test: mongock couchbase importer test --- .../build.gradle.kts | 2 + .../build.gradle.kts | 29 +++- .../couchbase/CouchbaseImporterTest.java | 164 ++++++++++++++++++ .../couchbase/changes/MongockChange1.java | 12 +- .../couchbase/changes/MongockChange2.java | 7 +- .../_0001__CreateUsersCollectionChange.java | 40 +++++ .../build.gradle.kts | 13 +- 7 files changed, 256 insertions(+), 11 deletions(-) create mode 100644 legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/CouchbaseImporterTest.java rename core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0002__ClientUpdater.java => legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange1.java (70%) rename core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0001__ClientInitializer.java => legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange2.java (77%) create mode 100644 legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java diff --git a/core/importer/flamingock-importer-couchbase-tests/build.gradle.kts b/core/importer/flamingock-importer-couchbase-tests/build.gradle.kts index 48eece1b2..565c1130e 100644 --- a/core/importer/flamingock-importer-couchbase-tests/build.gradle.kts +++ b/core/importer/flamingock-importer-couchbase-tests/build.gradle.kts @@ -11,6 +11,8 @@ repositories { dependencies { compileOnly("com.couchbase.client:java-client:3.6.0") + + testImplementation(project(":core:importer:flamingock-importer")) testAnnotationProcessor(project(":core:flamingock-processor")) testImplementation(project(":community:flamingock-auditstore-couchbase")) diff --git a/legacy/mongock-importer-couchbase/build.gradle.kts b/legacy/mongock-importer-couchbase/build.gradle.kts index 3528e32fd..cb48a3c5b 100644 --- a/legacy/mongock-importer-couchbase/build.gradle.kts +++ b/legacy/mongock-importer-couchbase/build.gradle.kts @@ -4,10 +4,24 @@ dependencies { //General compileOnly("com.couchbase.client:java-client:3.6.0") + + + testAnnotationProcessor(project(":core:flamingock-processor")) + testAnnotationProcessor(project(":legacy:mongock-support")) + testImplementation(project(":legacy:mongock-support")) + testImplementation(project(":core:target-systems:couchbase-target-system")) + + testImplementation(project(":community:flamingock-auditstore-couchbase")) + testImplementation(project(":utils:couchbase-util")) + testImplementation(project(":utils:test-util")) + + testImplementation("org.testcontainers:couchbase:1.21.3") + testImplementation("org.testcontainers:junit-jupiter:1.21.3") + testImplementation("org.mockito:mockito-inline:4.11.0") } -description = "A MongoDB migration utility that imports Mongock’s execution history into Flamingock-Community’s audit store for smooth project upgrades." +description = "A Couchbase migration utility that imports Mongock’s execution history into Flamingock-Community’s audit store for smooth project upgrades." java { @@ -15,3 +29,16 @@ java { languageVersion.set(JavaLanguageVersion.of(8)) } } + + +tasks.withType().configureEach { + if (name.contains("Test", ignoreCase = true)) { + options.compilerArgs.addAll(listOf( + "-Asources=${projectDir}/src/test/java", + "-Aresources=${projectDir}/src/test/resources" + )) + } +} +configurations.testImplementation { + extendsFrom(configurations.compileOnly.get()) +} \ No newline at end of file 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 new file mode 100644 index 000000000..d7ac93c9b --- /dev/null +++ b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/CouchbaseImporterTest.java @@ -0,0 +1,164 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.couchbase; + +import com.couchbase.client.core.io.CollectionIdentifier; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.manager.bucket.BucketManager; +import com.couchbase.client.java.manager.bucket.BucketSettings; +import io.flamingock.api.annotations.EnableFlamingock; +import io.flamingock.api.annotations.Stage; +import io.flamingock.community.couchbase.driver.CouchbaseAuditStore; +import io.flamingock.internal.common.couchbase.CouchbaseCollectionHelper; +import io.flamingock.internal.core.builder.FlamingockFactory; +import io.flamingock.internal.core.runner.Runner; +import io.flamingock.internal.util.constants.CommunityPersistenceConstants; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.testcontainers.couchbase.CouchbaseContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; + +import static io.flamingock.api.StageType.LEGACY; +import static io.flamingock.api.StageType.SYSTEM; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@EnableFlamingock( + stages = { + @Stage(location = "io.flamingock.importer.couchbase.system", type = SYSTEM), + @Stage(location = "io.flamingock.importer.couchbase.legacy", type = LEGACY), + @Stage(location = "io.flamingock.importer.couchbase.couchbase") + } +) +@Testcontainers +public class CouchbaseImporterTest { + + public static final String FLAMINGOCK_BUCKET_NAME = "test"; + public static final String FLAMINGOCK_SCOPE_NAME = "flamingock"; + public static final String FLAMINGOCK_COLLECTION_NAME = CommunityPersistenceConstants.DEFAULT_AUDIT_STORE_NAME; + + public static final String MONGOCK_BUCKET_NAME = "test"; + public static final String MONGOCK_SCOPE_NAME = CollectionIdentifier.DEFAULT_SCOPE; + public static final String MONGOCK_COLLECTION_NAME = CollectionIdentifier.DEFAULT_COLLECTION; + + + @Container + static final CouchbaseContainer couchbaseContainer = new CouchbaseContainer("couchbase/server:7.2.4") + .withBucket(new org.testcontainers.couchbase.BucketDefinition(FLAMINGOCK_BUCKET_NAME)); + + private static Cluster cluster; + + @BeforeAll + static void setupAll() { + couchbaseContainer.start(); + cluster = Cluster.connect( + couchbaseContainer.getConnectionString(), + couchbaseContainer.getUsername(), + couchbaseContainer.getPassword() + ); + cluster.bucket(FLAMINGOCK_BUCKET_NAME).waitUntilReady(Duration.ofSeconds(10)); + + // Setup Mongock Bucket, Scope and Collection + BucketManager bucketManager = cluster.buckets(); + + int ramQuotaMB = 100; + + if (!bucketManager.getAllBuckets().containsKey(MONGOCK_BUCKET_NAME)) { + bucketManager.createBucket(BucketSettings.create(MONGOCK_BUCKET_NAME).ramQuotaMB(ramQuotaMB)); + cluster.bucket(MONGOCK_BUCKET_NAME).waitUntilReady(Duration.ofSeconds(10)); + } + + CouchbaseCollectionHelper.createScopeIfNotExists(cluster, MONGOCK_BUCKET_NAME, MONGOCK_SCOPE_NAME); + CouchbaseCollectionHelper.createCollectionIfNotExists(cluster, MONGOCK_BUCKET_NAME, MONGOCK_SCOPE_NAME, MONGOCK_COLLECTION_NAME); + CouchbaseCollectionHelper.createPrimaryIndexIfNotExists(cluster, MONGOCK_BUCKET_NAME, MONGOCK_SCOPE_NAME, MONGOCK_COLLECTION_NAME); + } + + @AfterEach + void cleanUp() { + CouchbaseCollectionHelper.deleteAllDocuments(cluster, FLAMINGOCK_BUCKET_NAME, FLAMINGOCK_SCOPE_NAME, FLAMINGOCK_COLLECTION_NAME); + CouchbaseCollectionHelper.deleteAllDocuments(cluster, MONGOCK_BUCKET_NAME, MONGOCK_SCOPE_NAME, MONGOCK_COLLECTION_NAME); + } + + @Test + @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") + void testImporterIntegration() { + Collection originCollection = cluster.bucket(MONGOCK_BUCKET_NAME).scope(MONGOCK_SCOPE_NAME).collection(MONGOCK_COLLECTION_NAME); + JsonObject doc = JsonObject.create() + .put("executionId", "exec-1") + .put("changeId", "change-1") + .put("author", "author1") + .put("timestamp", String.valueOf(Instant.now().toEpochMilli())) + .put("state", "EXECUTED") + .put("type", "EXECUTION") + .put("changeLogClass", "io.flamingock.changelog.Class1") + .put("changeSetMethod", "method1") + .putNull("metadata") + .put("executionMillis", 123L) + .put("executionHostName", "host1") + .putNull("errorTrace") + .put("systemChange", true) + .put("_doctype", "mongockChangeEntry"); + originCollection.upsert("change-1", doc); + + Runner flamingock = FlamingockFactory.getCommunityBuilder() + .setAuditStore(new CouchbaseAuditStore(cluster, FLAMINGOCK_BUCKET_NAME) + .withScopeName(FLAMINGOCK_SCOPE_NAME) + .withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME)) + .build(); + + flamingock.run(); + + List auditLog = CouchbaseCollectionHelper.selectAllDocuments(cluster, FLAMINGOCK_BUCKET_NAME, FLAMINGOCK_SCOPE_NAME, FLAMINGOCK_COLLECTION_NAME); + + assertFalse(auditLog.isEmpty(), "Audit log should not be empty"); + + JsonObject entry = auditLog.stream() + .filter(e -> "change-1".equals(e.getString("changeId"))) + .findFirst() + .orElseThrow(() -> new AssertionError("Entry with changeId 'change-1' not found")); + + assertEquals("change-1", entry.getString("changeId")); + assertEquals("author1", entry.getString("author")); + assertEquals("exec-1", entry.getString("executionId")); + assertEquals("APPLIED", entry.getString("state")); + assertTrue(entry.getBoolean("systemChange")); + } + + @Test + @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") + void failIfEmptyOrigin() { + Runner flamingock = FlamingockFactory.getCommunityBuilder() + .setAuditStore(new CouchbaseAuditStore(cluster, FLAMINGOCK_BUCKET_NAME) + .withScopeName(FLAMINGOCK_SCOPE_NAME) + .withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME)) + .build(); + + org.junit.jupiter.api.Assertions.assertThrows( + io.flamingock.internal.common.core.error.FlamingockException.class, + flamingock::run + ); + } +} \ No newline at end of file diff --git a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0002__ClientUpdater.java b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange1.java similarity index 70% rename from core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0002__ClientUpdater.java rename to legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange1.java index 61e8a66c6..fe5032279 100644 --- a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0002__ClientUpdater.java +++ b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange1.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.couchbase.legacy; +package io.flamingock.importer.mongock.couchbase.changes; -import io.flamingock.api.annotations.Change; -import io.flamingock.api.annotations.Apply; +import io.mongock.api.annotations.ChangeUnit; +import io.mongock.api.annotations.Execution; -@Change(id = "client-updater", author = "mongock", transactional = false) -public class _0002__ClientUpdater { +@ChangeUnit(id = "client-initializer", order = "1", author = "flamingock-team", transactional = false) +public class MongockChange1 { - @Apply + @Execution public void apply() { System.out.println("Client Initializer"); } diff --git a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0001__ClientInitializer.java b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange2.java similarity index 77% rename from core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0001__ClientInitializer.java rename to legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange2.java index 6d6937266..4ab1324c5 100644 --- a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0001__ClientInitializer.java +++ b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange2.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.couchbase.legacy; +package io.flamingock.importer.mongock.couchbase.changes; import io.flamingock.api.annotations.Change; import io.flamingock.api.annotations.Apply; +import io.mongock.api.annotations.ChangeUnit; -@Change(id = "client-initializer", author = "mongock", transactional = false) -public class _0001__ClientInitializer { +@ChangeUnit(id = "client-updater", order = "2", author = "flamingock-team", transactional = false) +public class MongockChange2 { @Apply public void apply() { diff --git a/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java new file mode 100644 index 000000000..5319f08c4 --- /dev/null +++ b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.importer.mongock.couchbase.changes; + +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.json.JsonObject; +import io.flamingock.api.annotations.Apply; +import io.flamingock.api.annotations.Change; + +import java.util.Collections; + +@Change(id = "create-users-collection", author = "importer", transactional = false) +public class _0001__CreateUsersCollectionChange { + + @Apply + public void apply(Bucket bucket) { + Collection collection = bucket.defaultCollection(); + + JsonObject user = JsonObject.create() + .put("email", "admin@company.com") + .put("name", "Admin") + .put("roles", Collections.singletonList("superuser")); + + collection.upsert("user::admin@company.com", user); + } +} diff --git a/legacy/mongock-importer-dynamodb/build.gradle.kts b/legacy/mongock-importer-dynamodb/build.gradle.kts index 5f3e889ec..cb65dc562 100644 --- a/legacy/mongock-importer-dynamodb/build.gradle.kts +++ b/legacy/mongock-importer-dynamodb/build.gradle.kts @@ -22,7 +22,7 @@ dependencies { } -description = "A MongoDB migration utility that imports Mongock’s execution history into Flamingock-Community’s audit store for smooth project upgrades." +description = "A DynamoDB migration utility that imports Mongock’s execution history into Flamingock-Community’s audit store for smooth project upgrades." java { @@ -30,3 +30,14 @@ java { languageVersion.set(JavaLanguageVersion.of(8)) } } +tasks.withType().configureEach { + if (name.contains("Test", ignoreCase = true)) { + options.compilerArgs.addAll(listOf( + "-Asources=${projectDir}/src/test/java", + "-Aresources=${projectDir}/src/test/resources" + )) + } +} +configurations.testImplementation { + extendsFrom(configurations.compileOnly.get()) +} \ No newline at end of file From 016cbc76d65bb4120b8f4dd6ec55fc9d5645bbcb Mon Sep 17 00:00:00 2001 From: Antonio Perez Dieppa Date: Mon, 24 Nov 2025 20:13:06 +0000 Subject: [PATCH 06/10] refactor: removed old importers --- .../io/flamingock/api/annotations/Stage.java | 2 - .../ChangeProcessStrategyFactory.java | 6 +- .../FlamingockAnnotationProcessor.java | 36 +- .../processor/PipelinePreProcessorTest.java | 114 +------ .../build.gradle.kts | 49 --- .../couchbase/CouchbaseImporterTest.java | 164 ---------- .../_0001__CreateUsersCollectionChange.java | 40 --- .../system/_0001__migration_from_mongock.yaml | 8 - .../build.gradle.kts | 42 --- .../dynamodb/DynamoDBImporterTest.java | 187 ----------- .../importer/dynamodb/DynamoDBTestHelper.java | 144 -------- .../dynamodb/DynamoDBAuditEntryEntity.java | 308 ------------------ .../dynamodb/dynamodb/DynamoDBConstants.java | 27 -- .../_0001__CreateUsersTableChange.java | 46 --- .../legacy/_0001__ClientInitializer.java | 28 -- .../dynamodb/legacy/_0002__ClientUpdater.java | 28 -- .../system/_0001__migration_from_mongock.yaml | 6 - .../build.gradle.kts | 40 --- .../importer/mongodb/MongoDBImporterTest.java | 159 --------- .../mongodb/MongoDBMongockTestHelper.java | 64 ---- .../legacy/_0001__ClientInitializer.java | 28 -- .../mongodb/legacy/_0002__ClientUpdater.java | 28 -- .../_0003__create_users_collections.yaml | 9 - .../mongodb/mongodb/_0004__seed_users.yaml | 16 - .../system/_0001__migration_from_mongock.yaml | 5 - .../couchbase/CouchbaseTargetSystem.java | 19 +- .../couchbase/CouchbaseImporterTest.java | 20 +- .../couchbase/changes/MongockChange2.java | 5 +- .../_0001__CreateUsersCollectionChange.java | 2 + .../dynamodb/DynamoDBImporterTest.java | 2 - .../_0001__CreateUsersTableChange.java | 2 +- .../support/mongock/MongockImportChange.java | 2 +- settings.gradle.kts | 16 - 33 files changed, 42 insertions(+), 1610 deletions(-) delete mode 100644 core/importer/flamingock-importer-couchbase-tests/build.gradle.kts delete mode 100644 core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/CouchbaseImporterTest.java delete mode 100644 core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/couchbase/_0001__CreateUsersCollectionChange.java delete mode 100644 core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/system/_0001__migration_from_mongock.yaml delete mode 100644 core/importer/flamingock-importer-dynamodb-tests/build.gradle.kts delete mode 100644 core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/DynamoDBImporterTest.java delete mode 100644 core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/DynamoDBTestHelper.java delete mode 100644 core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/DynamoDBAuditEntryEntity.java delete mode 100644 core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/DynamoDBConstants.java delete mode 100644 core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/_0001__CreateUsersTableChange.java delete mode 100644 core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0001__ClientInitializer.java delete mode 100644 core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0002__ClientUpdater.java delete mode 100644 core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/system/_0001__migration_from_mongock.yaml delete mode 100644 core/importer/flamingock-importer-mongodb-tests/build.gradle.kts delete mode 100644 core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBImporterTest.java delete mode 100644 core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java delete mode 100644 core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0001__ClientInitializer.java delete mode 100644 core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0002__ClientUpdater.java delete mode 100644 core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0003__create_users_collections.yaml delete mode 100644 core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0004__seed_users.yaml delete mode 100644 core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/system/_0001__migration_from_mongock.yaml diff --git a/core/flamingock-core-api/src/main/java/io/flamingock/api/annotations/Stage.java b/core/flamingock-core-api/src/main/java/io/flamingock/api/annotations/Stage.java index 503f3cc75..5ce800998 100644 --- a/core/flamingock-core-api/src/main/java/io/flamingock/api/annotations/Stage.java +++ b/core/flamingock-core-api/src/main/java/io/flamingock/api/annotations/Stage.java @@ -50,7 +50,5 @@ String name() default ""; String description() default ""; - - StageType type() default StageType.DEFAULT; } \ No newline at end of file diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java index 2e8f7bb1a..a41d81fd5 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java @@ -108,7 +108,7 @@ public ChangeProcessStrategy build() { changeLogger.logStartChangeProcessStrategy(change.getId()); - TargetSystemOps targetSystemOps = getTargetSystem(change.getId()); + TargetSystemOps targetSystemOps = getTargetSystem(); // Log target system resolution changeLogger.logTargetSystemResolved(change.getId(), change.getTargetSystem()); @@ -130,11 +130,11 @@ public ChangeProcessStrategy build() { ); } - private TargetSystemOps getTargetSystem(String changeId) { + private TargetSystemOps getTargetSystem() { try { return targetSystemManager.getTargetSystem(change.getTargetSystem()); } catch (Exception e) { - String message = String.format("Error in change [%s] : %s", changeId, e.getMessage()); + String message = String.format("Error in change [%s] : %s", change.getId(), e.getMessage()); throw new FlamingockException(message); } } 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 f885b11f9..4bb5ac667 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 @@ -315,36 +315,6 @@ private int getStageTypePriority(StageType stageType) { } } - /** - * Validates that stage types conform to the restrictions: - * - Maximum 1 SYSTEM stage allowed - * - Maximum 1 LEGACY stage allowed - * - Unlimited DEFAULT stages allowed - * - * @param stages the stages to validate - * @throws RuntimeException if validation fails - */ - private void validateStageTypes(Stage[] stages) { - int systemStageCount = 0; - int legacyStageCount = 0; - - for (Stage stage : stages) { - StageType stageType = stage.type(); - - if (stageType == StageType.SYSTEM) { - systemStageCount++; - if (systemStageCount > 1) { - throw new RuntimeException("Multiple SYSTEM stages are not allowed. Only one stage with type StageType.SYSTEM is permitted."); - } - } else if (stageType == StageType.LEGACY) { - legacyStageCount++; - if (legacyStageCount > 1) { - throw new RuntimeException("Multiple LEGACY stages are not allowed. Only one stage with type StageType.LEGACY is permitted."); - } - } - } - } - /** * Validates that stage types from YAML conform to the restrictions: * - Maximum 1 SYSTEM stage allowed @@ -450,7 +420,7 @@ private PreviewStage mapAnnotationToStage(Map> c logger.verbose("Resources directory: " + resourcesDir); } - return PreviewStage.defaultBuilder(stageAnnotation.type()) + return PreviewStage.defaultBuilder(StageType.DEFAULT) .setName(name) .setDescription(stageAnnotation.description().isEmpty() ? null : stageAnnotation.description()) .setSourcesRoots(sourceRoots) @@ -704,10 +674,6 @@ private void validateConfiguration(EnableFlamingock pipelineAnnotation, boolean throw new RuntimeException("@EnableFlamingock annotation must specify either configFile OR stages configuration."); } - // Validate stage type restrictions when using annotation-based configuration - if (hasStagesInAnnotation) { - validateStageTypes(pipelineAnnotation.stages()); - } } /** diff --git a/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java b/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java index 155994aaf..716f9bee3 100644 --- a/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java +++ b/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java @@ -178,68 +178,6 @@ void shouldCreatePipelineWithCorrectObjectStructure() throws Exception { assertEquals(StageType.DEFAULT, firstStage.getType()); } - /** - * Test validation that only one SYSTEM stage is allowed in annotation configuration. - */ - @Test - @DisplayName("Should throw error for multiple SYSTEM stages in annotation configuration") - void shouldThrowErrorForMultipleSystemStagesInAnnotation() throws Exception { - // Given - create annotation with multiple system stages - EnableFlamingock annotation = new MockFlamingockBuilder() - .withStages( - createMockStage("", StageType.SYSTEM, "com.example.system1"), - createMockStage("", StageType.SYSTEM, "com.example.system2"), - createMockStage("", StageType.DEFAULT, "com.example.migrations") - ) - .build(); - Map> changes = createMockChangesMap(); - FlamingockAnnotationProcessor processor = new FlamingockAnnotationProcessor(); - - // When & Then - should throw RuntimeException - Exception exception = assertThrows(Exception.class, () -> - callGetPipelineFromProcessChanges(processor, changes, annotation)); - - Throwable cause = exception.getCause(); - if (cause instanceof RuntimeException) { - assertTrue(cause.getMessage().contains("Multiple SYSTEM stages are not allowed"), - "Should have error about multiple SYSTEM stages"); - } else { - assertTrue(exception.getMessage().contains("Multiple SYSTEM stages are not allowed"), - "Should have error about multiple SYSTEM stages"); - } - } - - /** - * Test validation that only one LEGACY stage is allowed in annotation configuration. - */ - @Test - @DisplayName("Should throw error for multiple LEGACY stages in annotation configuration") - void shouldThrowErrorForMultipleLegacyStagesInAnnotation() throws Exception { - // Given - create annotation with multiple legacy stages - EnableFlamingock annotation = new MockFlamingockBuilder() - .withStages( - createMockStage("", StageType.LEGACY, "com.example.legacy1"), - createMockStage("", StageType.LEGACY, "com.example.legacy2"), - createMockStage("", StageType.DEFAULT, "com.example.migrations") - ) - .build(); - Map> changes = createMockChangesMap(); - FlamingockAnnotationProcessor processor = new FlamingockAnnotationProcessor(); - - // When & Then - should throw RuntimeException - Exception exception = assertThrows(Exception.class, () -> - callGetPipelineFromProcessChanges(processor, changes, annotation)); - - Throwable cause = exception.getCause(); - if (cause instanceof RuntimeException) { - assertTrue(cause.getMessage().contains("Multiple LEGACY stages are not allowed"), - "Should have error about multiple LEGACY stages"); - } else { - assertTrue(exception.getMessage().contains("Multiple LEGACY stages are not allowed"), - "Should have error about multiple LEGACY stages"); - } - } - /** * Test validation that multiple DEFAULT stages are allowed. */ @@ -249,9 +187,9 @@ void shouldAllowMultipleDefaultStagesInAnnotation() throws Exception { // Given - create annotation with multiple default stages EnableFlamingock annotation = new MockFlamingockBuilder() .withStages( - createMockStage("", StageType.DEFAULT, "com.example.migrations1"), - createMockStage("", StageType.DEFAULT, "com.example.migrations2"), - createMockStage("", StageType.DEFAULT, "com.example.migrations3") + createMockStage("", "com.example.migrations1"), + createMockStage("", "com.example.migrations2"), + createMockStage("", "com.example.migrations3") ) .build(); Map> changes = createMockChangesMap(); @@ -266,47 +204,6 @@ void shouldAllowMultipleDefaultStagesInAnnotation() throws Exception { assertNull(pipeline.getSystemStage(), "Should not have system stage"); } - /** - * Test that stages are ordered correctly regardless of declaration order. - */ - @Test - @DisplayName("Should order stages by type priority: LEGACY before DEFAULT") - void shouldOrderStagesByTypePriorityLegacyBeforeDefault() throws Exception { - // Given - create annotation with stages in reverse order (DEFAULT first, LEGACY second) - EnableFlamingock annotation = new MockFlamingockBuilder() - .withStages( - createMockStage("", StageType.DEFAULT, "com.example.migrations"), - createMockStage("", StageType.LEGACY, "com.example.init"), - createMockStage("", StageType.DEFAULT, "com.example.cleanup") - ) - .build(); - Map> changes = createMockChangesMap(); - FlamingockAnnotationProcessor processor = new FlamingockAnnotationProcessor(); - - // When - build pipeline from annotation - PreviewPipeline pipeline = buildPipelineFromAnnotation(processor, annotation, changes); - - // Then - verify stages are sorted by type priority - assertNotNull(pipeline, "Pipeline should be created"); - assertEquals(3, pipeline.getStages().size(), "Should have 3 stages"); - - PreviewStage[] stages = pipeline.getStages().toArray(new PreviewStage[0]); - - // First stage should be LEGACY (highest priority) - assertEquals(StageType.LEGACY, stages[0].getType()); - assertEquals("init", stages[0].getName()); - assertEquals("com.example.init", stages[0].getSourcesPackage()); - - // Second and third stages should be DEFAULT (lower priority) - assertEquals(StageType.DEFAULT, stages[1].getType()); - assertEquals("migrations", stages[1].getName()); - assertEquals("com.example.migrations", stages[1].getSourcesPackage()); - - assertEquals(StageType.DEFAULT, stages[2].getType()); - assertEquals("cleanup", stages[2].getName()); - assertEquals("com.example.cleanup", stages[2].getSourcesPackage()); - } - /** * Test that YAML stages are ordered correctly regardless of declaration order. */ @@ -573,7 +470,7 @@ private Map> createMockChangesMap() { private EnableFlamingock createMockAnnotationWithStages() { return new MockFlamingockBuilder() .withStages( - createMockStage("", StageType.DEFAULT, "com.example.migrations") + createMockStage("", "com.example.migrations") ) .build(); } @@ -588,11 +485,10 @@ private EnableFlamingock createMockAnnotationWithNeitherFileNorStages() { return new MockFlamingockBuilder().build(); } - private Stage createMockStage(String name, StageType type, String location) { + private Stage createMockStage(String name, String location) { return new Stage() { @Override public String name() { return name; } @Override public String description() { return ""; } - @Override public StageType type() { return type; } @Override public String location() { return location; } @Override public Class annotationType() { return Stage.class; } }; diff --git a/core/importer/flamingock-importer-couchbase-tests/build.gradle.kts b/core/importer/flamingock-importer-couchbase-tests/build.gradle.kts deleted file mode 100644 index 565c1130e..000000000 --- a/core/importer/flamingock-importer-couchbase-tests/build.gradle.kts +++ /dev/null @@ -1,49 +0,0 @@ -plugins { - id("java") -} - -group = "io.flamingock" -version = "0.0.38-beta" - -repositories { - mavenCentral() -} - -dependencies { - compileOnly("com.couchbase.client:java-client:3.6.0") - - - testImplementation(project(":core:importer:flamingock-importer")) - testAnnotationProcessor(project(":core:flamingock-processor")) - testImplementation(project(":community:flamingock-auditstore-couchbase")) - testImplementation(project(":utils:couchbase-util")) - testImplementation(project(":utils:test-util")) - - testImplementation("org.testcontainers:couchbase:1.21.3") - testImplementation("org.testcontainers:junit-jupiter:1.21.3") - testImplementation("org.mockito:mockito-inline:4.11.0") -} - -description = "Couchbase-specific integration tests for the Flamingock importer tool" - -tasks.test { - useJUnitPlatform() -} - -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(8)) - } -} - -tasks.withType().configureEach { - if (name.contains("Test", ignoreCase = true)) { - options.compilerArgs.addAll(listOf( - "-Asources=${projectDir}/src/test/java", - "-Aresources=${projectDir}/src/test/resources" - )) - } -} -configurations.testImplementation { - extendsFrom(configurations.compileOnly.get()) -} \ No newline at end of file diff --git a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/CouchbaseImporterTest.java b/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/CouchbaseImporterTest.java deleted file mode 100644 index 6b7645dbf..000000000 --- a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/CouchbaseImporterTest.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.couchbase; - -import com.couchbase.client.core.io.CollectionIdentifier; -import com.couchbase.client.java.Cluster; -import com.couchbase.client.java.Collection; -import com.couchbase.client.java.json.JsonObject; -import com.couchbase.client.java.manager.bucket.BucketManager; -import com.couchbase.client.java.manager.bucket.BucketSettings; -import io.flamingock.api.annotations.EnableFlamingock; -import io.flamingock.api.annotations.Stage; -import io.flamingock.community.couchbase.driver.CouchbaseAuditStore; -import io.flamingock.internal.core.builder.FlamingockFactory; -import io.flamingock.internal.util.constants.CommunityPersistenceConstants; -import io.flamingock.internal.core.runner.Runner; -import io.flamingock.internal.common.couchbase.CouchbaseCollectionHelper; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.testcontainers.couchbase.CouchbaseContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import java.time.Duration; -import java.time.Instant; -import java.util.List; - -import static io.flamingock.api.StageType.LEGACY; -import static io.flamingock.api.StageType.SYSTEM; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertFalse; - -@EnableFlamingock( - stages = { - @Stage(location = "io.flamingock.importer.couchbase.system", type = SYSTEM), - @Stage(location = "io.flamingock.importer.couchbase.legacy", type = LEGACY), - @Stage(location = "io.flamingock.importer.couchbase.couchbase") - } -) -@Testcontainers -public class CouchbaseImporterTest { - - public static final String FLAMINGOCK_BUCKET_NAME = "test"; - public static final String FLAMINGOCK_SCOPE_NAME = "flamingock"; - public static final String FLAMINGOCK_COLLECTION_NAME = CommunityPersistenceConstants.DEFAULT_AUDIT_STORE_NAME; - - public static final String MONGOCK_BUCKET_NAME = "test"; - public static final String MONGOCK_SCOPE_NAME = CollectionIdentifier.DEFAULT_SCOPE; - public static final String MONGOCK_COLLECTION_NAME = CollectionIdentifier.DEFAULT_COLLECTION; - - - @Container - static final CouchbaseContainer couchbaseContainer = new CouchbaseContainer("couchbase/server:7.2.4") - .withBucket(new org.testcontainers.couchbase.BucketDefinition(FLAMINGOCK_BUCKET_NAME)); - - private static Cluster cluster; - - @BeforeAll - static void setupAll() { - couchbaseContainer.start(); - cluster = Cluster.connect( - couchbaseContainer.getConnectionString(), - couchbaseContainer.getUsername(), - couchbaseContainer.getPassword() - ); - cluster.bucket(FLAMINGOCK_BUCKET_NAME).waitUntilReady(Duration.ofSeconds(10)); - - // Setup Mongock Bucket, Scope and Collection - BucketManager bucketManager = cluster.buckets(); - - int ramQuotaMB = 100; - - if (!bucketManager.getAllBuckets().containsKey(MONGOCK_BUCKET_NAME)) { - bucketManager.createBucket(BucketSettings.create(MONGOCK_BUCKET_NAME).ramQuotaMB(ramQuotaMB)); - cluster.bucket(MONGOCK_BUCKET_NAME).waitUntilReady(Duration.ofSeconds(10)); - } - - CouchbaseCollectionHelper.createScopeIfNotExists(cluster, MONGOCK_BUCKET_NAME, MONGOCK_SCOPE_NAME); - CouchbaseCollectionHelper.createCollectionIfNotExists(cluster, MONGOCK_BUCKET_NAME, MONGOCK_SCOPE_NAME, MONGOCK_COLLECTION_NAME); - CouchbaseCollectionHelper.createPrimaryIndexIfNotExists(cluster, MONGOCK_BUCKET_NAME, MONGOCK_SCOPE_NAME, MONGOCK_COLLECTION_NAME); - } - - @AfterEach - void cleanUp() { - CouchbaseCollectionHelper.deleteAllDocuments(cluster, FLAMINGOCK_BUCKET_NAME, FLAMINGOCK_SCOPE_NAME, FLAMINGOCK_COLLECTION_NAME); - CouchbaseCollectionHelper.deleteAllDocuments(cluster, MONGOCK_BUCKET_NAME, MONGOCK_SCOPE_NAME, MONGOCK_COLLECTION_NAME); - } - - @Test - @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") - void testImporterIntegration() { - Collection originCollection = cluster.bucket(MONGOCK_BUCKET_NAME).scope(MONGOCK_SCOPE_NAME).collection(MONGOCK_COLLECTION_NAME); - JsonObject doc = JsonObject.create() - .put("executionId", "exec-1") - .put("changeId", "change-1") - .put("author", "author1") - .put("timestamp", String.valueOf(Instant.now().toEpochMilli())) - .put("state", "EXECUTED") - .put("type", "EXECUTION") - .put("changeLogClass", "io.flamingock.changelog.Class1") - .put("changeSetMethod", "method1") - .putNull("metadata") - .put("executionMillis", 123L) - .put("executionHostName", "host1") - .putNull("errorTrace") - .put("systemChange", true) - .put("_doctype", "mongockChangeEntry"); - originCollection.upsert("change-1", doc); - - Runner flamingock = FlamingockFactory.getCommunityBuilder() - .setAuditStore(new CouchbaseAuditStore(cluster, FLAMINGOCK_BUCKET_NAME) - .withScopeName(FLAMINGOCK_SCOPE_NAME) - .withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME)) - .build(); - - flamingock.run(); - - List auditLog = CouchbaseCollectionHelper.selectAllDocuments(cluster, FLAMINGOCK_BUCKET_NAME, FLAMINGOCK_SCOPE_NAME, FLAMINGOCK_COLLECTION_NAME); - - assertFalse(auditLog.isEmpty(), "Audit log should not be empty"); - - JsonObject entry = auditLog.stream() - .filter(e -> "change-1".equals(e.getString("changeId"))) - .findFirst() - .orElseThrow(() -> new AssertionError("Entry with changeId 'change-1' not found")); - - assertEquals("change-1", entry.getString("changeId")); - assertEquals("author1", entry.getString("author")); - assertEquals("exec-1", entry.getString("executionId")); - assertEquals("APPLIED", entry.getString("state")); - assertTrue(entry.getBoolean("systemChange")); - } - - @Test - @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") - void failIfEmptyOrigin() { - Runner flamingock = FlamingockFactory.getCommunityBuilder() - .setAuditStore(new CouchbaseAuditStore(cluster, FLAMINGOCK_BUCKET_NAME) - .withScopeName(FLAMINGOCK_SCOPE_NAME) - .withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME)) - .build(); - - org.junit.jupiter.api.Assertions.assertThrows( - io.flamingock.internal.common.core.error.FlamingockException.class, - flamingock::run - ); - } -} \ No newline at end of file diff --git a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/couchbase/_0001__CreateUsersCollectionChange.java b/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/couchbase/_0001__CreateUsersCollectionChange.java deleted file mode 100644 index 34abae265..000000000 --- a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/couchbase/_0001__CreateUsersCollectionChange.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.couchbase.couchbase; - -import com.couchbase.client.java.Bucket; -import com.couchbase.client.java.Collection; -import com.couchbase.client.java.json.JsonObject; -import io.flamingock.api.annotations.Change; -import io.flamingock.api.annotations.Apply; - -import java.util.Collections; - -@Change(id = "create-users-collection", author = "importer", transactional = false) -public class _0001__CreateUsersCollectionChange { - - @Apply - public void apply(Bucket bucket) { - Collection collection = bucket.defaultCollection(); - - JsonObject user = JsonObject.create() - .put("email", "admin@company.com") - .put("name", "Admin") - .put("roles", Collections.singletonList("superuser")); - - collection.upsert("user::admin@company.com", user); - } -} diff --git a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/system/_0001__migration_from_mongock.yaml b/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/system/_0001__migration_from_mongock.yaml deleted file mode 100644 index 9fca41949..000000000 --- a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/system/_0001__migration_from_mongock.yaml +++ /dev/null @@ -1,8 +0,0 @@ -id: migration-from-mongock -transactional: false -template: CouchbaseImporterChangeTemplate -configuration: - origin: - scopeName: _default - collectionName: _default - failOnEmptyOrigin: true diff --git a/core/importer/flamingock-importer-dynamodb-tests/build.gradle.kts b/core/importer/flamingock-importer-dynamodb-tests/build.gradle.kts deleted file mode 100644 index 17cdf5f22..000000000 --- a/core/importer/flamingock-importer-dynamodb-tests/build.gradle.kts +++ /dev/null @@ -1,42 +0,0 @@ -dependencies { - - compileOnly("software.amazon.awssdk:dynamodb-enhanced:2.25.29") - - testImplementation(project(":core:importer:flamingock-importer")) - testAnnotationProcessor(project(":core:flamingock-processor")) - testImplementation(project(":community:flamingock-auditstore-dynamodb")) - - - testImplementation(project(":utils:test-util")) - - testImplementation("org.testcontainers:junit-jupiter:1.18.3") - testImplementation("org.mockito:mockito-inline:4.11.0") - testImplementation("org.testcontainers:localstack:1.19.7") - testImplementation("software.amazon.awssdk:dynamodb:2.25.61") - - testImplementation("org.mockito:mockito-inline:4.11.0") -} - -description = "DynamoDB-specific integration tests for the Flamingock importer tool" - -tasks.test { - useJUnitPlatform() -} - -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(8)) - } -} - -tasks.withType().configureEach { - if (name.contains("Test", ignoreCase = true)) { - options.compilerArgs.addAll(listOf( - "-Asources=${projectDir}/src/test/java", - "-Aresources=${projectDir}/src/test/resources" - )) - } -} -configurations.testImplementation { - extendsFrom(configurations.compileOnly.get()) -} \ No newline at end of file diff --git a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/DynamoDBImporterTest.java b/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/DynamoDBImporterTest.java deleted file mode 100644 index 744e67e1b..000000000 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/DynamoDBImporterTest.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.dynamodb; - -import io.flamingock.api.annotations.EnableFlamingock; -import io.flamingock.api.annotations.Stage; -import io.flamingock.community.dynamodb.driver.DynamoDBAuditStore; -import io.flamingock.internal.common.core.audit.AuditEntry; -import io.flamingock.internal.common.core.error.FlamingockException; -import io.flamingock.internal.core.builder.FlamingockFactory; -import io.flamingock.internal.core.runner.Runner; -import org.junit.jupiter.api.*; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.dynamodb.DynamoDbClient; -import software.amazon.awssdk.services.dynamodb.model.ScanRequest; -import software.amazon.awssdk.services.dynamodb.model.ScanResponse; - -import java.net.URI; -import java.time.Instant; -import java.util.*; - -import static io.flamingock.api.StageType.LEGACY; -import static io.flamingock.api.StageType.SYSTEM; -import static io.flamingock.internal.util.constants.CommunityPersistenceConstants.DEFAULT_AUDIT_STORE_NAME; -import static org.junit.jupiter.api.Assertions.*; - -@EnableFlamingock( - stages = { - @Stage(location = "io.flamingock.importer.dynamodb.system", type = SYSTEM), - @Stage(location = "io.flamingock.importer.dynamodb.legacy", type = LEGACY), - @Stage(location = "io.flamingock.importer.dynamodb.dynamodb") - } -) -@Testcontainers -public class DynamoDBImporterTest { - - @Container - public static final GenericContainer dynamoDBContainer = new GenericContainer<>("amazon/dynamodb-local:latest") - .withExposedPorts(8000); - - public static final String MONGOCK_CHANGE_LOGS = "mongockChangeLogs"; - - - private static DynamoDbClient client; - private DynamoDBTestHelper mongockChangeLogsHelper; - - @BeforeAll - static void beforeAll() { - dynamoDBContainer.start(); - - String endpoint = String.format("http://%s:%d", - dynamoDBContainer.getHost(), - dynamoDBContainer.getMappedPort(8000)); - client = DynamoDbClient.builder() - .endpointOverride(URI.create(endpoint)) - .region(Region.US_EAST_1) - .credentialsProvider( - StaticCredentialsProvider.create( - AwsBasicCredentials.create("dummy", "dummy") - ) - ) - .build(); - } - - @BeforeEach - void setUp() { - mongockChangeLogsHelper = new DynamoDBTestHelper(client, MONGOCK_CHANGE_LOGS); - mongockChangeLogsHelper.ensureTableExists(); - mongockChangeLogsHelper.resetTable(); - - new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).ensureTableExists(); - new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).resetTable(); - } - - @Test - @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") - void testImportDynamoDBChangeLogs() { - List entries = Arrays.asList( - new MongockDynamoDBAuditEntry( - "exec-1", - "client-initializer", - "author1", - String.valueOf(Instant.now().toEpochMilli()), - "EXECUTED", - "EXECUTION", - "io.flamingock.changelog.Class1", - "method1", - new HashMap() {{ put("meta1", "value1"); }}.toString(), - 123L, - "host1", - null, - true - ), - new MongockDynamoDBAuditEntry( - "exec-1", - "client-updater", - "author1", - String.valueOf(Instant.now().toEpochMilli()), - "EXECUTED", - "EXECUTION", - "io.flamingock.changelog.Class2", - "method1", - new HashMap() {{ put("meta1", "value1"); }}.toString(), - 123L, - "host1", - null, - true - ) - ); - - mongockChangeLogsHelper.insertChangeEntries(entries); - - Runner flamingock = FlamingockFactory.getCommunityBuilder() - .setAuditStore(new DynamoDBAuditStore(client)) - .build(); - - flamingock.run(); - - List auditLog = new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).getAuditEntriesSorted(); - assertEquals(6, auditLog.size()); - - for (AuditEntry entry : auditLog) { - System.out.println("executionId: " + entry.getExecutionId()); - System.out.println("stageId: " + entry.getStageId()); - System.out.println("taskId: " + entry.getTaskId()); - System.out.println("author: " + entry.getAuthor()); - System.out.println("createdAt: " + entry.getCreatedAt()); - System.out.println("state: " + entry.getState()); - System.out.println("type: " + entry.getType()); - System.out.println("className: " + entry.getClassName()); - System.out.println("methodName: " + entry.getMethodName()); - System.out.println("executionMillis: " + entry.getExecutionMillis()); - System.out.println("executionHostname: " + entry.getExecutionHostname()); - System.out.println("metadata: " + entry.getMetadata()); - System.out.println("systemChange: " + entry.getSystemChange()); - System.out.println("errorTrace: " + entry.getErrorTrace()); - System.out.println("txStrategy: " + entry.getTxType()); - System.out.println("targetSystemId: " + entry.getTargetSystemId()); - System.out.println("order: " + entry.getOrder()); - System.out.println("-----"); - } - - AuditEntry entry1 = auditLog.stream() - .filter(e -> "client-updater".equals(e.getTaskId())) - .findFirst() - .orElseThrow(() -> new AssertionError("Entry with changeId 'client-updater' not found")); - - - assertEquals("client-updater", entry1.getTaskId()); - assertEquals("author1", entry1.getAuthor()); - assertEquals("exec-1", entry1.getExecutionId()); - assertTrue(entry1.getSystemChange()); - - ScanResponse scanResponse = client.scan( - ScanRequest.builder().tableName(DEFAULT_AUDIT_STORE_NAME).build() - ); - assertTrue(scanResponse.count() > 0, "Audit table should not be empty"); - } - - @Test - @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") - void failIfEmptyOrigin() { - Runner flamingock = FlamingockFactory.getCommunityBuilder() - .setAuditStore(new DynamoDBAuditStore(client)) - .build(); - - Assertions.assertThrows(FlamingockException.class, flamingock::run); - } -} diff --git a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/DynamoDBTestHelper.java b/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/DynamoDBTestHelper.java deleted file mode 100644 index 8bce7a966..000000000 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/DynamoDBTestHelper.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.dynamodb; - -import io.flamingock.importer.dynamodb.dynamodb.DynamoDBAuditEntryEntity; -import io.flamingock.internal.common.core.audit.AuditEntry; -import software.amazon.awssdk.enhanced.dynamodb.*; -import software.amazon.awssdk.services.dynamodb.DynamoDbClient; -import software.amazon.awssdk.services.dynamodb.model.*; - -import java.util.*; -import java.util.stream.Collectors; - -import static io.flamingock.internal.util.constants.CommunityPersistenceConstants.DEFAULT_AUDIT_STORE_NAME; - -public class DynamoDBTestHelper { - - private final DynamoDbClient client; - private final String tableName; - private final DynamoDbTable table; - - public DynamoDBTestHelper(DynamoDbClient client, String tableName) { - this.client = client; - this.tableName = tableName; - DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() - .dynamoDbClient(client) - .build(); - - if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { - this.table = enhancedClient.table(tableName, TableSchema.fromBean(DynamoDBAuditEntryEntity.class)); - } else { - this.table = enhancedClient.table(tableName, TableSchema.fromBean(MongockDynamoDBAuditEntry.class)); - } - } - - public void ensureTableExists() { - ListTablesResponse tables = client.listTables(); - if (!tables.tableNames().contains(tableName)) { - if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { - client.createTable(CreateTableRequest.builder() - .tableName(tableName) - .keySchema( - KeySchemaElement.builder().attributeName("partitionKey").keyType(KeyType.HASH).build() - ) - .attributeDefinitions( - AttributeDefinition.builder().attributeName("partitionKey").attributeType(ScalarAttributeType.S).build() - ) - .provisionedThroughput( - ProvisionedThroughput.builder().readCapacityUnits(5L).writeCapacityUnits(5L).build() - ) - .build()); - } else { - client.createTable(CreateTableRequest.builder() - .tableName(tableName) - .keySchema( - KeySchemaElement.builder().attributeName("executionId").keyType(KeyType.HASH).build(), - KeySchemaElement.builder().attributeName("changeId").keyType(KeyType.RANGE).build() - ) - .attributeDefinitions( - AttributeDefinition.builder().attributeName("executionId").attributeType(ScalarAttributeType.S).build(), - AttributeDefinition.builder().attributeName("changeId").attributeType(ScalarAttributeType.S).build() - ) - .provisionedThroughput( - ProvisionedThroughput.builder().readCapacityUnits(5L).writeCapacityUnits(5L).build() - ) - .build()); - } - waitForTableActive(); - } - } - - private void waitForTableActive() { - while (true) { - DescribeTableResponse resp = client.describeTable(DescribeTableRequest.builder().tableName(tableName).build()); - if (resp.table().tableStatus() == TableStatus.ACTIVE) { - break; - } - try { - Thread.sleep(200); - } catch (InterruptedException ignored) {} - } - } - - public void resetTable() { - ScanRequest scanRequest = ScanRequest.builder().tableName(tableName).build(); - ScanResponse scanResponse = client.scan(scanRequest); - for (Map item : scanResponse.items()) { - Map key = new HashMap<>(); - if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { - key.put("partitionKey", item.get("partitionKey")); - } else { - key.put("executionId", item.get("executionId")); - key.put("changeId", item.get("changeId")); - } - client.deleteItem(DeleteItemRequest.builder() - .tableName(tableName) - .key(key) - .build()); - } - } - - public void insertChangeEntries(List entries) { - if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { - throw new UnsupportedOperationException("insertChangeEntries is only for change log tables"); - } - DynamoDbTable changeTable = (DynamoDbTable) table; - for (MongockDynamoDBAuditEntry entry : entries) { - changeTable.putItem(entry); - } - } - - public List getAuditEntriesSorted() { - if (DEFAULT_AUDIT_STORE_NAME.equals(tableName)) { - DynamoDbTable auditTable = (DynamoDbTable) table; - List entities = new ArrayList<>(); - auditTable.scan().items().forEach(entities::add); - return entities.stream() - .map(DynamoDBAuditEntryEntity::toAuditEntry) - .sorted() - .collect(Collectors.toList()); - } else { - DynamoDbTable changeTable = (DynamoDbTable) table; - List entries = new ArrayList<>(); - changeTable.scan().items().forEach(entries::add); - return entries.stream() - .map(MongockDynamoDBAuditEntry::toAuditEntry) - .sorted() - .collect(Collectors.toList()); - } - } -} diff --git a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/DynamoDBAuditEntryEntity.java b/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/DynamoDBAuditEntryEntity.java deleted file mode 100644 index 5bf22e163..000000000 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/DynamoDBAuditEntryEntity.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.dynamodb.dynamodb; - -import io.flamingock.api.RecoveryStrategy; -import io.flamingock.internal.common.core.audit.AuditEntry; -import io.flamingock.internal.util.constants.AuditEntryFieldConstants; -import io.flamingock.internal.common.core.audit.AuditTxType; -import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute; -import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; -import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; - -import java.time.LocalDateTime; -import java.util.Objects; - -@DynamoDbBean -public class DynamoDBAuditEntryEntity implements Comparable { - - protected Boolean systemChange; - private String partitionKey; - private String taskId; - private String stageId; - private String executionId; - private String author; - private LocalDateTime createdAt; - private AuditEntry.Status state; - private String className; - private String methodName; - private Object metadata; - private Long executionMillis; - private String executionHostname; - private Object errorTrace; - private AuditEntry.ExecutionType type; - private AuditTxType txStrategy; - private String targetSystemId; - private String order; - private String recoveryStrategy; - private Boolean transactionFlag; - - public static DynamoDBAuditEntryEntity fromAuditEntry(AuditEntry auditEntry) { - return new DynamoDBAuditEntryEntity(auditEntry); - } - - public DynamoDBAuditEntryEntity(AuditEntry auditEntry) { - this.partitionKey = partitionKey(auditEntry.getExecutionId(), auditEntry.getTaskId(), auditEntry.getState()); - this.taskId = auditEntry.getTaskId(); - this.stageId = auditEntry.getStageId(); - this.executionId = auditEntry.getExecutionId(); - this.author = auditEntry.getAuthor(); - this.createdAt = auditEntry.getCreatedAt(); - this.state = auditEntry.getState(); - this.className = auditEntry.getClassName(); - this.methodName = auditEntry.getMethodName(); - this.metadata = auditEntry.getMetadata(); - this.executionMillis = auditEntry.getExecutionMillis(); - this.executionHostname = auditEntry.getExecutionHostname(); - this.errorTrace = auditEntry.getErrorTrace(); - this.type = auditEntry.getType(); - this.txStrategy = auditEntry.getTxType(); - this.targetSystemId = auditEntry.getTargetSystemId(); - this.order = auditEntry.getOrder(); - this.systemChange = auditEntry.getSystemChange(); - this.recoveryStrategy = auditEntry.getRecoveryStrategy().name(); - this.transactionFlag = auditEntry.getTransactionFlag(); - } - - public DynamoDBAuditEntryEntity() {} - - public static String partitionKey(String executionId, String taskId, AuditEntry.Status state) { - return executionId + '#' + taskId + '#' + state.name(); - } - - @DynamoDbPartitionKey - @DynamoDbAttribute(DynamoDBConstants.AUDIT_LOG_PK) - public String getPartitionKey() { - return partitionKey; - } - - public void setPartitionKey(String partitionKey) { - this.partitionKey = partitionKey; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_CHANGE_ID) - public String getTaskId() { - return taskId; - } - - public void setTaskId(String taskId) { - this.taskId = taskId; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_STAGE_ID) - public String getStageId() { - return stageId; - } - - public void setStageId(String stageId) { - this.stageId = stageId; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_EXECUTION_ID) - public String getExecutionId() { - return executionId; - } - - public void setExecutionId(String executionId) { - this.executionId = executionId; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_AUTHOR) - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TIMESTAMP) - public LocalDateTime getCreatedAt() { - return createdAt; - } - - public void setCreatedAt(LocalDateTime createdAt) { - this.createdAt = createdAt; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_STATE) - public String getState() { - return state.name(); - } - - public void setState(String state) { - this.state = AuditEntry.Status.valueOf(state); - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_CHANGE_CLASS) - public String getClassName() { - return className; - } - - public void setClassName(String className) { - this.className = className; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_INVOKED_METHOD) - public String getMethodName() { - return methodName; - } - - public void setMethodName(String methodName) { - this.methodName = methodName; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_METADATA) - public String getMetadata() { - return metadata.toString(); - } - - public void setMetadata(Object metadata) { - this.metadata = metadata; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_EXECUTION_MILLIS) - public Long getExecutionMillis() { - return executionMillis; - } - - public void setExecutionMillis(Long executionMillis) { - this.executionMillis = executionMillis; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_EXECUTION_HOSTNAME) - public String getExecutionHostname() { - return executionHostname; - } - - public void setExecutionHostname(String executionHostname) { - this.executionHostname = executionHostname; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_ERROR_TRACE) - public String getErrorTrace() { - return errorTrace.toString(); - } - - public void setErrorTrace(Object errorTrace) { - this.errorTrace = errorTrace; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TYPE) - public String getType() { - return type.name(); - } - - public void setType(String type) { - this.type = AuditEntry.ExecutionType.valueOf(type); - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_SYSTEM_CHANGE) - public Boolean getSystemChange() { - return systemChange; - } - - public void setSystemChange(Boolean systemChange) { - this.systemChange = systemChange; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TX_STRATEGY) - public String getTxType() { - return AuditTxType.safeString(txStrategy); - } - - public void setTxType(String txStrategy) { - this.txStrategy = AuditTxType.fromString(txStrategy); - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TARGET_SYSTEM_ID) - public String getTargetSystemId() { - return targetSystemId; - } - - public void setTargetSystemId(String targetSystemId) { - this.targetSystemId = targetSystemId; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_ORDER) - public String getOrder() { - return order; - } - - public void setOrder(String order) { - this.order = order; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_RECOVERY_STRATEGY) - public String getRecoveryStrategy() { - return recoveryStrategy; - } - - public void setRecoveryStrategy(String recoveryStrategy) { - this.recoveryStrategy = recoveryStrategy; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TRANSACTION_FLAG) - public Boolean getTransactionFlag() { - return transactionFlag; - } - - public void setTransactionFlag(Boolean transactionFlag) { - this.transactionFlag = transactionFlag; - } - - @Override - public int compareTo(DynamoDBAuditEntryEntity other) { - if (other == null) { - return 1; - } - int timeComparison = this.createdAt.compareTo(other.createdAt); - if (timeComparison != 0) { - return timeComparison; - } - if (this.order != null && other.order != null) { - int orderComparison = this.order.compareTo(other.order); - if (orderComparison != 0) { - return orderComparison; - } - } - return Integer.compare(this.state.getPriority(), other.state.getPriority()); - } - - public AuditEntry toAuditEntry() { - return new AuditEntry( - executionId, - stageId, - taskId, - author, - createdAt, - state, - type, - className, - methodName, - executionMillis, - executionHostname, - metadata, - systemChange, - Objects.toString(errorTrace, ""), - txStrategy, - targetSystemId, - order, - recoveryStrategy != null ? RecoveryStrategy.valueOf(recoveryStrategy) : RecoveryStrategy.MANUAL_INTERVENTION, - transactionFlag - ); - } -} \ No newline at end of file diff --git a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/DynamoDBConstants.java b/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/DynamoDBConstants.java deleted file mode 100644 index 752a06b92..000000000 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/DynamoDBConstants.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.dynamodb.dynamodb; - -public final class DynamoDBConstants { - - public static final String AUDIT_LOG_PK = "partitionKey"; - - public static final String LOCK_PK = "partitionKey"; - public static final String LOCK_OWNER = "lockOwner"; - - private DynamoDBConstants() { - } -} diff --git a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/_0001__CreateUsersTableChange.java b/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/_0001__CreateUsersTableChange.java deleted file mode 100644 index c785004a8..000000000 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/_0001__CreateUsersTableChange.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.dynamodb.dynamodb; - -import io.flamingock.api.annotations.Change; -import io.flamingock.api.annotations.Apply; -import software.amazon.awssdk.services.dynamodb.DynamoDbClient; -import software.amazon.awssdk.services.dynamodb.model.*; - -@Change(id = "create-users-table", author = "importer") -public class _0001__CreateUsersTableChange { - - @Apply - public void apply(DynamoDbClient dynamoDBClient) { - String tableName = "users"; - try { - dynamoDBClient.createTable(CreateTableRequest.builder() - .tableName(tableName) - .keySchema(KeySchemaElement.builder() - .attributeName("email") - .keyType(KeyType.HASH) - .build()) - .attributeDefinitions(AttributeDefinition.builder() - .attributeName("email") - .attributeType(ScalarAttributeType.S) - .build()) - .billingMode(BillingMode.PAY_PER_REQUEST) - .build()); - } catch (ResourceInUseException ignored) { - // Table already exists, ignore - } - } -} diff --git a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0001__ClientInitializer.java b/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0001__ClientInitializer.java deleted file mode 100644 index be241903c..000000000 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0001__ClientInitializer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.dynamodb.legacy; - -import io.flamingock.api.annotations.Change; -import io.flamingock.api.annotations.Apply; - -@Change(id = "client-initializer", author = "mongock") -public class _0001__ClientInitializer { - - @Apply - public void apply() { - System.out.println("Client Initializer"); - } -} diff --git a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0002__ClientUpdater.java b/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0002__ClientUpdater.java deleted file mode 100644 index 0f9fc9077..000000000 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0002__ClientUpdater.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.dynamodb.legacy; - -import io.flamingock.api.annotations.Change; -import io.flamingock.api.annotations.Apply; - -@Change(id = "client-updater", author = "mongock") -public class _0002__ClientUpdater { - - @Apply - public void apply() { - System.out.println("Client Initializer"); - } -} diff --git a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/system/_0001__migration_from_mongock.yaml b/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/system/_0001__migration_from_mongock.yaml deleted file mode 100644 index d3b2cdeb3..000000000 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/system/_0001__migration_from_mongock.yaml +++ /dev/null @@ -1,6 +0,0 @@ -id: migration-from-mongock -transactional: false -template: DynamoDBImporterChangeTemplate -configuration: - origin: mongockChangeLogs - failOnEmptyOrigin: true diff --git a/core/importer/flamingock-importer-mongodb-tests/build.gradle.kts b/core/importer/flamingock-importer-mongodb-tests/build.gradle.kts deleted file mode 100644 index d68e41624..000000000 --- a/core/importer/flamingock-importer-mongodb-tests/build.gradle.kts +++ /dev/null @@ -1,40 +0,0 @@ -dependencies { - compileOnly("org.mongodb:mongodb-driver-sync:4.0.0") - - testImplementation(project(":core:importer:flamingock-importer")) - testAnnotationProcessor(project(":core:flamingock-processor")) - testImplementation(project(":community:flamingock-auditstore-mongodb-sync")) - testImplementation(project(":templates:flamingock-mongodb-sync-template")) - testImplementation(project(":utils:test-util")) - testImplementation(project(":utils:mongodb-util")) - - testImplementation("org.testcontainers:mongodb:1.18.3") - - testImplementation("org.testcontainers:junit-jupiter:1.18.3") - testImplementation("org.mockito:mockito-inline:4.11.0") - -} - -description = "MongoDB-specific integration tests for the Flamingock importer tool" - -tasks.test { - useJUnitPlatform() -} - -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(8)) - } -} - -tasks.withType().configureEach { - if (name.contains("Test", ignoreCase = true)) { - options.compilerArgs.addAll(listOf( - "-Asources=${projectDir}/src/test/java", - "-Aresources=${projectDir}/src/test/resources" - )) - } -} -configurations.testImplementation { - extendsFrom(configurations.compileOnly.get()) -} \ No newline at end of file diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBImporterTest.java b/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBImporterTest.java deleted file mode 100644 index a1510427e..000000000 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBImporterTest.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.mongodb; - -import com.mongodb.ConnectionString; -import com.mongodb.MongoClientSettings; -import com.mongodb.client.MongoClient; -import com.mongodb.client.MongoClients; -import com.mongodb.client.MongoDatabase; -import io.flamingock.api.annotations.EnableFlamingock; -import io.flamingock.api.annotations.Stage; -import io.flamingock.internal.common.core.error.FlamingockException; -import io.flamingock.internal.core.runner.Runner; -import io.flamingock.mongodb.kit.MongoDBSyncTestKit; -import io.flamingock.community.mongodb.sync.driver.MongoDBSyncAuditStore; -import io.flamingock.core.kit.TestKit; -import io.flamingock.core.kit.audit.AuditTestHelper; -import org.bson.Document; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.testcontainers.containers.MongoDBContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - -import java.util.ArrayList; -import java.util.List; - -import static io.flamingock.api.StageType.LEGACY; -import static io.flamingock.api.StageType.SYSTEM; -import static io.flamingock.core.kit.audit.AuditEntryExpectation.APPLIED; -import static io.flamingock.core.kit.audit.AuditEntryExpectation.STARTED; -import static org.junit.jupiter.api.Assertions.assertEquals; - -@EnableFlamingock( - stages = { - @Stage(location = "io.flamingock.importer.mongodb.system", type = SYSTEM), - @Stage(location = "io.flamingock.importer.mongodb.legacy", type = LEGACY), - @Stage(location = "io.flamingock.importer.mongodb.mongodb") - } -) -@Testcontainers -public class MongoDBImporterTest { - - @Container - public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); - - private static final String DB_NAME = "test"; - public static final String MONGOCK_CHANGE_LOGS = "mongockChangeLogs"; - - private static MongoClient mongoClient; - private static MongoDatabase database; - private MongoDBMongockTestHelper mongockTestHelper; - private TestKit testKit; - private AuditTestHelper auditHelper; - - - @BeforeEach - void setUp() { - mongoClient = MongoClients.create(MongoClientSettings - .builder() - .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) - .build()); - database = mongoClient.getDatabase(DB_NAME); - - mongockTestHelper = new MongoDBMongockTestHelper(database.getCollection(MONGOCK_CHANGE_LOGS)); - - // Initialize TestKit for unified testing - testKit = MongoDBSyncTestKit.create(new MongoDBSyncAuditStore(mongoClient, "test"), mongoClient, database); - auditHelper = testKit.getAuditHelper(); - - } - - @AfterEach - void tearDown() { - database.drop(); // Clean between tests - mongoClient.close(); - } - - @Test - @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") - void testImportMongockChangeLogs() { - //adds the Mongock - mongockTestHelper.setupBasicScenario(); - - Runner flamingock = testKit.createBuilder() - .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("client-initializer_before"), - APPLIED("client-initializer"), - APPLIED("client-updater"), - - // System stage - actual system importer change - STARTED("migration-from-mongock"), - APPLIED("migration-from-mongock"), - - // 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 - @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") - void failIfEmptyOrigin() { - //adds the Mongock - - Runner flamingock = testKit.createBuilder() - .build(); - - //TODO should check error message, but currently it return the summary text - Assertions.assertThrows(FlamingockException.class, flamingock::run); - - } - -} diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java b/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java deleted file mode 100644 index 74012b8b2..000000000 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.mongodb; - -import com.mongodb.client.MongoCollection; -import io.flamingock.common.test.mongock.MongockTestHelper; -import org.bson.Document; - -import java.util.ArrayList; -import java.util.List; - -public class MongoDBMongockTestHelper implements MongockTestHelper { - - private final MongoCollection changeLogCollection; - - public MongoDBMongockTestHelper(MongoCollection changeLogCollection) { - this.changeLogCollection = changeLogCollection; - } - - public void write(MongockChangeEntry entry) { - changeLogCollection.insertOne(convertToDocument(entry)); - } - - public int writeAll(List entries) { - List documents = new ArrayList<>(entries.size()); - for (MongockChangeEntry entry : entries) { - documents.add(convertToDocument(entry)); - } - changeLogCollection.insertMany(documents); - return documents.size(); - } - - private Document convertToDocument(MongockChangeEntry entry) { - Document document = new Document(); - document.put("executionId", entry.getExecutionId()); - document.put("changeId", entry.getChangeId()); - document.put("author", entry.getAuthor()); - document.put("timestamp", entry.getTimestamp()); - document.put("state", entry.getState() != null ? entry.getState().toString() : null); - document.put("type", entry.getType() != null ? entry.getType().toString() : null); - document.put("changeLogClass", entry.getChangeLogClass()); - document.put("changeSetMethod", entry.getChangeSetMethod()); - document.put("metadata", entry.getMetadata()); - document.put("executionMillis", entry.getExecutionMillis()); - document.put("executionHostname", entry.getExecutionHostname()); - document.put("errorTrace", entry.getErrorTrace()); - document.put("systemChange", entry.getSystemChange()); - document.put("originalTimestamp", entry.getOriginalTimestamp()); - return document; - } -} diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0001__ClientInitializer.java b/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0001__ClientInitializer.java deleted file mode 100644 index 7fc4b3a5e..000000000 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0001__ClientInitializer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.mongodb.legacy; - -import io.flamingock.api.annotations.Change; -import io.flamingock.api.annotations.Apply; - -@Change(id = "client-initializer", author = "flamingock-team") -public class _0001__ClientInitializer { - - @Apply - public void apply() { - System.out.println("Client Initializer"); - } -} diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0002__ClientUpdater.java b/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0002__ClientUpdater.java deleted file mode 100644 index 32622a1dd..000000000 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0002__ClientUpdater.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.mongodb.legacy; - -import io.flamingock.api.annotations.Change; -import io.flamingock.api.annotations.Apply; - -@Change(id = "client-updater", author = "flamingock-team") -public class _0002__ClientUpdater { - - @Apply - public void apply() { - System.out.println("Client Initializer"); - } -} diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0003__create_users_collections.yaml b/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0003__create_users_collections.yaml deleted file mode 100644 index 5e91a29be..000000000 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0003__create_users_collections.yaml +++ /dev/null @@ -1,9 +0,0 @@ -id: create-users-collection-with-index -#transactional: false -template: MongoChangeTemplate -targetSystem: - id: "mongodb" -apply: - type: createCollection - collection: users - diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0004__seed_users.yaml b/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0004__seed_users.yaml deleted file mode 100644 index 1d2f53822..000000000 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0004__seed_users.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: seed-users -transactional: true -template: MongoChangeTemplate -targetSystem: - id: "mongodb" -apply: - type: insert - collection: users - parameters: - documents: - - name: "Admin" - email: "admin@company.com" - roles: [ "superuser" ] - - name: "Backup" - email: "backup@company.com" - roles: [ "readonly" ] \ No newline at end of file diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/system/_0001__migration_from_mongock.yaml b/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/system/_0001__migration_from_mongock.yaml deleted file mode 100644 index 0e3d37f0b..000000000 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/system/_0001__migration_from_mongock.yaml +++ /dev/null @@ -1,5 +0,0 @@ -id: migration-from-mongock -transactional: false -template: MongoDBImporterChangeTemplate -configuration: - origin: mongockChangeLogs 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 255432d19..9ab9578e7 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 @@ -19,14 +19,22 @@ import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.transactions.TransactionAttemptContext; +import io.flamingock.importer.mongock.couchbase.MongockImporterCouchbase; +import io.flamingock.internal.common.core.audit.AuditHistoryReader; +import io.flamingock.internal.common.core.audit.AuditReaderType; import io.flamingock.internal.common.core.context.ContextResolver; -import io.flamingock.internal.core.builder.FlamingockEdition; import io.flamingock.internal.core.transaction.TransactionManager; import io.flamingock.internal.core.targets.TransactionalTargetSystem; import io.flamingock.internal.core.targets.mark.NoOpTargetSystemAuditMarker; import io.flamingock.internal.core.transaction.TransactionWrapper; import io.flamingock.internal.common.core.error.FlamingockException; +import java.util.Objects; +import java.util.Optional; + +import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK; +import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; + public class CouchbaseTargetSystem extends TransactionalTargetSystem { private Cluster cluster; @@ -87,4 +95,13 @@ protected CouchbaseTargetSystem getSelf() { public TransactionWrapper getTxWrapper() { return txWrapper; } + + @Override + public Optional getAuditAuditReader(AuditReaderType type) { + if (Objects.requireNonNull(type) == MONGOCK) { + return Optional.of(new MongockImporterCouchbase(cluster, bucketName, scopeName, DEFAULT_MONGOCK_ORIGIN)); + } else { + return Optional.empty(); + } + } } 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 d7ac93c9b..1faf07c1f 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 @@ -28,6 +28,8 @@ import io.flamingock.internal.core.builder.FlamingockFactory; import io.flamingock.internal.core.runner.Runner; import io.flamingock.internal.util.constants.CommunityPersistenceConstants; +import io.flamingock.support.mongock.annotations.MongockSupport; +import io.flamingock.targetsystem.couchbase.CouchbaseTargetSystem; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; @@ -40,20 +42,14 @@ import java.time.Instant; import java.util.List; -import static io.flamingock.api.StageType.LEGACY; -import static io.flamingock.api.StageType.SYSTEM; +import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -@EnableFlamingock( - stages = { - @Stage(location = "io.flamingock.importer.couchbase.system", type = SYSTEM), - @Stage(location = "io.flamingock.importer.couchbase.legacy", type = LEGACY), - @Stage(location = "io.flamingock.importer.couchbase.couchbase") - } -) @Testcontainers +@MongockSupport(targetSystem = "couchbase-target-system") +@EnableFlamingock(stages = {@Stage(location = "io.flamingock.importer.mongock.couchbase.changes")}) public class CouchbaseImporterTest { public static final String FLAMINGOCK_BUCKET_NAME = "test"; @@ -62,7 +58,7 @@ public class CouchbaseImporterTest { public static final String MONGOCK_BUCKET_NAME = "test"; public static final String MONGOCK_SCOPE_NAME = CollectionIdentifier.DEFAULT_SCOPE; - public static final String MONGOCK_COLLECTION_NAME = CollectionIdentifier.DEFAULT_COLLECTION; + public static final String MONGOCK_COLLECTION_NAME = DEFAULT_MONGOCK_ORIGIN; @Container @@ -103,7 +99,6 @@ void cleanUp() { } @Test - @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") void testImporterIntegration() { Collection originCollection = cluster.bucket(MONGOCK_BUCKET_NAME).scope(MONGOCK_SCOPE_NAME).collection(MONGOCK_COLLECTION_NAME); JsonObject doc = JsonObject.create() @@ -123,10 +118,13 @@ void testImporterIntegration() { .put("_doctype", "mongockChangeEntry"); originCollection.upsert("change-1", doc); + CouchbaseTargetSystem targetSystem = new CouchbaseTargetSystem("couchbase-target-system", cluster, FLAMINGOCK_BUCKET_NAME); + Runner flamingock = FlamingockFactory.getCommunityBuilder() .setAuditStore(new CouchbaseAuditStore(cluster, FLAMINGOCK_BUCKET_NAME) .withScopeName(FLAMINGOCK_SCOPE_NAME) .withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME)) + .addTargetSystem(targetSystem) .build(); flamingock.run(); diff --git a/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange2.java b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange2.java index 4ab1324c5..2d5f9b1de 100644 --- a/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange2.java +++ b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange2.java @@ -15,14 +15,13 @@ */ package io.flamingock.importer.mongock.couchbase.changes; -import io.flamingock.api.annotations.Change; -import io.flamingock.api.annotations.Apply; import io.mongock.api.annotations.ChangeUnit; +import io.mongock.api.annotations.Execution; @ChangeUnit(id = "client-updater", order = "2", author = "flamingock-team", transactional = false) public class MongockChange2 { - @Apply + @Execution public void apply() { System.out.println("Client Initializer"); } diff --git a/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java index 5319f08c4..4e04dcc1e 100644 --- a/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java +++ b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java @@ -20,9 +20,11 @@ import com.couchbase.client.java.json.JsonObject; import io.flamingock.api.annotations.Apply; import io.flamingock.api.annotations.Change; +import io.flamingock.api.annotations.TargetSystem; import java.util.Collections; +@TargetSystem(id = "couchbase-target-system") @Change(id = "create-users-collection", author = "importer", transactional = false) public class _0001__CreateUsersCollectionChange { 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 d4e8c59b6..c8cd18987 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 @@ -47,8 +47,6 @@ 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.util.constants.CommunityPersistenceConstants.DEFAULT_AUDIT_STORE_NAME; -import static io.flamingock.internal.util.constants.CommunityPersistenceConstants.DEFAULT_LOCK_STORE_NAME; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java index 82acb60fd..c8ec51e5a 100644 --- a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java @@ -27,8 +27,8 @@ import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException; import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; -@Change(id = "create-users-table", author = "importer") @TargetSystem(id = "dynamodb-target-system") +@Change(id = "create-users-table", author = "importer") public class _0001__CreateUsersTableChange { @Apply 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 581746b0c..4a08cad92 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 @@ -65,7 +65,7 @@ private static AuditHistoryReader getAuditHistoryReader(String targetSystemId, T if (targetSystemOps instanceof TransactionalTargetSystemOps) { legacyAuditReader = ((TransactionalTargetSystemOps) targetSystemOps).getAuditAuditReader(MONGOCK) .orElseThrow(() -> { - String message = "TargetSystem[%s], specified in @MongockSupport doesn't provide Mongock importing support"; + String message = String.format("TargetSystem[%s], specified in @MongockSupport doesn't provide Mongock importing support", targetSystemId); return new FlamingockException(message); }); } else { diff --git a/settings.gradle.kts b/settings.gradle.kts index 590ee1c4f..46d72f3a1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -159,22 +159,6 @@ include("core:importer:flamingock-importer") project(":core:importer:flamingock-importer").name = "flamingock-importer" project(":core:importer:flamingock-importer").projectDir = file("core/importer/flamingock-importer") -include("core:importer:flamingock-importer-mongodb-tests") -project(":core:importer:flamingock-importer-mongodb-tests").name = "flamingock-importer-mongodb-tests" -project(":core:importer:flamingock-importer-mongodb-tests").projectDir = - file("core/importer/flamingock-importer-mongodb-tests") - - -include("core:importer:flamingock-importer-dynamodb-tests") -project(":core:importer:flamingock-importer-dynamodb-tests").name = "flamingock-importer-dynamodb-tests" -project(":core:importer:flamingock-importer-dynamodb-tests").projectDir = - file("core/importer/flamingock-importer-dynamodb-tests") - - -include("core:importer:flamingock-importer-couchbase-tests") -project(":core:importer:flamingock-importer-couchbase-tests").name = "flamingock-importer-couchbase-tests" -project(":core:importer:flamingock-importer-couchbase-tests").projectDir = - file("core/importer/flamingock-importer-couchbase-tests") ////////////////////////////////////// // LEGACY From 311529cbe87575f81bb3aac0e9d6943e6807c8b5 Mon Sep 17 00:00:00 2001 From: Antonio Perez Dieppa Date: Mon, 24 Nov 2025 21:36:25 +0000 Subject: [PATCH 07/10] refactor: fixed deprecated import clases --- core/flamingock-core/build.gradle.kts | 1 - .../targets/TransactionalTargetSystem.java | 1 - .../TransactionalTargetSystemOps.java | 1 - .../graalvm/RegistrationFeature.java | 56 ++-- core/importer/flamingock-importer/README.md | 7 - .../flamingock-importer/build.gradle.kts | 43 --- .../importer/AbstractImportConfiguration.java | 33 -- .../importer/ImportConfiguration.java | 31 -- .../flamingock/importer/ImporterAdapter.java | 23 -- .../flamingock/importer/ImporterExecutor.java | 76 ----- .../importer/ImporterTemplateFactory.java | 125 ------- .../couchbase/CouchbaseChangeEntry.java | 105 ------ .../CouchbaseImportConfiguration.java | 31 -- .../couchbase/CouchbaseImporterAdapter.java | 62 ---- .../CouchbaseImporterChangeTemplate.java | 63 ---- .../importer/couchbase/CouchbaseOrigin.java | 43 --- .../dynamodb/DynamoDBImporterAdapter.java | 50 --- .../DynamoDBImporterChangeTemplate.java | 51 --- .../mongodb/MongoDBImporterAdapter.java | 97 ------ .../MongoDBImporterChangeTemplate.java | 53 --- ...common.core.template.ChangeTemplateFactory | 1 - .../importer/ImporterExecutorTest.java | 65 ---- .../mongock/dynamodb/MongockAuditEntry.java | 1 - .../mongock/dynamodb/MongockChangeState.java | 22 +- .../dynamodb/DynamoDBMongockTestHelper.java | 3 +- .../dynamodb/MongockDynamoDBAuditEntry.java | 4 +- .../changes/DynamoDBAuditEntryEntity.java | 308 ------------------ .../dynamodb/changes/DynamoDBConstants.java | 27 -- .../mongodb/MongoDBMongockTestHelper.java | 2 +- settings.gradle.kts | 8 - .../test/mongock}/MongockChangeEntry.java | 3 +- .../test/mongock}/MongockChangeState.java | 21 +- .../test/mongock}/MongockChangeType.java | 14 +- .../test/mongock/MongockTestHelper.java | 4 +- 34 files changed, 63 insertions(+), 1372 deletions(-) delete mode 100644 core/importer/flamingock-importer/README.md delete mode 100644 core/importer/flamingock-importer/build.gradle.kts delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/AbstractImportConfiguration.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImportConfiguration.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterAdapter.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterExecutor.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterTemplateFactory.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImportConfiguration.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterChangeTemplate.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseOrigin.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterChangeTemplate.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java delete mode 100644 core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterChangeTemplate.java delete mode 100644 core/importer/flamingock-importer/src/main/resources/META-INF/services/io.flamingock.internal.common.core.template.ChangeTemplateFactory delete mode 100644 core/importer/flamingock-importer/src/test/java/io/flamingock/importer/ImporterExecutorTest.java rename core/importer/flamingock-importer/src/main/java/io/flamingock/importer/AbstractImporterChangeTemplate.java => legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockChangeState.java (52%) rename {core/importer/flamingock-importer/src/main/java/io/flamingock/importer => legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock}/dynamodb/MongockDynamoDBAuditEntry.java (98%) delete mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBAuditEntryEntity.java delete mode 100644 legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBConstants.java rename {core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb => utils/test-util/src/main/java/io/flamingock/common/test/mongock}/MongockChangeEntry.java (99%) rename {core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb => utils/test-util/src/main/java/io/flamingock/common/test/mongock}/MongockChangeState.java (60%) rename {core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb => utils/test-util/src/main/java/io/flamingock/common/test/mongock}/MongockChangeType.java (77%) diff --git a/core/flamingock-core/build.gradle.kts b/core/flamingock-core/build.gradle.kts index d87c6b6b1..c775aa5f8 100644 --- a/core/flamingock-core/build.gradle.kts +++ b/core/flamingock-core/build.gradle.kts @@ -2,7 +2,6 @@ val jacksonVersion = "2.16.0" dependencies { api(project(":core:flamingock-core-commons")) - api(project(":core:importer:flamingock-importer")) api(project(":utils:general-util")) api("javax.inject:javax.inject:1") diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TransactionalTargetSystem.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TransactionalTargetSystem.java index bf554a2fe..daefd8ac4 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TransactionalTargetSystem.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TransactionalTargetSystem.java @@ -124,7 +124,6 @@ public TargetSystemAuditMarker getOnGoingTaskStatusRepository() { * or {@link Optional#empty()} if this target system does not support audit reading for the specified type * @see AuditHistoryReader * @see AuditReaderType - * @see io.flamingock.importer.ImporterAdapter */ public Optional getAuditAuditReader(AuditReaderType type) { return Optional.empty(); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOps.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOps.java index 724e16b17..4c29a857b 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOps.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/operations/TransactionalTargetSystemOps.java @@ -77,7 +77,6 @@ public interface TransactionalTargetSystemOps extends TargetSystemOps, TargetSys * or {@link Optional#empty()} if this target system does not support audit reading for the specified type * @see AuditHistoryReader * @see AuditReaderType - * @see io.flamingock.importer.ImporterAdapter */ Optional getAuditAuditReader(AuditReaderType type); diff --git a/core/flamingock-graalvm/src/main/java/io/flamingock/graalvm/RegistrationFeature.java b/core/flamingock-graalvm/src/main/java/io/flamingock/graalvm/RegistrationFeature.java index a0a3ef719..3f74aa680 100644 --- a/core/flamingock-graalvm/src/main/java/io/flamingock/graalvm/RegistrationFeature.java +++ b/core/flamingock-graalvm/src/main/java/io/flamingock/graalvm/RegistrationFeature.java @@ -17,8 +17,6 @@ import io.flamingock.api.template.AbstractChangeTemplate; import io.flamingock.api.template.ChangeTemplate; -import io.flamingock.importer.ImporterTemplateFactory; -import io.flamingock.importer.mongodb.MongoDBImporterChangeTemplate; import io.flamingock.internal.common.core.metadata.FlamingockMetadata; import io.flamingock.internal.common.core.preview.CodePreviewChange; import io.flamingock.internal.common.core.preview.PreviewMethod; @@ -40,8 +38,8 @@ import io.flamingock.internal.core.task.loaded.TemplateLoadedChange; import io.flamingock.internal.util.log.FlamingockLoggerFactory; import org.graalvm.nativeimage.hosted.Feature; -import org.graalvm.nativeimage.hosted.RuntimeReflection; import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; +import org.graalvm.nativeimage.hosted.RuntimeReflection; import org.slf4j.LoggerFactory; import java.nio.charset.CoderResult; @@ -52,17 +50,6 @@ public class RegistrationFeature implements Feature { private static final Logger logger = new Logger(); - @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { - logger.startProcess("GraalVM classes registration and initialization"); - initializeInternalClassesAtBuildTime(); - initializeExternalClassesAtBuildTime(); - registerInternalClasses(); - registerTemplates(); - registerUserClasses(); - logger.finishedProcess("GraalVM classes registration and initialization"); - } - private static void registerInternalClasses() { logger.startRegistrationProcess("internal classes"); @@ -91,7 +78,6 @@ private static void registerInternalClasses() { //others registerClassForReflection(CoderResult.class.getName()); - registerClassForReflection(ImporterTemplateFactory.class.getName()); logger.completedRegistrationProcess("internal classes"); @@ -103,10 +89,8 @@ private static void initializeInternalClassesAtBuildTime() { initializeClassAtBuildTime(AbstractLoadedChange.class); initializeClassAtBuildTime(TemplateLoadedChange.class); initializeClassAtBuildTime(ChangeTemplateManager.class); - initializeClassAtBuildTime(ImporterTemplateFactory.class); initializeClassAtBuildTime(RecoveryDescriptor.class); initializeClassAtBuildTime(FlamingockLoggerFactory.class); - initializeClassAtBuildTime(MongoDBImporterChangeTemplate.class); logger.completeInitializationProcess("internal classes"); } @@ -116,7 +100,6 @@ private static void initializeExternalClassesAtBuildTime() { logger.completeInitializationProcess("external classes"); } - private static void registerUserClasses() { logger.startRegistrationProcess("user classes"); List classesToRegister = FileUtil.getClassesForRegistration(); @@ -124,19 +107,6 @@ private static void registerUserClasses() { logger.completedRegistrationProcess("user classes"); } - private void registerTemplates() { - logger.startRegistrationProcess("templates"); - registerClassForReflection(ChangeTemplateManager.class); - registerClassForReflection(ChangeTemplate.class); - registerClassForReflection(AbstractChangeTemplate.class); - ChangeTemplateManager.getTemplates().forEach(template -> { - registerClassForReflection(template.getClass()); - template.getReflectiveClasses().forEach(RegistrationFeature::registerClassForReflection); - }); - - logger.completedRegistrationProcess("templates"); - } - private static void registerClassForReflection(String className) { try { registerClassForReflection(Class.forName(className)); @@ -159,5 +129,29 @@ private static void initializeClassAtBuildTime(Class clazz) { RuntimeClassInitialization.initializeAtBuildTime(clazz); } + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + logger.startProcess("GraalVM classes registration and initialization"); + initializeInternalClassesAtBuildTime(); + initializeExternalClassesAtBuildTime(); + registerInternalClasses(); + registerTemplates(); + registerUserClasses(); + logger.finishedProcess("GraalVM classes registration and initialization"); + } + + private void registerTemplates() { + logger.startRegistrationProcess("templates"); + registerClassForReflection(ChangeTemplateManager.class); + registerClassForReflection(ChangeTemplate.class); + registerClassForReflection(AbstractChangeTemplate.class); + ChangeTemplateManager.getTemplates().forEach(template -> { + registerClassForReflection(template.getClass()); + template.getReflectiveClasses().forEach(RegistrationFeature::registerClassForReflection); + }); + + logger.completedRegistrationProcess("templates"); + } + } diff --git a/core/importer/flamingock-importer/README.md b/core/importer/flamingock-importer/README.md deleted file mode 100644 index ff6016ece..000000000 --- a/core/importer/flamingock-importer/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Flamingock importer: Internal notes - - -## Notes - -### Note on Importer ChangeTemplates and GraalVM -While most ChangeTemplates require SPI registration for GraalVM compatibility, Importer ChangeTemplates are an exception. These are loaded manually in the GraalVM feature rather than through SPI. Attempting to register Importer ChangeTemplates via SPI would cause failures, as we selectively load them based on the specific driver the user is importingver the user imports \ No newline at end of file diff --git a/core/importer/flamingock-importer/build.gradle.kts b/core/importer/flamingock-importer/build.gradle.kts deleted file mode 100644 index cb6efac4f..000000000 --- a/core/importer/flamingock-importer/build.gradle.kts +++ /dev/null @@ -1,43 +0,0 @@ - -dependencies { - implementation(project(":core:flamingock-core-commons")) - - compileOnly("org.mongodb:mongodb-driver-sync:4.0.0") - compileOnly("software.amazon.awssdk:dynamodb-enhanced:2.25.29") - compileOnly("com.couchbase.client:java-client:3.6.0") - - - testAnnotationProcessor(project(":core:flamingock-processor")) - testImplementation(project(":community:flamingock-auditstore-mongodb-sync")) - testImplementation(project(":templates:flamingock-mongodb-sync-template")) - testImplementation(project(":community:flamingock-auditstore-dynamodb")) - - testImplementation(project(":utils:test-util")) - testImplementation("org.testcontainers:mongodb:1.18.3") - testImplementation("org.testcontainers:junit-jupiter:1.18.3") - testImplementation("org.mockito:mockito-inline:4.11.0") - testImplementation("org.testcontainers:localstack:1.19.7") - testImplementation("software.amazon.awssdk:dynamodb:2.25.61") - - testImplementation("com.couchbase.client:java-client:3.6.0") -} - -description = "Import tool for migrating from legacy database migration tools like Mongock to Flamingock" - -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(8)) - } -} - -tasks.withType().configureEach { - if (name.contains("Test", ignoreCase = true)) { - options.compilerArgs.addAll(listOf( - "-Asources=${projectDir}/src/test/java", - "-Aresources=${projectDir}/src/test/resources" - )) - } -} -configurations.testImplementation { - extendsFrom(configurations.compileOnly.get()) -} \ No newline at end of file diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/AbstractImportConfiguration.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/AbstractImportConfiguration.java deleted file mode 100644 index 501375f76..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/AbstractImportConfiguration.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer; - -public abstract class AbstractImportConfiguration { - - private boolean failOnEmptyOrigin = true; - - public abstract ORIGIN getOrigin(); - - public abstract void setOrigin(ORIGIN origin); - - public boolean isFailOnEmptyOrigin() { - return failOnEmptyOrigin; - } - - public void setFailOnEmptyOrigin(boolean failOnEmptyOrigin) { - this.failOnEmptyOrigin = failOnEmptyOrigin; - } -} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImportConfiguration.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImportConfiguration.java deleted file mode 100644 index 550beb6ce..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImportConfiguration.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer; - -public class ImportConfiguration extends AbstractImportConfiguration { - - private String origin = "mongockChangeLog"; - - @Override - public String getOrigin() { - return origin; - } - - @Override - public void setOrigin(String origin) { - this.origin = origin; - } -} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterAdapter.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterAdapter.java deleted file mode 100644 index 420bf87d3..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterAdapter.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer; - -import io.flamingock.internal.common.core.audit.AuditHistoryReader; - - -public interface ImporterAdapter extends AuditHistoryReader { - -} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterExecutor.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterExecutor.java deleted file mode 100644 index 01b425054..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterExecutor.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer; - -import io.flamingock.internal.common.core.pipeline.PipelineHelper; -import io.flamingock.internal.common.core.audit.AuditEntry; -import io.flamingock.internal.common.core.audit.AuditWriter; -import io.flamingock.internal.common.core.error.FlamingockException; -import io.flamingock.internal.common.core.pipeline.PipelineDescriptor; - -import java.util.List; - -/** - * This change imports the Mongock data in the database to Flamingock(local or cloud). - * Although we could have just one Change for importing - * - Mongock to Flamingock local - * - Mongock to Flamingock CLoud - * - Flamingock local to Flamingock cloud - * We need to differentiate it, as we can have two steps(Mongock to Flamingock local to Flamingock Cloud) - */ -public final class ImporterExecutor { - - private ImporterExecutor() { - - } - - /** - * Reads from a database (either Mongock or Flamingock local) and writes to Flamingock (either local or cloud). - * The supported migration paths are: - * - Mongock to Flamingock-ce - * - Mongock to Flamingock Cloud - * - Flamingock-ce to Flamingock Cloud - * - * @param importerAdapter Database log reader. - * @param auditWriter Destination writer. - * @param pipelineDescriptor Structure containing all information about the changes and tasks to execute. - */ - public static void runImport(ImporterAdapter importerAdapter, - AbstractImportConfiguration importConfiguration, - AuditWriter auditWriter, - PipelineDescriptor pipelineDescriptor) { - PipelineHelper pipelineHelper = new PipelineHelper(pipelineDescriptor); - List auditEntries = importerAdapter.getAuditHistory(); - if(importConfiguration.isFailOnEmptyOrigin() && auditEntries.isEmpty()) { - throw new FlamingockException( - String.format("No audit entries found when importing from '%s'. " + - "Set 'failOnEmptyOrigin=false' in the import change to disable this validation.", - importConfiguration.getOrigin()) - ); - } - - auditEntries.forEach(auditEntryFromOrigin -> { - //This is the taskId present in the pipeline. If it's a system change or '..._before' won't appear - AuditEntry auditEntryWithStageId = auditEntryFromOrigin.copyWithNewIdAndStageId( - pipelineHelper.getStorableTaskId(auditEntryFromOrigin), - pipelineHelper.getStageId(auditEntryFromOrigin)); - auditWriter.writeEntry(auditEntryWithStageId); - }); - } - - - -} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterTemplateFactory.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterTemplateFactory.java deleted file mode 100644 index 394fe5ad3..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterTemplateFactory.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer; - -import io.flamingock.api.template.ChangeTemplate; -import io.flamingock.internal.common.core.template.ChangeTemplateFactory; -import org.jetbrains.annotations.NotNull; -import io.flamingock.internal.util.log.FlamingockLoggerFactory; -import org.slf4j.Logger; - -import java.lang.reflect.InvocationTargetException; -import java.util.Collection; -import java.util.Collections; -import java.util.Optional; - -public class ImporterTemplateFactory implements ChangeTemplateFactory { - - private static final Logger logger = FlamingockLoggerFactory.getLogger("ImporterFactory"); - - private static final String MONGO_TEMPLATE_CLASS = "io.flamingock.importer.mongodb.MongoDBImporterChangeTemplate"; - private static final String DYNAMO_TEMPLATE_CLASS = "io.flamingock.importer.dynamodb.DynamoDBImporterChangeTemplate"; - private static final String COUCHBASE_TEMPLATE_CLASS = "io.flamingock.importer.couchbase.CouchbaseImporterChangeTemplate"; - - - @Override - public Collection> getTemplates() { - try { - Optional className = getClassName(); - if (className.isPresent()) { - logger.info("Loading importer template: {}", className); - Class changeTemplateClass = Class.forName(className.get()); - return Collections.singletonList( - (ChangeTemplate) changeTemplateClass.getDeclaredConstructor().newInstance() - ); - } else { - return Collections.emptyList(); - } - - - } catch (ClassNotFoundException e) { - throw new RuntimeException("Importer importer template class not found", e); - } catch (Exception e) { - throw new RuntimeException("Failed to instantiate importer class ", e); - } - } - - @NotNull - private static Optional getClassName() { - - if (isMongoDBAdapter()) { - return Optional.of(MONGO_TEMPLATE_CLASS); - } else if (isDynamoDBAdapter()) { - return Optional.of(DYNAMO_TEMPLATE_CLASS); - } else if (isCouchbaseAdapter()) { - return Optional.of(COUCHBASE_TEMPLATE_CLASS); - } else { - logger.debug("No compatible database driver detected. Please include a supported database dependency (MongoDB, DynamoDB, or Couchbase) in your project classpath."); - } - return Optional.empty(); - } - - private static boolean isMongoDBAdapter() { - try { - Class.forName("com.mongodb.client.MongoCollection"); - return true; - } catch (ClassNotFoundException e) { - logger.warn("MongoDB adapter not found, skipping"); - return false; - } - } - - private static boolean isDynamoDBAdapter() { - try { - Class.forName("software.amazon.awssdk.enhanced.dynamodb.DynamoDBTable"); - return true; - } catch (ClassNotFoundException e) { - logger.warn("DynamoDB adapter not found, skipping"); - return false; - } - } - - private static boolean isCouchbaseAdapter() { - try { - Class.forName("com.couchbase.client.java.Cluster"); - return true; - } catch (ClassNotFoundException e) { - logger.warn("Couchbase adapter not found, skipping"); - return false; - } - } - - private static Class loadClass(String className) { - try { - return Class.forName(className); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Importer importer template class not found", e); - } catch (Exception e) { - throw new RuntimeException("Failed to instantiate importer class ", e); - } - } - - @NotNull - private static ChangeTemplate getInstance(Class changeTemplateClass) { - try { - return (ChangeTemplate) changeTemplateClass.getDeclaredConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | - NoSuchMethodException e) { - throw new RuntimeException("Failed to instantiate importer class ", e); - } - } -} - diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java deleted file mode 100644 index abc68f725..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.couchbase; - -import com.couchbase.client.java.json.JsonObject; -import io.flamingock.importer.mongodb.MongockChangeState; -import io.flamingock.internal.common.core.audit.AuditEntry; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; - -public class CouchbaseChangeEntry { - private String executionId; - private String changeId; - private String author; - private String timestamp; - private String state; - private String type; - private String changeLogClass; - private String changeSetMethod; - private String metadata; - private Long executionMillis; - private String executionHostName; - private String errorTrace; - private Boolean systemChange; - - public String getExecutionId() { - return executionId; - } - - public void setExecutionId(String executionId) { - this.executionId = executionId; - } - - public static CouchbaseChangeEntry fromJson(JsonObject doc) { - CouchbaseChangeEntry entry = new CouchbaseChangeEntry(); - entry.executionId = doc.getString("executionId"); - entry.changeId = doc.getString("changeId"); - entry.author = doc.getString("author"); - entry.timestamp = doc.getString("timestamp"); - entry.state = doc.getString("state"); - entry.type = doc.getString("type"); - entry.changeLogClass = doc.getString("changeLogClass"); - entry.changeSetMethod = doc.getString("changeSetMethod"); - entry.metadata = doc.getString("metadata"); - entry.executionMillis = parseLong(doc.get("executionMillis")); - entry.executionHostName = doc.getString("executionHostName"); - entry.errorTrace = doc.getString("errorTrace"); - entry.systemChange = doc.getBoolean("systemChange"); - return entry; - } - - private static Long parseLong(Object value) { - if (value == null) return null; - if (value instanceof Number) return ((Number) value).longValue(); - if (value instanceof String) return Long.parseLong((String) value); - throw new IllegalArgumentException("Cannot convert value to Long: " + value); - } - - public AuditEntry toAuditEntry() { - long epochMillis; - try { - epochMillis = Long.parseLong(timestamp); - } catch (NumberFormatException e) { - String ts = timestamp; - if (ts.matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}")) { - ts = ts + "Z"; - } - epochMillis = Instant.parse(ts).toEpochMilli(); - } - LocalDateTime ts = LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()); - - MongockChangeState stateEnum = MongockChangeState.valueOf(state); - return new AuditEntry( - executionId, - null, - changeId, - author, - ts, - stateEnum.toAuditStatus(), - AuditEntry.ExecutionType.valueOf(type), - changeLogClass, - changeSetMethod, - executionMillis, - executionHostName, - metadata, - systemChange != null && systemChange, - errorTrace - ); - } -} \ No newline at end of file diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImportConfiguration.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImportConfiguration.java deleted file mode 100644 index 36a117ae4..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImportConfiguration.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.couchbase; - -import io.flamingock.importer.AbstractImportConfiguration; - -public class CouchbaseImportConfiguration extends AbstractImportConfiguration { - - private CouchbaseOrigin origin = new CouchbaseOrigin(); - - public CouchbaseOrigin getOrigin() { - return origin; - } - - public void setOrigin(CouchbaseOrigin origin) { - this.origin = origin; - } -} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java deleted file mode 100644 index 180728c61..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.couchbase; - -import com.couchbase.client.java.Cluster; -import com.couchbase.client.java.json.JsonObject; -import com.couchbase.client.java.query.QueryOptions; -import com.couchbase.client.java.query.QueryResult; -import com.couchbase.client.java.query.QueryScanConsistency; -import io.flamingock.importer.ImporterAdapter; -import io.flamingock.internal.common.core.audit.AuditEntry; - -import java.util.List; -import java.util.stream.Collectors; - -public class CouchbaseImporterAdapter implements ImporterAdapter { - - private static final String MONGOCK_CHANGE_ENTRY_DOCTYPE = "mongockChangeEntry"; - - private final Cluster cluster; - private final String bucketName; - private final String scopeName; - private final String collectionName; - - public CouchbaseImporterAdapter(Cluster cluster, String bucketName, String scopeName, String collectionName) { - this.cluster = cluster; - this.bucketName = bucketName; - this.scopeName = scopeName; - this.collectionName = collectionName; - } - - @Override - public List getAuditHistory() { - QueryResult result = cluster.query( - String.format( - "SELECT `%s`.* FROM `%s`.`%s`.`%s` WHERE `_doctype` = $p1", - collectionName, bucketName, scopeName, collectionName - ), - QueryOptions.queryOptions() - .scanConsistency(QueryScanConsistency.REQUEST_PLUS) - .parameters(JsonObject.create().put("p1", MONGOCK_CHANGE_ENTRY_DOCTYPE)) - ); - - return result.rowsAsObject().stream() - .map(CouchbaseChangeEntry::fromJson) - .map(CouchbaseChangeEntry::toAuditEntry) - .collect(Collectors.toList()); - } -} \ No newline at end of file diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterChangeTemplate.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterChangeTemplate.java deleted file mode 100644 index 487299681..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterChangeTemplate.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.couchbase; - -import com.couchbase.client.java.Bucket; -import com.couchbase.client.java.Cluster; -import io.flamingock.api.annotations.Apply; -import io.flamingock.api.annotations.NonLockGuarded; -import io.flamingock.api.annotations.Rollback; -import io.flamingock.importer.AbstractImporterChangeTemplate; -import io.flamingock.importer.ImporterExecutor; -import io.flamingock.internal.common.core.audit.AuditWriter; -import io.flamingock.internal.common.core.error.FlamingockException; -import io.flamingock.internal.common.core.pipeline.PipelineDescriptor; -import io.flamingock.internal.util.StringUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CouchbaseImporterChangeTemplate extends AbstractImporterChangeTemplate { - private static final Logger logger = LoggerFactory.getLogger("CouchbaseImporterChangeTemplate"); - - public CouchbaseImporterChangeTemplate() { - super(CouchbaseImportConfiguration.class); - } - - @Apply - public void apply(Cluster cluster, - Bucket bucket, //TODO this is the main bucket, we need to provide a way to get a custom bucket (target system) - @NonLockGuarded AuditWriter auditWriter, - @NonLockGuarded PipelineDescriptor pipelineDescriptor) { - logger.info("Starting audit log migration from Mongock to Flamingock local audit store[Couchbase]"); - this.validateConfiguration(); - CouchbaseImporterAdapter adapter = new CouchbaseImporterAdapter(cluster, bucket.name(), configuration.getOrigin().getScopeName(), configuration.getOrigin().getCollectionName()); - ImporterExecutor.runImport(adapter, configuration, auditWriter, pipelineDescriptor); - logger.info("Finished audit log migration from Mongock to Flamingock local audit store[Couchbase]"); - } - - @Rollback - public void rollback() { - // TODO: Implement rollback logic if needed - } - - private void validateConfiguration() { - if (this.configuration.getOrigin() == null - || StringUtil.isEmpty(this.configuration.getOrigin().getScopeName()) - || StringUtil.isEmpty(this.configuration.getOrigin().getCollectionName())) { - throw new FlamingockException("No valid origin found in the configuration. Please ensure that both ‘scopeName’ and ‘collectionName’ are set."); - } - } -} \ No newline at end of file diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseOrigin.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseOrigin.java deleted file mode 100644 index e2e21414a..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseOrigin.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.couchbase; - -public class CouchbaseOrigin { - - private String scopeName; - private String collectionName; - - public CouchbaseOrigin() { - this.scopeName = null; - this.collectionName = null; - } - - public String getCollectionName() { - return collectionName; - } - - public void setCollectionName(String collectionName) { - this.collectionName = collectionName; - } - - public String getScopeName() { - return scopeName; - } - - public void setScopeName(String scopeName) { - this.scopeName = scopeName; - } -} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java deleted file mode 100644 index 3c7fb2c29..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.dynamodb; - -import io.flamingock.importer.ImporterAdapter; -import io.flamingock.internal.common.core.audit.AuditEntry; -import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; -import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; -import software.amazon.awssdk.enhanced.dynamodb.TableSchema; -import software.amazon.awssdk.services.dynamodb.DynamoDbClient; - -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -public class DynamoDBImporterAdapter implements ImporterAdapter { - - private final DynamoDbTable sourceTable; - - public DynamoDBImporterAdapter(DynamoDbClient client, String tableName) { - DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() - .dynamoDbClient(client) - .build(); - this.sourceTable = enhancedClient.table(tableName, TableSchema.fromBean(MongockDynamoDBAuditEntry.class)); - } - - @Override - public List getAuditHistory() { - List entries = StreamSupport - .stream(sourceTable.scan().items().spliterator(), false) - .collect(Collectors.toList()); - - return entries.stream() - .map(MongockDynamoDBAuditEntry::toAuditEntry) - .collect(Collectors.toList()); - } -} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterChangeTemplate.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterChangeTemplate.java deleted file mode 100644 index 386fd43aa..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterChangeTemplate.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.dynamodb; - -import io.flamingock.api.annotations.Apply; -import io.flamingock.api.annotations.NonLockGuarded; -import io.flamingock.api.annotations.Rollback; -import io.flamingock.importer.AbstractImporterChangeTemplate; -import io.flamingock.importer.ImportConfiguration; -import io.flamingock.importer.ImporterExecutor; -import io.flamingock.internal.common.core.audit.AuditWriter; -import io.flamingock.internal.common.core.pipeline.PipelineDescriptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import software.amazon.awssdk.services.dynamodb.DynamoDbClient; - -public class DynamoDBImporterChangeTemplate extends AbstractImporterChangeTemplate { - private static final Logger logger = LoggerFactory.getLogger("DynamoDBImporterChangeTemplate"); - - public DynamoDBImporterChangeTemplate() { - super(ImportConfiguration.class); - } - - @Apply - public void apply(DynamoDbClient client, - @NonLockGuarded AuditWriter auditWriter, - @NonLockGuarded PipelineDescriptor pipelineDescriptor) { - logger.info("Starting audit log migration from Mongock to Flamingock local audit store[MongoDB]"); - DynamoDBImporterAdapter adapter = new DynamoDBImporterAdapter(client, configuration.getOrigin()); - ImporterExecutor.runImport(adapter, configuration, auditWriter, pipelineDescriptor); - logger.info("Finished audit log migration from Mongock to Flamingock local audit store[Couchbase]"); - } - - @Rollback - public void rollback() { - //TODO - } -} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java deleted file mode 100644 index 093ffca6a..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.mongodb; - -import com.mongodb.client.MongoCollection; -import com.mongodb.client.MongoDatabase; -import io.flamingock.importer.ImporterAdapter; -import io.flamingock.internal.common.core.audit.AuditEntry; -import org.bson.Document; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.stream.Collectors; - -//TODO implement reading from Flamingock -public class MongoDBImporterAdapter implements ImporterAdapter { - - private final MongoCollection sourceCollection; - - public MongoDBImporterAdapter(MongoDatabase mongoDatabase, String collectionName) { - this.sourceCollection = mongoDatabase.getCollection(collectionName); - } - - @Override - public List getAuditHistory() { - return sourceCollection.find() - .into(new ArrayList<>()) - .stream() - .map(MongoDBImporterAdapter::toAuditEntry) - .collect(Collectors.toList()); - } - - - private static AuditEntry toAuditEntry(Document document) { - MongockChangeEntry changeEntry = toChangeEntry(document); - LocalDateTime timestamp = Instant.ofEpochMilli(changeEntry.getTimestamp().getTime()) - .atZone(ZoneId.systemDefault()) - .toLocalDateTime(); - - if (changeEntry.getState() == MongockChangeState.IGNORED) { - return null; - } - return new AuditEntry( - changeEntry.getExecutionId(), - null, - changeEntry.getChangeId(), - changeEntry.getAuthor(), - timestamp, - changeEntry.getState().toAuditStatus(), - changeEntry.getType().toAuditType(), - changeEntry.getChangeLogClass(), - changeEntry.getChangeSetMethod(), - changeEntry.getExecutionMillis(), - changeEntry.getExecutionHostname(), - changeEntry.getMetadata(), - changeEntry.getSystemChange(), - changeEntry.getErrorTrace() - ); - } - - private static MongockChangeEntry toChangeEntry(Document document) { - Date timestamp = document.getDate("timestamp"); - return new MongockChangeEntry( - document.getString("executionId"), - document.getString("changeId"), - document.getString("author"), - timestamp, - MongockChangeState.valueOf(document.getString("state")), - MongockChangeType.valueOf(document.getString("type")), - document.getString("changeLogClass"), - document.getString("changeSetMethod"), - document.get("metadata"), - document.getLong("executionMillis"), - document.getString("executionHostName"), - document.getString("errorTrace"), - document.getBoolean("systemChange"), - timestamp - ); - } -} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterChangeTemplate.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterChangeTemplate.java deleted file mode 100644 index 57837bce0..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterChangeTemplate.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.mongodb; - -import com.mongodb.client.MongoDatabase; -import io.flamingock.api.annotations.Apply; -import io.flamingock.api.annotations.NonLockGuarded; -import io.flamingock.api.annotations.Rollback; -import io.flamingock.importer.AbstractImporterChangeTemplate; -import io.flamingock.importer.ImportConfiguration; -import io.flamingock.importer.ImporterExecutor; -import io.flamingock.internal.common.core.audit.AuditWriter; -import io.flamingock.internal.common.core.pipeline.PipelineDescriptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MongoDBImporterChangeTemplate extends AbstractImporterChangeTemplate { - - private static final Logger logger = LoggerFactory.getLogger("MongoDBImporterChangeTemplate"); - - public MongoDBImporterChangeTemplate() { - super(ImportConfiguration.class); - } - - @Apply - public void apply(MongoDatabase db, - @NonLockGuarded AuditWriter auditWriter, - @NonLockGuarded PipelineDescriptor pipelineDescriptor) { - logger.info("Starting audit log migration from Mongock to Flamingock local audit store[MongoDB]"); - MongoDBImporterAdapter adapter = new MongoDBImporterAdapter(db, configuration.getOrigin()); - ImporterExecutor.runImport(adapter, configuration, auditWriter, pipelineDescriptor); - logger.info("Finished audit log migration from Mongock to Flamingock local audit store[MongoDB]"); - } - - @Rollback - public void rollback() { - //TODO - } - -} diff --git a/core/importer/flamingock-importer/src/main/resources/META-INF/services/io.flamingock.internal.common.core.template.ChangeTemplateFactory b/core/importer/flamingock-importer/src/main/resources/META-INF/services/io.flamingock.internal.common.core.template.ChangeTemplateFactory deleted file mode 100644 index e781059d5..000000000 --- a/core/importer/flamingock-importer/src/main/resources/META-INF/services/io.flamingock.internal.common.core.template.ChangeTemplateFactory +++ /dev/null @@ -1 +0,0 @@ -io.flamingock.importer.ImporterTemplateFactory \ No newline at end of file diff --git a/core/importer/flamingock-importer/src/test/java/io/flamingock/importer/ImporterExecutorTest.java b/core/importer/flamingock-importer/src/test/java/io/flamingock/importer/ImporterExecutorTest.java deleted file mode 100644 index 63a7e90dc..000000000 --- a/core/importer/flamingock-importer/src/test/java/io/flamingock/importer/ImporterExecutorTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer; - -import io.flamingock.internal.common.core.audit.AuditWriter; -import io.flamingock.internal.common.core.error.FlamingockException; -import io.flamingock.internal.common.core.pipeline.PipelineDescriptor; -import org.junit.jupiter.api.Test; - -import java.util.Collections; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class ImporterExecutorTest { - - @Test - void SHOULD_throwFlamingockException_WHEN_auditEntriesEmpty_IF_defaultImportConfiguration() { - // Given - ImporterAdapter importerAdapter = mock(ImporterAdapter.class); - ImportConfiguration importConfiguration = new ImportConfiguration(); - AuditWriter auditWriter = mock(AuditWriter.class); - PipelineDescriptor pipelineDescriptor = mock(PipelineDescriptor.class); - - when(importerAdapter.getAuditHistory()).thenReturn(Collections.emptyList()); - - // When & Then - FlamingockException exception = assertThrows(FlamingockException.class, - () -> ImporterExecutor.runImport(importerAdapter, importConfiguration, auditWriter, pipelineDescriptor)); - - assertTrue(exception.getMessage().contains("No audit entries found when importing from 'mongockChangeLog'")); - assertTrue(exception.getMessage().contains("Set 'failOnEmptyOrigin=false'")); - } - - @Test - void SHOULD_notThrowException_WHEN_auditEntriesEmpty_IF_failOnEmptyOriginFalse() { - // Given - ImporterAdapter importerAdapter = mock(ImporterAdapter.class); - ImportConfiguration importConfiguration = new ImportConfiguration(); - importConfiguration.setFailOnEmptyOrigin(false); - AuditWriter auditWriter = mock(AuditWriter.class); - PipelineDescriptor pipelineDescriptor = mock(PipelineDescriptor.class); - - when(importerAdapter.getAuditHistory()).thenReturn(Collections.emptyList()); - - // When & Then - assertDoesNotThrow(() -> ImporterExecutor.runImport(importerAdapter, importConfiguration, auditWriter, pipelineDescriptor)); - } -} diff --git a/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java index 129aa7127..f065121e4 100644 --- a/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java +++ b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java @@ -15,7 +15,6 @@ */ package io.flamingock.importer.mongock.dynamodb; -import io.flamingock.importer.mongodb.MongockChangeState; import io.flamingock.internal.common.core.audit.AuditEntry; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/AbstractImporterChangeTemplate.java b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockChangeState.java similarity index 52% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/AbstractImporterChangeTemplate.java rename to legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockChangeState.java index b17735135..712f527a8 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/AbstractImporterChangeTemplate.java +++ b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockChangeState.java @@ -1,3 +1,5 @@ +package io.flamingock.importer.mongock.dynamodb; + /* * Copyright 2023 Flamingock (https://www.flamingock.io) * @@ -13,18 +15,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer; - -import io.flamingock.api.annotations.Categories; -import io.flamingock.api.task.ChangeCategory; -import io.flamingock.api.template.AbstractChangeTemplate; +import io.flamingock.internal.common.core.audit.AuditEntry; -@Categories(ChangeCategory.IMPORT) -public abstract class AbstractImporterChangeTemplate> extends AbstractChangeTemplate { +public enum MongockChangeState { + EXECUTED, FAILED, ROLLED_BACK, ROLLBACK_FAILED, IGNORED; - public AbstractImporterChangeTemplate(Class configurationClass) { - super(configurationClass); + public AuditEntry.Status toAuditStatus() { + switch (this) { + case FAILED: return AuditEntry.Status.FAILED; + case ROLLED_BACK: return AuditEntry.Status.ROLLED_BACK; + case ROLLBACK_FAILED: return AuditEntry.Status.ROLLBACK_FAILED; + case EXECUTED: + default: return AuditEntry.Status.APPLIED; + } } } diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBMongockTestHelper.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBMongockTestHelper.java index b2c16780a..ebeec80ef 100644 --- a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBMongockTestHelper.java +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBMongockTestHelper.java @@ -15,9 +15,8 @@ */ package io.flamingock.importer.mongock.dynamodb; +import io.flamingock.common.test.mongock.MongockChangeEntry; import io.flamingock.common.test.mongock.MongockTestHelper; -import io.flamingock.importer.dynamodb.MongockDynamoDBAuditEntry; -import io.flamingock.importer.mongodb.MongockChangeEntry; import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; import software.amazon.awssdk.enhanced.dynamodb.TableSchema; diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/MongockDynamoDBAuditEntry.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/MongockDynamoDBAuditEntry.java similarity index 98% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/MongockDynamoDBAuditEntry.java rename to legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/MongockDynamoDBAuditEntry.java index f02374dc6..dbc39dd1c 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/MongockDynamoDBAuditEntry.java +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/MongockDynamoDBAuditEntry.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.dynamodb; +package io.flamingock.importer.mongock.dynamodb; -import io.flamingock.importer.mongodb.MongockChangeState; +import io.flamingock.importer.mongock.dynamodb.MongockChangeState; import io.flamingock.internal.common.core.audit.AuditEntry; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBAuditEntryEntity.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBAuditEntryEntity.java deleted file mode 100644 index 45ba01d50..000000000 --- a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBAuditEntryEntity.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2023 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.mongock.dynamodb.changes; - -import io.flamingock.api.RecoveryStrategy; -import io.flamingock.internal.common.core.audit.AuditEntry; -import io.flamingock.internal.common.core.audit.AuditTxType; -import io.flamingock.internal.util.constants.AuditEntryFieldConstants; -import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute; -import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; -import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; - -import java.time.LocalDateTime; -import java.util.Objects; - -@DynamoDbBean -public class DynamoDBAuditEntryEntity implements Comparable { - - protected Boolean systemChange; - private String partitionKey; - private String taskId; - private String stageId; - private String executionId; - private String author; - private LocalDateTime createdAt; - private AuditEntry.Status state; - private String className; - private String methodName; - private Object metadata; - private Long executionMillis; - private String executionHostname; - private Object errorTrace; - private AuditEntry.ExecutionType type; - private AuditTxType txStrategy; - private String targetSystemId; - private String order; - private String recoveryStrategy; - private Boolean transactionFlag; - - public static DynamoDBAuditEntryEntity fromAuditEntry(AuditEntry auditEntry) { - return new DynamoDBAuditEntryEntity(auditEntry); - } - - public DynamoDBAuditEntryEntity(AuditEntry auditEntry) { - this.partitionKey = partitionKey(auditEntry.getExecutionId(), auditEntry.getTaskId(), auditEntry.getState()); - this.taskId = auditEntry.getTaskId(); - this.stageId = auditEntry.getStageId(); - this.executionId = auditEntry.getExecutionId(); - this.author = auditEntry.getAuthor(); - this.createdAt = auditEntry.getCreatedAt(); - this.state = auditEntry.getState(); - this.className = auditEntry.getClassName(); - this.methodName = auditEntry.getMethodName(); - this.metadata = auditEntry.getMetadata(); - this.executionMillis = auditEntry.getExecutionMillis(); - this.executionHostname = auditEntry.getExecutionHostname(); - this.errorTrace = auditEntry.getErrorTrace(); - this.type = auditEntry.getType(); - this.txStrategy = auditEntry.getTxType(); - this.targetSystemId = auditEntry.getTargetSystemId(); - this.order = auditEntry.getOrder(); - this.systemChange = auditEntry.getSystemChange(); - this.recoveryStrategy = auditEntry.getRecoveryStrategy().name(); - this.transactionFlag = auditEntry.getTransactionFlag(); - } - - public DynamoDBAuditEntryEntity() {} - - public static String partitionKey(String executionId, String taskId, AuditEntry.Status state) { - return executionId + '#' + taskId + '#' + state.name(); - } - - @DynamoDbPartitionKey - @DynamoDbAttribute(DynamoDBConstants.AUDIT_LOG_PK) - public String getPartitionKey() { - return partitionKey; - } - - public void setPartitionKey(String partitionKey) { - this.partitionKey = partitionKey; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_CHANGE_ID) - public String getTaskId() { - return taskId; - } - - public void setTaskId(String taskId) { - this.taskId = taskId; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_STAGE_ID) - public String getStageId() { - return stageId; - } - - public void setStageId(String stageId) { - this.stageId = stageId; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_EXECUTION_ID) - public String getExecutionId() { - return executionId; - } - - public void setExecutionId(String executionId) { - this.executionId = executionId; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_AUTHOR) - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TIMESTAMP) - public LocalDateTime getCreatedAt() { - return createdAt; - } - - public void setCreatedAt(LocalDateTime createdAt) { - this.createdAt = createdAt; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_STATE) - public String getState() { - return state.name(); - } - - public void setState(String state) { - this.state = AuditEntry.Status.valueOf(state); - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_CHANGE_CLASS) - public String getClassName() { - return className; - } - - public void setClassName(String className) { - this.className = className; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_INVOKED_METHOD) - public String getMethodName() { - return methodName; - } - - public void setMethodName(String methodName) { - this.methodName = methodName; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_METADATA) - public String getMetadata() { - return metadata.toString(); - } - - public void setMetadata(Object metadata) { - this.metadata = metadata; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_EXECUTION_MILLIS) - public Long getExecutionMillis() { - return executionMillis; - } - - public void setExecutionMillis(Long executionMillis) { - this.executionMillis = executionMillis; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_EXECUTION_HOSTNAME) - public String getExecutionHostname() { - return executionHostname; - } - - public void setExecutionHostname(String executionHostname) { - this.executionHostname = executionHostname; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_ERROR_TRACE) - public String getErrorTrace() { - return errorTrace.toString(); - } - - public void setErrorTrace(Object errorTrace) { - this.errorTrace = errorTrace; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TYPE) - public String getType() { - return type.name(); - } - - public void setType(String type) { - this.type = AuditEntry.ExecutionType.valueOf(type); - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_SYSTEM_CHANGE) - public Boolean getSystemChange() { - return systemChange; - } - - public void setSystemChange(Boolean systemChange) { - this.systemChange = systemChange; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TX_STRATEGY) - public String getTxType() { - return AuditTxType.safeString(txStrategy); - } - - public void setTxType(String txStrategy) { - this.txStrategy = AuditTxType.fromString(txStrategy); - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TARGET_SYSTEM_ID) - public String getTargetSystemId() { - return targetSystemId; - } - - public void setTargetSystemId(String targetSystemId) { - this.targetSystemId = targetSystemId; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_ORDER) - public String getOrder() { - return order; - } - - public void setOrder(String order) { - this.order = order; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_RECOVERY_STRATEGY) - public String getRecoveryStrategy() { - return recoveryStrategy; - } - - public void setRecoveryStrategy(String recoveryStrategy) { - this.recoveryStrategy = recoveryStrategy; - } - - @DynamoDbAttribute(AuditEntryFieldConstants.KEY_TRANSACTION_FLAG) - public Boolean getTransactionFlag() { - return transactionFlag; - } - - public void setTransactionFlag(Boolean transactionFlag) { - this.transactionFlag = transactionFlag; - } - - @Override - public int compareTo(DynamoDBAuditEntryEntity other) { - if (other == null) { - return 1; - } - int timeComparison = this.createdAt.compareTo(other.createdAt); - if (timeComparison != 0) { - return timeComparison; - } - if (this.order != null && other.order != null) { - int orderComparison = this.order.compareTo(other.order); - if (orderComparison != 0) { - return orderComparison; - } - } - return Integer.compare(this.state.getPriority(), other.state.getPriority()); - } - - public AuditEntry toAuditEntry() { - return new AuditEntry( - executionId, - stageId, - taskId, - author, - createdAt, - state, - type, - className, - methodName, - executionMillis, - executionHostname, - metadata, - systemChange, - Objects.toString(errorTrace, ""), - txStrategy, - targetSystemId, - order, - recoveryStrategy != null ? RecoveryStrategy.valueOf(recoveryStrategy) : RecoveryStrategy.MANUAL_INTERVENTION, - transactionFlag - ); - } -} \ No newline at end of file diff --git a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBConstants.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBConstants.java deleted file mode 100644 index 997b78d06..000000000 --- a/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/DynamoDBConstants.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2025 Flamingock (https://www.flamingock.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.flamingock.importer.mongock.dynamodb.changes; - -public final class DynamoDBConstants { - - public static final String AUDIT_LOG_PK = "partitionKey"; - - public static final String LOCK_PK = "partitionKey"; - public static final String LOCK_OWNER = "lockOwner"; - - private DynamoDBConstants() { - } -} diff --git a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java index d08746de8..a096ed2e0 100644 --- a/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java @@ -16,8 +16,8 @@ package io.flamingock.importer.mongock.mongodb; import com.mongodb.client.MongoCollection; +import io.flamingock.common.test.mongock.MongockChangeEntry; import io.flamingock.common.test.mongock.MongockTestHelper; -import io.flamingock.importer.mongodb.MongockChangeEntry; import org.bson.Document; import java.util.ArrayList; diff --git a/settings.gradle.kts b/settings.gradle.kts index 46d72f3a1..d9d8312d7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -152,14 +152,6 @@ include("utils:sql-util") project(":utils:sql-util").name = "sql-util" project(":utils:sql-util").projectDir = file("utils/sql-util") -////////////////////////////////////// -// IMPORTER -////////////////////////////////////// -include("core:importer:flamingock-importer") -project(":core:importer:flamingock-importer").name = "flamingock-importer" -project(":core:importer:flamingock-importer").projectDir = file("core/importer/flamingock-importer") - - ////////////////////////////////////// // LEGACY ////////////////////////////////////// diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeEntry.java b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeEntry.java similarity index 99% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeEntry.java rename to utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeEntry.java index 7072f7f0a..c2dd14265 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeEntry.java +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeEntry.java @@ -1,3 +1,5 @@ +package io.flamingock.common.test.mongock; + /* * Copyright 2023 Flamingock (https://www.flamingock.io) * @@ -13,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongodb; import java.util.Date; diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeState.java b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeState.java similarity index 60% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeState.java rename to utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeState.java index b7a9cc5c6..efa0cb9cc 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeState.java +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeState.java @@ -1,3 +1,5 @@ +package io.flamingock.common.test.mongock; + /* * Copyright 2023 Flamingock (https://www.flamingock.io) * @@ -13,21 +15,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongodb; import io.flamingock.internal.common.core.audit.AuditEntry; public enum MongockChangeState { - EXECUTED, FAILED, ROLLED_BACK, ROLLBACK_FAILED, IGNORED; + EXECUTED, FAILED, ROLLED_BACK, ROLLBACK_FAILED, IGNORED; - public AuditEntry.Status toAuditStatus() { - switch (this) { - case FAILED: return AuditEntry.Status.FAILED; - case ROLLED_BACK: return AuditEntry.Status.ROLLED_BACK; - case ROLLBACK_FAILED: return AuditEntry.Status.ROLLBACK_FAILED; - case EXECUTED: - default: return AuditEntry.Status.APPLIED; + public AuditEntry.Status toAuditStatus() { + switch (this) { + case FAILED: return AuditEntry.Status.FAILED; + case ROLLED_BACK: return AuditEntry.Status.ROLLED_BACK; + case ROLLBACK_FAILED: return AuditEntry.Status.ROLLBACK_FAILED; + case EXECUTED: + default: return AuditEntry.Status.APPLIED; + } } - } } diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeType.java b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeType.java similarity index 77% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeType.java rename to utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeType.java index 3d5f5a03b..529694afc 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongockChangeType.java +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeType.java @@ -1,3 +1,5 @@ +package io.flamingock.common.test.mongock; + /* * Copyright 2023 Flamingock (https://www.flamingock.io) * @@ -13,15 +15,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongodb; - import io.flamingock.internal.common.core.audit.AuditEntry; public enum MongockChangeType { - EXECUTION, BEFORE_EXECUTION; + EXECUTION, BEFORE_EXECUTION; - public AuditEntry.ExecutionType toAuditType() { - //TODO: remove - return AuditEntry.ExecutionType.EXECUTION; - } + public AuditEntry.ExecutionType toAuditType() { + //TODO: remove + return AuditEntry.ExecutionType.EXECUTION; + } } diff --git a/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockTestHelper.java b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockTestHelper.java index f2312909a..79d16c86c 100644 --- a/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockTestHelper.java +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockTestHelper.java @@ -15,9 +15,7 @@ */ package io.flamingock.common.test.mongock; -import io.flamingock.importer.mongodb.MongockChangeEntry; -import io.flamingock.importer.mongodb.MongockChangeState; -import io.flamingock.importer.mongodb.MongockChangeType; + import java.text.ParseException; import java.text.SimpleDateFormat; From 5078b99bf5f1613ebe113aa4fdea48257e4bb424 Mon Sep 17 00:00:00 2001 From: Antonio Perez Dieppa Date: Tue, 25 Nov 2025 08:10:27 +0000 Subject: [PATCH 08/10] refactor: fix compilation error --- .../processor/FlamingockAnnotationProcessor.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) 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 4bb5ac667..1530ef804 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 @@ -209,14 +209,15 @@ public boolean process(Set annotations, RoundEnvironment List legacyChanges = allChanges.stream().filter(CodePreviewChange::isLegacy).collect(Collectors.toList()); List standardChanges = allChanges.stream().filter(TaskDescriptor::isStandard).collect(Collectors.toList()); + Map> standardChangesMapByPackage = getCodeChangesMapByPackage(standardChanges); PreviewPipeline pipeline = getPipelineFromProcessChanges( systemChanges, legacyChanges, - getCodeChangesMapByPackage(standardChanges), + standardChangesMapByPackage, flamingockAnnotation ); - validateAllChangesAreMappedToStages(legacyChanges, noLegacyChangesByPackage, pipeline, flamingockAnnotation.strictStageMapping()); + validateAllChangesAreMappedToStages(standardChangesMapByPackage, pipeline, flamingockAnnotation.strictStageMapping()); Serializer serializer = new Serializer(processingEnv, logger); String setup = flamingockAnnotation.setup().toString(); @@ -681,16 +682,14 @@ private void validateConfiguration(EnableFlamingock pipelineAnnotation, boolean * It checks package names from the changes map against the pipeline stages' sourcesPackage * (including the SYSTEM stage). If any stage does not represent any package, a RuntimeException is thrown. * - * @param legacyCodedChanges legacy code changes (kept for completeness; not used for package mapping) - * @param noLegacyCodedChangesByPackage non-legacy changes grouped by source package + * @param standardChanges non-legacy changes grouped by source package * @param pipeline built preview pipeline * @param strictStageMapping if true, unmapped changes will throw an exception; if false, will log a warning */ - private void validateAllChangesAreMappedToStages(List legacyCodedChanges, - Map> noLegacyCodedChangesByPackage, + private void validateAllChangesAreMappedToStages(Map> standardChanges, PreviewPipeline pipeline, Boolean strictStageMapping) { - if (noLegacyCodedChangesByPackage == null || noLegacyCodedChangesByPackage.isEmpty()) { + if (standardChanges == null || standardChanges.isEmpty()) { return; } @@ -702,7 +701,7 @@ private void validateAllChangesAreMappedToStages(List legacyC List unmapped = new ArrayList<>(); - for (String pkg : noLegacyCodedChangesByPackage.keySet()) { + for (String pkg : standardChanges.keySet()) { if (pkg == null) { continue; } From e5bfda9a6cbc2cb4a94d1af8d98c0e6010d8fdd4 Mon Sep 17 00:00:00 2001 From: Antonio Perez Dieppa Date: Tue, 25 Nov 2025 08:18:43 +0000 Subject: [PATCH 09/10] chore: licence header --- .../mongock/dynamodb/MongockChangeState.java | 15 +++++++++++++++ .../common/test/mongock/MongockChangeEntry.java | 15 +++++++++++++++ .../common/test/mongock/MongockChangeState.java | 15 +++++++++++++++ .../common/test/mongock/MongockChangeType.java | 15 +++++++++++++++ 4 files changed, 60 insertions(+) diff --git a/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockChangeState.java b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockChangeState.java index 712f527a8..4323042cd 100644 --- a/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockChangeState.java +++ b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockChangeState.java @@ -1,3 +1,18 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.flamingock.importer.mongock.dynamodb; /* diff --git a/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeEntry.java b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeEntry.java index c2dd14265..20e81c3d9 100644 --- a/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeEntry.java +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeEntry.java @@ -1,3 +1,18 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.flamingock.common.test.mongock; /* diff --git a/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeState.java b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeState.java index efa0cb9cc..6ea69e016 100644 --- a/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeState.java +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeState.java @@ -1,3 +1,18 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.flamingock.common.test.mongock; /* diff --git a/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeType.java b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeType.java index 529694afc..a010b46e3 100644 --- a/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeType.java +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeType.java @@ -1,3 +1,18 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.flamingock.common.test.mongock; /* From fedfea2c61b023ffe47b249089c4b09ec8150772 Mon Sep 17 00:00:00 2001 From: Antonio Perez Dieppa Date: Tue, 25 Nov 2025 08:50:37 +0000 Subject: [PATCH 10/10] chore: fix test --- .../flamingock/core/processor/PipelinePreProcessorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java b/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java index 716f9bee3..b638d0928 100644 --- a/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java +++ b/core/flamingock-processor/src/test/java/io/flamingock/core/processor/PipelinePreProcessorTest.java @@ -309,11 +309,11 @@ void shouldThrowErrorForUnmappedChanges() throws Exception { // Invoke private validator by reflection and assert it throws (InvocationTargetException wraps the RuntimeException) Method validator = FlamingockAnnotationProcessor.class.getDeclaredMethod( - "validateAllChangesAreMappedToStages", List.class, Map.class, PreviewPipeline.class, Boolean.class); + "validateAllChangesAreMappedToStages", Map.class, PreviewPipeline.class, Boolean.class); validator.setAccessible(true); InvocationTargetException ex = assertThrows(InvocationTargetException.class, () -> - validator.invoke(processor, Collections.emptyList(), changesByPackage, pipeline, true)); + validator.invoke(processor, changesByPackage, pipeline, true)); Throwable cause = ex.getCause(); assertNotNull(cause, "Validator should throw a RuntimeException cause");