diff --git a/retrofit/kotlin-test/src/test/java/retrofit2/KotlinSuspendTest.kt b/retrofit/kotlin-test/src/test/java/retrofit2/KotlinSuspendTest.kt index 260fd7ab98..a7bdcbbd88 100644 --- a/retrofit/kotlin-test/src/test/java/retrofit2/KotlinSuspendTest.kt +++ b/retrofit/kotlin-test/src/test/java/retrofit2/KotlinSuspendTest.kt @@ -18,6 +18,7 @@ package retrofit2 import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import okhttp3.OkHttpClient @@ -36,6 +37,9 @@ import retrofit2.http.GET import retrofit2.http.HEAD import retrofit2.http.Path import java.io.IOException +import java.io.PrintWriter +import java.io.StringWriter +import java.lang.Runnable import java.lang.reflect.ParameterizedType import java.lang.reflect.Type import kotlin.coroutines.CoroutineContext @@ -202,6 +206,58 @@ class KotlinSuspendTest { runBlocking { example.headUnit() } } + @Test fun await404() { + val retrofit = Retrofit.Builder() + .baseUrl(server.url("/")) + .addConverterFactory(ToStringConverterFactory()) + .build() + val example = retrofit.create(Service::class.java) + + server.enqueue(MockResponse().setResponseCode(404)) + + try { + runBlocking { + val deferred = async { example.body() } + + deferred.await() + } + fail() + } catch (e: HttpException) { + val writer = StringWriter() + e.printStackTrace(PrintWriter(writer)) + val trace = writer.toString() + + assertThat(trace).contains("KotlinSuspendTest") + assertThat(trace).contains("await404") + } + } + + @Test fun launch404() { + val retrofit = Retrofit.Builder() + .baseUrl(server.url("/")) + .addConverterFactory(ToStringConverterFactory()) + .build() + val example = retrofit.create(Service::class.java) + + server.enqueue(MockResponse().setResponseCode(404)) + + try { + runBlocking { + val job = launch { example.body() } + + job.join() + } + fail() + } catch (e: HttpException) { + val writer = StringWriter() + e.printStackTrace(PrintWriter(writer)) + val trace = writer.toString() + + assertThat(trace).contains("KotlinSuspendTest") + assertThat(trace).contains("launch404") + } + } + @Test fun params() { val retrofit = Retrofit.Builder() .baseUrl(server.url("/")) diff --git a/retrofit/src/main/java/retrofit2/KotlinExtensions.kt b/retrofit/src/main/java/retrofit2/KotlinExtensions.kt index d334b25136..181ff999d8 100644 --- a/retrofit/src/main/java/retrofit2/KotlinExtensions.kt +++ b/retrofit/src/main/java/retrofit2/KotlinExtensions.kt @@ -18,6 +18,7 @@ package retrofit2 +import kotlinx.coroutines.CopyableThrowable import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.suspendCancellableCoroutine import java.lang.reflect.ParameterizedType @@ -51,7 +52,7 @@ suspend fun Call.await(): T { continuation.resume(body) } } else { - continuation.resumeWithException(HttpException(response)) + continuation.resumeWithException(KotlinHttpException(response)) } } @@ -73,7 +74,7 @@ suspend fun Call.await(): T? { if (response.isSuccessful) { continuation.resume(response.body()) } else { - continuation.resumeWithException(HttpException(response)) + continuation.resumeWithException(KotlinHttpException(response)) } } @@ -124,3 +125,14 @@ internal suspend fun Exception.suspendAndThrow(): Nothing { COROUTINE_SUSPENDED } } + +private class KotlinHttpException( + private val response: Response<*> +) : HttpException(response), CopyableThrowable { + + override fun createCopy(): KotlinHttpException { + val result = KotlinHttpException(response) + result.initCause(this) + return result + } +}