diff options
Diffstat (limited to 'lib/kernel/test')
-rw-r--r-- | lib/kernel/test/code_SUITE.erl | 29 | ||||
-rw-r--r-- | lib/kernel/test/gen_tcp_misc_SUITE.erl | 115 | ||||
-rw-r--r-- | lib/kernel/test/gen_udp_SUITE.erl | 162 | ||||
-rw-r--r-- | lib/kernel/test/global_SUITE.erl | 13 | ||||
-rw-r--r-- | lib/kernel/test/interactive_shell_SUITE.erl | 60 | ||||
-rw-r--r-- | lib/kernel/test/interactive_shell_SUITE_data/.gitignore | 1 | ||||
-rw-r--r-- | lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl | 6 | ||||
-rw-r--r-- | lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl | 6 | ||||
-rw-r--r-- | lib/kernel/test/logger_std_h_SUITE.erl | 49 | ||||
-rw-r--r-- | lib/kernel/test/seq_trace_SUITE.erl | 32 |
10 files changed, 418 insertions, 55 deletions
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 4f0847084f..6b133f8d6b 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -41,7 +41,7 @@ big_boot_embedded/1, module_status/1, native_early_modules/1, get_mode/1, - normalized_paths/1]). + normalized_paths/1, mult_embedded_flags/1]). -export([init_per_testcase/2, end_per_testcase/2, init_per_suite/1, end_per_suite/1]). @@ -72,7 +72,8 @@ all() -> on_load_purge, on_load_self_call, on_load_pending, on_load_deleted, module_status, - big_boot_embedded, native_early_modules, get_mode, normalized_paths]. + big_boot_embedded, native_early_modules, get_mode, normalized_paths, + mult_embedded_flags]. %% These need to run in order groups() -> [{sequence, [sequence], [on_load_update, @@ -354,7 +355,7 @@ load_abs(Config) when is_list(Config) -> ensure_loaded(Config) when is_list(Config) -> {module, lists} = code:ensure_loaded(lists), case init:get_argument(mode) of - {ok, [["embedded"]]} -> + {ok, [["embedded"] | _]} -> {error, embedded} = code:ensure_loaded(code_b_test), {error, badarg} = code:ensure_loaded(34), ok; @@ -1836,6 +1837,28 @@ do_normalized_paths([M|Ms]) -> do_normalized_paths([]) -> ok. +%% Make sure that the extra -mode flags are ignored +mult_embedded_flags(_Config) -> + Modes = [{" -mode embedded", embedded}, + {" -mode interactive", interactive}, + {" -mode invalid", interactive}], + + [ begin + {ArgMode, ExpectedMode} = Mode, + {ok, Node} = start_node(mode_test, ArgMode), + ExpectedMode = rpc:call(Node, code, get_mode, []), + true = stop_node(Node) + end || Mode <- Modes], + + [ begin + {ArgIgnoredMode, _} = IgnoredMode, + {ArgRelevantMode, ExpectedMode} = RelevantMode, + {ok, Node} = start_node(mode_test, ArgRelevantMode ++ ArgIgnoredMode), + ExpectedMode = rpc:call(Node, code, get_mode, []), + true = stop_node(Node) + end || IgnoredMode <- Modes, RelevantMode <- Modes], + ok. + %% Test that module_status/1 behaves as expected module_status(_Config) -> case test_server:is_cover() of diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index edf30448c4..de87bd9472 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2018. All Rights Reserved. +%% Copyright Ericsson AB 1998-2019. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ init_per_group/2,end_per_group/2, controlling_process/1, controlling_process_self/1, no_accept/1, close_with_pending_output/1, active_n/1, + active_n_closed/1, data_before_close/1, iter_max_socks/0, iter_max_socks/1, get_status/1, @@ -36,7 +37,8 @@ show_econnreset_passive/1, econnreset_after_sync_send/1, econnreset_after_async_send_active/1, econnreset_after_async_send_active_once/1, - econnreset_after_async_send_passive/1, linger_zero/1, + econnreset_after_async_send_passive/1, + linger_zero/1, linger_zero_sndbuf/1, default_options/1, http_bad_packet/1, busy_send/1, busy_disconnect_passive/1, busy_disconnect_active/1, fill_sendq/1, partial_recv_and_close/1, @@ -73,14 +75,15 @@ suite() -> all() -> [controlling_process, controlling_process_self, no_accept, close_with_pending_output, data_before_close, - iter_max_socks, passive_sockets, active_n, + iter_max_socks, passive_sockets, active_n, active_n_closed, accept_closed_by_other_process, otp_3924, closed_socket, shutdown_active, shutdown_passive, shutdown_pending, show_econnreset_active, show_econnreset_active_once, show_econnreset_passive, econnreset_after_sync_send, econnreset_after_async_send_active, econnreset_after_async_send_active_once, - econnreset_after_async_send_passive, linger_zero, + econnreset_after_async_send_passive, + linger_zero, linger_zero_sndbuf, default_options, http_bad_packet, busy_send, busy_disconnect_passive, busy_disconnect_active, fill_sendq, partial_recv_and_close, @@ -1356,7 +1359,42 @@ linger_zero(Config) when is_list(Config) -> ok = gen_tcp:close(Client), ok = ct:sleep(1), undefined = erlang:port_info(Client, connected), - {error, econnreset} = gen_tcp:recv(S, PayloadSize). + {error, econnreset} = gen_tcp:recv(S, PayloadSize), + ok. + + +linger_zero_sndbuf(Config) when is_list(Config) -> + %% All the econnreset tests will prove that {linger, {true, 0}} aborts + %% a connection when the driver queue is empty. We will test here + %% that it also works when the driver queue is not empty + %% and the linger zero option is set on the listen socket. + {OS, _} = os:type(), + {ok, Listen} = + gen_tcp:listen(0, [{active, false}, + {recbuf, 4096}, + {show_econnreset, true}, + {linger, {true, 0}}]), + {ok, Port} = inet:port(Listen), + {ok, Client} = + gen_tcp:connect(localhost, Port, + [{active, false}, + {sndbuf, 4096}]), + {ok, Server} = gen_tcp:accept(Listen), + ok = gen_tcp:close(Listen), + PayloadSize = 1024 * 1024, + Payload = binary:copy(<<"0123456789ABCDEF">>, 256 * 1024), % 1 MB + ok = gen_tcp:send(Server, Payload), + case erlang:port_info(Server, queue_size) of + {queue_size, N} when N > 0 -> ok; + {queue_size, 0} when OS =:= win32 -> ok; + {queue_size, 0} = T -> ct:fail(T) + end, + {ok, [{linger, {true, 0}}]} = inet:getopts(Server, [linger]), + ok = gen_tcp:close(Server), + ok = ct:sleep(1), + undefined = erlang:port_info(Server, connected), + {error, closed} = gen_tcp:recv(Client, PayloadSize), + ok. %% Thanks to Luke Gorrie. Tests for a very specific problem with @@ -1981,10 +2019,10 @@ recvtclass(_Config) -> %% platforms - change {unix,_} to false? %% pktoptions is not supported for IPv4 -recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); +recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); %% Using the option returns einval, so it is not implemented. -recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0}); +recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0}); recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% Does not return any value - not implemented for pktoptions recvtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0}); @@ -1993,10 +2031,10 @@ recvtos_ok({unix,_}, _) -> true; recvtos_ok(_, _) -> false. %% pktoptions is not supported for IPv4 -recvttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); +recvttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); recvttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); %% Using the option returns einval, so it is not implemented. -recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0}); +recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0}); recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% Does not return any value - not implemented for pktoptions recvttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,7,0}); @@ -2005,11 +2043,11 @@ recvttl_ok({unix,_}, _) -> true; recvttl_ok(_, _) -> false. %% pktoptions is not supported for IPv6 -recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); +recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% Using the option returns einval, so it is not implemented. -recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0}); +recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0}); %% Does not return any value - not implemented for pktoptions recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0}); %% @@ -2186,18 +2224,19 @@ collect_accepts(N,Tmo) -> A = millis(), receive {accepted,P,Msg} -> - [{P,Msg}] ++ collect_accepts(N-1,Tmo-(millis() - A)) + NextN = if N =:= infinity -> N; true -> N - 1 end, + [{P,Msg}] ++ collect_accepts(NextN, Tmo - (millis()-A)) after Tmo -> [] end. -define(EXPECT_ACCEPTS(Pattern,N,Timeout), (fun() -> - case collect_accepts(if N =:= infinity -> -1; true -> N end,Timeout) of + case collect_accepts((N), (Timeout)) of Pattern -> ok; - Other -> - {error,{unexpected,{Other,process_info(self(),messages)}}} + Other__ -> + {error,{unexpected,{Other__,process_info(self(),messages)}}} end end)()). @@ -2582,7 +2621,51 @@ active_once_closed(Config) when is_list(Config) -> ok = inet:setopts(A,[{active,once}]), ok = receive {tcp_closed, A} -> ok after 1000 -> error end end)(). - + +%% Check that active n and tcp_close messages behave as expected. +active_n_closed(Config) when is_list(Config) -> + {ok, L} = gen_tcp:listen(0, [binary, {active, false}]), + + P = self(), + + {ok,Port} = inet:port(L), + + spawn_link(fun() -> + Payload = <<0:50000/unit:8>>, + Cnt = 10000, + P ! {size,Cnt * byte_size(Payload)}, + {ok, S} = gen_tcp:connect("localhost", Port, [binary, {active, false}]), + _ = [gen_tcp:send(S, Payload) || _ <- lists:seq(1, Cnt)], + gen_tcp:close(S) + end), + + receive {size,SendSize} -> SendSize end, + {ok, S} = gen_tcp:accept(L), + inet:setopts(S, [{active, 10}]), + RecvSize = + (fun Server(Size) -> + receive + {tcp, S, Bin} -> + Server(byte_size(Bin) + Size); + {tcp_closed, S} -> + Size; + {tcp_passive, S} -> + inet:setopts(S, [{active, 10}]), + Server(Size); + Msg -> + io:format("~p~n", [Msg]), + Server(Size) + end + end)(0), + + gen_tcp:close(L), + + if SendSize =:= RecvSize -> + ok; + true -> + ct:fail("Send and Recv size not equal: ~p ~p",[SendSize, RecvSize]) + end. + %% Test the send_timeout socket option. send_timeout(Config) when is_list(Config) -> Dir = filename:dirname(code:which(?MODULE)), diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index af9985de45..70d8caf478 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2018. All Rights Reserved. +%% Copyright Ericsson AB 1998-2019. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1, read_packets/1, open_fd/1, connect/1, implicit_inet6/1, recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1, + sendtos/1, sendtosttl/1, sendttl/1, sendtclass/1, local_basic/1, local_unbound/1, local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]). @@ -49,6 +50,7 @@ all() -> bad_address, read_packets, open_fd, connect, implicit_inet6, active_n, recvtos, recvtosttl, recvttl, recvtclass, + sendtos, sendtosttl, sendttl, sendtclass, {group, local}]. groups() -> @@ -312,7 +314,6 @@ read_packets(Config) when is_list(Config) -> {ok,R} = gen_udp:open(0, [{read_packets,N1}]), {ok,RP} = inet:port(R), {ok,Node} = start_node(gen_udp_SUITE_read_packets), - Die = make_ref(), %% {V1, Trace1} = read_packets_test(R, RP, Msgs, Node), {ok,[{read_packets,N1}]} = inet:getopts(R, [read_packets]), @@ -324,7 +325,7 @@ read_packets(Config) when is_list(Config) -> stop_node(Node), ct:log("N1=~p, V1=~p vs N2=~p, V2=~p",[N1,V1,N2,V2]), - dump_terms(Config, "trace1.terms", Trace2), + dump_terms(Config, "trace1.terms", Trace1), dump_terms(Config, "trace2.terms", Trace2), %% Because of the inherit racy-ness of the feature it is @@ -348,15 +349,6 @@ dump_terms(Config, Name, Terms) -> file:write_file(FName, term_to_binary(Terms)), ct:log("Logged terms to ~s",[FName]). -infinite_loop(Die) -> - receive - Die -> - ok - after - 0 -> - infinite_loop(Die) - end. - read_packets_test(R, RP, Msgs, Node) -> Receiver = self(), Tracer = @@ -577,19 +569,19 @@ active_n(Config) when is_list(Config) -> recvtos(_Config) -> test_recv_opts( - inet, [{recvtos,tos,96}], + inet, [{recvtos,tos,96}], false, fun recvtos_ok/2). recvtosttl(_Config) -> test_recv_opts( - inet, [{recvtos,tos,96},{recvttl,ttl,33}], + inet, [{recvtos,tos,96},{recvttl,ttl,33}], false, fun (OSType, OSVer) -> recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer) end). recvttl(_Config) -> test_recv_opts( - inet, [{recvttl,ttl,33}], + inet, [{recvttl,ttl,33}], false, fun recvttl_ok/2). recvtclass(_Config) -> @@ -601,15 +593,48 @@ recvtclass(_Config) -> of [_] -> test_recv_opts( - inet6, [{recvtclass,tclass,224}], + inet6, [{recvtclass,tclass,224}], false, fun recvtclass_ok/2); [] -> {skip,ipv6_not_supported,IFs} end. + +sendtos(_Config) -> + test_recv_opts( + inet, [{recvtos,tos,96}], true, + fun sendtos_ok/2). + +sendtosttl(_Config) -> + test_recv_opts( + inet, [{recvtos,tos,96},{recvttl,ttl,33}], true, + fun (OSType, OSVer) -> + sendtos_ok(OSType, OSVer) andalso sendttl_ok(OSType, OSVer) + end). + +sendttl(_Config) -> + test_recv_opts( + inet, [{recvttl,ttl,33}], true, + fun sendttl_ok/2). + +sendtclass(_Config) -> + {ok,IFs} = inet:getifaddrs(), + case + [Name || + {Name,Opts} <- IFs, + lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)] + of + [_] -> + test_recv_opts( + inet6, [{recvtclass,tclass,224}], true, + fun sendtclass_ok/2); + [] -> + {skip,ipv6_not_supported,IFs} + end. + %% These version numbers are just above the highest noted in daily tests %% where the test fails for a plausible reason, that is the lowest -%% where we can expect that the test mighe succeed, so +%% where we can expect that the test might succeed, so %% skip on platforms lower than this. %% %% On newer versions it might be fixed, but we'll see about that @@ -621,23 +646,65 @@ recvtclass(_Config) -> %% Using the option returns einval, so it is not implemented. recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0}); %% Using the option returns einval, so it is not implemented. -recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); +recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); %% Using the option returns einval, so it is not implemented. recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% recvtos_ok({unix,_}, _) -> true; recvtos_ok(_, _) -> false. +%% Option has no effect +recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); +%% recvttl_ok({unix,_}, _) -> true; recvttl_ok(_, _) -> false. %% Using the option returns einval, so it is not implemented. recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0}); recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11}); +%% Option has no effect +recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% recvtclass_ok({unix,_}, _) -> true; recvtclass_ok(_, _) -> false. + +%% To send ancillary data seems to require much higher version numbers +%% than receiving it... +%% + +%% Using the option returns einval, so it is not implemented. +sendtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); +sendtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); +sendtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); +sendtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {4,0,0}); +sendtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0}); +%% +sendtos_ok({unix,_}, _) -> true; +sendtos_ok(_, _) -> false. + +%% Using the option returns einval, so it is not implemented. +sendttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); +sendttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {4,0,0}); +%% Using the option returns enoprotoopt, so it is not implemented. +sendttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0}); +%% Option has no effect +sendttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); +sendttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); +%% +sendttl_ok({unix,_}, _) -> true; +sendttl_ok(_, _) -> false. + +%% Using the option returns einval, so it is not implemented. +sendtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0}); +sendtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11}); +%% Option has no effect +sendtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); +%% +sendtclass_ok({unix,_}, _) -> true; +sendtclass_ok(_, _) -> false. + + semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) -> if X1 > X2 -> false; @@ -650,18 +717,18 @@ semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) -> end; semver_lt(_, {_,_,_}) -> false. -test_recv_opts(Family, Spec, OSFilter) -> +test_recv_opts(Family, Spec, TestSend, OSFilter) -> OSType = os:type(), OSVer = os:version(), case OSFilter(OSType, OSVer) of true -> io:format("Os: ~p, ~p~n", [OSType,OSVer]), - test_recv_opts(Family, Spec, OSType, OSVer); + test_recv_opts(Family, Spec, TestSend, OSType, OSVer); false -> {skip,{not_supported_for_os_version,{OSType,OSVer}}} end. %% -test_recv_opts(Family, Spec, _OSType, _OSVer) -> +test_recv_opts(Family, Spec, TestSend, _OSType, _OSVer) -> Timeout = 5000, RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec], TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec], @@ -686,16 +753,33 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) -> ok = inet:setopts(S1, TrueRecvOpts_OptsVals), {ok,TrueRecvOpts_OptsVals} = inet:getopts(S1, RecvOpts ++ Opts), %% + %% S1 now has true receive options and set option values + %% {ok,S2} = gen_udp:open(0, [Family,binary,{active,true}|FalseRecvOpts]), {ok,P2} = inet:port(S2), {ok,FalseRecvOpts_OptsVals2} = inet:getopts(S2, RecvOpts ++ Opts), OptsVals2 = FalseRecvOpts_OptsVals2 -- FalseRecvOpts, %% - ok = gen_udp:send(S2, Addr, P1, <<"abcde">>), + %% S2 now has false receive options and default option values, + %% OptsVals2 contains the default option values + %% + ok = gen_udp:send(S2, {Addr,P1}, <<"abcde">>), ok = gen_udp:send(S1, Addr, P2, <<"fghij">>), + TestSend andalso + begin + ok = gen_udp:send(S2, Addr, P1, OptsVals, <<"ABCDE">>), + ok = gen_udp:send(S2, {Addr,P1}, OptsVals, <<"12345">>) + end, {ok,{_,P2,OptsVals3,<<"abcde">>}} = gen_udp:recv(S1, 0, Timeout), verify_sets_eq(OptsVals3, OptsVals2), + TestSend andalso + begin + {ok,{_,P2,OptsVals0,<<"ABCDE">>}} = gen_udp:recv(S1, 0, Timeout), + {ok,{_,P2,OptsVals1,<<"12345">>}} = gen_udp:recv(S1, 0, Timeout), + verify_sets_eq(OptsVals0, OptsVals), + verify_sets_eq(OptsVals1, OptsVals) + end, receive {udp,S2,_,P1,<<"fghij">>} -> ok; @@ -710,8 +794,16 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) -> ok = inet:setopts(S2, TrueRecvOpts), {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts), %% - ok = gen_udp:send(S2, Addr, P1, <<"klmno">>), - ok = gen_udp:send(S1, Addr, P2, <<"pqrst">>), + %% S1 now has false receive options and set option values + %% + %% S2 now has true receive options and default option values + %% + ok = gen_udp:send(S2, {Addr,P1}, [], <<"klmno">>), + ok = gen_udp:send(S1, {Family,{loopback,P2}}, <<"pqrst">>), + TestSend andalso + begin + ok = gen_udp:send(S1, {Family,{loopback,P2}}, OptsVals2, <<"PQRST">>) + end, {ok,{_,P2,<<"klmno">>}} = gen_udp:recv(S1, 0, Timeout), receive {udp,S2,_,P1,OptsVals4,<<"pqrst">>} -> @@ -721,9 +813,18 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) -> after Timeout -> exit(timeout) end, + TestSend andalso + receive + {udp,S2,_,P1,OptsVals5,<<"PQRST">>} -> + verify_sets_eq(OptsVals5, OptsVals2); + Other3 -> + exit({unexpected,Other3}) + after Timeout -> + exit(timeout) + end, ok = gen_udp:close(S1), ok = gen_udp:close(S2), -%% exit({{OSType,OSVer},success}), % In search for the truth +%%% exit({{_OSType,_OSVer},success}), % In search for the truth ok. verify_sets_eq(L1, L2) -> @@ -877,6 +978,10 @@ connect(Config) when is_list(Config) -> implicit_inet6(Config) when is_list(Config) -> Host = ok(inet:gethostname()), case inet:getaddr(Host, inet6) of + {ok,{16#fe80,0,0,0,_,_,_,_} = Addr} -> + {skip, + "Got link local IPv6 address: " + ++inet:ntoa(Addr)}; {ok,Addr} -> implicit_inet6(Host, Addr); {error,Reason} -> @@ -927,11 +1032,12 @@ ok({ok,V}) -> V; ok(NotOk) -> try throw(not_ok) catch - throw:Thrown:Stacktrace -> - erlang:raise( - error, {Thrown, NotOk}, tl(Stacktrace)) + throw:not_ok:Stacktrace -> + raise_error({not_ok, NotOk}, tl(Stacktrace)) end. +raise_error(Reason, Stacktrace) -> + erlang:raise(error, Reason, Stacktrace). local_filename(Tag) -> "/tmp/" ?MODULE_STRING "_" ++ os:getpid() ++ "_" ++ atom_to_list(Tag). diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl index 8eab36e308..5bff9cc292 100644 --- a/lib/kernel/test/global_SUITE.erl +++ b/lib/kernel/test/global_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2018. All Rights Reserved. +%% Copyright Ericsson AB 1997-2019. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -2512,8 +2512,10 @@ re_register_name(Config) when is_list(Config) -> Me = self(), Pid1 = spawn(fun() -> proc(Me) end), yes = global:register_name(name, Pid1), + wait_for_monitor(Pid1), Pid2 = spawn(fun() -> proc(Me) end), _ = global:re_register_name(name, Pid2), + wait_for_monitor(Pid2), Pid2 ! die, Pid1 ! die, receive {Pid1, MonitoredBy1} -> [] = MonitoredBy1 end, @@ -2522,6 +2524,15 @@ re_register_name(Config) when is_list(Config) -> init_condition(Config), ok. +wait_for_monitor(Pid) -> + case process_info(Pid, monitored_by) of + {monitored_by, []} -> + timer:sleep(1), + wait_for_monitor(Pid); + {monitored_by, [_]} -> + ok + end. + proc(Parent) -> receive die -> ok end, {monitored_by, MonitoredBy} = process_info(self(), monitored_by), diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl index 298a364a91..173e25c520 100644 --- a/lib/kernel/test/interactive_shell_SUITE.erl +++ b/lib/kernel/test/interactive_shell_SUITE.erl @@ -23,7 +23,8 @@ init_per_group/2,end_per_group/2, get_columns_and_rows/1, exit_initial/1, job_control_local/1, job_control_remote/1, - job_control_remote_noshell/1,ctrl_keys/1]). + job_control_remote_noshell/1,ctrl_keys/1, + get_columns_and_rows_escript/1]). -export([init_per_testcase/2, end_per_testcase/2]). %% For spawn @@ -40,7 +41,8 @@ suite() -> {timetrap,{minutes,3}}]. all() -> - [get_columns_and_rows, exit_initial, job_control_local, + [get_columns_and_rows_escript,get_columns_and_rows, + exit_initial, job_control_local, job_control_remote, job_control_remote_noshell, ctrl_keys]. @@ -72,6 +74,60 @@ end_per_group(_GroupName, Config) -> -define(dbg(Data),noop). -endif. +string_to_term(Str) -> + {ok,Tokens,_EndLine} = erl_scan:string(Str ++ "."), + {ok,AbsForm} = erl_parse:parse_exprs(Tokens), + {value,Value,_Bs} = erl_eval:exprs(AbsForm, erl_eval:new_bindings()), + Value. + +run_unbuffer_escript(Rows, Columns, EScript, NoTermStdIn, NoTermStdOut) -> + DataDir = filename:join(filename:dirname(code:which(?MODULE)), "interactive_shell_SUITE_data"), + TmpFile = filename:join(DataDir, "tmp"), + ok = file:write_file(TmpFile, <<>>), + CommandModifier = + case {NoTermStdIn, NoTermStdOut} of + {false, false} -> ""; + {true, false} -> io_lib:format(" < ~s", [TmpFile]); + {false, true} -> io_lib:format(" > ~s ; cat ~s", [TmpFile, TmpFile]); + {true, true} -> io_lib:format(" > ~s < ~s ; cat ~s", [TmpFile, TmpFile, TmpFile]) + end, + Command = io_lib:format("unbuffer -p bash -c \"stty rows ~p; stty columns ~p; escript ~s ~s\"", + [Rows, Columns, EScript, CommandModifier]), + %% io:format("Command: ~s ~n", [Command]), + Out = os:cmd(Command), + %% io:format("Out: ~p ~n", [Out]), + string_to_term(Out). + +get_columns_and_rows_escript(Config) when is_list(Config) -> + ExpectUnbufferInstalled = + try + "79" = string:trim(os:cmd("unbuffer -p bash -c \"stty columns 79 ; tput cols\"")), + true + catch + _:_ -> false + end, + case ExpectUnbufferInstalled of + false -> + {skip, + "The unbuffer tool (https://core.tcl-lang.org/expect/index) does not seem to be installed.~n" + "On Ubuntu/Debian: \"sudo apt-get install expect\""}; + true -> + DataDir = filename:join(filename:dirname(code:which(?MODULE)), "interactive_shell_SUITE_data"), + IoColumnsErl = filename:join(DataDir, "io_columns.erl"), + IoRowsErl = filename:join(DataDir, "io_rows.erl"), + [ + begin + {ok, 42} = run_unbuffer_escript(99, 42, IoColumnsErl, NoTermStdIn, NoTermStdOut), + {ok, 99} = run_unbuffer_escript(99, 42, IoRowsErl, NoTermStdIn, NoTermStdOut) + end + || + {NoTermStdIn, NoTermStdOut} <- [{false, false}, {true, false}, {false, true}] + ], + {error,enotsup} = run_unbuffer_escript(99, 42, IoRowsErl, true, true), + {error,enotsup} = run_unbuffer_escript(99, 42, IoColumnsErl, true, true), + ok + end. + %% Test that the shell can access columns and rows. get_columns_and_rows(Config) when is_list(Config) -> case proplists:get_value(default_shell,Config) of diff --git a/lib/kernel/test/interactive_shell_SUITE_data/.gitignore b/lib/kernel/test/interactive_shell_SUITE_data/.gitignore new file mode 100644 index 0000000000..1c2f433de1 --- /dev/null +++ b/lib/kernel/test/interactive_shell_SUITE_data/.gitignore @@ -0,0 +1 @@ +tmp
\ No newline at end of file diff --git a/lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl b/lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl new file mode 100644 index 0000000000..32d0cf25df --- /dev/null +++ b/lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl @@ -0,0 +1,6 @@ +-module(io_columns). + +-export([main/1]). + +main(_) -> + io:format("~p",[io:columns()]). diff --git a/lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl b/lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl new file mode 100644 index 0000000000..53ceb464b0 --- /dev/null +++ b/lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl @@ -0,0 +1,6 @@ +-module(io_rows). + +-export([main/1]). + +main(_) -> + io:format("~p",[io:rows()]). diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl index 16ab0e97fc..2b2d509860 100644 --- a/lib/kernel/test/logger_std_h_SUITE.erl +++ b/lib/kernel/test/logger_std_h_SUITE.erl @@ -132,6 +132,7 @@ all() -> bad_input, reconfig, file_opts, + relative_file_path, sync, write_failure, sync_failure, @@ -693,6 +694,54 @@ file_opts(Config) -> file_opts(cleanup, _Config) -> logger:remove_handler(?MODULE). +relative_file_path(_Config) -> + {ok,Dir} = file:get_cwd(), + AbsName1 = filename:join(Dir,?MODULE), + ok = logger:add_handler(?MODULE, + logger_std_h, + #{config => #{type=>file}, + filter_default=>log, + filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]), + formatter=>{?MODULE,self()}}), + #{cb_state := #{handler_state := #{file:=AbsName1}}} = + logger_olp:info(h_proc_name()), + {ok,#{config := #{file:=AbsName1}}} = + logger:get_handler_config(?MODULE), + ok = logger:remove_handler(?MODULE), + + RelName2 = filename:join(atom_to_list(?FUNCTION_NAME), + lists:concat([?FUNCTION_NAME,".log"])), + AbsName2 = filename:join(Dir,RelName2), + ok = logger:add_handler(?MODULE, + logger_std_h, + #{config => #{file => RelName2}, + filter_default=>log, + filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]), + formatter=>{?MODULE,self()}}), + #{cb_state := #{handler_state := #{file:=AbsName2}}} = + logger_olp:info(h_proc_name()), + {ok,#{config := #{file:=AbsName2}}} = + logger:get_handler_config(?MODULE), + logger:notice(M1=?msg,?domain), + ?check(M1), + B1 = ?bin(M1), + try_read_file(AbsName2, {ok,B1}, filesync_rep_int()), + + ok = file:set_cwd(".."), + logger:notice(M2=?msg,?domain), + ?check(M2), + B20 = ?bin(M2), + B2 = <<B1/binary,B20/binary>>, + try_read_file(AbsName2, {ok,B2}, filesync_rep_int()), + + {error,_} = logger:update_handler_config(?MODULE,config,#{file=>RelName2}), + ok = logger:update_handler_config(?MODULE,config,#{file=>AbsName2}), + ok = file:set_cwd(Dir), + ok = logger:update_handler_config(?MODULE,config,#{file=>RelName2}), + ok. +relative_file_path(cleanup,_Config) -> + logger:remove_handler(?MODULE). + sync(Config) -> Dir = ?config(priv_dir,Config), diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl index 663f910751..83a94ab087 100644 --- a/lib/kernel/test/seq_trace_SUITE.erl +++ b/lib/kernel/test/seq_trace_SUITE.erl @@ -26,6 +26,7 @@ init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2]). -export([token_set_get/1, tracer_set_get/1, print/1, + old_heap_token/1, send/1, distributed_send/1, recv/1, distributed_recv/1, trace_exit/1, distributed_exit/1, call/1, port/1, match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1, @@ -50,6 +51,7 @@ suite() -> all() -> [token_set_get, tracer_set_get, print, send, send_literal, distributed_send, recv, distributed_recv, trace_exit, + old_heap_token, distributed_exit, call, port, match_set_seq_token, gc_seq_token, label_capability_mismatch]. @@ -149,17 +151,19 @@ tracer_set_get(Config) when is_list(Config) -> ok. print(Config) when is_list(Config) -> - lists:foreach(fun do_print/1, ?TIMESTAMP_MODES). + [do_print(TsType, Label) || TsType <- ?TIMESTAMP_MODES, + Label <- [17, "label"]]. -do_print(TsType) -> +do_print(TsType, Label) -> start_tracer(), + seq_trace:set_token(label, Label), set_token_flags([print, TsType]), - seq_trace:print(0,print1), + seq_trace:print(Label,print1), seq_trace:print(1,print2), seq_trace:print(print3), seq_trace:reset_trace(), - [{0,{print,_,_,[],print1}, Ts0}, - {0,{print,_,_,[],print3}, Ts1}] = stop_tracer(2), + [{Label,{print,_,_,[],print1}, Ts0}, + {Label,{print,_,_,[],print3}, Ts1}] = stop_tracer(2), check_ts(TsType, Ts0), check_ts(TsType, Ts1). @@ -563,6 +567,24 @@ get_port_message(Port) -> end. +%% OTP-15849 ERL-700 +%% Verify changing label on existing token when it resides on old heap. +%% Bug caused faulty ref from old to new heap. +old_heap_token(Config) when is_list(Config) -> + seq_trace:set_token(label, 1), + erlang:garbage_collect(self(), [{type, minor}]), + erlang:garbage_collect(self(), [{type, minor}]), + %% Now token tuple should be on old-heap. + %% Set a new non-literal label which should reside on new-heap. + NewLabel = {self(), "new label"}, + 1 = seq_trace:set_token(label, NewLabel), + + %% If bug, we now have a ref from old to new heap. Yet another minor gc + %% will make that a ref to deallocated memory. + erlang:garbage_collect(self(), [{type, minor}]), + {label,NewLabel} = seq_trace:get_token(label), + ok. + match_set_seq_token(doc) -> ["Tests that match spec function set_seq_token does not " |