Adds a new JVM-only integration test suite (ZIOAppIntegrationSpec) that verifies ZIOApp lifecycle behaviour by spawning real JVM sub-processes. This complements the existing in-process ZIOAppSpec (which uses invoke) by exercising the full main() path: JVM shutdown hooks, signal delivery, exit codes and gracefulShutdownTimeout.
| Suite | Tests | Signal? |
|---|---|---|
| app completion | exit code 0 (success), 1 (failure), 1 (defect), completes work | No |
| finalizers on normal completion | finalizers on success, finalizers on failure | No |
| external signal handling | SIGINT + finalizer, slow finalizer with Infinity timeout, LIFO order, bootstrap layer cleanup | Yes |
| gracefulShutdownTimeout | timeout cuts slow finalizer, well-behaved app doesn’t hang | Yes |
| background fiber cleanup | daemon fibers interrupted on shutdown | Yes |
Signal-based suites are gated behind a unixOnly aspect — Process.destroy() on Windows doesn’t trigger JVM shutdown hooks, so those tests are skipped there. CI runs on Linux so all 13 tests will execute.
gracefulShutdownTimeout is InfinityshuttingDown flag prevents shutdown-hook race (all signal tests exercise this path)NoClassDefFoundError (reflection-based signal handler works)Each test fixture is a small ZIOAppDefault / ZIOApp object in ZIOAppTestApps.scala. The parent test launches them with ProcessBuilder using the current test classpath, communicates through stdout markers (READY, FINALIZED, etc.), and sends kill -INT for signal tests.
sbt "coreTestsJVM/testOnly zio.ZIOAppIntegrationSpec"
core-tests/jvm/src/test/scala/zio/ZIOAppTestApps.scala — 10 fixture appscore-tests/jvm/src/test/scala/zio/ZIOAppIntegrationSpec.scala — test specRelates to #9901, #9807, #9240.
/claim #9909
legendary658
@legendary658
ZIO
@ZIO