blob: 0507484e9dfafa82514be76e41663665f327766b [file] [log] [blame]
Roman Elizarova74eb5f2017-05-11 20:15:18 +03001/*
Roman Elizarov1f74a2d2018-06-29 19:19:45 +03002 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
Roman Elizarova74eb5f2017-05-11 20:15:18 +03003 */
4
5package kotlinx.coroutines.experimental
6
Roman Elizarov9fe5f462018-02-21 19:05:52 +03007import kotlinx.coroutines.experimental.channels.*
8import kotlinx.coroutines.experimental.selects.*
9import kotlinx.coroutines.experimental.sync.*
10import kotlin.coroutines.experimental.*
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030011import kotlin.test.*
Roman Elizarova74eb5f2017-05-11 20:15:18 +030012
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030013class AtomicCancellationTest : TestBase() {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030014 @Test
Roman Elizarova74eb5f2017-05-11 20:15:18 +030015 fun testSendAtomicCancel() = runBlocking {
16 expect(1)
17 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +030018 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030019 expect(2)
20 channel.send(42) // suspends
21 expect(4) // should execute despite cancellation
22 }
23 expect(3)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030024 assertEquals(42, channel.receive()) // will schedule sender for further execution
Roman Elizarova74eb5f2017-05-11 20:15:18 +030025 job.cancel() // cancel the job next
26 yield() // now yield
27 finish(5)
28 }
29
30 @Test
31 fun testSelectSendAtomicCancel() = runBlocking {
32 expect(1)
33 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +030034 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030035 expect(2)
36 val result = select<String> { // suspends
37 channel.onSend(42) {
38 expect(4)
39 "OK"
40 }
41 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030042 assertEquals("OK", result)
Roman Elizarova74eb5f2017-05-11 20:15:18 +030043 expect(5) // should execute despite cancellation
44 }
45 expect(3)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030046 assertEquals(42, channel.receive()) // will schedule sender for further execution
Roman Elizarova74eb5f2017-05-11 20:15:18 +030047 job.cancel() // cancel the job next
48 yield() // now yield
49 finish(6)
50 }
51
52 @Test
53 fun testReceiveAtomicCancel() = runBlocking {
54 expect(1)
55 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +030056 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030057 expect(2)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030058 assertEquals(42, channel.receive()) // suspends
Roman Elizarova74eb5f2017-05-11 20:15:18 +030059 expect(4) // should execute despite cancellation
60 }
61 expect(3)
62 channel.send(42) // will schedule receiver for further execution
63 job.cancel() // cancel the job next
64 yield() // now yield
65 finish(5)
66 }
67
68 @Test
69 fun testSelectReceiveAtomicCancel() = runBlocking {
70 expect(1)
71 val channel = Channel<Int>()
Roman Elizarov43e3af72017-07-21 16:01:31 +030072 val job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +030073 expect(2)
74 val result = select<String> { // suspends
75 channel.onReceive {
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030076 assertEquals(42, it)
Roman Elizarova74eb5f2017-05-11 20:15:18 +030077 expect(4)
78 "OK"
79 }
80 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030081 assertEquals("OK", result)
Roman Elizarova74eb5f2017-05-11 20:15:18 +030082 expect(5) // should execute despite cancellation
83 }
84 expect(3)
85 channel.send(42) // will schedule receiver for further execution
86 job.cancel() // cancel the job next
87 yield() // now yield
88 finish(6)
89 }
90
91 @Test
Roman Elizarova74eb5f2017-05-11 20:15:18 +030092 fun testSelectDeferredAwaitCancellable() = runBlocking {
93 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +030094 val deferred = async(coroutineContext) { // deferred, not yet complete
Roman Elizarova74eb5f2017-05-11 20:15:18 +030095 expect(4)
96 "OK"
97 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030098 assertEquals(false, deferred.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +030099 var job: Job? = null
Roman Elizarov43e3af72017-07-21 16:01:31 +0300100 launch(coroutineContext) { // will cancel job as soon as deferred completes
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300101 expect(5)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300102 assertEquals(true, deferred.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300103 job!!.cancel()
104 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300105 job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300106 expect(2)
107 try {
108 select<Unit> { // suspends
109 deferred.onAwait { expectUnreached() }
110 }
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 job suspends
117 yield() // to deferred & canceller
118 expect(6)
119 }
120
121 @Test
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300122 fun testSelectJobJoinCancellable() = runBlocking {
123 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300124 val jobToJoin = launch(coroutineContext) { // not yet complete
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300125 expect(4)
126 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300127 assertEquals(false, jobToJoin.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300128 var job: Job? = null
Roman Elizarov43e3af72017-07-21 16:01:31 +0300129 launch(coroutineContext) { // will cancel job as soon as jobToJoin completes
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300130 expect(5)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +0300131 assertEquals(true, jobToJoin.isCompleted)
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300132 job!!.cancel()
133 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300134 job = launch(coroutineContext, start = CoroutineStart.UNDISPATCHED) {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300135 expect(2)
136 try {
137 select<Unit> { // suspends
138 jobToJoin.onJoin { expectUnreached() }
139 }
140 expectUnreached() // will not execute -- cancelled while dispatched
141 } finally {
142 finish(7) // but will execute finally blocks
143 }
144 }
145 expect(3) // continues to execute when job suspends
146 yield() // to jobToJoin & canceller
147 expect(6)
148 }
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300149}