Skip to content

Commit

Permalink
Add response body checking to HttpWaitStrategy (#441)
Browse files Browse the repository at this point in the history
Add forResponsePredicate() method to HttpWaitStrategy class.
  • Loading branch information
barrycommins authored and kiview committed Sep 19, 2017
1 parent 135da1b commit 66bd7c0
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 7 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ All notable changes to this project will be documented in this file.
- Stopping creation of temporary directory prior to creating temporary file (#443)

### Changed
- Added `forResponsePredicate` method to HttpWaitStrategy to test response body (#441)
- Changed `DockerClientProviderStrategy` to be loaded via Service Loader (#434, #435)
- Made it possible to specify docker compose container in configuration (#422, #425)
- Clarified wording of pre-flight check messages (#457, #436)
- Added caching of failure to find a docker daemon, so that subsequent tests fail fast. This is likely to be a significant improvement in situations where there is no docker daemon available, dramatically reducing run time and log output when further attempts to find the docker daemon cannot succeed.
- Allowing JDBC containers' username, password and DB name to be customized (#400, #354)


## [1.4.2] - 2017-07-25
### Fixed
- Worked around incompatibility between Netty's Unix socket support and OS X 10.11. Reinstated use of TCP-Unix Socket proxy when running on OS X prior to v10.12. (Fixes #402)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
import com.google.common.base.Strings;
import com.google.common.io.BaseEncoding;
import org.rnorth.ducttape.TimeoutException;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.ContainerLaunchException;
import org.testcontainers.containers.GenericContainer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;

import static org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess;

Expand All @@ -36,6 +38,7 @@ public class HttpWaitStrategy extends GenericContainer.AbstractWaitStrategy {
private boolean tlsEnabled;
private String username;
private String password;
private Predicate<String> responsePredicate;

/**
* Waits for the given status code.
Expand Down Expand Up @@ -82,6 +85,16 @@ public HttpWaitStrategy withBasicCredentials(String username, String password) {
return this;
}

/**
* Waits for the response to pass the given predicate
* @param responsePredicate The predicate to test the response against
* @return this
*/
public HttpWaitStrategy forResponsePredicate(Predicate<String> responsePredicate) {
this.responsePredicate = responsePredicate;
return this;
}

@Override
protected void waitUntilReady() {
final Integer livenessCheckPort = getLivenessCheckPort();
Expand Down Expand Up @@ -114,6 +127,14 @@ protected void waitUntilReady() {
connection.getResponseCode()));
}

if(responsePredicate != null) {
String responseBody = getResponseBody(connection);
if(!responsePredicate.test(responseBody)) {
throw new RuntimeException(String.format("Response: %s did not match predicate",
responseBody));
}
}

} catch (IOException e) {
throw new RuntimeException(e);
}
Expand Down Expand Up @@ -155,4 +176,20 @@ private URI buildLivenessUri(int livenessCheckPort) {
private String buildAuthString(String username, String password) {
return AUTH_BASIC + BaseEncoding.base64().encode((username + ":" + password).getBytes());
}

private String getResponseBody(HttpURLConnection connection) throws IOException {
BufferedReader reader;
if (200 <= connection.getResponseCode() && connection.getResponseCode() <= 299) {
reader = new BufferedReader(new InputStreamReader((connection.getInputStream())));
} else {
reader = new BufferedReader(new InputStreamReader((connection.getErrorStream())));
}

StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
return builder.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@
*/
public class HttpWaitStrategyTest extends AbstractWaitStrategyTest<HttpWaitStrategy> {
/**
* Doubly-escaped newline sequence indicating end of the HTTP header.
* newline sequence indicating end of the HTTP header.
*/
private static final String DOUBLE_NEWLINE = "\\\r\\\n\\\r\\\n";
private static final String NEWLINE = "\r\n";

private static final String GOOD_RESPONSE_BODY = "Good Response Body";

/**
* Expects that the WaitStrategy returns successfully after receiving an HTTP 200 response from the container.
*/
@Test
public void testWaitUntilReady_Success() {
waitUntilReadyAndSucceed("while true; do echo -e \"HTTP/1.1 200 OK" + DOUBLE_NEWLINE + "\" | nc -lp 8080; done");
waitUntilReadyAndSucceed(createShellCommand("200 OK", GOOD_RESPONSE_BODY));
}

/**
Expand All @@ -32,7 +34,16 @@ public void testWaitUntilReady_Success() {
*/
@Test
public void testWaitUntilReady_Timeout() {
waitUntilReadyAndTimeout("while true; do echo -e \"HTTP/1.1 400 Bad Request" + DOUBLE_NEWLINE + "\" | nc -lp 8080; done");
waitUntilReadyAndTimeout(createShellCommand("400 Bad Request", GOOD_RESPONSE_BODY));
}

/**
* Expects that the WaitStrategy throws a {@link RetryCountExceededException} after not the expected response body
* from the container within the timeout period.
*/
@Test
public void testWaitUntilReady_Timeout_BadResponseBody() {
waitUntilReadyAndTimeout(createShellCommand("200 OK", "Bad Response"));
}

/**
Expand All @@ -48,6 +59,14 @@ protected void waitUntilReady() {
super.waitUntilReady();
ready.set(true);
}
};
}.forResponsePredicate(s -> s.equals(GOOD_RESPONSE_BODY));
}

private String createShellCommand(String header, String responseBody) {
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";
}
}

0 comments on commit 66bd7c0

Please sign in to comment.