`ContainerTimeoutTest` is flaky and I can't figure...
# kotest-contributors
e
ContainerTimeoutTest
is flaky and I can't figure out why 😕 Putting a breakpoint at
TimeoutInterceptor:34
consistently causes the same failure
m
@Emil Kantis would nesting the assertion within
eventually
helps? that seems like it’s a race condition between test asserting too early and interceptor not hit
e
doesn't seem to make a difference
I think has something to do with the
TimeoutCancellationException
sometimes being caught by the
TestInvocationInterceptor
instead of the
TimeoutInterceptor
m
ah right i see
that might be it
you’re right @Emil Kantis I reckon we might need to perhaps match against the exception type there explicitly and return kotest’s timeout instead
e
But what if the user runs some code that throws a TimeoutCancellationException?
m
ah right, we do have the specific error type
TestTimeoutException
we should only introspect that.. The problem seems like a lot of function in kotest piggiback on
withTimeout
and then catching the timeout ex and translating that to the exception type..
in ideal scenario we should be defining a kotest-specific withTimeout function which would be throwing kotest’s error type, something like
withKotestTimeout
or something like so. naming is hard
that way it’s impossible for the engine to mistakenly catch timeouts by users’ code
e
Yes, but sadly withTimeout doesn’t provide any way of specifying what to throw, and I think it's kinda deeply embedded in Coroutine execution..
Maybe we could add a Coroutine context element which says the Kotest specific timeout, and if the elapsed millis => kotest timeout, we translate it to
TestTimeoutException
?
Maybe we could just increase the timeout in ContainerTimeoutTest a bit, I dont think it's a problem in practice
m
yeah that’s just a bit annoying.. I think we should be able to just do a launch and then cancel. something like
Copy code
suspend fun withKotestTimeout(duration: Duration, onTimeout: suspend () -> Throwable, fn: suspend () -> T): T {
  val currentTime = ...
  val fallthroughAt = currentTime + duration
  val eventuallyValue = async { fn() }
  while (!eventuallyValue.isCompleted) {
    if (now() < fallthroughAt) { 
      delay(25.milliseconds)
    } else {
      onTimeout()
    }
  }
  eventuallyValue.await()
}
e
true, that looks doable 🙂
m
dw about it for now. i reckon like you said it’s just a bit of an annoyance right now..
if we do that we need to make changes in gazilion places..
e
Isn’t the TimeoutInterceptor the only thing that needs adjusting?
s
I like the idea of catching the exception and seeing if timeout >= kotest timeout