blob: 6d43cc16b5bffd0c3378fae18f05a257a26fc48d [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
19import kotlinx.coroutines.experimental.channels.Channel
20import kotlinx.coroutines.experimental.selects.select
21import kotlinx.coroutines.experimental.sync.Mutex
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030022import kotlin.test.*
Roman Elizarova74eb5f2017-05-11 20:15:18 +030023
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030024class AtomicCancellationTest : TestBase() {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030025 @Test
26 fun testLockAtomicCancel() = runBlocking {
27 expect(1)
28 val mutex = Mutex(true) // locked mutex
Roman Elizarov43e3af72017-07-21 16:01:31 +030029 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030030 expect(2)
31 mutex.lock() // suspends
32 expect(4) // should execute despite cancellation
33 }
34 expect(3)
35 mutex.unlock() // unlock mutex first
36 job.cancel() // cancel the job next
37 yield() // now yield
38 finish(5)
39 }
40
41 @Test
42 fun testSelectLockAtomicCancel() = runBlocking {
43 expect(1)
44 val mutex = Mutex(true) // locked mutex
Roman Elizarov43e3af72017-07-21 16:01:31 +030045 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030046 expect(2)
47 val result = select<String> { // suspends
48 mutex.onLock {
49 expect(4)
50 "OK"
51 }
52 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030053 assertEquals("OK", result)
Roman Elizarova74eb5f2017-05-11 20:15:18 +030054 expect(5) // should execute despite cancellation
55 }
56 expect(3)
57 mutex.unlock() // unlock mutex first
58 job.cancel() // cancel the job next
59 yield() // now yield
60 finish(6)
61 }
62
63 @Test
64 fun testSendAtomicCancel() = runBlocking {
65 expect(1)
66 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +030067 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030068 expect(2)
69 channel.send(42) // suspends
70 expect(4) // should execute despite cancellation
71 }
72 expect(3)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030073 assertEquals(42, channel.receive()) // will schedule sender for further execution
Roman Elizarova74eb5f2017-05-11 20:15:18 +030074 job.cancel() // cancel the job next
75 yield() // now yield
76 finish(5)
77 }
78
79 @Test
80 fun testSelectSendAtomicCancel() = runBlocking {
81 expect(1)
82 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +030083 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030084 expect(2)
85 val result = select<String> { // suspends
86 channel.onSend(42) {
87 expect(4)
88 "OK"
89 }
90 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030091 assertEquals("OK", result)
Roman Elizarova74eb5f2017-05-11 20:15:18 +030092 expect(5) // should execute despite cancellation
93 }
94 expect(3)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030095 assertEquals(42, channel.receive()) // will schedule sender for further execution
Roman Elizarova74eb5f2017-05-11 20:15:18 +030096 job.cancel() // cancel the job next
97 yield() // now yield
98 finish(6)
99 }
100
101 @Test
102 fun testReceiveAtomicCancel() = runBlocking {
103 expect(1)
104 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +0300105 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300106 expect(2)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300107 assertEquals(42, channel.receive()) // suspends
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300108 expect(4) // should execute despite cancellation
109 }
110 expect(3)
111 channel.send(42) // will schedule receiver for further execution
112 job.cancel() // cancel the job next
113 yield() // now yield
114 finish(5)
115 }
116
117 @Test
118 fun testSelectReceiveAtomicCancel() = runBlocking {
119 expect(1)
120 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +0300121 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300122 expect(2)
123 val result = select<String> { // suspends
124 channel.onReceive {
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300125 assertEquals(42, it)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300126 expect(4)
127 "OK"
128 }
129 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300130 assertEquals("OK", result)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300131 expect(5) // should execute despite cancellation
132 }
133 expect(3)
134 channel.send(42) // will schedule receiver for further execution
135 job.cancel() // cancel the job next
136 yield() // now yield
137 finish(6)
138 }
139
140 @Test
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300141 fun testSelectDeferredAwaitCancellable() = runBlocking {
142 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300143 val deferred = async(coroutineContext) { // deferred, not yet complete
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300144 expect(4)
145 "OK"
146 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300147 assertEquals(false, deferred.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300148 var job: Job? = null
Roman Elizarov43e3af72017-07-21 16:01:31 +0300149 launch(coroutineContext) { // will cancel job as soon as deferred completes
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300150 expect(5)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300151 assertEquals(true, deferred.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300152 job!!.cancel()
153 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300154 job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300155 expect(2)
156 try {
157 select<Unit> { // suspends
158 deferred.onAwait { expectUnreached() }
159 }
160 expectUnreached() // will not execute -- cancelled while dispatched
161 } finally {
162 finish(7) // but will execute finally blocks
163 }
164 }
165 expect(3) // continues to execute when job suspends
166 yield() // to deferred & canceller
167 expect(6)
168 }
169
170 @Test
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300171 fun testSelectJobJoinCancellable() = runBlocking {
172 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300173 val jobToJoin = launch(coroutineContext) { // not yet complete
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300174 expect(4)
175 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300176 assertEquals(false, jobToJoin.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300177 var job: Job? = null
Roman Elizarov43e3af72017-07-21 16:01:31 +0300178 launch(coroutineContext) { // will cancel job as soon as jobToJoin completes
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300179 expect(5)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300180 assertEquals(true, jobToJoin.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300181 job!!.cancel()
182 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300183 job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300184 expect(2)
185 try {
186 select<Unit> { // suspends
187 jobToJoin.onJoin { expectUnreached() }
188 }
189 expectUnreached() // will not execute -- cancelled while dispatched
190 } finally {
191 finish(7) // but will execute finally blocks
192 }
193 }
194 expect(3) // continues to execute when job suspends
195 yield() // to jobToJoin & canceller
196 expect(6)
197 }
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300198}