Skip to content

Commit b4b232d

Browse files
Refactor testsetup handling
1 parent b381807 commit b4b232d

File tree

4 files changed

+43
-52
lines changed

4 files changed

+43
-52
lines changed

src/ReTestItems.jl

Lines changed: 37 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -785,14 +785,14 @@ function include_testfiles!(project_name, projectfile, paths, ti_filter::TestIte
785785
# we set it below in tls as __RE_TEST_SETUPS__ for each included file
786786
setup_channel = Channel{Pair{Symbol, TestSetup}}(Inf)
787787
setup_task = @spawn begin
788-
setups = Dict{Symbol, TestSetup}()
789-
for (name, setup) in setup_channel
790-
if haskey(setups, name)
788+
testsetups = Dict{Symbol, TestSetup}()
789+
for (name, ts) in setup_channel
790+
if haskey(testsetups, name)
791791
@warn "Encountered duplicate @testsetup with name: `$name`. Replacing..."
792792
end
793-
setups[name] = setup
793+
testsetups[name] = ts
794794
end
795-
return setups
795+
return testsetups
796796
end
797797
hidden_re = r"\.\w"
798798
@sync for (root, d, files) in Base.walkdir(project_root)
@@ -844,21 +844,21 @@ function include_testfiles!(project_name, projectfile, paths, ti_filter::TestIte
844844
# prune empty directories/files
845845
close(setup_channel)
846846
prune!(root_node)
847-
ti = TestItems(root_node)
848-
flatten_testitems!(ti)
849-
check_ids(ti.testitems)
850-
setups = fetch(setup_task)
851-
for (i, x) in enumerate(ti.testitems)
847+
tis = TestItems(root_node)
848+
flatten_testitems!(tis)
849+
check_ids(tis.testitems)
850+
testsetups = fetch(setup_task)
851+
for (i, ti) in enumerate(tis.testitems)
852852
# set a unique number for each testitem
853-
x.number[] = i
853+
ti.number[] = i
854854
# populate testsetups for each testitem
855-
for s in x.setups
856-
if haskey(setups, s)
857-
push!(x.testsetups, setups[s])
855+
for setup_name in ti.setups
856+
if haskey(testsetups, setup_name)
857+
push!(ti.testsetups, setup_name => testsetups[setup_name])
858858
end
859859
end
860860
end
861-
return ti, setups # only returned for testing
861+
return tis, testsetups # only returned for testing
862862
end
863863

864864
function check_ids(testitems)
@@ -941,28 +941,18 @@ function with_source_path(f, path)
941941
end
942942
end
943943

944-
function ensure_setup!(ctx::TestContext, setup::Symbol, setups::Vector{TestSetup}, logs::Symbol)
944+
function ensure_setup!(ctx::TestContext, ts::TestSetup, logs::Symbol)
945945
mods = ctx.setups_evaled
946946
@lock mods.lock begin
947-
mod = get(mods.modules, setup, nothing)
947+
mod = get(mods.modules, ts.name, nothing)
948948
if mod !== nothing
949949
# we've eval-ed this module before, so just return the module name
950950
return nameof(mod)
951951
end
952-
# we haven't eval-ed this module before, so we need to eval it
953-
i = findfirst(s -> s.name == setup, setups)
954-
if i === nothing
955-
# if the setup hasn't been eval-ed before and we don't have it
956-
# in our testsetups, then it was never found during including
957-
# in that case, we return the expected test setup module name
958-
# which will turn into a `using $setup` in the test item
959-
# which will throw an appropriate error
960-
return setup
961-
end
962-
ts = setups[i]
963-
# In case the setup fails to eval, we discard its logs -- the setup will be
964-
# attempted to eval for each of the dependent test items and we'd for each
965-
# failed test item, we'd print the cumulative logs from all the previous attempts.
952+
# We haven't eval-ed this module before, so we need to eval it.
953+
# In case the setup fails to eval, we discard its logs -- we will attempt to eval
954+
# this testsetup for each of the dependent test items, and then for each failed
955+
# test item, we'd print the cumulative logs from all the previous attempts.
966956
isassigned(ts.logstore) && close(ts.logstore[])
967957
ts.logstore[] = open(logpath(ts), "w")
968958
mod_expr = :(module $(gensym(ts.name)) end)
@@ -972,7 +962,7 @@ function ensure_setup!(ctx::TestContext, setup::Symbol, setups::Vector{TestSetup
972962
with_source_path(() -> Core.eval(Main, mod_expr), ts.file)
973963
end
974964
# add the new module to our TestSetupModules
975-
mods.modules[setup] = newmod
965+
mods.modules[ts.name] = newmod
976966
return nameof(newmod)
977967
end
978968
end
@@ -1020,9 +1010,9 @@ function runtestitem(ti::TestItem; kw...)
10201010
# make a fresh TestSetupModules for each testitem run
10211011
GLOBAL_TEST_CONTEXT_FOR_TESTING.setups_evaled = TestSetupModules()
10221012
empty!(ti.testsetups)
1023-
for setup in ti.setups
1024-
ts = get(GLOBAL_TEST_SETUPS_FOR_TESTING, setup, nothing)
1025-
ts !== nothing && push!(ti.testsetups, ts)
1013+
for setup_name in ti.setups
1014+
ts = get(GLOBAL_TEST_SETUPS_FOR_TESTING, setup_name, nothing)
1015+
ts !== nothing && push!(ti.testsetups, setup_name => ts)
10261016
end
10271017
runtestitem(ti, GLOBAL_TEST_CONTEXT_FOR_TESTING; kw...)
10281018
end
@@ -1071,23 +1061,24 @@ function runtestitem(
10711061
prev = get(task_local_storage(), :__TESTITEM_ACTIVE__, false)
10721062
task_local_storage()[:__TESTITEM_ACTIVE__] = true
10731063
try
1074-
for setup in ti.setups
1075-
# TODO(nhd): Consider implementing some affinity to setups, so that we can
1076-
# prefer to send testitems to the workers that have already eval'd setups.
1077-
# Or maybe allow user-configurable grouping of test items by worker?
1078-
# Or group them by file by default?
1079-
1064+
for (setup_name, ts) in ti.testsetups
10801065
# ensure setup has been evaled before
1081-
@debugv 1 "Ensuring setup for test item $(repr(name)) $(setup)$(_on_worker())."
1082-
ts_mod = ensure_setup!(ctx, setup, ti.testsetups, logs)
1066+
@debugv 1 "Ensuring setup for test item $(repr(name)) $(setup_name)$(_on_worker())."
1067+
ts_mod = ensure_setup!(ctx, ts, logs)
10831068
# eval using in our @testitem module
1084-
@debugv 1 "Importing setup for test item $(repr(name)) $(setup)$(_on_worker())."
1069+
@debugv 1 "Importing setup for test item $(repr(name)) $(setup_name)$(_on_worker())."
10851070
# We look up the testsetups from Main (since tests are eval'd in their own
10861071
# temporary anonymous module environment.)
10871072
push!(body.args, Expr(:using, Expr(:., :Main, ts_mod)))
10881073
# ts_mod is a gensym'd name so that setup modules don't clash
10891074
# so we set a const alias inside our @testitem module to make things work
1090-
push!(body.args, :(const $setup = $ts_mod))
1075+
push!(body.args, :(const $setup_name = $ts_mod))
1076+
end
1077+
for setup_name in setdiff(ti.setups, keys(ti.testsetups))
1078+
# if the setup was requested but is not in our testsetups, then it was never
1079+
# found when including files. We still add `using $setup` in the test item
1080+
# so that we throw an appropriate error when running the test item.
1081+
push!(body.args, Expr(:using, Expr(:., :Main, setup_name)))
10911082
end
10921083
@debugv 1 "Setup for test item $(repr(name)) done$(_on_worker())."
10931084

@@ -1145,7 +1136,7 @@ function runtestitem(
11451136
end
11461137
finally
11471138
# Make sure all test setup logs are commited to file
1148-
foreach(ts->isassigned(ts.logstore) && flush(ts.logstore[]), ti.testsetups)
1139+
foreach(ts->isassigned(ts.logstore) && flush(ts.logstore[]), values(ti.testsetups))
11491140
ts1 = Test.pop_testset()
11501141
task_local_storage()[:__TESTITEM_ACTIVE__] = prev
11511142
@assert ts1 === ts

src/log_capture.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ function print_errors_and_captured_logs(
172172
)
173173
ts = ti.testsets[run_number]
174174
has_errors = any_non_pass(ts)
175-
has_logs = _has_logs(ti, run_number) || any(_has_logs, ti.testsetups)
175+
has_logs = _has_logs(ti, run_number) || any(_has_logs, values(ti.testsetups))
176176
if has_errors || logs == :batched
177177
report_iob = IOContext(IOBuffer(), :color=>Base.get_have_color())
178178
println(report_iob)
@@ -214,7 +214,7 @@ end
214214
# the captured logs or a messgage that no logs were captured. `print_errors_and_captured_logs`
215215
# will call this function only if some logs were collected or when called with `verbose_results`.
216216
function _print_captured_logs(io, ti::TestItem, run_number::Int)
217-
for setup in ti.testsetups
217+
for (_name, setup) in ti.testsetups
218218
_print_captured_logs(io, setup, ti)
219219
end
220220
has_logs = _has_logs(ti, run_number)

src/macros.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ struct TestItem
126126
line::Int
127127
project_root::String
128128
code::Any
129-
testsetups::Vector{TestSetup} # populated by runtests coordinator
129+
testsetups::Dict{Symbol,TestSetup} # populated by runtests coordinator
130130
workerid::Base.RefValue{Int} # populated when the test item is scheduled
131131
testsets::Vector{DefaultTestSet} # populated when the test item is finished running
132132
eval_number::Base.RefValue{Int} # to keep track of how many items have been run so far
@@ -137,7 +137,7 @@ function TestItem(number, name, id, tags, default_imports, setups, retries, time
137137
_id = @something(id, repr(hash(name, hash(relpath(file, project_root)))))
138138
return TestItem(
139139
number, name, _id, tags, default_imports, setups, retries, timeout, skip, failfast, file, line, project_root, code,
140-
TestSetup[],
140+
Dict{Symbol,TestSetup}(),
141141
Ref{Int}(0),
142142
DefaultTestSet[],
143143
Ref{Int}(0),

test/log_capture.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ end
3434
setup1 = @testsetup module TheTestSetup1 end
3535
setup2 = @testsetup module TheTestSetup2 end
3636
ti = TestItem(Ref(42), "TheTestItem", "ID007", [], false, [], 0, nothing, false, nothing, "source/path", 42, ".", nothing)
37-
push!(ti.testsetups, setup1)
38-
push!(ti.testsetups, setup2)
37+
push!(ti.testsetups, :TheTestSetup1 => setup1)
38+
push!(ti.testsetups, :TheTestSetup2 => setup2)
3939
push!(ti.testsets, Test.DefaultTestSet("dummy"))
4040
setup1.logstore[] = open(ReTestItems.logpath(setup1), "w")
4141
setup2.logstore[] = open(ReTestItems.logpath(setup2), "w")

0 commit comments

Comments
 (0)