Wiremock: Unexpected end of file from server exception when several test methods within one class

Created on 29 Apr 2014  Â·  57Comments  Â·  Source: tomakehurst/wiremock

This doesn't seem to be a problem on my own computer. However when I run the maven build on Jenkins, it always fails with the following message:
Caused by: java.net.SocketException: SocketException invoking http://localhost:8098/some/useless/path: Unexpected end of file from server.

I searched Wiremock's config, it doesn't seem that I can change the server timeout settings.

Bug

Most helpful comment

Changing from :
@Rule public WireMockRule wireMockRule = new WireMockRule(9091);
to
@ClassRule public static WireMockRule wireMockRule = new WireMockRule(9091);

worked for me.

All 57 comments

Can you provide some more detail?

How are your stubs set up? What kind of HTTP client are you using? What is the full exception?

I am using Apache's CXF-RS client(WebClient), the test I have is:

I haven't confirm but I suspect that the @AfterClass was called before the input stream in the response of the last test method is read and cause the problem. I am thinking to put a 2 seconds sleep in the method to see if this is true. If my theory is confirmed, I think it might be better that WireMock to fix it instead of the arbitrary 2 seconds sleep

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.List;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;

import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.junit.WireMockClassRule;
import com.yesmail.apiv2.client.GenericClient;
import com.yesmail.apiv2.client.tickets.model.Event;
import com.yesmail.apiv2.client.tickets.model.Request;
import com.yesmail.apiv2.client.tickets.model.State;
import com.yesmail.apiv2.client.tickets.model.Ticket;
import com.yesmail.apiv2.client.tickets.model.TicketResponse;
import com.yesmail.apiv2.client.tickets.model.UpdateTicket;
import com.yesmail.apiv2.util.Utils;

public class TicketsClientTest {
static private TicketsClient ticketsClient;

@ClassRule
public static WireMockClassRule wireMockRule = new WireMockClassRule(8098);

@BeforeClass
static public void setupServer() {
    ticketsClient = new TicketsClient("http://localhost:8098");
}

@Rule
public WireMockClassRule instanceRule = wireMockRule;

@Before
public void setup() {
    WireMock.reset();
}

@Test
public void testGetTicket() {
    stubFor(get(urlEqualTo("/v2/tickets/12345"))
            .willReturn(aResponse().withStatus(200)
                    .withHeader("Content-Type", "application/json")
                    .withHeader("Content-Location", "http://api.yesmail.com/v2/tickets/12345")
                    .withBody(Utils.toJSON(createTicketForGetAndCreateNewTicketResponse()))));

    TicketResponse tr = ticketsClient.getTicket("12345");
    assertNotNull(tr);

    assertEquals("http://api.yesmail.com/v2/tickets/12345", tr.getUri());

    Ticket t = tr.getTicket();
    assertNotNull(t);
    assertEquals("12345", t.getId());
    assertEquals(State.ACCEPTED, t.getState());
    assertEquals("http://api.yesmail.com/v2/emails", t.getRequest().getUri());
    assertEquals(1, t.getEvents().size());
    assertEquals(State.ACCEPTED, t.getEvents().get(0).getState());
}

@Test
public void testGetTicketCustomPath() {
    stubFor(get(urlEqualTo("/tickets/12345"))
            .willReturn(aResponse().withStatus(200)
                    .withHeader("Content-Type", "application/json")
                    .withHeader("Content-Location", "http://api.yesmail.com/v2/tickets/12345")
                    .withBody(Utils.toJSON(createTicketForGetAndCreateNewTicketResponse()))));

    TicketResponse tr = ticketsClient.getTicket("12345", "/tickets");
    assertNotNull(tr);

    assertEquals("http://api.yesmail.com/v2/tickets/12345", tr.getUri());

    Ticket t = tr.getTicket();
    assertNotNull(t);
    assertEquals("12345", t.getId());
    assertEquals(State.ACCEPTED, t.getState());
    assertEquals("http://api.yesmail.com/v2/emails", t.getRequest().getUri());
    assertEquals(1, t.getEvents().size());
    assertEquals(State.ACCEPTED, t.getEvents().get(0).getState());

}

//Temporarily disable this test as it always failed on Jenkins

@Test
public void testCreateTicket() {
    Ticket reqTicket = createTicketForPostRequest();

    stubFor(post(urlEqualTo("/v2/tickets"))
            .withHeader("Accept", equalTo("application/json"))
            .withHeader("Content-Type", equalTo("application/json"))
            .withRequestBody(equalToJson(Utils.toJSON(reqTicket)))
            .willReturn(aResponse().withStatus(201)
                    .withHeader("Content-Type", "application/json")
                    .withHeader("Content-Location", "http://api.yesmail.com/v2/tickets/12345")
                    .withBody(Utils.toJSON(createTicketForGetAndCreateNewTicketResponse()))));

    TicketResponse tr = ticketsClient.createTicket(reqTicket);
    assertNotNull(tr);

    assertEquals("http://api.yesmail.com/v2/tickets/12345", tr.getUri());

    Ticket t = tr.getTicket();
    assertNotNull(t);
    assertEquals("12345", t.getId());
    assertEquals(State.ACCEPTED, t.getState());
    assertEquals("http://api.yesmail.com/v2/emails", t.getRequest().getUri());
    assertEquals(1, t.getEvents().size());
    assertEquals(State.ACCEPTED, t.getEvents().get(0).getState());
}

@Test
public void testCreateTicketWithCustomPath() {
    Ticket reqTicket = createTicketForPostRequest();

    stubFor(post(urlEqualTo("/some/useless/path"))
            .withHeader("Accept", equalTo("application/json"))
            .withHeader("Content-Type", equalTo("application/json"))
            .withRequestBody(equalToJson(Utils.toJSON(reqTicket)))
            .willReturn(aResponse().withStatus(201)
                    .withHeader("Content-Type", "application/json")
                    .withHeader("Content-Location", "http://api.yesmail.com/v2/tickets/12345")
                    .withBody(Utils.toJSON(createTicketForGetAndCreateNewTicketResponse()))));

    TicketResponse tr = ticketsClient.createTicket(reqTicket, "/some/useless/path");
    assertNotNull(tr);

    assertEquals("http://api.yesmail.com/v2/tickets/12345", tr.getUri());

    Ticket t = tr.getTicket();
    assertNotNull(t);
    assertEquals("12345", t.getId());
    assertEquals(State.ACCEPTED, t.getState());
    assertEquals("http://api.yesmail.com/v2/emails", t.getRequest().getUri());
    assertEquals(1, t.getEvents().size());
    assertEquals(State.ACCEPTED, t.getEvents().get(0).getState());
}

@Test
public void testUpdateTicket() {
    UpdateTicket ut = createUpdateTicketForPostRequest();

    stubFor(post(urlEqualTo("/v2/tickets/12345"))
            .withHeader("Accept", equalTo("application/json"))
            .withHeader("Content-Type", equalTo("application/json"))
            .withRequestBody(equalToJson(Utils.toJSON(ut)))
            .willReturn(aResponse().withStatus(200)
                    .withHeader("Content-Type", "application/json")
                    .withHeader("Content-Location", "http://api.yesmail.com/v2/tickets/12345")
                    .withBody(Utils.toJSON(createTicketForUpdateTicketResponse()))));

    TicketResponse tr = ticketsClient.updateTicket("12345", ut);
    assertNotNull(tr);

    assertEquals("http://api.yesmail.com/v2/tickets/12345", tr.getUri());

    Ticket t = tr.getTicket();
    assertNotNull(t);
    assertEquals("12345", t.getId());
    assertEquals(State.PROCESSING, t.getState());
    assertEquals("http://api.yesmail.com/v2/emails", t.getRequest().getUri());
    assertEquals(2, t.getEvents().size());
    assertEquals(State.PROCESSING, t.getEvents().get(1).getState());

    WireMock.reset();

    ut.setReturnTicket(false);
    stubFor(post(urlEqualTo("/v2/tickets/12345"))
            .withHeader("Accept", equalTo("application/json"))
            .withHeader("Content-Type", equalTo("application/json"))
            .withRequestBody(equalToJson(Utils.toJSON(ut)))
            .willReturn(aResponse().withStatus(200)
                    .withHeader("Content-Type", "application/json")
                    .withHeader("Content-Location", "http://api.yesmail.com/v2/tickets/12345")
                    .withBody("")));

    tr = ticketsClient.updateTicket("12345", ut);
    assertNotNull(tr);
    assertNull(tr.getUri());
    assertNull(tr.getTicket());
}

@Test
public void testUpdateTicketWithCustomPath() {
    UpdateTicket ut = createUpdateTicketForPostRequest();

    stubFor(post(urlEqualTo("/tickets/12345"))
            .withHeader("Accept", equalTo("application/json"))
            .withHeader("Content-Type", equalTo("application/json"))
            .withRequestBody(equalToJson(Utils.toJSON(ut)))
            .willReturn(aResponse().withStatus(200)
                    .withHeader("Content-Type", "application/json")
                    .withHeader("Content-Location", "http://api.yesmail.com/v2/tickets/12345")
                    .withBody(Utils.toJSON(createTicketForUpdateTicketResponse()))));

    TicketResponse tr = ticketsClient.updateTicket("12345", ut, "/tickets");
    assertNotNull(tr);

    assertEquals("http://api.yesmail.com/v2/tickets/12345", tr.getUri());

    Ticket t = tr.getTicket();
    assertNotNull(t);
    assertEquals("12345", t.getId());
    assertEquals(State.PROCESSING, t.getState());
    assertEquals("http://api.yesmail.com/v2/emails", t.getRequest().getUri());
    assertEquals(2, t.getEvents().size());
    assertEquals(State.PROCESSING, t.getEvents().get(1).getState());

    WireMock.reset();

    ut.setReturnTicket(false);
    stubFor(post(urlEqualTo("/tickets/12345"))
            .withHeader("Accept", equalTo("application/json"))
            .withHeader("Content-Type", equalTo("application/json"))
            .withRequestBody(equalToJson(Utils.toJSON(ut)))
            .willReturn(aResponse().withStatus(200)
                    .withHeader("Content-Type", "application/json")
                    .withHeader("Content-Location", "http://api.yesmail.com/v2/tickets/12345")
                    .withBody("")));

    tr = ticketsClient.updateTicket("12345", ut, "/tickets");
    assertNotNull(tr);
    assertNull(tr.getUri());
    assertNull(tr.getTicket());
}

@AfterClass
static public void tearDown() {
    GenericClient.getApiClientFactory().stop();

    //wireMockServer.stop();
}

private Ticket createTicketForPostRequest() {
    Ticket t = new Ticket();
    t.setState(State.ACCEPTED);

    Request req = new Request();
    req.setUri("http://api.yesmail.com/v2/emails");
    t.setRequest(req);

    return t;
}

private UpdateTicket createUpdateTicketForPostRequest() {
    UpdateTicket ut = new UpdateTicket();

    ut.setMessage("Start to processing ...");
    ut.setState(State.PROCESSING);
    ut.setReturnTicket(true);

    return ut;
}

private Ticket createTicketForUpdateTicketResponse() {
    Ticket t = createTicketForGetAndCreateNewTicketResponse();

    t.setState(State.PROCESSING);
    t.setMessage("Start to processing ...");

    Event e = new Event();
    e.setMessage("request is under processing");
    e.setState(State.PROCESSING);
    t.getEvents().add(e);

    return t;
}

private Ticket createTicketForGetAndCreateNewTicketResponse() {
    Ticket t = new Ticket();

    t.setId("12345");
    t.setState(State.ACCEPTED);

    Request req = new Request();
    req.setId("12345");
    req.setUri("http://api.yesmail.com/v2/emails");
    t.setRequest(req);

    List<Event> el = new ArrayList<Event>();
    t.setEvents(el);
    Event e = new Event();
    e.setMessage("request accepted");
    e.setState(State.ACCEPTED);
    el.add(e);

    return t;
}

}

No the sleep call didn't fix the problem

One gotcha in there - you've changed the port number, but haven't set the static client up to use it (by calling WireMock.configureFor("localhost", 8098)). This means that the call to WireMock.reset() is trying to contact port 8080.

Also, the reset call is redundant as the @Rule takes care of that for you. I suggest removing the reset call and seeing how you get on.

Thanks. I will try your suggestion and let you know the result

From: tomakehurst <[email protected]notifications@github.com>
Reply-To: tomakehurst/wiremock <[email protected]reply@reply.github.com>
Date: Tuesday, April 29, 2014 4:18 PM
To: tomakehurst/wiremock <[email protected]wiremock@noreply.github.com>
Cc: "Pang, Tongguo" [email protected]Tongguo.Pang@yeslifecyclemarketing.com>
Subject: Re: [wiremock] Unexpected end of file from server exception when several test methods within one class (#132)

One gotcha in there - you've changed the port number, but haven't set the static client up to use it (by calling WireMock.configureFor("localhost", 8098)). This means that the call to WireMock.reset() is trying to contact port 8080.

Also, the reset call is redundant as the @Rulehttps://github.com/Rule takes care of that for you. I suggest removing the reset call and seeing how you get on.

—
Reply to this email directly or view it on GitHubhttps://github.com/tomakehurst/wiremock/issues/132#issuecomment-41726634.

This doesn't work. It seemed that the problem came from my Utils.toJSON() method call to crate the string of the JSON object and when I send to in the same JSON object by POST, somehow WireMock could not get it. Below is the exception on Jenkins. It says that the request could not be sent:

org.apache.cxf.interceptor.Fault: Could not send Message.
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:64)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
at org.apache.cxf.jaxrs.client.AbstractClient.doRunInterceptorChain(AbstractClient.java:634)
at org.apache.cxf.jaxrs.client.WebClient.doChainedInvocation(WebClient.java:1058)
at org.apache.cxf.jaxrs.client.WebClient.doInvoke(WebClient.java:865)
at org.apache.cxf.jaxrs.client.WebClient.doInvoke(WebClient.java:839)
at org.apache.cxf.jaxrs.client.WebClient.invoke(WebClient.java:299)
at org.apache.cxf.jaxrs.client.WebClient.post(WebClient.java:308)
at com.yesmail.apiv2.client.core.impl.cxf.CxfApiClient.postImpl(CxfApiClient.java:94)
at com.yesmail.apiv2.client.core.ApiClient.post(ApiClient.java:54)
at com.yesmail.apiv2.client.tickets.TicketsClient.createTicket(TicketsClient.java:52)
at com.yesmail.apiv2.client.tickets.TicketsClient.createTicket(TicketsClient.java:43)
at com.yesmail.apiv2.client.tickets.TicketsClientTest.testCreateTicket(TicketsClientTest.java:114)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at com.github.tomakehurst.wiremock.junit.WireMockClassRule$1.evaluate(WireMockClassRule.java:70)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at com.github.tomakehurst.wiremock.junit.WireMockClassRule$1.evaluate(WireMockClassRule.java:79)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
Caused by: java.net.SocketException: SocketException invoking http://localhost:8098/v2/tickets: Unexpected end of file from server
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.mapException(HTTPConduit.java:1339)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1323)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:628)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
... 48 more

From: tomakehurst <[email protected]notifications@github.com>
Reply-To: tomakehurst/wiremock <[email protected]reply@reply.github.com>
Date: Tuesday, April 29, 2014 4:18 PM
To: tomakehurst/wiremock <[email protected]wiremock@noreply.github.com>
Cc: "Pang, Tongguo" [email protected]Tongguo.Pang@yeslifecyclemarketing.com>
Subject: Re: [wiremock] Unexpected end of file from server exception when several test methods within one class (#132)

One gotcha in there - you've changed the port number, but haven't set the static client up to use it (by calling WireMock.configureFor("localhost", 8098)). This means that the call to WireMock.reset() is trying to contact port 8080.

Also, the reset call is redundant as the @Rulehttps://github.com/Rule takes care of that for you. I suggest removing the reset call and seeing how you get on.

—
Reply to this email directly or view it on GitHubhttps://github.com/tomakehurst/wiremock/issues/132#issuecomment-41726634.

Ah, the same problem, different manifestation I think.

Because you're calling stubFor(...) statically, you're hitting port 8080. Try using the DSL from the rule object:
wireMockRule.stubFor(post(...))

Thanks for the suggestions. I appreciate it. Will try after I finish the current task.

Thanks again

From: tomakehurst <[email protected]notifications@github.com>
Reply-To: tomakehurst/wiremock <[email protected]reply@reply.github.com>
Date: Thursday, May 1, 2014 1:13 PM
To: tomakehurst/wiremock <[email protected]wiremock@noreply.github.com>
Cc: "Pang, Tongguo" [email protected]Tongguo.Pang@yeslifecyclemarketing.com>
Subject: Re: [wiremock] Unexpected end of file from server exception when several test methods within one class (#132)

Ah, the same problem, different manifestation I think.

Because you're calling stubFor(...) statically, you're hitting port 8080. Try using the DSL from the rule object:
wireMockRule.stubFor(post(...))

—
Reply to this email directly or view it on GitHubhttps://github.com/tomakehurst/wiremock/issues/132#issuecomment-41931541.

Well this is not the issue. Calling stubFor either way doesn't matter.

But I think I do find the problem, and I believe this is a bug inside WireMock: when I change my return status to 201, all my tests works. But if I set the return status to 202(ACCEPTED), it appears that WireMock closes the output stream from the server side immediately without sending back the response body, and the client side hence receives the Unexpected end of file from server exception.

I will temporarily set all my tests to return 201(Created) status, but in long run it is better that WireMock to fix this problem.

Thanks again for you quick response. This is a great tool, and of course there are few small bumpers.

From: tomakehurst <[email protected]notifications@github.com>
Reply-To: tomakehurst/wiremock <[email protected]reply@reply.github.com>
Date: Thursday, May 1, 2014 1:13 PM
To: tomakehurst/wiremock <[email protected]wiremock@noreply.github.com>
Cc: "Pang, Tongguo" [email protected]Tongguo.Pang@yeslifecyclemarketing.com>
Subject: Re: [wiremock] Unexpected end of file from server exception when several test methods within one class (#132)

Ah, the same problem, different manifestation I think.

Because you're calling stubFor(...) statically, you're hitting port 8080. Try using the DSL from the rule object:
wireMockRule.stubFor(post(...))

—
Reply to this email directly or view it on GitHubhttps://github.com/tomakehurst/wiremock/issues/132#issuecomment-41931541.

I'd be surprised if that was the problem. WireMock doesn't attempt to differentiate between return codes, so it should behave any differently.

Have you tried it with a different HTTP client? It could be the CXF client is expecting more content in one case but not the other. If that's the case, adding a Content-Length header to the response will fix this.

This would be a very good idea. I will try it today.

Thanks again for the quick response

From: tomakehurst <[email protected]notifications@github.com>
Reply-To: tomakehurst/wiremock <[email protected]reply@reply.github.com>
Date: Friday, May 2, 2014 4:46 AM
To: tomakehurst/wiremock <[email protected]wiremock@noreply.github.com>
Cc: "Pang, Tongguo" [email protected]Tongguo.Pang@yeslifecyclemarketing.com>
Subject: Re: [wiremock] Unexpected end of file from server exception when several test methods within one class (#132)

I'd be surprised if that was the problem. WireMock doesn't attempt to differentiate between return codes, so it should behave any differently.

Have you tried it with a different HTTP client? It could be the CXF client is expecting more content in one case but not the other. If that's the case, adding a Content-Length header to the response will fix this.

—
Reply to this email directly or view it on GitHubhttps://github.com/tomakehurst/wiremock/issues/132#issuecomment-42004403.

Hi just want to let you know I figured out what's happening.

It seems to be a Jenkins (I don't remember the version of Jenkins) with JDK 1.6 problem. Even though there is no problem on my laptop with JDK 1.6, it does happen all the time when I tried to build with the Jenkins server in my company and JDK 1.6.

As i am upgrading my company's JDK gradually to JDK 1.7, and I rebuild the project with JDK 1.7, all the tests were successful. And I tried another 3 times with several more tests and they all worked.

So this is no longer an issue. Thank you for such a great tool

Glad to hear you resolved the issue!

Regarding the 202 response breaking subsequent calls - if you mock a 204 (no content) response and mistakenly attempt to return a body as well, the next mocked call fails as it appears the previous body is being returned in the following mocked response and it's not correctly formed. I found this thread/issue when I was trying to work out what was going wrong in my test, but in my case, removing the body for my 204 mocked response solved my issue.

Hi,

we're encountering the same issue. It occurs from time to time. So one of the tests fails. We're using RestTemplate (PUT method)

Wiremock is configured like this:

@Rule
 WireMockRule wireMockRule = new WireMockRule(12346)

and the stub

stubFor(put(urlEqualTo("/offers/${offerId}/buy-now-price"))
                .willReturn(aResponse().withStatus(200)
                .withHeader("Content-Type", "application/json")
                .withBody("""{"value":"123456"}""")))

The exception

ResourceAccessException: I/O error on PUT request for "http://localhost:12346/offers/offerId/buy-now-price": Unexpected end of file from server; nested exception is java.net.SocketException: Unexpected end of file from server

The stub is inside given part (spock)

JDK 1.8
wiremock: 2.1.11

Can you post the whole test source code?

I'm guessing that example is Groovy rather than Java? If so, by putting 'offerId' in the URL are you making it not match?

Sure,

I've simplified test

`class ChangePriceEndpointIntegrationSpec extends IntegrationSpec {

@Autowired
OfferServiceClient offerServiceClient

def "should handle event"() {
    given:
    def itemId = "offerId"
    OfferManagerStub.stub(itemId)
    when:
    offerServiceClient.updateOfferPrice(new OfferUpdatePriceRequest(itemId, 22, 1, "PLN", "TOKEN"))
    then:
    true
}

}`

The logs from the integrationTest

13:02:01.391 [Test worker] INFO o.s.t.c.s.AbstractContextLoader - Could not detect default resource locations for test class [xxx.sale.merchandising.offerproductpriceservice.IntegrationSpec]: no resource found for suffixes {-context.xml, Context.groovy}.
13:02:01.406 [Test worker] INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.AutoConfigureReportTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
13:02:01.407 [Test worker] INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@7b21acf3, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@c84c8bf, org.springframework.boot.test.autoconfigure.AutoConfigureReportTestExecutionListener@5a9749d, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@4a4e192c, org.springframework.test.context.support.DirtiesContextTestExecutionListener@3cfe72a2, org.springframework.test.context.transaction.TransactionalTestExecutionListener@169584b2, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@58560761, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@626bf23e, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@2dcfe7b3, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@174546ac, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@7fc0262a]
13:02:01.437 [Test worker] INFO org.eclipse.jetty.server.Server - jetty-9.2.13.v20150730
13:02:01.439 [Test worker] INFO o.e.j.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@21246617{/__admin,null,AVAILABLE}
13:02:01.441 [Test worker] INFO o.e.j.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@60eb4bda{/,null,AVAILABLE}
13:02:01.441 [Test worker] INFO o.e.jetty.server.ServerConnector - Started ServerConnector@627d9d0e{HTTP/1.1}{0.0.0.0:12347}
13:02:01.441 [Test worker] INFO org.eclipse.jetty.server.Server - Started @17330ms
13:02:01.473 [qtp1399165453-88] INFO /__admin - RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.AdminRequestHandler. Normalized mapped under returned 'null'
13:02:01.528 [Test worker] INFO p.a.s.m.o.i.o.OfferServiceRetriableClient - Updating offer price:
13:02:01.531 [Test worker] INFO p.a.s.t.o.OfferManagerClient - Update buyNow price request: ChangePriceDto{price=PriceDto{amount=22, currency=PLN}, userId='1'}, offerId: offerId
13:02:01.580 [Test worker] INFO o.e.jetty.server.ServerConnector - Stopped ServerConnector@627d9d0e{HTTP/1.1}{0.0.0.0:12347}
13:02:01.581 [Test worker] INFO o.e.j.server.handler.ContextHandler - Stopped o.e.j.s.ServletContextHandler@60eb4bda{/,null,UNAVAILABLE}
13:02:01.583 [Test worker] INFO o.e.j.server.handler.ContextHandler - Stopped o.e.j.s.ServletContextHandler@21246617{/__admin,null,UNAVAILABLE}
13:02:01.584 [Test worker] WARN o.e.j.util.thread.QueuedThreadPool - qtp1399165453{STOPPING,8<=8<=10,i=2,q=4} Couldn't stop Thread[qtp1399165453-84,5,main]
13:02:01.584 [Test worker] WARN o.e.j.util.thread.QueuedThreadPool - qtp1399165453{STOPPING,8<=8<=10,i=2,q=4} Couldn't stop Thread[qtp1399165453-89,5,main]

Sorry, should've been more specific. Can you post the code that starts the WireMock server and the actual HTTP client code that sends the PUT request?

Please keep in mind that if you run single test from IDE it's 'GREEN'

If there are more tests that interacts with Wiremock the problem occurs. The application is Spring Boot app

I'm going to struggle to replicate this with the info you've given me so far. Happy to investigate but only if I can get to a failing test.

Hello,

I've simplified test:

`class ChangePriceEndpointIntegrationSpec extends Specification {

@Rule
WireMockRule wireMockRule = new WireMockRule(12346)

RestTemplate restTemplate = new RestTemplate()

def "should handle event"() {
    given:
    def itemId = "offerId"
    stubFor(put(urlEqualTo("/offers/${itemId}/buy-now-price"))
            .willReturn(aResponse().withStatus(200)
            .withHeader("Content-Type", "application/json")
            .withBody("""{"value":"123456"}""")))
    RequestEntity<ChangePriceDto> request = new RequestEntity<>(new ChangePriceDto(), new LinkedMultiValueMap<>(), HttpMethod.PUT, new URI("http://localhost:12346/offers/${itemId}/buy-now-price"))
    when:
    ResponseEntity<JobIdDto> response = restTemplate.exchange(request, JobIdDto.class);
    then:
    println response
    true
}

}`

There are other integration tests that passes and uses WireMockRule on the same port
As I mentioned. Running test from IDE it's fine. If I rune all tests from gradle - it passes from time to time

Stack Trace:

org.springframework.web.client.ResourceAccessException: I/O error on PUT request for "http://localhost:12346/offers/offerId/buy-now-price": Unexpected end of file from server; nested exception is java.net.SocketException: Unexpected end of file from server
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:633)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:595)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:557)
at xxxxxxx.sale.merchandising.offerproductpriceservice.api.change.ChangePriceEndpointIntegrationSpec.should handle event(ChangePriceEndpointIntegrationSpec.groovy:37)
Caused by: java.net.SocketException: Unexpected end of file from server
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:792)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:647)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1536)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:52)
at org.springframework.http.client.AbstractClientHttpResponse.getStatusCode(AbstractClientHttpResponse.java:33)
at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:56)
at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:655)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:620)
... 3 more

Which WireMock version are you running?

I'm investigating issue on my side

I've changed the code a little bit.
I've added groovy Http-builder client.
Groovy client is working fine, RestTemplate still causes the problem ?

Modified code:

`
class ChangePriceEndpointIntegrationSpec extends Specification {

@Rule
WireMockRule wireMockRule = new WireMockRule(12346)

def "should handle event"() {
    given:
    def itemId = "offerId"
    // here is stub
    stubFor(put(urlEqualTo("/offers/${itemId}/buy-now-price"))
            .willReturn(aResponse().withStatus(200)
            .withHeader("Content-Type", "application/json")
            .withBody("""{"value":"123456"}""")))

    // init clients
    RestTemplate restTemplate = new RestTemplate()
    HTTPBuilder http = new HTTPBuilder("http://localhost:12346/offers/${itemId}/buy-now-price");

    MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    headers.put(HttpHeaders.ACCEPT, Lists.newArrayList("application/json"));
    RequestEntity<ChangePriceDto> request = new RequestEntity<>(new ChangePriceDto(), headers, HttpMethod.PUT, new URI("http://localhost:12346/offers/${itemId}/buy-now-price"))

    when:
    http.request(PUT, TEXT) { req ->
        body = [ticket: [subject: 'xyz']]

        response.success = { resp, json ->
            println "Success! ${resp.status} ${json}"
        }

        response.failure = { resp ->
            println "Request failed with status ${resp.status} ${resp.responseData}"
        }
    }
    ResponseEntity<JobIdDto> response = restTemplate.exchange(request, JobIdDto.class);
    then:
    println response
}

}
`

wiremock: 2.1.11

OK, rules out the problem I thought it might have been. I guess the signs are that it's a RESTTemplate problem in any case. Happy to take a look again if you find anything that points to WM being at issue.

It looks like race condition.

I have 2 tests.

1st test invokes Rest endpoint that calls WM

2nd test:

`class ChangePriceEndpointIntegrationSpec extends Specification {

@Rule
WireMockRule wireMockRule = new WireMockRule(12346)

def "should handle event"() {
    given:
    // here is stub
    stubFor(put(urlEqualTo("/some"))
            .willReturn(aResponse().withStatus(200)
            .withHeader("Content-Type", "application/json")
            .withBody("""{"value":"123456"}""")))

    // init client
    RestTemplate restTemplate = new RestTemplate()
    MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    headers.put(HttpHeaders.ACCEPT, Lists.newArrayList("application/json"));
    RequestEntity<ChangePriceDto> request = new RequestEntity<>(new ChangePriceDto(), headers, HttpMethod.PUT, new URI("http://localhost:12346/some"))

    // sleep(5000)
    // let's call stub
    when:
    2.times {
        try {
            println restTemplate.exchange(request, JobIdDto.class);
        } catch (Exception ex) {
            println "failure ${ex}"
        }
    }
    then:
    "OK"
}

}`

First call fails, second is fine. If you add sleep(5000) both calls are working.

Most interesting part are logs. I don't know WM so good so maybe You can help me with that

10:00:59.968 [main] INFO o.e.jetty.server.ServerConnector - Started ServerConnector@48697181{HTTP/1.1}{0.0.0.0:12346}
10:00:59.970 [main] INFO org.eclipse.jetty.server.Server - Started @13654ms
10:00:59.978 [qtp237594516-40] INFO /__admin - RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.AdminRequestHandler. Normalized mapped under returned 'null'
failure org.springframework.web.client.ResourceAccessException: I/O error on PUT request for "http://localhost:12346/some": Unexpected end of file from server; nested exception is java.net.SocketException: Unexpected end of file from server
10:01:00.057 [qtp237594516-41] INFO / - RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.StubRequestHandler. Normalized mapped under returned 'null'
<200 OK,JobIdDto{value='123456'},{Content-Type=[application/json], Transfer-Encoding=[chunked], Server=[Jetty(9.2.13.v20150730)]}>
10:01:00.093 [main] INFO o.e.jetty.server.ServerConnector - Stopped ServerConnector@48697181{HTTP/1.1}{0.0.0.0:12346}

And this entry :

10:01:00.057 [qtp237594516-41] INFO / - RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.StubRequestHandler. Normalized mapped under returned 'null'

It occurs just after failure ...

Hello,
if these logs are not helpful - please let me know. Issue is quite annoying

Thanks

It's not obvious what's happening from the logs. I think I'm going to have to set up my own concurrent test and hope that I can replicate it. Agree it looks like a race condition, but the question is where it exists.

We had similar problems, Spring rest template invocation always failed in few test cases.

Looks like this has something to do with Spring restTemplate's underlying HTTP handling. To verify that this we added a Apache httpClient rest invocation before spring and httpClient invocations were always success while restTemplate is failing.

We have solved this by using the Apache httpClient as the RestTemplate.setRequestFactory()

That's very useful to know. Thanks for sharing!

This issue is still occurring with 2.2 version, using ClassRules and no other framework even for a single HTTP Get request too. For now I am resorting to writing an embedded tomcat server for testing. Can we expect a solution soon?

For me works good after changing ClientHttpRequestFactory like this RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());

Hello,
solution proposed by @anicos didn't help me. It looks like the problem is harder to solve.

Ok I've got something. I fixed it with that configuration.

Related problem and solution is reported here

Here is my code

import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.HttpContext;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;

@Component
public class TestRestConfig {

    @Bean
    RestTemplate seachClient() {
        return new RestTemplate(new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().setRetryHandler(new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                return true;
            }
        }).build()));
    }

}

Please bare in mind it's ONLY for Tests

OK, I'm getting pretty confused by this thread now. I created this test - executing PUTs using a default RestTemplate across 200 threads:
https://gist.github.com/tomakehurst/dd09638e631acf76e723c18fa52fb417

I can't get this to fail.

If anybody on here still believes this is a WireMock bug, please can they provide a full test project on GH I can check out and run, that reliably fails. Otherwise I'm going to assume this is a client bug and close it off.

@trzaszcs you are right my solutions doesn't work. My mistake. sorry:(

Finally I have solution by workaround. In my project I use random port for WireMock
@Rule WireMockRule wireMockRule = new WireMockRule(Options.DYNAMIC_PORT)

And it is working perfect. It's even better solution because now I can run my tests in parallel:)

Having the same issue in our project. I switched from using the Unirest client to pure HttpUrlConnection and started having issues with interactions with WireMock failing.

The first test will run smoothly, but the second one will always fail. If I reverse the execution order of the test, the problem stays the same. So there is no inherent problem in the test.

I can fix the issue quite simply via a Thread.sleep statement after setting up the new mock that I want to interact with. Have tried increasing the jetty request and acceptor handling threads to no avail.

@tlefevre please could you post a test project that reliably replicates this?

Same problem here with the most recent version "2.15.0" and even with HttpComponentsClientHttpRequestFactory.

Changing from :
@Rule public WireMockRule wireMockRule = new WireMockRule(9091);
to
@ClassRule public static WireMockRule wireMockRule = new WireMockRule(9091);

worked for me.

Changing from :
@Rule public WireMockRule wireMockRule = new WireMockRule(9091);
to
@ClassRule public static WireMockRule wireMockRule = new WireMockRule(9091);

worked for me.

Helped me too

Having the same problem between test classes.

Already using ClassRule annotation because of Spring Boots SpringRunner.

Both tests use the same two WireMockRule with the same ports.

The order of the tests is not relevant.
First Test1 then Test2 and the first test method in Test2 using the rules fails.
First Test2 then Test1 and the first test method in Test1 using the rules fails.

Edit 1

Adding a sleep to the AfterClass solves the problem:

@AfterClass
public static void cleanUpClass() throws InterruptedException {
    Thread.sleep(5000L);
}

That can be considered as workaround.

Edit 2

I've added a fake test to the first called test class, which does not use any rules.

@Test
public void test() {
    Assert.assertTrue(true);
}

If only Test1#test is called and then Test2 it does not fail.

Edit 3

Internally I use a Feign client to call WireMock stubs. If I configure the HttpClient used by Feign in the way that all connections will be discarded the tests will not fail.

Edit 4

Feigns OkHttpClient does work, too. Only Feigns default HTTP client has the problem.

@sdoeringNew please can you post a test project with the failing tests?

Also, try these: https://github.com/tomakehurst/wiremock/issues/97#issuecomment-496681952

@tomakehurst If you don't mind that it is a Maven project, then yes.
I've just created a simple test application those tests are failing with the error: https://github.com/sdoeringNew/oh_noez_wiremock

I'll also look at the comment.

Ensure WireMock is starting and stopping in unison with the app under test. In practice this usually means using @ClassRule in JUnit rather than @Rule with the WireMockRule.

Already using @ClassRule and the error occurs.

Disable chunked transfer encoding (see http://wiremock.org/docs/configuration/#transfer-encoding)

No change.

Switch away from Java's HttpURLConnection as an HTTP client, as it has buggy connection pool handling in some circumstances. Note: many HTTP clients, including Spring's RestTemplate and the Jersey client will use this under the hood by default.

Already done that and the error would be gone.

If you're using the Netty HttpClient or something that wraps it such as Spring's reactive WebClient, ensure you have the latest version of the Netty dependency. See #914 (comment)

No Netty.

Turn off connection reuse in your HTTP client.

With the system property http.keepAlive=false the error is gone but a warning including stacktrace occurs:

2019-11-05 16:27:02.140  WARN 4564 --- [tp1035357140-33] o.eclipse.jetty.servlet.ServletHandler   : /test

java.nio.channels.ClosedChannelException: null
        at org.eclipse.jetty.util.IteratingCallback.close(IteratingCallback.java:459) ~[jetty-util-9.2.28.v20190418.jar:9.2.28.v20190418]
        .
        .
        .

If you're using Spring, use org.springframework.cloud:spring-cloud-contract-wiremock (as described in the previous comment). See https://cloud.spring.io/spring-cloud-contract/multi/multi__spring_cloud_contract_wiremock.html

Same error.

@sdoeringNew thanks for posting the test project.

When I run all tests I get an immediate connection reset error in test2:

feign.RetryableException: Connection reset executing POST http://localhost:8888/test
    at com.example.wiremock.Test1Test.test1(Test1Test.java:39)
Caused by: java.net.SocketException: Connection reset
    at com.example.wiremock.Test1Test.test1(Test1Test.java:39)

Is this also what you see?

Ah OK. Feign's default underlying client is HTTPUrlConnection, which would explain why this is happening.

HTTPUrlConnection will pool connections to localhot:8888 between tests unless you set http.keepAlive=false. So you will end up with a reference to a dead connection in the second test, since WireMock has been shut down and restarted in the meantime.

More advanced HTTP clients will detect this and create a fresh connection but HTTPUrlConnection won't. I've looked at this variation of the problem in the past, but I can't see any way this can be fixed at the WireMock end.

We configured wiremock to return

      "Connection": "close"

header. This also worked for us. Obviously not a great solution..

I'll mention this again - if you can possibly avoid using HTTPURLConnection (directly or as an underlying impl) then I'd say you should do that. It's not very good, and nearly always at the root of these kinds of problems.

I'll mention this again - if you can possibly avoid using HTTPURLConnection (directly or as an underlying impl) then I'd say you should do that. It's not very good, and nearly always at the root of these kinds of problems.

Agreed, sadly not a choice when a third party library uses it.

I'll mention this again - if you can possibly avoid using HTTPURLConnection (directly or as an underlying impl) then I'd say you should do that. It's not very good, and nearly always at the root of these kinds of problems.

Especially in JUnit tests or generally?

@sdoeringNew generally, I'd say. It's buggy and has very limited control over connection lifecycle.

Closing this as it's old, and not really a WireMock issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kmejka picture kmejka  Â·  15Comments

ntam picture ntam  Â·  13Comments

khanh-nguyen picture khanh-nguyen  Â·  18Comments

joegluntz picture joegluntz  Â·  130Comments

michaelrice picture michaelrice  Â·  17Comments