From e5fe603fec9f576641941e91d616e001f87282bb Mon Sep 17 00:00:00 2001 From: Marios Trivyzas Date: Mon, 20 Mar 2023 20:57:54 +0200 Subject: [PATCH] Use two variants, one with CrateDB driver, one with PGSQL --- docs/modules/databases/cratedb.md | 1 + docs/modules/databases/jdbc.md | 2 +- .../containers/CrateDBContainer.java | 6 +- .../containers/CrateDBContainerProvider.java | 2 +- .../CrateDBLegacyDriverContainer.java | 31 +++++++ .../CrateDBLegacyDriverContainerProvider.java | 19 +++++ ...s.containers.JdbcDatabaseContainerProvider | 1 + .../containers/CrateDBConnectionURLTest.java | 2 +- .../CrateDBLegacyDriverConnectionURLTest.java | 84 +++++++++++++++++++ .../jdbc/cratedb/CrateDBJDBCDriverTest.java | 4 + .../SimpleCrateDBLegacyDriverTest.java | 76 +++++++++++++++++ 11 files changed, 222 insertions(+), 6 deletions(-) create mode 100644 modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBLegacyDriverContainer.java create mode 100644 modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBLegacyDriverContainerProvider.java create mode 100644 modules/cratedb/src/test/java/org/testcontainers/containers/CrateDBLegacyDriverConnectionURLTest.java create mode 100644 modules/cratedb/src/test/java/org/testcontainers/junit/cratedb/SimpleCrateDBLegacyDriverTest.java diff --git a/docs/modules/databases/cratedb.md b/docs/modules/databases/cratedb.md index addf2b5f268..8e9a9e52ccc 100644 --- a/docs/modules/databases/cratedb.md +++ b/docs/modules/databases/cratedb.md @@ -22,5 +22,6 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: !!! 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. + If you'd like to use the PostgreSQL JDBC Driver, use `org.postgresql:postgresql`, if you'd like to use CrateDB's JDBC driver, use `io.crate:crate-jdbc`. diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index 0a753668d83..d98fb8062b9 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -33,7 +33,7 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database #### Using CrateDB -`jdbc:tc:crate:5.2.3//localhost:5432/crate` +`jdbc:tc:cratedb:5.2.3//localhost:5432/crate` or `jdbc:tc:cratedb_legacy:5.2.3//localhost:5432/crate` #### Using PostgreSQL diff --git a/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBContainer.java b/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBContainer.java index 2b0fbf1c13d..19387973ee4 100644 --- a/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBContainer.java +++ b/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBContainer.java @@ -14,7 +14,7 @@ public class CrateDBContainer> extends JdbcD public static final String DEFAULT_TAG = "latest"; - private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("crate"); + protected static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("crate"); public static final Integer CRATEDB_PG_PORT = 5432; @@ -61,14 +61,14 @@ protected Set getLivenessCheckPorts() { @Override public String getDriverClassName() { - return "io.crate.client.jdbc.CrateDriver"; + return "org.postgresql.Driver"; } @Override public String getJdbcUrl() { String additionalUrlParams = constructUrlParameters("?", "&"); return ( - "jdbc:crate://" + + "jdbc:postgresql://" + getHost() + ":" + getMappedPort(CRATEDB_PG_PORT) + diff --git a/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBContainerProvider.java b/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBContainerProvider.java index da2872ccf94..a390a68c241 100644 --- a/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBContainerProvider.java +++ b/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBContainerProvider.java @@ -4,7 +4,7 @@ import org.testcontainers.utility.DockerImageName; /** - * Factory for CrateDB containers using its JDBC driver. + * Factory for CrateDB containers using PostgreSQL JDBC driver. */ public class CrateDBContainerProvider extends JdbcDatabaseContainerProvider { diff --git a/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBLegacyDriverContainer.java b/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBLegacyDriverContainer.java new file mode 100644 index 00000000000..e2478bb2330 --- /dev/null +++ b/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBLegacyDriverContainer.java @@ -0,0 +1,31 @@ +package org.testcontainers.containers; + +import org.testcontainers.utility.DockerImageName; + +public class CrateDBLegacyDriverContainer> extends CrateDBContainer { + + public static final String NAME = "cratedb_legacy"; + + public CrateDBLegacyDriverContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + } + + @Override + public String getDriverClassName() { + return "io.crate.client.jdbc.CrateDriver"; + } + + @Override + public String getJdbcUrl() { + String additionalUrlParams = constructUrlParameters("?", "&"); + return ( + "jdbc:crate://" + + getHost() + + ":" + + getMappedPort(CRATEDB_PG_PORT) + + "/" + + getDatabaseName() + + additionalUrlParams + ); + } +} diff --git a/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBLegacyDriverContainerProvider.java b/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBLegacyDriverContainerProvider.java new file mode 100644 index 00000000000..b616768aedd --- /dev/null +++ b/modules/cratedb/src/main/java/org/testcontainers/containers/CrateDBLegacyDriverContainerProvider.java @@ -0,0 +1,19 @@ +package org.testcontainers.containers; + +import org.testcontainers.utility.DockerImageName; + +/** + * Factory for CrateDB containers using its own legacy JDBC driver. + */ +public class CrateDBLegacyDriverContainerProvider extends JdbcDatabaseContainerProvider { + + @Override + public boolean supports(String databaseType) { + return databaseType.equals(CrateDBLegacyDriverContainer.NAME); + } + + @Override + public JdbcDatabaseContainer newInstance(String tag) { + return new CrateDBLegacyDriverContainer<>(DockerImageName.parse(CrateDBContainer.IMAGE).withTag(tag)); + } +} diff --git a/modules/cratedb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/cratedb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider index e0a3c27a029..67745735f2b 100644 --- a/modules/cratedb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider +++ b/modules/cratedb/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider @@ -1 +1,2 @@ org.testcontainers.containers.CrateDBContainerProvider +org.testcontainers.containers.CrateDBLegacyDriverContainerProvider diff --git a/modules/cratedb/src/test/java/org/testcontainers/containers/CrateDBConnectionURLTest.java b/modules/cratedb/src/test/java/org/testcontainers/containers/CrateDBConnectionURLTest.java index b0c0c078f75..f665304920d 100644 --- a/modules/cratedb/src/test/java/org/testcontainers/containers/CrateDBConnectionURLTest.java +++ b/modules/cratedb/src/test/java/org/testcontainers/containers/CrateDBConnectionURLTest.java @@ -78,7 +78,7 @@ public NoParamsUrlCrateDBContainer() { @Override public String getJdbcUrl() { - return "jdbc:crate://host:port/database"; + return "jdbc:postgresql://host:port/database"; } } } diff --git a/modules/cratedb/src/test/java/org/testcontainers/containers/CrateDBLegacyDriverConnectionURLTest.java b/modules/cratedb/src/test/java/org/testcontainers/containers/CrateDBLegacyDriverConnectionURLTest.java new file mode 100644 index 00000000000..624b39356c0 --- /dev/null +++ b/modules/cratedb/src/test/java/org/testcontainers/containers/CrateDBLegacyDriverConnectionURLTest.java @@ -0,0 +1,84 @@ +package org.testcontainers.containers; + +import org.junit.Test; +import org.testcontainers.CrateDBTestImages; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +public class CrateDBLegacyDriverConnectionURLTest { + + @Test + public void shouldCorrectlyAppendQueryString() { + CrateDBContainer cratedb = new FixedJdbcUrlCrateDBContainer(); + String connectionUrl = cratedb.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); + String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); + + assertThat(queryString) + .as("Query String contains expected params") + .contains("?stringtype=unspecified&stringtype=unspecified"); + assertThat(queryString.indexOf('?')).as("Query String starts with '?'").isZero(); + assertThat(queryString.substring(1)).as("Query String does not contain extra '?'").doesNotContain("?"); + } + + @Test + public void shouldCorrectlyAppendQueryStringWhenNoBaseParams() { + CrateDBContainer cratedb = new NoParamsUrlCrateDBContainer(); + String connectionUrl = cratedb.constructUrlForConnection("?stringtype=unspecified&stringtype=unspecified"); + String queryString = connectionUrl.substring(connectionUrl.indexOf('?')); + + assertThat(queryString) + .as("Query String contains expected params") + .contains("?stringtype=unspecified&stringtype=unspecified"); + assertThat(queryString.indexOf('?')).as("Query String starts with '?'").isZero(); + assertThat(queryString.substring(1)).as("Query String does not contain extra '?'").doesNotContain("?"); + } + + @Test + public void shouldReturnOriginalURLWhenEmptyQueryString() { + CrateDBContainer cratedb = new FixedJdbcUrlCrateDBContainer(); + String connectionUrl = cratedb.constructUrlForConnection(""); + + assertThat(cratedb.getJdbcUrl()).as("Query String remains unchanged").isEqualTo(connectionUrl); + } + + @Test + public void shouldRejectInvalidQueryString() { + assertThat( + catchThrowable(() -> { + new NoParamsUrlCrateDBContainer().constructUrlForConnection("stringtype=unspecified"); + }) + ) + .as("Fails when invalid query string provided") + .isInstanceOf(IllegalArgumentException.class); + } + + static class FixedJdbcUrlCrateDBContainer extends CrateDBLegacyDriverContainer { + + public FixedJdbcUrlCrateDBContainer() { + super(CrateDBTestImages.CRATEDB_TEST_IMAGE); + } + + @Override + public String getHost() { + return "localhost"; + } + + @Override + public Integer getMappedPort(int originalPort) { + return 5432; + } + } + + static class NoParamsUrlCrateDBContainer extends CrateDBLegacyDriverContainer { + + public NoParamsUrlCrateDBContainer() { + super(CrateDBTestImages.CRATEDB_TEST_IMAGE); + } + + @Override + public String getJdbcUrl() { + return "jdbc:crate://host:port/database"; + } + } +} diff --git a/modules/cratedb/src/test/java/org/testcontainers/jdbc/cratedb/CrateDBJDBCDriverTest.java b/modules/cratedb/src/test/java/org/testcontainers/jdbc/cratedb/CrateDBJDBCDriverTest.java index 54ef9704ac5..e89e41d5868 100644 --- a/modules/cratedb/src/test/java/org/testcontainers/jdbc/cratedb/CrateDBJDBCDriverTest.java +++ b/modules/cratedb/src/test/java/org/testcontainers/jdbc/cratedb/CrateDBJDBCDriverTest.java @@ -15,6 +15,10 @@ public static Iterable data() { return Arrays.asList( new Object[][] { { "jdbc:tc:cratedb:5.2.3://hostname/crate?user=crate&password=somepwd", EnumSet.noneOf(Options.class) }, + { + "jdbc:tc:cratedb_legacy:5.2.3://hostname/crate?user=crate&password=somepwd", + EnumSet.noneOf(Options.class), + }, } ); } diff --git a/modules/cratedb/src/test/java/org/testcontainers/junit/cratedb/SimpleCrateDBLegacyDriverTest.java b/modules/cratedb/src/test/java/org/testcontainers/junit/cratedb/SimpleCrateDBLegacyDriverTest.java new file mode 100644 index 00000000000..7bcd2777cad --- /dev/null +++ b/modules/cratedb/src/test/java/org/testcontainers/junit/cratedb/SimpleCrateDBLegacyDriverTest.java @@ -0,0 +1,76 @@ +package org.testcontainers.junit.cratedb; + +import org.junit.Test; +import org.testcontainers.CrateDBTestImages; +import org.testcontainers.containers.CrateDBContainer; +import org.testcontainers.containers.CrateDBLegacyDriverContainer; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.logging.Level; +import java.util.logging.LogManager; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SimpleCrateDBLegacyDriverTest extends AbstractContainerDatabaseTest { + static { + // Postgres JDBC driver uses JUL; disable it to avoid annoying, irrelevant, stderr logs during connection testing + LogManager.getLogManager().getLogger("").setLevel(Level.OFF); + } + + @Test + public void testSimple() throws SQLException { + try ( + CrateDBLegacyDriverContainer cratedb = new CrateDBLegacyDriverContainer<>( + CrateDBTestImages.CRATEDB_TEST_IMAGE + ) + ) { + cratedb.start(); + + ResultSet resultSet = performQuery(cratedb, "SELECT 1"); + int resultSetInt = resultSet.getInt(1); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + assertHasCorrectExposedAndLivenessCheckPorts(cratedb); + } + } + + @Test + public void testCommandOverride() throws SQLException { + try ( + CrateDBContainer cratedb = new CrateDBLegacyDriverContainer<>(CrateDBTestImages.CRATEDB_TEST_IMAGE) + .withCommand("crate -C cluster.name=testcontainers") + ) { + cratedb.start(); + + ResultSet resultSet = performQuery(cratedb, "select name from sys.cluster"); + String result = resultSet.getString(1); + assertThat(result).as("cluster name should be overriden").isEqualTo("testcontainers"); + } + } + + @Test + public void testExplicitInitScript() throws SQLException { + try ( + CrateDBContainer cratedb = new CrateDBLegacyDriverContainer<>(CrateDBTestImages.CRATEDB_TEST_IMAGE) + .withInitScript("somepath/init_cratedb.sql") + ) { + cratedb.start(); + + ResultSet resultSet = performQuery(cratedb, "SELECT foo FROM bar"); + + String firstColumnValue = resultSet.getString(1); + assertThat(firstColumnValue).as("Value from init script should equal real value").isEqualTo("hello world"); + } + } + + private void assertHasCorrectExposedAndLivenessCheckPorts(CrateDBLegacyDriverContainer cratedb) { + assertThat(cratedb.getExposedPorts()) + .containsExactly(CrateDBContainer.CRATEDB_PG_PORT, CrateDBContainer.CRATEDB_HTTP_PORT); + assertThat(cratedb.getLivenessCheckPortNumbers()) + .containsExactlyInAnyOrder( + cratedb.getMappedPort(CrateDBContainer.CRATEDB_PG_PORT), + cratedb.getMappedPort(CrateDBContainer.CRATEDB_HTTP_PORT) + ); + } +}