Skip to content

Commit 25a7fe0

Browse files
committed
More tests for the scheduler
1 parent 50dfc7b commit 25a7fe0

File tree

2 files changed

+85
-17
lines changed

2 files changed

+85
-17
lines changed

kotlinx-coroutines-test/common/test/TestCoroutineSchedulerTest.kt

+69-6
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class TestCoroutineSchedulerTest {
7070

7171
/** Tests the basic functionality of [TestCoroutineScheduler.advanceTimeBy]. */
7272
@Test
73-
fun testAdvanceTimeBy() {
73+
fun testAdvanceTimeBy() = assertRunsFast {
7474
val scheduler = TestCoroutineScheduler()
7575
val scope = TestCoroutineScope(scheduler)
7676
var stage = 1
@@ -96,26 +96,89 @@ class TestCoroutineSchedulerTest {
9696
scope.cleanupTestCoroutines()
9797
}
9898

99+
/** Tests the basic functionality of [TestCoroutineScheduler.runCurrent]. */
100+
@Test
101+
fun testRunCurrent() = runBlockingTest {
102+
var stage = 0
103+
launch {
104+
delay(1)
105+
++stage
106+
delay(1)
107+
stage += 10
108+
}
109+
launch {
110+
delay(1)
111+
++stage
112+
delay(1)
113+
stage += 10
114+
}
115+
testScheduler.advanceTimeBy(1)
116+
assertEquals(0, stage)
117+
runCurrent()
118+
assertEquals(2, stage)
119+
testScheduler.advanceTimeBy(1)
120+
assertEquals(2, stage)
121+
runCurrent()
122+
assertEquals(22, stage)
123+
}
124+
99125
/** Tests that [TestCoroutineScheduler.runCurrent] will not run new tasks after the current time has advanced. */
100126
@Test
101-
fun testRunCurrentNotDrainingQueue() {
127+
fun testRunCurrentNotDrainingQueue() = assertRunsFast {
102128
val scheduler = TestCoroutineScheduler()
103129
val scope = TestCoroutineScope(scheduler)
104130
var stage = 1
105131
scope.launch {
106-
delay(1)
132+
delay(SLOW)
107133
launch {
108-
delay(1)
134+
delay(SLOW)
109135
stage = 3
110136
}
111-
scheduler.advanceTimeBy(1)
137+
scheduler.advanceTimeBy(SLOW)
112138
stage = 2
113139
}
114-
scheduler.advanceTimeBy(1)
140+
scheduler.advanceTimeBy(SLOW)
115141
assertEquals(1, stage)
116142
scheduler.runCurrent()
117143
assertEquals(2, stage)
118144
scheduler.runCurrent()
119145
assertEquals(3, stage)
120146
}
147+
148+
/** Tests that [TestCoroutineScheduler.advanceUntilIdle] doesn't hang when itself running in a scheduler task. */
149+
@Test
150+
fun testNestedAdvanceUntilIdle() = assertRunsFast {
151+
val scheduler = TestCoroutineScheduler()
152+
val scope = TestCoroutineScope(scheduler)
153+
var executed = false
154+
scope.launch {
155+
launch {
156+
delay(SLOW)
157+
executed = true
158+
}
159+
scheduler.advanceUntilIdle()
160+
}
161+
scheduler.advanceUntilIdle()
162+
assertTrue(executed)
163+
}
164+
165+
/** Tests [yield] scheduling tasks for future execution and not executing immediately. */
166+
@Test
167+
fun testYield() {
168+
val scope = TestCoroutineScope()
169+
var stage = 0
170+
scope.launch {
171+
yield()
172+
assertEquals(1, stage)
173+
stage = 2
174+
}
175+
scope.launch {
176+
yield()
177+
assertEquals(2, stage)
178+
stage = 3
179+
}
180+
assertEquals(0, stage)
181+
stage = 1
182+
scope.runCurrent()
183+
}
121184
}

kotlinx-coroutines-test/common/test/TestModuleHelpers.kt

+16-11
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,27 @@
44

55
package kotlinx.coroutines.test
66

7-
import kotlinx.coroutines.*
87
import kotlin.test.*
98
import kotlin.time.*
109

11-
const val SLOW = 10_000L
10+
/**
11+
* The number of milliseconds that is sure not to pass [assertRunsFast].
12+
*/
13+
const val SLOW = 100_000L
1214

1315
/**
14-
* Assert a block completes within a second or fail the suite
16+
* Asserts that a block completed within [timeout].
1517
*/
1618
@OptIn(ExperimentalTime::class)
17-
suspend fun CoroutineScope.assertRunsFast(block: suspend CoroutineScope.() -> Unit) {
18-
val start = TimeSource.Monotonic.markNow()
19-
// don't need to be fancy with timeouts here since anything longer than a few ms is an error
20-
block()
21-
val duration = start.elapsedNow()
22-
assertTrue("All tests must complete within 2000ms (use longer timeouts to cause failure)") {
23-
duration.inWholeSeconds < 2
24-
}
19+
inline fun <T> assertRunsFast(timeout: Duration, block: () -> T): T {
20+
val result: T
21+
val elapsed = TimeSource.Monotonic.measureTime { result = block() }
22+
assertTrue("Should complete in $timeout, but took $elapsed") { elapsed < timeout }
23+
return result
2524
}
25+
26+
/**
27+
* Asserts that a block completed within two seconds.
28+
*/
29+
@OptIn(ExperimentalTime::class)
30+
inline fun <T> assertRunsFast(block: () -> T): T = assertRunsFast(Duration.seconds(2), block)

0 commit comments

Comments
 (0)