• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<lambda>null1 package kotlinx.coroutines.tasks
2 
3 import kotlinx.coroutines.testing.*
4 import com.google.android.gms.tasks.*
5 import kotlinx.coroutines.*
6 import org.junit.*
7 import org.junit.Test
8 import java.util.concurrent.locks.*
9 import kotlin.concurrent.*
10 import kotlin.test.*
11 
12 class TaskTest : TestBase() {
13     @Before
14     fun setup() {
15         ignoreLostThreads("ForkJoinPool.commonPool-worker-")
16     }
17 
18     @Test
19     fun testCompletedDeferredAsTask() = runTest {
20         expect(1)
21         val deferred = async(start = CoroutineStart.UNDISPATCHED) {
22             expect(2) // Completed immediately
23             "OK"
24         }
25         expect(3)
26         val task = deferred.asTask()
27         assertEquals("OK", task.await())
28         finish(4)
29     }
30 
31     @Test
32     fun testDeferredAsTask() = runTest {
33         expect(1)
34         val deferred = async {
35             expect(3) // Completed later
36             "OK"
37         }
38         expect(2)
39         val task = deferred.asTask()
40         assertEquals("OK", task.await())
41         finish(4)
42     }
43 
44     @Test
45     fun testCancelledAsTask() = runTest {
46         val deferred = async(Dispatchers.Default) {
47             delay(100)
48         }.apply { cancel() }
49 
50         val task = deferred.asTask()
51         try {
52             runTest { task.await() }
53         } catch (e: Exception) {
54             assertIs<CancellationException>(e)
55             assertTrue(task.isCanceled)
56         }
57     }
58 
59     @Test
60     fun testThrowingAsTask() = runTest({ e -> e is TestException }) {
61         val deferred = async<Int>(Dispatchers.Default) {
62             throw TestException("Fail")
63         }
64 
65         val task = deferred.asTask()
66         runTest(expected = { it is TestException }) {
67             task.await()
68         }
69     }
70 
71     @Test
72     fun testStateAsTask() = runTest {
73         val lock = ReentrantLock().apply { lock() }
74 
75         val deferred: Deferred<Int> = Tasks.call {
76             lock.withLock { 42 }
77         }.asDeferred()
78 
79         assertFalse(deferred.isCompleted)
80         lock.unlock()
81 
82         assertEquals(42, deferred.await())
83         assertTrue(deferred.isCompleted)
84     }
85 
86     @Test
87     fun testTaskAsDeferred() = runTest {
88         val deferred = Tasks.forResult(42).asDeferred()
89         assertEquals(42, deferred.await())
90     }
91 
92     @Test
93     fun testNullResultTaskAsDeferred() = runTest {
94         assertNull(Tasks.forResult(null).asDeferred().await())
95     }
96 
97     @Test
98     fun testCancelledTaskAsDeferred() = runTest {
99         val deferred = Tasks.forCanceled<Int>().asDeferred()
100 
101         assertTrue(deferred.isCancelled)
102         try {
103             deferred.await()
104             fail("deferred.await() should be cancelled")
105         } catch (e: Exception) {
106             assertIs<CancellationException>(e)
107         }
108     }
109 
110     @Test
111     fun testFailedTaskAsDeferred() = runTest {
112         val deferred = Tasks.forException<Int>(TestException("something went wrong")).asDeferred()
113 
114         assertTrue(deferred.isCancelled && deferred.isCompleted)
115         val completionException = deferred.getCompletionExceptionOrNull()!!
116         assertIs<TestException>(completionException)
117         assertEquals("something went wrong", completionException.message)
118 
119         try {
120             deferred.await()
121             fail("deferred.await() should throw an exception")
122         } catch (e: Exception) {
123             assertIs<TestException>(e)
124             assertEquals("something went wrong", e.message)
125         }
126     }
127 
128     @Test
129     fun testFailingTaskAsDeferred() = runTest {
130         val lock = ReentrantLock().apply { lock() }
131 
132         val deferred: Deferred<Int> = Tasks.call {
133             lock.withLock { throw TestException("something went wrong") }
134         }.asDeferred()
135 
136         assertFalse(deferred.isCompleted)
137         lock.unlock()
138 
139         try {
140             deferred.await()
141             fail("deferred.await() should throw an exception")
142         } catch (e: Exception) {
143             assertIs<TestException>(e)
144             assertEquals("something went wrong", e.message)
145             assertSame(e.cause, deferred.getCompletionExceptionOrNull()) // debug mode stack augmentation
146         }
147     }
148 
149     @Test
150     fun testCancellableTaskAsDeferred() = runTest {
151         val cancellationTokenSource = CancellationTokenSource()
152         val deferred = Tasks.forResult(42).asDeferred(cancellationTokenSource)
153         assertEquals(42, deferred.await())
154         assertTrue(cancellationTokenSource.token.isCancellationRequested)
155     }
156 
157     @Test
158     fun testNullResultCancellableTaskAsDeferred() = runTest {
159         val cancellationTokenSource = CancellationTokenSource()
160         assertNull(Tasks.forResult(null).asDeferred(cancellationTokenSource).await())
161         assertTrue(cancellationTokenSource.token.isCancellationRequested)
162     }
163 
164     @Test
165     fun testCancelledCancellableTaskAsDeferred() = runTest {
166         val cancellationTokenSource = CancellationTokenSource()
167         val deferred = Tasks.forCanceled<Int>().asDeferred(cancellationTokenSource)
168 
169         assertTrue(deferred.isCancelled)
170         try {
171             deferred.await()
172             fail("deferred.await() should be cancelled")
173         } catch (e: Exception) {
174             assertIs<CancellationException>(e)
175         }
176         assertTrue(cancellationTokenSource.token.isCancellationRequested)
177     }
178 
179     @Test
180     fun testCancellingCancellableTaskAsDeferred() = runTest {
181         val cancellationTokenSource = CancellationTokenSource()
182         val task = TaskCompletionSource<Int>(cancellationTokenSource.token).task
183         val deferred = task.asDeferred(cancellationTokenSource)
184 
185         deferred.cancel()
186         try {
187             deferred.await()
188             fail("deferred.await() should be cancelled")
189         } catch (e: Exception) {
190             assertIs<CancellationException>(e)
191         }
192         assertTrue(cancellationTokenSource.token.isCancellationRequested)
193     }
194 
195     @Test
196     fun testExternallyCancelledCancellableTaskAsDeferred() = runTest {
197         val cancellationTokenSource = CancellationTokenSource()
198         val task = TaskCompletionSource<Int>(cancellationTokenSource.token).task
199         val deferred = task.asDeferred(cancellationTokenSource)
200 
201         cancellationTokenSource.cancel()
202 
203         try {
204             deferred.await()
205             fail("deferred.await() should be cancelled")
206         } catch (e: Exception) {
207             assertIs<CancellationException>(e)
208         }
209         assertTrue(cancellationTokenSource.token.isCancellationRequested)
210     }
211 
212     @Test
213     fun testSeparatelyCancelledCancellableTaskAsDeferred() = runTest {
214         val cancellationTokenSource = CancellationTokenSource()
215         val task = TaskCompletionSource<Int>().task
216         task.asDeferred(cancellationTokenSource)
217 
218         cancellationTokenSource.cancel()
219 
220         assertTrue(cancellationTokenSource.token.isCancellationRequested)
221     }
222 
223     @Test
224     fun testFailedCancellableTaskAsDeferred() = runTest {
225         val cancellationTokenSource = CancellationTokenSource()
226         val deferred =
227             Tasks.forException<Int>(TestException("something went wrong")).asDeferred(cancellationTokenSource)
228 
229         assertTrue(deferred.isCancelled && deferred.isCompleted)
230         val completionException = deferred.getCompletionExceptionOrNull()!!
231         assertIs<TestException>(completionException)
232         assertEquals("something went wrong", completionException.message)
233 
234         try {
235             deferred.await()
236             fail("deferred.await() should throw an exception")
237         } catch (e: Exception) {
238             assertIs<TestException>(e)
239             assertEquals("something went wrong", e.message)
240         }
241         assertTrue(cancellationTokenSource.token.isCancellationRequested)
242     }
243 
244     @Test
245     fun testFailingCancellableTaskAsDeferred() = runTest {
246         val cancellationTokenSource = CancellationTokenSource()
247         val lock = ReentrantLock().apply { lock() }
248 
249         val deferred: Deferred<Int> = Tasks.call {
250             lock.withLock { throw TestException("something went wrong") }
251         }.asDeferred(cancellationTokenSource)
252 
253         assertFalse(deferred.isCompleted)
254         lock.unlock()
255 
256         try {
257             deferred.await()
258             fail("deferred.await() should throw an exception")
259         } catch (e: Exception) {
260             assertIs<TestException>(e)
261             assertEquals("something went wrong", e.message)
262             assertSame(e.cause, deferred.getCompletionExceptionOrNull()) // debug mode stack augmentation
263         }
264         assertTrue(cancellationTokenSource.token.isCancellationRequested)
265     }
266 
267     @Test
268     fun testFastPathCompletedTaskWithCancelledTokenSourceAsDeferred() = runTest {
269         val cancellationTokenSource = CancellationTokenSource()
270         val deferred = Tasks.forResult(42).asDeferred(cancellationTokenSource)
271         cancellationTokenSource.cancel()
272         assertEquals(42, deferred.await())
273     }
274 
275     @Test
276     fun testAwaitCancellableTask() = runTest {
277         val cancellationTokenSource = CancellationTokenSource()
278         val taskCompletionSource = TaskCompletionSource<Int>(cancellationTokenSource.token)
279 
280         val deferred: Deferred<Int> = async(start = CoroutineStart.UNDISPATCHED) {
281             taskCompletionSource.task.await(cancellationTokenSource)
282         }
283 
284         assertFalse(deferred.isCompleted)
285         taskCompletionSource.setResult(42)
286 
287         assertEquals(42, deferred.await())
288         assertTrue(deferred.isCompleted)
289     }
290 
291     @Test
292     fun testFailedAwaitTask() = runTest(expected = { it is TestException }) {
293         val cancellationTokenSource = CancellationTokenSource()
294         val taskCompletionSource = TaskCompletionSource<Int>(cancellationTokenSource.token)
295 
296         val deferred: Deferred<Int> = async(start = CoroutineStart.UNDISPATCHED) {
297             taskCompletionSource.task.await(cancellationTokenSource)
298         }
299 
300         assertFalse(deferred.isCompleted)
301         taskCompletionSource.setException(TestException("something went wrong"))
302 
303         deferred.await()
304     }
305 
306     @Test
307     fun testCancelledAwaitCancellableTask() = runTest {
308         val cancellationTokenSource = CancellationTokenSource()
309         val taskCompletionSource = TaskCompletionSource<Int>(cancellationTokenSource.token)
310 
311         val deferred: Deferred<Int> = async(start = CoroutineStart.UNDISPATCHED) {
312             taskCompletionSource.task.await(cancellationTokenSource)
313         }
314 
315         assertFalse(deferred.isCompleted)
316         // Cancel the deferred
317         deferred.cancel()
318 
319         try {
320             deferred.await()
321             fail("deferred.await() should be cancelled")
322         } catch (e: Exception) {
323             assertIs<CancellationException>(e)
324         }
325 
326         assertTrue(cancellationTokenSource.token.isCancellationRequested)
327     }
328 
329     @Test
330     fun testExternallyCancelledAwaitCancellableTask() = runTest {
331         val cancellationTokenSource = CancellationTokenSource()
332         val taskCompletionSource = TaskCompletionSource<Int>(cancellationTokenSource.token)
333 
334         val deferred: Deferred<Int> = async(start = CoroutineStart.UNDISPATCHED) {
335             taskCompletionSource.task.await(cancellationTokenSource)
336         }
337 
338         assertFalse(deferred.isCompleted)
339         // Cancel the cancellation token source
340         cancellationTokenSource.cancel()
341 
342         try {
343             deferred.await()
344             fail("deferred.await() should be cancelled")
345         } catch (e: Exception) {
346             assertIs<CancellationException>(e)
347         }
348 
349         assertTrue(cancellationTokenSource.token.isCancellationRequested)
350     }
351 
352     @Test
353     fun testFastPathCancellationTokenSourceCancelledAwaitCancellableTask() = runTest {
354         val cancellationTokenSource = CancellationTokenSource()
355         // Construct a task without the cancellation token source
356         val taskCompletionSource = TaskCompletionSource<Int>()
357 
358         val deferred: Deferred<Int> = async(start = CoroutineStart.LAZY) {
359             taskCompletionSource.task.await(cancellationTokenSource)
360         }
361 
362         assertFalse(deferred.isCompleted)
363         cancellationTokenSource.cancel()
364 
365         // Cancelling the token doesn't cancel the deferred
366         assertTrue(cancellationTokenSource.token.isCancellationRequested)
367         assertFalse(deferred.isCompleted)
368 
369         // Cleanup
370         deferred.cancel()
371     }
372 
373     @Test
374     fun testSlowPathCancellationTokenSourceCancelledAwaitCancellableTask() = runTest {
375         val cancellationTokenSource = CancellationTokenSource()
376         // Construct a task without the cancellation token source
377         val taskCompletionSource = TaskCompletionSource<Int>()
378 
379         val deferred: Deferred<Int> = async(start = CoroutineStart.UNDISPATCHED) {
380             taskCompletionSource.task.await(cancellationTokenSource)
381         }
382 
383         assertFalse(deferred.isCompleted)
384         cancellationTokenSource.cancel()
385 
386         // Cancelling the token doesn't cancel the deferred
387         assertTrue(cancellationTokenSource.token.isCancellationRequested)
388         assertFalse(deferred.isCompleted)
389 
390         // Cleanup
391         deferred.cancel()
392     }
393 
394     @Test
395     fun testFastPathWithCompletedTaskAndCanceledTokenSourceAwaitTask() = runTest {
396         val firstCancellationTokenSource = CancellationTokenSource()
397         val secondCancellationTokenSource = CancellationTokenSource()
398         // Construct a task with a different cancellation token source
399         val taskCompletionSource = TaskCompletionSource<Int>(firstCancellationTokenSource.token)
400 
401         val deferred: Deferred<Int> = async(start = CoroutineStart.LAZY) {
402             taskCompletionSource.task.await(secondCancellationTokenSource)
403         }
404 
405         assertFalse(deferred.isCompleted)
406         secondCancellationTokenSource.cancel()
407 
408         assertFalse(deferred.isCompleted)
409         taskCompletionSource.setResult(42)
410 
411         assertEquals(42, deferred.await())
412         assertTrue(deferred.isCompleted)
413     }
414 
415     class TestException(message: String) : Exception(message)
416 }
417