Skip to content

Commit

Permalink
@testset: with Xoshiro, restore Random.GLOBAL_SEED (#43188)
Browse files Browse the repository at this point in the history
A `@testset` is supposed to restore the "global RNG state" as
it was before execution (so that they can be re-ordered easily, etc.)
Also, before a testset starts, the default RNG is re-seeded with the
"global seed" (to help reproduce test failures).

Before `Xoshiro` as the default RNG, the "global seed" was stored
within a `MersenneTwister` object. It was enough for a testset to
copy the default RNG at the start, and copy it back at the end.
But now the global seed is stored outside of the RNG, so it should
also be restored separately.

(cherry picked from commit 08ea2d8)
  • Loading branch information
rfourquet authored and KristofferC committed Nov 26, 2021
1 parent 72d6569 commit bf8d60b
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 1 deletion.
1 change: 1 addition & 0 deletions stdlib/Random/src/RNGs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ copy!(::_GLOBAL_RNG, src::Xoshiro) = copy!(default_rng(), src)
copy(::_GLOBAL_RNG) = copy(default_rng())

GLOBAL_SEED = 0
set_global_seed!(seed) = global GLOBAL_SEED = seed

function seed!(::_GLOBAL_RNG, seed=rand(RandomDevice(), UInt64, 4))
global GLOBAL_SEED = seed
Expand Down
4 changes: 4 additions & 0 deletions stdlib/Test/src/Test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,7 @@ function testset_beginend(args, tests, source)
# by wrapping the body in a function
local RNG = default_rng()
local oldrng = copy(RNG)
local oldseed = Random.GLOBAL_SEED
try
# RNG is re-seeded with its own seed to ease reproduce a failed test
Random.seed!(Random.GLOBAL_SEED)
Expand All @@ -1288,6 +1289,7 @@ function testset_beginend(args, tests, source)
record(ts, Error(:nontest_error, Expr(:tuple), err, Base.current_exceptions(), $(QuoteNode(source))))
finally
copy!(RNG, oldrng)
Random.set_global_seed!(oldseed)
pop_testset()
ret = finish(ts)
end
Expand Down Expand Up @@ -1368,6 +1370,7 @@ function testset_forloop(args, testloop, source)
local ts
local RNG = default_rng()
local oldrng = copy(RNG)
local oldseed = Random.GLOBAL_SEED
Random.seed!(Random.GLOBAL_SEED)
local tmprng = copy(RNG)
try
Expand All @@ -1381,6 +1384,7 @@ function testset_forloop(args, testloop, source)
push!(arr, finish(ts))
end
copy!(RNG, oldrng)
Random.set_global_seed!(oldseed)
end
arr
end
Expand Down
25 changes: 24 additions & 1 deletion stdlib/Test/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,29 @@ end
Random.seed!(seed)
@test a == rand()
@test b == rand()

# Even when seed!() is called within a testset A, subsequent testsets
# should start with the same "global RNG state" as what A started with,
# such that the test `refvalue == rand(Int)` below succeeds.
# Currently, this means that Random.GLOBAL_SEED has to be restored,
# in addition to the state of Random.default_rng().
GLOBAL_SEED_orig = Random.GLOBAL_SEED
local refvalue
@testset "GLOBAL_SEED is also preserved (setup)" begin
@test GLOBAL_SEED_orig == Random.GLOBAL_SEED
refvalue = rand(Int)
Random.seed!()
@test GLOBAL_SEED_orig != Random.GLOBAL_SEED
end
@test GLOBAL_SEED_orig == Random.GLOBAL_SEED
@testset "GLOBAL_SEED is also preserved (forloop)" for _=1:3
@test refvalue == rand(Int)
Random.seed!()
end
@test GLOBAL_SEED_orig == Random.GLOBAL_SEED
@testset "GLOBAL_SEED is also preserved (beginend)" begin
@test refvalue == rand(Int)
end
end

@testset "InterruptExceptions #21043" begin
Expand Down Expand Up @@ -1202,4 +1225,4 @@ Test.finish(ts::PassInformationTestSet) = ts
@test ts.results[2].data == ErrorException
@test ts.results[2].value == ErrorException("Msg")
@test ts.results[2].source == LineNumberNode(test_throws_line_number, @__FILE__)
end
end

0 comments on commit bf8d60b

Please sign in to comment.