Oliver.O
06/24/2024, 3:44 PMeventually
, continually
, until
or retry
in coroutines using the `TestDispatcher`'s virtual time? (You are using virtual time in tests configured with coroutineTestScope = true
.)
So far, all of those functions were operating on real time, even when used in coroutines operating on virtual time. We intend to change this, so that with the TestDispatcher
in use, these functions also use virtual time. So, for example, where a delay
would use virtual time, eventually
would as well. Switching from virtual to real-time schedulers via withContext(<http://Dispatchers.IO|Dispatchers.IO>)
is supported, and would switch to real time for everything.
Do you have a use case or can you think of one, where you would mix real time and virtual time for the above scenarios?
👌 I have a use case or can imagine one, details in 🧵
no red I don't have a use case and I have no idea why I'd want to do this.
Clarification: Please answer 👌 if and only if both of the following conditions are true
1. you have a coroutine running on virtual time, and
2. in that coroutine you use eventually
with a real-time timeout.
If you have or can imagine such a concrete use case, please post it in the 🧵.Klitos Kyriacou
06/24/2024, 4:59 PMTestDispatcher
but may do in the future. I currently use eventually
and rely on real time because it's waiting for a service running in another container to start.Oliver.O
06/24/2024, 5:04 PMeventually
on a TestDispatcher
, right? Where would the TestDispatcher
come in? What does the use case look like?Klitos Kyriacou
06/24/2024, 8:11 PMTestDispatcher
so far, so I may be mistaken thinking it might be relevant here. My use case is that my production code contains some coroutines, most of which use withContext(<http://Dispatchers.IO|Dispatchers.IO>)
, and I have an integration test that depends on some containers having been started which communicate with the system under test, hence I use eventually
as those containers can take some time to start up.Oliver.O
06/24/2024, 8:28 PMeventually
to wait for something to become ready is perfectly legitimate. You'd just use the eventually
within a standard dispatcher to do so.
A TestDispatcher
requires all of your code under test to execute in a single thread. Why? Because the purpose of the TestDispatcher
is to skip time, omitting unnecessary waits, making tests faster. And it can only skip time if it knows precisely, what comes next. So if coroutine #1 delays for 2 seconds, and coroutine #2 one for 1 second, it would just advance virtual time by 1 second (eliminating a real-time wait), then resume coroutine #2. It can never know what comes next in code running on different threads (or just concurrently under non-test dispatchers).
Even within a TestDispatcher
-controlled coroutine you could still wait for some service to start up by doing withContext(<http://Dispatchers.IO|Dispatchers.IO>) { eventually(...) { ... } }
. So there would be no mix of virtual time and real time.sam
06/24/2024, 9:18 PMOliver.O
06/24/2024, 9:33 PMCLOVIS
06/25/2024, 7:41 AMeventually
& co: because I'm using coroutines, most of the time I can just await the event I want. Or, in the case of cache expiration, I know after how long it's supposed to trigger, so I can simply delay
until that point.Oliver.O
06/25/2024, 9:14 AMeventually
with a real-time timeout.
If you have or can imagine such a concrete use case, please post it.
If this additional explanation would change your answer, you can choose a different one at any time.Adam S
06/25/2024, 9:42 AMOliver.O
06/25/2024, 9:47 AMAdam S
06/25/2024, 10:18 AMAdam S
06/25/2024, 10:18 AMOliver.O
06/25/2024, 10:45 AMsam
06/25/2024, 7:40 PMOliver.O
06/25/2024, 7:42 PMeventually
and others. Kotest users would probably not need it.Adam S
06/25/2024, 7:44 PMeventually
, what would be more surprising? eventually
also using virtual time, or not?Adam S
06/25/2024, 7:47 PMOliver.O
06/25/2024, 7:55 PMsam
06/25/2024, 7:56 PMOliver.O
06/25/2024, 7:57 PMsam
06/25/2024, 7:58 PMOliver.O
06/25/2024, 7:58 PMsam
06/25/2024, 7:58 PMsam
06/25/2024, 7:58 PMOliver.O
06/25/2024, 7:59 PMsam
06/25/2024, 8:00 PMsam
06/25/2024, 8:01 PMOliver.O
06/25/2024, 8:01 PMOliver.O
06/25/2024, 8:02 PMOliver.O
06/25/2024, 8:03 PMOliver.O
06/25/2024, 8:03 PMAdam S
06/25/2024, 8:04 PMeventually
et al is configuring test behaviour.Oliver.O
06/25/2024, 10:04 PMdelay
uses time, eventually
uses time. Both always use the same time source, whatever it is. Result for now is: We have stable tests. Kotest users might not need it (if we ignore the above case), it doesn't hurt either.
If we don't want that, what should we change? What would be the added value?sam
06/26/2024, 12:01 AMOliver.O
06/26/2024, 12:26 AMsam
06/26/2024, 12:27 AMOliver.O
06/26/2024, 12:31 AMsam
06/26/2024, 12:31 AMsam
06/26/2024, 12:31 AMOliver.O
06/26/2024, 7:15 AMAdam S
06/26/2024, 8:33 AMeventually
with a limit of 1 minute, because it's easier than fixing the flaky server.
Their HttpClient implementation has a custom retry, using coroutines and delay(...)
. In their HttpClientTest they don't actually want to delay()
when the server fails, so they enable virtual-time.
However, if eventually
respects virtual-time, and the server is flaky, now the HttpClient's delay()
will cause the eventually
to complete earlier than what they want.
What they wanted is to make sure that the tests complete within a fixed time limit. But instead an implementation detail of their HttpClient will mean that the flaky server doesn't get retried as often as they want. What could they do instead?Oliver.O
06/26/2024, 9:20 AMTheir HttpClient implementation has a custom retry, using coroutines andWhat is the delay inside the HTTP client for?. In their HttpClientTest they don't actually want todelay(...)
when the server fails, so they enable virtual-time.delay()
Adam S
06/26/2024, 9:25 AMOliver.O
06/26/2024, 10:32 AMAdam S
06/26/2024, 10:56 AMOliver.O
06/26/2024, 10:57 AMAdam S
06/26/2024, 10:59 AMOliver.O
06/26/2024, 11:00 AMOliver.O
06/26/2024, 11:22 AMwithContext(<http://Dispatchers.IO|Dispatchers.IO>) { ... }
, but switching back to outside virtual time inside the new real-time world is a no-no.Adam S
06/28/2024, 6:29 AMI guess in the end it boils down to having an explicit test mode: Parameterize the server, so that it acts differently under test, parameterize the client so that it does not delay.What if the code can't be parameterised? E.g. it's in a 3rd party library
Oliver.O
06/28/2024, 12:05 PMwithContext(StandardTestDispatcher()) {
… }
inside an eventually
running on a regular dispatcher.