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 data() { + return Arrays.asList( + new Object[][] { // + { "jdbc:tc:databend://hostname/databasename", EnumSet.of(Options.PmdKnownBroken) }, + } + ); + } +} diff --git a/modules/databend/src/test/resources/logback-test.xml b/modules/databend/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/databend/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + +