1 /* 2 * Copyright 2016-2018 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.selects.* 8 import kotlinx.coroutines.sync.* 9 import kotlin.test.* 10 11 class AtomicCancellationCommonTest : TestBase() { 12 @Test 13 fun testCancellableLaunch() = runTest { 14 expect(1) 15 val job = launch { 16 expectUnreached() // will get cancelled before start 17 } 18 expect(2) 19 job.cancel() 20 finish(3) 21 } 22 23 @Test 24 fun testAtomicLaunch() = runTest { 25 expect(1) 26 val job = launch(start = CoroutineStart.ATOMIC) { 27 finish(4) // will execute even after it was cancelled 28 } 29 expect(2) 30 job.cancel() 31 expect(3) 32 } 33 34 @Test 35 fun testDeferredAwaitCancellable() = runTest { 36 expect(1) 37 val deferred = async { // deferred, not yet complete 38 expect(4) 39 "OK" 40 } 41 assertEquals(false, deferred.isCompleted) 42 var job: Job? = null 43 launch { // will cancel job as soon as deferred completes 44 expect(5) 45 assertEquals(true, deferred.isCompleted) 46 job!!.cancel() 47 } 48 job = launch(start = CoroutineStart.UNDISPATCHED) { 49 expect(2) 50 try { 51 deferred.await() // suspends 52 expectUnreached() // will not execute -- cancelled while dispatched 53 } finally { 54 finish(7) // but will execute finally blocks 55 } 56 } 57 expect(3) // continues to execute when the job suspends 58 yield() // to deferred & canceller 59 expect(6) 60 } 61 62 @Test 63 fun testJobJoinCancellable() = runTest { 64 expect(1) 65 val jobToJoin = launch { // not yet complete 66 expect(4) 67 } 68 assertEquals(false, jobToJoin.isCompleted) 69 var job: Job? = null 70 launch { // will cancel job as soon as jobToJoin completes 71 expect(5) 72 assertEquals(true, jobToJoin.isCompleted) 73 job!!.cancel() 74 } 75 job = launch(start = CoroutineStart.UNDISPATCHED) { 76 expect(2) 77 try { 78 jobToJoin.join() // suspends 79 expectUnreached() // will not execute -- cancelled while dispatched 80 } finally { 81 finish(7) // but will execute finally blocks 82 } 83 } 84 expect(3) // continues to execute when the job suspends 85 yield() // to jobToJoin & canceller 86 expect(6) 87 } 88 89 @Test 90 fun testLockAtomicCancel() = runTest { 91 expect(1) 92 val mutex = Mutex(true) // locked mutex 93 val job = launch(start = CoroutineStart.UNDISPATCHED) { 94 expect(2) 95 mutex.lock() // suspends 96 expect(4) // should execute despite cancellation 97 } 98 expect(3) 99 mutex.unlock() // unlock mutex first 100 job.cancel() // cancel the job next 101 yield() // now yield 102 finish(5) 103 } 104 105 @Test 106 fun testSelectLockAtomicCancel() = runTest { 107 expect(1) 108 val mutex = Mutex(true) // locked mutex 109 val job = launch(start = CoroutineStart.UNDISPATCHED) { 110 expect(2) 111 val result = select<String> { // suspends 112 mutex.onLock { 113 expect(4) 114 "OK" 115 } 116 } 117 assertEquals("OK", result) 118 expect(5) // should execute despite cancellation 119 } 120 expect(3) 121 mutex.unlock() // unlock mutex first 122 job.cancel() // cancel the job next 123 yield() // now yield 124 finish(6) 125 } 126 }