diff options
Diffstat (limited to 'lib/stdlib/test/proc_lib_SUITE.erl')
-rw-r--r-- | lib/stdlib/test/proc_lib_SUITE.erl | 238 |
1 files changed, 161 insertions, 77 deletions
diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl index f7a6a38138..127b1317e4 100644 --- a/lib/stdlib/test/proc_lib_SUITE.erl +++ b/lib/stdlib/test/proc_lib_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2014. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -26,9 +26,9 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, - crash/1, sync_start_nolink/1, sync_start_link/1, - spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1, - hibernate/1, stop/1, t_format/1]). + crash/1, stacktrace/1, sync_start_nolink/1, sync_start_link/1, + spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1, '\x{447}'/0, + hibernate/1, stop/1, t_format/1, t_format_arbitrary/1]). -export([ otp_6345/1, init_dont_hang/1]). -export([hib_loop/1, awaken/1]). @@ -44,14 +44,14 @@ -ifdef(STANDALONE). -define(line, noop, ). -else. --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -endif. suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [crash, {group, sync_start}, spawn_opt, hibernate, - {group, tickets}, stop, t_format]. + [crash, stacktrace, {group, sync_start}, spawn_opt, hibernate, + {group, tickets}, stop, t_format, t_format_arbitrary]. groups() -> [{tickets, [], [otp_6345, init_dont_hang]}, @@ -78,6 +78,14 @@ end_per_group(_GroupName, Config) -> %% synchronous, and we want to test that the crash report is ok. %%----------------------------------------------------------------- crash(Config) when is_list(Config) -> + ok = application:unset_env(kernel, error_logger_format_depth), + crash_1(Config), + ok = application:set_env(kernel, error_logger_format_depth, 30), + crash_1(Config), + ok = application:unset_env(kernel, error_logger_format_depth), + ok. + +crash_1(_Config) -> error_logger:add_report_handler(?MODULE, self()), %% Make sure that we don't get a crash report if a process @@ -115,7 +123,7 @@ crash(Config) when is_list(Config) -> %% Spawn function with neighbour. Pid4 = proc_lib:spawn(?MODULE, sp2, []), - test_server:sleep(100), + ct:sleep(100), {?MODULE,sp2,[]} = proc_lib:initial_call(Pid4), {?MODULE,sp2,0} = proc_lib:translate_initial_call(Pid4), Pid4 ! die, @@ -139,6 +147,14 @@ crash(Config) when is_list(Config) -> {error_info,{exit,abnormal,{stacktrace}}}], analyse_crash(Pid5, Exp5, []), + %% Unicode atom + Pid6 = proc_lib:spawn(?MODULE, '\x{447}', []), + Pid6 ! die, + Exp6 = [{initial_call,{?MODULE,'\x{447}',[]}}, + {ancestors,[self()]}, + {error_info,{exit,die,{stacktrace}}}], + analyse_crash(Pid6, Exp6, []), + error_logger:delete_report_handler(?MODULE), ok. @@ -152,9 +168,9 @@ analyse_crash(Pid, Expected0, ExpLinks) -> analyse_links(ExpLinks, Links); Unexpected -> io:format("~p\n", [Unexpected]), - test_server:fail(unexpected_message) + ct:fail(unexpected_message) after 5000 -> - test_server:fail(no_crash_report) + ct:fail(no_crash_report) end. analyse_links([H|Es], [{neighbour,N}|Links]) -> @@ -170,7 +186,7 @@ analyse_crash_1([{Key,Pattern}|T], Report) -> case lists:keyfind(Key, 1, Report) of false -> io:format("~p", [Report]), - test_server:fail({missing_key,Key}); + ct:fail({missing_key,Key}); {Key,Info} -> try match_info(Pattern, Info) @@ -179,7 +195,7 @@ analyse_crash_1([{Key,Pattern}|T], Report) -> io:format("key: ~p", [Key]), io:format("pattern: ~p", [Pattern]), io:format("actual: ~p", [Report]), - test_server:fail(no_match) + ct:fail(no_match) end, analyse_crash_1(T, Report) end; @@ -198,12 +214,37 @@ match_info(Tuple1, Tuple2) when tuple_size(Tuple1) =:= tuple_size(Tuple2) -> match_info(_, _) -> throw(no_match). +stacktrace(Config) when is_list(Config) -> + process_flag(trap_exit, true), + %% Errors. + Pid1 = proc_lib:spawn_link(fun() -> 1 = 2 end), + receive + {'EXIT',Pid1,{{badmatch,2},_Stack1}} -> ok + after 500 -> + ct:fail(error) + end, + %% Exits. + Pid2 = proc_lib:spawn_link(fun() -> exit(bye) end), + receive + {'EXIT',Pid2,bye} -> ok + after 500 -> + ct:fail(exit) + end, + %% Throws. + Pid3 = proc_lib:spawn_link(fun() -> throw(ball) end), + receive + {'EXIT',Pid3,{{nocatch,ball},_Stack3}} -> ok + after 500 -> + ct:fail(throw) + end, + ok. + sync_start_nolink(Config) when is_list(Config) -> _Pid = spawn_link(?MODULE, sp5, [self()]), receive {sync_started, F} -> exit(F, kill), - test_server:fail(async_start) + ct:fail(async_start) after 1000 -> ok end, receive @@ -214,14 +255,14 @@ sync_start_nolink(Config) when is_list(Config) -> {sync_started, _} -> ok after 1000 -> exit(Pid2, kill), - test_server:fail(no_sync_start) + ct:fail(no_sync_start) end, ok. - + sync_start_link(Config) when is_list(Config) -> _Pid = spawn_link(?MODULE, sp3, [self()]), receive - {sync_started, _} -> test_server:fail(async_start) + {sync_started, _} -> ct:fail(async_start) after 1000 -> ok end, receive @@ -230,24 +271,24 @@ sync_start_link(Config) when is_list(Config) -> end, receive {sync_started, _} -> ok - after 1000 -> test_server:fail(no_sync_start) + after 1000 -> ct:fail(no_sync_start) end, ok. - + spawn_opt(Config) when is_list(Config) -> F = fun sp1/0, {name,Fname} = erlang:fun_info(F, name), FunMFArgs = {?MODULE,Fname,[]}, FunMFArity = {?MODULE,Fname,0}, - ?line Pid1 = proc_lib:spawn_opt(node(), F, [{priority,low}]), - ?line Pid = proc_lib:spawn_opt(F, [{priority,low}]), - ?line test_server:sleep(100), - ?line FunMFArgs = proc_lib:initial_call(Pid), - ?line FunMFArity = proc_lib:translate_initial_call(Pid), - ?line Pid ! die, - ?line FunMFArgs = proc_lib:initial_call(Pid1), - ?line FunMFArity = proc_lib:translate_initial_call(Pid1), - ?line Pid1 ! die, + Pid1 = proc_lib:spawn_opt(node(), F, [{priority,low}]), + Pid = proc_lib:spawn_opt(F, [{priority,low}]), + ct:sleep(100), + FunMFArgs = proc_lib:initial_call(Pid), + FunMFArity = proc_lib:translate_initial_call(Pid), + Pid ! die, + FunMFArgs = proc_lib:initial_call(Pid1), + FunMFArity = proc_lib:translate_initial_call(Pid1), + Pid1 ! die, ok. @@ -279,61 +320,67 @@ sp4(Parent, Tester) -> end, proc_lib:init_ack(Parent, self()). +'\x{447}'() -> + receive + die -> exit(die); + _ -> sp1() + end. + hibernate(Config) when is_list(Config) -> Ref = make_ref(), Self = self(), LoopData = {Ref,Self}, - ?line Pid = proc_lib:spawn_link(?MODULE, hib_loop, [LoopData]), + Pid = proc_lib:spawn_link(?MODULE, hib_loop, [LoopData]), %% Just check that the child process can process and answer messages. - ?line Pid ! {Self,loop_data}, + Pid ! {Self,loop_data}, receive {loop_data,LoopData} -> ok; Unexpected0 -> - ?line io:format("Unexpected: ~p\n", [Unexpected0]), - ?line ?t:fail() + io:format("Unexpected: ~p\n", [Unexpected0]), + ct:fail(failed) after 1000 -> - ?line io:format("Timeout"), - ?line ?t:fail() + io:format("Timeout"), + ct:fail(failed) end, %% Hibernate the process. - ?line Pid ! hibernate, + Pid ! hibernate, erlang:yield(), io:format("~p\n", [process_info(Pid, heap_size)]), %% Send a message to the process... - ?line Pid ! {Self,loop_data}, + Pid ! {Self,loop_data}, %% ... expect first a wake up message from the process... receive {awaken,LoopData} -> ok; Unexpected1 -> - ?line io:format("Unexpected: ~p\n", [Unexpected1]), - ?line ?t:fail() + io:format("Unexpected: ~p\n", [Unexpected1]), + ct:fail(failed) after 1000 -> - ?line io:format("Timeout"), - ?line ?t:fail() + io:format("Timeout"), + ct:fail(failed) end, %% ... followed by the answer to the actual request. receive {loop_data,LoopData} -> ok; Unexpected2 -> - ?line io:format("Unexpected: ~p\n", [Unexpected2]), - ?line ?t:fail() + io:format("Unexpected: ~p\n", [Unexpected2]), + ct:fail(failed) after 1000 -> - ?line io:format("Timeout"), - ?line ?t:fail() + io:format("Timeout"), + ct:fail(failed) end, %% Test that errors are handled correctly after wake up from hibernation... - ?line process_flag(trap_exit, true), - ?line error_logger:add_report_handler(?MODULE, self()), - ?line Pid ! crash, + process_flag(trap_exit, true), + error_logger:add_report_handler(?MODULE, self()), + Pid ! crash, %% We should receive two messages. Especially in the SMP emulator, %% we can't be sure of the message order, so sort the messages before @@ -341,10 +388,10 @@ hibernate(Config) when is_list(Config) -> Messages = lists:sort(hib_receive_messages(2)), io:format("~p", [Messages]), - ?line [{'EXIT',Pid,i_crashed},{crash_report,Pid,[Report,[]]}] = Messages, + [{'EXIT',Pid,i_crashed},{crash_report,Pid,[Report,[]]}] = Messages, %% Check that the initial_call has the expected format. - ?line {value,{initial_call,{?MODULE,hib_loop,[_]}}} = + {value,{initial_call,{?MODULE,hib_loop,[_]}}} = lists:keysearch(initial_call, 1, Report), error_logger:delete_report_handler(?MODULE), @@ -371,10 +418,7 @@ hib_receive_messages(N) -> Any -> [Any|hib_receive_messages(N-1)] end. -otp_6345(suite) -> - []; -otp_6345(doc) -> - ["'monitor' spawn_opt option"]; +%% 'monitor' spawn_opt option. otp_6345(Config) when is_list(Config) -> Opts = [link,monitor], {'EXIT', {badarg,[{proc_lib,check_for_monitor,_,_}|_Stack]}} = @@ -392,11 +436,8 @@ otp_6345_loop() -> otp_6345_loop() end. -%% OTP-9803 -init_dont_hang(suite) -> - []; -init_dont_hang(doc) -> - ["Check that proc_lib:start don't hang if spawned process crashes before proc_lib:init_ack/2"]; +%% OTP-9803. Check that proc_lib:start() doesn't hang if spawned process +%% crashes before proc_lib:init_ack/2. init_dont_hang(Config) when is_list(Config) -> %% Start should behave as start_link process_flag(trap_exit, true), @@ -405,8 +446,8 @@ init_dont_hang(Config) when is_list(Config) -> StartLinkRes = proc_lib:start(?MODULE, init_dont_hang_init, [self()], 1000), StartLinkRes = proc_lib:start(?MODULE, init_dont_hang_init, [self()], 1000, []), ok - catch _:Error -> - io:format("Error ~p /= ~p ~n",[erlang:get_stacktrace(), StartLinkRes]), + catch _:Error:Stacktrace -> + io:format("Error ~p /= ~p ~n",[Stacktrace, StartLinkRes]), exit(Error) end. @@ -463,7 +504,7 @@ stop(_Config) -> %% System message is handled, but process dies with other reason %% than the given (in system_terminate/4 below) Pid5 = proc_lib:spawn(SysMsgProc), - {'EXIT',{badmatch,2}} = (catch proc_lib:stop(Pid5,crash,infinity)), + {'EXIT',{{badmatch,2},_Stacktrace}} = (catch proc_lib:stop(Pid5,crash,infinity)), false = erlang:is_process_alive(Pid5), %% Local registered name @@ -489,7 +530,7 @@ stop(_Config) -> {'EXIT',noproc} = (catch proc_lib:stop({to_stop,Node})), true = test_server:stop_node(Node), - + %% Remote registered name, but non-existing node {'EXIT',{{nodedown,Node},_}} = (catch proc_lib:stop({to_stop,Node})), ok. @@ -501,47 +542,90 @@ system_terminate(Reason,_Parent,_Deb,_State) -> t_format(_Config) -> - error_logger:tty(false), + {ok,#{level:=Level}} = logger:get_handler_config(default), + logger:set_handler_config(default,level,none), + error_logger:add_report_handler(?MODULE, self()), try t_format() after - error_logger:tty(true) + error_logger:delete_report_handler(?MODULE), + logger:set_handler_config(default,level,Level) end, ok. t_format() -> - error_logger:add_report_handler(?MODULE, self()), - Pid = proc_lib:spawn(fun t_format_looper/0), + Pid = proc_lib:spawn(fun '\x{aaa}t_format_looper'/0), HugeData = gb_sets:from_list(lists:seq(1, 100)), - Pid ! {die,HugeData}, + SomeData1 = list_to_atom([246]), + SomeData2 = list_to_atom([1024]), + Pid ! {SomeData1,SomeData2}, + Pid ! {die,{HugeData,SomeData1,SomeData2}}, Report = receive {crash_report, Pid, Report0} -> Report0 end, - Usz = do_test_format(Report, unlimited), - Tsz = do_test_format(Report, 20), + Usz = do_test_format(Report, latin1, unlimited), + Tsz = do_test_format(Report, latin1, 20), if Tsz >= Usz -> - ?t:fail(); + ct:fail(failed); + true -> + ok + end, + + UszU = do_test_format(Report, unicode, unlimited), + TszU = do_test_format(Report, unicode, 20), + + if + TszU >= UszU -> + ct:fail(failed); true -> ok end, ok. +t_format_arbitrary(_Config) -> + {ok,#{level:=Level}} = logger:get_handler_config(default), + logger:set_handler_config(default,level,none), + try + t_format_arbitrary() + after + logger:set_handler_config(default,level,Level) + end, + ok. + +t_format_arbitrary() -> + A = list_to_atom([1024]), + do_test_format([fake_report, A], unlimited), + do_test_format([fake_report, A], 20), + + do_test_format([fake_report, foo], unlimited), + do_test_format([fake_report, foo], 20), + do_test_format([fake_report, []], unlimited), + do_test_format([fake_report, []], 20). + do_test_format(Report, Depth) -> - io:format("*** Depth = ~p", [Depth]), - S0 = proc_lib:format(Report, latin1, Depth), + do_test_format(Report, latin1, Depth), + do_test_format(Report, unicode, Depth). + +do_test_format(Report, Encoding, Depth) -> + io:format("*** Depth = ~p, Encoding = ~p", [Depth, Encoding]), + S0 = proc_lib:format(Report, Encoding, Depth), S = lists:flatten(S0), - io:put_chars(S), + case Encoding of + latin1 -> io:format("~s\n", [S]); + _ -> io:format("~ts\n", [S]) + end, length(S). -t_format_looper() -> +'\x{aaa}t_format_looper'() -> receive {die,Data} -> exit(Data); - _ -> - t_format_looper() + M -> + put(M, M), + '\x{aaa}t_format_looper'() end. %%----------------------------------------------------------------- @@ -549,9 +633,9 @@ t_format_looper() -> %%----------------------------------------------------------------- init(Tester) -> {ok, Tester}. - + handle_event({error_report, _GL, {Pid, crash_report, Report}}, Tester) -> - io:format("~s\n", [proc_lib:format(Report)]), + io:format("~ts\n", [proc_lib:format(Report)]), Tester ! {crash_report, Pid, Report}, {ok, Tester}; handle_event(_Event, State) -> |