Skip to content

Commit 32928b5

Browse files
authored
ZIO Test: Warn If Scope Cannot Be Closed (zio#8288)
* warn if scope cannot be closed * add test * fix race condition
1 parent b1221b3 commit 32928b5

File tree

2 files changed

+34
-11
lines changed

2 files changed

+34
-11
lines changed

test-tests/shared/src/test/scala/zio/test/SpecSpec.scala

+12-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ object SpecSpec extends ZIOBaseSpec {
1010
val specLayer: ZLayer[Any, Nothing, Unit] =
1111
ZLayer.succeed(())
1212

13+
val neverFinalizerLayer =
14+
ZLayer.scoped(ZIO.acquireRelease(ZIO.unit)(_ => ZIO.never))
15+
1316
def spec: Spec[TestEnvironment, TestFailure[Nothing]] = suite("SpecSpec")(
1417
suite("provideLayer")(
1518
test("does not have early initialization issues") {
@@ -207,6 +210,14 @@ object SpecSpec extends ZIOBaseSpec {
207210
assert(false)(isFalse)
208211
}
209212
)
210-
}
213+
},
214+
suite("suite does not wait for finalizer to complete")(
215+
test("some test") {
216+
assertCompletes
217+
},
218+
test("some other test") {
219+
assertCompletes
220+
}
221+
).provideLayerShared(neverFinalizerLayer)
211222
)
212223
}

test/shared/src/main/scala/zio/test/TestExecutor.scala

+22-10
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,29 @@ object TestExecutor {
6262
loop(label :: labels, spec, exec, ancestors, sectionId)
6363

6464
case Spec.ScopedCase(managed) =>
65-
ZIO
66-
.scoped(
67-
managed
68-
.flatMap(loop(labels, _, exec, ancestors, sectionId))
69-
)
70-
.catchAllCause { e =>
71-
val event =
72-
ExecutionEvent.RuntimeFailure(sectionId, labels, TestFailure.Runtime(e), ancestors)
65+
Scope.make.flatMap { scope =>
66+
scope
67+
.extend(managed.flatMap(loop(labels, _, exec, ancestors, sectionId)))
68+
.onExit { exit =>
69+
val warning =
70+
"Warning: ZIO Test is attempting to close the scope of suite " +
71+
s"${labels.reverse.mkString(" - ")} in $fullyQualifiedName, " +
72+
"but closing the scope has taken more than 60 seconds to " +
73+
"complete. This may indicate a resource leak."
74+
for {
75+
warning <-
76+
ZIO.logWarning(warning).delay(60.seconds).withClock(ClockLive).interruptible.forkDaemon
77+
finalizer <- scope.close(exit).ensuring(warning.interrupt).forkDaemon
78+
exit <- warning.await
79+
_ <- finalizer.join.when(exit.isInterrupted)
80+
} yield ()
81+
}
82+
}.catchAllCause { e =>
83+
val event =
84+
ExecutionEvent.RuntimeFailure(sectionId, labels, TestFailure.Runtime(e), ancestors)
7385

74-
processEvent(event)
75-
}
86+
processEvent(event)
87+
}
7688

7789
case Spec.MultipleCase(specs) =>
7890
ZIO.uninterruptibleMask(restore =>

0 commit comments

Comments
 (0)