ziozio-test

How to use regular time in ZIO-Test?


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)
  )
}

Solution

  • 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 point race attempts to interrupt wait(15). However, interruption normally occurs "between" effects and wait(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 until wait(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 example wait(5).race(wait(15).disconnect). With this change your test will pass as written. You can also use the attemptBlockingInterrupt 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.