pact-foundation / pact-jvm

JVM version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.
https://docs.pact.io
Apache License 2.0
1.08k stars 479 forks source link

Subsequent tests fails in au.com.dius.pact:consumer for a project using ApacheHttpClient #1383

Open mjureczko opened 3 years ago

mjureczko commented 3 years ago

I created a sample with a failing test: https://github.com/mjureczko/pact-consumer-issue.

When running tests on the consumer side in a series where each test case requires the same provider endpoint, but in a different state, the second test fails without a response from the provider. It fails unless I give it some additional time (sleep for 1-2 seconds). I was tinkering with the debugger and the sleep is apparently required after executing server.stop(0) in the MockHttpServer.kt. So according to my observations, the mock server is restarted between test cases, and during the teardown, something is done asynchronously, unfortunately, not fast enough.

uglyog commented 3 years ago

Thanks for the example project.

Please note that this is not a Pact-JVM issue, but an issue with HTTP clients caching connections with HTTP/1.1 and not taking the port into account (i.e. the connections are cached based on host name). The reason the sleep works because it causes the time to live value for the connection in connection pool to be exceeded and it will be evicted when the second test runs.

One way to fix it is to change:

public class MyFeignConfiguration {
    @Bean
    public feign.Client client() {
        CloseableHttpClient httpClient = HttpClientBuilder.create()
          .setConnectionReuseStrategy(new NoConnectionReuseStrategy())
          .build();
        return new ApacheHttpClient(httpClient);
    }
}

Another way is to enable using system properties on the HTTP client and then set the http.keepAlive property to false.

public class MyFeignConfiguration {
    @Bean
    public feign.Client client() {
        CloseableHttpClient httpClient = HttpClientBuilder.create()
          .useSystemProperties()
          .build();
        return new ApacheHttpClient(httpClient);
    }
}

and then in the project POM add:

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M4</version>
                <configuration>
                    <systemProperties>
                        <property>
                            <name>http.keepAlive</name>
                            <value>false</value>
                        </property>
                    </systemProperties>
                </configuration>
            </plugin>
uglyog commented 3 years ago

Duplicate of #342

uglyog commented 3 years ago

Added a note to readme about persistent HTTP/1.1 connections: https://github.com/pact-foundation/pact-jvm/tree/master/consumer#dealing-with-persistent-http11-connections-keep-alive