blob: dff2202861693326b0956f251d4d190892d0efe1 [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
22import org.hamcrest.core.IsEqual
23import org.junit.Assert.assertThat
24import org.junit.Test
25
26class AtomicCancellationTest: TestBase() {
27 @Test
28 fun testCancellableLaunch() = runBlocking {
29 expect(1)
30 val job = launch(context) {
31 expectUnreached() // will get cancelled before start
32 }
33 expect(2)
34 job.cancel()
35 finish(3)
36 }
37
38 @Test
39 fun testAtomicLaunch() = runBlocking {
40 expect(1)
41 val job = launch(context, start = CoroutineStart.ATOMIC) {
42 finish(4) // will execute even after it was cancelled
43 }
44 expect(2)
45 job.cancel()
46 expect(3)
47 }
48
49 @Test
50 fun testLockAtomicCancel() = runBlocking {
51 expect(1)
52 val mutex = Mutex(true) // locked mutex
53 val job = launch(context, start = CoroutineStart.UNDISPATCHED) {
54 expect(2)
55 mutex.lock() // suspends
56 expect(4) // should execute despite cancellation
57 }
58 expect(3)
59 mutex.unlock() // unlock mutex first
60 job.cancel() // cancel the job next
61 yield() // now yield
62 finish(5)
63 }
64
65 @Test
66 fun testSelectLockAtomicCancel() = runBlocking {
67 expect(1)
68 val mutex = Mutex(true) // locked mutex
69 val job = launch(context, start = CoroutineStart.UNDISPATCHED) {
70 expect(2)
71 val result = select<String> { // suspends
72 mutex.onLock {
73 expect(4)
74 "OK"
75 }
76 }
77 assertThat(result, IsEqual("OK"))
78 expect(5) // should execute despite cancellation
79 }
80 expect(3)
81 mutex.unlock() // unlock mutex first
82 job.cancel() // cancel the job next
83 yield() // now yield
84 finish(6)
85 }
86
87 @Test
88 fun testSendAtomicCancel() = runBlocking {
89 expect(1)
90 val channel = Channel<Int>()
91 val job = launch(context, start = CoroutineStart.UNDISPATCHED) {
92 expect(2)
93 channel.send(42) // suspends
94 expect(4) // should execute despite cancellation
95 }
96 expect(3)
97 assertThat(channel.receive(), IsEqual(42)) // will schedule sender for further execution
98 job.cancel() // cancel the job next
99 yield() // now yield
100 finish(5)
101 }
102
103 @Test
104 fun testSelectSendAtomicCancel() = runBlocking {
105 expect(1)
106 val channel = Channel<Int>()
107 val job = launch(context, start = CoroutineStart.UNDISPATCHED) {
108 expect(2)
109 val result = select<String> { // suspends
110 channel.onSend(42) {
111 expect(4)
112 "OK"
113 }
114 }
115 assertThat(result, IsEqual("OK"))
116 expect(5) // should execute despite cancellation
117 }
118 expect(3)
119 assertThat(channel.receive(), IsEqual(42)) // will schedule sender for further execution
120 job.cancel() // cancel the job next
121 yield() // now yield
122 finish(6)
123 }
124
125 @Test
126 fun testReceiveAtomicCancel() = runBlocking {
127 expect(1)
128 val channel = Channel<Int>()
129 val job = launch(context, start = CoroutineStart.UNDISPATCHED) {
130 expect(2)
131 assertThat(channel.receive(), IsEqual(42)) // suspends
132 expect(4) // 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(5)
139 }
140
141 @Test
142 fun testSelectReceiveAtomicCancel() = runBlocking {
143 expect(1)
144 val channel = Channel<Int>()
145 val job = launch(context, start = CoroutineStart.UNDISPATCHED) {
146 expect(2)
147 val result = select<String> { // suspends
148 channel.onReceive {
149 assertThat(it, IsEqual(42))
150 expect(4)
151 "OK"
152 }
153 }
154 assertThat(result, IsEqual("OK"))
155 expect(5) // should execute despite cancellation
156 }
157 expect(3)
158 channel.send(42) // will schedule receiver for further execution
159 job.cancel() // cancel the job next
160 yield() // now yield
161 finish(6)
162 }
163
164 @Test
165 fun testDeferredAwaitCancellable() = runBlocking {
166 expect(1)
167 val deferred = async(context) { // deferred, not yet complete
168 expect(4)
169 "OK"
170 }
171 assertThat(deferred.isCompleted, IsEqual(false))
172 var job: Job? = null
173 launch(context) { // will cancel job as soon as deferred completes
174 expect(5)
175 assertThat(deferred.isCompleted, IsEqual(true))
176 job!!.cancel()
177 }
178 job = launch(context, start = CoroutineStart.UNDISPATCHED) {
179 expect(2)
180 try {
181 deferred.await() // suspends
182 expectUnreached() // will not execute -- cancelled while dispatched
183 } finally {
184 finish(7) // but will execute finally blocks
185 }
186 }
187 expect(3) // continues to execute when job suspends
188 yield() // to deferred & canceller
189 expect(6)
190 }
191
192 @Test
193 fun testSelectDeferredAwaitCancellable() = runBlocking {
194 expect(1)
195 val deferred = async(context) { // deferred, not yet complete
196 expect(4)
197 "OK"
198 }
199 assertThat(deferred.isCompleted, IsEqual(false))
200 var job: Job? = null
201 launch(context) { // will cancel job as soon as deferred completes
202 expect(5)
203 assertThat(deferred.isCompleted, IsEqual(true))
204 job!!.cancel()
205 }
206 job = launch(context, start = CoroutineStart.UNDISPATCHED) {
207 expect(2)
208 try {
209 select<Unit> { // suspends
210 deferred.onAwait { expectUnreached() }
211 }
212 expectUnreached() // will not execute -- cancelled while dispatched
213 } finally {
214 finish(7) // but will execute finally blocks
215 }
216 }
217 expect(3) // continues to execute when job suspends
218 yield() // to deferred & canceller
219 expect(6)
220 }
221
222 @Test
223 fun testJobJoinCancellable() = runBlocking {
224 expect(1)
225 val jobToJoin = launch(context) { // not yet complete
226 expect(4)
227 }
228 assertThat(jobToJoin.isCompleted, IsEqual(false))
229 var job: Job? = null
230 launch(context) { // will cancel job as soon as jobToJoin completes
231 expect(5)
232 assertThat(jobToJoin.isCompleted, IsEqual(true))
233 job!!.cancel()
234 }
235 job = launch(context, start = CoroutineStart.UNDISPATCHED) {
236 expect(2)
237 try {
238 jobToJoin.join() // suspends
239 expectUnreached() // will not execute -- cancelled while dispatched
240 } finally {
241 finish(7) // but will execute finally blocks
242 }
243 }
244 expect(3) // continues to execute when job suspends
245 yield() // to jobToJoin & canceller
246 expect(6)
247 }
248
249 @Test
250 fun testSelectJobJoinCancellable() = runBlocking {
251 expect(1)
252 val jobToJoin = launch(context) { // not yet complete
253 expect(4)
254 }
255 assertThat(jobToJoin.isCompleted, IsEqual(false))
256 var job: Job? = null
257 launch(context) { // will cancel job as soon as jobToJoin completes
258 expect(5)
259 assertThat(jobToJoin.isCompleted, IsEqual(true))
260 job!!.cancel()
261 }
262 job = launch(context, start = CoroutineStart.UNDISPATCHED) {
263 expect(2)
264 try {
265 select<Unit> { // suspends
266 jobToJoin.onJoin { expectUnreached() }
267 }
268 expectUnreached() // will not execute -- cancelled while dispatched
269 } finally {
270 finish(7) // but will execute finally blocks
271 }
272 }
273 expect(3) // continues to execute when job suspends
274 yield() // to jobToJoin & canceller
275 expect(6)
276 }
277
278
279}