summaryrefslogtreecommitdiff
path: root/lib/kernel/test/erl_distribution_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test/erl_distribution_SUITE.erl')
-rw-r--r--lib/kernel/test/erl_distribution_SUITE.erl430
1 files changed, 370 insertions, 60 deletions
diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl
index 40670e45d2..dc6f9072a2 100644
--- a/lib/kernel/test/erl_distribution_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_SUITE.erl
@@ -21,6 +21,8 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/dist.hrl").
+-include_lib("stdlib/include/assert.hrl").
+-include_lib("kernel/include/file.hrl").
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
@@ -34,6 +36,7 @@
setopts/1,
table_waste/1, net_setuptime/1,
inet_dist_options_options/1,
+ net_ticker_spawn_options/1,
monitor_nodes_nodedown_reason/1,
monitor_nodes_complex_nodedown_reason/1,
@@ -50,16 +53,19 @@
erl_uds_dist_smoke_test/1,
erl_1424/1, net_kernel_start/1, differing_cookies/1,
cmdline_setcookie_2/1, connection_cookie/1,
- dyn_differing_cookies/1]).
+ dyn_differing_cookies/1,
+ xdg_cookie/1]).
%% Performs the test at another node.
-export([get_socket_priorities/0,
+ get_net_ticker_fullsweep_option/1,
tick_cli_test/3, tick_cli_test1/3,
tick_serv_test/2, tick_serv_test1/1,
run_remote_test/1,
dyn_node_name_do/2,
epmd_reconnect_do/2,
setopts_do/2,
+ setopts_deadlock_test/2,
keep_conn/1, time_ping/1,
ddc_remote_run/2]).
@@ -97,6 +103,7 @@ all() ->
epmd_reconnect,
hidden_node, setopts,
table_waste, net_setuptime, inet_dist_options_options,
+ net_ticker_spawn_options,
{group, monitor_nodes},
erl_uds_dist_smoke_test,
erl_1424, net_kernel_start,
@@ -115,7 +122,8 @@ groups() ->
[differing_cookies,
cmdline_setcookie_2,
connection_cookie,
- dyn_differing_cookies]}].
+ dyn_differing_cookies,
+ xdg_cookie]}].
init_per_suite(Config) ->
start_gen_tcp_dist_test_type_server(),
@@ -213,14 +221,14 @@ tick_test(DCfg, _Config, CheckIntensityArg) ->
"-kernel net_ticktime 100 -connect_all false"),
rpc:call(ServNode, erl_distribution_SUITE, tick_serv_test, [Node, node()]),
- %% We set min/max half a second lower/higher than expected since it
- %% takes time for termination dist controller, delivery of messages
- %% scheduling of process receiving nodedown, etc...
+ %% We set min/max a second lower/higher than expected since it takes
+ %% time for termination of the dist controller, delivery of messages,
+ %% scheduling of the process receiving nodedown, etc...
{IArg, Min, Max} = case CheckIntensityArg of
false ->
- {"", 7500, 16500};
+ {"", 7000, 17000};
true ->
- {" -kernel net_tickintensity 24", 11000, 13000}
+ {" -kernel net_tickintensity 24", 10500, 13500}
end,
{ok, Node} = start_node(DCfg, Name1,
@@ -334,14 +342,14 @@ illegal(Name) ->
test_node(Name) ->
test_node(Name, false).
-test_node(Name, Illigal) ->
- test_node(Name, Illigal, "").
-test_node(Name, Illigal, ExtraArgs) ->
+test_node(Name, Illegal) ->
+ test_node(Name, Illegal, "").
+test_node(Name, Illegal, ExtraArgs) ->
ProgName = ct:get_progname(),
Command = ProgName ++ " -noinput " ++
long_or_short() ++ Name ++ ExtraArgs ++
" -eval \"net_adm:ping('" ++ atom_to_list(node()) ++ "')\"" ++
- case Illigal of
+ case Illegal of
true ->
" -eval \"timer:sleep(10000),init:stop().\"";
false ->
@@ -570,54 +578,84 @@ wait_for_names(Names, N, Wait) when N > 0 ->
dyn_node_name(Config) when is_list(Config) ->
- %%run_dist_configs(fun dyn_node_name/2, Config).
- dyn_node_name("", Config).
+ run_dist_configs(fun dyn_node_name/2, Config).
dyn_node_name(DCfg, _Config) ->
- {_N1F,Port1} = start_node_unconnected(DCfg ++ " -dist_listen false",
+ NameDomain = case net_kernel:get_state() of
+ #{name_domain := shortnames} -> "shortnames";
+ #{name_domain := longnames} -> "longnames"
+ end,
+ {_N1F,Port1} = start_node_unconnected(DCfg,
undefined, ?MODULE, run_remote_test,
- ["dyn_node_name_do", atom_to_list(node())]),
+ ["dyn_node_name_do", atom_to_list(node()),
+ NameDomain]),
0 = wait_for_port_exit(Port1),
ok.
-dyn_node_name_do(TestNode, _Args) ->
+dyn_node_name_do(TestNode, [NameDomainStr]) ->
nonode@nohost = node(),
[] = nodes(),
[] = nodes(hidden),
+ NameDomain = list_to_atom(NameDomainStr),
+ #{started := static, name_type := dynamic, name := undefined,
+ name_domain := NameDomain} = net_kernel:get_state(),
net_kernel:monitor_nodes(true, [{node_type,all}]),
net_kernel:connect_node(TestNode),
[] = nodes(),
[TestNode] = nodes(hidden),
MyName = node(),
+ false = (MyName =:= undefined),
+ false = (MyName =:= nonode@nohost),
+ #{started := static, name_type := dynamic, name := MyName,
+ name_domain := NameDomain} = net_kernel:get_state(),
check([MyName], rpc:call(TestNode, erlang, nodes, [hidden])),
- {nodeup, MyName, [{node_type, visible}]} = receive_any(0),
- {nodeup, TestNode, [{node_type, hidden}]} = receive_any(0),
+ {nodeup, MyName, [{node_type, visible}]} = receive_any(),
+ {nodeup, TestNode, [{node_type, hidden}]} = receive_any(),
true = net_kernel:disconnect(TestNode),
- {nodedown, TestNode, [{node_type, hidden}]} = receive_any(0),
- [] = nodes(hidden),
- {nodedown, MyName, [{node_type, visible}]} = receive_any(1000),
+ %% We don't know the order of these nodedown messages. Often
+ %% nodedown from the connection comes first, but not always...
+
+ NodedownMsgsA = lists:sort([{nodedown, TestNode, [{node_type, hidden}]},
+ {nodedown, MyName, [{node_type, visible}]}]),
+ NodedownMsgA1 = receive_any(),
+ NodedownMsgA2 = receive_any(),
+ NodedownMsgsA = lists:sort([NodedownMsgA1, NodedownMsgA2]),
+ [] = nodes(hidden),
nonode@nohost = node(),
+ #{started := static, name_type := dynamic, name := undefined,
+ name_domain := NameDomain} = net_kernel:get_state(),
net_kernel:connect_node(TestNode),
[] = nodes(),
[TestNode] = nodes(hidden),
MyName = node(),
+ #{started := static, name_type := dynamic, name := MyName,
+ name_domain := NameDomain} = net_kernel:get_state(),
+
check([MyName], rpc:call(TestNode, erlang, nodes, [hidden])),
- {nodeup, MyName, [{node_type, visible}]} = receive_any(0),
- {nodeup, TestNode, [{node_type, hidden}]} = receive_any(0),
+ {nodeup, MyName, [{node_type, visible}]} = receive_any(),
+ {nodeup, TestNode, [{node_type, hidden}]} = receive_any(),
true = rpc:cast(TestNode, net_kernel, disconnect, [MyName]),
- {nodedown, TestNode, [{node_type, hidden}]} = receive_any(1000),
+ %% We don't know the order of these nodedown messages. Often
+ %% nodedown from the connection comes first, but not always...
+
+ NodedownMsgsB = lists:sort([{nodedown, TestNode, [{node_type, hidden}]},
+ {nodedown, MyName, [{node_type, visible}]}]),
+ NodedownMsgB1 = receive_any(),
+ NodedownMsgB2 = receive_any(),
+ NodedownMsgsB = lists:sort([NodedownMsgB1, NodedownMsgB2]),
+
[] = nodes(hidden),
- {nodedown, MyName, [{node_type, visible}]} = receive_any(1000),
nonode@nohost = node(),
-
+ #{started := static, name_type := dynamic, name := undefined,
+ name_domain := NameDomain} = net_kernel:get_state(),
ok.
check(X, X) -> ok.
@@ -627,7 +665,7 @@ setopts(Config) when is_list(Config) ->
setopts(DCfg, _Config) ->
register(setopts_regname, self()),
- [N1,N2,N3,N4] = get_nodenames(4, setopts),
+ [N1,N2,N3,N4,N5] = get_nodenames(5, setopts),
{_N1F,Port1} = start_node_unconnected(DCfg, N1, ?MODULE, run_remote_test,
["setopts_do", atom_to_list(node()), "1", "ping"]),
@@ -652,6 +690,32 @@ setopts(DCfg, _Config) ->
wait_and_connect(LSock, N4F, Port4),
0 = wait_for_port_exit(Port4),
+ %% net_kernel:setopts(new, _) used to be able to produce a deadlock
+ %% in net_kernel. GH-6129/OTP-18198
+ {N5F,Port5} = start_node_unconnected(DCfg, N5, ?MODULE, run_remote_test,
+ ["setopts_deadlock_test", atom_to_list(node()),
+ integer_to_list(LTcpPort)]),
+ wait_and_connect(LSock, N5F, Port5),
+ repeat(fun () ->
+ receive after 10 -> ok end,
+ erlang:disconnect_node(N5F),
+ WD = spawn_link(fun () ->
+ receive after 2000 -> ok end,
+ exit({net_kernel_probably_deadlocked, N5F})
+ end),
+ pong = net_adm:ping(N5F),
+ unlink(WD),
+ exit(WD, kill),
+ false = is_process_alive(WD)
+ end,
+ 200),
+ try
+ erpc:call(N5F, erlang, halt, [])
+ catch
+ error:{erpc,noconnection} -> ok
+ end,
+ 0 = wait_for_port_exit(Port5),
+
unregister(setopts_regname),
ok.
@@ -740,6 +804,19 @@ setopts_do(TestNode, [OptNr, ConnectData]) ->
ok.
+setopts_deadlock_test(_TestNode, [TcpPort]) ->
+ {ok, Sock} = gen_tcp:connect("localhost", list_to_integer(TcpPort),
+ [{active,false},{packet,2}]),
+ ok = gen_tcp:send(Sock, "Connect please"),
+ {ok, "Connect done"} = gen_tcp:recv(Sock, 0),
+ gen_tcp:close(Sock),
+ setopts_new_loop().
+
+setopts_new_loop() ->
+ ok = net_kernel:setopts(new, [{nodelay, true}]),
+ receive after 10 -> ok end,
+ setopts_new_loop().
+
opt_from_nr("1") -> {nodelay, true};
opt_from_nr("2") -> {nodelay, false}.
@@ -978,8 +1055,14 @@ run_tick_change_test(DCfg, B, C, PrevTT, TT) ->
hidden_node(Config) when is_list(Config) ->
run_dist_configs(fun hidden_node/2, Config).
-hidden_node(DCfg, _Config) ->
- HArgs = "-hidden",
+hidden_node(DCfg, Config) ->
+ hidden_node(DCfg, "-hidden", Config),
+ hidden_node(DCfg, "-hidden -hidden", Config),
+ hidden_node(DCfg, "-hidden true -hidden true", Config),
+ ok.
+
+hidden_node(DCfg, HArgs, _Config) ->
+ ct:pal("--- Hidden argument(s): ~s~n", [HArgs]),
{ok, V} = start_node(DCfg, visible_node),
VMN = start_monitor_nodes_proc(V),
{ok, H} = start_node(DCfg, hidden_node, HArgs),
@@ -1121,6 +1204,75 @@ get_socket_priorities() ->
+%% check net_ticker_spawn_options
+net_ticker_spawn_options(Config) when is_list(Config) ->
+ run_dist_configs(fun net_ticker_spawn_options/2, Config).
+
+net_ticker_spawn_options(DCfg, Config) when is_list(Config) ->
+ FullsweepString0 = "[{fullsweep_after,0}]",
+ FullsweepString =
+ case os:cmd("echo [{a,1}]") of
+ "[{a,1}]"++_ ->
+ FullsweepString0;
+ _ ->
+ %% Some shells need quoting of [{}]
+ "'"++FullsweepString0++"'"
+ end,
+ InetDistOptions =
+ "-hidden "
+ "-kernel net_ticker_spawn_options "++FullsweepString,
+ {ok,Node1} =
+ start_node(DCfg, net_ticker_spawn_options_1, InetDistOptions),
+ {ok,Node2} =
+ start_node(DCfg, net_ticker_spawn_options_2, InetDistOptions),
+ %%
+ pong =
+ erpc:call(Node1, net_adm, ping, [Node2]),
+ FullsweepOptionNode1 =
+ erpc:call(Node1, ?MODULE, get_net_ticker_fullsweep_option, [Node2]),
+ FullsweepOptionNode2 =
+ erpc:call(Node2, ?MODULE, get_net_ticker_fullsweep_option, [Node1]),
+ io:format("FullsweepOptionNode1 = ~p", [FullsweepOptionNode1]),
+ io:format("FullsweepOptionNode2 = ~p", [FullsweepOptionNode2]),
+ 0 = FullsweepOptionNode1,
+ 0 = FullsweepOptionNode2,
+ %%
+ stop_node(Node2),
+ stop_node(Node1),
+ ok.
+
+get_net_ticker_fullsweep_option(Node) ->
+ Links = case proplists:get_value(Node, erlang:system_info(dist_ctrl)) of
+ DistCtrl when is_port(DistCtrl) ->
+ {links, Ls} = erlang:port_info(DistCtrl, links),
+ Ls;
+ DistCtrl when is_pid(DistCtrl) ->
+ {links, Ls} = process_info(DistCtrl, links),
+ Ls
+ end,
+ Ticker = try
+ lists:foreach(
+ fun (Pid) when is_pid(Pid) ->
+ {current_stacktrace, Stk}
+ = process_info(Pid, current_stacktrace),
+ lists:foreach(
+ fun ({dist_util, con_loop, _, _}) ->
+ throw(Pid);
+ (_) ->
+ ok
+ end, Stk);
+ (_) ->
+ ok
+ end, Links),
+ error(no_ticker_found)
+ catch
+ throw:Pid when is_pid(Pid) -> Pid
+ end,
+ {garbage_collection, GCOpts} = erlang:process_info(Ticker, garbage_collection),
+ proplists:get_value(fullsweep_after, GCOpts).
+
+
+
%%
%% Testcase:
%% monitor_nodes_nodedown_reason
@@ -1137,9 +1289,9 @@ monitor_nodes_nodedown_reason(DCfg, _Config) ->
Names = get_numbered_nodenames(5, node),
[NN1, NN2, NN3, NN4, NN5] = Names,
- {ok, N1} = start_node(DCfg, NN1),
- {ok, N2} = start_node(DCfg, NN2),
- {ok, N3} = start_node(DCfg, NN3),
+ {ok, N1} = start_node(DCfg, NN1, "-connect_all false"),
+ {ok, N2} = start_node(DCfg, NN2, "-connect_all false"),
+ {ok, N3} = start_node(DCfg, NN3, "-connect_all false"),
{ok, N4} = start_node(DCfg, NN4, "-hidden"),
receive {nodeup, N1} -> ok end,
@@ -1315,7 +1467,9 @@ monitor_nodes_misc(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
ok = net_kernel:monitor_nodes(true),
ok = net_kernel:monitor_nodes(true, [{node_type, all}, nodedown_reason]),
- ok = net_kernel:monitor_nodes(true, [nodedown_reason, {node_type, all}]),
+ ok = net_kernel:monitor_nodes(true, [nodedown_reason, {node_type, all}, connection_id]),
+ ok = net_kernel:monitor_nodes(true, #{node_type => all, nodedown_reason => true}),
+ ok = net_kernel:monitor_nodes(true, #{node_type => all, nodedown_reason => true, connection_id => true}),
Names = get_numbered_nodenames(3, node),
[NN1, NN2, NN3] = Names,
@@ -1324,27 +1478,90 @@ monitor_nodes_misc(DCfg, _Config) ->
receive {nodeup, N1} -> ok end,
+ receive {nodeup, N1, #{node_type := visible}} -> ok end,
+ receive {nodeup, N2, #{node_type := hidden}} -> ok end,
receive {nodeup, N1, [{node_type, visible}]} -> ok end,
- receive {nodeup, N1, [{node_type, visible}]} -> ok end,
- receive {nodeup, N2, [{node_type, hidden}]} -> ok end,
receive {nodeup, N2, [{node_type, hidden}]} -> ok end,
+ NodesInfo = erlang:nodes(connected, #{connection_id => true}),
+
+ {N1, #{connection_id := N1CId}} = lists:keyfind(N1, 1, NodesInfo),
+ {N2, #{connection_id := N2CId}} = lists:keyfind(N2, 1, NodesInfo),
+
+ ct:pal("N1: ~p ~p~n", [N1, N1CId]),
+ ct:pal("N2: ~p ~p~n", [N2, N2CId]),
+
+ receive {nodeup, N1, #{node_type := visible, connection_id := N1CId}} -> ok end,
+ receive {nodeup, N2, #{node_type := hidden, connection_id := N2CId}} -> ok end,
+
+ N1UpInfoSorted = lists:sort([{node_type, visible},{connection_id, N1CId}]),
+ N2UpInfoSorted = lists:sort([{node_type, hidden},{connection_id, N2CId}]),
+
+ receive {nodeup, N1, UpN1Info} -> N1UpInfoSorted = lists:sort(UpN1Info) end,
+ receive {nodeup, N2, UpN2Info} -> N2UpInfoSorted = lists:sort(UpN2Info) end,
+
stop_node(N1),
stop_node(N2),
- VisbleDownInfo = lists:sort([{node_type, visible},
- {nodedown_reason, connection_closed}]),
- HiddenDownInfo = lists:sort([{node_type, hidden},
- {nodedown_reason, connection_closed}]),
-
receive {nodedown, N1} -> ok end,
- receive {nodedown, N1, Info1A} -> VisbleDownInfo = lists:sort(Info1A) end,
- receive {nodedown, N1, Info1B} -> VisbleDownInfo = lists:sort(Info1B) end,
- receive {nodedown, N2, Info2A} -> HiddenDownInfo = lists:sort(Info2A) end,
- receive {nodedown, N2, Info2B} -> HiddenDownInfo = lists:sort(Info2B) end,
+ receive {nodedown, N1, #{node_type := visible,
+ nodedown_reason := connection_closed}} -> ok end,
+ receive {nodedown, N1, #{node_type := visible,
+ nodedown_reason := connection_closed,
+ connection_id := N1CId}} -> ok end,
+ receive {nodedown, N2, #{node_type := hidden,
+ nodedown_reason := connection_closed}} -> ok end,
+ receive {nodedown, N2, #{node_type := hidden,
+ nodedown_reason := connection_closed,
+ connection_id := N2CId}} -> ok end,
+
+ N1ADownInfoSorted = lists:sort([{node_type, visible},
+ {nodedown_reason, connection_closed}]),
+ N1BDownInfoSorted = lists:sort([{node_type, visible},
+ {nodedown_reason, connection_closed},
+ {connection_id, N1CId}]),
+ N2ADownInfoSorted = lists:sort([{node_type, hidden},
+ {nodedown_reason, connection_closed}]),
+ N2BDownInfoSorted = lists:sort([{node_type, hidden},
+ {nodedown_reason, connection_closed},
+ {connection_id, N2CId}]),
+
+ receive
+ {nodedown, N1, N1Info1} ->
+ case lists:sort(N1Info1) of
+ N1ADownInfoSorted ->
+ receive
+ {nodedown, N1, N1Info2} ->
+ N1BDownInfoSorted = lists:sort(N1Info2)
+ end;
+ N1BDownInfoSorted ->
+ receive
+ {nodedown, N1, N1Info2} ->
+ N1ADownInfoSorted = lists:sort(N1Info2)
+ end
+ end
+ end,
+ receive
+ {nodedown, N2, N2Info1} ->
+ case lists:sort(N2Info1) of
+ N2ADownInfoSorted ->
+ receive
+ {nodedown, N2, N2Info2} ->
+ N2BDownInfoSorted = lists:sort(N2Info2)
+ end;
+ N2BDownInfoSorted ->
+ receive
+ {nodedown, N2, N2Info2} ->
+ N2ADownInfoSorted = lists:sort(N2Info2)
+ end
+ end
+ end,
ok = net_kernel:monitor_nodes(false, [{node_type, all}, nodedown_reason]),
+ ok = net_kernel:monitor_nodes(false, [nodedown_reason, {node_type, all}, connection_id]),
+ ok = net_kernel:monitor_nodes(false, #{node_type => all, nodedown_reason => true}),
+ ok = net_kernel:monitor_nodes(false, #{node_type => all, nodedown_reason => true, connection_id => true}),
{ok, N3} = start_node(DCfg, NN3),
receive {nodeup, N3} -> ok end,
@@ -1480,7 +1697,11 @@ monitor_nodes_errors(Config) when is_list(Config) ->
[gurka]}} = net_kernel:monitor_nodes(true,
[gurka]),
{error,
- {options_not_a_list,
+ {unknown_options,
+ #{gurka := true}}} = net_kernel:monitor_nodes(true,
+ #{gurka => true}),
+ {error,
+ {invalid_options,
gurka}} = net_kernel:monitor_nodes(true,
gurka),
{error,
@@ -1502,6 +1723,10 @@ monitor_nodes_errors(Config) when is_list(Config) ->
{node_type,
blaha}}}
= net_kernel:monitor_nodes(true, [{node_type, blaha}]),
+ {error,
+ {bad_option_value,
+ #{node_type := blaha}}}
+ = net_kernel:monitor_nodes(true, #{node_type => blaha}),
MonNodeState = monitor_node_state(),
ok.
@@ -1676,14 +1901,10 @@ monitor_nodes_many(DCfg, _Config) ->
%% Test order of messages nodedown and nodeup.
monitor_nodes_down_up(Config) when is_list(Config) ->
- [An] = get_nodenames(1, monitor_nodeup),
- {ok, A} = ct_slave:start(An),
-
- try
- monitor_nodes_yoyo(A)
- after
- catch ct_slave:stop(A)
- end.
+ {ok, Peer, Node} = ?CT_PEER(#{connection => 0}),
+ true = net_kernel:connect_node(Node),
+ monitor_nodes_yoyo(Node),
+ peer:stop(Peer).
monitor_nodes_yoyo(A) ->
net_kernel:monitor_nodes(true),
@@ -2044,21 +2265,34 @@ erl_1424(Config) when is_list(Config) ->
net_kernel_start(Config) when is_list(Config) ->
MyName = net_kernel_start_tester,
register(MyName, self()),
- net_kernel_start_test(MyName, 120, 8),
- net_kernel_start_test(MyName, undefined, undefined).
+ net_kernel_start_test(MyName, 120, 8, true, false),
+ net_kernel_start_test(MyName, 120, 8, false, false),
+ net_kernel_start_test(MyName, 120, 8, true, true),
+ net_kernel_start_test(MyName, undefined, undefined, undefined, undefined).
-net_kernel_start_test(MyName, NetTickTime, NetTickIntesity) ->
+net_kernel_start_test(MyName, NetTickTime, NetTickIntesity, DistListen, Hidden) ->
TestNameStr = "net_kernel_start_test_node-"
++ integer_to_list(erlang:system_time(seconds))
++ "-" ++ integer_to_list(erlang:unique_integer([monotonic,positive])),
TestNode = list_to_atom(TestNameStr ++ "@" ++ atom_to_list(gethostname())),
CmdLine = net_kernel_start_cmdline(MyName, list_to_atom(TestNameStr),
- NetTickTime, NetTickIntesity),
+ NetTickTime, NetTickIntesity, DistListen, Hidden),
io:format("Starting test node ~p: ~s~n", [TestNode, CmdLine]),
case open_port({spawn, CmdLine}, []) of
Port when is_port(Port) ->
+ case DistListen == false of
+ false ->
+ ok;
+ true ->
+ receive after 1500 -> ok end,
+ pang = net_adm:ping(TestNode),
+ ok
+ end,
receive
{i_am_alive, Pid, Node, NTT} = Msg ->
+ IsHidden = lists:member(TestNode, nodes(hidden)),
+ IsVisible = lists:member(TestNode, nodes(visible)),
+ io:format("IsVisible = ~p~nIsHidden = ~p~n", [IsVisible, IsHidden]),
io:format("Response from ~p: ~p~n", [Node, Msg]),
rpc:cast(Node, erlang, halt, []),
catch erlang:port_close(Port),
@@ -2070,6 +2304,14 @@ net_kernel_start_test(MyName, NetTickTime, NetTickIntesity) ->
DefNTT = NTT;
false ->
NetTickTime = NTT
+ end,
+ case DistListen == false orelse Hidden == true of
+ true ->
+ true = IsHidden,
+ false = IsVisible;
+ false ->
+ false = IsHidden,
+ true = IsVisible
end
end,
ok;
@@ -2077,7 +2319,7 @@ net_kernel_start_test(MyName, NetTickTime, NetTickIntesity) ->
error({open_port_failed, TestNode, Error})
end.
-net_kernel_start_cmdline(TestName, Name, NetTickTime, NetTickIntensity) ->
+net_kernel_start_cmdline(TestName, Name, NetTickTime, NetTickIntensity, DistListen, Hidden) ->
Pa = filename:dirname(code:which(?MODULE)),
Prog = case catch init:get_argument(progname) of
{ok, [[Prg]]} -> Prg;
@@ -2101,21 +2343,36 @@ net_kernel_start_cmdline(TestName, Name, NetTickTime, NetTickIntensity) ->
false ->
" " ++ integer_to_list(NetTickTime) ++
" " ++ integer_to_list(NetTickIntensity)
+ end
+ ++ case DistListen == undefined of
+ true -> "";
+ false -> " " ++ atom_to_list(DistListen)
+ end
+ ++ case Hidden == undefined of
+ true -> "";
+ false -> " " ++ atom_to_list(Hidden)
end.
net_kernel_start_do_test([TestName, TestNode, Name, NameDomain]) ->
net_kernel_start_do_test(TestName, TestNode, list_to_atom(Name),
#{name_domain => list_to_atom(NameDomain)});
-net_kernel_start_do_test([TestName, TestNode, Name, NameDomain, NetTickTime, NetTickIntensity]) ->
+net_kernel_start_do_test([TestName, TestNode, Name, NameDomain, NetTickTime, NetTickIntensity,
+ DistListen, Hidden]) ->
net_kernel_start_do_test(TestName, TestNode, list_to_atom(Name),
#{net_ticktime => list_to_integer(NetTickTime),
name_domain => list_to_atom(NameDomain),
- net_tickintensity => list_to_integer(NetTickIntensity)}).
+ net_tickintensity => list_to_integer(NetTickIntensity),
+ dist_listen => list_to_atom(DistListen),
+ hidden => list_to_atom(Hidden)}).
net_kernel_start_do_test(TestName, TestNode, Name, Options) ->
case net_kernel:start(Name, Options) of
{ok, _Pid} ->
+ case maps:get(dist_listen, Options, true) of
+ false -> receive after 3000 -> ok end;
+ true -> ok
+ end,
Tester = {list_to_atom(TestName), list_to_atom(TestNode)},
Tester ! {i_am_alive, self(), node(), net_kernel:get_net_ticktime()},
receive after 60000 -> ok end,
@@ -2410,6 +2667,59 @@ ddc_remote_run(MotherNode, [SetCookie, MotherNodeCookieL]) ->
error({unexpected, Other})
end.
+xdg_cookie(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+
+ TestHome = filename:join(PrivDir, ?FUNCTION_NAME),
+ ok = file:make_dir(TestHome),
+
+ HomeEnv = case os:type() of
+ {win32, _} ->
+ [Drive | Path] = filename:split(TestHome),
+ [{"APPDATA", filename:join(TestHome,"AppData")},
+ {"HOMEDRIVE", Drive}, {"HOMEPATH", filename:join(Path)}];
+ _ ->
+ [{"HOME", TestHome}]
+ end,
+
+ NodeOpts = #{ env => HomeEnv ++
+ [{"ERL_CRASH_DUMP", filename:join([TestHome,"erl_crash.dump"])}],
+ connection => 0 },
+
+ %% Test that a default .erlang.cookie file is created
+ {ok, CreatorPeer, _} = peer:start_link(NodeOpts#{ name => peer:random_name(?FUNCTION_NAME) }),
+ UserConfig = peer:call(CreatorPeer, filename, basedir, [user_config,"erlang"]),
+ ?assert(peer:call(CreatorPeer, filelib, is_regular,
+ [filename:join(TestHome, ".erlang.cookie")])),
+ OrigCookie = peer:call(CreatorPeer, erlang, get_cookie, []),
+ peer:stop(CreatorPeer),
+
+ %% Test that the $HOME/.erlang.cookie file takes precedence over XDG
+ XDGCookie = filename:join([UserConfig, ".erlang.cookie"]),
+ ok = filelib:ensure_dir(XDGCookie),
+ ok = file:write_file(XDGCookie, "Me want cookie!"),
+ {ok, XDGFI} = file:read_file_info(XDGCookie),
+ ok = file:write_file_info(XDGCookie, XDGFI#file_info{ mode = 8#600 }),
+
+ {ok, Peer, _} = peer:start_link(NodeOpts#{ name => peer:random_name(?FUNCTION_NAME) }),
+
+ ?assertEqual(OrigCookie, peer:call(Peer, erlang, get_cookie, [])),
+
+ peer:stop(Peer),
+
+ %% Check that XDG cookie works after we delete the $HOME cookie
+ HomeCookie = filename:join(TestHome, ".erlang.cookie"),
+ {ok, HomeFI} = file:read_file_info(HomeCookie),
+ ok = file:write_file_info(HomeCookie, HomeFI#file_info{ mode = 8#777 }),
+ ok = file:delete(HomeCookie),
+ {ok, Peer2, _} = peer:start_link(NodeOpts#{ name => peer:random_name(?FUNCTION_NAME) }),
+ ?assertEqual('Me want cookie!', peer:call(Peer2, erlang, get_cookie, [])),
+
+ peer:stop(Peer2),
+
+ ok.
+
+
%% Misc. functions