From c4b2613bb2824adc5d21c707e53b1c78318bc4e9 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Tue, 9 Jun 2026 17:58:11 -0400 Subject: [PATCH 1/3] Canonical CI: grouped-tests.yml + root test/test_groups.toml Convert the root test workflow (Tests.yml, name: CI) to the canonical SciML/.github grouped-tests.yml@v1 thin caller, with the group x version matrix declared once in test/test_groups.toml at the repo root. - .github/workflows/Tests.yml: replace the hand-maintained group({CPU,QA}) x version({lts,1}) matrix job (which called the legacy per-job tests.yml@v1) with a thin caller to grouped-tests.yml@v1. on: and concurrency: preserved verbatim; filename + name: kept. - test/test_groups.toml (new, root): [Core] and [QA], each on [lts, 1]. Reproduces the old matrix with the functional CPU group renamed to the canonical Core (QA unchanged). Linux-only, no os axis. - test/qa/Project.toml (new): isolated QA env (Aqua, ExplicitImports, Documenter + the doctest/ExplicitImports support deps) with DeepEquilibriumNetworks via [sources] path = "../.." and julia = "1.10". - test/qa/qa.jl: the QA checks, moved verbatim from test/qa_tests.jl (no checks added, removed, or excluded). - test/runtests.jl: GROUP == "QA" now activates test/qa, develops the package, instantiates, then includes qa/qa.jl. Functional tests run under GROUP Core (CPU and ALL still accepted for back-compat). - test/shared_testsetup.jl: treat BACKEND_GROUP "core" as CPU so the renamed Core group selects the CPU device. Project.toml already satisfies the benign-metadata checks: [compat] julia = "1.10" (LTS floor) and every [extras] dep has a [compat] entry. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/Tests.yml | 15 +-------------- test/qa/Project.toml | 26 ++++++++++++++++++++++++++ test/{qa_tests.jl => qa/qa.jl} | 0 test/runtests.jl | 9 ++++++--- test/shared_testsetup.jl | 2 +- test/test_groups.toml | 5 +++++ 6 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 test/qa/Project.toml rename test/{qa_tests.jl => qa/qa.jl} (100%) create mode 100644 test/test_groups.toml diff --git a/.github/workflows/Tests.yml b/.github/workflows/Tests.yml index 2e073536..b3fb879c 100644 --- a/.github/workflows/Tests.yml +++ b/.github/workflows/Tests.yml @@ -17,18 +17,5 @@ concurrency: jobs: tests: - name: "Tests" - strategy: - fail-fast: false - matrix: - group: - - CPU - - QA - version: - - 'lts' - - '1' - uses: "SciML/.github/.github/workflows/tests.yml@v1" - with: - julia-version: "${{ matrix.version }}" - group: "${{ matrix.group }}" + uses: "SciML/.github/.github/workflows/grouped-tests.yml@v1" secrets: "inherit" diff --git a/test/qa/Project.toml b/test/qa/Project.toml new file mode 100644 index 00000000..4e24b53e --- /dev/null +++ b/test/qa/Project.toml @@ -0,0 +1,26 @@ +[deps] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +DeepEquilibriumNetworks = "6748aba7-0e9b-415e-a410-ae3cc0ecb334" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" +Lux = "b2108857-7c20-44ae-9111-449ecde12c47" +NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[sources] +DeepEquilibriumNetworks = {path = "../.."} + +[compat] +Aqua = "0.8" +Documenter = "1" +ExplicitImports = "1" +Lux = "1" +NonlinearSolve = "4" +OrdinaryDiffEq = "6.74, 7" +Random = "1.10" +SciMLSensitivity = "7.43" +Test = "1.10" +julia = "1.10" diff --git a/test/qa_tests.jl b/test/qa/qa.jl similarity index 100% rename from test/qa_tests.jl rename to test/qa/qa.jl diff --git a/test/runtests.jl b/test/runtests.jl index 15d788cf..c04d6176 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,17 +1,20 @@ using Pkg using SafeTestsets, Test -const GROUP = uppercase(get(ENV, "GROUP", "CPU")) +const GROUP = uppercase(get(ENV, "GROUP", "CORE")) @info "Running tests for GROUP: $GROUP" @time begin - if GROUP == "CPU" || GROUP == "ALL" + if GROUP == "CORE" || GROUP == "CPU" || GROUP == "ALL" @time @safetestset "Utils Tests" include("utils_tests.jl") @time @safetestset "Layers Tests" include("layers_tests.jl") end if GROUP == "QA" - @time @safetestset "Quality Assurance Tests" include("qa_tests.jl") + Pkg.activate(joinpath(@__DIR__, "qa")) + Pkg.develop(PackageSpec(path = dirname(@__DIR__))) + Pkg.instantiate() + @time @safetestset "Quality Assurance Tests" include(joinpath("qa", "qa.jl")) end end diff --git a/test/shared_testsetup.jl b/test/shared_testsetup.jl index 01c900b8..d83f4a9a 100644 --- a/test/shared_testsetup.jl +++ b/test/shared_testsetup.jl @@ -14,7 +14,7 @@ end GPUArraysCore.allowscalar(false) -cpu_testing() = BACKEND_GROUP == "all" || BACKEND_GROUP == "cpu" +cpu_testing() = BACKEND_GROUP == "all" || BACKEND_GROUP == "cpu" || BACKEND_GROUP == "core" function cuda_testing() return (BACKEND_GROUP == "all" || BACKEND_GROUP == "cuda") && MLDataDevices.functional(CUDADevice) diff --git a/test/test_groups.toml b/test/test_groups.toml new file mode 100644 index 00000000..464058a7 --- /dev/null +++ b/test/test_groups.toml @@ -0,0 +1,5 @@ +[Core] +versions = ["lts", "1"] + +[QA] +versions = ["lts", "1"] From 8575f2d90a59225c44daa0d94823561ad3b9a577 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Wed, 10 Jun 2026 06:19:09 -0400 Subject: [PATCH 2/3] Fold GPU.yml CUDA tests into the [GPU] test group The bespoke .github/workflows/GPU.yml ran the functional suite on the self-hosted CUDA runner with BACKEND_GROUP=CUDA. That is now a [GPU] group in test/test_groups.toml (versions ["1"], runner [self-hosted, Linux, X64, gpu], timeout 240) executed by the grouped-tests.yml@v1 caller, with runtests.jl setting BACKEND_GROUP=CUDA for GROUP=GPU. The workflow's gpu-docs job was a duplicate of the centralized documentation.yml already on main, so GPU.yml is deleted outright. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/GPU.yml | 65 --------------------------------------- test/runtests.jl | 6 +++- test/test_groups.toml | 5 +++ 3 files changed, 10 insertions(+), 66 deletions(-) delete mode 100644 .github/workflows/GPU.yml diff --git a/.github/workflows/GPU.yml b/.github/workflows/GPU.yml deleted file mode 100644 index d1655435..00000000 --- a/.github/workflows/GPU.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: "GPU Tests" - -on: - pull_request: - branches: - - main - paths-ignore: - - 'docs/**' - push: - branches: - - main - paths-ignore: - - 'docs/**' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.ref_name != github.event.repository.default_branch || github.ref != 'refs/tags/v*' }} - -jobs: - cuda-tests: - name: "CUDA GPU Tests" - runs-on: [self-hosted, Linux, X64, gpu] - timeout-minutes: 240 - steps: - - uses: actions/checkout@v6 - - uses: julia-actions/setup-julia@v3 - with: - version: "1" - - uses: julia-actions/julia-buildpkg@v1 - - uses: julia-actions/julia-runtest@v1 - env: - BACKEND_GROUP: "CUDA" - - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v7 - with: - files: lcov.info - token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: false - - gpu-docs: - name: "Documentation" - runs-on: [self-hosted, Linux, X64, gpu] - timeout-minutes: 240 - if: github.event_name == 'push' || !github.event.pull_request.draft - steps: - - uses: actions/checkout@v6 - - uses: julia-actions/setup-julia@v3 - with: - version: "1" - - run: | - julia --project --color=yes --threads=3 -e ' - println("--- Instantiating project") - using Pkg - Pkg.instantiate() - Pkg.activate("docs") - Pkg.develop(PackageSpec(path=pwd())) - Pkg.instantiate() - println("+++ Building documentation") - include("docs/make.jl")' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} - DATADEPS_ALWAYS_ACCEPT: true - JULIA_DEBUG: "Documenter" - GKSwstype: "100" diff --git a/test/runtests.jl b/test/runtests.jl index c04d6176..14011770 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,8 +5,12 @@ const GROUP = uppercase(get(ENV, "GROUP", "CORE")) @info "Running tests for GROUP: $GROUP" +# GPU is the self-hosted CUDA runner cell of test/test_groups.toml: the same +# functional suite, with shared_testsetup.jl's backend switched to CUDA. +GROUP == "GPU" && (ENV["BACKEND_GROUP"] = "CUDA") + @time begin - if GROUP == "CORE" || GROUP == "CPU" || GROUP == "ALL" + if GROUP == "CORE" || GROUP == "CPU" || GROUP == "ALL" || GROUP == "GPU" @time @safetestset "Utils Tests" include("utils_tests.jl") @time @safetestset "Layers Tests" include("layers_tests.jl") end diff --git a/test/test_groups.toml b/test/test_groups.toml index 464058a7..2f61e5bc 100644 --- a/test/test_groups.toml +++ b/test/test_groups.toml @@ -3,3 +3,8 @@ versions = ["lts", "1"] [QA] versions = ["lts", "1"] + +[GPU] +versions = ["1"] +runner = ["self-hosted", "Linux", "X64", "gpu"] +timeout = 240 From 67febc3ef65305d63946335fb1ac2bfe3552cbda Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sun, 14 Jun 2026 19:55:36 -0400 Subject: [PATCH 3/3] Adopt SciMLTesting v1.2 folder-based run_tests (on top of grouped-tests conversion) DEQ's GROUP semantics are backend/capability-based, not folder-partitioned: the GPU group runs the *same* Core test files (utils_tests.jl + layers_tests.jl) with shared_testsetup.jl's backend switched to CUDA via BACKEND_GROUP, so it cannot be expressed as a separate folder of files. Use explicit-args run_tests (v1.2): core = the two top-level Core files (each in its own @safetestset), GPU group = same body with BACKEND_GROUP=CUDA, QA = test/qa sub-env. Curated all=["Core"] so the self-hosted GPU lane and QA stay out of the aggregate. Drop Pkg from the test deps (only the old harness used it; SciMLTesting handles activate/develop now) and add SciMLTesting + SafeTestsets to the QA sub-env. test_groups.toml unchanged. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- Project.toml | 6 +++--- test/qa/Project.toml | 3 +++ test/runtests.jl | 47 +++++++++++++++++++++++--------------------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Project.toml b/Project.toml index 844fb0c1..f8031e5b 100644 --- a/Project.toml +++ b/Project.toml @@ -46,11 +46,11 @@ NonlinearSolve = "4" NonlinearSolveBase = "1.5, 2" OrdinaryDiffEq = "6.74, 7" OrdinaryDiffEqAdamsBashforthMoulton = "1, 2" -Pkg = "1.10" PrecompileTools = "1.2.1" Random = "1.10" SciMLBase = "2, 3.3" SciMLSensitivity = "7.43" +SciMLTesting = "1" StableRNGs = "1" Static = "1" SteadyStateDiffEq = "2.5.0" @@ -73,11 +73,11 @@ NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" OrdinaryDiffEqAdamsBashforthMoulton = "89bda076-bce5-4f1c-845f-551c83cdda9a" -Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1" +SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283" StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [targets] -test = ["Aqua", "Documenter", "ExplicitImports", "ForwardDiff", "Functors", "GPUArraysCore", "InteractiveUtils", "LuxTestUtils", "MLDataDevices", "NLsolve", "NonlinearSolve", "OrdinaryDiffEq", "OrdinaryDiffEqAdamsBashforthMoulton", "Pkg", "SafeTestsets", "SciMLSensitivity", "StableRNGs", "Test", "Zygote"] +test = ["Aqua", "Documenter", "ExplicitImports", "ForwardDiff", "Functors", "GPUArraysCore", "InteractiveUtils", "LuxTestUtils", "MLDataDevices", "NLsolve", "NonlinearSolve", "OrdinaryDiffEq", "OrdinaryDiffEqAdamsBashforthMoulton", "SafeTestsets", "SciMLSensitivity", "SciMLTesting", "StableRNGs", "Test", "Zygote"] diff --git a/test/qa/Project.toml b/test/qa/Project.toml index 4e24b53e..123b618f 100644 --- a/test/qa/Project.toml +++ b/test/qa/Project.toml @@ -7,7 +7,9 @@ Lux = "b2108857-7c20-44ae-9111-449ecde12c47" NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1" +SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [sources] @@ -22,5 +24,6 @@ NonlinearSolve = "4" OrdinaryDiffEq = "6.74, 7" Random = "1.10" SciMLSensitivity = "7.43" +SciMLTesting = "1" Test = "1.10" julia = "1.10" diff --git a/test/runtests.jl b/test/runtests.jl index 14011770..e35b82b2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,24 +1,27 @@ -using Pkg -using SafeTestsets, Test +using SciMLTesting +using SafeTestsets -const GROUP = uppercase(get(ENV, "GROUP", "CORE")) - -@info "Running tests for GROUP: $GROUP" - -# GPU is the self-hosted CUDA runner cell of test/test_groups.toml: the same -# functional suite, with shared_testsetup.jl's backend switched to CUDA. -GROUP == "GPU" && (ENV["BACKEND_GROUP"] = "CUDA") - -@time begin - if GROUP == "CORE" || GROUP == "CPU" || GROUP == "ALL" || GROUP == "GPU" - @time @safetestset "Utils Tests" include("utils_tests.jl") - @time @safetestset "Layers Tests" include("layers_tests.jl") - end - - if GROUP == "QA" - Pkg.activate(joinpath(@__DIR__, "qa")) - Pkg.develop(PackageSpec(path = dirname(@__DIR__))) - Pkg.instantiate() - @time @safetestset "Quality Assurance Tests" include(joinpath("qa", "qa.jl")) - end +# DEQ's GROUP semantics are backend/capability-based, not folder-partitioned: the +# GPU group runs the *same* Core test files (utils_tests.jl + layers_tests.jl) +# with shared_testsetup.jl's backend switched to CUDA via BACKEND_GROUP, so it +# cannot be expressed as a separate folder of files. Hence explicit-args run_tests. +function core_body() + @safetestset "Utils Tests" include("utils_tests.jl") + @safetestset "Layers Tests" include("layers_tests.jl") end + +run_tests(; + core = core_body, + groups = Dict( + # GPU is the self-hosted CUDA runner lane: the same Core suite with the + # backend switched to CUDA. + "GPU" => () -> begin + ENV["BACKEND_GROUP"] = "CUDA" + core_body() + end, + ), + qa = (; env = joinpath(@__DIR__, "qa"), body = joinpath(@__DIR__, "qa", "qa.jl")), + # Curated "All": run only Core. GPU (self-hosted CUDA lane) and QA stay + # selectable by name but out of the aggregate. + all = ["Core"], +)