Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve log messages when database container test query fails #3015

Merged
merged 8 commits into from
May 19, 2021
1 change: 1 addition & 0 deletions modules/jdbc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ dependencies {
testCompile 'org.apache.tomcat:tomcat-jdbc:9.0.36'
testCompile 'com.zaxxer:HikariCP-java6:2.3.13'
testCompile 'com.googlecode.junit-toolbox:junit-toolbox:2.4'
testCompile 'org.assertj:assertj-core:3.16.1'
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.testcontainers.containers;

import com.github.dockerjava.api.command.InspectContainerResponse;
import java.sql.Statement;
import lombok.NonNull;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.testcontainers.containers.traits.LinkableContainer;
Expand Down Expand Up @@ -122,25 +124,23 @@ public SELF withInitScript(String initScriptPath) {
return self();
}

@SneakyThrows(InterruptedException.class)
@Override
protected void waitUntilContainerStarted() {
logger().info("Waiting for database connection to become available at {} using query '{}'", getJdbcUrl(), getTestQueryString());

// 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;
}
while (System.currentTimeMillis() < start + (1000 * startupTimeoutSeconds)) {
vcvitaly marked this conversation as resolved.
Show resolved Hide resolved
if (!isRunning()) {
Thread.sleep(100L);
} else {
try (Statement statement = createConnection("").createStatement()) {
boolean testQuerySucceeded = statement.execute(this.getTestQueryString());
if (testQuerySucceeded) {
logger().info("Container is started (JDBC URL: {})", JdbcDatabaseContainer.this.getJdbcUrl());
return;
}
} catch (NoDriverFoundException e) {
// we explicitly want this exception to fail fast without retries
Expand All @@ -151,12 +151,12 @@ protected void waitUntilContainerStarted() {
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());
throw new IllegalStateException(
String.format("Container is started, but cannot be accessed by (JDBC URL: %s), please check container logs",
JdbcDatabaseContainer.this.getJdbcUrl())
rnorth marked this conversation as resolved.
Show resolved Hide resolved
);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.testcontainers.containers;

import java.sql.Connection;
import java.sql.SQLException;
import lombok.NonNull;
import org.junit.Test;
import org.slf4j.Logger;

import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.mock;

public class JdbcDatabaseContainerTest {

@Test
public void anExceptionIsThrownIfJdbcIsNotAvailable() {
JdbcDatabaseContainer<?> jdbcContainer = new JdbcDatabaseContainerStub("mysql:latest")
.withStartupTimeoutSeconds(1);

assertThatExceptionOfType(IllegalStateException.class).isThrownBy(jdbcContainer::waitUntilContainerStarted);
}

static class JdbcDatabaseContainerStub extends JdbcDatabaseContainer {

public JdbcDatabaseContainerStub(@NonNull String dockerImageName) {
super(dockerImageName);
}

@Override
public String getDriverClassName() {
return null;
}

@Override
public String getJdbcUrl() {
return null;
}

@Override
public String getUsername() {
return null;
}

@Override
public String getPassword() {
return null;
}

@Override
protected String getTestQueryString() {
return null;
}

@Override
public boolean isRunning() {
return true;
}

@Override
public Connection createConnection(String queryString) throws SQLException, NoDriverFoundException {
throw new SQLException("Could not create new connection");
}

@Override
protected Logger logger() {
return mock(Logger.class);
}

@Override
public void setDockerImageName(@NonNull String dockerImageName) {}
}
}