diff options
Diffstat (limited to 'lib/common_test/src')
| -rw-r--r-- | lib/common_test/src/ct_hooks.erl | 7 | ||||
| -rw-r--r-- | lib/common_test/src/ct_logs.erl | 82 | ||||
| -rw-r--r-- | lib/common_test/src/ct_netconfc.erl | 94 | ||||
| -rw-r--r-- | lib/common_test/src/ct_run.erl | 2 | ||||
| -rw-r--r-- | lib/common_test/src/ct_util.erl | 69 | ||||
| -rw-r--r-- | lib/common_test/src/cth_log_redirect.erl | 141 | 
6 files changed, 323 insertions, 72 deletions
| diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl index 3d87a82e24..e845e9e908 100644 --- a/lib/common_test/src/ct_hooks.erl +++ b/lib/common_test/src/ct_hooks.erl @@ -50,9 +50,8 @@  -spec init(State :: term()) -> ok |  			       {fail, Reason :: term()}.  init(Opts) -> -    call(get_new_hooks(Opts, undefined) ++ get_builtin_hooks(Opts), +    call(get_builtin_hooks(Opts) ++ get_new_hooks(Opts, undefined),  	 ok, init, []). -		        %% @doc Called after all suites are done.  -spec terminate(Hooks :: term()) -> @@ -276,8 +275,10 @@ get_new_hooks(Config, Fun) ->  		end, get_new_hooks(Config)).  get_new_hooks(Config) when is_list(Config) -> -    lists:flatmap(fun({?config_name, HookConfigs}) -> +    lists:flatmap(fun({?config_name, HookConfigs}) when is_list(HookConfigs) ->  			  HookConfigs; +		     ({?config_name, HookConfig}) when is_atom(HookConfig) -> +			  [HookConfig];  		     (_) ->  			  []  		  end, Config); diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index f5355bfefe..1a6e4d31a8 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -61,6 +61,7 @@  -define(index_name, "index.html").  -define(totals_name, "totals.info").  -define(log_cache_name, "ct_log_cache"). +-define(misc_io_log, "misc_io.log.html").  -define(table_color1,"#ADD8E6").  -define(table_color2,"#E4F0FE"). @@ -446,6 +447,8 @@ tc_print(Category,Importance,Format,Args) ->  		   ct_util:get_verbosity('$unspecified');  	       {error,bad_invocation} ->  		   ?MAX_VERBOSITY; +	       {error,_Failure} -> +		   ?MAX_VERBOSITY;  	       Val ->  		   Val  	   end, @@ -521,7 +524,7 @@ int_footer() ->  div_header(Class) ->      div_header(Class,"User").  div_header(Class,Printer) -> -    "<div class=\"" ++ atom_to_list(Class) ++ "\"><b>*** " ++ Printer ++ +    "\n<div class=\"" ++ atom_to_list(Class) ++ "\"><b>*** " ++ Printer ++      " " ++ log_timestamp(now()) ++ " ***</b>".  div_footer() ->      "</div>". @@ -615,6 +618,34 @@ logger(Parent, Mode, Verbosity) ->  		    end  	    end      end, + +    test_server_io:start_link(), +    MiscIoName = filename:join(Dir, ?misc_io_log), +    {ok,MiscIoFd} = file:open(MiscIoName, +			      [write,{encoding,utf8}]), +    test_server_io:set_fd(unexpected_io, MiscIoFd), + +    {MiscIoHeader,MiscIoFooter} = +	case get_ts_html_wrapper("Pre/post-test I/O log", Dir, false, +				 Dir, undefined, utf8) of +	    {basic_html,UH,UF} -> +		{UH,UF}; +	    {xhtml,UH,UF} -> +		{UH,UF} +	end, +    io:put_chars(MiscIoFd, +		 [MiscIoHeader, +		  "<a name=\"pretest\"></a>\n", +		  xhtml("<br>\n<h2>Pre-test Log</h2>", +			"<br />\n<h3>PRE-TEST LOG</h3>"), +		  "\n<pre>\n"]), +    MiscIoDivider = +	"\n<a name=\"posttest\"></a>\n"++ +	xhtml("</pre>\n<br><h2>Post-test Log</h2>\n<pre>\n", +	      "</pre>\n<br />\n<h3>POST-TEST LOG</h3>\n<pre>\n"), +    ct_util:set_testdata_async({misc_io_log,{filename:absname(MiscIoName), +					     MiscIoDivider,MiscIoFooter}}), +      ct_event:notify(#event{name=start_logging,node=node(),  			   data=AbsDir}),      make_all_runs_index(start), @@ -625,7 +656,7 @@ logger(Parent, Mode, Verbosity) ->      end,      file:set_cwd(Dir),      make_last_run_index(Time), -    CtLogFd = open_ctlog(), +    CtLogFd = open_ctlog(?misc_io_log),      io:format(CtLogFd,int_header()++int_footer(),  	      [log_timestamp(now()),"Common Test Logger started"]),      Parent ! {started,self(),{Time,filename:absname("")}}, @@ -690,14 +721,15 @@ logger_loop(State) ->  				false ->  				    %% Group leader is dead, so write to the  				    %% CtLog or unexpected_io log instead -				    unexpected_io(Pid,Category,List,State), +				    unexpected_io(Pid,Category,Importance, +						  List,State),  				    logger_loop(State)			      			    end;  			{ct_log,_Fd,TCGLs} ->  			    %% If category is ct_internal then write  			    %% to ct_log, else write to unexpected_io  			    %% log -			    unexpected_io(Pid,Category,List,State), +			    unexpected_io(Pid,Category,Importance,List,State),  			    logger_loop(State#logger_state{  					  tc_groupleaders = TCGLs})  		    end; @@ -798,7 +830,7 @@ print_to_log(sync, FromPid, Category, TCGL, List, State) ->  	    IoFun = create_io_fun(FromPid, State),  	    io:format(TCGL,"~ts", [lists:foldl(IoFun, [], List)]);         true -> -	    unexpected_io(FromPid,Category,List,State) +	    unexpected_io(FromPid,Category,?MAX_IMPORTANCE,List,State)      end,      State; @@ -814,7 +846,8 @@ print_to_log(async, FromPid, Category, TCGL, List, State) ->  		end;  	   true ->  		fun() -> -			unexpected_io(FromPid,Category,List,State) +			unexpected_io(FromPid,Category,?MAX_IMPORTANCE, +				      List,State)  		end  	end,      case State#logger_state.async_print_jobs of @@ -918,7 +951,7 @@ set_evmgr_gl(GL) ->  	EvMgrPid -> group_leader(GL,EvMgrPid)      end. -open_ctlog() -> +open_ctlog(MiscIoName) ->      {ok,Fd} = file:open(?ct_log_name,[write,{encoding,utf8}]),      io:format(Fd, header("Common Test Framework Log", {[],[1,2],[]}), []),      case file:consult(ct_run:variables_file_name("../")) of @@ -933,10 +966,21 @@ open_ctlog() ->  		      "No configuration found for test!!\n",  		      [Variables,Reason])      end, +    io:format(Fd,  +	      xhtml("<br><br><h2>Pre/post-test I/O Log</h2>\n", +		    "<br /><br />\n<h4>PRE/POST TEST I/O LOG</h4>\n"), []),     +    io:format(Fd, +	      "\n<ul>\n" +	      "<li><a href=\"~ts#pretest\">" +	      "View I/O logged before the test run</a></li>\n" +	      "<li><a href=\"~ts#posttest\">" +	      "View I/O logged after the test run</a></li>\n</ul>\n", +	      [MiscIoName,MiscIoName]), +      print_style(Fd,undefined),      io:format(Fd,  -	      xhtml("<br><br><h2>Progress Log</h2>\n<pre>\n", -		    "<br /><br /><h4>PROGRESS LOG</h4>\n<pre>\n"), []), +	      xhtml("<br><h2>Progress Log</h2>\n<pre>\n", +		    "<br />\n<h4>PROGRESS LOG</h4>\n<pre>\n"), []),      Fd.  print_style(Fd,undefined) -> @@ -2852,6 +2896,9 @@ make_relative1(DirTs, CwdTs) ->  %%% @doc  %%%  get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) -> +    get_ts_html_wrapper(TestName, undefined, PrintLabel, Cwd, TableCols, Encoding). + +get_ts_html_wrapper(TestName, Logdir, PrintLabel, Cwd, TableCols, Encoding) ->      TestName1 = if is_list(TestName) ->  			lists:flatten(TestName);  		   true -> @@ -2872,7 +2919,12 @@ get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) ->  		end  	end,      CTPath = code:lib_dir(common_test), -    {ok,CtLogdir} = get_log_dir(true), + +    {ok,CtLogdir} = +	if Logdir == undefined -> get_log_dir(true); +	   true -> {ok,Logdir} +	end, +      AllRuns = make_relative(filename:join(filename:dirname(CtLogdir),  					  ?all_runs_name), Cwd),      TestIndex = make_relative(filename:join(filename:dirname(CtLogdir), @@ -3066,10 +3118,12 @@ html_encoding(latin1) ->  html_encoding(utf8) ->      "utf-8". -unexpected_io(Pid,ct_internal,List,#logger_state{ct_log_fd=Fd}=State) -> +unexpected_io(Pid,ct_internal,_Importance,List,State) ->      IoFun = create_io_fun(Pid,State), -    io:format(Fd, "~ts", [lists:foldl(IoFun, [], List)]); -unexpected_io(Pid,_Category,List,State) -> +    io:format(State#logger_state.ct_log_fd, "~ts", +	      [lists:foldl(IoFun, [], List)]); +unexpected_io(Pid,_Category,_Importance,List,State) ->      IoFun = create_io_fun(Pid,State),      Data = io_lib:format("~ts", [lists:foldl(IoFun, [], List)]), -    test_server_io:print_unexpected(Data). +    test_server_io:print_unexpected(Data), +    ok. diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl index e094ee877a..7f10e1db09 100644 --- a/lib/common_test/src/ct_netconfc.erl +++ b/lib/common_test/src/ct_netconfc.erl @@ -247,7 +247,11 @@  -define(is_timeout(T), (is_integer(T) orelse T==infinity)).  -define(is_filter(F), -	(is_atom(F) orelse (is_tuple(F) andalso is_atom(element(1,F))))). +	(?is_simple_xml(F) +	 orelse (F==[]) +	 orelse (is_list(F) andalso ?is_simple_xml(hd(F))))). +-define(is_simple_xml(Xml), +	(is_atom(Xml) orelse (is_tuple(Xml) andalso is_atom(element(1,Xml))))).  -define(is_string(S), (is_list(S) andalso is_integer(hd(S)))).  %%---------------------------------------------------------------------- @@ -540,22 +544,51 @@ get_capabilities(Client) ->  get_capabilities(Client, Timeout) ->      call(Client, get_capabilities, Timeout). -%% @private +%%---------------------------------------------------------------------- +%% @spec send(Client, SimpleXml) -> Result +%% @equiv send(Client, SimpleXml, infinity)  send(Client, SimpleXml) ->      send(Client, SimpleXml, ?DEFAULT_TIMEOUT). -%% @private + +%%---------------------------------------------------------------------- +-spec send(Client, SimpleXml, Timeout) -> Result when +      Client :: client(), +      SimpleXml :: simple_xml(), +      Timeout :: timeout(), +      Result :: ok | {error,error_reason()}. +%% @doc Send an XML document to the server. +%% +%% The given XML document is sent as is to the server. This function +%% can be used for sending XML documents that can not be expressed by +%% other interface functions in this module.  send(Client, SimpleXml, Timeout) ->      call(Client,{send, Timeout, SimpleXml}). -%% @private +%%---------------------------------------------------------------------- +%% @spec send_rpc(Client, SimpleXml) -> Result +%% @equiv send_rpc(Client, SimpleXml, infinity)  send_rpc(Client, SimpleXml) ->      send_rpc(Client, SimpleXml, ?DEFAULT_TIMEOUT). -%% @private + +%%---------------------------------------------------------------------- +-spec send_rpc(Client, SimpleXml, Timeout) -> Result when +      Client :: client(), +      SimpleXml :: simple_xml(), +      Timeout :: timeout(), +      Result :: ok | {error,error_reason()}. +%% @doc Send a Netconf <code>rpc</code> request to the server. +%% +%% The given XML document is wrapped in a valid Netconf +%% <code>rpc</code> request and sent to the server. The +%% <code>message-id</code> and namespace attributes are added to the +%% <code>rpc</code> element. +%% +%% This function can be used for sending <code>rpc</code> requests +%% that can not be expressed by other interface functions in this +%% module.  send_rpc(Client, SimpleXml, Timeout) ->      call(Client,{send_rpc, SimpleXml, Timeout}). - -  %%----------------------------------------------------------------------  %% @spec lock(Client, Target) -> Result  %% @equiv lock(Client, Target, infinity) @@ -761,7 +794,7 @@ create_subscription(Client,Timeout)    when ?is_timeout(Timeout) ->      create_subscription(Client,?DEFAULT_STREAM,Timeout);  create_subscription(Client,Stream) -  when is_list(Stream) -> +  when ?is_string(Stream) ->      create_subscription(Client,Stream,?DEFAULT_TIMEOUT);  create_subscription(Client,Filter)    when ?is_filter(Filter) -> @@ -769,14 +802,14 @@ create_subscription(Client,Filter)  			?DEFAULT_TIMEOUT).  create_subscription(Client,Stream,Timeout) -  when is_list(Stream) andalso +  when ?is_string(Stream) andalso         ?is_timeout(Timeout) ->      call(Client,{send_rpc_op,{create_subscription,self()},  		 [Stream,undefined,undefined,undefined],  		 Timeout});  create_subscription(Client,StartTime,StopTime) -  when is_list(StartTime) andalso -       is_list(StopTime) -> +  when ?is_string(StartTime) andalso +       ?is_string(StopTime) ->      create_subscription(Client,?DEFAULT_STREAM,StartTime,StopTime,  			?DEFAULT_TIMEOUT);  create_subscription(Client,Filter,Timeout) @@ -784,28 +817,28 @@ create_subscription(Client,Filter,Timeout)         ?is_timeout(Timeout) ->      create_subscription(Client,?DEFAULT_STREAM,Filter,Timeout);  create_subscription(Client,Stream,Filter) -  when is_list(Stream) andalso +  when ?is_string(Stream) andalso         ?is_filter(Filter) ->      create_subscription(Client,Stream,Filter,?DEFAULT_TIMEOUT).  create_subscription(Client,StartTime,StopTime,Timeout) -  when is_list(StartTime) andalso -       is_list(StopTime) andalso +  when ?is_string(StartTime) andalso +       ?is_string(StopTime) andalso         ?is_timeout(Timeout) ->      create_subscription(Client,?DEFAULT_STREAM,StartTime,StopTime,Timeout);  create_subscription(Client,Stream,StartTime,StopTime) -  when is_list(Stream) andalso -       is_list(StartTime) andalso -       is_list(StopTime) -> +  when ?is_string(Stream) andalso +       ?is_string(StartTime) andalso +       ?is_string(StopTime) ->      create_subscription(Client,Stream,StartTime,StopTime,?DEFAULT_TIMEOUT);  create_subscription(Client,Filter,StartTime,StopTime)    when ?is_filter(Filter) andalso -       is_list(StartTime) andalso -       is_list(StopTime) -> +       ?is_string(StartTime) andalso +       ?is_string(StopTime) ->      create_subscription(Client,?DEFAULT_STREAM,Filter,  			StartTime,StopTime,?DEFAULT_TIMEOUT);  create_subscription(Client,Stream,Filter,Timeout) -  when is_list(Stream) andalso +  when ?is_string(Stream) andalso         ?is_filter(Filter) andalso         ?is_timeout(Timeout) ->      call(Client,{send_rpc_op,{create_subscription,self()}, @@ -813,18 +846,18 @@ create_subscription(Client,Stream,Filter,Timeout)  		 Timeout}).  create_subscription(Client,Stream,StartTime,StopTime,Timeout) -  when is_list(Stream) andalso -       is_list(StartTime) andalso -       is_list(StopTime) andalso +  when ?is_string(Stream) andalso +       ?is_string(StartTime) andalso +       ?is_string(StopTime) andalso         ?is_timeout(Timeout) ->      call(Client,{send_rpc_op,{create_subscription,self()},  		 [Stream,undefined,StartTime,StopTime],  		 Timeout});  create_subscription(Client,Stream,Filter,StartTime,StopTime) -  when is_list(Stream) andalso +  when ?is_string(Stream) andalso         ?is_filter(Filter) andalso -       is_list(StartTime) andalso -       is_list(StopTime) -> +       ?is_string(StartTime) andalso +       ?is_string(StopTime) ->      create_subscription(Client,Stream,Filter,StartTime,StopTime,?DEFAULT_TIMEOUT).  %%---------------------------------------------------------------------- @@ -832,7 +865,7 @@ create_subscription(Client,Stream,Filter,StartTime,StopTime)  				 Result when        Client :: client(),        Stream :: stream_name(), -      Filter :: simple_xml(), +      Filter :: simple_xml() | [simple_xml()],        StartTime :: xs_datetime(),        StopTime :: xs_datetime(),        Timeout :: timeout(), @@ -855,8 +888,7 @@ create_subscription(Client,Stream,Filter,StartTime,StopTime)  %%   possible events is of interest.  The format of this parameter is  %%   the same as that of the filter parameter in the NETCONF protocol  %%   operations.  If not present, all events not precluded by other -%%   parameters will be sent.  See section 3.6 for more information on -%%   filters.</dd> +%%   parameters will be sent.</dd>  %%  %%   <dt>StartTime:</dt>  %%   <dd>An optional parameter used to trigger the replay feature and @@ -1241,8 +1273,10 @@ filter(undefined) ->      [];  filter({xpath,Filter}) when ?is_string(Filter) ->      [{filter,[{type,"xpath"},{select, Filter}],[]}]; +filter(Filter) when is_list(Filter) -> +    [{filter,[{type,"subtree"}],Filter}];  filter(Filter) -> -    [{filter,[{type,"subtree"}],[Filter]}]. +    filter([Filter]).  maybe_element(_,undefined) ->      []; diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 266ca73417..7c797be03e 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -1883,7 +1883,7 @@ verify_suites(TestSuites) ->  								  atom_to_list(  								    Suite)),  						io:format(user, -							  "Suite ~w not found" +							  "Suite ~w not found "  							  "in directory ~ts~n",  							  [Suite,TestDir]),  						{Found,[{DS,[Name]}|NotFound]} diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl index 68e76c2396..bcc4caa62e 100644 --- a/lib/common_test/src/ct_util.erl +++ b/lib/common_test/src/ct_util.erl @@ -187,6 +187,7 @@ do_start(Parent, Mode, LogDir, Verbosity) ->  	false ->  	    ok      end, +      {StartTime,TestLogDir} = ct_logs:init(Mode, Verbosity),      ct_event:notify(#event{name=test_start, @@ -198,12 +199,26 @@ do_start(Parent, Mode, LogDir, Verbosity) ->  	ok ->  	    Parent ! {self(),started};  	{fail,CTHReason} -> -	    ct_logs:tc_print('Suite Callback',CTHReason,[]), +	    ErrorInfo = if is_atom(CTHReason) -> +				io_lib:format("{~p,~p}", +					      [CTHReason, +					       erlang:get_stacktrace()]); +			   true -> +				CTHReason +			end, +	    ct_logs:tc_print('Suite Callback',ErrorInfo,[]),  	    self() ! {{stop,{self(),{user_error,CTHReason}}},  		      {Parent,make_ref()}}      catch  	_:CTHReason -> -	    ct_logs:tc_print('Suite Callback',CTHReason,[]), +	    ErrorInfo = if is_atom(CTHReason) -> +				io_lib:format("{~p,~p}", +					      [CTHReason, +					       erlang:get_stacktrace()]); +			   true -> +				CTHReason +			end, +	    ct_logs:tc_print('Suite Callback',ErrorInfo,[]),  	    self() ! {{stop,{self(),{user_error,CTHReason}}},  		      {Parent,make_ref()}}      end, @@ -286,14 +301,23 @@ get_start_dir() ->  %% handle verbosity outside ct_util_server (let the client read  %% the verbosity table) to avoid possible deadlock situations  set_verbosity(Elem = {_Category,_Level}) -> -    ets:insert(?verbosity_table, Elem), -    ok. +    try ets:insert(?verbosity_table, Elem) of +	_ -> +	    ok +    catch +	_:Reason -> +	    {error,Reason} +    end. +	  get_verbosity(Category) -> -    case ets:lookup(?verbosity_table, Category) of +    try ets:lookup(?verbosity_table, Category) of  	[{Category,Level}] ->   	    Level;  	_ ->  	    undefined +    catch +	_:Reason -> +	    {error,Reason}      end.  loop(Mode,TestData,StartDir) -> @@ -383,19 +407,38 @@ loop(Mode,TestData,StartDir) ->  	    return(From,StartDir),  	    loop(From,TestData,StartDir);  	{{stop,Info},From} -> +	    test_server_io:reset_state(), +	    {MiscIoName,MiscIoDivider,MiscIoFooter} = +		proplists:get_value(misc_io_log,TestData), +	    {ok,MiscIoFd} = file:open(MiscIoName, +				      [append,{encoding,utf8}]), +	    io:put_chars(MiscIoFd, MiscIoDivider), +	    test_server_io:set_fd(unexpected_io, MiscIoFd), +  	    Time = calendar:local_time(),  	    ct_event:sync_notify(#event{name=test_done,  					node=node(),  					data=Time}), -	    Callbacks = ets:lookup_element(?suite_table, -					   ct_hooks, -					   #suite_data.value), +	    Callbacks = +		try ets:lookup_element(?suite_table, +				       ct_hooks, +				       #suite_data.value) of +		    CTHMods -> CTHMods +		catch +		    %% this is because ct_util failed in init +		    error:badarg -> [] +		end,  	    ct_hooks:terminate(Callbacks),  	    close_connections(ets:tab2list(?conn_table)),  	    ets:delete(?conn_table),  	    ets:delete(?board_table),  	    ets:delete(?suite_table),  	    ets:delete(?verbosity_table), + +	    io:put_chars(MiscIoFd, "\n</pre>\n"++MiscIoFooter), +	    test_server_io:stop([unexpected_io]), +	    test_server_io:finish(), +  	    ct_logs:close(Info, StartDir),  	    ct_event:stop(),  	    ct_config:stop(), @@ -670,8 +713,14 @@ reset_silent_connections() ->  %%% @see ct  stop(Info) ->      case whereis(ct_util_server) of -	undefined -> ok; -	_ -> call({stop,Info}) +	undefined ->  +	    ok; +	CtUtilPid -> +	    Ref = monitor(process, CtUtilPid), +	    call({stop,Info}), +	    receive +		{'DOWN',Ref,_,_,_} -> ok +	    end      end.  %%%----------------------------------------------------------------- diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl index 958b7a94c7..11af1aa346 100644 --- a/lib/common_test/src/cth_log_redirect.erl +++ b/lib/common_test/src/cth_log_redirect.erl @@ -25,16 +25,29 @@  %% CTH Callbacks --export([id/1, init/2, post_init_per_group/4, pre_end_per_group/3, -	 post_end_per_testcase/4]). +-export([id/1, init/2, +	 pre_init_per_suite/3, pre_end_per_suite/3, post_end_per_suite/4, +	 pre_init_per_group/3, post_init_per_group/4, +	 pre_end_per_group/3, post_end_per_group/4, +	 pre_init_per_testcase/3, post_end_per_testcase/4]).  %% Event handler Callbacks  -export([init/1,  	 handle_event/2, handle_call/2, handle_info/2,  	 terminate/1]). +%% Other +-export([handle_remote_events/1]). +  -include("ct.hrl"). +-record(eh_state, {log_func, +		   curr_suite, +		   curr_group, +		   curr_func, +		   parallel_tcs = false, +		   handle_remote_events = false}). +  id(_Opts) ->      ?MODULE. @@ -42,36 +55,62 @@ init(?MODULE, _Opts) ->      error_logger:add_report_handler(?MODULE),      tc_log_async. +pre_init_per_suite(Suite, Config, State) -> +    set_curr_func({Suite,init_per_suite}, Config), +    {Config, State}. + +pre_end_per_suite(Suite, Config, State) -> +    set_curr_func({Suite,end_per_suite}, Config), +    {Config, State}. + +post_end_per_suite(_Suite, Config, Return, State) -> +    set_curr_func(undefined, Config), +    {Return, State}. + +pre_init_per_group(Group, Config, State) -> +    set_curr_func({group,Group,init_per_group}, Config), +    {Config, State}. +  post_init_per_group(Group, Config, Result, tc_log_async) ->      case lists:member(parallel,proplists:get_value(  				 tc_group_properties,Config,[])) of  	true -> -	    {Result, {set_log_func(ct_log),Group}}; +	    {Result, {set_log_func(tc_log),Group}};  	false ->  	    {Result, tc_log_async}      end;  post_init_per_group(_Group, _Config, Result, State) ->      {Result, State}. +pre_init_per_testcase(TC, Config, State) -> +    set_curr_func(TC, Config), +    {Config, State}. +  post_end_per_testcase(_TC, _Config, Result, State) ->      %% Make sure that the event queue is flushed      %% before ending this test case.      gen_event:call(error_logger, ?MODULE, flush, 300000),      {Result, State}. -pre_end_per_group(Group, Config, {ct_log, Group}) -> +pre_end_per_group(Group, Config, {tc_log, Group}) -> +    set_curr_func({group,Group,end_per_group}, Config),      {Config, set_log_func(tc_log_async)}; -pre_end_per_group(_Group, Config, State) -> +pre_end_per_group(Group, Config, State) -> +    set_curr_func({group,Group,end_per_group}, Config),      {Config, State}. +post_end_per_group(_Group, Config, Return, State) -> +    set_curr_func({group,undefined}, Config), +    {Return, State}.  %% Copied and modified from sasl_report_tty_h.erl  init(_Type) -> -    {ok, tc_log_async}. +    {ok, #eh_state{log_func = tc_log_async}}. -handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() -> +handle_event({_Type,GL,_Msg}, #eh_state{handle_remote_events = false} = State) +  when node(GL) /= node() ->      {ok, State}; -handle_event(Event, LogFunc) -> +handle_event(Event, #eh_state{log_func = LogFunc} = State) ->      case lists:keyfind(sasl, 1, application:which_applications()) of  	false ->  	    sasl_not_started; @@ -80,7 +119,8 @@ handle_event(Event, LogFunc) ->  	    SReport = sasl_report:format_report(group_leader(), ErrLogType,  						tag_event(Event)),  	    if is_list(SReport) -> -		    ct_logs:LogFunc(sasl, ?STD_IMPORTANCE, "System", SReport, []); +		    SaslHeader = format_header(State), +		    ct_logs:LogFunc(sasl, ?STD_IMPORTANCE, SaslHeader, SReport, []);  	       true -> %% Report is an atom if no logging is to be done  		    ignore  	    end @@ -88,20 +128,50 @@ handle_event(Event, LogFunc) ->      EReport = error_logger_tty_h:write_event(  		tag_event(Event),io_lib),      if is_list(EReport) -> -	    ct_logs:LogFunc(error_logger, ?STD_IMPORTANCE, "System", EReport, []); +	    ErrHeader = format_header(State), +	    ct_logs:LogFunc(error_logger, ?STD_IMPORTANCE, ErrHeader, EReport, []);         true -> %% Report is an atom if no logging is to be done  	    ignore      end, -    {ok, LogFunc}. +    {ok, State}.  handle_info(_,State) -> {ok, State}.  handle_call(flush,State) ->      {ok, ok, State}; -handle_call({set_logfunc,NewLogFunc},_) -> -    {ok, NewLogFunc, NewLogFunc}; -handle_call(_Query, _State) -> {error, bad_query}. + +handle_call({set_curr_func,{group,Group,Conf},Config}, State) -> +    Parallel = case proplists:get_value(tc_group_properties, Config) of +		   undefined -> false; +		   Props -> lists:member(parallel, Props) +	       end, +    {ok, ok, State#eh_state{curr_group = Group, +			    curr_func = Conf, +			    parallel_tcs = Parallel}}; +handle_call({set_curr_func,{group,undefined},_Config}, State) -> +    {ok, ok, State#eh_state{curr_group = undefined, +			    curr_func = undefined, +			    parallel_tcs = false}}; +handle_call({set_curr_func,{Suite,Conf},_Config}, State) -> +    {ok, ok, State#eh_state{curr_suite = Suite, +			    curr_func = Conf, +			    parallel_tcs = false}}; +handle_call({set_curr_func,undefined,_Config}, State) -> +    {ok, ok, State#eh_state{curr_suite = undefined, +			    curr_func = undefined, +			    parallel_tcs = false}}; +handle_call({set_curr_func,TC,_Config}, State) -> +    {ok, ok, State#eh_state{curr_func = TC}}; + +handle_call({set_logfunc,NewLogFunc}, State) -> +    {ok, NewLogFunc, State#eh_state{log_func = NewLogFunc}}; + +handle_call({handle_remote_events,Bool}, State) -> +    {ok, ok, State#eh_state{handle_remote_events = Bool}}; + +handle_call(_Query, _State) -> +    {error, bad_query}.  terminate(_State) ->      error_logger:delete_report_handler(?MODULE), @@ -110,5 +180,48 @@ terminate(_State) ->  tag_event(Event) ->      {calendar:local_time(), Event}. +set_curr_func(CurrFunc, Config) -> +    gen_event:call(error_logger, ?MODULE, {set_curr_func, CurrFunc, Config}). +  set_log_func(Func) ->      gen_event:call(error_logger, ?MODULE, {set_logfunc, Func}). + +handle_remote_events(Bool) -> +    gen_event:call(error_logger, ?MODULE, {handle_remote_events, Bool}). + +%%%----------------------------------------------------------------- + +format_header(#eh_state{curr_suite = undefined, +			curr_group = undefined, +			curr_func = undefined}) -> +    io_lib:format("System report", []); + +format_header(#eh_state{curr_suite = Suite, +			curr_group = undefined, +			curr_func = undefined}) -> +    io_lib:format("System report during ~w", [Suite]); + +format_header(#eh_state{curr_suite = Suite, +			curr_group = undefined, +			curr_func = TcOrConf}) -> +    io_lib:format("System report during ~w:~w/1", +		  [Suite,TcOrConf]); + +format_header(#eh_state{curr_suite = Suite, +			curr_group = Group, +			curr_func = Conf}) when Conf == init_per_group; +						Conf == end_per_group -> +    io_lib:format("System report during ~w:~w/2 for ~w", +		  [Suite,Conf,Group]); + +format_header(#eh_state{curr_suite = Suite, +			curr_group = Group, +			parallel_tcs = true}) -> +    io_lib:format("System report during ~w in ~w", +		  [Group,Suite]); + +format_header(#eh_state{curr_suite = Suite, +			curr_group = Group, +			curr_func = TC}) -> +    io_lib:format("System report during ~w:~w/1 in ~w", +		  [Suite,TC,Group]). | 
