From 356f8d85d1d38134baaf7d38c7625584ae896c11 Mon Sep 17 00:00:00 2001 From: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com> Date: Thu, 24 Sep 2026 23:17:34 +0900 Subject: [PATCH] Read test query results before reporting JDBC container as ready --- .../containers/JdbcDatabaseContainer.java | 8 ++++ .../containers/JdbcDatabaseContainerTest.java | 46 +++++++++++++++++++ 2 files changed, 54 insertions(+) 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 cf6c995528f..d711e4c448b 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -15,6 +15,7 @@ import java.sql.Connection; import java.sql.Driver; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; @@ -192,6 +193,13 @@ protected void waitUntilContainerStarted() { try (Connection connection = createConnection(""); Statement statement = connection.createStatement()) { boolean testQuerySucceeded = statement.execute(this.getTestQueryString()); if (testQuerySucceeded) { + // Some databases (e.g. Trino) accept the query but only fail once its results are fetched, + // so the database is only considered ready after the results have been read successfully + try (ResultSet resultSet = statement.getResultSet()) { + if (resultSet != null) { + while (resultSet.next()) {} + } + } return; } } catch (NoDriverFoundException e) { diff --git a/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java b/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java index ca41c3f5d1c..8076c56eb5b 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/containers/JdbcDatabaseContainerTest.java @@ -5,10 +5,15 @@ import org.slf4j.Logger; import java.sql.Connection; +import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; +import java.util.concurrent.atomic.AtomicInteger; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; class JdbcDatabaseContainerTest { @@ -20,6 +25,47 @@ void anExceptionIsThrownIfJdbcIsNotAvailable() { assertThatExceptionOfType(IllegalStateException.class).isThrownBy(jdbcContainer::waitUntilContainerStarted); } + @Test + void testQueryIsRetriedIfReadingItsResultsFails() { + // Some databases (e.g. Trino) accept the test query but only fail once its results are fetched + FailingResultSetJdbcDatabaseContainerStub jdbcContainer = new FailingResultSetJdbcDatabaseContainerStub(); + jdbcContainer.withStartupTimeoutSeconds(5); + + jdbcContainer.waitUntilContainerStarted(); + + assertThat(jdbcContainer.connectionAttempts).hasValue(2); + } + + static class FailingResultSetJdbcDatabaseContainerStub extends JdbcDatabaseContainerStub { + + private final AtomicInteger connectionAttempts = new AtomicInteger(); + + FailingResultSetJdbcDatabaseContainerStub() { + super("mysql:latest"); + } + + @Override + protected String getTestQueryString() { + return "SELECT 1"; + } + + @Override + public Connection createConnection(String queryString) throws SQLException, NoDriverFoundException { + ResultSet resultSet = mock(ResultSet.class); + if (connectionAttempts.incrementAndGet() == 1) { + when(resultSet.next()).thenThrow(new SQLException("No nodes available to run query")); + } else { + when(resultSet.next()).thenReturn(true, false); + } + Statement statement = mock(Statement.class); + when(statement.execute("SELECT 1")).thenReturn(true); + when(statement.getResultSet()).thenReturn(resultSet); + Connection connection = mock(Connection.class); + when(connection.createStatement()).thenReturn(statement); + return connection; + } + } + static class JdbcDatabaseContainerStub extends JdbcDatabaseContainer { public JdbcDatabaseContainerStub(@NonNull String dockerImageName) {