Search code examples
javamockingjunit5aws-sdk-java-2.0hoverfly

How to use the AWS CRT HTTP Client with Hoverfly?


I would like to implement the AwsCrtHttpClient and intercept the HTTP requests in the unit tests with Hoverfly, but Hoverfly is not intercepting the requests. The client is initialized like: private static final SdkHttpClient httpClient = AwsCrtHttpClient.builder().build();. While there are options to modify the proxy settings (which I have tried), Hoverfly is still not intercepting the requests.

I have also tried:

private static final SdkHttpClient httpClient = AwsCrtHttpClient.builder()
        .proxyConfiguration(ProxyConfiguration.builder()
                .host("localhost")
                .port(8500)
                .build())
        .build();

and

private static final SdkHttpClient httpClient = AwsCrtHttpClient.builder()
        .proxyConfiguration(ProxyConfiguration.builder()
                .host(System.getProperty("http.proxyHost"))
                .port(Integer.parseInt(System.getProperty("http.proxyPort")))
                .build())
        .build();

and

private static final SdkHttpClient httpClient = AwsCrtHttpClient.builder()
        .proxyConfiguration(ProxyConfiguration.builder()
                .useSystemPropertyValues(true)
                .build())
        .build();

Hoverfly does not intercept the requests with any of these configurations. According to the AWS documentation (here), the proxy settings seem unnecessary to manually configure as

the SDK looks for external settings to configure a default proxy configuration.

Also, the Hoverfly configuration should be correct, as I am migrating from the default Java HTTP client to use the AWS CRT HTTP client, and the requests were previously intercepted. For reference, I am using the @ExtendWith(HoverflyExtension.class) annotation with my test class and simulating the endpoint with hoverfly.simulate(dsl(service(uri).anyMethod().willReturn(success().body("success")))). I am using hoverfly-java-junit5 with Java 11. I can still see the Hoverfly logs initializing properly. Here are some logs related to the initialization:

[Thread-1] INFO hoverfly - Default proxy port has been overwritten port=50022
[Thread-1] INFO hoverfly - Default admin port has been overwritten port=50023
[Thread-1] INFO hoverfly - Using memory backend 
[Thread-1] INFO hoverfly - Proxy prepared... Destination=. Mode=simulate ProxyPort=50022
[Thread-1] INFO hoverfly - current proxy configuration destination=. mode=simulate port=50022
[Thread-1] INFO hoverfly - serving proxy 
[Thread-1] INFO hoverfly - Admin interface is starting... AdminPort=50023
[main] INFO io.specto.hoverfly.junit.core.Hoverfly - A local Hoverfly with version v1.8.0 is ready
[Thread-1] INFO hoverfly - Mode has been changed mode=simulate
[main] INFO io.specto.hoverfly.junit.core.ProxyConfigurer - Setting proxy host to localhost
[main] INFO io.specto.hoverfly.junit.core.ProxyConfigurer - Setting proxy proxyPort to 50022
[main] INFO io.specto.hoverfly.junit.core.Hoverfly - Importing simulation data to Hoverfly

Finally, the HTTP call is being made properly (i.e., I obtain the response from the non-simulated endpoint over the public internet) with the following logic:

SdkHttpRequest.Builder sdkHttpRequestBuilder = SdkHttpRequest.builder().uri(new URI(uri)).method(method);
// Conditionally append headers with sdkHttpRequestBuilder.appendHeader(headerName, headerValue);
// ...
SdkHttpRequest sdkHttpRequest = sdkHttpRequestBuilder
        .appendHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType())
        .build();
HttpExecuteResponse response = httpClient.prepareRequest(HttpExecuteRequest.builder().request(sdkHttpRequest).build()).call();

Why would Hoverfly work with the old logic using the default HTTP client, but not the AWS CRT HTTP Client? The previous HTTP requests were made like:

private static final HttpClient httpClient = HttpClient.newHttpClient();
// Prepare request
// ...
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

I am looking for a some low-level setting on this AWS CRT HTTP client or Hoverfly that I can modify to ensure the requests are intercepted by Hoverfly.


Solution

  • The solution was to set the proxyLocalHost flag in the Hoverfly configuration to true. That's because the client's builder logic in the AWS CRT HTTP Client was reading Hoverfly's default values for the environment variable "http.nonProxyHosts" and then setting the client's proxy configuration to null with its builder logic. The workaround was to modify the Hoverfly configuration to set the proxyLocalHost flag to true like the following:

    @HoverflyCore(config = @HoverflyConfig(proxyLocalHost = true))
    @ExtendWith(HoverflyExtension.class)
    class MyTest {
    // ...
    

    This sets the proxyLocalHost environment variable to "", and it allows for the default AWS CRT HTTP Client to proxy to localhost.