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.07k stars 473 forks source link

Pact Consumer tests fail due to mock server closed connection #1176

Open lokashivkumar opened 3 years ago

lokashivkumar commented 3 years ago

Here is the context: I am trying to work with junit5 and pact framework to write some consumer tests. Here are some of the code snippets:

`@ExtendWith({PactConsumerTestExt.class}) public class DDConfigConsumerPactTest { private static final String CONFIG_URL = "/config";

@BeforeEach
public void setUp(MockServer mockServer) {
    LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
    Configuration config = ctx.getConfiguration();
    LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
    loggerConfig.setLevel(Level.DEBUG);
    ctx.updateLoggers();
    assertNotNull(mockServer);
}

@Pact(provider="config-service", consumer="test-integration") public RequestResponsePact validCredentials(PactDslWithProvider builder) { Map<String, String> headers = Map.of("Content-Type", ContentType.TEXT.toString()); Gson gson = new Gson();

    RequestResponsePact pact = builder
            .uponReceiving("valid configuration")
            .path(CONFIG_URL)
            .method("GET")
            .headers(headers)
            .body("text")
            .willRespondWith()
            .status(200)
            .body(json(Map.of("data", "", "status", "success")).toString())
            .toPact();

    return pact;
}

@Test
@PactTestFor(hostInterface = "localhost", pactMethod = "validCredentials", port = "7001")
public void runTest(MockServer mockServer) {
    RequestLoggingFilter requestLoggingFilter = new RequestLoggingFilter();
    ResponseLoggingFilter responseLoggingFilter = new ResponseLoggingFilter();

    Gson gson = new Gson();

    RequestSpecification requestSpec = new RequestSpecBuilder()
            .setContentType(ContentType.TEXT)
            .setPort(mockServer.getPort())
            .setBasePath(CONFIG_URL)
            .addFilter(requestLoggingFilter)
            .addFilter(responseLoggingFilter)
            .setBody("text")
            .build();

    Response response = given().spec(requestSpec).get();
    assertEquals( "success", response.body().jsonPath().get("status"));
}

`

I expect this basic test to run successfully as I understand the headers and body match, but here is the exception:

localhost:7001 failed to respond org.apache.http.NoHttpResponseException: localhost:7001 failed to respond at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56) at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259) at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:294) at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:257) at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:207) at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273) at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125) at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:679) at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:481) at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) at org.apache.http.client.HttpClient$execute$0.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:148) at io.restassured.internal.RequestSpecificationImpl$RestAssuredHttpBuilder.doRequest(RequestSpecificationImpl.groovy:2055) at io.restassured.internal.http.HTTPBuilder.doRequest(HTTPBuilder.java:495) at io.restassured.internal.http.HTTPBuilder.request(HTTPBuilder.java:452) at io.restassured.internal.http.HTTPBuilder$request$2.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:166) at io.restassured.internal.RequestSpecificationImpl.sendHttpRequest(RequestSpecificationImpl.groovy:1451) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:107) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1262) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1029) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:816) at groovy.lang.GroovyObject.invokeMethod(GroovyObject.java:39) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:45) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:55) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:171) at io.restassured.internal.RequestSpecificationImpl.sendRequest(RequestSpecificationImpl.groovy:1200) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:107) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1262) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1029) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:816) at groovy.lang.GroovyObject.invokeMethod(GroovyObject.java:39) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:45) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:166) at io.restassured.internal.filter.SendRequestFilter.filter(SendRequestFilter.groovy:30) at io.restassured.filter.Filter$filter$0.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at io.restassured.filter.Filter$filter.call(Unknown Source) at io.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:72) at io.restassured.filter.time.TimingFilter.filter(TimingFilter.java:56) at io.restassured.filter.Filter$filter.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at io.restassured.filter.Filter$filter.call(Unknown Source) at io.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:72) at io.restassured.filter.log.StatusCodeBasedLoggingFilter.filter(StatusCodeBasedLoggingFilter.java:112) at io.restassured.filter.log.ResponseLoggingFilter.filter(ResponseLoggingFilter.java:31) at io.restassured.filter.Filter$filter.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at io.restassured.filter.Filter$filter.call(Unknown Source) at io.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:72) at io.restassured.filter.log.RequestLoggingFilter.filter(RequestLoggingFilter.java:140) at io.restassured.filter.Filter$filter.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:157) at io.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:72) at io.restassured.filter.FilterContext$next.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:148) at io.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1655) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:107) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1262) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1029) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:816) at groovy.lang.GroovyObject.invokeMethod(GroovyObject.java:39) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:45) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:55) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:171) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:203) at io.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1661) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:107) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1262) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1029) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:816) at groovy.lang.GroovyObject.invokeMethod(GroovyObject.java:39) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:45) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:55) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:171) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:203) at io.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy:171) at io.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:107) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1262) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1029) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:816) at groovy.lang.GroovyObject.invokeMethod(GroovyObject.java:39) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:45) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:55) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:171) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:185) at io.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy:255) at io.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy)

lokashivkumar commented 3 years ago

I tried a few things since this post. when I do not have a body in the mock response, it seems to be working fine. So I suspect that the PactDslResponse is having trouble processing/returning a response body.

uglyog commented 3 years ago

GET request can't have a body. It is invalid according to the HTTP RFC. Try with a POST or PUT to test with a body.

lokashivkumar commented 3 years ago

Sorry I shared the wrong snippet... I’ve tried it with POST and it yields the same result. What’s strange is that when there is no body (empty response from mock server with only a 200 status code) it works fine

I also tried an invalid/mismatched request, it responds successfully but it fails only when the request is matched and it has to respond with a body.

uglyog commented 3 years ago

I can't replicate this issue. When I run your test, it works (both from IntelliJ IDEA and via Gradle). See https://github.com/DiUS/pact-jvm/blob/master/consumer/junit5/src/test/java/au/com/dius/pact/consumer/junit5/Issue1176Test.java

uglyog commented 3 years ago

Try running with the latest Pact-JVM and Restassured versions

jaymell commented 3 years ago

Note that I was able to fix a similar issue by updating org.apache.commons.commons-lang3 to the latest version (3.11). In my case, the problem would only occur when using PactDslJsonBody to construct the body matcher.