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
<lambda>null17     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
<lambda>null31     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
<lambda>null47     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
testYieldBlockingWithTimeoutnull73     fun testYieldBlockingWithTimeout() = runTest(
74         expected = { it is CancellationException }
<lambda>null75     ) {
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
<lambda>null87     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
<lambda>null102     fun testBadClass() = runTest {
103         val bad = BadClass()
104         val result = withTimeout(100) {
105             bad
106         }
107         assertSame(bad, result)
108     }
109 
110     @Test
<lambda>null111     fun testExceptionOnTimeout() = runTest {
112         expect(1)
113         try {
114             withTimeout(100) {
115                 expect(2)
116                 delay(1000)
117                 expectUnreached()
118                 "OK"
119             }
120         } catch (e: CancellationException) {
121             assertEquals("Timed out waiting for 100 ms", e.message)
122             finish(3)
123         }
124     }
125 
126     @Test
testSuppressExceptionWithResultnull127     fun testSuppressExceptionWithResult() = runTest(
128         expected = { it is CancellationException }
<lambda>null129     ) {
130         expect(1)
131         withTimeout(100) {
132             expect(2)
133             try {
134                 delay(1000)
135             } catch (e: CancellationException) {
136                 finish(3)
137             }
138             "OK"
139         }
140         expectUnreached()
141     }
142 
143     @Test
<lambda>null144     fun testSuppressExceptionWithAnotherException() = runTest{
145         expect(1)
146         try {
147             withTimeout(100) {
148                 expect(2)
149                 try {
150                     delay(1000)
151                 } catch (e: CancellationException) {
152                     expect(3)
153                     throw TestException()
154                 }
155                 expectUnreached()
156                 "OK"
157             }
158             expectUnreached()
159         } catch (e: TestException) {
160             finish(4)
161         }
162     }
163 
164     @Test
<lambda>null165     fun testNegativeTimeout() = runTest {
166         expect(1)
167         try {
168             withTimeout(-1) {
169                 expectUnreached()
170                 "OK"
171             }
172         } catch (e: TimeoutCancellationException) {
173             assertEquals("Timed out immediately", e.message)
174             finish(2)
175         }
176     }
177 
178     @Test
<lambda>null179     fun testExceptionFromWithinTimeout() = runTest {
180         expect(1)
181         try {
182             expect(2)
183             withTimeout(1000) {
184                 expect(3)
185                 throw TestException()
186             }
187             expectUnreached()
188         } catch (e: TestException) {
189             finish(4)
190         }
191     }
192 
193     @Test
<lambda>null194     fun testIncompleteWithTimeoutState() = runTest {
195         lateinit var timeoutJob: Job
196         val handle = withTimeout(Long.MAX_VALUE) {
197             timeoutJob = coroutineContext[Job]!!
198             timeoutJob.invokeOnCompletion { }
199         }
200 
201         handle.dispose()
202         timeoutJob.join()
203         assertTrue(timeoutJob.isCompleted)
204         assertFalse(timeoutJob.isActive)
205         assertFalse(timeoutJob.isCancelled)
206     }
207 }
208