Okhttp: MockWebServer tests hang when run in suite.

Created on 25 Oct 2017  路  7Comments  路  Source: square/okhttp

I am having an issue running a suite of tests with some of the tests using MockWebServer. I really don't know where the error is, that's why I'm not including any failing unit tests.

The suite of tests is for an Android application which is transitioning into Kotlin. The application is using RxJava and Volley and it is using MockWebServer to test the API calls. The application is using Robolectric to test with the Android dependencies.

When each of the tests in the suite are run individually, the test runs successfully but when running the whole suite, the suite hangs when getting to one of the tests using MockWebServer. MockWebServer is started in the @BeforeClass and the shutdown method is called in the @AfterClass in each test.

The reason why it hags is because I'm using a Volley RequestFuture to turn it into a Single (using Single.fromFuture() without providing timeout). My hunch is that from the second time onwards, MockWebserver is not been started for some reason.

I have ruled out that it could be a problem in the machine since I've encountered the same issue in the CI server as well as in my working laptop.

The tests are very simple. I enqueue the responses, I call the production code and I use takeRequest without timeout to receive the request and then checking the result. The tests are also using a TestScheduler for the IO scheduler. I may be missing something. Do you have any ideas? Thanks in advance for your help.

Most helpful comment

I don't know if this is related, but I had to add a timeout to takeRequest or MockWebServer would hang forever:

RecordedRequest request = server.takeRequest(1, TimeUnit.SECONDS);

All 7 comments

We don鈥檛 have this problem in OkHttp鈥檚 own tests. Could you provide a small executable example of the problem?

I've been able to replicate the same behaviour in a little example with one single test. I've been debugging it but I haven't found the issue yet. This example is slightly different that the one I reported. This one uses a custom Volley listener and hangs because I have a call to waitTerminalEvent in the TestObserver. I think the issue in both cases is the same.

I don't really know why I'm having the issue. Hopefully, you guys can give me some clues as to why this is happening. If you remove the line that calls await terminal event, you are going to find that the test fails because the listener is not emitting any events. The listener is also unit tested and all its tests are passing. Anyway, here is the link. Thanks in advance for your help.

https://github.com/psa-anddev/rxvolleylistener

I have been able to solve the issue. It turns out that the problem wasn't with MockWebServer but with Robolectric. The problem was because of the use Volley does of executors. The solution is therefore create a new implementation of ResponseDelivery that will just deliver the responses in the same thread. Once that is done, the test passes. If you are interested in how to solve it, just go to the linked repository and check the last two commits.

I was having the same issue today and couldn't find a solution online. I am using Retrofit which bundles with okHTTP and it always hangs forever only when running on a test suite but weirdly works when manually running single test.

After sometime playing around and trying find a way to fix it, I realized that if the Robolectric is configured to run on sdk = >25 it works like a charms but if it is not configured or sdk is '<25' it will hang forever.

This is for sure a Robolectric issue that resulted to a limbo when trying to do a requesr through the mock server.

I don't know if this is related, but I had to add a timeout to takeRequest or MockWebServer would hang forever:

RecordedRequest request = server.takeRequest(1, TimeUnit.SECONDS);

Thanks man @dtandersen ! It works like a charm, an alternative is to use takeRequest() without parameter instead.

If you take a look at the source code, you will find out the reason.

takeRequest(long timeout, TimeUnit unit)

Awaits the next HTTP request (waiting up to the specified wait time if necessary), removes it, and returns it. Callers should use this to verify the request was sent as intended within the given time.

takeRequest()

Awaits the next HTTP request, removes it, and returns it. Callers should use this to verify the request was sent as intended. This method will block until the request is available, possibly forever.

Therefore, another way is as below:

// This method will block until the request is available, possibly forever.
server.takeRequest();

// verify the behavior
verify()
assert()

...

I'm not sure but adding TimeUnit throws IllegalStateException.

java.lang.IllegalStateException: srv!!.takeRequest(1, TimeUnit.SECONDS) must not be null

Does anybody have this issue?

Was this page helpful?
0 / 5 - 0 ratings