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

Fixes the issue of missing root cause in container launch TimeoutException (e.g. SSLHandshakeException) #5778

Merged
merged 9 commits into from Nov 28, 2022
Expand Up @@ -319,7 +319,8 @@ protected void waitUntilReady() {
"Timed out waiting for URL to be accessible (%s should return HTTP %s)",
uri,
statusCodes.isEmpty() ? HttpURLConnection.HTTP_OK : statusCodes
)
),
e
);
}
}
Expand Down
@@ -1,10 +1,12 @@
package org.testcontainers.junit.wait.strategy;

import org.assertj.core.api.Assertions;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import org.rnorth.ducttape.RetryCountExceededException;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
import org.testcontainers.images.builder.ImageFromDockerfile;

import java.time.Duration;
import java.util.HashMap;
Expand Down Expand Up @@ -200,7 +202,7 @@ public void testWaitUntilReadyWithSpecificPort() {
}

@Test
public void testWaitUntilReadyWithTimoutCausedByReadTimeout() {
public void testWaitUntilReadyWithTimeoutCausedByReadTimeout() {
try (
GenericContainer<?> container = startContainerWithCommand(
createShellCommand("0 Connection Refused", GOOD_RESPONSE_BODY, 9090),
Expand All @@ -212,6 +214,31 @@ public void testWaitUntilReadyWithTimoutCausedByReadTimeout() {
}
}

/**
* Test to validate fix from GitHub Pull Request <a href="https://github.com/testcontainers/testcontainers-java/pull/5778">#5778</a>, i.e. when the container startup fails (ContainerLaunchException) before timeout for some reason, we are able to see the root cause of the error in the stack trace, e.g. in this case, a TLS certificate validation error during the TLS handshake test, because we are using a NGINX docker image with self-signed certificate created with the image, that is obviously not trusted.
* The exceptions we should see in the stacktrace ('/' means 'caused by'): ContainerLaunchException / TimeoutException / RuntimeException / SSLHandshakeException / ValidatorException (in sun.* package so not accessible) / SunCertPathBuilderException (in sun.* package so not accessible).
*/
@Test
public void testWaitUntilReadyWithTimeoutCausedBySslHandshakeError() {
try (
GenericContainer<?> container = new GenericContainer<>(
new ImageFromDockerfile()
.withFileFromClasspath("Dockerfile", "https-wait-strategy-dockerfile/Dockerfile")
.withFileFromClasspath("nginx-ssl.conf", "https-wait-strategy-dockerfile/nginx-ssl.conf")
)
.withExposedPorts(8443)
.waitingFor(
createHttpWaitStrategy(ready)
.forPort(8443)
.usingTls()
.withStartupTimeout(Duration.ofMillis(WAIT_TIMEOUT_MILLIS))
)
) {
Throwable throwable = Assertions.catchThrowable(container::start);
assertThat(throwable).hasStackTraceContaining("javax.net.ssl.SSLHandshakeException");
}
}

/**
* @param ready the AtomicBoolean on which to indicate success
* @return the WaitStrategy under test
Expand Down
@@ -0,0 +1,6 @@
FROM nginx:1.17-alpine

# Create keypair and self-signed certificate for https test
RUN apk update && apk add bash openssl && openssl req -batch -x509 -nodes -days 365 -newkey rsa:2048 -subj "/CN=localhost" -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt

ADD nginx-ssl.conf /etc/nginx/conf.d/default.conf
@@ -0,0 +1,10 @@
# This configuration makes Nginx listen on port port 8443
# In order to use this config, add this line to the Dockerfile to create the keypair and self-signed certificate:
# RUN apk update && apk add openssl && openssl req -batch -x509 -nodes -days 365 -newkey rsa:2048 -subj "/CN=localhost" -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt

server {
listen 8443 ssl;
server_name localhost;
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
}