From 87fce5499baa1824eebe822cc62608c5bb58d3cf Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Tue, 17 Aug 2010 13:34:35 +0200 Subject: Add SASL test suite --- lib/sasl/test/rb_SUITE.erl | 606 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 606 insertions(+) create mode 100644 lib/sasl/test/rb_SUITE.erl (limited to 'lib/sasl/test/rb_SUITE.erl') diff --git a/lib/sasl/test/rb_SUITE.erl b/lib/sasl/test/rb_SUITE.erl new file mode 100644 index 0000000000..b53c382609 --- /dev/null +++ b/lib/sasl/test/rb_SUITE.erl @@ -0,0 +1,606 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(rb_SUITE). +-include("test_server.hrl"). + +-compile(export_all). + +-define(SUP,rb_SUITE_sup). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +all() -> + no_group_cases() ++ [{group,running_error_logger}]. + +no_group_cases() -> + [help, + start_error_stop]. + +groups() -> + [{running_error_logger,[shuffle],[show, + list, + rescan, + start_stop_log, + grep, + filter_filter, + filter_date, + filter_filter_and_date, + filter_re_no + ]}]. + + +all(suite) -> + no_group_cases() ++ + [{conf, + install_mf_h, + element(3,lists:keyfind(running_error_logger,1,groups())), + remove_mf_h} + ]. + + +init_per_suite(Config) -> + ?line PrivDir = ?config(priv_dir,Config), + ?line RbDir = filename:join(PrivDir,rb), + ?line ok = file:make_dir(RbDir), + NewConfig = [{rb_dir,RbDir}|Config], + reset_sasl(NewConfig), + NewConfig. + +end_per_suite(_Config) -> + ok. + +init_per_group(running_error_logger,Config) -> + install_mf_h(Config). + +end_per_group(running_error_logger,Config) -> + remove_mf_h(Config). + +init_per_testcase(_Case,Config) -> + case whereis(?SUP) of + undefined -> ok; + Pid -> kill(Pid) + end, + empty_error_logs(Config), + Config. + +kill(Pid) -> + Ref = erlang:monitor(process,Pid), + exit(Pid,kill), + receive {'DOWN', Ref, process, Pid, _Info} -> ok end. + +end_per_testcase(Case,Config) -> + try apply(?MODULE,Case,[cleanup,Config]) + catch error:undef -> ok + end, + ok. + + +%%%----------------------------------------------------------------- + +help() -> help(suite). +help(suite) -> []; +help(_Config) -> + ?line Help = capture(fun() -> rb:h() end), + ?line "Report Browser Tool - usage" = hd(Help), + ?line "rb:stop - stop the rb_server" = lists:last(Help), + ok. + + +start_error_stop() -> start_error_stop(suite). +start_error_stop(suite) -> []; +start_error_stop(Config) -> + ?line RbDir = ?config(rb_dir,Config), + + ?line {error,{"cannot locate report directory",_}} = rb:start(), + + + ?line ok = application:set_env(sasl,error_logger_mf_dir,"invaliddir"), + ?line ok = application:set_env(sasl,error_logger_mf_maxbytes,1000), + ?line ok = application:set_env(sasl,error_logger_mf_maxfiles,2), + ?line restart_sasl(), + ?line {error,{"cannot read the index file",_}} = rb:start(), + ?line ok = application:set_env(sasl,error_logger_mf_dir,RbDir), + ?line restart_sasl(), + ?line {ok,_} = rb:start(), + + ?line ok = rb:stop(), + ok. + + +%% start_opts(suite) -> []; +%% start_opts(Config) -> +%% PrivDir = ?config(priv_dir,Config), +%% RbDir = filename:join(PrivDir,rb_opts), +%% ok = file:make_dir(RbDir), + + +install_mf_h(Config) -> + ?line RbDir = ?config(rb_dir,Config), + ?line ok = application:set_env(sasl,error_logger_mf_dir,RbDir), + ?line ok = application:set_env(sasl,error_logger_mf_maxbytes,5000), + ?line ok = application:set_env(sasl,error_logger_mf_maxfiles,2), + ?line restart_sasl(), + Config. + +remove_mf_h(_Config) -> + ok. + + + +show() -> show(suite). +show(suite) -> []; +show(Config) -> + ?line PrivDir = ?config(priv_dir,Config), + ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + + %% Insert some reports in the error log and start rb + init_error_logs(), + ?line ok = start_rb(OutFile), + + %% Show all reports + ?line All = check_report(fun() -> rb:show() end,OutFile), + + %% Show by number + ?line [{_,First}] = check_report(fun() -> rb:show(1) end,OutFile), + ?line {1,First} = lists:keyfind(1,1,All), + + %% Show by type + ?line [{_,CR}] = check_report(fun() -> rb:show(crash_report) end,OutFile), + ?line true = contains(CR,"rb_test_crash"), + ?line [{_,EC},{_,EM}] = check_report(fun() -> rb:show(error) end,OutFile), + ?line true = contains(EC,"rb_test_crash"), + ?line true = contains(EM,"rb_test_error_msg"), + ?line [{_,ER}] = check_report(fun() -> rb:show(error_report) end,OutFile), + ?line true = contains(ER,"rb_test_error"), + ?line [{_,IR}] = check_report(fun() -> rb:show(info_report) end,OutFile), + ?line true = contains(IR,"rb_test_info"), + ?line [{_,IM}] = check_report(fun() -> rb:show(info_msg) end,OutFile), + ?line true = contains(IM,"rb_test_info_msg"), + ?line [_|_] = check_report(fun() -> rb:show(progress) end,OutFile), + ?line [{_,SR}] = check_report(fun() -> rb:show(supervisor_report) end, + OutFile), + ?line true = contains(SR,"child_terminated"), + ?line true = contains(SR,"{rb_SUITE,rb_test_crash}"), + + ok. + +list() -> list(suite). +list(suite) -> []; +list(Config) -> + ?line PrivDir = ?config(priv_dir,Config), + ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + + %% Insert some reports in the error log and start rb + init_error_logs(), + ?line ok = start_rb(OutFile), + + ?line All = capture(fun() -> rb:list() end), + ?line [{crash_report,[_]=CR}, + {error,[_,_]=EM}, + {error_report,[_]=ER}, + {info_msg,[_]=IM}, + {info_report,[_]=IR}, + {progress,[_|_]=P}, + {supervisor_report,[_]=SR}] = sort_list(All), + + ?line [{crash_report,CR}] = + sort_list(capture(fun() -> rb:list(crash_report) end)), + ?line [{error,EM}] = + sort_list(capture(fun() -> rb:list(error) end)), + ?line [{error_report,ER}] = + sort_list(capture(fun() -> rb:list(error_report) end)), + ?line [{info_msg,IM}] = + sort_list(capture(fun() -> rb:list(info_msg) end)), + ?line [{info_report,IR}] = + sort_list(capture(fun() -> rb:list(info_report) end)), + ?line [{progress,P}] = + sort_list(capture(fun() -> rb:list(progress) end)), + ?line [{supervisor_report,SR}] = + sort_list(capture(fun() -> rb:list(supervisor_report) end)), + + ok. + + +grep() -> grep(suite). +grep(suite) -> []; +grep(Config) -> + ?line PrivDir = ?config(priv_dir,Config), + ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + + %% Insert some reports in the error log and start rb + init_error_logs(), + ?line ok = start_rb(OutFile), + + ?line [{_,S}, + {_,CR}, + {_,EC}, + {_,IM}, + {_,IR}, + {_,EM}, + {_,ER}]= check_report(fun() -> rb:grep("rb_test_") end,OutFile), + ?line true = contains(S, "rb_test_crash"), + ?line true = contains(CR, "rb_test_crash"), + ?line true = contains(EC, "rb_test_crash"), + ?line true = contains(IM, "rb_test_info_msg"), + ?line true = contains(IR, "rb_test_info"), + ?line true = contains(EM, "rb_test_error_msg"), + ?line true = contains(ER, "rb_test_error"), + ok. + + +filter_filter() -> filter_filter(suite). +filter_filter(suite) -> []; +filter_filter(Config) -> + ?line PrivDir = ?config(priv_dir,Config), + ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + + %% Insert some reports in the error log and start rb + init_error_logs(), + ?line ok = start_rb(OutFile), + + ?line All = check_report(fun() -> rb:show() end,OutFile), + + ?line ER = [_] = rb_filter([{rb_SUITE,rb_test_error}],OutFile), + ?line [] = rb_filter([{rb_SUITE,rb_test}],OutFile), + ?line _E = [_,_] = rb_filter([{rb_SUITE,"rb_test",re}],OutFile), + ?line AllButER = rb_filter([{rb_SUITE,rb_test_error,no}],OutFile), + + {_,AllRep} = lists:unzip(All), + {_,ERRep} = lists:unzip(ER), + {_,AllButERRep} = lists:unzip(AllButER), + ?line AllButERRep = AllRep -- ERRep, + + ok. + +filter_date() -> filter_date(suite). +filter_date(suite) -> []; +filter_date(Config) -> + ?line PrivDir = ?config(priv_dir,Config), + ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + + + %% Insert some reports in the error log and start rb + init_error_logs(), + Between1 = calendar:local_time(), + timer:sleep(1000), + Between2 = calendar:local_time(), + ?line ok = start_rb(OutFile), + + ?line All = check_report(fun() -> rb:show() end,OutFile), + + Before = calendar:gregorian_seconds_to_datetime( + calendar:datetime_to_gregorian_seconds(calendar:local_time()) - 10), + After = calendar:gregorian_seconds_to_datetime( + calendar:datetime_to_gregorian_seconds(calendar:local_time()) + 1), + + ?line All = rb_filter([],{Before,from},OutFile), + ?line All = rb_filter([],{After,to},OutFile), + ?line [] = rb_filter([],{Before,to},OutFile), + ?line [] = rb_filter([],{After,from},OutFile), + ?line All = rb_filter([],{Before,After},OutFile), + + %%?t:format("~p~n",[All]), + ?line AllButLast = [{N-1,R} || {N,R} <- tl(All)], + ?line AllButLast = rb_filter([],{Before,Between1},OutFile), + + ?line Last = hd(All), + ?line [Last] = rb_filter([],{Between2,After},OutFile), + + ok. + +filter_filter_and_date() -> filter_filter_and_date(suite). +filter_filter_and_date(suite) -> []; +filter_filter_and_date(Config) -> + ?line PrivDir = ?config(priv_dir,Config), + ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + + + %% Insert some reports in the error log and start rb + init_error_logs(), + Between1 = calendar:local_time(), + timer:sleep(1000), + Between2 = calendar:local_time(), + ?line error_logger:error_report([{rb_SUITE,rb_test_filter}]), + ?line ok = start_rb(OutFile), + + Before = calendar:gregorian_seconds_to_datetime( + calendar:datetime_to_gregorian_seconds(calendar:local_time()) - 10), + After = calendar:gregorian_seconds_to_datetime( + calendar:datetime_to_gregorian_seconds(calendar:local_time()) + 1), + + ?line All = check_report(fun() -> rb:show() end,OutFile), + ?line Last = hd(All), + + ?line [_,_,_] = rb_filter([{rb_SUITE,"rb_test",re}],{Before,After},OutFile), + ?line [_,_] = rb_filter([{rb_SUITE,"rb_test",re}],{Before,Between1},OutFile), + ?line [_] = rb_filter([{rb_SUITE,"rb_test",re}],{Between2,After},OutFile), + ?line [_] = rb_filter([{rb_SUITE,rb_test_filter}],{Before,After},OutFile), + ?line [] = rb_filter([{rb_SUITE,rb_test_filter}],{Before,Between1},OutFile), + ?line [Last] = rb_filter([{rb_SUITE,rb_test_filter,no}],{Between2,After},OutFile), + ?line {_,Str} = Last, + ?line false = contains(Str,"rb_test_filter"), + + ok. + + +filter_re_no() -> filter_re_no(suite). +filter_re_no(suite) -> []; +filter_re_no(Config) -> + ?line PrivDir = ?config(priv_dir,Config), + ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + + %% Insert some reports in the error log and start rb + init_error_logs(), + ?line ok = start_rb(OutFile), + + ?line All = check_report(fun() -> rb:show() end,OutFile), + + ?line E = [_,_] = rb_filter([{rb_SUITE,"rb_test",re}],OutFile), + ?line AllButE = rb_filter([{rb_SUITE,"rb_test",re,no}],OutFile), + + {_,AllRep} = lists:unzip(All), + {_,ERep} = lists:unzip(E), + {_,AllButERep} = lists:unzip(AllButE), + ?line AllButERep = AllRep -- ERep, + + ok. + + +rescan() -> rescan(suite). +rescan(suite) -> []; +rescan(Config) -> + ?line PrivDir = ?config(priv_dir,Config), + ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + + %% Start rb + ?line ok = start_rb(OutFile), + + %% Insert one more report and check that the list is longer. Note + %% that there might be two more reports, since the progress report + %% from starting rb_server might not be included before the rescan. + ?line AllBefore = capture(fun() -> rb:list() end), + ?line error_logger:error_report([{rb_SUITE,rb_test_rescan}]), + ?line ok = rb:rescan(), + ?line AllAfter = capture(fun() -> rb:list() end), + ?line Diff = length(AllAfter) - length(AllBefore), + ?line true = (Diff >= 1), + + ok. + + +start_stop_log() -> start_stop_log(suite). +start_stop_log(suite) -> []; +start_stop_log(Config) -> + ?line PrivDir = ?config(priv_dir,Config), + ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + ?line ok = file:write_file(OutFile,[]), + + %% Start rb and check that show is printed to standard_io + ?line ok = start_rb(), + ?line StdioResult = [_|_] = capture(fun() -> rb:show(1) end), + ?line {ok,<<>>} = file:read_file(OutFile), + + %% Start log and check that show is printed to log and not to standad_io + ?line ok = rb:start_log(OutFile), + ?line [] = capture(fun() -> rb:show(1) end), + ?line {ok,Bin} = file:read_file(OutFile), + ?line true = (Bin =/= <<>>), + + %% Stop log and check that show is printed to standard_io and not to log + ?line ok = rb:stop_log(), + ?line ok = file:write_file(OutFile,[]), + ?line StdioResult = capture(fun() -> rb:show(1) end), + ?line {ok,<<>>} = file:read_file(OutFile), + + %% Test that standard_io is used if log file can not be opened + ?line ok = rb:start_log(filename:join(nonexistingdir,"newfile.txt")), + ?line StdioResult = capture(fun() -> rb:show(1) end), + ?line {ok,<<>>} = file:read_file(OutFile), + + ok. + + +%%%----------------------------------------------------------------- +%%% INTERNAL FUNCTIONS + +restart_sasl() -> + application:stop(sasl), + ok = application:start(sasl), + wait_for_sasl(). + +reset_sasl(Config) -> + application:unset_env(sasl,error_logger_mf_dir), + application:unset_env(sasl,error_logger_mf_maxbytes), + application:unset_env(sasl,error_logger_mf_maxfiles), + empty_error_logs(Config). + +empty_error_logs(Config) -> + application:stop(sasl), + catch delete_content(?config(rb_dir, Config)), + ok = application:start(sasl), + wait_for_sasl(). + +wait_for_sasl() -> + wait_for_sasl(50). +wait_for_sasl(0) -> + ?t:fail("sasl application did not start within 5 seconds"); +wait_for_sasl(N) -> + case lists:keymember(sasl,1,application:which_applications()) of + true -> + ok; + false -> + timer:sleep(100), + wait_for_sasl(N-1) + end. + +start_rb(OutFile) -> + do_start_rb([{start_log,OutFile}]). +start_rb() -> + do_start_rb([]). + +do_start_rb(Opts) -> + {ok,Pid} = rb:start(Opts), + + %% Wait for process to started, then wait a little bit more + sys:get_status(Pid), + timer:sleep(500), + + %% Make sure printouts (e.g. from rb:list(), come to the test log, + %% and that they can be captured. + group_leader(group_leader(),Pid), + ok. + + +delete_tree(Dir) -> + case filelib:is_dir(Dir) of + true -> + delete_content(Dir), + file:del_dir(Dir); + false -> + ok = file:delete(Dir) + end. + +delete_content(Dir) -> + {ok,Files} = file:list_dir(Dir), + lists:foreach(fun(File) -> delete_tree(filename:join(Dir,File)) end, + Files). + +init_error_logs() -> + ?line error_logger:error_report([{rb_SUITE,rb_test_error}]), + ?line error_logger:error_msg("rb_test_error_msg"), + ?line error_logger:info_report([{rb_SUITE,rb_test_info}]), + ?line error_logger:info_msg("rb_test_info_msg"), + ?line _Pid = start(), + ?line Ref = erlang:monitor(process,?MODULE), + ?line gen_server:cast(?MODULE,crash), + ?line receive {'DOWN',Ref,process,_,{rb_SUITE,rb_test_crash}} -> ok + after 2000 -> + ?t:format("Got: ~p~n",[process_info(self(),messages)]), + ?t:fail("rb_SUITE server never died") + end, + ?line erlang:demonitor(Ref), + ?line wait_for_server(), + ok. + +wait_for_server() -> + case whereis(?MODULE) of + undefined -> + wait_for_server(); + Pid -> + timer:sleep(100), % allow the supervisor report to be written + Pid + end. + +capture(Fun) -> + ?t:capture_start(), + ok = Fun(), + timer:sleep(1000), + ?t:capture_stop(), + string:tokens(lists:append(?t:capture_get()),"\n"). + + +rb_filter(Filter,OutFile) -> + check_report(fun() -> rb:filter(Filter) end, OutFile). +rb_filter(Filter,Dates,OutFile) -> + check_report(fun() -> rb:filter(Filter,Dates) end, OutFile). + + +%% This function first empties the given report file, then executes +%% the fun and returns a list of {N,Report}, where Report is a report +%% read from the file and N is an integer. The newest report has the +%% lowest number. +%% If the fun was a call to rb:show() (i.e. with no arguments), then +%% the numbering (N) will be the same as rb's own numbering (as shown +%% by rb:list()). +check_report(Fun,File) -> + file:delete(File), + rb:rescan([{start_log,File}]), + ok = Fun(), + {ok,Bin} = file:read_file(File), + Reports = split_reports(binary_to_list(Bin),[],[]), + lists:zip(lists:seq(1,length(Reports)),Reports). + +-define(report_header_line,"\n===============================================================================\n"). +split_reports([],Report,Reports) -> + add_report(Report,Reports); +split_reports(Text,Report,Reports) -> + case Text of + ?report_header_line++Rest -> + {Heading,PrevReport} = lists:splitwith(fun($\n) -> false; + (_) -> true + end, + Report), + split_reports(Rest, + ?report_header_line++Heading, + add_report(PrevReport,Reports)); + [Ch|Rest] -> + split_reports(Rest,[Ch|Report],Reports) + end. + +add_report(Report,Reports) -> + case string:strip(Report,both,$\n) of + [] -> Reports; + Report1 -> [lists:reverse(Report1)|Reports] + end. + +%% Returns true if Substr is a substring of Str. +contains(Str,Substr) -> + 0 =/= string:str(Str,Substr). + +%% Sort the result of rb_list after report type +sort_list(List) -> + sort_list(List,dict:new()). +sort_list([H|T],D) -> + case re:run(H,"\s+[0-9]+\s+([a-z_]+)",[{capture,all_but_first,list}]) of + nomatch -> + sort_list(T,D); + {match,[TypeStr]} -> + sort_list(T,dict:append(list_to_atom(TypeStr),H,D)) + end; +sort_list([],D) -> + lists:sort(dict:to_list(D)). + + +%%%----------------------------------------------------------------- +%%% A dummy supervisor and gen_server used for creating crash- and +%%% supervisor reports +start() -> + {ok,Pid} = + supervisor:start_link({local, ?SUP}, ?MODULE, i_am_supervisor), + unlink(Pid), + Pid. +start_server() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, i_am_server, []). +init(i_am_server) -> + {ok, state}; +init(i_am_supervisor) -> + AChild = {?SUP,{?MODULE,start_server,[]}, + permanent,2000,worker,[?MODULE]}, + {ok,{{one_for_all,1,1}, [AChild]}}. +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. +handle_cast(crash, State) -> + exit({rb_SUITE,rb_test_crash}), + {noreply, State}. +handle_info(_Info, State) -> + {noreply, State}. +terminate(_Reason, _State) -> + ok. + -- cgit v1.2.3