diff --git a/.github/workflows/nightly-artifacts.yml b/.github/workflows/nightly-artifacts.yml index b8890e0a..a22b4773 100644 --- a/.github/workflows/nightly-artifacts.yml +++ b/.github/workflows/nightly-artifacts.yml @@ -32,6 +32,9 @@ jobs: test: name: Test (Java 21, headless) runs-on: ubuntu-latest + # A healthy run takes about four minutes. The per-test limit in build.gradle.kts names + # a hanging test; this cap covers a hang outside any test, such as in Gradle itself. + timeout-minutes: 20 steps: - name: Checkout diff --git a/.github/workflows/pr-compile-check.yml b/.github/workflows/pr-compile-check.yml index 5b62bdaf..e0e1239b 100644 --- a/.github/workflows/pr-compile-check.yml +++ b/.github/workflows/pr-compile-check.yml @@ -155,6 +155,9 @@ jobs: test: name: Test (Java 21, headless) runs-on: ubuntu-latest + # A healthy run takes about four minutes. The per-test limit in build.gradle.kts names + # a hanging test; this cap covers a hang outside any test, such as in Gradle itself. + timeout-minutes: 20 steps: - name: Checkout diff --git a/.github/workflows/tagged-release.yml b/.github/workflows/tagged-release.yml index 09b73a6a..1818a350 100644 --- a/.github/workflows/tagged-release.yml +++ b/.github/workflows/tagged-release.yml @@ -24,6 +24,9 @@ jobs: test: name: Test (Java 21, headless) runs-on: ubuntu-latest + # A healthy run takes about four minutes. The per-test limit in build.gradle.kts names + # a hanging test; this cap covers a hang outside any test, such as in Gradle itself. + timeout-minutes: 20 steps: - name: Checkout diff --git a/build.gradle.kts b/build.gradle.kts index 636abeb8..bf9eba28 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -141,6 +141,16 @@ subprojects { } testUserHome.mkdirs() } + /* + * A test that never returns must fail by name instead of holding the job until + * GitHub kills it after six hours: Nightly #302 hung in :app-desktop:test for over + * an hour, and the log named only the task. The limit is far above the slowest test + * (under four seconds). SEPARATE_THREAD also ends a test whose thread ignores + * interruption, such as a busy loop or a blocked native call, and the failure's + * cause carries that thread's stack, so it shows where the test stood. + */ + systemProperty("junit.jupiter.execution.timeout.default", "2m") + systemProperty("junit.jupiter.execution.timeout.thread.mode.default", "SEPARATE_THREAD") finalizedBy(checkTestUserHome) }