summaryrefslogtreecommitdiff
path: root/erts/emulator/test
diff options
context:
space:
mode:
authorRickard Green <rickard@erlang.org>2023-04-29 00:30:12 +0200
committerRickard Green <rickard@erlang.org>2023-04-29 00:59:16 +0200
commit330b119be68f95f6f8fbdef8bf16bba314783973 (patch)
treef78d545d1f7f2ff98410150028981f14e9f527b5 /erts/emulator/test
parent3002f55f409f44122d3a45ac53bfd453e9aa2cb2 (diff)
downloaderlang-330b119be68f95f6f8fbdef8bf16bba314783973.tar.gz
[erts] ensure no mix of external and internal identifiers
Silently reject proposed creation and select another one when a node goes alive if there are external identifiers in the system with the proposed creation and the same node name that are to be used. Such identifiers would not work as expected in various situations, and are not from the instance of the node that are about to go alive.
Diffstat (limited to 'erts/emulator/test')
-rw-r--r--erts/emulator/test/distribution_SUITE.erl123
1 files changed, 121 insertions, 2 deletions
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index 128c9b07e0..61d9ced3b5 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -75,7 +75,9 @@
system_limit/1,
hopefull_data_encoding/1,
hopefull_export_fun_bug/1,
- huge_iovec/1]).
+ huge_iovec/1,
+ creation_selection/1,
+ creation_selection_test/1]).
%% Internal exports.
-export([sender/3, receiver2/2, dummy_waiter/0, dead_process/0,
@@ -106,7 +108,7 @@ all() ->
{group, bad_dist}, {group, bad_dist_ext},
start_epmd_false, epmd_module, system_limit,
hopefull_data_encoding, hopefull_export_fun_bug,
- huge_iovec].
+ huge_iovec, creation_selection].
groups() ->
[{bulk_send, [], [bulk_send_small, bulk_send_big, bulk_send_bigbig]},
@@ -2810,9 +2812,126 @@ mk_rand_bin(0, Data) ->
mk_rand_bin(N, Data) ->
mk_rand_bin(N-1, [rand:uniform(256) - 1 | Data]).
+creation_selection(Config) when is_list(Config) ->
+ register(creation_selection_test_supervisor, self()),
+ Name = atom_to_list(?FUNCTION_NAME) ++ "-"
+ ++ integer_to_list(erlang:system_time()),
+ Host = hostname(),
+ Cmd = lists:append(
+ [ct:get_progname(),
+ " -noshell",
+ " -setcookie ", atom_to_list(erlang:get_cookie()),
+ " -pa ", filename:dirname(code:which(?MODULE)),
+ " -s ", atom_to_list(?MODULE), " ",
+ " creation_selection_test ", atom_to_list(node()), " ",
+ atom_to_list(net_kernel:longnames()), " ", Name, " ", Host]),
+ ct:pal("Node command: ~p~n", [Cmd]),
+ Port = open_port({spawn, Cmd}, [exit_status]),
+ Node = list_to_atom(lists:append([Name, "@", Host])),
+ ok = receive_creation_selection_info(Port, Node).
+
+receive_creation_selection_info(Port, Node) ->
+ receive
+ {creation_selection_test, Node, Creations, InvalidCreation,
+ ClashResolvedCreation} = Msg ->
+ ct:log("Test result: ~p~n", [Msg]),
+ %% Verify that creation values are created as expected. The
+ %% list of creations is in reverse start order...
+ MaxC = (1 bsl 32) - 1,
+ MinC = 4,
+ StartOrderCreations = lists:reverse(Creations),
+ InvalidCreation = lists:foldl(fun (C, C) when is_integer(C),
+ MinC =< C,
+ C =< MaxC ->
+ %% Return next expected
+ %% creation...
+ if C == MaxC -> MinC;
+ true -> C+1
+ end
+ end,
+ hd(StartOrderCreations),
+ StartOrderCreations),
+ false = lists:member(ClashResolvedCreation, [InvalidCreation
+ | Creations]),
+ receive
+ {Port, {exit_status, 0}} ->
+ Port ! {self(), close},
+ ok;
+ {Port, {exit_status, EStat}} ->
+ ct:fail({"node exited abnormally: ", EStat})
+ end;
+ {Port, {exit_status, EStat}} ->
+ ct:fail({"node prematurely exited: ", EStat});
+ {Port, {data, Data}} ->
+ ct:log("~ts", [Data]),
+ receive_creation_selection_info(Port, Node)
+ end,
+ ok.
+
+creation_selection_test([TestSupNode, LongNames, Name, Host]) ->
+ try
+ StartArgs = [Name,
+ case LongNames of
+ true -> longnames;
+ false -> shortnames
+ end],
+ Node = list_to_atom(lists:append([atom_to_list(Name),
+ "@", atom_to_list(Host)])),
+ GoDistributed = fun (F) ->
+ {ok, _} = net_kernel:start(StartArgs),
+ Node = node(),
+ Creation = erlang:system_info(creation),
+ _ = F(Creation),
+ net_kernel:stop(),
+ Creation
+ end,
+ %% We start multiple times to verify that the creation values
+ %% we get from epmd are delivered in sequence. This is a
+ %% must for the test case such as it is written now, but can be
+ %% changed. If changed, this test case must be updated...
+ {Creations,
+ LastCreation} = lists:foldl(fun (_, {Cs, _LC}) ->
+ CFun = fun (X) -> X end,
+ C = GoDistributed(CFun),
+ {[C|Cs], C}
+ end, {[], 0}, lists:seq(1, 5)),
+ %% We create a pid with the creation that epmd will offer us the next
+ %% time we start the distribution and then start the distribution
+ %% once more. The node should avoid this creation, since this would
+ %% cause external identifiers in the system with same
+ %% nodename/creation pair as used by the local node, which in turn
+ %% would cause these identifers not to work as expected. That is, the
+ %% node should silently reject this creation and chose another one when
+ %% starting the distribution.
+ InvalidCreation = LastCreation+1,
+ Pid = erts_test_utils:mk_ext_pid({Node, InvalidCreation}, 4711, 0),
+ true = erts_debug:size(Pid) > 0, %% External pid
+ ResultFun = fun (ClashResolvedCreation) ->
+ pong = net_adm:ping(TestSupNode),
+ Msg = {creation_selection_test, node(), Creations,
+ InvalidCreation, ClashResolvedCreation},
+ {creation_selection_test_supervisor, TestSupNode}
+ ! Msg,
+ %% Wait a bit so the message have time to get
+ %% through before we take down the distribution...
+ receive after 500 -> ok end
+ end,
+ _ = GoDistributed(ResultFun),
+ %% Ensure Pid is not garbage collected before starting the
+ %% distribution...
+ _ = id(Pid),
+ erlang:halt(0)
+ catch
+ Class:Reason:StackTrace ->
+ erlang:display({Class, Reason, StackTrace}),
+ erlang:halt(17)
+ end.
%%% Utilities
+id(X) ->
+ X.
+
timestamp() ->
erlang:monotonic_time(millisecond).