Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ability to pass customer defined okhttp client #89

Merged
merged 2 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.getunleash.android

import io.getunleash.android.backup.LocalStorageConfig
import io.getunleash.android.data.DataStrategy
import okhttp3.OkHttpClient
import java.util.UUID

/**
Expand All @@ -11,6 +12,7 @@ import java.util.UUID
* @property appName: name of the underlying application. Will be used as default in the [io.getunleash.android.data.UnleashContext] call (Required).
* @property pollingStrategy How to poll for features. (Optional - Defaults to [io.getunleash.android.data.DataStrategy] with poll interval set to 60 seconds).
* @property metricsStrategy How to poll for metrics. (Optional - Defaults to [io.getunleash.android.data.DataStrategy] with poll interval set to 60 seconds).
* @property httpClient Custom http client to be used. (Optional - Use if you want to pass in custom SSL certificates).
*/
data class UnleashConfig(
val proxyUrl: String?,
Expand All @@ -24,7 +26,8 @@ data class UnleashConfig(
pauseOnBackground = true,
),
val delayedInitialization: Boolean = true,
val forceImpressionData: Boolean = false
val forceImpressionData: Boolean = false,
val httpClient: OkHttpClient? = null,
) {
companion object {
val instanceId: String = UUID.randomUUID().toString()
Expand Down Expand Up @@ -62,6 +65,7 @@ data class UnleashConfig(
.newBuilder(parent = this)
val localStorageConfig: LocalStorageConfig.Builder = LocalStorageConfig()
.newBuilder(parent = this)
var httpClient: OkHttpClient? = null
fun build(): UnleashConfig {
if ((proxyUrl == null || clientKey == null) && (pollingStrategy.enabled || metricsStrategy.enabled)) {
throw IllegalStateException("You must either set proxyUrl and clientKey or disable both polling and metrics.")
Expand All @@ -74,7 +78,8 @@ data class UnleashConfig(
metricsStrategy = metricsStrategy.build(),
delayedInitialization = delayedInitialization,
forceImpressionData = forceImpressionData,
localStorageConfig = localStorageConfig.build()
localStorageConfig = localStorageConfig.build(),
httpClient = httpClient
)
}

Expand All @@ -86,5 +91,9 @@ data class UnleashConfig(

fun forceImpressionData(forceImpressionData: Boolean) =
apply { this.forceImpressionData = forceImpressionData }

fun httpClient(httpClient: OkHttpClient) = apply {
this.httpClient = httpClient
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package io.getunleash.android.data

import io.getunleash.android.UnleashConfig
import okhttp3.OkHttpClient

/**
* @property enabled Whether the strategy is enabled or not. (Optional - Defaults to true)
* @property interval How often to perform the operation in milliseconds. (Optional - Defaults to 60000)
* @property delay How long to wait before starting the operation in milliseconds. (Optional - Defaults to 0)
* @property pauseOnBackground Whether the operation should pause when the app is in background. (Optional - Defaults to true)
* @property httpReadTimeout How long to wait for HTTP reads in milliseconds. (Optional - Defaults to 5000)
* @property httpWriteTimeout How long to wait for HTTP writes in milliseconds. (Optional - Defaults to 5000)
* @property httpConnectionTimeout How long to wait for HTTP connection in milliseconds. (Optional - Defaults to 2000)
* @property httpCacheSize Disk space (in bytes) set aside for http cache. (Optional - Defaults to 10MB)
* @property httpCustomHeaders Enables users to override httpCustomHeaders. (Optional - Defaults to empty)
Expand All @@ -19,6 +21,7 @@ data class DataStrategy(
val pauseOnBackground: Boolean = true,
val httpConnectionTimeout: Long = 2000,
val httpReadTimeout: Long = 5000,
val httpWriteTimeout: Long = 5000,
val httpCacheSize: Long = 1024 * 1024 * 10,
val httpCustomHeaders: Map<String, String> = emptyMap(),
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ class ClientBuilder(private val unleashConfig: UnleashConfig, private val androi
clientName: String,
strategy: DataStrategy
): OkHttpClient {
val builder = OkHttpClient.Builder()
// either use the provided client or create a new one
val clientBuilder = unleashConfig.httpClient?.newBuilder() ?: OkHttpClient.Builder()
val builder = clientBuilder
.readTimeout(strategy.httpReadTimeout, TimeUnit.MILLISECONDS)
.writeTimeout(strategy.httpWriteTimeout, TimeUnit.MILLISECONDS)
.connectTimeout(strategy.httpConnectionTimeout, TimeUnit.MILLISECONDS)
if (unleashConfig.localStorageConfig.enabled) {
builder.cache(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@ package io.getunleash.android.http
import android.content.Context
import io.getunleash.android.BaseTest
import io.getunleash.android.UnleashConfig
import okhttp3.OkHttpClient
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import java.util.concurrent.TimeUnit
import kotlin.io.path.createTempDirectory

class ClientBuilderTest : BaseTest() {
Expand Down Expand Up @@ -38,4 +46,24 @@ class ClientBuilderTest : BaseTest() {

assertThat(client.cache).isNull()
}

@Test
fun `when http client is provided by customer we should use it`() {
val builder = spy(OkHttpClient.Builder())
val customHttpClient = mock(OkHttpClient::class.java)
`when`(customHttpClient.newBuilder()).thenReturn(builder)
val config =
UnleashConfig.newBuilder("my-app")
.proxyUrl("https://localhost:4242/proxy")
.httpClient(customHttpClient)
.localStorageConfig.enabled(false)
.clientKey("some-key").build()

val clientBuilder = ClientBuilder(config, mock(Context::class.java))
clientBuilder.build("clientName", config.pollingStrategy)

verify(builder).readTimeout(5000, TimeUnit.MILLISECONDS)
verify(builder).writeTimeout(5000, TimeUnit.MILLISECONDS)
verify(builder).connectTimeout(2000, TimeUnit.MILLISECONDS)
}
}