-
Notifications
You must be signed in to change notification settings - Fork 1.9k
runTest
doesn't report test failure if a non-cancellable coroutine happens to be hanging
#3066
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
runTest
doesn't report test failure a non-cancellable coroutine happens to be hangingrunTest
doesn't report test failure if a non-cancellable coroutine happens to be hanging
Thanks for reporting this! Some thoughts:
@Test
fun testFailureWithPendingCoroutine() = runTest(dispatchTimeoutMs = 5000) {
launch {
withContext(NonCancellable) {
try {
// we entered the `try` block...
awaitCancellation() // hanging non-cancellable coroutine
} finally {
// ... but we never enter `finally`! Wow, this is surprising!
}
}
}
yield()
fail("some test failure") // this line is reached and throws, but it's never reported
}
Now, we could achieve more helpful behavior in this case by, for example, adding the exception the coroutine finished with as a suppressed one. Not really straightforward though, as, after all, we want to prevent accessing the completion exception before the coroutine is completed, but it could be done. |
I was about to answer something, but when thinking about it a bit more I agree with you here (at least partly). My initial arguments were:
But I'll answer my own questions here. The hanging coroutine might be a problem that's only visible in case of failure, so if we just report the failure, and the dev fixes it, we might miss the fact that structured concurrency is broken in the code or the test. That being said, maybe we could have different behaviour in case of
Yes, in case we wait for the full timeout, both exceptions should be visible. We definitely don't want to hide the
Maybe my use case is just a bit peculiar here. To give a bit more context, I'm testing the timeout behaviour of a 2-step connection operation (websocket first, then STOMP). If the Now my My test was advancing the time artificially until the timeout and trying to assert that the connection coroutine was complete, which was not the case due to a bug in the code (the production code was indeed hanging). My test failure made it clear that the coroutine was hanging after timeout with a precise error message, but that message never surfaced in the test result, and I just got the vague exception from the test framework. Both would have reported the hanging behaviour, but since I explicitly checked and asserted for this in the test, I expected my error to be visible in that case.
Yes, this is exactly what I'm looking for here. I think it is important to have all failures visible because sometimes it's also critical information (on top of the hanging coroutine one). |
* The error is more verbose: it lists the active children. * If the test coroutine is already finishing with an error, that error is added to the timeout notification as suppressed. * The timeout is considered more important, so now, if there were any uncaught exceptions, they don't take precedence over it but are suppressed by it. Fixes #3066 Fixes #3069
* The error is more verbose: it lists the active children. * If the test coroutine is already finishing with an error, that error is added to the timeout notification as suppressed. * The timeout is considered more important, so now, if there were any uncaught exceptions, they don't take precedence over it but are suppressed by it. Fixes Kotlin#3066 Fixes Kotlin#3069
* The error is more verbose: it lists the active children. * If the test coroutine is already finishing with an error, that error is added to the timeout notification as suppressed. * The timeout is considered more important, so now, if there were any uncaught exceptions, they don't take precedence over it but are suppressed by it. Fixes Kotlin#3066 Fixes Kotlin#3069
I'm using
kotlinx-coroutines-test
1.6.0-RC.If some non-cancellable coroutine code is hanging, exceptions or assertion errors from the test are never reported despite being reached:
I could see with debugging that the
fail()
is indeed reached and called. It does fail, but the assertion error is just swallowed somewhere inrunTest
and never makes it to the output. I just get the error message about the hanging coroutine:Moreover, the test spends the whole
dispatchTimeoutMs
before failing (this is why I reduced it to 5 seconds in the repro). It is somewhat understandable because of the non-cancellability of the coroutine, but it's quite annoying too. Not sure we could do anything about that though, at least the reporting of test failure in addition to the timeout would be great.The text was updated successfully, but these errors were encountered: