aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test')
-rw-r--r--lib/kernel/test/code_SUITE.erl94
-rw-r--r--lib/kernel/test/erl_distribution_SUITE.erl163
-rw-r--r--lib/kernel/test/file_SUITE.erl54
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl148
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl21
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c2
-rw-r--r--lib/kernel/test/init_SUITE.erl61
-rw-r--r--lib/kernel/test/os_SUITE.erl19
-rw-r--r--lib/kernel/test/os_SUITE_data/Makefile.src8
-rw-r--r--lib/kernel/test/os_SUITE_data/my_fds.c9
-rw-r--r--lib/kernel/test/zlib_SUITE.erl38
11 files changed, 519 insertions, 98 deletions
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 8da67c89f8..c5167efa56 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -36,6 +36,7 @@
code_archive/1, code_archive2/1, on_load/1, on_load_binary/1,
on_load_embedded/1, on_load_errors/1, on_load_update/1,
on_load_purge/1, on_load_self_call/1, on_load_pending/1,
+ on_load_deleted/1,
big_boot_embedded/1,
native_early_modules/1, get_mode/1,
normalized_paths/1]).
@@ -66,6 +67,7 @@ all() ->
bad_erl_libs, code_archive, code_archive2, on_load,
on_load_binary, on_load_embedded, on_load_errors, on_load_update,
on_load_purge, on_load_self_call, on_load_pending,
+ on_load_deleted,
big_boot_embedded, native_early_modules, get_mode, normalized_paths].
groups() ->
@@ -1602,6 +1604,98 @@ on_load_pending(_Config) ->
ok = Mod:t(),
ok.
+on_load_deleted(_Config) ->
+ Mod = ?FUNCTION_NAME,
+
+ R0 = fun() ->
+ Tree = ?Q(["-module('@Mod@').\n",
+ "-on_load(f/0).\n",
+ "f() -> ok.\n"]),
+ merl:print(Tree),
+ {ok,Mod,Code} = merl:compile(Tree),
+ {module,Mod} = code:load_binary(Mod, "", Code)
+ end,
+ delete_before_reload(Mod, R0),
+ delete_before_reload(Mod, R0),
+
+ R1 = fun() ->
+ Tree = ?Q(["-module('@Mod@').\n",
+ "-on_load(f/0).\n",
+ "f() -> fail.\n"]),
+ merl:print(Tree),
+ {ok,Mod,Code} = merl:compile(Tree),
+ {error,on_load_failure} = code:load_binary(Mod, "", Code)
+ end,
+ delete_before_reload(Mod, R1),
+ delete_before_reload(Mod, R1),
+
+ OtherMod = list_to_atom(lists:concat([Mod,"_42"])),
+ OtherTree = ?Q(["-module('@OtherMod@').\n"]),
+ merl:print(OtherTree),
+ {ok,OtherMod,OtherCode} = merl:compile(OtherTree),
+
+ R2 = fun() ->
+ RegName = 'on_load__registered_name',
+ Tree = ?Q(["-module('@Mod@').\n",
+ "-on_load(f/0).\n",
+ "f() ->\n",
+ " register('@RegName@', self()),\n",
+ " receive _ -> ok end.\n"]),
+ merl:print(Tree),
+ {ok,Mod,Code} = merl:compile(Tree),
+ spawn(fun() ->
+ {module,Mod} = code:load_binary(Mod, "", Code)
+ end),
+ receive after 1 -> ok end,
+ {module,OtherMod} = code:load_binary(OtherMod, "",
+ OtherCode),
+ RegName ! stop
+ end,
+ delete_before_reload(Mod, R2),
+
+ ok.
+
+delete_before_reload(Mod, Reload) ->
+ false = check_old_code(Mod),
+
+ Tree1 = ?Q(["-module('@Mod@').\n",
+ "-export([f/1]).\n",
+ "f(Parent) ->\n",
+ " register('@Mod@', self()),\n",
+ " Parent ! started,\n",
+ " receive _ -> ok end.\n"]),
+ merl:print(Tree1),
+ {ok,Mod,Code1} = merl:compile(Tree1),
+
+ Self = self(),
+ spawn(fun() ->
+ {module,Mod} = code:load_binary(Mod, "", Code1),
+ Mod:f(Self)
+ end),
+ receive started -> ok end,
+
+ true = code:delete(Mod),
+ true = check_old_code(Mod),
+
+ Reload(),
+
+ %% When loading the the module with the -on_load() function,
+ %% the reference to the old code would be lost. Make sure that
+ %% the old code is remembered and is still preventing the
+ %% purge.
+ false = code:soft_purge(Mod),
+
+ %% Get rid of the old code.
+ Mod ! stop,
+ receive after 1 -> ok end,
+ true = code:soft_purge(Mod),
+
+ %% Unload the version of the module with the -on_load() function.
+ true = code:delete(Mod),
+ true = code:soft_purge(Mod),
+
+ ok.
+
%% Test that the native code of early loaded modules is loaded.
native_early_modules(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl
index bd62096684..f630896e03 100644
--- a/lib/kernel/test/erl_distribution_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_SUITE.erl
@@ -25,6 +25,7 @@
init_per_group/2,end_per_group/2]).
-export([tick/1, tick_change/1, illegal_nodenames/1, hidden_node/1,
+ setopts/1,
table_waste/1, net_setuptime/1,
inet_dist_options_options/1,
@@ -42,6 +43,8 @@
-export([get_socket_priorities/0,
tick_cli_test/1, tick_cli_test1/1,
tick_serv_test/2, tick_serv_test1/1,
+ run_remote_test/1,
+ setopts_do/2,
keep_conn/1, time_ping/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -66,6 +69,7 @@ suite() ->
all() ->
[tick, tick_change, illegal_nodenames, hidden_node,
+ setopts,
table_waste, net_setuptime, inet_dist_options_options,
{group, monitor_nodes}].
@@ -282,6 +286,165 @@ tick_cli_test1(Node) ->
end
end.
+setopts(Config) when is_list(Config) ->
+ register(setopts_regname, self()),
+ [N1,N2,N3,N4] = get_nodenames(4, setopts),
+
+ {_N1F,Port1} = start_node_unconnected(N1, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()), "1", "ping"]),
+ 0 = wait_for_port_exit(Port1),
+
+ {_N2F,Port2} = start_node_unconnected(N2, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()), "2", "ping"]),
+ 0 = wait_for_port_exit(Port2),
+
+ {ok, LSock} = gen_tcp:listen(0, [{packet,2}, {active,false}]),
+ {ok, LTcpPort} = inet:port(LSock),
+
+ {N3F,Port3} = start_node_unconnected(N3, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()),
+ "1", integer_to_list(LTcpPort)]),
+ wait_and_connect(LSock, N3F, Port3),
+ 0 = wait_for_port_exit(Port3),
+
+ {N4F,Port4} = start_node_unconnected(N4, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()),
+ "2", integer_to_list(LTcpPort)]),
+ wait_and_connect(LSock, N4F, Port4),
+ 0 = wait_for_port_exit(Port4),
+
+ ok.
+
+wait_and_connect(LSock, NodeName, NodePort) ->
+ {ok, Sock} = gen_tcp:accept(LSock),
+ {ok, "Connect please"} = gen_tcp:recv(Sock, 0),
+ flush_from_port(NodePort),
+ pong = net_adm:ping(NodeName),
+ gen_tcp:send(Sock, "Connect done"),
+ gen_tcp:close(Sock).
+
+
+flush_from_port(Port) ->
+ flush_from_port(Port, 10).
+
+flush_from_port(Port, Timeout) ->
+ receive
+ {Port,{data,String}} ->
+ io:format("~p: ~s\n", [Port, String]),
+ flush_from_port(Port, Timeout)
+ after Timeout ->
+ timeout
+ end.
+
+wait_for_port_exit(Port) ->
+ case (receive M -> M end) of
+ {Port,{exit_status,Status}} ->
+ Status;
+ {Port,{data,String}} ->
+ io:format("~p: ~s\n", [Port, String]),
+ wait_for_port_exit(Port)
+ end.
+
+run_remote_test([FuncStr, TestNodeStr | Args]) ->
+ Status = try
+ io:format("Node ~p started~n", [node()]),
+ TestNode = list_to_atom(TestNodeStr),
+ io:format("Node ~p spawning function ~p~n", [node(), FuncStr]),
+ {Pid,Ref} = spawn_monitor(?MODULE, list_to_atom(FuncStr), [TestNode, Args]),
+ io:format("Node ~p waiting for function ~p~n", [node(), FuncStr]),
+ receive
+ {'DOWN', Ref, process, Pid, normal} ->
+ 0;
+ Other ->
+ io:format("Node ~p got unexpected msg: ~p\n",[node(), Other]),
+ 1
+ end
+ catch
+ C:E ->
+ io:format("Node ~p got EXCEPTION ~p:~p\nat ~p\n",
+ [node(), C, E, erlang:get_stacktrace()]),
+ 2
+ end,
+ io:format("Node ~p doing halt(~p).\n",[node(), Status]),
+ erlang:halt(Status).
+
+% Do the actual test on the remote node
+setopts_do(TestNode, [OptNr, ConnectData]) ->
+ [] = nodes(),
+ {Opt, Val} = opt_from_nr(OptNr),
+ ok = net_kernel:setopts(new, [{Opt, Val}]),
+
+ [] = nodes(),
+ {error, noconnection} = net_kernel:getopts(TestNode, [Opt]),
+
+ case ConnectData of
+ "ping" -> % We connect
+ net_adm:ping(TestNode);
+ TcpPort -> % Other connect
+ {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)
+ end,
+ [TestNode] = nodes(),
+ {ok, [{Opt,Val}]} = net_kernel:getopts(TestNode, [Opt]),
+ {error, noconnection} = net_kernel:getopts('pixie@fairyland', [Opt]),
+
+ NewVal = change_val(Val),
+ ok = net_kernel:setopts(TestNode, [{Opt, NewVal}]),
+ {ok, [{Opt,NewVal}]} = net_kernel:getopts(TestNode, [Opt]),
+
+ ok = net_kernel:setopts(TestNode, [{Opt, Val}]),
+ {ok, [{Opt,Val}]} = net_kernel:getopts(TestNode, [Opt]),
+
+ ok.
+
+opt_from_nr("1") -> {nodelay, true};
+opt_from_nr("2") -> {nodelay, false}.
+
+change_val(true) -> false;
+change_val(false) -> true.
+
+start_node_unconnected(Name, Mod, Func, Args) ->
+ FullName = full_node_name(Name),
+ CmdLine = mk_node_cmdline(Name,Mod,Func,Args),
+ io:format("Starting node ~p: ~s~n", [FullName, CmdLine]),
+ case open_port({spawn, CmdLine}, [exit_status]) of
+ Port when is_port(Port) ->
+ {FullName, Port};
+ Error ->
+ exit({failed_to_start_node, FullName, Error})
+ end.
+
+full_node_name(PreName) ->
+ HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end,
+ atom_to_list(node())),
+ list_to_atom(atom_to_list(PreName) ++ HostSuffix).
+
+mk_node_cmdline(Name,Mod,Func,Args) ->
+ Static = "-noinput",
+ Pa = filename:dirname(code:which(?MODULE)),
+ Prog = case catch init:get_argument(progname) of
+ {ok,[[P]]} -> P;
+ _ -> exit(no_progname_argument_found)
+ end,
+ NameSw = case net_kernel:longnames() of
+ false -> "-sname ";
+ true -> "-name ";
+ _ -> exit(not_distributed_node)
+ end,
+ {ok, Pwd} = file:get_cwd(),
+ NameStr = atom_to_list(Name),
+ Prog ++ " "
+ ++ Static ++ " "
+ ++ NameSw ++ " " ++ NameStr
+ ++ " -pa " ++ Pa
+ ++ " -env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr
+ ++ " -setcookie " ++ atom_to_list(erlang:get_cookie())
+ ++ " -run " ++ atom_to_list(Mod) ++ " " ++ atom_to_list(Func)
+ ++ " " ++ string:join(Args, " ").
+
%% OTP-4255.
tick_change(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 375899987e..f2094431d8 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -493,22 +493,13 @@ read_write_file(Config) when is_list(Config) ->
%% Try writing and reading back some term
SomeTerm = {"This term",{will,be},[written,$t,$o],1,file,[]},
- ok = ?FILE_MODULE:write_file(Name,term_to_binary(SomeTerm)),
- {ok,Bin1} = ?FILE_MODULE:read_file(Name),
- SomeTerm = binary_to_term(Bin1),
+ Bin1 = term_to_binary(SomeTerm),
+ ok = do_read_write_file(Name, Bin1),
%% Try a "null" term
NullTerm = [],
- ok = ?FILE_MODULE:write_file(Name,term_to_binary(NullTerm)),
- {ok,Bin2} = ?FILE_MODULE:read_file(Name),
- NullTerm = binary_to_term(Bin2),
-
- %% Try some "complicated" types
- BigNum = 123456789012345678901234567890,
- ComplTerm = {self(),make_ref(),BigNum,3.14159},
- ok = ?FILE_MODULE:write_file(Name,term_to_binary(ComplTerm)),
- {ok,Bin3} = ?FILE_MODULE:read_file(Name),
- ComplTerm = binary_to_term(Bin3),
+ Bin2 = term_to_binary(NullTerm),
+ ok = do_read_write_file(Name, Bin2),
%% Try reading a nonexistent file
Name2 = filename:join(RootDir,
@@ -519,25 +510,42 @@ read_write_file(Config) when is_list(Config) ->
{error, enoent} = ?FILE_MODULE:read_file(''),
%% Try writing to a bad filename
- {error, enoent} =
- ?FILE_MODULE:write_file("",term_to_binary(NullTerm)),
+ {error, enoent} = do_read_write_file("", Bin2),
%% Try writing something else than a binary
- {error, badarg} = ?FILE_MODULE:write_file(Name,{1,2,3}),
- {error, badarg} = ?FILE_MODULE:write_file(Name,self()),
+ {error, badarg} = do_read_write_file(Name, {1,2,3}),
+ {error, badarg} = do_read_write_file(Name, self()),
%% Some non-term binaries
- ok = ?FILE_MODULE:write_file(Name,[]),
- {ok,Bin4} = ?FILE_MODULE:read_file(Name),
- 0 = byte_size(Bin4),
+ ok = do_read_write_file(Name, []),
- ok = ?FILE_MODULE:write_file(Name,[Bin1,[],[[Bin2]]]),
- {ok,Bin5} = ?FILE_MODULE:read_file(Name),
- {Bin1,Bin2} = split_binary(Bin5,byte_size(Bin1)),
+ %% Write some iolists
+ ok = do_read_write_file(Name, [Bin1,[],[[Bin2]]]),
+ ok = do_read_write_file(Name, ["string",<<"binary">>]),
+ ok = do_read_write_file(Name, "pure string"),
[] = flush(),
ok.
+do_read_write_file(Name, Data) ->
+ case ?FILE_MODULE:write_file(Name, Data) of
+ ok ->
+ BinData = iolist_to_binary(Data),
+ {ok,BinData} = ?FILE_MODULE:read_file(Name),
+
+ ok = ?FILE_MODULE:write_file(Name, Data, []),
+ {ok,BinData} = ?FILE_MODULE:read_file(Name),
+
+ ok = ?FILE_MODULE:write_file(Name, Data, [raw]),
+ {ok,BinData} = ?FILE_MODULE:read_file(Name),
+
+ ok;
+ {error,_}=Res ->
+ Res = ?FILE_MODULE:write_file(Name, Data, []),
+ Res = ?FILE_MODULE:write_file(Name, Data, [raw]),
+ Res
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index f836b2aa94..620ab235a0 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -117,7 +117,11 @@ xfer_min(Config) when is_list(Config) ->
Stream = 0,
Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>,
Loopback = {127,0,0,1},
+ StatOpts =
+ [recv_avg,recv_cnt,recv_max,recv_oct,
+ send_avg,send_cnt,send_max,send_oct],
{ok,Sb} = gen_sctp:open([{type,seqpacket}]),
+ {ok,SbStat1} = inet:getstat(Sb, StatOpts),
{ok,Pb} = inet:port(Sb),
ok = gen_sctp:listen(Sb, true),
@@ -212,6 +216,8 @@ xfer_min(Config) when is_list(Config) ->
assoc_id=SbAssocId}} =
recv_event(log_ok(gen_sctp:recv(Sb, infinity))),
ok = gen_sctp:close(Sa),
+ {ok,SbStat2} = inet:getstat(Sb, StatOpts),
+ [] = filter_stat_eq(SbStat1, SbStat2),
ok = gen_sctp:close(Sb),
receive
@@ -220,6 +226,18 @@ xfer_min(Config) when is_list(Config) ->
end,
ok.
+filter_stat_eq([], []) ->
+ [];
+filter_stat_eq([{Tag,Val1}=Stat|SbStat1], [{Tag,Val2}|SbStat2]) ->
+ if
+ Val1 == Val2 ->
+ [Stat|filter_stat_eq(SbStat1, SbStat2)];
+ true ->
+ filter_stat_eq(SbStat1, SbStat2)
+ end.
+
+
+
%% Minimal data transfer in active mode.
xfer_active(Config) when is_list(Config) ->
Timeout = 2000,
@@ -383,26 +401,28 @@ def_sndrcvinfo(Config) when is_list(Config) ->
assoc_id=S2AssocId} = S2AssocChange =
log_ok(gen_sctp:connect(S2, Loopback, P1, [])),
?LOGVAR(S2AssocChange),
- case recv_event(log_ok(gen_sctp:recv(S1))) of
- {Loopback,P2,
- #sctp_assoc_change{
- state=comm_up,
- error=0,
- assoc_id=S1AssocId}} ->
- ?LOGVAR(S1AssocId);
- {Loopback,P2,
- #sctp_paddr_change{
- state=addr_confirmed,
- error=0,
- assoc_id=S1AssocId}} ->
- ?LOGVAR(S1AssocId),
+ S1AssocId =
+ case recv_event(log_ok(gen_sctp:recv(S1))) of
{Loopback,P2,
#sctp_assoc_change{
state=comm_up,
error=0,
- assoc_id=S1AssocId}} =
- recv_event(log_ok(gen_sctp:recv(S1)))
- end,
+ assoc_id=AssocId}} ->
+ AssocId;
+ {Loopback,P2,
+ #sctp_paddr_change{
+ state=addr_confirmed,
+ error=0,
+ assoc_id=AssocId}} ->
+ {Loopback,P2,
+ #sctp_assoc_change{
+ state=comm_up,
+ error=0,
+ assoc_id=AssocId}} =
+ recv_event(log_ok(gen_sctp:recv(S1))),
+ AssocId
+ end,
+ ?LOGVAR(S1AssocId),
#sctp_sndrcvinfo{
ppid=17, context=0, timetolive=0} = %, assoc_id=S1AssocId} =
@@ -1055,6 +1075,7 @@ peeloff(Config, SockOpts) when is_list(Config) ->
Addr = {127,0,0,1},
Stream = 0,
Timeout = 333,
+ StartTime = timestamp(),
S1 = socket_open([{ifaddr,Addr}|SockOpts], Timeout),
?LOGVAR(S1),
P1 = socket_call(S1, get_port),
@@ -1077,7 +1098,7 @@ peeloff(Config, SockOpts) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId2}}} -> AssocId2
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
?LOGVAR(S2Ai),
S1Ai =
@@ -1087,7 +1108,7 @@ peeloff(Config, SockOpts) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId1}}} -> AssocId1
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
?LOGVAR(S1Ai),
%%
@@ -1095,13 +1116,13 @@ peeloff(Config, SockOpts) when is_list(Config) ->
receive
{S1,{Addr,P2,S1Ai,Stream,<<"Number one">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
socket_call(S2, {send,Socket1,S1Ai,Stream,<<"Number two">>}),
receive
{S2,{Addr,P1,S2Ai,Stream,<<"Number two">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
%%
S3 = socket_peeloff(Socket1, S1Ai, SockOpts, Timeout),
@@ -1120,31 +1141,31 @@ peeloff(Config, SockOpts) when is_list(Config) ->
receive
{S2,{Addr,P3,S2Ai,Stream,<<"Number three">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2,S3])
+ socket_bailout([S1,S2,S3], StartTime)
end,
socket_call(S3, {send,Socket2,S2Ai,Stream,<<"Number four">>}),
receive
{S3,{Addr,P2,S3Ai,Stream,<<"Number four">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2,S3])
+ socket_bailout([S1,S2,S3], StartTime)
end,
%%
inet:i(sctp),
- socket_close_verbose(S1),
- socket_close_verbose(S2),
+ socket_close_verbose(S1, StartTime),
+ socket_close_verbose(S2, StartTime),
receive
{S3,{Addr,P2,#sctp_shutdown_event{assoc_id=S3Ai_X}}} ->
match_unless_solaris(S3Ai, S3Ai_X)
after Timeout ->
- socket_bailout([S3])
+ socket_bailout([S3], StartTime)
end,
receive
{S3,{Addr,P2,#sctp_assoc_change{state=shutdown_comp,
assoc_id=S3Ai}}} -> ok
after Timeout ->
- socket_bailout([S3])
+ socket_bailout([S3], StartTime)
end,
- socket_close_verbose(S3),
+ socket_close_verbose(S3, StartTime),
[] = flush(),
ok.
@@ -1156,6 +1177,7 @@ buffers(Config) when is_list(Config) ->
Addr = {127,0,0,1},
Stream = 1,
Timeout = 3333,
+ StartTime = timestamp(),
S1 = socket_open([{ip,Addr}], Timeout),
?LOGVAR(S1),
P1 = socket_call(S1, get_port),
@@ -1174,7 +1196,7 @@ buffers(Config) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId2}}} -> AssocId2
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
S1Ai =
receive
@@ -1183,7 +1205,7 @@ buffers(Config) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId1}}} -> AssocId1
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
%%
socket_call(S1, {setopts,[{recbuf,Limit}]}),
@@ -1197,22 +1219,22 @@ buffers(Config) when is_list(Config) ->
receive
{S1,{Addr,P2,S1Ai,Stream,Data}} -> ok
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
%%
- socket_close_verbose(S1),
+ socket_close_verbose(S1, StartTime),
receive
{S2,{Addr,P1,#sctp_shutdown_event{assoc_id=S2Ai}}} -> ok
after Timeout ->
- socket_bailout([S2])
+ socket_bailout([S2], StartTime)
end,
receive
{S2,{Addr,P1,#sctp_assoc_change{state=shutdown_comp,
assoc_id=S2Ai}}} -> ok
after Timeout ->
- socket_bailout([S2])
+ socket_bailout([S2], StartTime)
end,
- socket_close_verbose(S2),
+ socket_close_verbose(S2, StartTime),
[] = flush(),
ok.
@@ -1521,8 +1543,8 @@ socket_peeloff(Socket, AssocId, SocketOpts, Timeout) ->
end,
s_start(Starter, Timeout).
-socket_close_verbose(S) ->
- History = socket_history(socket_close(S)),
+socket_close_verbose(S, StartTime) ->
+ History = socket_history(socket_close(S), StartTime),
io:format("socket_close ~p:~n ~p.~n", [S,History]),
History.
@@ -1535,19 +1557,19 @@ socket_call(S, Request) ->
%% socket_get(S, Key) ->
%% s_req(S, {get,Key}).
-socket_bailout([S|Ss]) ->
- History = socket_history(socket_close(S)),
+socket_bailout([S|Ss], StartTime) ->
+ History = socket_history(socket_close(S), StartTime),
io:format("bailout ~p:~n ~p.~n", [S,History]),
- socket_bailout(Ss);
-socket_bailout([]) ->
+ socket_bailout(Ss, StartTime);
+socket_bailout([], _) ->
io:format("flush: ~p.~n", [flush()]),
ct:fail(socket_bailout).
-socket_history({State,Flush}) ->
+socket_history({State,Flush}, StartTime) ->
{lists:keysort(
2,
lists:flatten(
- [[{Key,Val} || Val <- Vals]
+ [[{Key,{TS-StartTime,Val}} || {TS,Val} <- Vals]
|| {Key,Vals} <- gb_trees:to_list(State)])),
Flush}.
@@ -1610,14 +1632,12 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
{Parent,Ref,exit} ->
ok = gen_sctp:close(Socket),
Key = exit,
- Val = {now(),Socket},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, Socket, State),
Parent ! {self(),Ref,{NewState,flush()}};
{Parent,Ref,{Msg}} ->
Result = Handler(Msg),
Key = req,
- Val = {now(),{Msg,Result}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Msg,Result}, State),
Parent ! {self(),Ref,Result},
s_loop(Socket, Timeout, Parent, Handler, NewState);
%% {Parent,Ref,{get,Key}} ->
@@ -1627,16 +1647,15 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
{[#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}=SRI],Data}}
when not is_tuple(Data) ->
case gb_get({assoc_change,AssocId}, State) of
- [{_,{Addr,Port,
- #sctp_assoc_change{
- state=comm_up,
- inbound_streams=Is}}}|_]
+ [{Addr,Port,
+ #sctp_assoc_change{
+ state=comm_up,
+ inbound_streams=Is}}|_]
when 0 =< Stream, Stream < Is-> ok;
[] -> ok
end,
Key = {msg,AssocId,Stream},
- Val = {now(),{Addr,Port,SRI,Data}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port,SRI,Data}, State),
Parent ! {self(),{Addr,Port,AssocId,Stream,Data}},
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
@@ -1647,13 +1666,12 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
[] -> ok
end,
Key = {assoc_change,AssocId},
- Val = {now(),{Addr,Port,SAC}},
case {gb_get(Key, State),St} of
{[],_} -> ok;
- {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_}
+ {[{Addr,Port,#sctp_assoc_change{state=comm_up}}|_],_}
when St =:= comm_lost; St =:= shutdown_comp -> ok
end,
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port,SAC}, State),
Parent ! {self(),{Addr,Port,SAC}},
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
@@ -1667,14 +1685,13 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
[] -> ok
end,
case {gb_get({assoc_change,AssocId}, State),St} of
- {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_}
+ {[{Addr,Port,#sctp_assoc_change{state=comm_up}}|_],_}
when St =:= addr_available;
St =:= addr_confirmed -> ok;
{[],addr_confirmed} -> ok
end,
Key = {paddr_change,AssocId},
- Val = {now(),{Addr,Port,SPC}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port,SPC}, State),
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
{sctp,Socket,Addr,Port,
@@ -1684,12 +1701,11 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
[] -> ok
end,
case gb_get({assoc_change,AssocId}, State) of
- [{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_] -> ok;
+ [{Addr,Port,#sctp_assoc_change{state=comm_up}}|_] -> ok;
[] -> ok
end,
Key = {shutdown_event,AssocId},
- Val = {now(),{Addr,Port}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port}, State),
Parent ! {self(), {Addr,Port,SSE}},
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
@@ -1707,11 +1723,12 @@ again(Socket) ->
end.
gb_push(Key, Val, GBT) ->
+ TS = timestamp(),
case gb_trees:lookup(Key, GBT) of
none ->
- gb_trees:insert(Key, [Val], GBT);
+ gb_trees:insert(Key, [{TS,Val}], GBT);
{value,V} ->
- gb_trees:update(Key, [Val|V], GBT)
+ gb_trees:update(Key, [{TS,Val}|V], GBT)
end.
gb_get(Key, GBT) ->
@@ -1719,7 +1736,7 @@ gb_get(Key, GBT) ->
none ->
[];
{value,V} ->
- V
+ [Val || {_TS,Val} <- V]
end.
match_unless_solaris(A, B) ->
@@ -1727,3 +1744,6 @@ match_unless_solaris(A, B) ->
{unix,sunos} -> B;
_ -> A = B
end.
+
+timestamp() ->
+ erlang:monotonic_time().
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index 77ec89b4f4..92a74465b7 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -38,7 +38,7 @@
t_local_basic/1, t_local_unbound/1, t_local_fdopen/1,
t_local_fdopen_listen/1, t_local_fdopen_listen_unbound/1,
t_local_fdopen_connect/1, t_local_fdopen_connect_unbound/1,
- t_local_abstract/1]).
+ t_local_abstract/1, t_accept_inet6_tclass/1]).
-export([getsockfd/0,closesockfd/1]).
@@ -50,6 +50,7 @@ all() ->
[{group, t_accept}, {group, t_connect}, {group, t_recv},
t_shutdown_write, t_shutdown_both, t_shutdown_error,
t_shutdown_async, t_fdopen, t_fdconnect, t_implicit_inet6,
+ t_accept_inet6_tclass,
{group, t_local}].
groups() ->
@@ -521,6 +522,24 @@ local_handshake(S, SAddr, C, CAddr) ->
SData = ok(gen_tcp:recv(C, length(SData))),
ok.
+t_accept_inet6_tclass(Config) when is_list(Config) ->
+ TClassOpt = {tclass,8#56 bsl 2}, % Expedited forwarding
+ case gen_tcp:listen(0, [inet6,TClassOpt]) of
+ {ok,L} ->
+ LPort = ok(inet:port(L)),
+ Loopback = {0,0,0,0,0,0,0,1},
+ Sa = ok(gen_tcp:connect(Loopback, LPort, [])),
+ Sb = ok(gen_tcp:accept(L)),
+ [TClassOpt] = ok(inet:getopts(Sb, [tclass])),
+ ok = gen_tcp:close(Sb),
+ ok = gen_tcp:close(Sa),
+ ok = gen_tcp:close(L),
+ ok;
+ {error,_} ->
+ {skip,"IPv6 TCLASS not supported"}
+ end.
+
+
%%% Utilities
%% Calls M:F/length(A), which should return a timeout error, and complete
diff --git a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
index 2990ddda41..b91dca61d4 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
+++ b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
@@ -17,7 +17,7 @@
*
* %CopyrightEnd%
*/
-#include "erl_nif.h"
+#include <erl_nif.h>
#include <stdio.h>
#include <string.h>
diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl
index 1370e23195..2b59eb2bfe 100644
--- a/lib/kernel/test/init_SUITE.erl
+++ b/lib/kernel/test/init_SUITE.erl
@@ -27,7 +27,8 @@
-export([get_arguments/1, get_argument/1, boot_var/1, restart/1,
many_restarts/0, many_restarts/1,
get_plain_arguments/1,
- reboot/1, stop_status/1, stop/1, get_status/1, script_id/1]).
+ reboot/1, stop_status/1, stop/1, get_status/1, script_id/1,
+ find_system_processes/0]).
-export([boot1/1, boot2/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -355,12 +356,16 @@ wait_for(N,Node,EHPid) ->
restart(Config) when is_list(Config) ->
Args = args(),
+ Pa = " -pa " ++ filename:dirname(code:which(?MODULE)),
+
%% Currently test_server:start_node cannot be used. The restarted
%% node immediately halts due to the implementation of
%% test_server:start_node.
- {ok, Node} = loose_node:start(init_test, Args, ?DEFAULT_TIMEOUT_SEC),
+ {ok, Node} = loose_node:start(init_test, Args ++ Pa, ?DEFAULT_TIMEOUT_SEC),
%% Ok, the node is up, now the real test test begins.
erlang:monitor_node(Node, true),
+ SysProcs0 = rpc:call(Node, ?MODULE, find_system_processes, []),
+ [InitPid, PurgerPid, LitCollectorPid, DirtyCodePid] = SysProcs0,
InitPid = rpc:call(Node, erlang, whereis, [init]),
PurgerPid = rpc:call(Node, erlang, whereis, [erts_code_purger]),
Procs = rpc:call(Node, erlang, processes, []),
@@ -375,6 +380,9 @@ restart(Config) when is_list(Config) ->
end,
ok = wait_restart(30, Node),
+ SysProcs1 = rpc:call(Node, ?MODULE, find_system_processes, []),
+ [InitPid1, PurgerPid1, LitCollectorPid1, DirtyCodePid1] = SysProcs1,
+
%% Still the same init process!
InitPid1 = rpc:call(Node, erlang, whereis, [init]),
InitP = pid_to_list(InitPid),
@@ -385,8 +393,24 @@ restart(Config) when is_list(Config) ->
PurgerP = pid_to_list(PurgerPid),
PurgerP = pid_to_list(PurgerPid1),
+ %% and same literal area collector process!
+ case LitCollectorPid of
+ undefined -> undefined = LitCollectorPid1;
+ _ ->
+ LitCollectorP = pid_to_list(LitCollectorPid),
+ LitCollectorP = pid_to_list(LitCollectorPid1)
+ end,
+
+ %% and same dirty process code checker process!
+ case DirtyCodePid of
+ undefined -> undefined = DirtyCodePid1;
+ _ ->
+ DirtyCodeP = pid_to_list(DirtyCodePid),
+ DirtyCodeP = pid_to_list(DirtyCodePid1)
+ end,
+
NewProcs0 = rpc:call(Node, erlang, processes, []),
- NewProcs = NewProcs0 -- [InitPid1, PurgerPid1],
+ NewProcs = NewProcs0 -- SysProcs1,
case check_processes(NewProcs, MaxPid) of
true ->
ok;
@@ -406,6 +430,37 @@ restart(Config) when is_list(Config) ->
loose_node:stop(Node),
ok.
+-record(sys_procs, {init,
+ code_purger,
+ literal_collector,
+ dirty_proc_checker}).
+
+find_system_processes() ->
+ find_system_procs(processes(), #sys_procs{}).
+
+find_system_procs([], SysProcs) ->
+ [SysProcs#sys_procs.init,
+ SysProcs#sys_procs.code_purger,
+ SysProcs#sys_procs.literal_collector,
+ SysProcs#sys_procs.dirty_proc_checker];
+find_system_procs([P|Ps], SysProcs) ->
+ case process_info(P, initial_call) of
+ {initial_call,{otp_ring0,start,2}} ->
+ undefined = SysProcs#sys_procs.init,
+ find_system_procs(Ps, SysProcs#sys_procs{init = P});
+ {initial_call,{erts_code_purger,start,0}} ->
+ undefined = SysProcs#sys_procs.code_purger,
+ find_system_procs(Ps, SysProcs#sys_procs{code_purger = P});
+ {initial_call,{erts_literal_area_collector,start,0}} ->
+ undefined = SysProcs#sys_procs.literal_collector,
+ find_system_procs(Ps, SysProcs#sys_procs{literal_collector = P});
+ {initial_call,{erts_dirty_process_code_checker,start,0}} ->
+ undefined = SysProcs#sys_procs.dirty_proc_checker,
+ find_system_procs(Ps, SysProcs#sys_procs{dirty_proc_checker = P});
+ _ ->
+ find_system_procs(Ps, SysProcs)
+ end.
+
wait_restart(0, _Node) ->
ct:fail(not_restarted);
wait_restart(N, Node) ->
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index b9ddc3bf48..3cbb75a633 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -25,7 +25,7 @@
-export([space_in_cwd/1, quoting/1, cmd_unicode/1, space_in_name/1, bad_command/1,
find_executable/1, unix_comment_in_command/1, deep_list_command/1,
large_output_command/1, background_command/0, background_command/1,
- message_leak/1, perf_counter_api/1]).
+ message_leak/1, close_stdin/0, close_stdin/1, perf_counter_api/1]).
-include_lib("common_test/include/ct.hrl").
@@ -37,7 +37,7 @@ all() ->
[space_in_cwd, quoting, cmd_unicode, space_in_name, bad_command,
find_executable, unix_comment_in_command, deep_list_command,
large_output_command, background_command, message_leak,
- perf_counter_api].
+ close_stdin, perf_counter_api].
groups() ->
[].
@@ -54,7 +54,8 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-init_per_testcase(background_command, Config) ->
+init_per_testcase(TC, Config)
+ when TC =:= background_command; TC =:= close_stdin ->
case os:type() of
{win32, _} ->
{skip,"Should not work on windows"};
@@ -294,7 +295,7 @@ message_leak(_Config) ->
case os:type() of
{unix, _} ->
- os:cmd("while true; do echo hello; done&"),
+ os:cmd("for i in $(seq 1 100); do echo hello; done&"),
[] = receive_all();
_ ->
ok % Cannot background on non-unix
@@ -302,6 +303,16 @@ message_leak(_Config) ->
process_flag(trap_exit, false).
+%% Test that os:cmd closes stdin of the program that is executed
+close_stdin() ->
+ [{timetrap, {seconds, 5}}].
+close_stdin(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ Fds = filename:join(DataDir, "my_fds"),
+
+ "-1" = os:cmd(Fds).
+
+
%% Test that the os:perf_counter api works as expected
perf_counter_api(_Config) ->
diff --git a/lib/kernel/test/os_SUITE_data/Makefile.src b/lib/kernel/test/os_SUITE_data/Makefile.src
index 912d0cbcb1..f83f781411 100644
--- a/lib/kernel/test/os_SUITE_data/Makefile.src
+++ b/lib/kernel/test/os_SUITE_data/Makefile.src
@@ -3,7 +3,7 @@ LD = @LD@
CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@
CROSSLDFLAGS = @CROSSLDFLAGS@
-PROGS = my_echo@exe@
+PROGS = my_echo@exe@ my_fds@exe@
all: $(PROGS)
@@ -12,3 +12,9 @@ my_echo@exe@: my_echo@obj@
my_echo@obj@: my_echo.c
$(CC) -c -o my_echo@obj@ $(CFLAGS) my_echo.c
+
+my_fds@exe@: my_fds@obj@
+ $(LD) $(CROSSLDFLAGS) -o my_fds my_fds@obj@ @LIBS@
+
+my_fds@obj@: my_fds.c
+ $(CC) -c -o my_fds@obj@ $(CFLAGS) my_fds.c
diff --git a/lib/kernel/test/os_SUITE_data/my_fds.c b/lib/kernel/test/os_SUITE_data/my_fds.c
new file mode 100644
index 0000000000..704a4d1e1d
--- /dev/null
+++ b/lib/kernel/test/os_SUITE_data/my_fds.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int
+main(int argc, char** argv)
+{
+ char buff[1];
+ int res = read(stdin, buff, 1);
+ printf("%d", res);
+}
diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl
index f8257bd20c..4b67fce9a8 100644
--- a/lib/kernel/test/zlib_SUITE.erl
+++ b/lib/kernel/test/zlib_SUITE.erl
@@ -83,7 +83,7 @@ groups() ->
[api_open_close, api_deflateInit,
api_deflateSetDictionary, api_deflateReset,
api_deflateParams, api_deflate, api_deflateEnd,
- api_inflateInit, api_inflateSetDictionary,
+ api_inflateInit, api_inflateSetDictionary, api_inflateGetDictionary,
api_inflateSync, api_inflateReset, api_inflate, api_inflateChunk,
api_inflateEnd, api_setBufsz, api_getBufsz, api_crc32,
api_adler32, api_getQSize, api_un_compress, api_un_zip,
@@ -288,6 +288,42 @@ api_inflateSetDictionary(Config) when is_list(Config) ->
?m({'EXIT',{stream_error,_}}, zlib:inflateSetDictionary(Z1,Dict)),
?m(ok, zlib:close(Z1)).
+%% Test inflateGetDictionary.
+api_inflateGetDictionary(Config) when is_list(Config) ->
+ Z1 = zlib:open(),
+ IsOperationSupported =
+ case catch zlib:inflateGetDictionary(Z1) of
+ {'EXIT',{einval,_}} -> true;
+ {'EXIT',{enotsup,_}} -> false
+ end,
+ _ = zlib:close(Z1),
+ api_inflateGetDictionary_if_supported(IsOperationSupported).
+
+api_inflateGetDictionary_if_supported(false) ->
+ {skip, "inflateGetDictionary/1 unsupported in current setup"};
+api_inflateGetDictionary_if_supported(true) ->
+ % Compress payload using custom dictionary
+ Z1 = zlib:open(),
+ ?m(ok, zlib:deflateInit(Z1)),
+ Dict = <<"foobar barfoo foo bar far boo">>,
+ ?m(_, zlib:deflateSetDictionary(Z1, Dict)),
+ Payload = <<"foobarbarbar">>,
+ Compressed = zlib:deflate(Z1, Payload, finish),
+ ?m(ok, zlib:close(Z1)),
+
+ % Decompress and test dictionary extraction
+ Z2 = zlib:open(),
+ ?m(ok, zlib:inflateInit(Z2)),
+ ?m(<<>>, iolist_to_binary(zlib:inflateGetDictionary(Z2))),
+ ?m({'EXIT',{stream_error,_}}, zlib:inflateSetDictionary(Z2, Dict)),
+ ?m({'EXIT',{{need_dictionary,_},_}}, zlib:inflate(Z2, Compressed)),
+ ?m(ok, zlib:inflateSetDictionary(Z2, Dict)),
+ ?m(Dict, iolist_to_binary(zlib:inflateGetDictionary(Z2))),
+ ?m(Payload, iolist_to_binary(zlib:inflate(Z2, Compressed))),
+ ?m(ok, zlib:close(Z2)),
+ ?m(?BARG, zlib:inflateSetDictionary(Z2, Dict)),
+ ok.
+
%% Test inflateSync.
api_inflateSync(Config) when is_list(Config) ->
{skip,"inflateSync/1 sucks"}.