%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2015-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.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
-module(sasl_report_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
-export([gen_server_crash/1, gen_server_crash_unicode/1]).
-export([legacy_gen_server_crash/1, legacy_gen_server_crash_unicode/1]).
-export([crash_me/0,start_link/0,init/1,handle_cast/2,terminate/2]).
-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[gen_server_crash,
gen_server_crash_unicode,
legacy_gen_server_crash,
legacy_gen_server_crash_unicode].
groups() ->
[].
init_per_suite(Config) ->
Config.
end_per_suite(_Config) ->
ok.
init_per_group(_GroupName, Config) ->
Config.
end_per_group(_GroupName, Config) ->
Config.
gen_server_crash(Config) ->
gen_server_crash(Config, latin1).
gen_server_crash_unicode(Config) ->
gen_server_crash(Config, unicode).
legacy_gen_server_crash(Config) ->
legacy_gen_server_crash(Config,latin1).
legacy_gen_server_crash_unicode(Config) ->
legacy_gen_server_crash(Config,unicode).
gen_server_crash(Config, Encoding) ->
TC = list_to_atom(lists:concat([?FUNCTION_NAME,"_",Encoding])),
PrivDir = filename:join(?config(priv_dir,Config),?MODULE),
ConfigFileName = filename:join(PrivDir,TC),
KernelLog = filename:join(PrivDir,lists:concat([TC,"_kernel.log"])),
SaslLog = filename:join(PrivDir,lists:concat([TC,"_sasl.log"])),
KernelConfig = [{logger,[{handler,default,logger_std_h,
#{config=>#{type=>{file,KernelLog}}}}]},
{logger_sasl_compatible,true}],
Modes = [write, {encoding, Encoding}],
SaslConfig = [{sasl_error_logger,{file,SaslLog,Modes}}],
ok = filelib:ensure_dir(SaslLog),
ok = file:write_file(ConfigFileName ++ ".config",
io_lib:format("[{kernel, ~p},~n{sasl, ~p}].",
[KernelConfig,SaslConfig])),
{ok,Node} =
test_server:start_node(
TC, peer,
[{args, ["-pa ",filename:dirname(code:which(?MODULE)),
" -boot start_sasl -kernel start_timer true "
"-config ",ConfigFileName]}]),
%% Set depth
ok = rpc:call(Node,logger,update_formatter_config,[default,depth,30]),
ok = rpc:call(Node,logger,update_formatter_config,[sasl,depth,30]),
%% Make sure remote node logs it's own logs, and current node does
%% not log them.
ok = rpc:call(Node,logger,remove_handler_filter,[default,remote_gl]),
ok = rpc:call(Node,logger,remove_handler_filter,[sasl,remote_gl]),
ok = logger:add_primary_filter(no_remote,{fun(#{meta:=#{pid:=Pid}},_)
when node(Pid)=/=node() -> stop;
(_,_) -> ignore
end,[]}),
ct:log("Local node Logger config:~n~p",
[rpc:call(Node,logger,get_config,[])]),
ct:log("Remote node Logger config:~n~p",
[rpc:call(Node,logger,get_config,[])]),
ct:log("Remote node error_logger handlers: ~p",
[rpc:call(Node,error_logger,which_report_handlers,[])]),
ok = rpc:call(Node,?MODULE,crash_me,[]),
test_server:stop_node(Node),
ok = logger:remove_primary_filter(no_remote),
check_file(KernelLog, utf8, 70000, 150000),
check_file(SaslLog, Encoding, 70000, 150000),
ok = file:delete(KernelLog),
ok = file:delete(SaslLog),
ok.
legacy_gen_server_crash(Config, Encoding) ->
StopFilter = {fun(_,_) -> stop end, ok},
logger:add_handler_filter(default,stop_all,StopFilter),
logger:add_handler_filter(sasl,stop_all,StopFilter),
logger:add_handler_filter(cth_log_redirect,stop_all,StopFilter),
try
do_gen_server_crash(Config, Encoding)
after
logger:remove_handler_filter(default,stop_all),
logger:remove_handler_filter(sasl,stop_all),
logger:remove_handler_filter(cth_log_redirect,stop_all)
end,
ok.
do_gen_server_crash(Config, Encoding) ->
PrivDir = ?config(priv_dir, Config),
LogDir = filename:join(PrivDir, ?MODULE),
KernelLog = filename:join(LogDir, "kernel.log"),
SaslLog = filename:join(LogDir, "sasl.log"),
ok = filelib:ensure_dir(SaslLog),
Modes = [write, {encoding, Encoding}],
application:set_env(kernel, error_logger_format_depth, 30),
error_logger:logfile({open,KernelLog}),
error_logger:add_report_handler(sasl_report_file_h,{SaslLog,Modes,all}),
ct:log("Logger config:~n~p",[logger:get_config()]),
ct:log("error_logger handlers: ~p",[error_logger:which_report_handlers()]),
crash_me(),
error_logger:logfile(close),
error_logger:delete_report_handler(sasl_report_file_h),
check_file(KernelLog, utf8, 70000, 150000),
check_file(SaslLog, Encoding, 70000, 150000),
ok = file:delete(KernelLog),
ok = file:delete(SaslLog),
ok.
check_file(File, Encoding, Min, Max) ->
{ok,Bin} = file:read_file(File),
Base = filename:basename(File),
io:format("*** Contents of ~s ***\n", [Base]),
case Encoding of
latin1 -> io:format("~s\n", [Bin]);
_ -> io:format("~ts\n", [Bin])
end,
Sz = byte_size(Bin),
io:format("Size: ~p (allowed range is ~p..~p)\n",
[Sz,Min,Max]),
if
Sz < Min ->
%% Truncated? Other problem?
?t:fail({too_short,Base});
Sz > Max ->
%% Truncation doesn't work?
?t:fail({too_big,Base});
true ->
ok
end.
%%%
%%% gen_server that crashes.
%%%
crash_me() ->
{ok,SuperPid} = supervisor:start_link(sasl_report_suite_supervisor, []),
[{Id,Pid,_,_}] = supervisor:which_children(SuperPid),
HugeData = gb_sets:from_list(lists:seq(1, 100000)),
SomeData1 = list_to_atom([246]),
SomeData2 = list_to_atom([1024]),
gen_server:cast(Pid, {HugeData,SomeData1,SomeData2}),
Ref = monitor(process, Pid),
receive
{'DOWN',Ref,process,Pid,_} ->
supervisor:terminate_child(SuperPid, Id),
unlink(SuperPid),
exit(SuperPid, kill),
ok
end.
start_link() ->
gen_server:start_link(?MODULE, [], []).
init(_) ->
St = <<0:100000/unit:8>>,
{ok,St}.
handle_cast(Big, St) ->
Seq = lists:seq(1, 10000),
Latin1Atom = list_to_atom([246]),
UnicodeAtom = list_to_atom([1024]),
put(Latin1Atom, Latin1Atom),
put(UnicodeAtom, UnicodeAtom),
self() ! Latin1Atom,
self() ! UnicodeAtom,
self() ! Seq,
self() ! Seq,
self() ! Seq,
self() ! Seq,
self() ! Seq,
x = Big,
{noreply,St}.
terminate(_, _) ->
ok.