blob: 9d7a20a8391d88e7866fddf7fe25045ce1b16ba9 [file] [log] [blame]
Roman Elizarova74eb5f2017-05-11 20:15:18 +03001/*
2 * Copyright 2016-2017 JetBrains s.r.o.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package kotlinx.coroutines.experimental
18
Roman Elizarov9fe5f462018-02-21 19:05:52 +030019import kotlinx.coroutines.experimental.channels.*
20import kotlinx.coroutines.experimental.selects.*
21import kotlinx.coroutines.experimental.sync.*
22import kotlin.coroutines.experimental.*
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030023import kotlin.test.*
Roman Elizarova74eb5f2017-05-11 20:15:18 +030024
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030025class AtomicCancellationTest : TestBase() {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030026 @Test
27 fun testLockAtomicCancel() = runBlocking {
28 expect(1)
29 val mutex = Mutex(true) // locked mutex
Roman Elizarov43e3af72017-07-21 16:01:31 +030030 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030031 expect(2)
32 mutex.lock() // suspends
33 expect(4) // should execute despite cancellation
34 }
35 expect(3)
36 mutex.unlock() // unlock mutex first
37 job.cancel() // cancel the job next
38 yield() // now yield
39 finish(5)
40 }
41
42 @Test
43 fun testSelectLockAtomicCancel() = runBlocking {
44 expect(1)
45 val mutex = Mutex(true) // locked mutex
Roman Elizarov43e3af72017-07-21 16:01:31 +030046 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030047 expect(2)
48 val result = select<String> { // suspends
49 mutex.onLock {
50 expect(4)
51 "OK"
52 }
53 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030054 assertEquals("OK", result)
Roman Elizarova74eb5f2017-05-11 20:15:18 +030055 expect(5) // should execute despite cancellation
56 }
57 expect(3)
58 mutex.unlock() // unlock mutex first
59 job.cancel() // cancel the job next
60 yield() // now yield
61 finish(6)
62 }
63
64 @Test
65 fun testSendAtomicCancel() = runBlocking {
66 expect(1)
67 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +030068 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030069 expect(2)
70 channel.send(42) // suspends
71 expect(4) // should execute despite cancellation
72 }
73 expect(3)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030074 assertEquals(42, channel.receive()) // will schedule sender for further execution
Roman Elizarova74eb5f2017-05-11 20:15:18 +030075 job.cancel() // cancel the job next
76 yield() // now yield
77 finish(5)
78 }
79
80 @Test
81 fun testSelectSendAtomicCancel() = runBlocking {
82 expect(1)
83 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +030084 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030085 expect(2)
86 val result = select<String> { // suspends
87 channel.onSend(42) {
88 expect(4)
89 "OK"
90 }
91 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030092 assertEquals("OK", result)
Roman Elizarova74eb5f2017-05-11 20:15:18 +030093 expect(5) // should execute despite cancellation
94 }
95 expect(3)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030096 assertEquals(42, channel.receive()) // will schedule sender for further execution
Roman Elizarova74eb5f2017-05-11 20:15:18 +030097 job.cancel() // cancel the job next
98 yield() // now yield
99 finish(6)
100 }
101
102 @Test
103 fun testReceiveAtomicCancel() = runBlocking {
104 expect(1)
105 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +0300106 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300107 expect(2)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300108 assertEquals(42, channel.receive()) // suspends
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300109 expect(4) // should execute despite cancellation
110 }
111 expect(3)
112 channel.send(42) // will schedule receiver for further execution
113 job.cancel() // cancel the job next
114 yield() // now yield
115 finish(5)
116 }
117
118 @Test
119 fun testSelectReceiveAtomicCancel() = runBlocking {
120 expect(1)
121 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +0300122 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300123 expect(2)
124 val result = select<String> { // suspends
125 channel.onReceive {
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300126 assertEquals(42, it)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300127 expect(4)
128 "OK"
129 }
130 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300131 assertEquals("OK", result)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300132 expect(5) // should execute despite cancellation
133 }
134 expect(3)
135 channel.send(42) // will schedule receiver for further execution
136 job.cancel() // cancel the job next
137 yield() // now yield
138 finish(6)
139 }
140
141 @Test
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300142 fun testSelectDeferredAwaitCancellable() = runBlocking {
143 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300144 val deferred = async(coroutineContext) { // deferred, not yet complete
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300145 expect(4)
146 "OK"
147 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300148 assertEquals(false, deferred.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300149 var job: Job? = null
Roman Elizarov43e3af72017-07-21 16:01:31 +0300150 launch(coroutineContext) { // will cancel job as soon as deferred completes
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300151 expect(5)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300152 assertEquals(true, deferred.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300153 job!!.cancel()
154 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300155 job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300156 expect(2)
157 try {
158 select<Unit> { // suspends
159 deferred.onAwait { expectUnreached() }
160 }
161 expectUnreached() // will not execute -- cancelled while dispatched
162 } finally {
163 finish(7) // but will execute finally blocks
164 }
165 }
166 expect(3) // continues to execute when job suspends
167 yield() // to deferred & canceller
168 expect(6)
169 }
170
171 @Test
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300172 fun testSelectJobJoinCancellable() = runBlocking {
173 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300174 val jobToJoin = launch(coroutineContext) { // not yet complete
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300175 expect(4)
176 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300177 assertEquals(false, jobToJoin.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300178 var job: Job? = null
Roman Elizarov43e3af72017-07-21 16:01:31 +0300179 launch(coroutineContext) { // will cancel job as soon as jobToJoin completes
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300180 expect(5)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300181 assertEquals(true, jobToJoin.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300182 job!!.cancel()
183 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300184 job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300185 expect(2)
186 try {
187 select<Unit> { // suspends
188 jobToJoin.onJoin { expectUnreached() }
189 }
190 expectUnreached() // will not execute -- cancelled while dispatched
191 } finally {
192 finish(7) // but will execute finally blocks
193 }
194 }
195 expect(3) // continues to execute when job suspends
196 yield() // to jobToJoin & canceller
197 expect(6)
198 }
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300199}