Why does delay() suspend a coroutine but yield() doesn't, inside Kotlin's runTest{} function?

50 Views Asked by At

The simplified test below has been converted from using runBlocking to runTest to make it work with Kotlin Multiplatform. However, runTest causes it to fail. Debugging shows that the delay in job1 suspends the coroutine and job2 becomes active. I would then expect the yield() call to suspend job2 and for job1 to become active again, allowing it to finish before job2. However, for some reason it doesn't. The while loop continues until the timer runs out and the test fails.

class YieldTest {
    @Volatile
    var locked: Boolean = false

    @Test
    fun test_delay_yields_coroutine() = runTest {
        val clock = Clock.System
        val timeSource = TimeSource.Monotonic

        val job1 = async {
            locked = true
            delay((500).toLong())
            locked = false

            timeSource.markNow()
        }

        val job2 = async {
            val timeout = clock.now().plus(5, DateTimeUnit.SECOND)
            while (locked && clock.now() <= timeout) {
                yield()
            }

            timeSource.markNow()
        }

        val job1Finish = job1.await()
        val job2Finish = job2.await()

        assertTrue(job1Finish < job2Finish)
    }
}

However, if I change yield() to delay(1), the coroutine is suspended and the test passes.

Why does changing to runTest cause this to fail and why does delay(1) work but yield() does not?

0

There are 0 best solutions below