[2.x] feat: Forward test events to listeners as they are emitted (#9087)

Test report listeners now receive testEvent callbacks as the underlying test framework emits events, instead of only after a whole group finishes. startGroup / endGroup timing is aligned with that streaming model for both in-process and forked test runs.

No public API changes - only listener callback timing and the internal worker <-> sbt JSON-RPC protocol.
This commit is contained in:
Clayton
2026-04-16 00:58:06 -04:00
committed by GitHub
parent 9d620f3b1f
commit ef90ca0540
8 changed files with 313 additions and 34 deletions
@@ -135,7 +135,12 @@ private[sbt] final class TestRunner(
// Thread-safe collection so AsyncFunSuite (and other async frameworks) can call
// handle() from multiple threads without corrupting results (fixes #5245).
val results = new CopyOnWriteArrayList[Event]
val handler = new EventHandler { def handle(e: Event): Unit = { results.add(e) } }
val handler = new EventHandler {
def handle(e: Event): Unit = {
results.add(e)
safeListenersCall(_.testEvent(TestEvent(Seq(e))))
}
}
val loggers: Vector[ContentLogger] = listeners.flatMap(_.contentLogger(testDefinition))
def errorEvents(e: Throwable): Array[sbt.testing.Task] = {
val taskDef = testTask.taskDef
@@ -148,6 +153,7 @@ private[sbt] final class TestRunner(
val duration = -1L
}
results.add(event)
safeListenersCall(_.testEvent(TestEvent(Seq(event))))
Array.empty
}
val nestedTasks =
@@ -160,8 +166,6 @@ private[sbt] final class TestRunner(
loggers.foreach(_.flush())
}
val resultsList = results.asScala.toList
val event = TestEvent(resultsList)
safeListenersCall(_.testEvent(event))
(SuiteResult(resultsList), nestedTasks.toSeq)
}