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