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

Allow testcontainer to wait for a specific port #703

Merged
merged 3 commits into from
May 18, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.common.base.Strings;
import com.google.common.io.BaseEncoding;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.rnorth.ducttape.TimeoutException;
import org.testcontainers.containers.ContainerLaunchException;
Expand Down Expand Up @@ -43,6 +44,7 @@ public class HttpWaitStrategy extends AbstractWaitStrategy {
if (statusCodes.isEmpty() && HttpURLConnection.HTTP_OK == responseCode) return true;
return statusCodes.contains(responseCode);
};
private Optional<Integer> livenessPort = Optional.empty();

/**
* Waits for the given status code.
Expand Down Expand Up @@ -76,6 +78,17 @@ public HttpWaitStrategy forPath(String path) {
return this;
}

/**
* Wait for the given port.
*
* @param port the given port
* @return this
*/
public HttpWaitStrategy forPort(int port) {
this.livenessPort = Optional.of(port);
return this;
}

/**
* Indicates that the status check should use HTTPS.
*
Expand Down Expand Up @@ -112,13 +125,19 @@ public HttpWaitStrategy forResponsePredicate(Predicate<String> responsePredicate
@Override
protected void waitUntilReady() {
final String containerName = waitStrategyTarget.getContainerInfo().getName();
final Set<Integer> livenessCheckPorts = getLivenessCheckPorts();
if (livenessCheckPorts == null || livenessCheckPorts.isEmpty()) {
log.warn("{}: No exposed ports or mapped ports - cannot wait for status", containerName);

final Integer livenessCheckPort = livenessPort.map(waitStrategyTarget::getMappedPort).orElseGet(() -> {
final Set<Integer> livenessCheckPorts = getLivenessCheckPorts();
if (livenessCheckPorts == null || livenessCheckPorts.isEmpty()) {
log.warn("{}: No exposed ports or mapped ports - cannot wait for status", containerName);
return -1;
}
return livenessCheckPorts.iterator().next();
});

if (null == livenessCheckPort || -1 == livenessCheckPort) {
return;
}

final Integer livenessCheckPort = livenessCheckPorts.iterator().next();
final String uri = buildLivenessUri(livenessCheckPort).toString();
log.info("{}: Waiting for {} seconds for URL: {}", containerName, startupTimeout.getSeconds(), uri);

Expand All @@ -138,13 +157,18 @@ protected void waitUntilReady() {
connection.setRequestMethod("GET");
connection.connect();

log.info("Get response code {}", connection.getResponseCode());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change this (and Get response {}) to .debug or even .trace

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bsideup thank you for review.

I changed the logging from INFO to TRACE and added an item to changelog.md.

Let me know if that looks better now :)


if (!statusCodePredicate.test(connection.getResponseCode())) {
throw new RuntimeException(String.format("HTTP response code was: %s",
connection.getResponseCode()));
}

if(responsePredicate != null) {
String responseBody = getResponseBody(connection);

log.info("Get response {}", responseBody);

if(!responsePredicate.test(responseBody)) {
throw new RuntimeException(String.format("Response: %s did not match predicate",
responseBody));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,13 @@ private GenericContainer startContainerWithCommand(String shellCommand) {
* @return the (unstarted) container
*/
protected GenericContainer startContainerWithCommand(String shellCommand, WaitStrategy waitStrategy) {
return startContainerWithCommand(shellCommand, waitStrategy, 8080);
}

protected GenericContainer startContainerWithCommand(String shellCommand, WaitStrategy waitStrategy, Integer... ports) {
// apply WaitStrategy to container
return new GenericContainer(IMAGE_NAME)
.withExposedPorts(8080)
.withExposedPorts(ports)
.withCommand("sh", "-c", shellCommand)
.waitingFor(waitStrategy.withStartupTimeout(Duration.ofMillis(WAIT_TIMEOUT_MILLIS)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,20 @@ public void testWaitUntilReadyWithTimeoutAndBadResponseBody() {
waitUntilReadyAndTimeout(createShellCommand("200 OK", "Bad Response"));
}


/**
* Expects the WaitStrategy probing the right port.
*/
@Test
public void testWaitUntilReadyWithSpecificPort() {
waitUntilReadyAndSucceed(startContainerWithCommand(
createShellCommand("200 OK", GOOD_RESPONSE_BODY, 9090),
createHttpWaitStrategy(ready)
.forPort(9090),
7070, 8080, 9090
));
}

/**
* @param ready the AtomicBoolean on which to indicate success
* @return the WaitStrategy under test
Expand Down Expand Up @@ -129,10 +143,14 @@ protected void waitUntilReady() {
}

private String createShellCommand(String header, String responseBody) {
return createShellCommand(header, responseBody, 8080);
}

private String createShellCommand(String header, String responseBody, int port) {
int length = responseBody.getBytes().length;
return "while true; do { echo -e \"HTTP/1.1 "+header+NEWLINE+
"Content-Type: text/html"+NEWLINE+
"Content-Length: "+length +NEWLINE+ "\";"
+" echo \""+responseBody+"\";} | nc -lp 8080; done";
+" echo \""+responseBody+"\";} | nc -lp " + port + "; done";
}
}