Skip to content

Commit 4dc1bb5

Browse files
committed
Make AsyncReadyLayerSpec deterministic via TestClock
1 parent 767dd3e commit 4dc1bb5

1 file changed

Lines changed: 16 additions & 4 deletions

File tree

testkit/src/test/scala/zio/openfeature/testkit/AsyncReadyLayerSpec.scala

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,36 @@ object AsyncReadyLayerSpec extends ZIOSpecDefault {
1212
): ZLayer[Any, Throwable, TestFeatureProvider with FeatureFlags] =
1313
Scope.default >>> TestFeatureProvider.asyncReadyLayer(flags, delay)
1414

15+
// Bound the polling loop so a real bug surfaces as a test failure instead of a hang.
16+
private val waitForReady: ZIO[FeatureFlags, Nothing, ProviderStatus] =
17+
FeatureFlags.providerStatus
18+
.repeatUntil(_ == ProviderStatus.Ready)
19+
.timeoutTo(ProviderStatus.NotReady)(identity)(5.seconds)
20+
.withClock(Clock.ClockLive)
21+
1522
def spec = suite("asyncReadyLayer")(
23+
// Under TestClock the forked transition fiber inside asyncReadyLayer suspends on its `ZIO.sleep`
24+
// until we explicitly adjust the clock. This eliminates the wall-clock race that made the
25+
// previous `withLiveClock` version flaky on slow CI runners.
1626
test("starts in NotReady then auto-transitions to Ready") {
1727
for {
1828
before <- FeatureFlags.providerStatus
19-
_ <- ZIO.sleep(500.millis)
20-
after <- FeatureFlags.providerStatus
29+
_ <- TestClock.adjust(60.millis)
30+
after <- waitForReady
2131
} yield assertTrue(before == ProviderStatus.NotReady) && assertTrue(after == ProviderStatus.Ready)
2232
}.provide(readyLayer(Map.empty, 50.millis)),
2333
test("evaluations work after auto-transition") {
2434
for {
25-
_ <- ZIO.sleep(500.millis)
35+
_ <- TestClock.adjust(60.millis)
36+
_ <- waitForReady
2637
value <- FeatureFlags.boolean("flag", default = false)
2738
} yield assertTrue(value == true)
2839
}.provide(readyLayer(Map("flag" -> true), 50.millis)),
2940
test("evaluations fail before init delay elapses") {
41+
// No clock adjustment: the forked transition fiber stays suspended, status remains NotReady.
3042
for {
3143
result <- FeatureFlags.boolean("flag", default = false).either
3244
} yield assertTrue(result.isLeft)
3345
}.provide(readyLayer(Map("flag" -> true), 10.seconds))
34-
) @@ TestAspect.withLiveClock
46+
)
3547
}

0 commit comments

Comments
 (0)