Skip to content

Commit 423ef55

Browse files
committed
eunit: Pass node name to {node, ...} instantiator
The migration from slave to peer in OTP-28 discarded the node name returned by peer:start_link/1, passing the Pid to the instantiator instead of the node name. This made {node, ...} unusable since the instantiator needs the node name to use with {spawn, Node, Tests} or erpc:call/4. Capture the node name and wrap the instantiator so it receives the node name as an atom. Restore auto-start of net_kernel for non-distributed nodes so {node, ...} works out of the box.
1 parent 7c95ed8 commit 423ef55

2 files changed

Lines changed: 111 additions & 44 deletions

File tree

lib/eunit/src/eunit_data.erl

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -386,49 +386,58 @@ parse({node, N, T}, Options) when is_atom(N) ->
386386
parse({node, N, "", T}, Options);
387387
parse({node, N, A, T1}=T, Options) when is_atom(N) ->
388388
case eunit_lib:is_string(A) of
389-
true ->
390-
%% TODO: better stack traces for internal funs like these
391-
parse({setup,
392-
fun () ->
393-
%% TODO: auto-start net_kernel if needed
394-
StartedNet = false,
395-
%% The following is commented out because of problems when running
396-
%% eunit as part of the init sequence (from the command line):
397-
%% StartedNet =
398-
%% case whereis(net_kernel) of
399-
%% undefined ->
400-
%% M = list_to_atom(atom_to_list(N)
401-
%% ++ "_master"),
402-
%% case net_kernel:start([M]) of
403-
%% {ok, _} ->
404-
%% true;
405-
%% {error, E} ->
406-
%% throw({net_kernel_start, E})
407-
%% end;
408-
%% _ -> false
409-
%% end,
410-
%% ?debugVal({started, StartedNet}),
411-
{Name, Host} = eunit_lib:split_node(N),
412-
{ok, Node} = case peer:start_link(#{
389+
true ->
390+
%% TODO: better stack traces for internal funs like these
391+
%% Wrap T1 so the instantiator receives the node name
392+
T2 = case T1 of
393+
F when is_function(F, 1) ->
394+
fun({_Peer, NodeName, _}) -> F(NodeName) end;
395+
{with, As} when is_list(As) ->
396+
fun({_Peer, NodeName, _}) ->
397+
{with, NodeName, As}
398+
end;
399+
_ ->
400+
T1
401+
end,
402+
parse({setup,
403+
fun () ->
404+
{Name, Host} = eunit_lib:split_node(N),
405+
StartedNet =
406+
case node() of
407+
'nonode@nohost' ->
408+
M = list_to_atom(atom_to_list(Name)
409+
++ "_master"),
410+
case net_kernel:start(M, #{name_domain => shortnames}) of
411+
{ok, _} ->
412+
true;
413+
{error, E} ->
414+
throw({net_kernel_start, E})
415+
end;
416+
_ -> false
417+
end,
418+
PathArgs = lists:flatmap(
419+
fun(P) -> ["-pa", P] end,
420+
code:get_path()),
421+
{ok, Peer, NodeName} = case peer:start_link(#{
413422
host => atom_to_list(Host),
414-
name => Name, args => parse_peer_args(A)}) of
415-
{ok, Pid} -> {ok, Pid};
416-
{ok, Pid, _Node} -> {ok, Pid};
423+
name => Name,
424+
args => PathArgs ++ parse_peer_args(A)}) of
425+
{ok, Pid, Node0} -> {ok, Pid, Node0};
417426
{error, Rsn} -> throw({peer_start, Rsn})
418427
end,
419-
{Node, StartedNet}
420-
end,
421-
fun ({Node, StopNet}) ->
422-
%% ?debugVal({stop, StopNet}),
423-
peer:stop(Node),
424-
case StopNet of
425-
true -> net_kernel:stop();
426-
false -> ok
427-
end
428-
end,
429-
T1}, Options);
430-
false ->
431-
bad_test(T)
428+
{Peer, NodeName, StartedNet}
429+
end,
430+
fun ({Peer, _NodeName, StopNet}) ->
431+
%% ?debugVal({stop, StopNet}),
432+
peer:stop(Peer),
433+
case StopNet of
434+
true -> net_kernel:stop();
435+
false -> ok
436+
end
437+
end,
438+
T2}, Options);
439+
false ->
440+
bad_test(T)
432441
end;
433442
parse({module, M}, Options) when is_atom(M) ->
434443
{data, {"module '" ++ atom_to_list(M) ++ "'", get_module_tests(M, Options)}};
@@ -844,7 +853,7 @@ data_test_() ->
844853
?_assertMatch(ok, eunit:test({spawn, Tests})),
845854
?_assertMatch(ok, eunit:test({setup, Setup, Cleanup,
846855
fun (P) -> ?_test(ok = ping(P)) end})),
847-
%%?_assertMatch(ok, eunit:test({node, test@localhost, Tests})),
856+
?_assertMatch(ok, eunit:test({node, test@localhost, Tests})),
848857
?_assertMatch(ok, eunit:test({module, eunit_lib})),
849858
?_assertMatch(ok, eunit:test(eunit_lib)),
850859
?_assertMatch(ok, eunit:test("examples/tests.txt"))

lib/eunit/test/eunit_SUITE.erl

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
-export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1,
2525
init_per_group/2, end_per_group/2,
2626
app_test/1, appup_test/1, eunit_test/1, eunit_exact_test/1,
27-
fixture_test/1, primitive_test/1, surefire_utf8_test/1,
27+
fixture_test/1, node_test/1, primitive_test/1, surefire_utf8_test/1,
2828
surefire_latin_test/1, surefire_c0_test/1, surefire_ensure_dir_test/1,
2929
stacktrace_at_timeout_test/1, scale_timeouts_test/1,
3030
report_failed_setup_inparallel_test/1, parse_commandline_test/1]).
@@ -42,8 +42,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
4242

4343
all() ->
4444
[app_test, appup_test, eunit_test, eunit_exact_test, primitive_test,
45-
fixture_test, surefire_utf8_test, surefire_latin_test, surefire_c0_test,
46-
surefire_ensure_dir_test, stacktrace_at_timeout_test,
45+
fixture_test, node_test, surefire_utf8_test, surefire_latin_test,
46+
surefire_c0_test, surefire_ensure_dir_test, stacktrace_at_timeout_test,
4747
scale_timeouts_test, report_failed_setup_inparallel_test,
4848
parse_commandline_test].
4949

@@ -155,6 +155,64 @@ fixture_test(Config) when is_list(Config) ->
155155
[{1, fun(_A, _B) -> fun() -> a_test end end}]}),
156156
ok.
157157

158+
node_test(Config) when is_list(Config) ->
159+
T = fun() -> ok end,
160+
%% Plain tests
161+
ok = eunit:test({node, eunit_node_plain, [T, T, T]}),
162+
%% Instantiator receives node name as atom
163+
ok = eunit:test(
164+
{node, eunit_node_inst, fun(Node) ->
165+
true = is_atom(Node),
166+
{spawn, Node, [
167+
fun() -> Node = node() end
168+
]}
169+
end}),
170+
%% With extra args
171+
ok = eunit:test(
172+
{node, eunit_node_args, "+S 1", fun(Node) ->
173+
true = is_atom(Node),
174+
{spawn, Node, [T]}
175+
end}),
176+
%% Test {node, ...} during system initialization (non-distributed).
177+
%% Verifies that auto-starting net_kernel is safe with -eval, -s,
178+
%% -run, and -S flags as described in init(3).
179+
PrivDir = proplists:get_value(priv_dir, Config, "."),
180+
HelperMod = eunit_node_init_test,
181+
HelperSrc = filename:join(PrivDir, atom_to_list(HelperMod) ++ ".erl"),
182+
ok = file:write_file(HelperSrc,
183+
"-module(" ++ atom_to_list(HelperMod) ++ ").\n"
184+
"-export([start/0, start/1]).\n"
185+
"start() -> start([]).\n"
186+
"start(_) ->\n"
187+
" ok = eunit:test({node, init_test, fun() -> ok end}),\n"
188+
" halt(0).\n"),
189+
{ok, HelperMod} = compile:file(HelperSrc, [{outdir, PrivDir}]),
190+
[Exec | ExecArgs] = string:split(ct:get_progname(), " ", all),
191+
Erl = os:find_executable(Exec),
192+
BaseArgs = ExecArgs ++ ["-noshell"],
193+
%% -eval
194+
0 = run_erl_cmd(Erl, BaseArgs ++ ["-eval",
195+
"ok = eunit:test({node, init_eval, fun() -> ok end}), halt(0)."]),
196+
%% -s
197+
0 = run_erl_cmd(Erl, BaseArgs ++ ["-pa", PrivDir,
198+
"-s", atom_to_list(HelperMod), "start"]),
199+
%% -run
200+
0 = run_erl_cmd(Erl, BaseArgs ++ ["-pa", PrivDir,
201+
"-run", atom_to_list(HelperMod), "start"]),
202+
%% -S
203+
0 = run_erl_cmd(Erl, BaseArgs ++ ["-pa", PrivDir,
204+
"-S", atom_to_list(HelperMod), "start"]),
205+
ok.
206+
207+
run_erl_cmd(Erl, Args) ->
208+
Port = open_port({spawn_executable, Erl},
209+
[{args, Args}, stderr_to_stdout, exit_status, hide]),
210+
receive
211+
{Port, {exit_status, Status}} -> Status
212+
after 30_000 ->
213+
ct:fail({erl_timeout, Args})
214+
end.
215+
158216
check_test_results(Primitive, Expected) ->
159217
receive
160218
{test_report, TestReport} ->

0 commit comments

Comments
 (0)