Skip to content

Commit 66bd7c0

Browse files
barrycomminskiview
authored andcommitted
Add response body checking to HttpWaitStrategy (#441)
Add forResponsePredicate() method to HttpWaitStrategy class.
1 parent 135da1b commit 66bd7c0

File tree

3 files changed

+63
-7
lines changed

3 files changed

+63
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ All notable changes to this project will be documented in this file.
99
- Stopping creation of temporary directory prior to creating temporary file (#443)
1010

1111
### Changed
12+
- Added `forResponsePredicate` method to HttpWaitStrategy to test response body (#441)
1213
- Changed `DockerClientProviderStrategy` to be loaded via Service Loader (#434, #435)
1314
- Made it possible to specify docker compose container in configuration (#422, #425)
1415
- Clarified wording of pre-flight check messages (#457, #436)
1516
- 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.
1617
- Allowing JDBC containers' username, password and DB name to be customized (#400, #354)
1718

18-
1919
## [1.4.2] - 2017-07-25
2020
### Fixed
2121
- 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)

core/src/main/java/org/testcontainers/containers/wait/HttpWaitStrategy.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@
33
import com.google.common.base.Strings;
44
import com.google.common.io.BaseEncoding;
55
import org.rnorth.ducttape.TimeoutException;
6-
import org.testcontainers.DockerClientFactory;
76
import org.testcontainers.containers.ContainerLaunchException;
87
import org.testcontainers.containers.GenericContainer;
98

9+
import java.io.BufferedReader;
1010
import java.io.IOException;
11+
import java.io.InputStreamReader;
1112
import java.net.HttpURLConnection;
1213
import java.net.URI;
1314
import java.net.URL;
1415
import java.util.concurrent.TimeUnit;
16+
import java.util.function.Predicate;
1517

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

@@ -36,6 +38,7 @@ public class HttpWaitStrategy extends GenericContainer.AbstractWaitStrategy {
3638
private boolean tlsEnabled;
3739
private String username;
3840
private String password;
41+
private Predicate<String> responsePredicate;
3942

4043
/**
4144
* Waits for the given status code.
@@ -82,6 +85,16 @@ public HttpWaitStrategy withBasicCredentials(String username, String password) {
8285
return this;
8386
}
8487

88+
/**
89+
* Waits for the response to pass the given predicate
90+
* @param responsePredicate The predicate to test the response against
91+
* @return this
92+
*/
93+
public HttpWaitStrategy forResponsePredicate(Predicate<String> responsePredicate) {
94+
this.responsePredicate = responsePredicate;
95+
return this;
96+
}
97+
8598
@Override
8699
protected void waitUntilReady() {
87100
final Integer livenessCheckPort = getLivenessCheckPort();
@@ -114,6 +127,14 @@ protected void waitUntilReady() {
114127
connection.getResponseCode()));
115128
}
116129

130+
if(responsePredicate != null) {
131+
String responseBody = getResponseBody(connection);
132+
if(!responsePredicate.test(responseBody)) {
133+
throw new RuntimeException(String.format("Response: %s did not match predicate",
134+
responseBody));
135+
}
136+
}
137+
117138
} catch (IOException e) {
118139
throw new RuntimeException(e);
119140
}
@@ -155,4 +176,20 @@ private URI buildLivenessUri(int livenessCheckPort) {
155176
private String buildAuthString(String username, String password) {
156177
return AUTH_BASIC + BaseEncoding.base64().encode((username + ":" + password).getBytes());
157178
}
179+
180+
private String getResponseBody(HttpURLConnection connection) throws IOException {
181+
BufferedReader reader;
182+
if (200 <= connection.getResponseCode() && connection.getResponseCode() <= 299) {
183+
reader = new BufferedReader(new InputStreamReader((connection.getInputStream())));
184+
} else {
185+
reader = new BufferedReader(new InputStreamReader((connection.getErrorStream())));
186+
}
187+
188+
StringBuilder builder = new StringBuilder();
189+
String line;
190+
while ((line = reader.readLine()) != null) {
191+
builder.append(line);
192+
}
193+
return builder.toString();
194+
}
158195
}

core/src/test/java/org/testcontainers/junit/wait/HttpWaitStrategyTest.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@
1414
*/
1515
public class HttpWaitStrategyTest extends AbstractWaitStrategyTest<HttpWaitStrategy> {
1616
/**
17-
* Doubly-escaped newline sequence indicating end of the HTTP header.
17+
* newline sequence indicating end of the HTTP header.
1818
*/
19-
private static final String DOUBLE_NEWLINE = "\\\r\\\n\\\r\\\n";
19+
private static final String NEWLINE = "\r\n";
20+
21+
private static final String GOOD_RESPONSE_BODY = "Good Response Body";
2022

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

2931
/**
@@ -32,7 +34,16 @@ public void testWaitUntilReady_Success() {
3234
*/
3335
@Test
3436
public void testWaitUntilReady_Timeout() {
35-
waitUntilReadyAndTimeout("while true; do echo -e \"HTTP/1.1 400 Bad Request" + DOUBLE_NEWLINE + "\" | nc -lp 8080; done");
37+
waitUntilReadyAndTimeout(createShellCommand("400 Bad Request", GOOD_RESPONSE_BODY));
38+
}
39+
40+
/**
41+
* Expects that the WaitStrategy throws a {@link RetryCountExceededException} after not the expected response body
42+
* from the container within the timeout period.
43+
*/
44+
@Test
45+
public void testWaitUntilReady_Timeout_BadResponseBody() {
46+
waitUntilReadyAndTimeout(createShellCommand("200 OK", "Bad Response"));
3647
}
3748

3849
/**
@@ -48,6 +59,14 @@ protected void waitUntilReady() {
4859
super.waitUntilReady();
4960
ready.set(true);
5061
}
51-
};
62+
}.forResponsePredicate(s -> s.equals(GOOD_RESPONSE_BODY));
63+
}
64+
65+
private String createShellCommand(String header, String responseBody) {
66+
int length = responseBody.getBytes().length;
67+
return "while true; do { echo -e \"HTTP/1.1 "+header+NEWLINE+
68+
"Content-Type: text/html"+NEWLINE+
69+
"Content-Length: "+length +NEWLINE+ "\";"
70+
+" echo \""+responseBody+"\";} | nc -lp 8080; done";
5271
}
5372
}

0 commit comments

Comments
 (0)