Search code examples
androidtestingretrofitandroid-testingmockwebserver

MockWebserver Retrofit - SSLHandshakeException: connection closed


I am writing a UI test using Espresso, Dagger2, Retrofit, and MockWebserver for mocking API response. I follow this tutorial by Weidian Huang on medium -> full github source here. Iam not using SSL pinning so I remote it. But I got problem when trying to change webmockserver interceptor. The log show error line is here chain.proceed(request).

class DebugUrlInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        var request: Request = chain.request()
        if (MockServerManager.shouldMockApi(request.url.encodedPath)) {
            val newUrl: HttpUrl = request.url.newBuilder()
                .scheme(MockServerManager.HTTPS_SCHEME)
                .host(MockServerManager.HOST)
                .port(MockServerManager.port)
                .build()

            request = request.newBuilder()
                .url(newUrl)
                .headers(request.headers)
                .method(request.method, request.body)
                .build()
        }
        return chain.proceed(request)
    }
}

I did use x509Trustmanager but it's still not working.

    @Provides
    @Named("unsafe")
    fun provideUnSafeOkHttpClient(okHttpClientBuilder: OkHttpClient.Builder): OkHttpClient {
        val x509TrustManager = @SuppressLint("CustomX509TrustManager")
        object : X509TrustManager {
            @SuppressLint("TrustAllX509TrustManager")
            override fun checkClientTrusted(
                chain: Array<out X509Certificate>?,
                authType: String?
            ) {
            }

            @SuppressLint("TrustAllX509TrustManager")
            override fun checkServerTrusted(
                chain: Array<out X509Certificate>?,
                authType: String?
            ) {
            }

            override fun getAcceptedIssuers(): Array<X509Certificate> {
                return arrayOf()
            }
        }

        val trustManagers = arrayOf<TrustManager>(x509TrustManager)

        val sslContext = SSLContext.getInstance("SSL")
        sslContext.init(null, trustManagers, java.security.SecureRandom())

        okHttpClientBuilder.sslSocketFactory(sslContext.socketFactory, x509TrustManager)
        okHttpClientBuilder.hostnameVerifier { _, _ -> true }

        return okHttpClientBuilder.build()
    }

Full error logs:

  javax.net.ssl.SSLHandshakeException: connection closed
 W      at com.android.org.conscrypt.SSLUtils.toSSLHandshakeException(SSLUtils.java:362)
 W      at com.android.org.conscrypt.ConscryptEngineSocket.doHandshake(ConscryptEngineSocket.java:240)
 W      at com.android.org.conscrypt.ConscryptEngineSocket.startHandshake(ConscryptEngineSocket.java:217)
 W      at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:379)
 W      at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337)
 W      at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209)
 W      at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
 W      at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
 W      at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
 W      at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
 W      at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
 W      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
 W      at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
 W      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
 W      at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
 W      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
 W      at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
 W      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
 W      at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.kt:221)
 W      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
 W      at com.jinjerkeihi.api.DebugUrlInterceptor.intercept(DebugUrlInterceptor.kt:29)
 W      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
 W      at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
 W      at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
 W      at retrofit2.OkHttpCall.execute(OkHttpCall.java:204)
 W      at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:46)
 W      at io.reactivex.Observable.subscribe(Observable.java:12246)
 W      at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:35)
 W      at io.reactivex.Observable.subscribe(Observable.java:12246)
 W      at io.reactivex.internal.operators.observable.ObservableSingleSingle.subscribeActual(ObservableSingleSingle.java:35)
 W      at io.reactivex.Single.subscribe(Single.java:3575)
 W      at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
 W      at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
 W      at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)

Do anyone done this before please help, I've spent a day for that :((


Solution

  • The problem is here:

    val newUrl: HttpUrl = request.url.newBuilder()
                    .scheme(MockServerManager.HTTPS_SCHEME)
                    .host(MockServerManager.HOST)
                    .port(MockServerManager.port)
                    .build()
    

    It's need to be HTTP_SCHEME instead of HTTPS_SCHEME