While working on zio-spark, we cannot race effects in Tests that are not using zio.Clock
. The effects are not interrupted. It's there a way to fix that?
package zio.spark.effect
import zio._
import zio.test.TestAspect.timeout
import zio.test._
object WeirdClocks extends DefaultRunnableSpec {
def wait(seconds: Int): UIO[Int] = UIO(Thread.sleep(seconds * 1000)).as(seconds)
override def spec: ZSpec[TestEnvironment, Any] = suite("clock")(
test("raceTest") {
wait(5).race(wait(15)) map (n => assertTrue(n == 5))
} @@ timeout(10.seconds)
)
}
This is expected behavior and doesn't have anything to do with ZIO Test or the
Clock
.Interruption in ZIO does not return until the effect has been successfully interrupted, which is an important guarantee for resource safety. In
wait(5).race(wait(15))
,wait(5)
wins the race after 5 seconds. At that pointrace
attempts to interruptwait(15)
. However, interruption normally occurs "between" effects andwait(15)
is a single block of side effecting code so there is no way to safely interrupt it in general. As a result, interruption suspends untilwait(15)
has completed execution, but by this time 15 seconds have elapsed and the test has already timed out.If you don't want to wait for interruption to complete you can use the
disconnect
operator, for examplewait(5).race(wait(15).disconnect)
. With this change your test will pass as written. You can also use theattemptBlockingInterrupt
to direct the ZIO runtime to attempt to interrupt a single block of side effecting code like this by interrupting the underlying thread, though this is relatively heavyweight.