-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
use ScopedValues for TestSets #53462
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
1c67443
to
b1fec32
Compare
@vchuravy @Keno I'm getting some weird failures on this branch originating from this line: julia/base/compiler/ssair/passes.jl Line 1162 in c379db7
The simplest reproducer I have is: using Test
@testset begin
@testset for r in Int[1]
end
end |
Blocked by #53521 |
73b39d1
to
0cd361c
Compare
0cd361c
to
7ef5878
Compare
Would love to see this merged! @simonbyrne do you have any time to work on this? I'd be happy to rebase and help get it over the line. I think rebasing, and then deciding what to do with the commented-out scope tests might be all that's needed here? |
I initially thought I managed to badly botch the rebase, but I believe this is now failing to build because after the rebase #55452 was merged in and that PR removed |
Sorry, it still needs some work. The handling of errors is wasn't quite correct, and the resetting of rng state is kind of confusing (arguably should be handled differently) |
Currently blocked by #56062 |
FYI, #56062 was recently fixed. |
1a89ef6
to
449a7ab
Compare
Okay, I think this is now passing. Any thoughts? |
@nanosoldier |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even though I recently touched the Test stdlib I'm not particularly familiar with its code, I don't understand some of the design choices. That said, this looks overall good to me (as much as that mean, not knowing the code), looks like a decent simplification. I'm going to trust hope existing tests already cover corner cases of nested testsets that we should make sure keep working.
test/scopedvalues.jl
Outdated
@test sprint(show, Core.current_scope()) == "nothing" | ||
@test sprint(show, ScopedValue{Int}()) == "$ScopedValue{$Int}(undefined)" | ||
@test sprint(show, sval) == "$ScopedValue{$Int}(1)" | ||
# @test sprint(show, Core.current_scope()) == "nothing" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this test commented out? Can we move it at the top-level, outside of any testset, to keep the test, or that's still within an implicit scope?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depending on how the runtests is called, it might be inside a scope. The only way to guarantee it is to run it in a separate process.
test/scopedvalues.jl
Outdated
@test sprint(show, sval) == "$ScopedValue{$Int}(2)" | ||
objid = sprint(show, Base.objectid(sval)) | ||
@test sprint(show, Core.current_scope()) == "Base.ScopedValues.Scope(Base.ScopedValues.ScopedValue{$Int}@$objid => 2)" | ||
# @test sprint(show, Core.current_scope()) == "Base.ScopedValues.Scope(Base.ScopedValues.ScopedValue{$Int}@$objid => 2)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this: why was it removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, I can't see a way to make this work.
""" | ||
push_testset(ts::AbstractTestSet) | ||
Adds the test set to the `task_local_storage`. | ||
""" | ||
function push_testset(ts::AbstractTestSet) | ||
testsets = get(task_local_storage(), :__BASETESTNEXT__, AbstractTestSet[]) | ||
push!(testsets, ts) | ||
setindex!(task_local_storage(), testsets, :__BASETESTNEXT__) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently some (testing) packages were using this: https://juliahub.com/ui/Search?type=symbols&q=push_testset&u=use. Presumably it's ok to ask them to adapt their use of internal functions? These aren't documented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, unfortunately I don't see how we could keep that working
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would one update a codebase that is using push_testset
? is it as simple as changing from
push_testset(ts)
try
...
finally
pop_testset()
end
to
@with_testset ts begin
...
end
?
(p.s. Very pleased to see this improvement!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that should work I think.
get_testset_depth() > 1 ? rethrow() : failfast_print() | ||
get_testset_depth() > 0 ? rethrow() : failfast_print() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't immediately tell the motivation for this change, could you please elaborate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously the check used to be inside the scope, now it is outside
The package evaluation job you requested has completed - possible new issues were detected. Report summary❗ Packages that crashed3 packages crashed only on the current version.
14 packages crashed on the previous version too. ✖ Packages that failed181 packages failed only on the current version.
1132 packages failed on the previous version too. ✔ Packages that passed tests22 packages passed tests only on the current version.
5158 packages passed tests on the previous version too. ~ Packages that at least loaded18 packages successfully loaded only on the current version.
2933 packages successfully loaded on the previous version too. ➖ Packages that were skipped altogether897 packages were skipped on the previous version too. |
Test has `Test.record_passes()` which gets `OncePerProcess` initialized to the value of `ENV["JULIA_TEST_RECORD_PASSES"]`. However, in another palce the test suite once to override this value for its scope, and does this by setting the environment variable, relying on OncePerProcess picking this up. However, this is not at all semantically guaranteed and of course fails if anybody happened to have a testset before (which is possible, because this is used by Base.runtests). It would be much better if we could use a ScopedValue for this like the other `Test` setting state (after #53462). However, there currently isn't any way to once-initialize the ScopedValue default. This PR aims to fix that by letting the scoped value default be an evaluated callback. The original `ScopedValue` struct is renamed `LazyScopedValue`, but the `ScopedValue` name is retained with the same API as an alias to a `LazyScopedValue` that just uses `Returns(default)` as its initializer. It might be a bit weird that the default could return a different value at every time, but I think a reasonable way to think about this is that the default chains to some dynamic state which is expressed in this callback.
Sigh, I don't understand the test failures here. I can't reproduce them locally and worse, #59372 which includes these commits doesn't show them either - and yet - the tests failed on all platforms on CI. |
I'm gonna go with testsets are not thread safe, and before this change, they did not propagate into |
The retry confirmed that theory |
In preparation of #53462, ensure that attempting to record test results to a test set from multiple threads does not cause corruption. Note that other part of `Test` remain non-threadsafe.
In preparation of #53462, ensure that attempting to record test results to a test set from multiple threads does not cause corruption. Note that other part of `Test` remain non-threadsafe.
I have rebased on top of #59374, in the hope that that will fix CI and the expectation that that'll get merged first. |
In preparation of #53462, ensure that attempting to record test results to a test set from multiple threads does not cause corruption. Note that other part of `Test` remain non-threadsafe.
In preparation of #53462, ensure that attempting to record test results to a test set from multiple threads does not cause corruption. Note that other part of `Test` remain non-threadsafe.
Test has `Test.record_passes()` which gets `OncePerProcess` initialized to the value of `ENV["JULIA_TEST_RECORD_PASSES"]`. However, in another palce the test suite once to override this value for its scope, and does this by setting the environment variable, relying on OncePerProcess picking this up. However, this is not at all semantically guaranteed and of course fails if anybody happened to have a testset before (which is possible, because this is used by Base.runtests). It would be much better if we could use a ScopedValue for this like the other `Test` setting state (after #53462). However, there currently isn't any way to once-initialize the ScopedValue default. This PR aims to fix that by letting the scoped value default be an evaluated callback.
In preparation of #53462, ensure that attempting to record test results to a test set from multiple threads does not cause corruption. Note that other part of `Test` remain non-threadsafe.
Thanks Keno for seeing this through! |
Amazing, I'm glad to see this! 💪 This is a really nice cleanup, and a perfect showcase for ScopedValues. 👏 |
Test has `Test.record_passes()` which gets `OncePerProcess` initialized to the value of `ENV["JULIA_TEST_RECORD_PASSES"]`. However, in another palce the test suite once to override this value for its scope, and does this by setting the environment variable, relying on OncePerProcess picking this up. However, this is not at all semantically guaranteed and of course fails if anybody happened to have a testset before (which is possible, because this is used by Base.runtests). It would be much better if we could use a ScopedValue for this like the other `Test` setting state (after #53462). However, there currently isn't any way to once-initialize the ScopedValue default. This PR aims to fix that by letting the scoped value default be an evaluated callback.
Another attempt at #51012