zio-logging ведет себя иначе при тестировании запланированных задач, чем на prod в ZIO
Я застрял в тестировании повторяемой задачи. Все работает, когда выполняется вне теста, но терпит неудачу в тестах. Похоже, что в тесте zio-logging ведет себя как-то иначе (как будто это "блокировка"). Когда я заменяю ведение журнала на вызовы консоли, он работает так же, как и когда я выполняю вызов входа в систему.
Может ли кто-нибудь намекнуть, что я делаю не так или почему?
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)
},
)
}