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