Skip to content

Commit

Permalink
Task/reduce min sdk to21 (#9)
Browse files Browse the repository at this point in the history
* Removed all java.time usage

* fix: Update readme to point out that we've reverted to milliseconds for all durations

* Added a couple of more tests of the builders

* chore: also add a test that checks that we can configure http client with cache

* fix: add readme note about minimum sdk level
  • Loading branch information
Christopher Kolstad authored Sep 7, 2021
1 parent 563d1fb commit 4361d3d
Show file tree
Hide file tree
Showing 23 changed files with 225 additions and 101 deletions.
34 changes: 5 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,8 @@ You will require the SDK on your classpath, so go ahead and add it to your gradl
implementation("io.getunleash:unleash-android-proxy-sdk:${unleash.sdk.version}")
```

### Add support for minSdk < 24

```kotlin
android {
defaultConfig {
// Required when setting minSdkVersion to 20 or lower
multiDexEnabled = true
}

compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled = true
// Sets Java compatibility to Java 8
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
// ...
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5")

// ...
}
```
Reference: https://developer.android.com/studio/write/java8-support

### Minimum Android SDK
- Currently aiming for a minimum SDK level of 21. Keeping in tune with OkHttp's requirement.

### Now configure your client instance

Expand Down Expand Up @@ -65,7 +41,7 @@ val context = UnleashContext.newBuilder()
val config = UnleashConfig.newBuilder()
.proxyUrl("URL to your proxy installation")
.clientSecret("yourProxyApiKey")
.pollMode(PollingModes.autoPoll(Duration.ofSeconds(60)) {
.pollMode(PollingModes.autoPoll(60000) { // poll interval in milliseconds
featuresUpdated()
})
.build()
Expand Down Expand Up @@ -100,7 +76,7 @@ val context = UnleashContext.newBuilder()
val config = UnleashConfig.newBuilder()
.proxyUrl("URL to your proxy installation")
.clientSecret("yourProxyApiKey")
.pollMode(PollingModes.autoPoll(Duration.ofSeconds(60)) {
.pollMode(PollingModes.autoPoll(60000) { poll interval in milliseconds
featuresUpdated()
})
.build()
Expand Down Expand Up @@ -144,6 +120,6 @@ val config = UnleashConfig

The default configuration configures a daemon to report metrics once every minute, this can be altered using the `metricsInterval(Duration d)` method on the builder, so if you'd rather see us post in 5 minutes intervals you could do
```kotlin
UnleasConfig().newBuilder().metricsInterval(Duration.ofMinutes(5))
UnleashConfig().newBuilder().metricsInterval(300000) // Every 5 minutes
```

19 changes: 10 additions & 9 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@ jacoco {
dependencies {
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("com.fasterxml.jackson.core:jackson-databind:2.12.3")
implementation("com.fasterxml.jackson.core:jackson-core:2.12.3")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3")
implementation("com.fasterxml.jackson.core:jackson-databind:2.12.5")
implementation("com.fasterxml.jackson.core:jackson-core:2.12.5")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.5")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.5")
implementation("net.sourceforge.streamsupport:android-retrofuture:1.7.3")
api("com.squareup.okhttp3:okhttp:4.9.1")
api("org.slf4j:slf4j-api:1.7.30")
api("org.slf4j:slf4j-api:1.7.32")

testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.2")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.2")
testImplementation("org.assertj:assertj-core:3.19.0")
testImplementation("org.assertj:assertj-core:3.20.2")
testImplementation("com.squareup.okhttp3:mockwebserver:4.9.1")
testImplementation("org.mockito.kotlin:mockito-kotlin:3.2.0")
testImplementation("org.slf4j:slf4j-simple:1.7.30")
testImplementation("org.slf4j:slf4j-simple:1.7.32")
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
Expand All @@ -62,9 +62,10 @@ tasks.withType<Test> {
tasks.jacocoTestReport {
dependsOn(tasks.test) // tests are required to run before generating the report
reports {
xml.isEnabled = true
html.isEnabled = true
xml.required.set(true)
html.required.set(true)
}

}


Expand Down
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
distributionSha256Sum=0e46229820205440b48a5501122002842b82886e76af35f0f3a069243dca4b3c
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionSha256Sum=f581709a9c35e9cb92e16f585d2c4bc99b2b1a5f85d2badbd3dc6bff59e1e6dd
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
4 changes: 2 additions & 2 deletions samples/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ android {

defaultConfig {
applicationId "com.example.unleash"
minSdkVersion 26
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
Expand Down Expand Up @@ -50,7 +50,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
implementation 'io.getunleash:unleash-android-proxy-sdk:0.1.2-SNAPSHOT'
implementation 'io.getunleash:unleash-android-proxy-sdk:0.2.1-SNAPSHOT'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ internal object UnleashClientModule {
.appName("unleash-android")
.instanceId("unleash-android-${Random.nextLong()}")
.environment("dev")
.clientSecret("proxy-123")
.clientSecret("s1")
.proxyUrl("http://192.168.1.42:3200/proxy")
.enableMetrics()
.pollingMode(
Expand Down
13 changes: 7 additions & 6 deletions src/main/kotlin/io/getunleash/UnleashClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.security.InvalidParameterException
import java9.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit
import kotlin.concurrent.timer

/**
Expand All @@ -30,8 +31,8 @@ class UnleashClient(
val unleashConfig: UnleashConfig,
var unleashContext: UnleashContext = UnleashContext(),
val httpClient: OkHttpClient = OkHttpClient.Builder()
.readTimeout(unleashConfig.httpClientReadTimeout)
.connectTimeout(unleashConfig.httpClientConnectionTimeout)
.readTimeout(unleashConfig.httpClientReadTimeout, TimeUnit.MILLISECONDS)
.connectTimeout(unleashConfig.httpClientConnectionTimeout, TimeUnit.MILLISECONDS)
.cache(
Cache(
directory = CacheDirectoryProvider().getCacheDirectory(),
Expand Down Expand Up @@ -65,8 +66,8 @@ class UnleashClient(
timer(
name = "unleash_report_metrics",
daemon = true,
initialDelay = unleashConfig.reportMetrics.metricsInterval.toMillis(),
period = unleashConfig.reportMetrics.metricsInterval.toMillis()
initialDelay = unleashConfig.reportMetrics.metricsInterval,
period = unleashConfig.reportMetrics.metricsInterval
) {
metricsReporter.reportMetrics()
}
Expand Down Expand Up @@ -119,8 +120,8 @@ class UnleashClient(
?: throw IllegalStateException("You must set an UnleashConfig for your UnleashClient"),
unleashContext = this.unleashContext ?: UnleashContext(),
httpClient = this.httpClient ?: OkHttpClient.Builder()
.readTimeout(unleashConfig!!.httpClientReadTimeout)
.connectTimeout(unleashConfig!!.httpClientConnectionTimeout)
.readTimeout(unleashConfig!!.httpClientReadTimeout, TimeUnit.MILLISECONDS)
.connectTimeout(unleashConfig!!.httpClientConnectionTimeout, TimeUnit.MILLISECONDS)
.cache(
Cache(
directory = CacheDirectoryProvider().getCacheDirectory(),
Expand Down
40 changes: 20 additions & 20 deletions src/main/kotlin/io/getunleash/UnleashConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ package io.getunleash

import io.getunleash.polling.AutoPollingMode
import io.getunleash.polling.PollingMode
import java.time.Duration
import java.util.UUID


data class ReportMetrics(val metricsInterval: Duration = Duration.ofSeconds(60))
data class ReportMetrics(val metricsInterval: Long = 60000)
/**
* Represents configuration for Unleash.
* @property url HTTP(s) URL to the Unleash Proxy (Required).
Expand All @@ -15,8 +14,8 @@ data class ReportMetrics(val metricsInterval: Duration = Duration.ofSeconds(60))
* @property environment which environment is the application running in. Will be used as default argument for the [io.getunleash.UnleashContext]. (Optional - Defaults to 'default')
* @property instanceId instance id of your client
* @property pollingMode How to poll for features. Defaults to [io.getunleash.polling.AutoPollingMode] with poll interval set to 60 seconds.
* @property httpClientReadTimeout How long to wait for HTTP reads. (Optional - Defaults to 5 seconds)
* @property httpClientConnectionTimeout How long to wait for HTTP connection. (Optional - Defaults to 2 seconds)
* @property httpClientReadTimeout How long to wait for HTTP reads in milliseconds. (Optional - Defaults to 5000)
* @property httpClientConnectionTimeout How long to wait for HTTP connection in milliseconds. (Optional - Defaults to 2000)
* @property httpClientCacheSize Disk space (in bytes) set aside for http cache. (Optional - Defaults to 10MB)
* @property reportMetrics Should the client collate and report metrics? The [io.getunleah.ReportMetrics] dataclass includes a metricsInterval field which defaults to 60 seconds. (Optional - defaults to null)
*/
Expand All @@ -26,9 +25,9 @@ data class UnleashConfig(
val appName: String? = null,
val environment: String? = null,
val instanceId: String? = UUID.randomUUID().toString(),
val pollingMode: PollingMode = AutoPollingMode(Duration.ofSeconds(60)),
val httpClientConnectionTimeout: Duration = Duration.ofSeconds(2),
val httpClientReadTimeout: Duration = Duration.ofSeconds(5),
val pollingMode: PollingMode = AutoPollingMode(60000),
val httpClientConnectionTimeout: Long = 2000,
val httpClientReadTimeout: Long = 5000,
val httpClientCacheSize: Long = 1024 * 1024 * 10,
val reportMetrics: ReportMetrics? = null
) {
Expand Down Expand Up @@ -66,11 +65,11 @@ data class UnleashConfig(
var appName: String? = null,
var environment: String? = null,
var pollingMode: PollingMode? = null,
var httpClientConnectionTimeout: Duration? = null,
var httpClientReadTimeout: Duration? = null,
var httpClientConnectionTimeout: Long? = null,
var httpClientReadTimeout: Long? = null,
var httpClientCacheSize: Long? = null,
var enableMetrics: Boolean = false,
var metricsInterval: Duration? = null,
var metricsInterval: Long? = null,
var instanceId: String? = null,

) {
Expand All @@ -79,27 +78,28 @@ data class UnleashConfig(
fun appName(appName: String) = apply { this.appName = appName }
fun environment(environment: String) = apply { this.environment = environment }
fun pollingMode(pollingMode: PollingMode) = apply { this.pollingMode = pollingMode }
fun httpClientConnectionTimeout(timeout: Duration) = apply { this.httpClientConnectionTimeout = timeout }
fun httpClientConnectionTimeoutInSeconds(seconds: Long) = apply { this.httpClientConnectionTimeout = Duration.ofSeconds(seconds) }
fun httpClientReadTimeout(timeout: Duration) = apply { this.httpClientReadTimeout = timeout }
fun httpClientReadTimeoutInSeconds(seconds: Long) = apply { this.httpClientReadTimeout = Duration.ofSeconds(seconds) }
fun httpClientConnectionTimeout(timeoutInMs: Long) = apply { this.httpClientConnectionTimeout = timeoutInMs }
fun httpClientConnectionTimeoutInSeconds(seconds: Long) = apply { this.httpClientConnectionTimeout = seconds * 1000 }
fun httpClientReadTimeout(timeoutInMs: Long) = apply { this.httpClientReadTimeout = timeoutInMs }
fun httpClientReadTimeoutInSeconds(seconds: Long) = apply { this.httpClientReadTimeout = seconds * 1000 }
fun httpClientCacheSize(cacheSize: Long) = apply { this.httpClientCacheSize = cacheSize }
fun enableMetrics() = apply { this.enableMetrics = true }
fun disableMetrics() = apply { this.enableMetrics = false }
fun metricsInterval(duration: Duration) = apply { this.metricsInterval = duration }
fun metricsInterval(intervalInMs: Long) = apply { this.metricsInterval = intervalInMs }
fun metricsIntervalInSeconds(seconds: Long) = apply { this.metricsInterval = seconds * 1000 }
fun instanceId(id: String) = apply { this.instanceId = id }
fun build(): UnleashConfig = UnleashConfig(
proxyUrl = proxyUrl ?: throw IllegalStateException("You have to set proxy url in your UnleashConfig"),
clientSecret = clientSecret
?: throw IllegalStateException("You have to set client secret in your UnleashConfig"),
appName = appName,
environment = environment,
pollingMode = pollingMode ?: AutoPollingMode(Duration.ofSeconds(60)),
httpClientConnectionTimeout = httpClientConnectionTimeout ?: Duration.ofSeconds(2),
httpClientReadTimeout = httpClientReadTimeout ?: Duration.ofSeconds(5),
httpClientCacheSize = httpClientCacheSize ?: 1024 * 1024 * 10,
pollingMode = pollingMode ?: AutoPollingMode(60000),
httpClientConnectionTimeout = httpClientConnectionTimeout ?: 2000,
httpClientReadTimeout = httpClientReadTimeout ?: 5000,
httpClientCacheSize = httpClientCacheSize ?: (1024 * 1024 * 10),
reportMetrics = if (enableMetrics) {
ReportMetrics(metricsInterval ?: Duration.ofSeconds(60))
ReportMetrics(metricsInterval ?: 60000)
} else {
null
},
Expand Down
8 changes: 7 additions & 1 deletion src/main/kotlin/io/getunleash/data/Parser.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package io.getunleash.data

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.util.StdDateFormat
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper

object Parser {
val jackson = jacksonObjectMapper().registerModule(JavaTimeModule()).disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
val jackson: ObjectMapper =
jacksonObjectMapper().registerModule(JavaTimeModule()).disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.setDateFormat(
StdDateFormat().withColonInTimeZone(true)
)
}
2 changes: 1 addition & 1 deletion src/main/kotlin/io/getunleash/errors/ServerException.kt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.getunleash.errors

class ServerException(statusCode: Int) : Exception("Unleash responsded with $statusCode") {
class ServerException(statusCode: Int) : Exception("Unleash responded with $statusCode") {
}
16 changes: 8 additions & 8 deletions src/main/kotlin/io/getunleash/metrics/MetricsReporter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.Closeable
import java.io.IOException
import java.time.Duration
import java.time.Instant
import java.util.Date
import java.util.concurrent.TimeUnit

interface MetricsReporter {
/**
Expand Down Expand Up @@ -58,20 +58,20 @@ class NonReporter : MetricsReporter {

data class EvaluationCount(var yes: Int, var no: Int, val variants: MutableMap<String, Int> = mutableMapOf())
data class Bucket(
val start: Instant,
var stop: Instant? = null,
val start: Date,
var stop: Date? = null,
val toggles: MutableMap<String, EvaluationCount> = mutableMapOf()
)

data class Report(val appName: String, val environment: String, val instanceId: String, val bucket: Bucket)

class HttpMetricsReporter(val config: UnleashConfig, val started: Instant = Instant.now()) : MetricsReporter,
class HttpMetricsReporter(val config: UnleashConfig, val started: Date = Date()) : MetricsReporter,
Closeable {
companion object {
val logger: Logger = LoggerFactory.getLogger(MetricsReporter::class.java)
}

val client = OkHttpClient.Builder().callTimeout(Duration.ofSeconds(2)).readTimeout(Duration.ofSeconds(5)).build()
val client = OkHttpClient.Builder().callTimeout(2, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build()
val metricsUrl = config.proxyUrl.toHttpUrl().newBuilder().addPathSegment("client").addPathSegment("metrics").build()
private var bucket: Bucket = Bucket(start = started)

Expand All @@ -80,7 +80,7 @@ class HttpMetricsReporter(val config: UnleashConfig, val started: Instant = Inst
appName = config.appName ?: "unknown",
instanceId = config.instanceId ?: "not-set",
environment = config.environment ?: "not-set",
bucket = bucket.copy(stop = Instant.now())
bucket = bucket.copy(stop = Date())
)
val request = Request.Builder().url(metricsUrl).post(
Parser.jackson.writeValueAsString(report).toRequestBody("application/json".toMediaType())
Expand All @@ -95,7 +95,7 @@ class HttpMetricsReporter(val config: UnleashConfig, val started: Instant = Inst
}
}
})
bucket = Bucket(start = Instant.now())
bucket = Bucket(start = Date())
}

override fun log(featureName: String, enabled: Boolean): Boolean {
Expand Down
4 changes: 1 addition & 3 deletions src/main/kotlin/io/getunleash/polling/AutoPollingMode.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package io.getunleash.polling

import java.time.Duration

class AutoPollingMode(val pollRateDuration: Duration, val togglesUpdatedListener: TogglesUpdatedListener = TogglesUpdatedListener { }, val erroredListener: TogglesErroredListener = TogglesErroredListener { }) : PollingMode {
class AutoPollingMode(val pollRateDuration: Long, val togglesUpdatedListener: TogglesUpdatedListener = TogglesUpdatedListener { }, val erroredListener: TogglesErroredListener = TogglesErroredListener { }) : PollingMode {
override fun pollingIdentifier(): String = "auto"

}
2 changes: 1 addition & 1 deletion src/main/kotlin/io/getunleash/polling/AutoPollingPolicy.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class AutoPollingPolicy(
name = "unleash_toggles_fetcher",
initialDelay = 0L,
daemon = true,
period = autoPollingConfig.pollRateDuration.toMillis()
period = autoPollingConfig.pollRateDuration
) {
updateToggles()
if (!initialized.getAndSet(true)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.getunleash
package io.getunleash.polling

import io.getunleash.polling.PollingMode
import java.io.File
Expand Down
1 change: 0 additions & 1 deletion src/main/kotlin/io/getunleash/polling/FilePollingPolicy.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.getunleash.polling

import com.fasterxml.jackson.module.kotlin.readValue
import io.getunleash.FilePollingMode
import io.getunleash.UnleashConfig
import io.getunleash.UnleashContext
import io.getunleash.cache.ToggleCache
Expand Down
Loading

0 comments on commit 4361d3d

Please sign in to comment.