syntheticBeanBuildItemBuildProducer) {
+
+ SyntheticBeanBuildItem.ExtendedBeanConfigurator configurator = SyntheticBeanBuildItem
+ .configure(LiquibaseMongodbFactory.class)
+ .scope(ApplicationScoped.class) // this is what the existing code does, but it doesn't seem reasonable
+ .setRuntimeInit()
+ .unremovable()
+ .supplier(recorder.liquibaseSupplier(liquibaseMongodbConfig, liquibaseMongodbBuildTimeConfig, mongodbConfig));
+
+ syntheticBeanBuildItemBuildProducer.produce(configurator.done());
+ }
+
+ @BuildStep
+ @Record(ExecutionTime.RUNTIME_INIT)
+ @Consume(SyntheticBeansRuntimeInitBuildItem.class)
+ ServiceStartBuildItem startLiquibase(LiquibaseMongodbRecorder recorder) {
+ // will actually run the actions at runtime
+ recorder.doStartActions();
+
+ return new ServiceStartBuildItem("liquibase-mongodb");
+ }
+
+ /**
+ * Collect the configured changeLog file for the default and all named datasources.
+ *
+ * A {@link LinkedHashSet} is used to avoid duplications.
+ */
+ private List getChangeLogs(LiquibaseMongodbBuildTimeConfig liquibaseBuildConfig) {
+ ChangeLogParameters changeLogParameters = new ChangeLogParameters();
+ ClassLoaderResourceAccessor classLoaderResourceAccessor = new ClassLoaderResourceAccessor(
+ Thread.currentThread().getContextClassLoader());
+
+ ChangeLogParserFactory changeLogParserFactory = ChangeLogParserFactory.getInstance();
+
+ Set resources = new LinkedHashSet<>();
+
+ resources.addAll(findAllChangeLogFiles(liquibaseBuildConfig.changeLog, changeLogParserFactory,
+ classLoaderResourceAccessor, changeLogParameters));
+
+ LOGGER.debugf("Liquibase changeLogs: %s", resources);
+
+ return new ArrayList<>(resources);
+ }
+
+ /**
+ * Finds all resource files for the given change log file
+ */
+ private Set findAllChangeLogFiles(String file, ChangeLogParserFactory changeLogParserFactory,
+ ClassLoaderResourceAccessor classLoaderResourceAccessor,
+ ChangeLogParameters changeLogParameters) {
+ try {
+ ChangeLogParser parser = changeLogParserFactory.getParser(file, classLoaderResourceAccessor);
+ DatabaseChangeLog changelog = parser.parse(file, changeLogParameters, classLoaderResourceAccessor);
+
+ if (changelog != null) {
+ Set result = new LinkedHashSet<>();
+ // get all changeSet files
+ for (ChangeSet changeSet : changelog.getChangeSets()) {
+ result.add(changeSet.getFilePath());
+
+ changeSet.getChanges().stream()
+ .map(change -> extractChangeFile(change, changeSet.getFilePath()))
+ .forEach(changeFile -> changeFile.ifPresent(result::add));
+
+ // get all parents of the changeSet
+ DatabaseChangeLog parent = changeSet.getChangeLog();
+ while (parent != null) {
+ result.add(parent.getFilePath());
+ parent = parent.getParentChangeLog();
+ }
+ }
+ result.add(changelog.getFilePath());
+ return result;
+ }
+ } catch (LiquibaseException ex) {
+ throw new IllegalStateException(ex);
+ }
+ return Collections.emptySet();
+ }
+
+ private Optional extractChangeFile(Change change, String changeSetFilePath) {
+ String path = null;
+ Boolean relative = null;
+ if (change instanceof LoadDataChange) {
+ LoadDataChange loadDataChange = (LoadDataChange) change;
+ path = loadDataChange.getFile();
+ relative = loadDataChange.isRelativeToChangelogFile();
+ } else if (change instanceof SQLFileChange) {
+ SQLFileChange sqlFileChange = (SQLFileChange) change;
+ path = sqlFileChange.getPath();
+ relative = sqlFileChange.isRelativeToChangelogFile();
+ } else if (change instanceof CreateProcedureChange) {
+ CreateProcedureChange createProcedureChange = (CreateProcedureChange) change;
+ path = createProcedureChange.getPath();
+ relative = createProcedureChange.isRelativeToChangelogFile();
+ } else if (change instanceof CreateViewChange) {
+ CreateViewChange createViewChange = (CreateViewChange) change;
+ path = createViewChange.getPath();
+ relative = createViewChange.getRelativeToChangelogFile();
+ }
+
+ // unrelated change or change does not reference a file (e.g. inline view)
+ if (path == null) {
+ return Optional.empty();
+ }
+ // absolute file path or changeSet has no file path
+ if (relative == null || !relative || changeSetFilePath == null) {
+ return Optional.of(path);
+ }
+
+ // relative file path needs to be resolved against changeSetFilePath
+ // notes: ClassLoaderResourceAccessor does not provide a suitable method and CLRA.getFinalPath() is not visible
+ return Optional.of(Paths.get(changeSetFilePath).resolveSibling(path).toString().replace('\\', '/'));
+ }
+}
diff --git a/extensions/liquibase-mongodb/pom.xml b/extensions/liquibase-mongodb/pom.xml
new file mode 100644
index 0000000000000..f9432f43440cb
--- /dev/null
+++ b/extensions/liquibase-mongodb/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ quarkus-extensions-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ quarkus-liquibase-mongodb-parent
+ Quarkus - Liquibase MongoDB
+ pom
+
+
+ runtime
+ deployment
+
+
+
\ No newline at end of file
diff --git a/extensions/liquibase-mongodb/runtime/pom.xml b/extensions/liquibase-mongodb/runtime/pom.xml
new file mode 100644
index 0000000000000..e027988136da5
--- /dev/null
+++ b/extensions/liquibase-mongodb/runtime/pom.xml
@@ -0,0 +1,71 @@
+
+
+
+ quarkus-liquibase-mongodb-parent
+ io.quarkus
+ 999-SNAPSHOT
+
+ 4.0.0
+
+ quarkus-liquibase-mongodb
+ Quarkus - Liquibase MongoDB - Runtime
+ Handle your MongoDB schema migrations with Liquibase
+
+
+ io.quarkus
+ quarkus-mongodb-client
+
+
+ org.liquibase
+ liquibase-core
+
+
+ org.yaml
+ snakeyaml
+
+
+ org.liquibase.ext
+ liquibase-mongodb
+
+
+ org.graalvm.nativeimage
+ svm
+ provided
+
+
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+
+
+
+
+ io.quarkus
+ quarkus-bootstrap-maven-plugin
+
+
+ io.quarkus.liquibase.mongodb
+
+
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+
+
diff --git a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/LiquibaseMongodbFactory.java b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/LiquibaseMongodbFactory.java
new file mode 100644
index 0000000000000..5369cfdad6b3b
--- /dev/null
+++ b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/LiquibaseMongodbFactory.java
@@ -0,0 +1,95 @@
+package io.quarkus.liquibase;
+
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import io.quarkus.liquibase.runtime.LiquibaseMongodbBuildTimeConfig;
+import io.quarkus.liquibase.runtime.LiquibaseMongodbConfig;
+import io.quarkus.mongodb.runtime.MongoClientConfig;
+import liquibase.Contexts;
+import liquibase.LabelExpression;
+import liquibase.Liquibase;
+import liquibase.database.Database;
+import liquibase.database.DatabaseFactory;
+import liquibase.resource.ClassLoaderResourceAccessor;
+import liquibase.resource.ResourceAccessor;
+
+public class LiquibaseMongodbFactory {
+
+ private final MongoClientConfig mongoClientConfig;
+ private final LiquibaseMongodbConfig liquibaseMongodbConfig;
+ private final LiquibaseMongodbBuildTimeConfig liquibaseMongodbBuildTimeConfig;
+
+ //connection-string format, see https://docs.mongodb.com/manual/reference/connection-string/
+ Pattern HAS_DB = Pattern.compile("(mongodb|mongodb\\+srv)://[^/]*/.*");
+
+ public LiquibaseMongodbFactory(LiquibaseMongodbConfig config,
+ LiquibaseMongodbBuildTimeConfig liquibaseMongodbBuildTimeConfig, MongoClientConfig mongoClientConfig) {
+ this.liquibaseMongodbConfig = config;
+ this.liquibaseMongodbBuildTimeConfig = liquibaseMongodbBuildTimeConfig;
+ this.mongoClientConfig = mongoClientConfig;
+ }
+
+ public Liquibase createLiquibase() {
+ try {
+ ResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor(Thread.currentThread().getContextClassLoader());
+ String connectionString = this.mongoClientConfig.connectionString.orElse("mongodb://localhost:27017");
+ if (!HAS_DB.matcher(connectionString).matches()) {
+ connectionString += "/" + this.mongoClientConfig.database.orElseThrow(
+ () -> new IllegalArgumentException(
+ "Config property 'quarkus.mongodb.database' must be defined when no database " +
+ "exist in the connection string"));
+ }
+ Database database = DatabaseFactory.getInstance().openDatabase(connectionString,
+ this.mongoClientConfig.credentials.username.orElse(null),
+ this.mongoClientConfig.credentials.password.orElse(null),
+ null, resourceAccessor);
+
+ ;
+ if (database != null) {
+ liquibaseMongodbConfig.liquibaseCatalogName.ifPresent(database::setLiquibaseCatalogName);
+ liquibaseMongodbConfig.liquibaseSchemaName.ifPresent(database::setLiquibaseSchemaName);
+ liquibaseMongodbConfig.liquibaseTablespaceName.ifPresent(database::setLiquibaseTablespaceName);
+
+ if (liquibaseMongodbConfig.defaultCatalogName.isPresent()) {
+ database.setDefaultCatalogName(liquibaseMongodbConfig.defaultCatalogName.get());
+ }
+ if (liquibaseMongodbConfig.defaultSchemaName.isPresent()) {
+ database.setDefaultSchemaName(liquibaseMongodbConfig.defaultSchemaName.get());
+ }
+ }
+ Liquibase liquibase = new Liquibase(liquibaseMongodbBuildTimeConfig.changeLog, resourceAccessor, database);
+
+ for (Map.Entry entry : liquibaseMongodbConfig.changeLogParameters.entrySet()) {
+ liquibase.getChangeLogParameters().set(entry.getKey(), entry.getValue());
+ }
+
+ return liquibase;
+
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ public LiquibaseMongodbConfig getConfiguration() {
+ return liquibaseMongodbConfig;
+ }
+
+ /**
+ * Creates the default labels base on the configuration
+ *
+ * @return the label expression
+ */
+ public LabelExpression createLabels() {
+ return new LabelExpression(liquibaseMongodbConfig.labels.orElse(null));
+ }
+
+ /**
+ * Creates the default contexts base on the configuration
+ *
+ * @return the contexts
+ */
+ public Contexts createContexts() {
+ return new Contexts(liquibaseMongodbConfig.contexts.orElse(null));
+ }
+}
diff --git a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseMongodbBuildTimeConfig.java b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseMongodbBuildTimeConfig.java
new file mode 100644
index 0000000000000..9bd5432a0f75e
--- /dev/null
+++ b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseMongodbBuildTimeConfig.java
@@ -0,0 +1,16 @@
+package io.quarkus.liquibase.runtime;
+
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+/**
+ * The liquibase configuration
+ */
+@ConfigRoot(name = "liquibase-mongodb", phase = ConfigPhase.BUILD_TIME)
+public class LiquibaseMongodbBuildTimeConfig {
+
+ /**
+ * The change log file
+ */
+ public String changeLog = "db/changeLog.xml";
+}
diff --git a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseMongodbConfig.java b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseMongodbConfig.java
new file mode 100644
index 0000000000000..6cab1009c19d7
--- /dev/null
+++ b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseMongodbConfig.java
@@ -0,0 +1,68 @@
+package io.quarkus.liquibase.runtime;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+/**
+ * The liquibase configuration
+ */
+@ConfigRoot(name = "liquibase-mongodb", phase = ConfigPhase.RUN_TIME)
+public class LiquibaseMongodbConfig {
+
+ /**
+ * The migrate at start flag
+ */
+ public boolean migrateAtStart = false;
+
+ /**
+ * The validate on update flag
+ */
+ public boolean validateOnMigrate = true;
+
+ /**
+ * The clean at start flag
+ */
+ public boolean cleanAtStart = false;
+
+ public Map changeLogParameters = null;
+
+ /**
+ * The list of contexts
+ */
+ public Optional> contexts = null;
+
+ /**
+ * The list of labels
+ */
+ public Optional> labels = null;
+
+ /**
+ * The default catalog name
+ */
+ public Optional defaultCatalogName = Optional.empty();
+
+ /**
+ * The default schema name
+ */
+ public Optional defaultSchemaName = Optional.empty();
+
+ /**
+ * The liquibase tables catalog name
+ */
+ public Optional liquibaseCatalogName = Optional.empty();
+
+ /**
+ * The liquibase tables schema name
+ */
+ public Optional liquibaseSchemaName = Optional.empty();
+
+ /**
+ * The liquibase tables tablespace name
+ */
+ public Optional liquibaseTablespaceName = Optional.empty();
+
+}
diff --git a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseMongodbRecorder.java b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseMongodbRecorder.java
new file mode 100644
index 0000000000000..84759f8ac1e6c
--- /dev/null
+++ b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseMongodbRecorder.java
@@ -0,0 +1,63 @@
+package io.quarkus.liquibase.runtime;
+
+import java.util.function.Supplier;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.UnsatisfiedResolutionException;
+
+import io.quarkus.arc.Arc;
+import io.quarkus.arc.InjectableInstance;
+import io.quarkus.arc.InstanceHandle;
+import io.quarkus.liquibase.LiquibaseMongodbFactory;
+import io.quarkus.mongodb.runtime.MongodbConfig;
+import io.quarkus.runtime.annotations.Recorder;
+import liquibase.Liquibase;
+
+@Recorder
+public class LiquibaseMongodbRecorder {
+
+ public Supplier liquibaseSupplier(LiquibaseMongodbConfig config,
+ LiquibaseMongodbBuildTimeConfig buildTimeConfig, MongodbConfig mongodbConfig) {
+ return new Supplier() {
+ @Override
+ public LiquibaseMongodbFactory get() {
+ return new LiquibaseMongodbFactory(config, buildTimeConfig, mongodbConfig.defaultMongoClientConfig);
+ }
+ };
+ }
+
+ public void doStartActions() {
+ try {
+ InjectableInstance liquibaseFactoryInstance = Arc.container()
+ .select(LiquibaseMongodbFactory.class, Any.Literal.INSTANCE);
+ if (liquibaseFactoryInstance.isUnsatisfied()) {
+ return;
+ }
+
+ for (InstanceHandle liquibaseFactoryHandle : liquibaseFactoryInstance.handles()) {
+ try {
+ LiquibaseMongodbFactory liquibaseFactory = liquibaseFactoryHandle.get();
+ if (liquibaseFactory.getConfiguration().cleanAtStart) {
+ try (Liquibase liquibase = liquibaseFactory.createLiquibase()) {
+ liquibase.dropAll();
+ }
+ }
+ if (liquibaseFactory.getConfiguration().migrateAtStart) {
+ if (liquibaseFactory.getConfiguration().validateOnMigrate) {
+ try (Liquibase liquibase = liquibaseFactory.createLiquibase()) {
+ liquibase.validate();
+ }
+ }
+ try (Liquibase liquibase = liquibaseFactory.createLiquibase()) {
+ liquibase.update(liquibaseFactory.createContexts(), liquibaseFactory.createLabels());
+ }
+ }
+ } catch (UnsatisfiedResolutionException e) {
+ //ignore, the DS is not configured
+ }
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Error starting Liquibase", e);
+ }
+ }
+}
diff --git a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/graal/SubstituteStringUtil.java b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/graal/SubstituteStringUtil.java
new file mode 100644
index 0000000000000..d4f28a00e8464
--- /dev/null
+++ b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/runtime/graal/SubstituteStringUtil.java
@@ -0,0 +1,37 @@
+package io.quarkus.liquibase.runtime.graal;
+
+import java.security.SecureRandom;
+
+import com.oracle.svm.core.annotate.Alias;
+import com.oracle.svm.core.annotate.InjectAccessors;
+import com.oracle.svm.core.annotate.TargetClass;
+
+@TargetClass(className = "liquibase.util.StringUtil")
+final class SubstituteStringUtil {
+
+ @Alias
+ @InjectAccessors(SecureRandomAccessors.class)
+ private static SecureRandom rnd;
+
+ public static final class SecureRandomAccessors {
+
+ private static volatile SecureRandom volatileRandom;
+
+ public static SecureRandom get() {
+ SecureRandom localVolatileRandom = volatileRandom;
+ if (localVolatileRandom == null) {
+ synchronized (SecureRandomAccessors.class) {
+ localVolatileRandom = volatileRandom;
+ if (localVolatileRandom == null) {
+ volatileRandom = localVolatileRandom = new SecureRandom();
+ }
+ }
+ }
+ return localVolatileRandom;
+ }
+
+ public static void set(SecureRandom rnd) {
+ throw new IllegalStateException("The setter for liquibase.util.StringUtil#rnd shouldn't be called.");
+ }
+ }
+}
diff --git a/extensions/liquibase-mongodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/liquibase-mongodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000000000..8cacc679b7975
--- /dev/null
+++ b/extensions/liquibase-mongodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,11 @@
+---
+artifact: ${project.groupId}:${project.artifactId}:${project.version}
+name: "Liquibase MongoDB"
+metadata:
+ keywords:
+ - "liquibase"
+ - "mongodb"
+ - "data"
+ categories:
+ - "data"
+ status: "experimental"
\ No newline at end of file
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 03e4923b78cb8..d20956728e9ea 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -175,6 +175,7 @@
flyway
liquibase
+ liquibase-mongodb
vault
diff --git a/integration-tests/liquibase-mongodb/pom.xml b/integration-tests/liquibase-mongodb/pom.xml
new file mode 100644
index 0000000000000..dc1d8393d2d02
--- /dev/null
+++ b/integration-tests/liquibase-mongodb/pom.xml
@@ -0,0 +1,106 @@
+
+
+
+ quarkus-integration-tests-parent
+ io.quarkus
+ 999-SNAPSHOT
+
+ 4.0.0
+
+ quarkus-integration-test-liquibase-mongodb
+ Quarkus - Integration Tests - Liquibase MongoDB
+ Module that contains Liquibase MongoDB related tests
+
+
+
+ io.quarkus
+ quarkus-liquibase-mongodb
+
+
+ io.quarkus
+ quarkus-mongodb-panache
+
+
+ io.quarkus
+ quarkus-resteasy-jackson
+
+
+
+
+ io.quarkus
+ quarkus-junit5
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+ io.quarkus
+ quarkus-test-mongodb
+ test
+
+
+
+
+ io.quarkus
+ quarkus-liquibase-mongodb-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ io.quarkus
+ quarkus-mongodb-panache-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ io.quarkus
+ quarkus-resteasy-jackson-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+
+
+
+
+ io.quarkus
+ quarkus-maven-plugin
+
+
+
+ build
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/integration-tests/liquibase-mongodb/src/main/java/io/quarkus/it/liquibase/mongodb/Fruit.java b/integration-tests/liquibase-mongodb/src/main/java/io/quarkus/it/liquibase/mongodb/Fruit.java
new file mode 100644
index 0000000000000..b5d0483404c0e
--- /dev/null
+++ b/integration-tests/liquibase-mongodb/src/main/java/io/quarkus/it/liquibase/mongodb/Fruit.java
@@ -0,0 +1,8 @@
+package io.quarkus.it.liquibase.mongodb;
+
+import io.quarkus.mongodb.panache.PanacheMongoEntity;
+
+public class Fruit extends PanacheMongoEntity {
+ public String name;
+ public String color;
+}
diff --git a/integration-tests/liquibase-mongodb/src/main/java/io/quarkus/it/liquibase/mongodb/FruitResource.java b/integration-tests/liquibase-mongodb/src/main/java/io/quarkus/it/liquibase/mongodb/FruitResource.java
new file mode 100644
index 0000000000000..cdbb0a4efc69c
--- /dev/null
+++ b/integration-tests/liquibase-mongodb/src/main/java/io/quarkus/it/liquibase/mongodb/FruitResource.java
@@ -0,0 +1,33 @@
+package io.quarkus.it.liquibase.mongodb;
+
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.bson.types.ObjectId;
+
+@Path("/fruits")
+@Produces(MediaType.APPLICATION_JSON)
+public class FruitResource {
+
+ @GET
+ public List list() {
+ return Fruit.listAll();
+ }
+
+ @GET
+ @Path("/{id}")
+ public Fruit get(@PathParam("id") String id) {
+ return Fruit.findById(new ObjectId(id));
+ }
+
+ @POST
+ public void save(Fruit fruit) {
+ fruit.persist();
+ }
+}
diff --git a/integration-tests/liquibase-mongodb/src/main/resources/application.properties b/integration-tests/liquibase-mongodb/src/main/resources/application.properties
new file mode 100644
index 0000000000000..9a40534908c6f
--- /dev/null
+++ b/integration-tests/liquibase-mongodb/src/main/resources/application.properties
@@ -0,0 +1,4 @@
+quarkus.mongodb.connection-string=mongodb://localhost:27017
+quarkus.mongodb.database=fruits
+quarkus.liquibase-mongodb.change-log=liquibase/changelog.xml
+quarkus.liquibase-mongodb.migrate-at-start=true
\ No newline at end of file
diff --git a/integration-tests/liquibase-mongodb/src/main/resources/liquibase/changelog.xml b/integration-tests/liquibase-mongodb/src/main/resources/liquibase/changelog.xml
new file mode 100644
index 0000000000000..18bd43e5611b4
--- /dev/null
+++ b/integration-tests/liquibase-mongodb/src/main/resources/liquibase/changelog.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+ {color: 1}
+ {name: "colorIdx"}
+
+
+
+ {"name":"orange", "color": "orange"}
+
+
+
+
+
\ No newline at end of file
diff --git a/integration-tests/liquibase-mongodb/src/test/java/io/quarkus/it/liquibase/mongodb/FruitResourceTest.java b/integration-tests/liquibase-mongodb/src/test/java/io/quarkus/it/liquibase/mongodb/FruitResourceTest.java
new file mode 100644
index 0000000000000..6f9a203d3ec4f
--- /dev/null
+++ b/integration-tests/liquibase-mongodb/src/test/java/io/quarkus/it/liquibase/mongodb/FruitResourceTest.java
@@ -0,0 +1,51 @@
+package io.quarkus.it.liquibase.mongodb;
+
+import static io.restassured.RestAssured.get;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import javax.inject.Inject;
+
+import org.bson.Document;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import com.mongodb.client.ListIndexesIterable;
+import com.mongodb.client.MongoClient;
+
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.mongodb.MongoTestResource;
+import io.restassured.common.mapper.TypeRef;
+
+@QuarkusTest
+@QuarkusTestResource(MongoTestResource.class)
+@DisabledOnOs(OS.WINDOWS)
+class FruitResourceTest {
+
+ @Inject
+ MongoClient mongoClient;
+
+ @Test
+ public void testTheEndpoint() {
+ // assert that a fruit exist as one has been created in the changelog
+ List list = get("/fruits").as(new TypeRef>() {
+ });
+ Assertions.assertEquals(1, list.size());
+ }
+
+ @Test
+ public void validateTheIdx() {
+ // check that the index that the changelog created exist
+ ListIndexesIterable indexes = mongoClient.getDatabase("fruits").getCollection("Fruit").listIndexes();
+ Set names = StreamSupport.stream(indexes.spliterator(), false)
+ .map(doc -> doc.getString("name"))
+ .collect(Collectors.toSet());
+ Assertions.assertTrue(names.contains("colorIdx"));
+ }
+}
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 85cd285c932c9..fb683ab4e1782 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -180,6 +180,7 @@
elytron-undertow
flyway
liquibase
+ liquibase-mongodb
oidc
oidc-client
oidc-client-reactive