Skip to content

Commit

Permalink
KTOR-7213 Allow access to the configuration options of a HttpRequestR…
Browse files Browse the repository at this point in the history
…etry client plugin (#4602)

* Drop deprecated API usage

* KTOR-7213 Allow access to the configuration options of HttpRequestRetry client plugin
  • Loading branch information
e5l authored Jan 15, 2025
1 parent 14e92ae commit 5c00a5a
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 22 deletions.
3 changes: 3 additions & 0 deletions ktor-client/ktor-client-core/api/ktor-client-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,9 @@ public final class io/ktor/client/plugins/HttpRequestRetryConfig {
public final fun exponentialDelay (DJJJZ)V
public static synthetic fun exponentialDelay$default (Lio/ktor/client/plugins/HttpRequestRetryConfig;DJJJZILjava/lang/Object;)V
public final fun getMaxRetries ()I
public final fun getModifyRequest ()Lkotlin/jvm/functions/Function2;
public final fun getRetryIf ()Lkotlin/jvm/functions/Function3;
public final fun getRetryOnExceptionIf ()Lkotlin/jvm/functions/Function3;
public final fun modifyRequest (Lkotlin/jvm/functions/Function2;)V
public final fun noRetry ()V
public final fun retryIf (ILkotlin/jvm/functions/Function3;)V
Expand Down
7 changes: 7 additions & 0 deletions ktor-client/ktor-client-core/api/ktor-client-core.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -653,9 +653,16 @@ final class io.ktor.client.plugins/HttpRedirectConfig { // io.ktor.client.plugin
final class io.ktor.client.plugins/HttpRequestRetryConfig { // io.ktor.client.plugins/HttpRequestRetryConfig|null[0]
constructor <init>() // io.ktor.client.plugins/HttpRequestRetryConfig.<init>|<init>(){}[0]

final val retryIf // io.ktor.client.plugins/HttpRequestRetryConfig.retryIf|{}retryIf[0]
final fun <get-retryIf>(): kotlin/Function3<io.ktor.client.plugins/HttpRetryShouldRetryContext, io.ktor.client.request/HttpRequest, io.ktor.client.statement/HttpResponse, kotlin/Boolean>? // io.ktor.client.plugins/HttpRequestRetryConfig.retryIf.<get-retryIf>|<get-retryIf>(){}[0]
final val retryOnExceptionIf // io.ktor.client.plugins/HttpRequestRetryConfig.retryOnExceptionIf|{}retryOnExceptionIf[0]
final fun <get-retryOnExceptionIf>(): kotlin/Function3<io.ktor.client.plugins/HttpRetryShouldRetryContext, io.ktor.client.request/HttpRequestBuilder, kotlin/Throwable, kotlin/Boolean>? // io.ktor.client.plugins/HttpRequestRetryConfig.retryOnExceptionIf.<get-retryOnExceptionIf>|<get-retryOnExceptionIf>(){}[0]

final var maxRetries // io.ktor.client.plugins/HttpRequestRetryConfig.maxRetries|{}maxRetries[0]
final fun <get-maxRetries>(): kotlin/Int // io.ktor.client.plugins/HttpRequestRetryConfig.maxRetries.<get-maxRetries>|<get-maxRetries>(){}[0]
final fun <set-maxRetries>(kotlin/Int) // io.ktor.client.plugins/HttpRequestRetryConfig.maxRetries.<set-maxRetries>|<set-maxRetries>(kotlin.Int){}[0]
final var modifyRequest // io.ktor.client.plugins/HttpRequestRetryConfig.modifyRequest|{}modifyRequest[0]
final fun <get-modifyRequest>(): kotlin/Function2<io.ktor.client.plugins/HttpRetryModifyRequestContext, io.ktor.client.request/HttpRequestBuilder, kotlin/Unit> // io.ktor.client.plugins/HttpRequestRetryConfig.modifyRequest.<get-modifyRequest>|<get-modifyRequest>(){}[0]

final fun constantDelay(kotlin/Long = ..., kotlin/Long = ..., kotlin/Boolean = ...) // io.ktor.client.plugins/HttpRequestRetryConfig.constantDelay|constantDelay(kotlin.Long;kotlin.Long;kotlin.Boolean){}[0]
final fun delay(kotlin.coroutines/SuspendFunction1<kotlin/Long, kotlin/Unit>) // io.ktor.client.plugins/HttpRequestRetryConfig.delay|delay(kotlin.coroutines.SuspendFunction1<kotlin.Long,kotlin.Unit>){}[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,26 @@ public class HttpRequestRetryConfig {
internal lateinit var shouldRetry: HttpRetryShouldRetryContext.(HttpRequest, HttpResponse) -> Boolean
internal lateinit var shouldRetryOnException: HttpRetryShouldRetryContext.(HttpRequestBuilder, Throwable) -> Boolean
internal lateinit var delayMillis: HttpRetryDelayContext.(Int) -> Long
internal var modifyRequest: HttpRetryModifyRequestContext.(HttpRequestBuilder) -> Unit = {}
internal var delay: suspend (Long) -> Unit = { kotlinx.coroutines.delay(it) }

/**
* Function that determines whether a request should be retried based on the response.
*/
public val retryIf: (HttpRetryShouldRetryContext.(HttpRequest, HttpResponse) -> Boolean)?
get() = if (::shouldRetry.isInitialized) shouldRetry else null

/**
* Function that determines whether a request should be retried based on the exception.
*/
public val retryOnExceptionIf: (HttpRetryShouldRetryContext.(HttpRequestBuilder, Throwable) -> Boolean)?
get() = if (::shouldRetryOnException.isInitialized) shouldRetryOnException else null

/**
* Indicated how the request should be modified before retrying.
*/
public var modifyRequest: HttpRetryModifyRequestContext.(HttpRequestBuilder) -> Unit = {}
private set

/**
* The maximum amount of retries to perform for a request.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
package io.ktor.client.plugins.auth

import io.ktor.client.plugins.auth.providers.*
import io.ktor.test.dispatcher.*
import kotlinx.coroutines.*
import kotlinx.coroutines.test.runTest
import kotlin.test.*

class AuthTokenHolderTest {

@Test
@OptIn(DelicateCoroutinesApi::class)
fun testSetTokenCalledOnce() = testSuspend {
fun testSetTokenCalledOnce() = runTest {
val holder = AuthTokenHolder<BearerTokens> { TODO() }

val monitor = Job()
Expand Down Expand Up @@ -44,7 +44,7 @@ class AuthTokenHolderTest {

@Test
@OptIn(DelicateCoroutinesApi::class)
fun testLoadTokenWaitsUntilTokenIsLoaded() = testSuspend {
fun testLoadTokenWaitsUntilTokenIsLoaded() = runTest {
val monitor = Job()
val holder = AuthTokenHolder {
monitor.join()
Expand All @@ -66,7 +66,7 @@ class AuthTokenHolderTest {

@Test
@OptIn(DelicateCoroutinesApi::class)
fun testClearCalledWhileLoadingTokens() = testSuspend {
fun testClearCalledWhileLoadingTokens() = runTest {
val monitor = Job()

var clearTokenCalled = false
Expand Down Expand Up @@ -97,7 +97,7 @@ class AuthTokenHolderTest {

@Test
@OptIn(DelicateCoroutinesApi::class)
fun testClearCalledWhileSettingTokens() = testSuspend {
fun testClearCalledWhileSettingTokens() = runTest {
val monitor = Job()

var clearTokenCalled = false
Expand Down Expand Up @@ -128,7 +128,7 @@ class AuthTokenHolderTest {
}

@Test
fun testExceptionInLoadTokens() = testSuspend {
fun testExceptionInLoadTokens() = runTest {
var firstCall = true
val holder = AuthTokenHolder {
if (firstCall) {
Expand All @@ -142,7 +142,7 @@ class AuthTokenHolderTest {
}

@Test
fun testExceptionInSetTokens() = testSuspend {
fun testExceptionInSetTokens() = runTest {
val holder = AuthTokenHolder<String> {
fail("loadTokens argument function shouldn't be invoked")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
/*
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

@file:Suppress("DEPRECATION")

package io.ktor.client.plugins.auth

import io.ktor.client.plugins.auth.providers.*
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.http.auth.*
import io.ktor.test.dispatcher.*
import io.ktor.util.*
import kotlinx.coroutines.test.runTest
import kotlin.test.*

class DigestProviderTest {
Expand Down Expand Up @@ -66,8 +63,8 @@ class DigestProviderTest {
}

@Test
fun addRequestHeadersSetsExpectedAuthHeaderFields() = testSuspend {
if (!PlatformUtils.IS_JVM) return@testSuspend
fun addRequestHeadersSetsExpectedAuthHeaderFields() = runTest {
if (!PlatformUtils.IS_JVM) return@runTest

runIsApplicable(authAllFields)
val authHeader = addRequestHeaders(authAllFields)
Expand All @@ -78,8 +75,8 @@ class DigestProviderTest {
}

@Test
fun addRequestHeadersMissingRealm() = testSuspend {
if (!PlatformUtils.IS_JVM) return@testSuspend
fun addRequestHeadersMissingRealm() = runTest {
if (!PlatformUtils.IS_JVM) return@runTest

@Suppress("DEPRECATION_ERROR")
val providerWithoutRealm = DigestAuthProvider("username", "pass", null)
Expand All @@ -93,8 +90,8 @@ class DigestProviderTest {
}

@Test
fun addRequestHeadersChangedRealm() = testSuspend {
if (!PlatformUtils.IS_JVM) return@testSuspend
fun addRequestHeadersChangedRealm() = runTest {
if (!PlatformUtils.IS_JVM) return@runTest

@Suppress("DEPRECATION_ERROR")
val providerWithoutRealm = DigestAuthProvider("username", "pass", "wrong!")
Expand All @@ -104,8 +101,8 @@ class DigestProviderTest {
}

@Test
fun addRequestHeadersOmitsQopAndOpaqueWhenMissing() = testSuspend {
if (!PlatformUtils.IS_JVM) return@testSuspend
fun addRequestHeadersOmitsQopAndOpaqueWhenMissing() = runTest {
if (!PlatformUtils.IS_JVM) return@runTest

runIsApplicable(authMissingQopAndOpaque)
val authHeader = addRequestHeaders(authMissingQopAndOpaque)
Expand All @@ -116,8 +113,8 @@ class DigestProviderTest {
}

@Test
fun testTokenWhenMissingRealmAndQop() = testSuspend {
if (!PlatformUtils.IS_JVM) return@testSuspend
fun testTokenWhenMissingRealmAndQop() = runTest {
if (!PlatformUtils.IS_JVM) return@runTest

@Suppress("DEPRECATION_ERROR")
val providerWithoutRealm = DigestAuthProvider("username", "pass", null)
Expand Down

0 comments on commit 5c00a5a

Please sign in to comment.