Skip to content

Commit

Permalink
Merge pull request #29 from Bram--/dev
Browse files Browse the repository at this point in the history
Adds requestTimeoutMillis to the configuration so timeout can be configured
  • Loading branch information
Bram-- committed Apr 23, 2024
2 parents 62a8dc9 + 6195b98 commit e7507d3
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 27 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ using it is as simple as adding a single line to Gradle.
##### Gradle

```kotlin
implementation("org.audux.bgg:bggclient:0.8.0")
implementation("org.audux.bgg:bggclient:0.8.1")
```

##### Maven
Expand All @@ -35,7 +35,7 @@ implementation("org.audux.bgg:bggclient:0.8.0")
<dependency>
<groupId>org.audux.bgg</groupId>
<artifactId>bggclient</artifactId>
<version>0.8.0</version>
<version>0.8.1</version>
</dependency>
```

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ publishing {
create<MavenPublication>("mavenJava") {
groupId = "org.audux.bgg"
artifactId = "bggclient"
version = "0.8.0"
version = "0.8.1"

pom {
name = "Unofficial JVM BGG client"
Expand Down
2 changes: 1 addition & 1 deletion examples/android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
implementation("io.coil-kt:coil-compose:2.5.0")
implementation("org.audux.bgg:bggclient:0.8.0")
implementation("org.audux.bgg:bggclient:0.8.1")

testImplementation("junit:junit:4.13.2")

Expand Down
2 changes: 1 addition & 1 deletion examples/java/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repositories {
}

dependencies {
implementation("org.audux.bgg:bggclient:0.8.0")
implementation("org.audux.bgg:bggclient:0.8.1")

testImplementation(platform("org.junit:junit-bom:5.9.1"))
testImplementation("org.junit.jupiter:junit-jupiter")
Expand Down
2 changes: 1 addition & 1 deletion examples/paginate/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ application {
}

dependencies {
implementation("org.audux.bgg:bggclient:0.8.0")
implementation("org.audux.bgg:bggclient:0.8.1")

testImplementation("org.jetbrains.kotlin:kotlin-test")
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/org/audux/bgg/BggClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -953,13 +953,15 @@ object BggClient {
* @property retryBase see kdoc for formula
* @property retryMaxDelayMs see kdoc for formula
* @property retryRandomizationMs see kdoc for formula
* @property requestTimeoutMillis At which point requests time out/throw an time out Exception.
*/
data class BggClientConfiguration(
var maxConcurrentRequests: Int = 10,
var maxRetries: Int = 5,
var retryBase: Double = 2.0,
var retryMaxDelayMs: Long = 60_000,
var retryRandomizationMs: Long = 1_000,
var requestTimeoutMillis: Long = 15_000
)

/** Thrown whenever any exception is thrown during a request to BGG. */
Expand Down
4 changes: 4 additions & 0 deletions src/main/kotlin/org/audux/bgg/InternalBggClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.fasterxml.jackson.module.kotlin.KotlinFeature
import com.fasterxml.jackson.module.kotlin.KotlinModule
import io.ktor.client.HttpClient
import io.ktor.client.plugins.HttpRequestRetry
import io.ktor.client.plugins.HttpTimeout
import java.util.Locale
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
Expand All @@ -33,6 +34,9 @@ internal class InternalBggClient {
install(ClientRateLimitPlugin) {
requestLimit = BggClient.configuration.maxConcurrentRequests
}
install(HttpTimeout) {
requestTimeoutMillis = BggClient.configuration.requestTimeoutMillis
}
install(HttpRequestRetry) {
exponentialDelay(
base = BggClient.configuration.retryBase,
Expand Down
39 changes: 39 additions & 0 deletions src/test/kotlin/org/audux/bgg/BggClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import io.ktor.client.engine.mock.MockEngine
import io.ktor.client.engine.mock.MockEngineConfig
import io.ktor.client.engine.mock.respond
import io.ktor.client.engine.mock.respondOk
import io.ktor.client.plugins.HttpRequestTimeoutException
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode
Expand All @@ -14,11 +15,27 @@ import java.util.concurrent.CountDownLatch
import kotlinx.coroutines.runBlocking
import org.audux.bgg.response.Response
import org.audux.bgg.util.TestUtils
import org.audux.bgg.util.TestUtils.delayedResponse
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource

class BggClientTest {
private lateinit var defaultConfiguration: BggClientConfiguration

@BeforeEach
fun setUp() {
defaultConfiguration = BggClient.configuration
}

@AfterEach
fun tearDown() {
BggClient.configuration = defaultConfiguration
}

@ParameterizedTest
@ValueSource(ints = [202, 429, 500, 599])
fun `Retries on Http status codes`(statusCode: Int) {
Expand Down Expand Up @@ -157,6 +174,28 @@ class BggClientTest {
assertThat(response).isEqualTo("Response")
}

@Test
fun `Throws Exception when request timeout has been met`() {
runBlocking {
BggClient.configure { this.requestTimeoutMillis = 10 }
BggClient.engine = {
MockEngine(MockEngineConfig().apply { addHandler(delayedResponse(1_000)) })
}

InternalBggClient().apply {
assertThrows<HttpRequestTimeoutException> {
request {
Response(
data = client().get("https://www.google.com/test").bodyAsText(),
error = null
)
}
.call()
}
}
}
}

private fun testRetryConfiguration(config: BggClientConfiguration) =
config.apply {
retryBase = 1.0
Expand Down
33 changes: 12 additions & 21 deletions src/test/kotlin/org/audux/bgg/plugin/ClientRateLimitPluginTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,19 @@ import com.google.common.truth.Truth.assertThat
import io.ktor.client.HttpClient
import io.ktor.client.engine.mock.MockEngine
import io.ktor.client.engine.mock.MockEngineConfig
import io.ktor.client.engine.mock.MockRequestHandleScope
import io.ktor.client.engine.mock.respondOk
import io.ktor.client.plugins.api.createClientPlugin
import io.ktor.client.request.HttpRequestData
import io.ktor.client.request.HttpResponseData
import io.ktor.client.request.get
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.audux.bgg.util.TestUtils.delayedResponse
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

/** Tests for [ClientRateLimitPlugin] and [ConcurrentRequestLimiter]. */
class ClientRateLimitPluginTest {
private lateinit var requestLimiter: ConcurrentRequestLimiter
private var delayedResponse:
suspend MockRequestHandleScope.(HttpRequestData) -> HttpResponseData =
{
delay(20)
respondOk("OK")
}

@BeforeEach
fun beforeEach() {
Expand All @@ -49,9 +40,9 @@ class ClientRateLimitPluginTest {
fun `Does not enqueue incoming requests that do not exceed the concurrent requests limit`() {
val client =
createClient(requestLimit = 3) {
addHandler(delayedResponse)
addHandler(delayedResponse)
addHandler(delayedResponse)
addHandler(delayedResponse())
addHandler(delayedResponse())
addHandler(delayedResponse())
}

val jobs = runBlocking {
Expand Down Expand Up @@ -79,9 +70,9 @@ class ClientRateLimitPluginTest {
fun `Enqueues incoming requests that would exceed the concurrent requests limit`() {
val client =
createClient(requestLimit = 2) {
addHandler(delayedResponse)
addHandler(delayedResponse)
addHandler(delayedResponse)
addHandler(delayedResponse())
addHandler(delayedResponse())
addHandler(delayedResponse())
}

val jobs = runBlocking {
Expand Down Expand Up @@ -109,11 +100,11 @@ class ClientRateLimitPluginTest {
fun `Enqueues incoming requests that would exceed the concurrent requests limit even for different clients`() {
val clients =
listOf(
createClient(requestLimit = 2) { addHandler(delayedResponse) },
createClient(requestLimit = 2) { addHandler(delayedResponse) },
createClient(requestLimit = 2) { addHandler(delayedResponse) },
createClient(requestLimit = 2) { addHandler(delayedResponse) },
createClient(requestLimit = 2) { addHandler(delayedResponse) },
createClient(requestLimit = 2) { addHandler(delayedResponse()) },
createClient(requestLimit = 2) { addHandler(delayedResponse()) },
createClient(requestLimit = 2) { addHandler(delayedResponse()) },
createClient(requestLimit = 2) { addHandler(delayedResponse()) },
createClient(requestLimit = 2) { addHandler(delayedResponse()) },
)

val jobs = runBlocking {
Expand Down
11 changes: 11 additions & 0 deletions src/test/kotlin/org/audux/bgg/util/TestUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ import co.touchlab.kermit.Logger
import co.touchlab.kermit.Severity
import io.ktor.client.engine.mock.MockEngine
import io.ktor.client.engine.mock.MockEngineConfig
import io.ktor.client.engine.mock.MockRequestHandleScope
import io.ktor.client.engine.mock.respondOk
import io.ktor.client.request.HttpRequestData
import io.ktor.client.request.HttpResponseData
import java.io.InputStream
import kotlinx.coroutines.delay
import org.audux.bgg.BggClient
import org.audux.bgg.InternalBggClient

Expand Down Expand Up @@ -71,6 +75,13 @@ object TestUtils {
fun logsWritten() = logWrites.toList()
}

fun delayedResponse(
delayMs: Long = 20
): suspend MockRequestHandleScope.(HttpRequestData) -> HttpResponseData = {
delay(delayMs)
respondOk("OK")
}

/** All data that is logged in a single [Logger.log] call. */
data class LogWrite(
val severity: Severity,
Expand Down

0 comments on commit e7507d3

Please sign in to comment.