when calling a `suspend` function within `runBlock...
# coroutines
k
when calling a 
suspend
 function within 
runBlocking
 , the following code should not be executed until the function completes, correct? I am seeing some flakiness in a test that doesn't make sense to me.
✔️ 1
w
Can you paste the function?
runBlocking
doesn’t change all suspend functions into blocking ones
k
the test function or the suspending function?
w
You can still run things in parallel for example
the test function or the suspending function?
The test function
k
Copy code
@Test fun someTest() = runBlocking {
  someSuspendingFunction()
  assertTrue(shouldBeTrue) // expects above function to have returned
}
it's working most of the time
l
@Kris Wong Which platform? Can you reproduce it with any code, or only an expectation is missed for a particular function you have written?
k
i am currently seeing a failure running junit tests from the command line via
./gradlew testDebugUnitTest
. it's a common test and passes on iOS, and also when run in the IDE.
l
"Failure" is too broad, you know it.
k
it's only 1 test that is failing. other tests are exercising the same code in similar ways. the suspending function ends up calling Ktor
HttpClient().post
l
Define "failing", please.
k
a boolean gets set to true in a callback that is called from the suspending function
which is not happening. the callback is not called in this one case.
w
My guess is that
someSuspendingFunction
does thing asynchronously, launches a coroutine in a separate scope for example. And the test is simply flaky, sometimes the asynchronous thing manages to complete and sometimes it doesn’t
k
also my guess, just not what I expected, and I'm not quite sure how to fix it
unfortunately I am limited to APIs in stdlib-common
w
I’m not quite sure how to fix it
It really depends on what
someSuspendingFunction()
does
l
You said it works all the time on iOS and in the IDE. If so, then on which platform is it sometimes failing?
k
android junit tests
which is of course just JVM
l
AGP 7?
Running in the JVM or in an emulator or device? Because Android is not "just JVM" despite it being almost it.
k
android unit tests run in the JVM (unlike connected tests). AGP 4.1.2.
l
Alright. Weird then blob thinking upside down
k
I believe something like
withContext
might do the trick, but I don't think that API is available
l
It is
You can also use
Dispatchers.Default { }
, or just
coroutineScope { }
if you fear you broke structured concurrency in a way or another at the immediate level.
If you have a class implementing
CoroutineScope
, it's very likely you're breaking structured concurrency BTW.
k
the only scope my code is creating is provided by
runBlocking
, however I am sure Ktor is creating one or more scopes
withContext
didn't fix it
l
Then we cannot help without a reproducer
It might be a ktor specific issue
k
oh snap, I notice the test execution order is not the same between the IDE and the command line. I think I may be on to something with that.
l
Shared mutable state? 🤔
k
yes, it succeeds when isolate the failing test
nothing to see here, sorry for the trouble!
I have tracked this down to what appears to be a very strange IllegalMonitorStateException with ReentrantLock that was being swallowed
man, yet another red herring. the root of the problem was that I was passing too small of a grace period/timeout to stop the Ktor server I was using for the tests.
moral of the story,
runBlocking
is working as expected
l
Why don't you stop the server only when all the tests are done?
g
Why start/stop server on every test, otherwise it breaks test isolation
k
test isolation is exactly why i start and stop it on every test
g
yep, makes sense, but I don’t see why stop timeout is required for tests
k
the API requires it
stopping the server does a bit of asynchronous work within
runBlocking
I was passing 1 [ms] for both values (grace period and timeout), bumped to 10 and 100
simple fix, but it took me nearly all day to get to the root of the issue