From a10044612bb8170c5b2065011fb2d0c71115d92c Mon Sep 17 00:00:00 2001 From: pwangryn Date: Tue, 18 Oct 2022 18:28:29 +0200 Subject: [PATCH 01/14] Implement QuestDB module --- modules/questdb/build.gradle | 10 +++ .../containers/QuestDBContainer.java | 88 +++++++++++++++++++ .../containers/QuestDBProvider.java | 16 ++++ ...s.containers.JdbcDatabaseContainerProvider | 1 + .../org/testcontainers/QuestDBTestImages.java | 7 ++ .../jdbc/questdb/QuestDBJDBCDriverTest.java | 19 ++++ .../junit/questdb/SimpleQuestDBTest.java | 26 ++++++ 7 files changed, 167 insertions(+) create mode 100644 modules/questdb/build.gradle create mode 100644 modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java create mode 100644 modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java create mode 100644 modules/questdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider create mode 100644 modules/questdb/src/test/java/org/testcontainers/QuestDBTestImages.java create mode 100644 modules/questdb/src/test/java/org/testcontainers/jdbc/questdb/QuestDBJDBCDriverTest.java create mode 100644 modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java diff --git a/modules/questdb/build.gradle b/modules/questdb/build.gradle new file mode 100644 index 00000000000..628c7b21b2d --- /dev/null +++ b/modules/questdb/build.gradle @@ -0,0 +1,10 @@ +description = "Testcontainers :: QuestDB" + +dependencies { + api project(':testcontainers') + api project(':jdbc') + + testImplementation 'org.postgresql:postgresql:42.5.0' + testImplementation project(':jdbc-test') + testImplementation 'org.assertj:assertj-core:3.23.1' +} diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java new file mode 100644 index 00000000000..1416d9b2388 --- /dev/null +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java @@ -0,0 +1,88 @@ +package org.testcontainers.containers; + +import lombok.NonNull; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +public class QuestDBContainer extends JdbcDatabaseContainer { + + public static final String DATABASE_PROVIDER = "postgresql"; + + private static final String DEFAULT_TAG = "6.5.3"; + + private static final String DEFAULT_DATABASE_NAME = "qdb"; + + private static final String DEFAULT_USERNAME = "admin"; + + private static final String DEFAULT_PASSWORD = "quest"; + + public static final Integer POSTGRES_PORT = 8812; + + public static final Integer REST_PORT = 9000; + + public static final Integer ILP_PORT = 9009; + + public static final String TEST_QUERY = "SELECT 1"; + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("questdb/questdb"); + + @Deprecated + public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); + + @Deprecated + public QuestDBContainer() { + this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); + } + + public QuestDBContainer(@NonNull String dockerImageName) { + super(dockerImageName); + } + + public QuestDBContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + this.withExposedPorts(POSTGRES_PORT, REST_PORT, ILP_PORT); + this.waitingFor(Wait.forLogMessage("(?i).*A server-main enjoy.*", 1)); + } + + @Override + public String getDriverClassName() { + return "org.postgresql.Driver"; + } + + @Override + public String getJdbcUrl() { + return this.getPostgresUrl(DEFAULT_DATABASE_NAME); + } + + @Override + public String getUsername() { + return DEFAULT_USERNAME; + } + + @Override + public String getPassword() { + return DEFAULT_PASSWORD; + } + + @Override + public String getTestQueryString() { + return TEST_QUERY; + } + + public Integer getIlpPort() { + return getMappedPort(ILP_PORT); + } + + public String getPostgresUrl(String databaseName) { + if (!this.isRunning()) { + throw new IllegalStateException("QuestDBContainer should be started first"); + } else { + return this.getPostgresConnectionString() + "/" + databaseName; + } + } + + public String getPostgresConnectionString() { + return String.format("jdbc:postgresql://%s:%d", this.getHost(), this.getMappedPort(8812)); + } +} diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java new file mode 100644 index 00000000000..c8e93c553d4 --- /dev/null +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java @@ -0,0 +1,16 @@ +package org.testcontainers.containers; + +import org.testcontainers.utility.DockerImageName; + +public class QuestDBProvider extends JdbcDatabaseContainerProvider { + + @Override + public boolean supports(String databaseType) { + return databaseType.equals(QuestDBContainer.DATABASE_PROVIDER); + } + + @Override + public JdbcDatabaseContainer newInstance(String tag) { + return new QuestDBContainer(DockerImageName.parse(QuestDBContainer.IMAGE).withTag(tag)); + } +} diff --git a/modules/questdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/questdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider new file mode 100644 index 00000000000..922a12a1328 --- /dev/null +++ b/modules/questdb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider @@ -0,0 +1 @@ +org.testcontainers.containers.QuestDBProvider diff --git a/modules/questdb/src/test/java/org/testcontainers/QuestDBTestImages.java b/modules/questdb/src/test/java/org/testcontainers/QuestDBTestImages.java new file mode 100644 index 00000000000..555b56f172c --- /dev/null +++ b/modules/questdb/src/test/java/org/testcontainers/QuestDBTestImages.java @@ -0,0 +1,7 @@ +package org.testcontainers; + +import org.testcontainers.utility.DockerImageName; + +public interface QuestDBTestImages { + DockerImageName QUESTDB_IMAGE = DockerImageName.parse("questdb/questdb:6.5.3"); +} diff --git a/modules/questdb/src/test/java/org/testcontainers/jdbc/questdb/QuestDBJDBCDriverTest.java b/modules/questdb/src/test/java/org/testcontainers/jdbc/questdb/QuestDBJDBCDriverTest.java new file mode 100644 index 00000000000..b19c2acc5fd --- /dev/null +++ b/modules/questdb/src/test/java/org/testcontainers/jdbc/questdb/QuestDBJDBCDriverTest.java @@ -0,0 +1,19 @@ +package org.testcontainers.jdbc.questdb; + +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 QuestDBJDBCDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return Arrays.asList( + new Object[][] { { "jdbc:tc:postgresql://hostname/databasename", EnumSet.of(Options.PmdKnownBroken) } } + ); + } +} diff --git a/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java new file mode 100644 index 00000000000..1de037207ca --- /dev/null +++ b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java @@ -0,0 +1,26 @@ +package org.testcontainers.junit.questdb; + +import org.junit.Test; +import org.testcontainers.QuestDBTestImages; +import org.testcontainers.containers.QuestDBContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SimpleQuestDBTest extends AbstractContainerDatabaseTest { + + @Test + public void testSimple() throws SQLException { + try (QuestDBContainer questDB = new QuestDBContainer(QuestDBTestImages.QUESTDB_IMAGE)) { + questDB.start(); + + ResultSet resultSet = performQuery(questDB, QuestDBContainer.TEST_QUERY); + + int resultSetInt = resultSet.getInt(1); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + } + } +} From 323cb659f0974073c0ba92d6deecf54941964531 Mon Sep 17 00:00:00 2001 From: pwangryn Date: Tue, 18 Oct 2022 18:38:44 +0200 Subject: [PATCH 02/14] Add md file for QuestDB --- .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + docs/modules/databases/questdb.md | 9 +++++++++ mkdocs.yml | 1 + 3 files changed, 11 insertions(+) create mode 100644 docs/modules/databases/questdb.md diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 9d65e1f12b8..2bbca5db3ae 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -41,6 +41,7 @@ body: - PostgreSQL - Presto - Pulsar + - QuestDB - RabbitMQ - Redpanda - Selenium diff --git a/docs/modules/databases/questdb.md b/docs/modules/databases/questdb.md new file mode 100644 index 00000000000..57714ec6f9e --- /dev/null +++ b/docs/modules/databases/questdb.md @@ -0,0 +1,9 @@ +# Dynalite Module + +Testcontainers module for [QuestDB](https://github.com/questdb/questdb). QuestDB is a high-performance, open-source SQL database for applications in financial services, IoT, machine learning, DevOps and observability. + +See [Database containers](./index.md) for documentation and usage that is common to all relational database container types. + +## Adding this module to your project dependencies + +[//]: # (placeholder) diff --git a/mkdocs.yml b/mkdocs.yml index 70421761e02..8871267cace 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -63,6 +63,7 @@ nav: - modules/databases/orientdb.md - modules/databases/postgres.md - modules/databases/presto.md + - modules/databases/questdb.md - modules/databases/tidb.md - modules/databases/trino.md - modules/azure.md From b1d88ee980e09373754f02d078a1862e5199d11d Mon Sep 17 00:00:00 2001 From: pwangryn Date: Tue, 18 Oct 2022 18:43:16 +0200 Subject: [PATCH 03/14] Add quest db to required .yaml files --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 +++++ .github/labeler.yml | 2 ++ 4 files changed, 9 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 8196451e88f..37609ce1424 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -41,6 +41,7 @@ body: - PostgreSQL - Presto - Pulsar + - QuestDB - RabbitMQ - Redpanda - Selenium diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 581870d976d..d29d0178c39 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -39,6 +39,7 @@ body: - Oracle-XE - OrientDB - PostgreSQL + - QuestDB - Presto - Pulsar - RabbitMQ diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 87ce5c86463..791afeece2e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -195,6 +195,11 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/questdb" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/r2dbc" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index 85144b7d7f9..bda614305fa 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -65,6 +65,8 @@ - modules/presto/* "modules/pulsar": - modules/pulsar/* +"modules/questdb": + - modules/questdb/* "modules/r2dbc": - modules/r2dbc/* "modules/rabbitmq": From 55aa39660b384524d863c8a6c00c1918996e3bfd Mon Sep 17 00:00:00 2001 From: pwangryn Date: Wed, 19 Oct 2022 09:39:06 +0200 Subject: [PATCH 04/14] Fix wrong md file title --- docs/modules/databases/questdb.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/databases/questdb.md b/docs/modules/databases/questdb.md index 57714ec6f9e..4488733ff31 100644 --- a/docs/modules/databases/questdb.md +++ b/docs/modules/databases/questdb.md @@ -1,4 +1,4 @@ -# Dynalite Module +# QuestDB Module Testcontainers module for [QuestDB](https://github.com/questdb/questdb). QuestDB is a high-performance, open-source SQL database for applications in financial services, IoT, machine learning, DevOps and observability. From d7ed013a3d7cd7e4252cfb77e2ea96eff5f3d8e5 Mon Sep 17 00:00:00 2001 From: pwangryn Date: Wed, 19 Oct 2022 09:49:55 +0200 Subject: [PATCH 05/14] Cleanup QuestDBContainer, add getHttpUrl and return ilp url instead only port --- .../containers/QuestDBContainer.java | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java index 1416d9b2388..6e539094b9d 100644 --- a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java @@ -41,8 +41,8 @@ public QuestDBContainer(@NonNull String dockerImageName) { public QuestDBContainer(DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); - this.withExposedPorts(POSTGRES_PORT, REST_PORT, ILP_PORT); - this.waitingFor(Wait.forLogMessage("(?i).*A server-main enjoy.*", 1)); + withExposedPorts(POSTGRES_PORT, REST_PORT, ILP_PORT); + waitingFor(Wait.forLogMessage("(?i).*A server-main enjoy.*", 1)); } @Override @@ -52,7 +52,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return this.getPostgresUrl(DEFAULT_DATABASE_NAME); + return String.format("jdbc:postgresql://%s:%d/", getHost(), getMappedPort(8812)); } @Override @@ -70,19 +70,11 @@ public String getTestQueryString() { return TEST_QUERY; } - public Integer getIlpPort() { - return getMappedPort(ILP_PORT); + public String getIlpUrl() { + return getHost() + ":" + getMappedPort(ILP_PORT); } - public String getPostgresUrl(String databaseName) { - if (!this.isRunning()) { - throw new IllegalStateException("QuestDBContainer should be started first"); - } else { - return this.getPostgresConnectionString() + "/" + databaseName; - } - } - - public String getPostgresConnectionString() { - return String.format("jdbc:postgresql://%s:%d", this.getHost(), this.getMappedPort(8812)); + public String getHttpUrl() { + return "http://" + getHost() + ":" + getMappedPort(REST_PORT); } } From 2160463d55461c76d1e071a5b621fea37c66f2dd Mon Sep 17 00:00:00 2001 From: pwangryn Date: Wed, 19 Oct 2022 09:51:11 +0200 Subject: [PATCH 06/14] Add default commit lag env --- .../org/testcontainers/containers/QuestDBContainer.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java index 6e539094b9d..7dc1a473f93 100644 --- a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java @@ -12,6 +12,8 @@ public class QuestDBContainer extends JdbcDatabaseContainer { private static final String DEFAULT_DATABASE_NAME = "qdb"; + private static final int DEFAULT_COMMIT_LAG_MS = 1000; + private static final String DEFAULT_USERNAME = "admin"; private static final String DEFAULT_PASSWORD = "quest"; @@ -42,9 +44,15 @@ public QuestDBContainer(DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(POSTGRES_PORT, REST_PORT, ILP_PORT); + withCommitLag(DEFAULT_COMMIT_LAG_MS); waitingFor(Wait.forLogMessage("(?i).*A server-main enjoy.*", 1)); } + public QuestDBContainer withCommitLag(int commitLagMillis) { + addEnv("QDB_CAIRO_COMMIT_LAG", String.valueOf(commitLagMillis)); + return this; + } + @Override public String getDriverClassName() { return "org.postgresql.Driver"; From 5ea3f6dd7520ce441a9001ad9600647ae293a1d9 Mon Sep 17 00:00:00 2001 From: pwangryn Date: Wed, 19 Oct 2022 09:55:45 +0200 Subject: [PATCH 07/14] Add more tests for questDB --- modules/questdb/build.gradle | 3 ++ .../junit/questdb/SimpleQuestDBTest.java | 51 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/modules/questdb/build.gradle b/modules/questdb/build.gradle index 628c7b21b2d..dc7df3a9e7e 100644 --- a/modules/questdb/build.gradle +++ b/modules/questdb/build.gradle @@ -7,4 +7,7 @@ dependencies { testImplementation 'org.postgresql:postgresql:42.5.0' testImplementation project(':jdbc-test') testImplementation 'org.assertj:assertj-core:3.23.1' + testImplementation group: 'org.questdb', name: 'questdb', version: '6.4.3-jdk8' + testImplementation 'org.awaitility:awaitility:4.2.0' + testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' } diff --git a/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java index 1de037207ca..e82ba8900b5 100644 --- a/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java +++ b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java @@ -1,17 +1,32 @@ package org.testcontainers.junit.questdb; +import io.questdb.client.Sender; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; import org.junit.Test; import org.testcontainers.QuestDBTestImages; import org.testcontainers.containers.QuestDBContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.sql.ResultSet; import java.sql.SQLException; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class SimpleQuestDBTest extends AbstractContainerDatabaseTest { + + private static final String TABLE_NAME = "mytable"; + @Test public void testSimple() throws SQLException { try (QuestDBContainer questDB = new QuestDBContainer(QuestDBTestImages.QUESTDB_IMAGE)) { @@ -23,4 +38,40 @@ public void testSimple() throws SQLException { assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); } } + + @Test + public void testRest() throws IOException { + try (QuestDBContainer questdb = new QuestDBContainer(QuestDBTestImages.QUESTDB_IMAGE)) { + questdb.start(); + populateByInfluxLineProtocol(questdb, 1_000); + try (CloseableHttpClient client = HttpClientBuilder.create().build()) { + String encodedSql = URLEncoder.encode("select * from " + TABLE_NAME, "UTF-8"); + HttpGet httpGet = new HttpGet(questdb.getHttpUrl() + "/exec?query=" + encodedSql); + await() + .untilAsserted(() -> { + try (CloseableHttpResponse response = client.execute(httpGet)) { + assertEquals(200, response.getStatusLine().getStatusCode()); + String json = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + assertTrue( + "questdb response '" + json + "' does not contain expected count 1000", + json.contains("\"count\":1000") + ); + } + }); + } + } + } + + private static void populateByInfluxLineProtocol(QuestDBContainer questdb, int rowCount) { + try (Sender sender = Sender.builder().address(questdb.getIlpUrl()).build()) { + for (int i = 0; i < rowCount; i++) { + sender + .table(TABLE_NAME) + .symbol("sym", "sym1" + i) + .stringColumn("str", "str1" + i) + .longColumn("long", i) + .atNow(); + } + } + } } From de78c2e682a17be8f2d57226200b96dfcc88ea47 Mon Sep 17 00:00:00 2001 From: pwangryn Date: Wed, 19 Oct 2022 10:39:35 +0200 Subject: [PATCH 08/14] Add more tests for questDB --- .../testcontainers/junit/questdb/SimpleQuestDBTest.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java index e82ba8900b5..026c2bedcbe 100644 --- a/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java +++ b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java @@ -6,6 +6,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; +import org.junit.Assert; import org.junit.Test; import org.testcontainers.QuestDBTestImages; import org.testcontainers.containers.QuestDBContainer; @@ -19,12 +20,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; public class SimpleQuestDBTest extends AbstractContainerDatabaseTest { - private static final String TABLE_NAME = "mytable"; @Test @@ -50,9 +48,9 @@ public void testRest() throws IOException { await() .untilAsserted(() -> { try (CloseableHttpResponse response = client.execute(httpGet)) { - assertEquals(200, response.getStatusLine().getStatusCode()); + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); String json = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); - assertTrue( + Assert.assertTrue( "questdb response '" + json + "' does not contain expected count 1000", json.contains("\"count\":1000") ); From 4b045e8f1d8ad042ce7e33469fd687e8303225e7 Mon Sep 17 00:00:00 2001 From: pwangryn Date: Wed, 19 Oct 2022 10:43:03 +0200 Subject: [PATCH 09/14] Add dependency info to questdb.md --- docs/modules/databases/questdb.md | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/modules/databases/questdb.md b/docs/modules/databases/questdb.md index 4488733ff31..8783dd4b757 100644 --- a/docs/modules/databases/questdb.md +++ b/docs/modules/databases/questdb.md @@ -1,9 +1,29 @@ # QuestDB Module -Testcontainers module for [QuestDB](https://github.com/questdb/questdb). QuestDB is a high-performance, open-source SQL database for applications in financial services, IoT, machine learning, DevOps and observability. +Testcontainers module for [QuestDB](https://github.com/questdb/questdb). QuestDB is a high-performance, open-source SQL +database for applications in financial services, IoT, machine learning, DevOps and observability. -See [Database containers](./index.md) for documentation and usage that is common to all relational database container types. +See [Database containers](./index.md) for documentation and usage that is common to all relational database container +types. ## Adding this module to your project dependencies -[//]: # (placeholder) +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" + +```groovy +testImplementation "org.testcontainers:questdb:{{latest_version}}" +``` + +=== "Maven" + +```xml + + + org.testcontainers + questdb + {{latest_version}} + test + +``` From d832648f40bee4b33cde54ba25869fb296d8067b Mon Sep 17 00:00:00 2001 From: pwangryn Date: Thu, 20 Oct 2022 11:55:09 +0200 Subject: [PATCH 10/14] Use assertj --- .../testcontainers/junit/questdb/SimpleQuestDBTest.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java index 026c2bedcbe..0821be17dfa 100644 --- a/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java +++ b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java @@ -6,7 +6,6 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; -import org.junit.Assert; import org.junit.Test; import org.testcontainers.QuestDBTestImages; import org.testcontainers.containers.QuestDBContainer; @@ -48,12 +47,11 @@ public void testRest() throws IOException { await() .untilAsserted(() -> { try (CloseableHttpResponse response = client.execute(httpGet)) { - Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); String json = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); - Assert.assertTrue( - "questdb response '" + json + "' does not contain expected count 1000", + assertThat( json.contains("\"count\":1000") - ); + ).isTrue(); } }); } From 1c75cabf6d1f07d9ab9483e7d8fa71757fe9df80 Mon Sep 17 00:00:00 2001 From: pwangryn Date: Thu, 20 Oct 2022 12:10:49 +0200 Subject: [PATCH 11/14] Cleanup questdb module classes --- modules/questdb/build.gradle | 2 +- .../containers/QuestDBContainer.java | 33 +++++++++---------- .../containers/QuestDBProvider.java | 4 +-- .../junit/questdb/SimpleQuestDBTest.java | 6 ++-- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/modules/questdb/build.gradle b/modules/questdb/build.gradle index dc7df3a9e7e..79fc0793879 100644 --- a/modules/questdb/build.gradle +++ b/modules/questdb/build.gradle @@ -7,7 +7,7 @@ dependencies { testImplementation 'org.postgresql:postgresql:42.5.0' testImplementation project(':jdbc-test') testImplementation 'org.assertj:assertj-core:3.23.1' - testImplementation group: 'org.questdb', name: 'questdb', version: '6.4.3-jdk8' + testImplementation 'org.questdb:questdb:6.4.3-jdk8' testImplementation 'org.awaitility:awaitility:4.2.0' testImplementation 'org.apache.httpcomponents:httpclient:4.5.13' } diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java index 7dc1a473f93..e2beba38e49 100644 --- a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java @@ -4,11 +4,12 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.DockerImageName; +/** + * Testcontainers implementation for QuestDB. + */ public class QuestDBContainer extends JdbcDatabaseContainer { - public static final String DATABASE_PROVIDER = "postgresql"; - - private static final String DEFAULT_TAG = "6.5.3"; + static final String DATABASE_PROVIDER = "postgresql"; private static final String DEFAULT_DATABASE_NAME = "qdb"; @@ -18,26 +19,18 @@ public class QuestDBContainer extends JdbcDatabaseContainer { private static final String DEFAULT_PASSWORD = "quest"; - public static final Integer POSTGRES_PORT = 8812; - - public static final Integer REST_PORT = 9000; + private static final Integer POSTGRES_PORT = 8812; - public static final Integer ILP_PORT = 9009; + private static final Integer REST_PORT = 9000; - public static final String TEST_QUERY = "SELECT 1"; + private static final Integer ILP_PORT = 9009; - private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("questdb/questdb"); + static final String TEST_QUERY = "SELECT 1"; - @Deprecated - public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart(); - - @Deprecated - public QuestDBContainer() { - this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); - } + static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("questdb/questdb"); public QuestDBContainer(@NonNull String dockerImageName) { - super(dockerImageName); + this(DockerImageName.parse(dockerImageName)); } public QuestDBContainer(DockerImageName dockerImageName) { @@ -60,7 +53,7 @@ public String getDriverClassName() { @Override public String getJdbcUrl() { - return String.format("jdbc:postgresql://%s:%d/", getHost(), getMappedPort(8812)); + return String.format("jdbc:postgresql://%s:%d/%s", getHost(), getMappedPort(8812), getDefaultDatabaseName()); } @Override @@ -78,6 +71,10 @@ public String getTestQueryString() { return TEST_QUERY; } + public String getDefaultDatabaseName() { + return DEFAULT_DATABASE_NAME; + } + public String getIlpUrl() { return getHost() + ":" + getMappedPort(ILP_PORT); } diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java index c8e93c553d4..0d4e9c6eeeb 100644 --- a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBProvider.java @@ -1,7 +1,5 @@ package org.testcontainers.containers; -import org.testcontainers.utility.DockerImageName; - public class QuestDBProvider extends JdbcDatabaseContainerProvider { @Override @@ -11,6 +9,6 @@ public boolean supports(String databaseType) { @Override public JdbcDatabaseContainer newInstance(String tag) { - return new QuestDBContainer(DockerImageName.parse(QuestDBContainer.IMAGE).withTag(tag)); + return new QuestDBContainer(QuestDBContainer.DEFAULT_IMAGE_NAME.withTag(tag)); } } diff --git a/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java index 0821be17dfa..c38524018c3 100644 --- a/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java +++ b/modules/questdb/src/test/java/org/testcontainers/junit/questdb/SimpleQuestDBTest.java @@ -29,7 +29,7 @@ public void testSimple() throws SQLException { try (QuestDBContainer questDB = new QuestDBContainer(QuestDBTestImages.QUESTDB_IMAGE)) { questDB.start(); - ResultSet resultSet = performQuery(questDB, QuestDBContainer.TEST_QUERY); + ResultSet resultSet = performQuery(questDB, questDB.getTestQueryString()); int resultSetInt = resultSet.getInt(1); assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); @@ -49,9 +49,7 @@ public void testRest() throws IOException { try (CloseableHttpResponse response = client.execute(httpGet)) { assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); String json = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); - assertThat( - json.contains("\"count\":1000") - ).isTrue(); + assertThat(json.contains("\"count\":1000")).isTrue(); } }); } From b892e2f9ffb2d97c75a4ca7731b6f659bed0197e Mon Sep 17 00:00:00 2001 From: vangreen Date: Thu, 20 Oct 2022 18:51:12 +0200 Subject: [PATCH 12/14] Remove add commit lag from api --- .../org/testcontainers/containers/QuestDBContainer.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java index e2beba38e49..7ab76ef4b81 100644 --- a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java @@ -37,15 +37,10 @@ public QuestDBContainer(DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); withExposedPorts(POSTGRES_PORT, REST_PORT, ILP_PORT); - withCommitLag(DEFAULT_COMMIT_LAG_MS); + addEnv("QDB_CAIRO_COMMIT_LAG", String.valueOf(DEFAULT_COMMIT_LAG_MS)); waitingFor(Wait.forLogMessage("(?i).*A server-main enjoy.*", 1)); } - public QuestDBContainer withCommitLag(int commitLagMillis) { - addEnv("QDB_CAIRO_COMMIT_LAG", String.valueOf(commitLagMillis)); - return this; - } - @Override public String getDriverClassName() { return "org.postgresql.Driver"; From 5bf65416e1370224f573666e60b5f4f59d77755e Mon Sep 17 00:00:00 2001 From: vangreen Date: Thu, 20 Oct 2022 19:01:40 +0200 Subject: [PATCH 13/14] Override waitUntilContainerStarted in QuestDBContainer --- .../java/org/testcontainers/containers/QuestDBContainer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java index 7ab76ef4b81..c6ab1b79e91 100644 --- a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java @@ -66,6 +66,11 @@ public String getTestQueryString() { return TEST_QUERY; } + @Override + protected void waitUntilContainerStarted() { + getWaitStrategy().waitUntilReady(this); + } + public String getDefaultDatabaseName() { return DEFAULT_DATABASE_NAME; } From 86b4d0f9127e79e6d6da2e43a775f8e596d58f0d Mon Sep 17 00:00:00 2001 From: vangreen Date: Thu, 20 Oct 2022 19:02:52 +0200 Subject: [PATCH 14/14] Add authors in QuestDBContainer --- .../java/org/testcontainers/containers/QuestDBContainer.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java index c6ab1b79e91..dd933dd6c95 100644 --- a/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java +++ b/modules/questdb/src/main/java/org/testcontainers/containers/QuestDBContainer.java @@ -6,6 +6,9 @@ /** * Testcontainers implementation for QuestDB. + * + * @author vangreen + * @author jerrinot */ public class QuestDBContainer extends JdbcDatabaseContainer {