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-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/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/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..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,10 +124,10 @@ 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 e534bc9b8..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 @@ -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,30 @@ 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 + */ + 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..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 @@ -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(); // Log target system resolution changeLogger.logTargetSystemResolved(change.getId(), change.getTargetSystem()); @@ -129,6 +130,15 @@ public ChangeProcessStrategy build() { ); } + private TargetSystemOps getTargetSystem() { + try { + return targetSystemManager.getTargetSystem(change.getTargetSystem()); + } catch (Exception e) { + String message = String.format("Error in change [%s] : %s", change.getId(), e.getMessage()); + throw new FlamingockException(message); + } + } + /** * Creates the appropriate change process strategy based on target system characteristics. * 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/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..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 @@ -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,16 +204,20 @@ 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()); + + Map> standardChangesMapByPackage = getCodeChangesMapByPackage(standardChanges); PreviewPipeline pipeline = getPipelineFromProcessChanges( + systemChanges, legacyChanges, - noLegacyChangesByPackage, + standardChangesMapByPackage, flamingockAnnotation ); - validateAllChangesAreMappedToStages(legacyChanges, noLegacyChangesByPackage, pipeline, flamingockAnnotation.strictStageMapping()); + validateAllChangesAreMappedToStages(standardChangesMapByPackage, pipeline, flamingockAnnotation.strictStageMapping()); Serializer serializer = new Serializer(processingEnv, logger); String setup = flamingockAnnotation.setup().toString(); @@ -238,10 +244,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 +259,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 +276,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,40 +305,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; - } - } - - /** - * 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."); - } - } + case SYSTEM: + return 0; + case LEGACY: + return 1; + case DEFAULT: + return 2; + default: + return 3; } } @@ -348,7 +331,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 +346,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) { @@ -459,7 +421,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) @@ -470,9 +432,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 +443,9 @@ private PreviewStage buildLegacyStageIfNeeded(List legacyChan .setResourcesDir(null) //TODO: .setChanges(legacyChanges) .build(); + return Optional.of(flamingockLegacyStage); } - return null; + return Optional.empty(); } @@ -545,7 +508,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 +525,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 +666,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."); @@ -719,10 +675,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()); - } } /** @@ -730,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; } @@ -751,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; } 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..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 @@ -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,78 +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()); - } - - /** - * 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"); - } + assertEquals("migrations", firstStage.getName()); + assertEquals(StageType.DEFAULT, firstStage.getType()); } /** @@ -256,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(); @@ -273,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. */ @@ -419,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"); @@ -445,9 +335,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 +350,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 +365,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 +441,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,9 +470,7 @@ 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") + createMockStage("", "com.example.migrations") ) .build(); } @@ -598,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/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/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/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/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/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/AbstractImporterChangeTemplate.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/AbstractImporterChangeTemplate.java deleted file mode 100644 index b17735135..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/AbstractImporterChangeTemplate.java +++ /dev/null @@ -1,30 +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.api.annotations.Categories; -import io.flamingock.api.task.ChangeCategory; -import io.flamingock.api.template.AbstractChangeTemplate; - - -@Categories(ChangeCategory.IMPORT) -public abstract class AbstractImporterChangeTemplate> extends AbstractChangeTemplate { - - public AbstractImporterChangeTemplate(Class configurationClass) { - super(configurationClass); - } - -} 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 779a44294..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/ImporterAdapter.java +++ /dev/null @@ -1,26 +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.AuditEntry; - -import java.util.List; - -public interface ImporterAdapter { - - List getAuditEntries(); - -} 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 290ad5f01..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.importer.util.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.getAuditEntries(); - 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/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/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/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/mongock/MongockChangeType.java b/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeType.java deleted file mode 100644 index a91c663b3..000000000 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeType.java +++ /dev/null @@ -1,27 +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; - -import io.flamingock.internal.common.core.audit.AuditEntry; - -public enum MongockChangeType { - EXECUTION, BEFORE_EXECUTION; - - public AuditEntry.ExecutionType toAuditType() { - //TODO: remove - return AuditEntry.ExecutionType.EXECUTION; - } -} 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 7c07c3975..000000000 --- a/core/importer/flamingock-importer/src/test/java/io/flamingock/importer/ImporterExecutorTest.java +++ /dev/null @@ -1,68 +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.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; -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.getAuditEntries()).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.getAuditEntries()).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/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/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/core/importer/flamingock-importer-couchbase-tests/build.gradle.kts b/legacy/mongock-importer-couchbase/build.gradle.kts similarity index 66% rename from core/importer/flamingock-importer-couchbase-tests/build.gradle.kts rename to legacy/mongock-importer-couchbase/build.gradle.kts index 48eece1b2..cb48a3c5b 100644 --- a/core/importer/flamingock-importer-couchbase-tests/build.gradle.kts +++ b/legacy/mongock-importer-couchbase/build.gradle.kts @@ -1,18 +1,16 @@ -plugins { - id("java") -} +dependencies { + implementation(project(":core:flamingock-core-commons")) + implementation(project(":utils:couchbase-util")) -group = "io.flamingock" -version = "0.0.38-beta" + //General + compileOnly("com.couchbase.client:java-client:3.6.0") -repositories { - mavenCentral() -} -dependencies { - compileOnly("com.couchbase.client:java-client:3.6.0") - testImplementation(project(":core:importer:flamingock-importer")) 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")) @@ -22,11 +20,9 @@ dependencies { testImplementation("org.mockito:mockito-inline:4.11.0") } -description = "Couchbase-specific integration tests for the Flamingock importer tool" -tasks.test { - useJUnitPlatform() -} +description = "A Couchbase migration utility that imports Mongock’s execution history into Flamingock-Community’s audit store for smooth project upgrades." + java { toolchain { @@ -34,6 +30,7 @@ java { } } + tasks.withType().configureEach { if (name.contains("Test", ignoreCase = true)) { options.compilerArgs.addAll(listOf( diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/CouchbaseChangeEntry.java similarity index 97% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java rename to legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/CouchbaseChangeEntry.java index fb7cf450c..2bf291e84 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseChangeEntry.java +++ b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/CouchbaseChangeEntry.java @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.couchbase; +package io.flamingock.importer.mongock.couchbase; import com.couchbase.client.java.json.JsonObject; -import io.flamingock.importer.mongock.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/mongock/MongockChangeState.java b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockChangeState.java similarity index 95% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeState.java rename to legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockChangeState.java index 2784b98cd..a98287448 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeState.java +++ b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/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.mongock.couchbase; import io.flamingock.internal.common.core.audit.AuditEntry; diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockImporterCouchbase.java similarity index 87% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java rename to legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockImporterCouchbase.java index ca7ea5d3f..9780fa9aa 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/couchbase/CouchbaseImporterAdapter.java +++ b/legacy/mongock-importer-couchbase/src/main/java/io/flamingock/importer/mongock/couchbase/MongockImporterCouchbase.java @@ -13,20 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.couchbase; +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.importer.ImporterAdapter; 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 CouchbaseImporterAdapter implements ImporterAdapter { +public class MongockImporterCouchbase implements AuditHistoryReader { private static final String MONGOCK_CHANGE_ENTRY_DOCTYPE = "mongockChangeEntry"; @@ -35,7 +35,7 @@ public class CouchbaseImporterAdapter implements ImporterAdapter { private final String scopeName; private final String collectionName; - public CouchbaseImporterAdapter(Cluster cluster, String bucketName, String scopeName, String collectionName) { + public MongockImporterCouchbase(Cluster cluster, String bucketName, String scopeName, String collectionName) { this.cluster = cluster; this.bucketName = bucketName; this.scopeName = scopeName; @@ -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-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/CouchbaseImporterTest.java b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/CouchbaseImporterTest.java similarity index 90% rename from core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/CouchbaseImporterTest.java rename to legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/CouchbaseImporterTest.java index 6b7645dbf..1faf07c1f 100644 --- a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/CouchbaseImporterTest.java +++ b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/CouchbaseImporterTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.couchbase; +package io.flamingock.importer.mongock.couchbase; import com.couchbase.client.core.io.CollectionIdentifier; import com.couchbase.client.java.Cluster; @@ -24,10 +24,12 @@ 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.util.constants.CommunityPersistenceConstants; import io.flamingock.internal.core.runner.Runner; -import io.flamingock.internal.common.couchbase.CouchbaseCollectionHelper; +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.assertTrue; 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/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0001__ClientInitializer.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-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0001__ClientInitializer.java rename to legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange1.java index be241903c..fe5032279 100644 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0001__ClientInitializer.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.dynamodb.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-initializer", author = "mongock") -public class _0001__ClientInitializer { +@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/_0002__ClientUpdater.java b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange2.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/MongockChange2.java index 61e8a66c6..2d5f9b1de 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/MongockChange2.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-updater", order = "2", author = "flamingock-team", transactional = false) +public class MongockChange2 { - @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/couchbase/_0001__CreateUsersCollectionChange.java b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java similarity index 90% rename from core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/couchbase/_0001__CreateUsersCollectionChange.java rename to legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java index 34abae265..4e04dcc1e 100644 --- a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/couchbase/_0001__CreateUsersCollectionChange.java +++ b/legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java @@ -13,16 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.couchbase.couchbase; +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.Change; 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/core/importer/flamingock-importer-dynamodb-tests/build.gradle.kts b/legacy/mongock-importer-dynamodb/build.gradle.kts similarity index 72% rename from core/importer/flamingock-importer-dynamodb-tests/build.gradle.kts rename to legacy/mongock-importer-dynamodb/build.gradle.kts index 17cdf5f22..cb65dc562 100644 --- a/core/importer/flamingock-importer-dynamodb-tests/build.gradle.kts +++ b/legacy/mongock-importer-dynamodb/build.gradle.kts @@ -1,9 +1,13 @@ dependencies { + implementation(project(":core:flamingock-core-commons")) + implementation(project(":utils:dynamodb-util")) compileOnly("software.amazon.awssdk:dynamodb-enhanced:2.25.29") - testImplementation(project(":core:importer:flamingock-importer")) testAnnotationProcessor(project(":core:flamingock-processor")) + testAnnotationProcessor(project(":legacy:mongock-support")) + testImplementation(project(":legacy:mongock-support")) + testImplementation(project(":community:flamingock-auditstore-dynamodb")) @@ -17,18 +21,15 @@ dependencies { testImplementation("org.mockito:mockito-inline:4.11.0") } -description = "DynamoDB-specific integration tests for the Flamingock importer tool" -tasks.test { - useJUnitPlatform() -} +description = "A DynamoDB 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.withType().configureEach { if (name.contains("Test", ignoreCase = true)) { options.compilerArgs.addAll(listOf( 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..f065121e4 --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java @@ -0,0 +1,214 @@ +/* + * 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 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); + // 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, + changeId, + author, + ts, + stateEnum.toAuditStatus(), + AuditEntry.ExecutionType.EXECUTION, + changeLogClass, + changeSetMethod, + executionMillis, + executionHostName, + metadata, + systemChange != null && systemChange, + errorTrace + ); + } +} 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 new file mode 100644 index 000000000..4323042cd --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockChangeState.java @@ -0,0 +1,49 @@ +/* + * 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; + +/* + * 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. + */ + +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/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockImporterDynamoDB.java similarity index 74% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java rename to legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockImporterDynamoDB.java index 202d8daa4..603ec3276 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/dynamodb/DynamoDBImporterAdapter.java +++ b/legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockImporterDynamoDB.java @@ -13,12 +13,12 @@ * 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.ImporterAdapter; import io.flamingock.internal.common.core.audit.AuditEntry; -import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; +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; @@ -26,25 +26,25 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; -public class DynamoDBImporterAdapter implements ImporterAdapter { +public class MongockImporterDynamoDB implements AuditHistoryReader { - private final DynamoDbTable sourceTable; + private final DynamoDbTable sourceTable; - public DynamoDBImporterAdapter(DynamoDbClient client, String tableName) { + public MongockImporterDynamoDB(DynamoDbClient client, String tableName) { DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() .dynamoDbClient(client) .build(); - this.sourceTable = enhancedClient.table(tableName, TableSchema.fromBean(MongockDynamoDBAuditEntry.class)); + this.sourceTable = enhancedClient.table(tableName, TableSchema.fromBean(MongockAuditEntry.class)); } @Override - public List getAuditEntries() { - List entries = StreamSupport + public List getAuditHistory() { + List entries = StreamSupport .stream(sourceTable.scan().items().spliterator(), false) .collect(Collectors.toList()); return entries.stream() - .map(MongockDynamoDBAuditEntry::toAuditEntry) + .map(MongockAuditEntry::toAuditEntry) .collect(Collectors.toList()); } } 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..c8cd18987 --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBImporterTest.java @@ -0,0 +1,152 @@ +/* + * 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.api.annotations.EnableFlamingock; +import io.flamingock.api.annotations.Stage; +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; +import io.flamingock.support.mongock.annotations.MongockSupport; +import io.flamingock.targetsystem.dynamodb.DynamoDBTargetSystem; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.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.DescribeTableRequest; +import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse; +import software.amazon.awssdk.services.dynamodb.model.KeyType; + +import java.net.URI; + +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; +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); + + private static DynamoDbClient client; + private DynamoDBMongockTestHelper mongockTestHelper; + private TestKit testKit; + private AuditTestHelper auditHelper; + + @BeforeEach + void setUp() { + 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(); + + // 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); + + // Initialize TestKit for unified testing + testKit = DynamoDBTestKit.create(client, new DynamoDBAuditStore(client)); + auditHelper = testKit.getAuditHelper(); + } + + @AfterEach + void tearDown() { + // DynamoDB local doesn't need explicit cleanup between tests + // Tables are automatically cleaned by Testcontainers on restart + client.close(); + } + + @Test + void testImportDynamoDBChangeLogs() { + // Setup Mongock entries + mongockTestHelper.setupBasicScenario(); + + DynamoDBTargetSystem dynamodbTargetSystem = new DynamoDBTargetSystem("dynamodb-target-system", client); + + Runner flamingock = testKit.createBuilder() + .addTargetSystem(dynamodbTargetSystem) + .build(); + + flamingock.run(); + + // 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") + ); + + // Validate actual table creation + assertTrue(client.listTables().tableNames().contains("users"), "Users table should exist"); + + // Verify table structure + DescribeTableResponse tableDescription = client.describeTable( + DescribeTableRequest.builder().tableName("users").build() + ); + assertEquals("email", tableDescription.table().keySchema().get(0).attributeName()); + assertEquals(KeyType.HASH, tableDescription.table().keySchema().get(0).keyType()); + } + + @Test + @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") + void failIfEmptyOrigin() { + 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..ebeec80ef --- /dev/null +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBMongockTestHelper.java @@ -0,0 +1,66 @@ +/* + * 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.MongockChangeEntry; +import io.flamingock.common.test.mongock.MongockTestHelper; +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/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 669a59ad2..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.mongock.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/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0001__ClientInitializer.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange1.java similarity index 72% rename from core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0001__ClientInitializer.java rename to legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange1.java index 6d6937266..a4653fde0 100644 --- a/core/importer/flamingock-importer-couchbase-tests/src/test/java/io/flamingock/importer/couchbase/legacy/_0001__ClientInitializer.java +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/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.dynamodb.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-initializer", author = "mongock", transactional = false) -public class _0001__ClientInitializer { +@ChangeUnit(id = "client-initializer", order = "1", author = "flamingock-team") +public class MongockChange1 { - @Apply + @Execution 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/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange2.java similarity index 72% rename from core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0002__ClientUpdater.java rename to legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange2.java index 0f9fc9077..3f95234bc 100644 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/legacy/_0002__ClientUpdater.java +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/MongockChange2.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.dynamodb.legacy; +package io.flamingock.importer.mongock.dynamodb.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") -public class _0002__ClientUpdater { +@ChangeUnit(id = "client-updater", order = "2", author = "flamingock-team") +public class MongockChange2 { - @Apply + @Execution public void apply() { System.out.println("Client Initializer"); } diff --git a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/_0001__CreateUsersTableChange.java b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java similarity index 72% rename from core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/_0001__CreateUsersTableChange.java rename to legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java index c785004a8..c8ec51e5a 100644 --- a/core/importer/flamingock-importer-dynamodb-tests/src/test/java/io/flamingock/importer/dynamodb/dynamodb/_0001__CreateUsersTableChange.java +++ b/legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/changes/_0001__CreateUsersTableChange.java @@ -13,13 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.dynamodb.dynamodb; +package io.flamingock.importer.mongock.dynamodb.changes; -import io.flamingock.api.annotations.Change; 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.*; +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; +@TargetSystem(id = "dynamodb-target-system") @Change(id = "create-users-table", author = "importer") public class _0001__CreateUsersTableChange { diff --git a/core/importer/flamingock-importer-mongodb-tests/build.gradle.kts b/legacy/mongock-importer-mongodb/build.gradle.kts similarity index 71% rename from core/importer/flamingock-importer-mongodb-tests/build.gradle.kts rename to legacy/mongock-importer-mongodb/build.gradle.kts index d68e41624..d2c8c4e2e 100644 --- a/core/importer/flamingock-importer-mongodb-tests/build.gradle.kts +++ b/legacy/mongock-importer-mongodb/build.gradle.kts @@ -1,8 +1,11 @@ dependencies { + implementation(project(":core:flamingock-core-commons")) compileOnly("org.mongodb:mongodb-driver-sync:4.0.0") - testImplementation(project(":core:importer:flamingock-importer")) 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")) @@ -12,14 +15,11 @@ dependencies { 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" +description = "A MongoDB migration utility that imports Mongock’s execution history into Flamingock-Community’s audit store for smooth project upgrades." -tasks.test { - useJUnitPlatform() -} java { toolchain { @@ -27,6 +27,11 @@ java { } } +tasks.test { + useJUnitPlatform() +} + + tasks.withType().configureEach { if (name.contains("Test", ignoreCase = true)) { options.compilerArgs.addAll(listOf( 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/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java b/legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockImporterMongoDB.java similarity index 73% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java rename to legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockImporterMongoDB.java index 83b948a2a..ee0aae869 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongodb/MongoDBImporterAdapter.java +++ b/legacy/mongock-importer-mongodb/src/main/java/io/flamingock/importer/mongock/mongodb/MongockImporterMongoDB.java @@ -13,15 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongodb; +package io.flamingock.importer.mongock.mongodb; 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 io.flamingock.internal.common.core.audit.AuditHistoryReader; import org.bson.Document; import java.time.Instant; @@ -32,32 +29,31 @@ import java.util.List; import java.util.stream.Collectors; -//TODO implement reading from Flamingock -public class MongoDBImporterAdapter implements ImporterAdapter { +public class MongockImporterMongoDB implements AuditHistoryReader { private final MongoCollection sourceCollection; - public MongoDBImporterAdapter(MongoDatabase mongoDatabase, String collectionName) { + public MongockImporterMongoDB(MongoDatabase mongoDatabase, String collectionName) { this.sourceCollection = mongoDatabase.getCollection(collectionName); } @Override - public List getAuditEntries() { + public List getAuditHistory() { return sourceCollection.find() .into(new ArrayList<>()) .stream() - .map(MongoDBImporterAdapter::toAuditEntry) + .map(MongockImporterMongoDB::toAuditEntry) .collect(Collectors.toList()); } private static AuditEntry toAuditEntry(Document document) { - MongockChangeEntry changeEntry = toChangeEntry(document); + MongockAuditEntry changeEntry = toChangeEntry(document); LocalDateTime timestamp = Instant.ofEpochMilli(changeEntry.getTimestamp().getTime()) .atZone(ZoneId.systemDefault()) .toLocalDateTime(); - if (changeEntry.getState() == MongockChangeState.IGNORED) { + if (changeEntry.shouldBeIgnored()) { return null; } return new AuditEntry( @@ -66,8 +62,8 @@ private static AuditEntry toAuditEntry(Document document) { changeEntry.getChangeId(), changeEntry.getAuthor(), timestamp, - changeEntry.getState().toAuditStatus(), - changeEntry.getType().toAuditType(), + changeEntry.getState(), + changeEntry.getType(), changeEntry.getChangeLogClass(), changeEntry.getChangeSetMethod(), changeEntry.getExecutionMillis(), @@ -78,15 +74,15 @@ private static AuditEntry toAuditEntry(Document document) { ); } - private static MongockChangeEntry toChangeEntry(Document document) { + private static MongockAuditEntry toChangeEntry(Document document) { Date timestamp = document.getDate("timestamp"); - return new MongockChangeEntry( + return new MongockAuditEntry( document.getString("executionId"), document.getString("changeId"), document.getString("author"), timestamp, - MongockChangeState.valueOf(document.getString("state")), - MongockChangeType.valueOf(document.getString("type")), + document.getString("state"), + document.getString("type"), document.getString("changeLogClass"), document.getString("changeSetMethod"), document.get("metadata"), diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBImporterTest.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBImporterTest.java similarity index 72% rename from core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBImporterTest.java rename to legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBImporterTest.java index a1510427e..84e0228e1 100644 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBImporterTest.java +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBImporterTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongodb; +package io.flamingock.importer.mongock.mongodb; import com.mongodb.ConnectionString; import com.mongodb.MongoClientSettings; @@ -22,12 +22,14 @@ 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 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; @@ -42,28 +44,20 @@ 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 io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN; 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 +@MongockSupport(targetSystem = "mongodb-target-system") +@EnableFlamingock(stages = {@Stage(location = "io.flamingock.importer.mongock.mongodb.changes")}) public class MongoDBImporterTest { @Container - public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); - + private 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 final String DATABASE_NAME = "test"; private static MongoClient mongoClient; private static MongoDatabase database; private MongoDBMongockTestHelper mongockTestHelper; @@ -79,10 +73,10 @@ void setUp() { .build()); database = mongoClient.getDatabase(DB_NAME); - mongockTestHelper = new MongoDBMongockTestHelper(database.getCollection(MONGOCK_CHANGE_LOGS)); + mongockTestHelper = new MongoDBMongockTestHelper(database.getCollection(DEFAULT_MONGOCK_ORIGIN)); // Initialize TestKit for unified testing - testKit = MongoDBSyncTestKit.create(new MongoDBSyncAuditStore(mongoClient, "test"), mongoClient, database); + testKit = MongoDBSyncTestKit.create(new MongoDBSyncAuditStore(mongoClient, DATABASE_NAME), mongoClient, database); auditHelper = testKit.getAuditHelper(); } @@ -94,12 +88,15 @@ void tearDown() { } @Test - @Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done") 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(); @@ -107,26 +104,29 @@ void testImportMongockChangeLogs() { // 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") + // 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() diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java similarity index 96% rename from core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java rename to legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java index dd37ae29f..a096ed2e0 100644 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/MongoDBMongockTestHelper.java +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/MongoDBMongockTestHelper.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongodb; +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.mongock.MongockChangeEntry; import org.bson.Document; import java.util.ArrayList; diff --git a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0002__ClientUpdater.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange1.java similarity index 72% rename from core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0002__ClientUpdater.java rename to legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange1.java index 32622a1dd..3f23e4384 100644 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0002__ClientUpdater.java +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/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.mongodb.legacy; +package io.flamingock.importer.mongock.mongodb.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 = "flamingock-team") -public class _0002__ClientUpdater { +@ChangeUnit(id = "client-initializer", order = "1", author = "flamingock-team") +public class MongockChange1 { - @Apply + @Execution 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/_0001__ClientInitializer.java b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange2.java similarity index 72% rename from core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0001__ClientInitializer.java rename to legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange2.java index 7fc4b3a5e..7fb32f3a7 100644 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/legacy/_0001__ClientInitializer.java +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/MongockChange2.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongodb.legacy; +package io.flamingock.importer.mongock.mongodb.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-initializer", author = "flamingock-team") -public class _0001__ClientInitializer { +@ChangeUnit(id = "client-updater", order = "2", author = "flamingock-team") +public class MongockChange2 { - @Apply + @Execution 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/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0003__create_users_collections.yaml similarity index 84% rename from core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0003__create_users_collections.yaml rename to legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0003__create_users_collections.yaml index 5e91a29be..555e3f317 100644 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0003__create_users_collections.yaml +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0003__create_users_collections.yaml @@ -2,7 +2,7 @@ id: create-users-collection-with-index #transactional: false template: MongoChangeTemplate targetSystem: - id: "mongodb" + id: "mongodb-target-system" 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/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0004__seed_users.yaml similarity index 91% rename from core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0004__seed_users.yaml rename to legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0004__seed_users.yaml index 1d2f53822..ca5b78b8d 100644 --- a/core/importer/flamingock-importer-mongodb-tests/src/test/java/io/flamingock/importer/mongodb/mongodb/_0004__seed_users.yaml +++ b/legacy/mongock-importer-mongodb/src/test/java/io/flamingock/importer/mongock/mongodb/changes/_0004__seed_users.yaml @@ -2,7 +2,7 @@ id: seed-users transactional: true template: MongoChangeTemplate targetSystem: - id: "mongodb" + id: "mongodb-target-system" apply: type: insert collection: users 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..4a08cad92 --- /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 = String.format("TargetSystem[%s], specified in @MongockSupport doesn't provide Mongock importing support", targetSystemId); + 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..d9d8312d7 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") @@ -149,33 +153,24 @@ 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") - -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") - -////////////////////////////////////// -// 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 +184,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/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 + } + } +} diff --git a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeEntry.java b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeEntry.java similarity index 87% rename from core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeEntry.java rename to utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeEntry.java index f3fa1b392..20e81c3d9 100644 --- a/core/importer/flamingock-importer/src/main/java/io/flamingock/importer/mongock/MongockChangeEntry.java +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeEntry.java @@ -1,3 +1,20 @@ +/* + * 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; + /* * Copyright 2023 Flamingock (https://www.flamingock.io) * @@ -13,7 +30,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.flamingock.importer.mongock; import java.util.Date; 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 new file mode 100644 index 000000000..6ea69e016 --- /dev/null +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeState.java @@ -0,0 +1,49 @@ +/* + * 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; + +/* + * 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. + */ + +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/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 new file mode 100644 index 000000000..a010b46e3 --- /dev/null +++ b/utils/test-util/src/main/java/io/flamingock/common/test/mongock/MongockChangeType.java @@ -0,0 +1,42 @@ +/* + * 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; + +/* + * 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. + */ +import io.flamingock.internal.common.core.audit.AuditEntry; + +public enum MongockChangeType { + EXECUTION, BEFORE_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 ca08df75f..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.mongock.MongockChangeEntry; -import io.flamingock.importer.mongock.MongockChangeState; -import io.flamingock.importer.mongock.MongockChangeType; + import java.text.ParseException; import java.text.SimpleDateFormat;