From 667e19d2e755e25831b98cd9dadaa032e19bb932 Mon Sep 17 00:00:00 2001 From: Chris Rackauckas - Beep Boop Edition Date: Wed, 10 Jun 2026 09:44:10 +0000 Subject: [PATCH] Canonical CI: grouped-tests.yml + root test/test_groups.toml (#79) * Canonical CI: grouped-tests.yml + root test/test_groups.toml Convert the root test workflow (Tests.yml) to the canonical grouped-tests.yml@v1 thin caller, with the group x version matrix declared once in test/test_groups.toml. - Tests.yml: replace the hand-maintained version matrix job with a thin `uses: SciML/.github/.github/workflows/grouped-tests.yml@v1` caller (secrets: inherit, default GROUP env). on:/concurrency: preserved. - test/test_groups.toml: [Core] and [QA] each on ["lts", "1"]. Core reproduces the old (version in {1, lts}) full-suite matrix. - runtests.jl: GROUP dispatch. Core runs the functional suite (interface_tests.jl, the type-stability checks, the MATLAB-solve block); QA activates test/qa, develops the package, instantiates, and includes qa/qa.jl. - test/qa: isolated environment (Aqua + JET + Test + MATLABDiffEq via [sources]) and qa.jl running Aqua.test_all + JET.report_package. This keeps the QA tooling out of the main test target's resolve. - jet_tests.jl: keep the functional type-stability tests; the package's JET static analysis now lives in the QA group. - Project.toml: raise julia compat floor 1.6 -> 1.10 (LTS); add [compat] for the test extras (ParameterizedFunctions, Test); move JET out of the main [extras]/[targets] into the isolated test/qa environment. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) * Add Pkg as test dependency for grouped-tests Core group The grouped test/runtests.jl uses `using Pkg` (for the QA group's Pkg.activate), but Pkg was not a declared test dependency. The Core group runs with project='.', so it died with: ArgumentError: Package Pkg not found in current path Declare Pkg in the root test environment so the Core job loads it. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) * Hoist Core-group usings to top level to fix macro-expansion bug The Core-group `using DiffEqBase, MATLABDiffEq, ParameterizedFunctions` sat inside the top-level `if GROUP` block that also uses `@ode_def_bare` inline. Julia macro-expands the entire `if` block as one unit before the in-block `using` runs, so the macro is undefined at expansion time (UndefVarError: @ode_def_bare not defined in Main). Hoisting the usings to top level fixes it. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --------- Co-authored-by: ChrisRackauckas-Claude Co-authored-by: Claude Opus 4.8 (1M context) --- .github/workflows/Tests.yml | 11 +--- Project.toml | 9 ++-- test/jet_tests.jl | 34 ++---------- test/qa/Project.toml | 14 +++++ test/qa/qa.jl | 11 ++++ test/runtests.jl | 104 +++++++++++++++++++++--------------- test/test_groups.toml | 13 +++++ 7 files changed, 111 insertions(+), 85 deletions(-) create mode 100644 test/qa/Project.toml create mode 100644 test/qa/qa.jl create mode 100644 test/test_groups.toml diff --git a/.github/workflows/Tests.yml b/.github/workflows/Tests.yml index 2d5e396..083c77c 100644 --- a/.github/workflows/Tests.yml +++ b/.github/workflows/Tests.yml @@ -18,14 +18,5 @@ concurrency: jobs: tests: - name: "Tests" - strategy: - fail-fast: false - matrix: - version: - - "1" - - "lts" - uses: "SciML/.github/.github/workflows/tests.yml@v1" - with: - julia-version: "${{ matrix.version }}" + uses: "SciML/.github/.github/workflows/grouped-tests.yml@v1" secrets: "inherit" diff --git a/Project.toml b/Project.toml index e498ac9..384df60 100644 --- a/Project.toml +++ b/Project.toml @@ -11,17 +11,18 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69" [compat] DiffEqBase = "6.122, 7" -JET = "0.9, 0.10, 0.11" MATLAB = "0.8, 0.9, 0.10" ModelingToolkit = "8, 9, 10, 11" +ParameterizedFunctions = "5" PrecompileTools = "1" Reexport = "0.2, 1.0" -julia = "1.6" +Test = "<0.0.1, 1" +julia = "1.10" [extras] -JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" ParameterizedFunctions = "65888b18-ceab-5e60-b2b9-181511a3b968" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test", "ParameterizedFunctions", "JET"] +test = ["Test", "ParameterizedFunctions", "Pkg"] diff --git a/test/jet_tests.jl b/test/jet_tests.jl index 11d9645..7319fd9 100644 --- a/test/jet_tests.jl +++ b/test/jet_tests.jl @@ -1,18 +1,12 @@ -# JET.jl static analysis tests for MATLABDiffEq -# These tests verify type stability and catch potential runtime errors -# They can run without MATLAB installed since they only test Julia code +# Static type-stability tests for MATLABDiffEq +# These tests verify type stability and catch potential runtime errors. +# They run without MATLAB installed since they only test Julia code. +# JET/Aqua static analysis of the package itself lives in the QA group +# (test/qa/qa.jl); this file holds the functional type-stability checks. using Test using DiffEqBase -# JET is an optional test dependency -const HAS_JET = try - @eval using JET - true -catch - false -end - # Import buildDEStats for testing - we need to access it from the module # Since MATLABDiffEq requires MATLAB, we'll test the function pattern directly @@ -65,14 +59,6 @@ end result_partial = buildDEStats_test(partial_stats) @test result_partial.nf == 42 @test result_partial.nreject == 0 - - # JET analysis - verify no obvious errors in the function - if HAS_JET - rep = JET.report_call(buildDEStats_test, (Dict{String, Any},)) - # We expect some reports due to Dict{String, Any} type uncertainty - # but the function should still be valid - @test true # Function analyzed successfully - end end @testset "Algorithm struct definitions" begin @@ -126,16 +112,6 @@ end @test _is_matlab_compatible_eltype_test(BigFloat) === false @test _is_matlab_compatible_eltype_test(BigInt) === false @test _is_matlab_compatible_eltype_test(Float32) === false - - # JET @test_opt analysis for type stability - if HAS_JET - @testset "JET @test_opt type stability" begin - # Test type stability of _is_matlab_compatible_eltype - @test_opt _is_matlab_compatible_eltype_test(Float64) - @test_opt _is_matlab_compatible_eltype_test(Int64) - @test_opt _is_matlab_compatible_eltype_test(BigFloat) - end - end end @testset "Return type inference" begin diff --git a/test/qa/Project.toml b/test/qa/Project.toml new file mode 100644 index 0000000..798ad79 --- /dev/null +++ b/test/qa/Project.toml @@ -0,0 +1,14 @@ +[deps] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +MATLABDiffEq = "e2752cbe-bcf4-5895-8727-84ebc14a76bd" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[sources] +MATLABDiffEq = {path = "../.."} + +[compat] +Aqua = "0.8" +JET = "0.9, 0.10, 0.11" +Test = "<0.0.1, 1" +julia = "1.10" diff --git a/test/qa/qa.jl b/test/qa/qa.jl new file mode 100644 index 0000000..9a37f3a --- /dev/null +++ b/test/qa/qa.jl @@ -0,0 +1,11 @@ +using MATLABDiffEq, Aqua, JET +using Test + +@testset "Aqua" begin + Aqua.test_all(MATLABDiffEq) +end + +@testset "JET static analysis" begin + rep = JET.report_package(MATLABDiffEq; target_modules = (MATLABDiffEq,)) + @test length(JET.get_reports(rep)) == 0 +end diff --git a/test/runtests.jl b/test/runtests.jl index 53cd636..21ff27b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,44 +1,64 @@ -using DiffEqBase, MATLABDiffEq, ParameterizedFunctions, Test - -# Interface tests - these test type validation without needing MATLAB runtime -include("interface_tests.jl") - -# JET static analysis tests - these also run without MATLAB -include("jet_tests.jl") - -# The following tests require MATLAB runtime to be available -# They test the actual ODE solving functionality - -f = @ode_def_bare LotkaVolterra begin - dx = a * x - b * x * y - dy = -c * y + d * x * y -end a b c d -p = [1.5, 1, 3, 1] -tspan = (0.0, 10.0) -u0 = [1.0, 1.0] -prob = ODEProblem(f, u0, tspan, p) -sol = solve(prob, MATLABDiffEq.ode45()) - -function lorenz(du, u, p, t) - du[1] = 10.0(u[2] - u[1]) - du[2] = u[1] * (28.0 - u[3]) - u[2] - return du[3] = u[1] * u[2] - (8 / 3) * u[3] +using Pkg +using Test +using DiffEqBase, MATLABDiffEq, ParameterizedFunctions + +const GROUP = get(ENV, "GROUP", "Core") + +# QA (Aqua + JET) runs in an isolated environment (test/qa) so its tooling deps +# never enter the main test target's resolve. On Julia < 1.11 the [sources] table +# is ignored, so develop the package by path to test the PR branch code. +function activate_qa_env() + Pkg.activate(joinpath(@__DIR__, "qa")) + Pkg.develop(PackageSpec(path = dirname(@__DIR__))) + return Pkg.instantiate() end -u0 = [1.0; 0.0; 0.0] -tspan = (0.0, 100.0) -prob = ODEProblem(lorenz, u0, tspan) -sol = solve(prob, MATLABDiffEq.ode45()) - -algs = [ - MATLABDiffEq.ode23 - MATLABDiffEq.ode45 - MATLABDiffEq.ode113 - MATLABDiffEq.ode23s - MATLABDiffEq.ode23t - MATLABDiffEq.ode23tb - MATLABDiffEq.ode15s -] - -for alg in algs - sol = solve(prob, alg()) + +if GROUP == "Core" || GROUP == "All" + # Interface tests - these test type validation without needing MATLAB runtime + include("interface_tests.jl") + + # Static type-stability tests - these also run without MATLAB + include("jet_tests.jl") + + # The following tests require MATLAB runtime to be available + # They test the actual ODE solving functionality + + f = @ode_def_bare LotkaVolterra begin + dx = a * x - b * x * y + dy = -c * y + d * x * y + end a b c d + p = [1.5, 1, 3, 1] + tspan = (0.0, 10.0) + u0 = [1.0, 1.0] + prob = ODEProblem(f, u0, tspan, p) + sol = solve(prob, MATLABDiffEq.ode45()) + + function lorenz(du, u, p, t) + du[1] = 10.0(u[2] - u[1]) + du[2] = u[1] * (28.0 - u[3]) - u[2] + return du[3] = u[1] * u[2] - (8 / 3) * u[3] + end + u0 = [1.0; 0.0; 0.0] + tspan = (0.0, 100.0) + prob = ODEProblem(lorenz, u0, tspan) + sol = solve(prob, MATLABDiffEq.ode45()) + + algs = [ + MATLABDiffEq.ode23 + MATLABDiffEq.ode45 + MATLABDiffEq.ode113 + MATLABDiffEq.ode23s + MATLABDiffEq.ode23t + MATLABDiffEq.ode23tb + MATLABDiffEq.ode15s + ] + + for alg in algs + sol = solve(prob, alg()) + end +end + +if GROUP == "QA" + activate_qa_env() + include("qa/qa.jl") end diff --git a/test/test_groups.toml b/test/test_groups.toml new file mode 100644 index 0000000..9565dea --- /dev/null +++ b/test/test_groups.toml @@ -0,0 +1,13 @@ +# Root MATLABDiffEq.jl test-group matrix, consumed by the reusable +# grouped-tests.yml@v1 caller (.github/workflows/Tests.yml) via +# scripts/compute_affected_sublibraries.jl --root-matrix. Each group runs on +# every Julia version it lists; runtests.jl dispatches on GROUP. +# +# Core reproduces the old Tests.yml matrix (the whole suite on "lts" and "1"). +# QA is newly split out: Aqua + JET run in the isolated test/qa environment. + +[Core] +versions = ["lts", "1"] + +[QA] +versions = ["lts", "1"]