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.channels.* 8 import kotlinx.coroutines.selects.* 9 import kotlin.test.* 10 11 class AtomicCancellationTest : TestBase() { 12 @Test <lambda>null13 fun testSendCancellable() = runBlocking { 14 expect(1) 15 val channel = Channel<Int>() 16 val job = launch(start = CoroutineStart.UNDISPATCHED) { 17 expect(2) 18 channel.send(42) // suspends 19 expectUnreached() // should NOT execute because of cancellation 20 } 21 expect(3) 22 assertEquals(42, channel.receive()) // will schedule sender for further execution 23 job.cancel() // cancel the job next 24 yield() // now yield 25 finish(4) 26 } 27 28 @Suppress("UNUSED_VARIABLE") 29 @Test <lambda>null30 fun testSelectSendCancellable() = runBlocking { 31 expect(1) 32 val channel = Channel<Int>() 33 val job = launch(start = CoroutineStart.UNDISPATCHED) { 34 expect(2) 35 val result = select<String> { // suspends 36 channel.onSend(42) { 37 expect(4) 38 "OK" 39 } 40 } 41 expectUnreached() // should NOT execute because of cancellation 42 } 43 expect(3) 44 assertEquals(42, channel.receive()) // will schedule sender for further execution 45 job.cancel() // cancel the job next 46 yield() // now yield 47 finish(4) 48 } 49 50 @Test <lambda>null51 fun testReceiveCancellable() = runBlocking { 52 expect(1) 53 val channel = Channel<Int>() 54 val job = launch(start = CoroutineStart.UNDISPATCHED) { 55 expect(2) 56 assertEquals(42, channel.receive()) // suspends 57 expectUnreached() // should NOT execute because of cancellation 58 } 59 expect(3) 60 channel.send(42) // will schedule receiver for further execution 61 job.cancel() // cancel the job next 62 yield() // now yield 63 finish(4) 64 } 65 66 @Test <lambda>null67 fun testSelectReceiveCancellable() = runBlocking { 68 expect(1) 69 val channel = Channel<Int>() 70 val job = launch(start = CoroutineStart.UNDISPATCHED) { 71 expect(2) 72 val result = select<String> { // suspends 73 channel.onReceive { 74 assertEquals(42, it) 75 expect(4) 76 "OK" 77 } 78 } 79 expectUnreached() // should NOT execute because of cancellation 80 } 81 expect(3) 82 channel.send(42) // will schedule receiver for further execution 83 job.cancel() // cancel the job next 84 yield() // now yield 85 finish(4) 86 } 87 88 @Test <lambda>null89 fun testSelectDeferredAwaitCancellable() = runBlocking { 90 expect(1) 91 val deferred = async { // deferred, not yet complete 92 expect(4) 93 "OK" 94 } 95 assertEquals(false, deferred.isCompleted) 96 var job: Job? = null 97 launch { // will cancel job as soon as deferred completes 98 expect(5) 99 assertEquals(true, deferred.isCompleted) 100 job!!.cancel() 101 } 102 job = launch(start = CoroutineStart.UNDISPATCHED) { 103 expect(2) 104 try { 105 select<Unit> { // suspends 106 deferred.onAwait { expectUnreached() } 107 } 108 expectUnreached() // will not execute -- cancelled while dispatched 109 } finally { 110 finish(7) // but will execute finally blocks 111 } 112 } 113 expect(3) // continues to execute when the job suspends 114 yield() // to deferred & canceller 115 expect(6) 116 } 117 118 @Test <lambda>null119 fun testSelectJobJoinCancellable() = runBlocking { 120 expect(1) 121 val jobToJoin = launch { // not yet complete 122 expect(4) 123 } 124 assertEquals(false, jobToJoin.isCompleted) 125 var job: Job? = null 126 launch { // will cancel job as soon as jobToJoin completes 127 expect(5) 128 assertEquals(true, jobToJoin.isCompleted) 129 job!!.cancel() 130 } 131 job = launch(start = CoroutineStart.UNDISPATCHED) { 132 expect(2) 133 try { 134 select<Unit> { // suspends 135 jobToJoin.onJoin { expectUnreached() } 136 } 137 expectUnreached() // will not execute -- cancelled while dispatched 138 } finally { 139 finish(7) // but will execute finally blocks 140 } 141 } 142 expect(3) // continues to execute when the job suspends 143 yield() // to jobToJoin & canceller 144 expect(6) 145 } 146 } 147