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.
  • Loading branch information
rfourquet authored Nov 23, 2021
1 parent 8c97995 commit 08ea2d8
Show file tree
Hide file tree
Showing 3 changed files with 28 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 @@ -392,6 +392,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 @@ -1340,6 +1340,7 @@ function testset_beginend_call(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 @@ -1353,6 +1354,7 @@ function testset_beginend_call(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 @@ -1433,6 +1435,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 @@ -1446,6 +1449,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
24 changes: 23 additions & 1 deletion stdlib/Test/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,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 @@ -1280,4 +1303,3 @@ let
end
end
end

0 comments on commit 08ea2d8

Please sign in to comment.