1 2 /* 3 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 4 */ 5 6 @file:Suppress("NAMED_ARGUMENTS_NOT_ALLOWED", "UNREACHABLE_CODE") // KT-21913 7 8 package kotlinx.coroutines 9 10 import kotlin.test.* 11 12 class WithTimeoutTest : TestBase() { 13 /** 14 * Tests a case of no timeout and no suspension inside. 15 */ 16 @Test 17 fun testBasicNoSuspend() = runTest { 18 expect(1) 19 val result = withTimeout(10_000) { 20 expect(2) 21 "OK" 22 } 23 assertEquals("OK", result) 24 finish(3) 25 } 26 27 /** 28 * Tests a case of no timeout and one suspension inside. 29 */ 30 @Test 31 fun testBasicSuspend() = runTest { 32 expect(1) 33 val result = withTimeout(10_000) { 34 expect(2) 35 yield() 36 expect(3) 37 "OK" 38 } 39 assertEquals("OK", result) 40 finish(4) 41 } 42 43 /** 44 * Tests proper dispatching of `withTimeout` blocks 45 */ 46 @Test 47 fun testDispatch() = runTest { 48 expect(1) 49 launch { 50 expect(4) 51 yield() // back to main 52 expect(7) 53 } 54 expect(2) 55 // test that it does not yield to the above job when started 56 val result = withTimeout(1000) { 57 expect(3) 58 yield() // yield only now 59 expect(5) 60 "OK" 61 } 62 assertEquals("OK", result) 63 expect(6) 64 yield() // back to launch 65 finish(8) 66 } 67 68 69 /** 70 * Tests that a 100% CPU-consuming loop will react on timeout if it has yields. 71 */ 72 @Test 73 fun testYieldBlockingWithTimeout() = runTest( 74 expected = { it is CancellationException } 75 ) { 76 withTimeout(100) { 77 while (true) { 78 yield() 79 } 80 } 81 } 82 83 /** 84 * Tests that [withTimeout] waits for children coroutines to complete. 85 */ 86 @Test 87 fun testWithTimeoutChildWait() = runTest { 88 expect(1) 89 withTimeout(100) { 90 expect(2) 91 // launch child with timeout 92 launch { 93 expect(4) 94 } 95 expect(3) 96 // now will wait for child before returning 97 } 98 finish(5) 99 } 100 101 @Test 102 fun testBadClass() = runTest { 103 val bad = BadClass() 104 val result = withTimeout(100) { 105 bad 106 } 107 assertSame(bad, result) 108 } 109 110 class BadClass { 111 override fun equals(other: Any?): Boolean = error("Should not be called") 112 override fun hashCode(): Int = error("Should not be called") 113 override fun toString(): String = error("Should not be called") 114 } 115 116 @Test 117 fun testExceptionOnTimeout() = runTest { 118 expect(1) 119 try { 120 withTimeout(100) { 121 expect(2) 122 delay(1000) 123 expectUnreached() 124 "OK" 125 } 126 } catch (e: CancellationException) { 127 assertEquals("Timed out waiting for 100 ms", e.message) 128 finish(3) 129 } 130 } 131 132 @Test 133 fun testSuppressExceptionWithResult() = runTest( 134 expected = { it is CancellationException } 135 ) { 136 expect(1) 137 withTimeout(100) { 138 expect(2) 139 try { 140 delay(1000) 141 } catch (e: CancellationException) { 142 finish(3) 143 } 144 "OK" 145 } 146 expectUnreached() 147 } 148 149 @Test 150 fun testSuppressExceptionWithAnotherException() = runTest{ 151 expect(1) 152 try { 153 withTimeout(100) { 154 expect(2) 155 try { 156 delay(1000) 157 } catch (e: CancellationException) { 158 expect(3) 159 throw TestException() 160 } 161 expectUnreached() 162 "OK" 163 } 164 expectUnreached() 165 } catch (e: TestException) { 166 finish(4) 167 } 168 } 169 170 @Test 171 fun testNegativeTimeout() = runTest { 172 expect(1) 173 try { 174 withTimeout(-1) { 175 expectUnreached() 176 "OK" 177 } 178 } catch (e: TimeoutCancellationException) { 179 assertEquals("Timed out immediately", e.message) 180 finish(2) 181 } 182 } 183 184 @Test 185 fun testExceptionFromWithinTimeout() = runTest { 186 expect(1) 187 try { 188 expect(2) 189 withTimeout(1000) { 190 expect(3) 191 throw TestException() 192 } 193 expectUnreached() 194 } catch (e: TestException) { 195 finish(4) 196 } 197 } 198 199 @Test 200 fun testIncompleteWithTimeoutState() = runTest { 201 lateinit var timeoutJob: Job 202 val handle = withTimeout(Long.MAX_VALUE) { 203 timeoutJob = coroutineContext[Job]!! 204 timeoutJob.invokeOnCompletion { } 205 } 206 207 handle.dispose() 208 timeoutJob.join() 209 assertTrue(timeoutJob.isCompleted) 210 assertFalse(timeoutJob.isActive) 211 assertFalse(timeoutJob.isCancelled) 212 } 213 } 214