diff --git a/core/src/main/java/org/testcontainers/containers/ContainerLaunchException.java b/core/src/main/java/org/testcontainers/containers/ContainerLaunchException.java
index 9943d9f612b..bf407c16808 100644
--- a/core/src/main/java/org/testcontainers/containers/ContainerLaunchException.java
+++ b/core/src/main/java/org/testcontainers/containers/ContainerLaunchException.java
@@ -9,7 +9,7 @@ public ContainerLaunchException(String message) {
super(message);
}
- public ContainerLaunchException(String message, Exception exception) {
- super(message, exception);
+ public ContainerLaunchException(String message, Throwable cause) {
+ super(message, cause);
}
}
diff --git a/core/src/test/resources/logback-test.xml b/core/src/test/resources/logback-test.xml
index 57a53cdd3aa..5e96a70b244 100644
--- a/core/src/test/resources/logback-test.xml
+++ b/core/src/test/resources/logback-test.xml
@@ -14,10 +14,8 @@
-
-
diff --git a/docs/examples/src/test/resources/logback-test.xml b/docs/examples/src/test/resources/logback-test.xml
index 49da0be9709..62bc2c43d3a 100644
--- a/docs/examples/src/test/resources/logback-test.xml
+++ b/docs/examples/src/test/resources/logback-test.xml
@@ -1,5 +1,4 @@
-
@@ -11,17 +10,4 @@
-
-
-
-
-
-
-
-
-
-
- PROFILER
- DENY
-
diff --git a/examples/disque-job-queue/src/test/resources/logback-test.xml b/examples/disque-job-queue/src/test/resources/logback-test.xml
index c53f381fca5..be4ebaed2c8 100644
--- a/examples/disque-job-queue/src/test/resources/logback-test.xml
+++ b/examples/disque-job-queue/src/test/resources/logback-test.xml
@@ -4,15 +4,11 @@
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
+ %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
-
+
-
-
-
-
-
\ No newline at end of file
+
diff --git a/examples/linked-container/src/test/resources/logback-test.xml b/examples/linked-container/src/test/resources/logback-test.xml
index 23f40bbec32..be4ebaed2c8 100644
--- a/examples/linked-container/src/test/resources/logback-test.xml
+++ b/examples/linked-container/src/test/resources/logback-test.xml
@@ -1,16 +1,14 @@
+
+
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
+ %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
-
+
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/examples/redis-backed-cache-testng/src/test/resources/logback-test.xml b/examples/redis-backed-cache-testng/src/test/resources/logback-test.xml
index c53f381fca5..be4ebaed2c8 100644
--- a/examples/redis-backed-cache-testng/src/test/resources/logback-test.xml
+++ b/examples/redis-backed-cache-testng/src/test/resources/logback-test.xml
@@ -4,15 +4,11 @@
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
+ %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
-
+
-
-
-
-
-
\ No newline at end of file
+
diff --git a/examples/redis-backed-cache/src/test/resources/logback-test.xml b/examples/redis-backed-cache/src/test/resources/logback-test.xml
index c53f381fca5..be4ebaed2c8 100644
--- a/examples/redis-backed-cache/src/test/resources/logback-test.xml
+++ b/examples/redis-backed-cache/src/test/resources/logback-test.xml
@@ -4,15 +4,11 @@
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
+ %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
-
+
-
-
-
-
-
\ No newline at end of file
+
diff --git a/examples/selenium-container/src/test/resources/logback-test.xml b/examples/selenium-container/src/test/resources/logback-test.xml
index c53f381fca5..be4ebaed2c8 100644
--- a/examples/selenium-container/src/test/resources/logback-test.xml
+++ b/examples/selenium-container/src/test/resources/logback-test.xml
@@ -4,15 +4,11 @@
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
+ %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
-
+
-
-
-
-
-
\ No newline at end of file
+
diff --git a/examples/spock/src/test/resources/logback-test.xml b/examples/spock/src/test/resources/logback-test.xml
index 6e7cfd092de..535e406fc13 100644
--- a/examples/spock/src/test/resources/logback-test.xml
+++ b/examples/spock/src/test/resources/logback-test.xml
@@ -12,16 +12,5 @@
-
-
-
-
-
-
-
-
-
- PROFILER
- DENY
-
+
diff --git a/examples/spring-boot/src/test/resources/logback-test.xml b/examples/spring-boot/src/test/resources/logback-test.xml
index 86c4c861a78..5431cb6200b 100644
--- a/examples/spring-boot/src/test/resources/logback-test.xml
+++ b/examples/spring-boot/src/test/resources/logback-test.xml
@@ -1,8 +1,3 @@
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/modules/cassandra/src/test/resources/logback-test.xml b/modules/cassandra/src/test/resources/logback-test.xml
index fc48b14c7de..535e406fc13 100644
--- a/modules/cassandra/src/test/resources/logback-test.xml
+++ b/modules/cassandra/src/test/resources/logback-test.xml
@@ -13,5 +13,4 @@
-
-
\ No newline at end of file
+
diff --git a/modules/couchbase/src/test/resources/logback-test.xml b/modules/couchbase/src/test/resources/logback-test.xml
index d163f3ececb..535e406fc13 100644
--- a/modules/couchbase/src/test/resources/logback-test.xml
+++ b/modules/couchbase/src/test/resources/logback-test.xml
@@ -8,18 +8,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
+
diff --git a/modules/dynalite/src/test/resources/logback-test.xml b/modules/dynalite/src/test/resources/logback-test.xml
index 5d27573a3cb..535e406fc13 100644
--- a/modules/dynalite/src/test/resources/logback-test.xml
+++ b/modules/dynalite/src/test/resources/logback-test.xml
@@ -8,17 +8,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
diff --git a/modules/elasticsearch/src/test/resources/logback-test.xml b/modules/elasticsearch/src/test/resources/logback-test.xml
index 6d3eb183989..535e406fc13 100644
--- a/modules/elasticsearch/src/test/resources/logback-test.xml
+++ b/modules/elasticsearch/src/test/resources/logback-test.xml
@@ -8,10 +8,9 @@
-
+
-
-
+
diff --git a/modules/influxdb/src/test/resources/logback-test.xml b/modules/influxdb/src/test/resources/logback-test.xml
index e8f35ff1c79..535e406fc13 100644
--- a/modules/influxdb/src/test/resources/logback-test.xml
+++ b/modules/influxdb/src/test/resources/logback-test.xml
@@ -8,17 +8,9 @@
-
+
-
-
-
-
-
-
-
-
-
+
diff --git a/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java b/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java
index a01146fe7a3..7230759382d 100644
--- a/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java
+++ b/modules/jdbc-test/src/test/java/org/testcontainers/junit/AbstractContainerDatabaseTest.java
@@ -2,15 +2,20 @@
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
+import org.junit.After;
import org.testcontainers.containers.JdbcDatabaseContainer;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
+import java.util.HashSet;
+import java.util.Set;
abstract class AbstractContainerDatabaseTest {
+ private final Set datasourcesForCleanup = new HashSet<>();
+
ResultSet performQuery(JdbcDatabaseContainer container, String sql) throws SQLException {
DataSource ds = getDataSource(container);
Statement statement = ds.getConnection().createStatement();
@@ -26,7 +31,16 @@ DataSource getDataSource(JdbcDatabaseContainer container) {
hikariConfig.setJdbcUrl(container.getJdbcUrl());
hikariConfig.setUsername(container.getUsername());
hikariConfig.setPassword(container.getPassword());
+ hikariConfig.setDriverClassName(container.getDriverClassName());
+
+ final HikariDataSource dataSource = new HikariDataSource(hikariConfig);
+ datasourcesForCleanup.add(dataSource);
+
+ return dataSource;
+ }
- return new HikariDataSource(hikariConfig);
+ @After
+ public void teardown() {
+ datasourcesForCleanup.forEach(HikariDataSource::close);
}
}
diff --git a/modules/jdbc-test/src/test/resources/logback-test.xml b/modules/jdbc-test/src/test/resources/logback-test.xml
index b0f6b00e3e0..535e406fc13 100644
--- a/modules/jdbc-test/src/test/resources/logback-test.xml
+++ b/modules/jdbc-test/src/test/resources/logback-test.xml
@@ -8,18 +8,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
+
diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java
index e480070168f..36a6461aa74 100644
--- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java
+++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java
@@ -1,11 +1,8 @@
package org.testcontainers.containers;
-import lombok.NonNull;
import com.github.dockerjava.api.command.InspectContainerResponse;
+import lombok.NonNull;
import org.jetbrains.annotations.NotNull;
-import org.rnorth.ducttape.ratelimits.RateLimiter;
-import org.rnorth.ducttape.ratelimits.RateLimiterBuilder;
-import org.rnorth.ducttape.unreliables.Unreliables;
import org.testcontainers.containers.traits.LinkableContainer;
import org.testcontainers.delegate.DatabaseDelegate;
import org.testcontainers.ext.ScriptUtils;
@@ -19,7 +16,6 @@
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
/**
* Base class for containers that expose a JDBC connection
@@ -33,11 +29,6 @@ public abstract class JdbcDatabaseContainer parameters = new HashMap<>();
- private static final RateLimiter DB_CONNECT_RATE_LIMIT = RateLimiterBuilder.newBuilder()
- .withRate(10, TimeUnit.SECONDS)
- .withConstantThroughput()
- .build();
-
private int startupTimeoutSeconds = 120;
private int connectTimeoutSeconds = 120;
@@ -123,26 +114,39 @@ public SELF withInitScript(String initScriptPath) {
@Override
protected void waitUntilContainerStarted() {
- // Repeatedly try and open a connection to the DB and execute a test query
-
logger().info("Waiting for database connection to become available at {} using query '{}'", getJdbcUrl(), getTestQueryString());
- Unreliables.retryUntilSuccess(getStartupTimeoutSeconds(), TimeUnit.SECONDS, () -> {
- if (!isRunning()) {
- throw new ContainerLaunchException("Container failed to start");
- }
-
- try (Connection connection = createConnection("")) {
- boolean success = connection.createStatement().execute(JdbcDatabaseContainer.this.getTestQueryString());
-
- if (success) {
- logger().info("Obtained a connection to container ({})", JdbcDatabaseContainer.this.getJdbcUrl());
- return null;
- } else {
- throw new SQLException("Failed to execute test query");
+ // Repeatedly try and open a connection to the DB and execute a test query
+ long start = System.currentTimeMillis();
+ try {
+ while (System.currentTimeMillis() < start + (1000 * startupTimeoutSeconds)) {
+ try {
+ if (!isRunning()) {
+ Thread.sleep(100L);
+ continue; // Don't attempt to connect yet
+ }
+
+ try (Connection connection = createConnection("")) {
+ boolean testQuerySucceeded = connection.createStatement().execute(this.getTestQueryString());
+ if (testQuerySucceeded) {
+ break;
+ }
+ }
+ } catch (NoDriverFoundException e) {
+ // we explicitly want this exception to fail fast without retries
+ throw e;
+ } catch (Exception e) {
+ // ignore so that we can try again
+ logger().debug("Failure when trying test query", e);
+ Thread.sleep(100L);
}
}
- });
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new ContainerLaunchException("Container startup wait was interrupted", e);
+ }
+
+ logger().info("Container is started (JDBC URL: {})", JdbcDatabaseContainer.this.getJdbcUrl());
}
@Override
@@ -155,14 +159,14 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) {
*
* @return a JDBC Driver
*/
- public Driver getJdbcDriverInstance() {
+ public Driver getJdbcDriverInstance() throws NoDriverFoundException {
synchronized (DRIVER_LOAD_MUTEX) {
if (driver == null) {
try {
driver = (Driver) Class.forName(this.getDriverClassName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
- throw new RuntimeException("Could not get Driver", e);
+ throw new NoDriverFoundException("Could not get Driver", e);
}
}
}
@@ -178,7 +182,7 @@ public Driver getJdbcDriverInstance() {
* @return a Connection
* @throws SQLException if there is a repeated failure to create the connection
*/
- public Connection createConnection(String queryString) throws SQLException {
+ public Connection createConnection(String queryString) throws SQLException, NoDriverFoundException {
final Properties info = new Properties();
info.put("user", this.getUsername());
info.put("password", this.getPassword());
@@ -186,13 +190,24 @@ public Connection createConnection(String queryString) throws SQLException {
final Driver jdbcDriverInstance = getJdbcDriverInstance();
+ SQLException lastException = null;
try {
- return Unreliables.retryUntilSuccess(getConnectTimeoutSeconds(), TimeUnit.SECONDS, () ->
- DB_CONNECT_RATE_LIMIT.getWhenReady(() ->
- jdbcDriverInstance.connect(url, info)));
- } catch (Exception e) {
- throw new SQLException("Could not create new connection", e);
+ long start = System.currentTimeMillis();
+ // give up if we hit the time limit or the container stops running for some reason
+ while (System.currentTimeMillis() < start + (1000 * connectTimeoutSeconds) && isRunning()) {
+ try {
+ logger().debug("Trying to create JDBC connection using {} to {} with properties: {}", driver.getClass().getName(), url, info);
+
+ return jdbcDriverInstance.connect(url, info);
+ } catch (SQLException e) {
+ lastException = e;
+ Thread.sleep(100L);
+ }
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
}
+ throw new SQLException("Could not create new connection", lastException);
}
/**
@@ -256,4 +271,10 @@ protected int getConnectTimeoutSeconds() {
protected DatabaseDelegate getDatabaseDelegate() {
return new JdbcDatabaseDelegate(this, "");
}
+
+ public static class NoDriverFoundException extends RuntimeException {
+ public NoDriverFoundException(String message, Throwable e) {
+ super(message, e);
+ }
+ }
}
diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java
new file mode 100644
index 00000000000..38ae38095eb
--- /dev/null
+++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java
@@ -0,0 +1,86 @@
+package org.testcontainers.jdbc;
+
+import com.google.common.base.Throwables;
+import org.junit.Test;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals;
+import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue;
+import static org.rnorth.visibleassertions.VisibleAssertions.fail;
+
+public class MissingJdbcDriverTest {
+
+ @Test
+ public void shouldFailFastIfNoDriverFound() {
+
+ final MissingDriverContainer container = new MissingDriverContainer();
+
+ try {
+ container.start();
+ fail("The container is expected to fail to start");
+ } catch (Exception e) {
+ final Throwable rootCause = Throwables.getRootCause(e);
+ assertTrue("ClassNotFoundException is the root cause", rootCause instanceof ClassNotFoundException);
+ } finally {
+ container.stop();
+ }
+
+ assertEquals("only one connection attempt should have been made", 1, container.getConnectionAttempts());
+ }
+
+ /**
+ * Container class for the purposes of testing, with a known non-existent driver
+ */
+ static class MissingDriverContainer extends JdbcDatabaseContainer {
+ private final AtomicInteger connectionAttempts = new AtomicInteger();
+
+ MissingDriverContainer() {
+ super("mysql:5.7.22");
+ withEnv("MYSQL_ROOT_PASSWORD", "test");
+ withExposedPorts(3306);
+ }
+
+ @Override
+ public String getDriverClassName() {
+ return "nonexistent.ClassName";
+ }
+
+ @Override
+ public String getJdbcUrl() {
+ return "";
+ }
+
+ @Override
+ public String getUsername() {
+ return "root";
+ }
+
+ @Override
+ public String getPassword() {
+ return "test";
+ }
+
+ @Override
+ protected String getTestQueryString() {
+ return "";
+ }
+
+ @Override
+ public Connection createConnection(String queryString) throws SQLException, NoDriverFoundException {
+ connectionAttempts.incrementAndGet(); //
+ return super.createConnection(queryString);
+ }
+
+ /**
+ * test window
+ * @return how many times a connection was attempted
+ */
+ int getConnectionAttempts() {
+ return connectionAttempts.get();
+ }
+ }
+}
diff --git a/modules/jdbc/src/test/resources/logback-test.xml b/modules/jdbc/src/test/resources/logback-test.xml
new file mode 100644
index 00000000000..535e406fc13
--- /dev/null
+++ b/modules/jdbc/src/test/resources/logback-test.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
+
+
+
+
+
+
+
+
+
diff --git a/modules/junit-jupiter/src/test/resources/logback-test.xml b/modules/junit-jupiter/src/test/resources/logback-test.xml
index 1d1a7695915..535e406fc13 100644
--- a/modules/junit-jupiter/src/test/resources/logback-test.xml
+++ b/modules/junit-jupiter/src/test/resources/logback-test.xml
@@ -8,8 +8,9 @@
-
+
-
\ No newline at end of file
+
+
diff --git a/modules/kafka/src/test/resources/logback-test.xml b/modules/kafka/src/test/resources/logback-test.xml
index 7bd6a94d827..535e406fc13 100644
--- a/modules/kafka/src/test/resources/logback-test.xml
+++ b/modules/kafka/src/test/resources/logback-test.xml
@@ -13,6 +13,4 @@
-
-
-
\ No newline at end of file
+
diff --git a/modules/localstack/src/test/resources/logback-test.xml b/modules/localstack/src/test/resources/logback-test.xml
index cc69fdf0ce0..535e406fc13 100644
--- a/modules/localstack/src/test/resources/logback-test.xml
+++ b/modules/localstack/src/test/resources/logback-test.xml
@@ -8,20 +8,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
diff --git a/modules/neo4j/src/test/resources/logback-test.xml b/modules/neo4j/src/test/resources/logback-test.xml
index 7bd6a94d827..535e406fc13 100644
--- a/modules/neo4j/src/test/resources/logback-test.xml
+++ b/modules/neo4j/src/test/resources/logback-test.xml
@@ -13,6 +13,4 @@
-
-
-
\ No newline at end of file
+
diff --git a/modules/nginx/src/test/resources/logback-test.xml b/modules/nginx/src/test/resources/logback-test.xml
index b0f6b00e3e0..535e406fc13 100644
--- a/modules/nginx/src/test/resources/logback-test.xml
+++ b/modules/nginx/src/test/resources/logback-test.xml
@@ -8,18 +8,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
+
diff --git a/modules/oracle-xe/src/test/resources/logback-test.xml b/modules/oracle-xe/src/test/resources/logback-test.xml
index b0f6b00e3e0..535e406fc13 100644
--- a/modules/oracle-xe/src/test/resources/logback-test.xml
+++ b/modules/oracle-xe/src/test/resources/logback-test.xml
@@ -8,18 +8,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
+
diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java
index eb7b78b1864..a9429210261 100644
--- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java
+++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java
@@ -59,7 +59,8 @@ public String getDriverClassName() {
@Override
public String getJdbcUrl() {
- return "jdbc:postgresql://" + getContainerIpAddress() + ":" + getMappedPort(POSTGRESQL_PORT) + "/" + databaseName;
+ // Disable Postgres driver use of java.util.logging to reduce noise at startup time
+ return "jdbc:postgresql://" + getContainerIpAddress() + ":" + getMappedPort(POSTGRESQL_PORT) + "/" + databaseName + "?loggerLevel=OFF";
}
@Override
diff --git a/modules/pulsar/src/test/resources/logback-test.xml b/modules/pulsar/src/test/resources/logback-test.xml
index 7bd6a94d827..535e406fc13 100644
--- a/modules/pulsar/src/test/resources/logback-test.xml
+++ b/modules/pulsar/src/test/resources/logback-test.xml
@@ -13,6 +13,4 @@
-
-
-
\ No newline at end of file
+
diff --git a/modules/selenium/src/test/resources/logback-test.xml b/modules/selenium/src/test/resources/logback-test.xml
index b0f6b00e3e0..535e406fc13 100644
--- a/modules/selenium/src/test/resources/logback-test.xml
+++ b/modules/selenium/src/test/resources/logback-test.xml
@@ -8,18 +8,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
+
diff --git a/modules/spock/src/test/resources/logback-test.xml b/modules/spock/src/test/resources/logback-test.xml
index 1d1a7695915..535e406fc13 100644
--- a/modules/spock/src/test/resources/logback-test.xml
+++ b/modules/spock/src/test/resources/logback-test.xml
@@ -8,8 +8,9 @@
-
+
-
\ No newline at end of file
+
+
diff --git a/modules/vault/src/test/resources/logback-test.xml b/modules/vault/src/test/resources/logback-test.xml
index 5d27573a3cb..535e406fc13 100644
--- a/modules/vault/src/test/resources/logback-test.xml
+++ b/modules/vault/src/test/resources/logback-test.xml
@@ -8,17 +8,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+