Augusto
Augusto

Reputation: 29997

Parallel calls to wiremock not returning the stubbed value

I'm running into some issues when I execute tests in parallel, it looks like there might be something wrong with the way I've setup wiremock (v2.27.2) or there is an internal race condition inside wiremock.

Here's an example that runs 100 threads on a fixed thread pool.

public class WiremockTest {
  private static final String BODY = "body";
  private static WireMockServer wireMockServer;

  @BeforeAll
  public static void setup() {
    wireMockServer = new WireMockServer(wireMockConfig().dynamicPort());
    wireMockServer.start();
  }

  @Test
  void concurrentWireMock() throws InterruptedException {
    final var wiremock = new WireMock("localhost", wireMockServer.port());
    final var okHttp = new OkHttpClient.Builder().build();

    var exec = Executors.newFixedThreadPool(12);
    for (int i = 0; i < 100; i++) {
      exec.submit(() -> execute(wiremock, okHttp));
    }

    exec.shutdown();
    exec.awaitTermination(5, TimeUnit.SECONDS);
  }

  void execute(WireMock wiremock, OkHttpClient okHttp) {
    UUID uuid = UUID.randomUUID();
    var url = String.format("/v1/item/%s", uuid);

    wiremock.register(get(url)
        .willReturn(
            aResponse()
                .withStatus(HttpStatus.OK.value())
                .withBody(BODY)
        ));

    var getRequest = new Request.Builder()
        .url(wireMockServer.baseUrl() + url)
        .get()
        .build();
    try {
      var response = okHttp.newCall(getRequest).execute();
      String actualBody = response.body().string();
      if (!actualBody.equals(BODY)) {
        System.out.printf("Body didn't match. Expected:\n%s\nActual:\n%s\n", BODY, actualBody);
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
}

Running the above I usually get 1 or 2 errors from the 100 runs in which wiremock throws a NPE. For example, this is a summary of the output of one error:

Body didn't match. Expected:
body
Actual:
<html>
<head>
[...]
<tr><th>URI:</th><td>/v1/item/e318684f-e061-4fee-9acb-36027aa88c5b</td></tr>
<tr><th>STATUS:</th><td>500</td></tr>
<tr><th>MESSAGE:</th><td>java.lang.NullPointerException</td></tr>
<tr><th>SERVLET:</th><td>com.github.tomakehurst.wiremock.servlet.WireMockHandlerDispatchingServlet-2a87176b</td></tr>
<tr><th>CAUSED BY:</th><td>java.lang.NullPointerException</td></tr>
</table>
<h3>Caused by:</h3><pre>java.lang.NullPointerException
    at com.github.tomakehurst.wiremock.servlet.WireMockHandlerDispatchingServlet.service(WireMockHandlerDispatchingServlet.java:120)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:779)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:760)
[...]
</body>
</html>

I'm wondering if I'm doing something wrong in my setup that is triggering this issue.

Upvotes: 0

Views: 1088

Answers (1)

Augusto
Augusto

Reputation: 29997

I did find an answer looking at the bug tracker. The issues seems to be that WireMockServer.start() returns a bit too early for wiremock to start accepting calls.

There's a workaround on the ticket

We now have a workaround and add a simple e.g. /readiness/wiremock stub right after starting the WireMockServer and try to hit it with a simple retry-mechanism and once HTTP status 200 returns we continue we our setup.

There's also a proposal to add a health endpoint on wiremock which would remove the need for the stub above, but one would still require to wait until wiremock is fully loaded and ready to receive requests.

Upvotes: 0

Related Questions