Skip to content

Instantly share code, notes, and snippets.

@mostr
Created April 7, 2021 08:52
Show Gist options
  • Save mostr/6b53fc13a686c0c358f8c8646f531263 to your computer and use it in GitHub Desktop.
Save mostr/6b53fc13a686c0c358f8c8646f531263 to your computer and use it in GitHub Desktop.
ZIO test clock + scheduled tasks
package scheduler
import zio.clock.Clock
import zio.duration.durationInt
import zio.logging.Logging
import zio.test.Assertion.equalTo
import zio.test.environment.TestEnvironment
import zio.test.{DefaultRunnableSpec, ZSpec}
import zio.{Has, Ref, ZIO}
/*
Testing ZIO-based repeated tasks. It works fine locally, but when there is logging within the task it stops working under test.
It looks like it somehow holds execution after first iteration, because adding `fork` to logging statement within `doWorkLogging` makes test pass
*/
object SimpleSpec extends DefaultRunnableSpec {
private val doWorkLogging = for {
_ <- ZIO.accessM[Has[Ref[Long]]](_.get.update(_ + 1))
now <- zio.clock.instant
_ <- zio.logging.log.info(s"Run $now")
} yield ()
private val doWorkConsole = for {
_ <- ZIO.accessM[Has[Ref[Long]]](_.get.update(_ + 1))
now <- zio.clock.instant
_ <- zio.console.putStrLn(s"Run $now")
} yield ()
private val logging = Logging.console()
override def spec: ZSpec[Environment, Any] = suite("simple test")(
testM("logging + delay work with Clock.live") {
val counter = Ref.make(0L).toLayer
val looper = doWorkLogging *> (zio.UIO.unit.delay(2.seconds) *> doWorkLogging).forever
(for {
f <- looper.fork
_ <- zio.clock.sleep(5.seconds)
ref <- ZIO.service[Ref[Long]]
count <- ref.get
_ <- f.interrupt
} yield zio.test.assert(count)(equalTo(3L))).provideSomeLayer(Clock.live ++ logging ++ counter)
},
// Why is this one failing with count = 1?
testM("logging + delay don't work with TestEnvironment") {
val counter = Ref.make(0L).toLayer
val looper = doWorkLogging *> (zio.UIO.unit.delay(2.seconds) *> doWorkLogging).forever
(for {
f <- looper.fork
_ <- zio.test.environment.TestClock.adjust(5.seconds)
ref <- ZIO.service[Ref[Long]]
count <- ref.get
_ <- f.interrupt
} yield zio.test.assert(count)(equalTo(3L))).provideSomeLayer[TestEnvironment](logging ++ counter)
},
// And why this one (with logging replaced with console) works then?
testM("console + delay work with TestEnvironment") {
val counter = Ref.make(0L).toLayer
val looper = doWorkConsole *> (zio.UIO.unit.delay(2.seconds) *> doWorkConsole).forever
(for {
f <- looper.fork
_ <- zio.test.environment.TestClock.adjust(5.seconds)
ref <- ZIO.service[Ref[Long]]
count <- ref.get
_ <- f.interrupt
} yield zio.test.assert(count)(equalTo(3L))).provideSomeLayer[TestEnvironment](logging ++ counter)
},
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment