Issue#41 Copy full example into separate module with Hilt Integration
This commit is contained in:
parent
69e76dc0da
commit
52a99a82fc
229 changed files with 8416 additions and 11 deletions
1
hilt/hilt-network-di-test-util/.gitignore
vendored
Normal file
1
hilt/hilt-network-di-test-util/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
43
hilt/hilt-network-di-test-util/build.gradle
Normal file
43
hilt/hilt-network-di-test-util/build.gradle
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
plugins {
|
||||
id 'com.android.library'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk 31
|
||||
|
||||
defaultConfig {
|
||||
minSdk 21
|
||||
targetSdk 31
|
||||
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = false
|
||||
}
|
||||
}
|
||||
|
||||
// since it itself contains the TestUtil it doesn't have tests of it's own
|
||||
disableTestTasks(this)
|
||||
|
||||
dependencies {
|
||||
implementation project(":hilt:hilt-network")
|
||||
implementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||
implementation project(':mockserver')
|
||||
implementation "androidx.test.espresso:espresso-core:$espresso_version"
|
||||
}
|
||||
0
hilt/hilt-network-di-test-util/consumer-rules.pro
Normal file
0
hilt/hilt-network-di-test-util/consumer-rules.pro
Normal file
21
hilt/hilt-network-di-test-util/proguard-rules.pro
vendored
Normal file
21
hilt/hilt-network-di-test-util/proguard-rules.pro
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.fnives.test.showcase.hilt.network.testutil">
|
||||
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package org.fnives.test.showcase.hilt.network.testutil
|
||||
|
||||
import okhttp3.tls.HandshakeCertificates
|
||||
import org.fnives.test.showcase.hilt.network.di.HiltNetworkModule
|
||||
import org.fnives.test.showcase.hilt.network.shared.PlatformInterceptor
|
||||
import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup
|
||||
|
||||
// @Module
|
||||
// @TestInstallIn(
|
||||
// components = [SingletonComponent::class],
|
||||
// replaces = [BindsBaseOkHttpClient::class]
|
||||
// )
|
||||
object HttpsConfigurationModuleTemplate {
|
||||
|
||||
lateinit var handshakeCertificates: HandshakeCertificates
|
||||
|
||||
// @Provides
|
||||
// @Singleton
|
||||
// @SessionLessQualifier
|
||||
fun bindsBaseOkHttpClient(enableLogging: Boolean, platformInterceptor: PlatformInterceptor) =
|
||||
HiltNetworkModule.provideSessionLessOkHttpClient(enableLogging, platformInterceptor)
|
||||
.newBuilder()
|
||||
.sslSocketFactory(
|
||||
handshakeCertificates.sslSocketFactory(),
|
||||
handshakeCertificates.trustManager
|
||||
)
|
||||
.build()
|
||||
|
||||
fun startWithHTTPSMockWebServer(): Pair<MockServerScenarioSetup, String> {
|
||||
val mockServerScenarioSetup = MockServerScenarioSetup()
|
||||
val url = mockServerScenarioSetup.start(true)
|
||||
|
||||
handshakeCertificates = mockServerScenarioSetup.clientCertificates
|
||||
?: throw IllegalStateException("ClientCertificate should be accessable")
|
||||
|
||||
return mockServerScenarioSetup to url
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package org.fnives.test.showcase.hilt.network.testutil
|
||||
|
||||
import androidx.annotation.CheckResult
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import okhttp3.OkHttpClient
|
||||
import org.fnives.test.showcase.hilt.network.di.SessionLessQualifier
|
||||
import org.fnives.test.showcase.hilt.network.di.SessionQualifier
|
||||
import javax.inject.Inject
|
||||
|
||||
class NetworkSynchronization @Inject constructor(
|
||||
@SessionQualifier
|
||||
private val sessionOkhttpClient: OkHttpClient,
|
||||
@SessionLessQualifier
|
||||
private val sessionlessOkhttpClient: OkHttpClient
|
||||
) {
|
||||
|
||||
@CheckResult
|
||||
fun networkIdlingResources(): List<IdlingResource> =
|
||||
OkHttpClientTypes.values()
|
||||
.map { it to getOkHttpClient(it) }
|
||||
.associateBy { it.second.dispatcher }
|
||||
.values
|
||||
.map { (key, client) -> client.asIdlingResource(key.qualifier) }
|
||||
|
||||
private fun getOkHttpClient(type: OkHttpClientTypes): OkHttpClient =
|
||||
when (type) {
|
||||
OkHttpClientTypes.SESSION -> sessionOkhttpClient
|
||||
OkHttpClientTypes.SESSIONLESS -> sessionlessOkhttpClient
|
||||
}
|
||||
|
||||
private fun OkHttpClient.asIdlingResource(name: String): IdlingResource =
|
||||
OkHttp3IdlingResource.create(name, this)
|
||||
|
||||
enum class OkHttpClientTypes(val qualifier: String) {
|
||||
SESSION("SESSION-NETWORKING"), SESSIONLESS("SESSIONLESS-NETWORKING")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package org.fnives.test.showcase.hilt.network.testutil
|
||||
|
||||
import androidx.annotation.CheckResult
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import okhttp3.Dispatcher
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
/**
|
||||
* AndroidX version of Jake Wharton's OkHttp3IdlingResource.
|
||||
*
|
||||
* Reference: https://github.com/JakeWharton/okhttp-idling-resource/blob/master/src/main/java/com/jakewharton/espresso/OkHttp3IdlingResource.java
|
||||
*/
|
||||
class OkHttp3IdlingResource private constructor(
|
||||
private val name: String,
|
||||
private val dispatcher: Dispatcher
|
||||
) : IdlingResource {
|
||||
@Volatile
|
||||
var callback: IdlingResource.ResourceCallback? = null
|
||||
private var isIdleCallbackWasCalled: Boolean = true
|
||||
|
||||
init {
|
||||
val currentCallback = dispatcher.idleCallback
|
||||
dispatcher.idleCallback = Runnable {
|
||||
sleepForDispatcherDefaultCallInRetrofitErrorState()
|
||||
callback?.onTransitionToIdle()
|
||||
currentCallback?.run()
|
||||
isIdleCallbackWasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun getName(): String = name
|
||||
|
||||
override fun isIdleNow(): Boolean {
|
||||
val isIdle = dispatcher.runningCallsCount() == 0
|
||||
if (isIdle) {
|
||||
// sometime the callback is just not properly called it seems, or maybe sync error.
|
||||
// if it isn't called Espresso crashes, so we add this here.
|
||||
callback?.onTransitionToIdle()
|
||||
}
|
||||
return isIdle
|
||||
}
|
||||
|
||||
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
|
||||
this.callback = callback
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Create a new [IdlingResource] from `client` as `name`. You must register
|
||||
* this instance using `Espresso.registerIdlingResources`.
|
||||
*/
|
||||
@CheckResult
|
||||
@NonNull
|
||||
fun create(@NonNull name: String?, @NonNull client: OkHttpClient?): OkHttp3IdlingResource {
|
||||
if (name == null) throw NullPointerException("name == null")
|
||||
if (client == null) throw NullPointerException("client == null")
|
||||
return OkHttp3IdlingResource(name, client.dispatcher)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is required, because in case of Errors Retrofit uses Dispatcher.Default to suspendThrow
|
||||
* see: retrofit2.KotlinExtensions.kt Exception.suspendAndThrow
|
||||
* Relevant code issue: https://github.com/square/retrofit/blob/6cd6f7d8287f73909614cb7300fcde05f5719750/retrofit/src/main/java/retrofit2/KotlinExtensions.kt#L121
|
||||
* This is the current suggested approach to their problem with Unchecked Exceptions
|
||||
*
|
||||
* Sadly Dispatcher.Default cannot be replaced yet, so we can't swap it out in tests:
|
||||
* https://github.com/Kotlin/kotlinx.coroutines/issues/1365
|
||||
*
|
||||
* This brings us to this sleep for now.
|
||||
*/
|
||||
fun sleepForDispatcherDefaultCallInRetrofitErrorState() {
|
||||
Thread.sleep(200L)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue