Skip to content
This repository was archived by the owner on Jun 6, 2019. It is now read-only.

Commit f36a310

Browse files
committed
Add cancelation test.
1 parent 43b5c59 commit f36a310

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
@file:Suppress("UNCHECKED_CAST")
2+
3+
package com.jakewharton.retrofit2.adapter.kotlin.coroutines.experimental
4+
5+
import com.google.common.reflect.TypeToken
6+
import kotlinx.coroutines.experimental.Deferred
7+
import org.junit.Assert.assertFalse
8+
import org.junit.Assert.assertTrue
9+
import org.junit.Test
10+
import retrofit2.CallAdapter
11+
import retrofit2.Retrofit
12+
import java.io.IOException
13+
import java.lang.reflect.Type
14+
15+
class CancelTest {
16+
private val factory = CoroutineCallAdapterFactory()
17+
private val retrofit = Retrofit.Builder()
18+
.baseUrl("http://example.com")
19+
.callFactory { TODO() }
20+
.build()
21+
22+
@Test fun noCancelOnResponse() {
23+
val deferredString = typeOf<Deferred<String>>()
24+
val adapter = factory.get(deferredString, emptyArray(), retrofit)!! as CallAdapter<String, Deferred<String>>
25+
val call = CompletableCall<String>()
26+
val deferred = adapter.adapt(call)
27+
call.complete("hey")
28+
assertFalse(call.isCanceled)
29+
assertTrue(deferred.isCompleted)
30+
}
31+
32+
@Test fun noCancelOnError() {
33+
val deferredString = typeOf<Deferred<String>>()
34+
val adapter = factory.get(deferredString, emptyArray(), retrofit)!! as CallAdapter<String, Deferred<String>>
35+
val call = CompletableCall<String>()
36+
val deferred = adapter.adapt(call)
37+
call.completeWithException(IOException())
38+
assertFalse(call.isCanceled)
39+
assertTrue(deferred.isCompletedExceptionally)
40+
}
41+
42+
@Test fun cancelOnCancel() {
43+
val deferredString = typeOf<Deferred<String>>()
44+
val adapter = factory.get(deferredString, emptyArray(), retrofit)!! as CallAdapter<String, Deferred<String>>
45+
val call = CompletableCall<String>()
46+
val deferred = adapter.adapt(call)
47+
assertFalse(call.isCanceled)
48+
deferred.cancel()
49+
assertTrue(call.isCanceled)
50+
}
51+
52+
private inline fun <reified T> typeOf(): Type = object : TypeToken<T>() {}.type
53+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.jakewharton.retrofit2.adapter.kotlin.coroutines.experimental
2+
3+
import okhttp3.Request
4+
import retrofit2.Call
5+
import retrofit2.Callback
6+
import retrofit2.Response
7+
import java.io.InterruptedIOException
8+
import java.util.concurrent.CountDownLatch
9+
10+
private val DUMMY_REQUEST = Request.Builder()
11+
.url("http://example.com")
12+
.build()
13+
14+
class CompletableCall<T>(private val request: Request = DUMMY_REQUEST) : Call<T> {
15+
private val lock = Any()
16+
private var executed = false
17+
private var canceled = false
18+
private var callback: Callback<T>? = null
19+
private val done = CountDownLatch(1)
20+
private var exception: Throwable? = null
21+
private var response: Response<T>? = null
22+
23+
fun completeWithException(t: Throwable) {
24+
synchronized(lock) {
25+
exception = t
26+
callback?.onFailure(this, t)
27+
}
28+
done.countDown()
29+
}
30+
31+
fun complete(body: T) = complete(Response.success(body))
32+
33+
fun complete(response: Response<T>) {
34+
synchronized(lock) {
35+
this.response = response
36+
callback?.onResponse(this, response)
37+
}
38+
done.countDown()
39+
}
40+
41+
override fun request() = request
42+
override fun isCanceled() = synchronized(lock) { canceled }
43+
override fun isExecuted() = synchronized(lock) { executed }
44+
override fun clone() = CompletableCall<T>(request)
45+
46+
override fun cancel() {
47+
synchronized(lock) {
48+
if (canceled) return
49+
canceled = true
50+
51+
val exception = InterruptedIOException("canceled")
52+
this.exception = exception
53+
callback?.onFailure(this, exception)
54+
}
55+
done.countDown()
56+
}
57+
58+
override fun execute(): Response<T> {
59+
synchronized(lock) {
60+
check(!executed) { "Already executed "}
61+
executed = true
62+
}
63+
done.await()
64+
synchronized(lock) {
65+
if (exception != null) {
66+
throw exception!!
67+
}
68+
return response!!
69+
}
70+
}
71+
72+
override fun enqueue(callback: Callback<T>) {
73+
synchronized(lock) {
74+
if (exception != null) {
75+
callback.onFailure(this, exception!!)
76+
} else if (response != null) {
77+
callback.onResponse(this, response!!)
78+
} else {
79+
this.callback = callback
80+
}
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)