-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Support :group
option in ExUnit
#13897
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
Changes from 11 commits
83e8e65
c74322f
7c6ece6
b0dd42f
07e5429
8707d42
ade7605
3b9d737
c1cfa3f
27b463d
55f38a4
fe3f66c
9882f65
fa5e52c
ad42780
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -161,11 +161,22 @@ defmodule ExUnit.Runner do | |
running | ||
end | ||
|
||
defp spawn_modules(config, [{module, params} | modules], async?, running) do | ||
defp spawn_modules( | ||
config, | ||
[{_group, group_modules} | modules], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The sync modules are not arriving in this shape and they are being skipped (because the group modules is treated as an empty map). I will add a pattern to help us catch it. :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Damn, that masked the other issues! And bummer about the tests being flaky, it would have been nice to have tests for this functionality. |
||
async?, | ||
running | ||
) do | ||
if max_failures_reached?(config) do | ||
running | ||
else | ||
{pid, ref} = spawn_monitor(fn -> run_module(config, module, async?, params) end) | ||
{pid, ref} = | ||
spawn_monitor(fn -> | ||
Enum.each(group_modules, fn {module, params} -> | ||
josevalim marked this conversation as resolved.
Show resolved
Hide resolved
|
||
run_module(config, module, async?, params) | ||
end) | ||
end) | ||
|
||
spawn_modules(config, modules, async?, Map.put(running, ref, pid)) | ||
end | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,15 +9,21 @@ defmodule ExUnit.Server do | |
GenServer.start_link(__MODULE__, :ok, name: @name) | ||
end | ||
|
||
def add_module(name, {async?, parameterize}) do | ||
def add_module(name, config) do | ||
%{ | ||
async?: async?, | ||
group: group, | ||
parameterize: parameterize | ||
} = config | ||
|
||
modules = | ||
if parameterize do | ||
Enum.map(parameterize, &{name, &1}) | ||
else | ||
[{name, %{}}] | ||
end | ||
|
||
case GenServer.call(@name, {:add, async?, modules}, @timeout) do | ||
case GenServer.call(@name, {:add, {async?, group}, modules}, @timeout) do | ||
:ok -> | ||
:ok | ||
|
||
|
@@ -51,6 +57,7 @@ defmodule ExUnit.Server do | |
state = %{ | ||
loaded: System.monotonic_time(), | ||
waiting: nil, | ||
async_groups: %{}, | ||
async_modules: :queue.new(), | ||
sync_modules: :queue.new() | ||
} | ||
|
@@ -74,10 +81,20 @@ defmodule ExUnit.Server do | |
|
||
# Called by the runner when --repeat-until-failure is used. | ||
def handle_call({:restore_modules, async_modules, sync_modules}, _from, state) do | ||
{async_modules, async_groups} = | ||
Enum.reduce(async_modules, {[], []}, fn | ||
{nil, [module]}, {modules, groups} -> | ||
{[{:module, module} | modules], groups} | ||
|
||
{group, group_modules}, {modules, groups} -> | ||
{[{:group, group} | modules], Map.put(groups, group, group_modules)} | ||
end) | ||
|
||
{:reply, :ok, | ||
%{ | ||
state | ||
| loaded: :done, | ||
async_groups: async_groups, | ||
async_modules: :queue.from_list(async_modules), | ||
reisub marked this conversation as resolved.
Show resolved
Hide resolved
|
||
sync_modules: :queue.from_list(sync_modules) | ||
josevalim marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}} | ||
|
@@ -91,7 +108,15 @@ defmodule ExUnit.Server do | |
when is_integer(loaded) do | ||
state = | ||
if uniq? do | ||
async_modules = :queue.to_list(state.async_modules) |> Enum.uniq() |> :queue.from_list() | ||
async_modules = | ||
state.async_modules | ||
|> :queue.to_list() | ||
|> Enum.uniq() | ||
|> Enum.map(fn {group, modules} -> | ||
{group, Enum.uniq(modules)} | ||
end) | ||
reisub marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|> :queue.from_list() | ||
|
||
sync_modules = :queue.to_list(state.sync_modules) |> Enum.uniq() |> :queue.from_list() | ||
|
||
%{ | ||
|
@@ -107,26 +132,40 @@ defmodule ExUnit.Server do | |
{:reply, diff, take_modules(%{state | loaded: :done})} | ||
end | ||
|
||
def handle_call({:add, true, names}, _from, %{loaded: loaded} = state) | ||
def handle_call({:add, {false = _async, _group}, names}, _from, %{loaded: loaded} = state) | ||
when is_integer(loaded) do | ||
state = | ||
update_in(state.sync_modules, &Enum.reduce(names, &1, fn name, q -> :queue.in(name, q) end)) | ||
|
||
{:reply, :ok, state} | ||
end | ||
|
||
def handle_call({:add, {true = _async, nil = _group}, names}, _from, %{loaded: loaded} = state) | ||
when is_integer(loaded) do | ||
state = | ||
update_in( | ||
state.async_modules, | ||
&Enum.reduce(names, &1, fn name, q -> :queue.in(name, q) end) | ||
&Enum.reduce(names, &1, fn name, q -> :queue.in({:module, name}, q) end) | ||
) | ||
|
||
{:reply, :ok, take_modules(state)} | ||
{:reply, :ok, state} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We lost a call to |
||
end | ||
|
||
def handle_call({:add, false, names}, _from, %{loaded: loaded} = state) | ||
def handle_call({:add, {true = _async, group}, names}, _from, %{loaded: loaded} = state) | ||
when is_integer(loaded) do | ||
state = | ||
update_in(state.sync_modules, &Enum.reduce(names, &1, fn name, q -> :queue.in(name, q) end)) | ||
if Map.has_key?(state.async_groups, group) do | ||
update_in(state.async_groups[group], &(names ++ &1)) | ||
else | ||
state | ||
|> put_in([:async_groups, group], names) | ||
|> update_in([:async_modules], &:queue.in({:group, group}, &1)) | ||
end | ||
reisub marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
{:reply, :ok, state} | ||
end | ||
|
||
def handle_call({:add, _async?, _names}, _from, state), | ||
def handle_call({:add, {_async?, _group}, _names}, _from, state), | ||
do: {:reply, :already_running, state} | ||
|
||
defp take_modules(%{waiting: nil} = state) do | ||
|
@@ -145,9 +184,26 @@ defmodule ExUnit.Server do | |
state | ||
|
||
true -> | ||
{modules, async_modules} = take_until(count, state.async_modules) | ||
GenServer.reply(from, modules) | ||
%{state | async_modules: async_modules, waiting: nil} | ||
{async_modules, remaining_modules} = take_until(count, state.async_modules) | ||
|
||
{async_modules, remaining_groups} = | ||
Enum.reduce(async_modules, {[], state.async_groups}, fn | ||
{:module, module}, {collected_modules, async_groups} -> | ||
{[{nil, [module]} | collected_modules], async_groups} | ||
|
||
{:group, group}, {collected_modules, async_groups} -> | ||
{group_modules, async_groups} = Map.pop!(async_groups, group) | ||
{[{group, group_modules} | collected_modules], async_groups} | ||
reisub marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
end) | ||
|
||
GenServer.reply(from, Enum.reverse(async_modules)) | ||
|
||
%{ | ||
state | ||
| async_groups: remaining_groups, | ||
async_modules: remaining_modules, | ||
waiting: nil | ||
} | ||
end | ||
end | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.