• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016-2021 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
<lambda>null13     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
<lambda>null24     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
<lambda>null35     fun testUndispatchedLaunch() = runTest {
36         expect(1)
37         assertFailsWith<CancellationException> {
38             withContext(Job()) {
39                 cancel()
40                 launch(start = CoroutineStart.UNDISPATCHED) {
41                     expect(2)
42                     yield()
43                     expectUnreached()
44                 }
45             }
46         }
47         finish(3)
48     }
49 
50     @Test
<lambda>null51     fun testUndispatchedLaunchWithUnconfinedContext() = runTest {
52         expect(1)
53         assertFailsWith<CancellationException> {
54             withContext(Dispatchers.Unconfined + Job()) {
55                 cancel()
56                 launch(start = CoroutineStart.UNDISPATCHED) {
57                     expect(2)
58                     yield()
59                     expectUnreached()
60                 }
61             }
62         }
63         finish(3)
64     }
65 
66     @Test
<lambda>null67     fun testDeferredAwaitCancellable() = runTest {
68         expect(1)
69         val deferred = async { // deferred, not yet complete
70             expect(4)
71             "OK"
72         }
73         assertEquals(false, deferred.isCompleted)
74         var job: Job? = null
75         launch { // will cancel job as soon as deferred completes
76             expect(5)
77             assertEquals(true, deferred.isCompleted)
78             job!!.cancel()
79         }
80         job = launch(start = CoroutineStart.UNDISPATCHED) {
81             expect(2)
82             try {
83                 deferred.await() // suspends
84                 expectUnreached() // will not execute -- cancelled while dispatched
85             } finally {
86                 finish(7) // but will execute finally blocks
87             }
88         }
89         expect(3) // continues to execute when the job suspends
90         yield() // to deferred & canceller
91         expect(6)
92     }
93 
94     @Test
testJobJoinCancellablenull95     fun testJobJoinCancellable() = runTest {
96         expect(1)
97         val jobToJoin = launch { // not yet complete
98             expect(4)
99         }
100         assertEquals(false, jobToJoin.isCompleted)
101         var job: Job? = null
102         launch { // will cancel job as soon as jobToJoin completes
103             expect(5)
104             assertEquals(true, jobToJoin.isCompleted)
105             job!!.cancel()
106         }
107         job = launch(start = CoroutineStart.UNDISPATCHED) {
108             expect(2)
109             try {
110                 jobToJoin.join() // suspends
111                 expectUnreached() // will not execute -- cancelled while dispatched
112             } finally {
113                 finish(7) // but will execute finally blocks
114             }
115         }
116         expect(3) // continues to execute when the job suspends
117         yield() // to jobToJoin & canceller
118         expect(6)
119     }
120 
121     @Test
<lambda>null122     fun testLockCancellable() = runTest {
123         expect(1)
124         val mutex = Mutex(true) // locked mutex
125         val job = launch(start = CoroutineStart.UNDISPATCHED) {
126             expect(2)
127             mutex.lock() // suspends
128             expectUnreached() // should NOT execute because of cancellation
129         }
130         expect(3)
131         mutex.unlock() // unlock mutex first
132         job.cancel() // cancel the job next
133         yield() // now yield
134         finish(4)
135     }
136 
137     @Test
<lambda>null138     fun testSelectLockCancellable() = runTest {
139         expect(1)
140         val mutex = Mutex(true) // locked mutex
141         val job = launch(start = CoroutineStart.UNDISPATCHED) {
142             expect(2)
143             select<String> { // suspends
144                 mutex.onLock {
145                     expect(4)
146                     "OK"
147                 }
148             }
149             expectUnreached() // should NOT execute because of cancellation
150         }
151         expect(3)
152         mutex.unlock() // unlock mutex first
153         job.cancel() // cancel the job next
154         yield() // now yield
155         finish(4)
156     }
157 }
158