1 /*
2  * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 package kotlinx.coroutines
6 
7 import kotlinx.coroutines.selects.*
8 import kotlinx.coroutines.sync.*
9 import kotlin.test.*
10 
11 class AtomicCancellationCommonTest : TestBase() {
12     @Test
13     fun testCancellableLaunch() = runTest {
14         expect(1)
15         val job = launch {
16             expectUnreached() // will get cancelled before start
17         }
18         expect(2)
19         job.cancel()
20         finish(3)
21     }
22 
23     @Test
24     fun testAtomicLaunch() = runTest {
25         expect(1)
26         val job = launch(start = CoroutineStart.ATOMIC) {
27             finish(4) // will execute even after it was cancelled
28         }
29         expect(2)
30         job.cancel()
31         expect(3)
32     }
33 
34     @Test
35     fun testDeferredAwaitCancellable() = runTest {
36         expect(1)
37         val deferred = async { // deferred, not yet complete
38             expect(4)
39             "OK"
40         }
41         assertEquals(false, deferred.isCompleted)
42         var job: Job? = null
43         launch { // will cancel job as soon as deferred completes
44             expect(5)
45             assertEquals(true, deferred.isCompleted)
46             job!!.cancel()
47         }
48         job = launch(start = CoroutineStart.UNDISPATCHED) {
49             expect(2)
50             try {
51                 deferred.await() // suspends
52                 expectUnreached() // will not execute -- cancelled while dispatched
53             } finally {
54                 finish(7) // but will execute finally blocks
55             }
56         }
57         expect(3) // continues to execute when the job suspends
58         yield() // to deferred & canceller
59         expect(6)
60     }
61 
62     @Test
63     fun testJobJoinCancellable() = runTest {
64         expect(1)
65         val jobToJoin = launch { // not yet complete
66             expect(4)
67         }
68         assertEquals(false, jobToJoin.isCompleted)
69         var job: Job? = null
70         launch { // will cancel job as soon as jobToJoin completes
71             expect(5)
72             assertEquals(true, jobToJoin.isCompleted)
73             job!!.cancel()
74         }
75         job = launch(start = CoroutineStart.UNDISPATCHED) {
76             expect(2)
77             try {
78                 jobToJoin.join() // suspends
79                 expectUnreached() // will not execute -- cancelled while dispatched
80             } finally {
81                 finish(7) // but will execute finally blocks
82             }
83         }
84         expect(3) // continues to execute when the job suspends
85         yield() // to jobToJoin & canceller
86         expect(6)
87     }
88 
89     @Test
90     fun testLockAtomicCancel() = runTest {
91         expect(1)
92         val mutex = Mutex(true) // locked mutex
93         val job = launch(start = CoroutineStart.UNDISPATCHED) {
94             expect(2)
95             mutex.lock() // suspends
96             expect(4) // should execute despite cancellation
97         }
98         expect(3)
99         mutex.unlock() // unlock mutex first
100         job.cancel() // cancel the job next
101         yield() // now yield
102         finish(5)
103     }
104 
105     @Test
106     fun testSelectLockAtomicCancel() = runTest {
107         expect(1)
108         val mutex = Mutex(true) // locked mutex
109         val job = launch(start = CoroutineStart.UNDISPATCHED) {
110             expect(2)
111             val result = select<String> { // suspends
112                 mutex.onLock {
113                     expect(4)
114                     "OK"
115                 }
116             }
117             assertEquals("OK", result)
118             expect(5) // should execute despite cancellation
119         }
120         expect(3)
121         mutex.unlock() // unlock mutex first
122         job.cancel() // cancel the job next
123         yield() // now yield
124         finish(6)
125     }
126 }