From b42b9249b52cf820dfe97b2efe132c117708cebb Mon Sep 17 00:00:00 2001 From: filoferra <66474175+filoferra@users.noreply.github.com> Date: Mon, 28 Sep 2026 18:33:55 +0200 Subject: [PATCH] Tests: no PETSc traceback from the callbacks that fail on purpose without_petsc_traceback pushes PETSc's return-only error handler around the four solves in pc.jl and snes.jl that check how a failing callback surfaces. The CI log printed a traceback for each of them, once per scalar type. --- test/runtests.jl | 3 ++- test/solvers/pc.jl | 8 ++++++-- test/solvers/snes.jl | 6 ++++-- test/testutils.jl | 17 ++++++++++++++++- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index b11e9b29d..2f5ecd1fb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -18,6 +18,8 @@ else @info "Testing PETSc.jl with" MPIPreferences.binary MPIPreferences.abi PETSc_jll.host_platform end +include("testutils.jl") # helpers the test files share; each includes it when run alone + # The test groups, one folder each, in the order they run. `Pkg.test(test_args = ["dm"])` # runs only the named groups; without arguments every group runs. const GROUPS = ("core", "vecmat", "solvers", "dm", "lowlevel", "regression", "examples", "mpi") @@ -117,7 +119,6 @@ if selected("examples") include("examples/manual_ts.jl") # the TS examples in the manual include("examples/manual_viewer.jl") # the PetscViewer examples in the manual - include("testutils.jl") include("examples/examples.jl") # every script in examples/ include("examples/mpi_examples.jl") # the examples marked `# INCLUDE IN MPI TEST` end diff --git a/test/solvers/pc.jl b/test/solvers/pc.jl index 0198ffa5e..fa0433d9b 100644 --- a/test/solvers/pc.jl +++ b/test/solvers/pc.jl @@ -4,6 +4,8 @@ using MPI using SparseArrays using LinearAlgebra MPI.Initialized() || MPI.Init() +isdefined(Main, :PETScTestUtils) || include(joinpath(@__DIR__, "..", "testutils.jl")) +using .PETScTestUtils: without_petsc_traceback @testset "PC" begin comm = MPI.COMM_SELF @@ -112,12 +114,14 @@ MPI.Initialized() || MPI.Init() PETSc.set_shell_apply!(PETSc.pc(ksp)) do y, p, x throw(DomainError(-1.0, "shell apply! failed on purpose")) end - @test_throws DomainError ksp \ b + @test_throws DomainError without_petsc_traceback(() -> ksp \ b, petsclib) # started through LibPETSc there is no high-level call to rethrow it petsc_b = LibPETSc.VecCreateSeqWithArray(petsclib, comm, 1, n, b) petsc_x = similar(petsc_b) @test_logs (:error, r"shell apply!") match_mode = :any begin - @test_throws LibPETSc.PetscError LibPETSc.KSPSolve(petsclib, ksp, petsc_b, petsc_x) + @test_throws LibPETSc.PetscError without_petsc_traceback(petsclib) do + LibPETSc.KSPSolve(petsclib, ksp, petsc_b, petsc_x) + end end PETSc.destroy!(petsc_b) PETSc.destroy!(petsc_x) diff --git a/test/solvers/snes.jl b/test/solvers/snes.jl index 223856f38..4f2ff0634 100644 --- a/test/solvers/snes.jl +++ b/test/solvers/snes.jl @@ -2,6 +2,8 @@ using Test using PETSc using MPI MPI.Initialized() || MPI.Init() +isdefined(Main, :PETScTestUtils) || include(joinpath(@__DIR__, "..", "testutils.jl")) +using .PETScTestUtils: without_petsc_traceback @testset "SNES" begin comm = MPI.COMM_WORLD @@ -323,14 +325,14 @@ MPI.Initialized() || MPI.Init() throw(DomainError(-1.0, "residual failed on purpose")) end x7 = LibPETSc.VecCreateSeqWithArray(petsclib, comm, PetscInt(1), PetscInt(2), PetscScalar.([2, 3])) - @test_throws DomainError PETSc.solve!(x7, snes7) + @test_throws DomainError without_petsc_traceback(() -> PETSc.solve!(x7, snes7), petsclib) # a nonzero Integer return still fails the call, and warns PETSc.set_function!(snes7, r7) do fx, snes, x return 3 end @test_logs (:warn, r"returned 3") match_mode = :any begin - @test_throws LibPETSc.PetscError PETSc.solve!(x7, snes7) + @test_throws LibPETSc.PetscError without_petsc_traceback(() -> PETSc.solve!(x7, snes7), petsclib) end # user_ctx is kept with the PETSc object, and snes.user_ctx forwards to its diff --git a/test/testutils.jl b/test/testutils.jl index 0e71ae778..70a22c61e 100644 --- a/test/testutils.jl +++ b/test/testutils.jl @@ -1,6 +1,9 @@ module PETScTestUtils -export find_sources +using Libdl +using PETSc: LibPETSc + +export find_sources, without_petsc_traceback function find_sources(path::String, sources = String[]) if isdir(path) @@ -13,4 +16,16 @@ function find_sources(path::String, sources = String[]) return sources end +# Runs `f()` with PETSc's return-only error handler, so an error raised on purpose +# fails the call as usual without printing PETSc's traceback to stderr +function without_petsc_traceback(f, petsclib) + handler = Libdl.dlsym(Libdl.dlopen(petsclib.petsc_library), :PetscReturnErrorHandler) + LibPETSc.PetscPushErrorHandler(petsclib, handler, C_NULL) + try + return f() + finally + LibPETSc.PetscPopErrorHandler(petsclib) + end +end + end # module PETScTestUtils