|
39 | 39 | import static org.mockito.Mockito.spy;
|
40 | 40 | import static org.mockito.Mockito.times;
|
41 | 41 |
|
| 42 | +import com.github.tomakehurst.wiremock.http.trafficlistener.WiremockNetworkTrafficListener; |
42 | 43 | import com.github.tomakehurst.wiremock.junit.WireMockRule;
|
43 | 44 | import io.netty.channel.EventLoopGroup;
|
44 | 45 | import io.netty.channel.nio.NioEventLoopGroup;
|
| 46 | + |
| 47 | +import java.io.IOException; |
| 48 | +import java.net.Socket; |
45 | 49 | import java.net.URI;
|
46 | 50 | import java.nio.ByteBuffer;
|
| 51 | +import java.nio.charset.StandardCharsets; |
47 | 52 | import java.time.Duration;
|
48 | 53 | import java.util.ArrayList;
|
49 | 54 | import java.util.Collection;
|
50 | 55 | import java.util.Collections;
|
51 | 56 | import java.util.List;
|
52 | 57 | import java.util.Map;
|
53 | 58 | import java.util.concurrent.CompletableFuture;
|
| 59 | +import java.util.concurrent.ExecutionException; |
54 | 60 | import java.util.concurrent.ThreadFactory;
|
55 | 61 | import java.util.concurrent.TimeUnit;
|
| 62 | +import java.util.concurrent.TimeoutException; |
56 | 63 | import java.util.stream.Stream;
|
57 | 64 | import org.assertj.core.api.Condition;
|
58 | 65 | import org.junit.AfterClass;
|
| 66 | +import org.junit.Before; |
59 | 67 | import org.junit.Rule;
|
60 | 68 | import org.junit.Test;
|
61 | 69 | import org.junit.runner.RunWith;
|
|
76 | 84 | @RunWith(MockitoJUnitRunner.class)
|
77 | 85 | public class NettyNioAsyncHttpClientWireMockTest {
|
78 | 86 |
|
| 87 | + private final RecordingNetworkTrafficListener wiremockTrafficListener = new RecordingNetworkTrafficListener(); |
| 88 | + |
79 | 89 | @Rule
|
80 |
| - public WireMockRule mockServer = new WireMockRule(wireMockConfig().dynamicPort().dynamicHttpsPort()); |
| 90 | + public WireMockRule mockServer = new WireMockRule(wireMockConfig() |
| 91 | + .dynamicPort() |
| 92 | + .dynamicHttpsPort() |
| 93 | + .networkTrafficListener(wiremockTrafficListener)); |
81 | 94 |
|
82 | 95 | @Mock
|
83 | 96 | private SdkRequestContext requestContext;
|
84 | 97 |
|
85 |
| - private static SdkAsyncHttpClient client = NettyNioAsyncHttpClient.builder() |
86 |
| - .buildWithDefaults(mapWithTrustAllCerts()); |
| 98 | + private static SdkAsyncHttpClient client = NettyNioAsyncHttpClient.builder().buildWithDefaults(mapWithTrustAllCerts()); |
| 99 | + |
| 100 | + @Before |
| 101 | + public void methodSetup() { |
| 102 | + wiremockTrafficListener.reset(); |
| 103 | + } |
87 | 104 |
|
88 | 105 | @AfterClass
|
89 | 106 | public static void tearDown() throws Exception {
|
@@ -227,6 +244,30 @@ public void canSendContentAndGetThatContentBack() throws Exception {
|
227 | 244 | assertThat(recorder.fullResponseAsString()).isEqualTo(reverse(body));
|
228 | 245 | }
|
229 | 246 |
|
| 247 | + @Test |
| 248 | + public void requestContentOnlyEqualToContentLengthHeaderFromProvider() throws InterruptedException, ExecutionException, TimeoutException, IOException { |
| 249 | + final String content = randomAlphabetic(32); |
| 250 | + final String streamContent = content + reverse(content); |
| 251 | + stubFor(any(urlEqualTo("/echo?reversed=true")) |
| 252 | + .withRequestBody(equalTo(content)) |
| 253 | + .willReturn(aResponse().withBody(reverse(content)))); |
| 254 | + URI uri = URI.create("http://localhost:" + mockServer.port()); |
| 255 | + |
| 256 | + SdkHttpFullRequest request = createRequest(uri, "/echo", streamContent, SdkHttpMethod.POST, singletonMap("reversed", "true")); |
| 257 | + request = request.toBuilder().header("Content-Length", Integer.toString(content.length())).build(); |
| 258 | + RecordingResponseHandler recorder = new RecordingResponseHandler(); |
| 259 | + |
| 260 | + |
| 261 | + client.prepareRequest(request, requestContext, createProvider(streamContent), recorder).run(); |
| 262 | + |
| 263 | + recorder.completeFuture.get(5, TimeUnit.SECONDS); |
| 264 | + |
| 265 | + // HTTP servers will stop processing the request as soon as it reads |
| 266 | + // bytes equal to 'Content-Length' so we need to inspect the raw |
| 267 | + // traffic to ensure that there wasn't anything after that. |
| 268 | + assertThat(wiremockTrafficListener.requests.toString()).endsWith(content); |
| 269 | + } |
| 270 | + |
230 | 271 | private void assertCanReceiveBasicRequest(URI uri, String body) throws Exception {
|
231 | 272 | stubFor(any(urlPathEqualTo("/")).willReturn(aResponse().withHeader("Some-Header", "With Value").withBody(body)));
|
232 | 273 |
|
@@ -275,11 +316,11 @@ public void cancel() {
|
275 | 316 | };
|
276 | 317 | }
|
277 | 318 |
|
278 |
| - private SdkHttpRequest createRequest(URI uri) { |
| 319 | + private SdkHttpFullRequest createRequest(URI uri) { |
279 | 320 | return createRequest(uri, "/", null, SdkHttpMethod.GET, emptyMap());
|
280 | 321 | }
|
281 | 322 |
|
282 |
| - private SdkHttpRequest createRequest(URI uri, |
| 323 | + private SdkHttpFullRequest createRequest(URI uri, |
283 | 324 | String resourcePath,
|
284 | 325 | String body,
|
285 | 326 | SdkHttpMethod method,
|
@@ -379,4 +420,33 @@ private static AttributeMap mapWithTrustAllCerts() {
|
379 | 420 | .put(SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES, true)
|
380 | 421 | .build();
|
381 | 422 | }
|
| 423 | + |
| 424 | + private static class RecordingNetworkTrafficListener implements WiremockNetworkTrafficListener { |
| 425 | + private final StringBuilder requests = new StringBuilder(); |
| 426 | + |
| 427 | + |
| 428 | + @Override |
| 429 | + public void opened(Socket socket) { |
| 430 | + |
| 431 | + } |
| 432 | + |
| 433 | + @Override |
| 434 | + public void incoming(Socket socket, ByteBuffer byteBuffer) { |
| 435 | + requests.append(StandardCharsets.UTF_8.decode(byteBuffer)); |
| 436 | + } |
| 437 | + |
| 438 | + @Override |
| 439 | + public void outgoing(Socket socket, ByteBuffer byteBuffer) { |
| 440 | + |
| 441 | + } |
| 442 | + |
| 443 | + @Override |
| 444 | + public void closed(Socket socket) { |
| 445 | + |
| 446 | + } |
| 447 | + |
| 448 | + public void reset() { |
| 449 | + requests.setLength(0); |
| 450 | + } |
| 451 | + } |
382 | 452 | }
|
0 commit comments