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