Elixir and Erlang/OTP versions
Elixir 1.19.5 (compiled with Erlang/OTP 28)
Operating system
Mac OS 26.2 (25C56)
Current behavior
From my experience and reading through the code - I believe the documented ExUnit test process life cycle is not respected by the current implementation. The steps that seem inverted are
4. it stops all supervised processes
5. the test process exits with reason :shutdown
I believe these blocks of code show the current issue
|
defp spawn_test_monitor( |
|
%{seed: seed, capture_log: capture_log, rand_algorithm: rand_algorithm}, |
|
test, |
|
parent_pid, |
|
context |
|
) do |
|
spawn_monitor(fn -> |
|
Process.set_label({test.case, test.name}) |
|
ExUnit.OnExitHandler.register(self()) |
|
generate_test_seed(seed, test, rand_algorithm) |
|
context = context |> Map.merge(test.tags) |> Map.put(:test_pid, self()) |
|
capture_log = Map.get(context, :capture_log, capture_log) |
|
|
|
{time, test} = |
|
:timer.tc( |
|
maybe_capture_log(capture_log, test, fn -> |
|
context = maybe_create_tmp_dir(context, test) |
|
|
|
case exec_test_setup(test, context) do |
|
{:ok, context} -> exec_test(test, context) |
|
{:error, test} -> test |
|
end |
|
end) |
|
) |
|
|
|
send(parent_pid, {self(), :test_finished, %{test | time: time}}) |
|
exit(:shutdown) |
|
end) |
|
end |
|
defp spawn_test(config, test, context) do |
|
parent_pid = self() |
|
timeout = get_timeout(config, test.tags) |
|
{test_pid, test_ref} = spawn_test_monitor(config, test, parent_pid, context) |
|
test = receive_test_reply(test, test_pid, test_ref, timeout) |
|
exec_on_exit(test, test_pid, timeout) |
|
end |
|
defp exec_on_exit(test_or_case, pid, timeout) do |
|
case ExUnit.OnExitHandler.run(pid, timeout) do |
|
:ok -> |
|
test_or_case |
|
|
|
{kind, reason, stack} -> |
|
state = test_or_case.state || failed(kind, reason, prune_stacktrace(stack)) |
|
%{test_or_case | state: state} |
|
end |
|
end |
|
def run(pid, timeout) when is_pid(pid) do |
|
[{^pid, sup, callbacks}] = :ets.take(@name, pid) |
|
error = terminate_supervisor(sup, timeout) |
|
exec_on_exit_callbacks(Enum.reverse(callbacks), timeout, error) |
|
end |
My understanding of this is that
1 - The Runner spawns a process to run the test
2 - On Complete the test processes sends a message back to the runner to alert it that has completed the test
ASYNC
3 A - The Runner receives the message from the test pid and shuts down the supervised processes
3 B - The test process exits
I have created a minimal reproduction of this problem that can be found in this repo
In my opinion it would be ideal to respect the currently documented test process lifecycle - but if that creates too large of a change to existing behavior it would be great if there was a way to opt into a more strict ordering. If the core team agrees that this should be addressed, I would be happy to work up a pr or in any other way provide whatever support I can
As always, appreciate everything the core team and community do!
Expected behavior
From the ExUnit docs
Here is a rundown of the life cycle of the test process:
the test process is spawned
it runs setup/2 callbacks
it runs the test itself
it stops all supervised processes
the test process exits with reason :shutdown
on_exit/2 callbacks are executed in a separate process
Elixir and Erlang/OTP versions
Elixir 1.19.5 (compiled with Erlang/OTP 28)
Operating system
Mac OS 26.2 (25C56)
Current behavior
From my experience and reading through the code - I believe the documented ExUnit test process life cycle is not respected by the current implementation. The steps that seem inverted are
I believe these blocks of code show the current issue
elixir/lib/ex_unit/lib/ex_unit/runner.ex
Lines 441 to 469 in 8f40bf1
elixir/lib/ex_unit/lib/ex_unit/runner.ex
Lines 433 to 439 in 8f40bf1
elixir/lib/ex_unit/lib/ex_unit/runner.ex
Lines 540 to 549 in 8f40bf1
elixir/lib/ex_unit/lib/ex_unit/on_exit_handler.ex
Lines 53 to 57 in 8f40bf1
My understanding of this is that
1 - The Runner spawns a process to run the test
2 - On Complete the test processes sends a message back to the runner to alert it that has completed the test
ASYNC
3 A - The Runner receives the message from the test pid and shuts down the supervised processes
3 B - The test process exits
I have created a minimal reproduction of this problem that can be found in this repo
In my opinion it would be ideal to respect the currently documented test process lifecycle - but if that creates too large of a change to existing behavior it would be great if there was a way to opt into a more strict ordering. If the core team agrees that this should be addressed, I would be happy to work up a pr or in any other way provide whatever support I can
As always, appreciate everything the core team and community do!
Expected behavior
From the ExUnit docs