Skip to content

Commit a992ee9

Browse files
committed
Only spawn setup_all process if there is such callbacks
1 parent 7190f41 commit a992ee9

File tree

4 files changed

+95
-68
lines changed

4 files changed

+95
-68
lines changed

lib/ex_unit/lib/ex_unit.ex

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,22 +124,28 @@ defmodule ExUnit do
124124
125125
It is received by formatters and contains the following fields:
126126
127-
* `:file` - (since v1.11.0) the file of the test module
127+
* `:file` - (since v1.11.0) the file of the test module
128128
129-
* `:name` - the test module name
129+
* `:name` - the test module name
130+
131+
* `:parameters` - (since v1.18.0) the test module parameters
132+
133+
* `:setup_all?` - (since v1.18.0) if the test module requies a setup all
130134
131135
* `:state` - the test error state (see `t:ExUnit.state/0`)
132136
133-
* `:tests` - all tests in this module
137+
* `:tags` - all tags in this module
134138
135-
* `:parameters` - the test module parameters
139+
* `:tests` - all tests in this module
136140
137141
"""
138-
defstruct [:file, :name, :state, tags: %{}, tests: [], parameters: %{}]
142+
defstruct [:file, :name, :setup_all?, :state, parameters: %{}, tags: %{}, tests: []]
139143

140144
@type t :: %__MODULE__{
141145
file: binary(),
142146
name: module,
147+
parameters: map(),
148+
setup_all?: boolean(),
143149
state: ExUnit.state(),
144150
tags: map,
145151
tests: [ExUnit.Test.t()]

lib/ex_unit/lib/ex_unit/callbacks.ex

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,23 @@ defmodule ExUnit.Callbacks do
174174
end
175175

176176
@doc false
177-
defmacro __before_compile__(env) do
178-
used_describes = Module.get_attribute(env.module, :ex_unit_used_describes)
177+
def __callbacks__(module) do
178+
setup = Module.get_attribute(module, :ex_unit_setup)
179+
setup_all = Module.get_attribute(module, :ex_unit_setup_all)
180+
used_describes = Module.get_attribute(module, :ex_unit_used_describes)
179181

180-
quote do
181-
unquote(compile_setup(env, :setup, used_describes))
182-
unquote(compile_setup(env, :setup_all, %{}))
183-
end
182+
code =
183+
quote do
184+
unquote(compile_setup(:setup, setup, used_describes))
185+
unquote(compile_setup(:setup_all, setup_all, %{}))
186+
end
187+
188+
{setup_all != [], code}
189+
end
190+
191+
@doc false
192+
defmacro __before_compile__(%{module: module}) do
193+
__callbacks__(module)
184194
end
185195

186196
@doc """
@@ -802,11 +812,8 @@ defmodule ExUnit.Callbacks do
802812
{name, body}
803813
end
804814

805-
defp compile_setup(env, kind, describes) do
806-
calls =
807-
env.module
808-
|> Module.get_attribute(:"ex_unit_#{kind}")
809-
|> compile_setup(kind)
815+
defp compile_setup(kind, value, describes) do
816+
calls = compile_setup(value, kind)
810817

811818
describe_clauses =
812819
for {describe, callback} <- describes,

lib/ex_unit/lib/ex_unit/case.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,6 @@ defmodule ExUnit.Case do
353353

354354
ExUnit.Callbacks.__register__(module)
355355
Module.put_attribute(module, :before_compile, ExUnit.Case)
356-
Module.put_attribute(module, :before_compile, ExUnit.Callbacks)
357356
end
358357

359358
past_opts = Module.get_attribute(module, :ex_unit_module, [])
@@ -564,11 +563,16 @@ defmodule ExUnit.Case do
564563
raise ArgumentError, ":parameterize must be a list of maps, got: #{inspect(parameterize)}"
565564
end
566565

566+
{setup_all?, callbacks} = ExUnit.Callbacks.__callbacks__(module)
567+
567568
quote do
569+
unquote(callbacks)
570+
568571
def __ex_unit__ do
569572
%ExUnit.TestModule{
570573
file: __ENV__.file,
571574
name: __MODULE__,
575+
setup_all?: unquote(setup_all?),
572576
tags: unquote(Macro.escape(tags)),
573577
tests: unquote(tests)
574578
}

lib/ex_unit/lib/ex_unit/runner.ex

Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -301,69 +301,79 @@ defmodule ExUnit.Runner do
301301
end
302302

303303
defp run_module_tests(config, test_module, async?, tests) do
304-
{module_pid, module_ref} = run_setup_all(test_module, async?, self())
304+
Process.put(@current_key, test_module)
305+
%ExUnit.TestModule{name: module, tags: tags, parameters: params} = test_module
306+
context = tags |> Map.merge(params) |> Map.merge(%{module: module, async: async?})
307+
308+
config
309+
|> run_setup_all(test_module, context, fn context ->
310+
if max_failures_reached?(config),
311+
do: [],
312+
else: run_tests(config, tests, test_module.parameters, context)
313+
end)
314+
|> case do
315+
{{:ok, finished_tests}, test_module} ->
316+
{test_module, [], finished_tests}
305317

306-
{test_module, invalid_tests, finished_tests} =
307-
receive do
308-
{^module_pid, :setup_all, {:ok, context}} ->
309-
finished_tests =
310-
if max_failures_reached?(config),
311-
do: [],
312-
else: run_tests(config, tests, test_module.parameters, context)
318+
{:error, test_module} ->
319+
{test_module, Enum.map(tests, &%{&1 | state: {:invalid, test_module}}), []}
320+
end
321+
end
313322

314-
:ok = exit_setup_all(module_pid, module_ref)
315-
{test_module, [], finished_tests}
323+
defp run_setup_all(
324+
_config,
325+
%ExUnit.TestModule{setup_all?: false} = test_module,
326+
context,
327+
callback
328+
) do
329+
{{:ok, callback.(context)}, test_module}
330+
end
316331

317-
{^module_pid, :setup_all, {:error, test_module}} ->
318-
invalid_tests = mark_tests_invalid(tests, test_module)
319-
:ok = exit_setup_all(module_pid, module_ref)
320-
{test_module, invalid_tests, []}
332+
defp run_setup_all(config, %ExUnit.TestModule{name: module} = test_module, context, callback) do
333+
parent_pid = self()
321334

322-
{:DOWN, ^module_ref, :process, ^module_pid, error} ->
323-
test_module = %{test_module | state: failed({:EXIT, module_pid}, error, [])}
324-
invalid_tests = mark_tests_invalid(tests, test_module)
325-
{test_module, invalid_tests, []}
326-
end
335+
{module_pid, module_ref} =
336+
spawn_monitor(fn ->
337+
ExUnit.OnExitHandler.register(self())
338+
339+
result =
340+
try do
341+
{:ok, module.__ex_unit__(:setup_all, context)}
342+
catch
343+
kind, error ->
344+
failed = failed(kind, error, prune_stacktrace(__STACKTRACE__))
345+
{:error, %{test_module | state: failed}}
346+
end
327347

328-
timeout = get_timeout(config, %{})
329-
{exec_on_exit(test_module, module_pid, timeout), invalid_tests, finished_tests}
330-
end
348+
send(parent_pid, {self(), :setup_all, result})
331349

332-
defp mark_tests_invalid(tests, test_module) do
333-
Enum.map(tests, &%{&1 | state: {:invalid, test_module}})
334-
end
350+
# We keep the process alive so all of its resources
351+
# stay alive until we run all tests in this case.
352+
ref = Process.monitor(parent_pid)
335353

336-
defp run_setup_all(
337-
%ExUnit.TestModule{name: module, tags: tags, parameters: params} = test_module,
338-
async?,
339-
parent_pid
340-
) do
341-
Process.put(@current_key, test_module)
342-
343-
spawn_monitor(fn ->
344-
ExUnit.OnExitHandler.register(self())
345-
tags = tags |> Map.merge(params) |> Map.merge(%{module: module, async: async?})
346-
347-
result =
348-
try do
349-
{:ok, module.__ex_unit__(:setup_all, Map.merge(tags, params))}
350-
catch
351-
kind, error ->
352-
failed = failed(kind, error, prune_stacktrace(__STACKTRACE__))
353-
{:error, %{test_module | state: failed}}
354+
receive do
355+
{^parent_pid, :exit} -> :ok
356+
{:DOWN, ^ref, _, _, _} -> :ok
354357
end
358+
end)
355359

356-
send(parent_pid, {self(), :setup_all, result})
360+
{ok_or_error, test_module} =
361+
receive do
362+
{^module_pid, :setup_all, {:ok, context}} ->
363+
finished_tests = callback.(context)
364+
:ok = exit_setup_all(module_pid, module_ref)
365+
{{:ok, finished_tests}, test_module}
357366

358-
# We keep the process alive so all of its resources
359-
# stay alive until we run all tests in this case.
360-
ref = Process.monitor(parent_pid)
367+
{^module_pid, :setup_all, {:error, test_module}} ->
368+
:ok = exit_setup_all(module_pid, module_ref)
369+
{:error, test_module}
361370

362-
receive do
363-
{^parent_pid, :exit} -> :ok
364-
{:DOWN, ^ref, _, _, _} -> :ok
371+
{:DOWN, ^module_ref, :process, ^module_pid, error} ->
372+
{:error, %{test_module | state: failed({:EXIT, module_pid}, error, [])}}
365373
end
366-
end)
374+
375+
timeout = get_timeout(config, %{})
376+
{ok_or_error, exec_on_exit(test_module, module_pid, timeout)}
367377
end
368378

369379
defp exit_setup_all(pid, ref) do

0 commit comments

Comments
 (0)