question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

MockWebServer tests got stuck after updating from 3.9.1 to 3.10.0

See original GitHub issue

After updating from 3.9.1 to 3.10.0 mockwebserver tests got stuck.

This is how I configure the HttpClient (I’m setting up HTTPS and Certificate Pinning ) 👀

private OkHttpClient configureHttpClient() {
    CertificatePinnerFactory factory = new CertificatePinnerFactory();
    OkHttpClient.Builder builder = client.newBuilder()
      .addInterceptor(new GzipRequestInterceptor())
      .retryOnConnectionFailure(true)
      .certificatePinner(factory.provideCertificatePinnerFor(environment))
      .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS));
    if (isSocketFactoryUnset(sslSocketFactory, x509TrustManager)) {
      builder.sslSocketFactory(sslSocketFactory, x509TrustManager);
    }

    return builder.build();
  }

3.9.1 👇

Feb 27, 2018 9:15:56 PM okhttp3.mockwebserver.MockWebServer$2 execute
INFO: MockWebServer[59072] starting to accept connections
Feb 27, 2018 9:15:57 PM okhttp3.mockwebserver.MockWebServer$3 processOneRequest
INFO: MockWebServer[59072] received request: POST /events/v2?access_token=anyAccessToken HTTP/1.1 and responded: HTTP/1.1 204 OK

3.10.0 👇

Feb 27, 2018 9:12:04 PM okhttp3.mockwebserver.MockWebServer$2 execute
INFO: MockWebServer[59055] starting to accept connections
Feb 27, 2018 9:12:06 PM okhttp3.mockwebserver.MockWebServer$3 processConnection
WARNING: MockWebServer[59055] connection from /127.0.0.1 didn't make a request

Following you can find a failing test 👀

package com.mapbox.android.telemetry;


import android.content.Context;

import org.junit.Test;

import java.net.HttpURLConnection;
import java.util.Arrays;
import java.util.List;

import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import okhttp3.internal.tls.SslClient;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;

public class Foo {

  @Test
  public void foo() throws Exception {
    MockWebServer server = new MockWebServer();
    server.useHttps(SslClient.localhost().socketFactory, false);
    server.start();
    Context mockedContext = mock(Context.class, RETURNS_DEEP_STUBS);
    MapboxTelemetry.applicationContext = mockedContext;
    TelemetryClient telemetryClient = obtainATelemetryClient("anyAccessToken", "anyUserAgent", server);
    List<Event> mockedEvent = obtainAnEvent();
    MockResponse mockResponse = new MockResponse();
    mockResponse.setResponseCode(HttpURLConnection.HTTP_NO_CONTENT);
    mockResponse.setBody("");
    server.enqueue(mockResponse);
    Callback mockedCallback = mock(Callback.class);

    telemetryClient.sendEvents(mockedEvent, mockedCallback);

    RecordedRequest request = server.takeRequest();
    assertEquals("/events/v2?access_token=anyAccessToken", request.getPath());
  }

  TelemetryClient obtainATelemetryClient(String accessToken, String userAgent, MockWebServer server) {
    TelemetryClientSettings mockedTelemetryClientSettings = provideDefaultTelemetryClientSettings(server);
    Logger mockedLogger = mock(Logger.class);
    return new TelemetryClient(accessToken, userAgent, mockedTelemetryClientSettings, mockedLogger);
  }

  private TelemetryClientSettings provideDefaultTelemetryClientSettings(MockWebServer server) {
    HttpUrl localUrl = obtainBaseEndpointUrl(server);
    SslClient sslClient = SslClient.localhost();

    return new TelemetryClientSettings.Builder()
      .baseUrl(localUrl)
      .sslSocketFactory(sslClient.socketFactory)
      .x509TrustManager(sslClient.trustManager)
      .build();
  }

  private List<Event> obtainAnEvent() {
    Event theEvent = new AppUserTurnstile("anySdkIdentifier", "anySdkVersion", false);

    return obtainEvents(theEvent);
  }

  private List<Event> obtainEvents(Event... theEvents) {
    return Arrays.asList(theEvents);
  }

  private HttpUrl obtainBaseEndpointUrl(MockWebServer server) {
    return server.url("/");
  }
}

☝️ is using https://github.com/mapbox/mapbox-events-android code.

You can check that we only bumped OkHttp version to 3.10.0 👉 https://github.com/mapbox/mapbox-events-android/commit/c92a4acdf684cedc003c769f44a62c345ce596f9 and after that tests got stuck.

Tried many things without luck 😓 Any hints? What did it change that could affect tests in that sense?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
Guardiola31337commented, Mar 2, 2018

Mystery solved! Well partially…

After a thoroughly debug session, @Sefford told me that when he bumped OkHttp version to 3.10.0, he started getting SSLPeerUnverifiedException: Hostname localhost not verified messages in their tests and he fixed it adding

.hostnameVerifier(new HostnameVerifier() {
  @Override
  public boolean verify(String hostname, SSLSession session) {
    return true;
  }
})

to the config of the OkHttpClient used in their tests. I wasn’t getting those messages because I’m mocking the Callback so they weren’t logged.

Thanks @Sefford for pointing me in that direction 🙏

It seems that after https://github.com/square/okhttp/pull/3764 changes if you’re using MockWebServer with HTTPS you need to add ☝️ to your tests in order to have them ✅ It’d be great if we could add that to the documentation somehow (if that’s the best solution to follow in these cases).

After adding that config to my tests everything is working again 💃

But now I’m wondering why even when passing in an empty Callback implementation (without adding the hostname verifier stub) tests still get stuck. Shouldn’t the exception bubble up and stop the execution of the test if the hostname is not verified? It seems that although the Callback is fired it’s not sending the notification to the lock properly and it remains opened forever. Does that make sense?

Let me know if it’s worth it to open a new issue reporting ☝️ or if you prefer to keep the discussion here.

0reactions
swankjessecommented, Jul 5, 2018

No action to take on this, other than to be afraid of how mocks + onFailure interact poorly.

Read more comments on GitHub >

github_iconTop Results From Across the Web

OkHttp MockWebServer fails to accept connections when ...
As I understand the setUp method happens before each test method, which means that a new instance of the mock server is created...
Read more >
3.x Change Log - OkHttp
Fix: Don't create malformed URLs when MockWebServer is reached via an IPv6 address. Fix: Don't crash if the system default authenticator is null....
Read more >
Test Spring WebClient with MockWebServer from OkHttp
Write tests for your Spring WebClient usage with OkHttp's MockWebServer and mock HTTP responses to test different scenarios.
Read more >
Mockito 3.10.0 API - javadoc.io
The Mockito library enables mock creation, verification and stubbing. This javadoc content is also available on the https://site.mockito.org/ web page.
Read more >
The Recommended Way Of Testing HTTP Calls ... - Medium
This testing library is built by the Square Team to easily test how the apps behave when making API calls. A mock web...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found