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