diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index 284e2c561fb..4251a2db853 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -23,6 +23,7 @@ body:
- Consul
- Couchbase
- CrateDB
+ - Databend
- DB2
- Dynalite
- Elasticsearch
diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml
index 2ca7de6bc3c..24d6b33ffdd 100644
--- a/.github/ISSUE_TEMPLATE/enhancement.yaml
+++ b/.github/ISSUE_TEMPLATE/enhancement.yaml
@@ -23,6 +23,7 @@ body:
- Consul
- Couchbase
- CrateDB
+ - Databend
- DB2
- Dynalite
- Elasticsearch
diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml
index 311ec8ca2c6..d36532b7d9d 100644
--- a/.github/ISSUE_TEMPLATE/feature.yaml
+++ b/.github/ISSUE_TEMPLATE/feature.yaml
@@ -23,6 +23,7 @@ body:
- CrateDB
- Consul
- Couchbase
+ - Databend
- DB2
- Dynalite
- Elasticsearch
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 0239be10168..22977397e03 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -90,6 +90,10 @@ updates:
directory: "/modules/database-commons"
schedule:
interval: "weekly"
+ - package-ecosystem: "gradle"
+ directory: "/modules/databend"
+ schedule:
+ interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: "gradle"
directory: "/modules/db2"
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 875e996c428..e88811fd50a 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -55,6 +55,10 @@
- changed-files:
- any-glob-to-any-file:
- modules/cratedb/**/*
+"modules/databend":
+ - changed-files:
+ - any-glob-to-any-file:
+ - modules/databend/**/*
"modules/db2":
- changed-files:
- any-glob-to-any-file:
diff --git a/.github/settings.yml b/.github/settings.yml
index 06b1c06e72f..d02aee1c7da 100644
--- a/.github/settings.yml
+++ b/.github/settings.yml
@@ -271,6 +271,9 @@ labels:
- name: modules/yugabytedb
color: '#006b75'
+ - name: modules/databend
+ color: '#006b75'
+
- name: os/linux
color: '#1d76db'
diff --git a/docs/modules/databases/databend.md b/docs/modules/databases/databend.md
new file mode 100644
index 00000000000..c399dc2bb51
--- /dev/null
+++ b/docs/modules/databases/databend.md
@@ -0,0 +1,24 @@
+# Databend Module
+
+## Adding this module to your project dependencies
+
+Add the following dependency to your `pom.xml`/`build.gradle` file:
+
+=== "Gradle"
+ ```groovy
+ testImplementation "org.testcontainers:databend:{{latest_version}}"
+ ```
+
+=== "Maven"
+ ```xml
+
+ org.testcontainers
+ databend
+ {{latest_version}}
+ test
+
+ ```
+
+!!! hint
+Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency.
+
diff --git a/mkdocs.yml b/mkdocs.yml
index 2e1c60c7dcc..f3cd49bab30 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -56,6 +56,7 @@ nav:
- modules/databases/couchbase.md
- modules/databases/clickhouse.md
- modules/databases/cratedb.md
+ - modules/databases/databend.md
- modules/databases/db2.md
- modules/databases/dynalite.md
- modules/databases/influxdb.md
diff --git a/modules/databend/build.gradle b/modules/databend/build.gradle
new file mode 100644
index 00000000000..81cc9ef2cbe
--- /dev/null
+++ b/modules/databend/build.gradle
@@ -0,0 +1,9 @@
+description = "Testcontainers :: JDBC :: Databend"
+
+dependencies {
+ api project(':jdbc')
+
+ testImplementation project(':jdbc-test')
+ testRuntimeOnly 'com.databend:databend-jdbc:0.2.9'
+ testImplementation 'org.assertj:assertj-core:3.26.3'
+}
diff --git a/modules/databend/src/main/java/org/testcontainers/databend/DatabendContainer.java b/modules/databend/src/main/java/org/testcontainers/databend/DatabendContainer.java
new file mode 100644
index 00000000000..389c8c44963
--- /dev/null
+++ b/modules/databend/src/main/java/org/testcontainers/databend/DatabendContainer.java
@@ -0,0 +1,112 @@
+package org.testcontainers.databend;
+
+import org.testcontainers.containers.JdbcDatabaseContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.DockerImageName;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Testcontainers implementation for Databend.
+ *
+ * Supported image: {@code datafuselabs/databend}
+ *
+ * Exposed ports:
+ *
+ */
+public class DatabendContainer extends JdbcDatabaseContainer {
+
+ static final String NAME = "databend";
+
+ static final DockerImageName DOCKER_IMAGE_NAME = DockerImageName.parse("datafuselabs/databend");
+
+ private static final Integer HTTP_PORT = 8000;
+
+ private static final String DRIVER_CLASS_NAME = "com.databend.jdbc.DatabendDriver";
+
+ private static final String JDBC_URL_PREFIX = "jdbc:" + NAME + "://";
+
+ private static final String TEST_QUERY = "SELECT 1";
+
+ private String databaseName = "default";
+
+ private String username = "databend";
+
+ private String password = "databend";
+
+ public DatabendContainer(String dockerImageName) {
+ this(DockerImageName.parse(dockerImageName));
+ }
+
+ public DatabendContainer(final DockerImageName dockerImageName) {
+ super(dockerImageName);
+ dockerImageName.assertCompatibleWith(DOCKER_IMAGE_NAME);
+
+ addExposedPorts(HTTP_PORT);
+ waitingFor(Wait.forHttp("/").forResponsePredicate(response -> response.equals("Ok.")));
+ }
+
+ @Override
+ protected void configure() {
+ withEnv("QUERY_DEFAULT_USER", this.username);
+ withEnv("QUERY_DEFAULT_PASSWORD", this.password);
+ }
+
+ @Override
+ public Set getLivenessCheckPortNumbers() {
+ return new HashSet<>(getMappedPort(HTTP_PORT));
+ }
+
+ @Override
+ public String getDriverClassName() {
+ return DRIVER_CLASS_NAME;
+ }
+
+ @Override
+ public String getJdbcUrl() {
+ return (
+ JDBC_URL_PREFIX +
+ getHost() +
+ ":" +
+ getMappedPort(HTTP_PORT) +
+ "/" +
+ this.databaseName +
+ constructUrlParameters("?", "&")
+ );
+ }
+
+ @Override
+ public String getUsername() {
+ return this.username;
+ }
+
+ @Override
+ public String getPassword() {
+ return this.password;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return this.databaseName;
+ }
+
+ @Override
+ public String getTestQueryString() {
+ return TEST_QUERY;
+ }
+
+ @Override
+ public DatabendContainer withUsername(String username) {
+ this.username = username;
+ return this;
+ }
+
+ @Override
+ public DatabendContainer withPassword(String password) {
+ this.password = password;
+ return this;
+ }
+}
diff --git a/modules/databend/src/main/java/org/testcontainers/databend/DatabendContainerProvider.java b/modules/databend/src/main/java/org/testcontainers/databend/DatabendContainerProvider.java
new file mode 100644
index 00000000000..9142bebcfd3
--- /dev/null
+++ b/modules/databend/src/main/java/org/testcontainers/databend/DatabendContainerProvider.java
@@ -0,0 +1,28 @@
+package org.testcontainers.databend;
+
+import org.testcontainers.containers.JdbcDatabaseContainer;
+import org.testcontainers.containers.JdbcDatabaseContainerProvider;
+
+public class DatabendContainerProvider extends JdbcDatabaseContainerProvider {
+
+ private static final String DEFAULT_TAG = "v1.2.615";
+
+ @Override
+ public boolean supports(String databaseType) {
+ return databaseType.equals(DatabendContainer.NAME);
+ }
+
+ @Override
+ public JdbcDatabaseContainer newInstance() {
+ return newInstance(DEFAULT_TAG);
+ }
+
+ @Override
+ public JdbcDatabaseContainer newInstance(String tag) {
+ if (tag != null) {
+ return new DatabendContainer(DatabendContainer.DOCKER_IMAGE_NAME.withTag(tag));
+ } else {
+ return newInstance();
+ }
+ }
+}
diff --git a/modules/databend/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/databend/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider
new file mode 100644
index 00000000000..ead69e77bee
--- /dev/null
+++ b/modules/databend/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider
@@ -0,0 +1 @@
+org.testcontainers.databend.DatabendContainerProvider
diff --git a/modules/databend/src/test/java/org/testcontainers/databend/DatabendContainerTest.java b/modules/databend/src/test/java/org/testcontainers/databend/DatabendContainerTest.java
new file mode 100644
index 00000000000..92f4842d119
--- /dev/null
+++ b/modules/databend/src/test/java/org/testcontainers/databend/DatabendContainerTest.java
@@ -0,0 +1,41 @@
+package org.testcontainers.databend;
+
+import org.junit.Test;
+import org.testcontainers.db.AbstractContainerDatabaseTest;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DatabendContainerTest extends AbstractContainerDatabaseTest {
+
+ @Test
+ public void testSimple() throws SQLException {
+ try (DatabendContainer databend = new DatabendContainer("datafuselabs/databend:v1.2.615")) {
+ databend.start();
+
+ ResultSet resultSet = performQuery(databend, "SELECT 1");
+
+ int resultSetInt = resultSet.getInt(1);
+ assertThat(resultSetInt).isEqualTo(1);
+ }
+ }
+
+ @Test
+ public void customCredentialsWithUrlParams() throws SQLException {
+ try (
+ DatabendContainer databend = new DatabendContainer("datafuselabs/databend:v1.2.615")
+ .withUsername("test")
+ .withPassword("test")
+ .withUrlParam("ssl", "false")
+ ) {
+ databend.start();
+
+ ResultSet resultSet = performQuery(databend, "SELECT 1;");
+
+ int resultSetInt = resultSet.getInt(1);
+ assertThat(resultSetInt).isEqualTo(1);
+ }
+ }
+}
diff --git a/modules/databend/src/test/java/org/testcontainers/databend/DatabendJDBCDriverTest.java b/modules/databend/src/test/java/org/testcontainers/databend/DatabendJDBCDriverTest.java
new file mode 100644
index 00000000000..a36039dc8d1
--- /dev/null
+++ b/modules/databend/src/test/java/org/testcontainers/databend/DatabendJDBCDriverTest.java
@@ -0,0 +1,21 @@
+package org.testcontainers.databend;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.testcontainers.jdbc.AbstractJDBCDriverTest;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+
+@RunWith(Parameterized.class)
+public class DatabendJDBCDriverTest extends AbstractJDBCDriverTest {
+
+ @Parameterized.Parameters(name = "{index} - {0}")
+ public static Iterable