okhttp: `isCleartextTrafficPermitted()` fails on OpenJDK 8 + Robolectric

How to reproduce:

  • Install OpenJDK 8
  • Use current 3.3.0-SNAPSHOT version
  • new OkHttpClient(): The code fails in the static initializer, when trying to figure out the platform.

The code that breaks was introduced here: https://github.com/square/okhttp/issues/2513

Either the detection of the runtime is broken, or the code is wrong there. I’ll try to figure out an automatic test for this.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 17
  • Comments: 39 (15 by maintainers)

Commits related to this issue

Most upvoted comments

I was able to get the test green. Here’s what I did:

  1. Change to using OkHttp-3.3.1. The project was using a SNAPSHOT version, but 3.3 has since been released.
  2. Upgrade to robolectric 3.1-rc1.
  3. Added config annotation with SDK specified to the test class:
@RunWith(RobolectricGradleTestRunner.class)
@Config(sdk = 23)
public class CreateOkHttpClientTest {

As for why it works, I don’t know. It appears the default SDK is 21. The bit I don’t understand is why it isn’t throwing a ClassNotFoundException given this class is only in SDK 23. The test project itself is depending on API 23, which may have something to do with it.

Ouch. This (hideous) workaround also appears functional with 3.0,

@RunWith(RobolectricGradleTestRunner.class)
@Config(shadows = CreateOkHttpClientTest.MyNetworkSecurityPolicy.class)
public class CreateOkHttpClientTest {

  @Test
  public void canCreateAClient() throws Exception {
    OkHttpClient client = new OkHttpClient();
    assertNotNull(client);
  }

  @Implements(NetworkSecurityPolicy.class)
  public static class MyNetworkSecurityPolicy {
    @Implementation public static NetworkSecurityPolicy getInstance() {
      try {
        Class<?> shadow = MyNetworkSecurityPolicy.class.forName("android.security.NetworkSecurityPolicy");
        return (NetworkSecurityPolicy) shadow.newInstance();
      } catch (Exception e) {
        throw new AssertionError();
      }
    }

    @Implementation public boolean isCleartextTrafficPermitted() {
      return true;
    }
  }
}

Happens with OkHttp 3.5.0 and robolectric 3.1.4

Oh, It works if you add a String argument to the isCleartetTrafficPermitted shadow method. Here’s the updated (hideous) workaround:

@Implements(NetworkSecurityPolicy.class)
public class NetworkSecurityPolicyWorkaround {
    @Implementation
    public static NetworkSecurityPolicy getInstance() {
        //noinspection OverlyBroadCatchBlock
        try {
            Class<?> shadow = Class.forName("android.security.NetworkSecurityPolicy");
            return (NetworkSecurityPolicy) shadow.newInstance();
        } catch (Exception e) {
            throw new AssertionError();
        }
    }

    @Implementation
    public boolean isCleartextTrafficPermitted(String hostname) {
        return true;
    }
}

A truly terrible hack for those who can’t upgrade to Robolectric 3+ is to add the following class to your test module under the android.security package. Probably not a good idea if you’re testing the actual NetworkSecurityPolicy.

public class NetworkSecurityPolicy {
  private static final NetworkSecurityPolicy INSTANCE = new NetworkSecurityPolicy();

  public static NetworkSecurityPolicy getInstance() {
    return INSTANCE;
  }

  public boolean isCleartextTrafficPermitted() {
    return true;
  }
}

I’m getting

java.lang.AssertionError
    at okhttp3.internal.AndroidPlatform.isCleartextTrafficPermitted(AndroidPlatform.java:143)
    at okhttp3.OkHttpClient.<clinit>(OkHttpClient.java:73)
    at okhttp3.OkHttpClient$Builder.<init>(OkHttpClient.java:381)

with okhttp 3.3.1 and both robolectric 3.0 and 3.1-rc1 all good with okhttp 3.2.+