diff options
Diffstat (limited to 'lib/test_server/src')
| -rw-r--r-- | lib/test_server/src/test_server.erl | 290 | ||||
| -rw-r--r-- | lib/test_server/src/test_server_ctrl.erl | 85 | 
2 files changed, 232 insertions, 143 deletions
| diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 6e94e4861a..17c5f5b253 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -35,6 +35,7 @@  -export([fail/0,fail/1,format/1,format/2,format/3]).  -export([capture_start/0,capture_stop/0,capture_get/0]).  -export([messages_get/0]). +-export([permit_io/2]).  -export([hours/1,minutes/1,seconds/1,sleep/1,adjusted_sleep/1,timecall/3]).  -export([timetrap_scale_factor/0,timetrap/1,get_timetrap_info/0,  	 timetrap_cancel/1,timetrap_cancel/0]). @@ -49,7 +50,7 @@  -export([run_on_shielded_node/2]).  -export([is_cover/0,is_debug/0,is_commercial/0]). --export([break/1,continue/0]). +-export([break/1,break/2,break/3,continue/0,continue/1]).  %%% DEBUGGER INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  -export([purify_new_leaks/0, purify_format/2, purify_new_fds_inuse/0, @@ -523,7 +524,7 @@ stick_all_sticky(Node,Sticky) ->  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% run_test_case_apply(Mod,Func,Args,Name,RunInit,TimetrapData) -> +%% run_test_case_apply(Mod,Func,Args,Name,RunInit,TimetrapData,RejectIoReqs) ->  %%               {Time,Value,Loc,Opts,Comment} | {died,Reason,unknown,Comment}  %%  %% Time = float()   (seconds) @@ -558,8 +559,12 @@ stick_all_sticky(Node,Sticky) ->  %% ScaleTimetrap indicates if test_server should attemp to automatically  %% compensate timetraps for runtime delays introduced by e.g. tools like  %% cover. +%%  +%% RejectIoReqs (bool) is information about whether printouts to stdout +%% should be visible in the minor log file or not. -run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit,TimetrapData}) -> +run_test_case_apply({CaseNum,Mod,Func,Args,Name, +		     RunInit,TimetrapData,RejectIoReqs}) ->      purify_format("Test case #~w ~w:~w/1", [CaseNum, Mod, Func]),      case os:getenv("TS_RUN_VALGRIND") of  	false -> @@ -570,17 +575,19 @@ run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit,TimetrapData}) ->      end,      test_server_h:testcase({Mod,Func,1}),      ProcBef = erlang:system_info(process_count), -    Result = run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData), +    Result = run_test_case_apply(Mod, Func, Args, Name, RunInit, +				 TimetrapData, RejectIoReqs),      ProcAft = erlang:system_info(process_count),      purify_new_leaks(),      DetFail = get(test_server_detected_fail),      {Result,DetFail,ProcBef,ProcAft}. -run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> +run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData, RejectIoReqs) ->      case get(test_server_job_dir) of  	undefined ->  	    %% i'm a local target -	    do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData); +	    do_run_test_case_apply(Mod, Func, Args, Name, RunInit, +				   TimetrapData, RejectIoReqs);  	JobDir ->  	    %% i'm a remote target  	    case Args of @@ -595,13 +602,14 @@ run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) ->  		    Config2 = lists:keyreplace(priv_dir, 1, Config1,  					       {priv_dir,TargetPrivDir}),  		    do_run_test_case_apply(Mod, Func, [Config2], Name, RunInit, -					   TimetrapData); +					   TimetrapData, RejectIoReqs);  		_other ->  		    do_run_test_case_apply(Mod, Func, Args, Name, RunInit, -					   TimetrapData) +					   TimetrapData, RejectIoReqs)  	    end      end. -do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> +do_run_test_case_apply(Mod, Func, Args, Name, RunInit, +		       TimetrapData, RejectIoReqs) ->      {ok,Cwd} = file:get_cwd(),      Args2Print = case Args of  		     [Args1] when is_list(Args1) -> @@ -628,7 +636,8 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) ->  	  end),      group_leader(OldGLeader, self()),      put(test_server_detected_fail, []), -    run_test_case_msgloop(Ref, Pid, false, false, "", undefined, starting). +    run_test_case_msgloop(Ref, Pid, false, RejectIoReqs, false, "", +			  undefined, starting).  %% Ugly bug (pre R5A):  %% If this process (group leader of the test case) terminates before @@ -639,7 +648,7 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) ->  %% A test case is known to have failed if it returns {'EXIT', _} tuple,  %% or sends a message {failed, File, Line} to it's group_leader  %% -run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, +run_test_case_msgloop(Ref, Pid, CaptureStdout, RejectIoReqs, Terminate,  		      Comment, CurrConf, Status) ->      %% NOTE: Keep job_proxy_msgloop/0 up to date when changes      %%       are made in this function! @@ -655,7 +664,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  	end,      receive  	{test_case_initialized,Pid} -> -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,running);  	Abort = {abort_current_testcase,_,_} when Status == starting ->  	    %% we're in init phase, must must postpone this operation @@ -663,7 +672,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  	    %% gets killed)  	    self() ! Abort,  	    erlang:yield(), -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);  	{abort_current_testcase,Reason,From} ->  	    Line = case is_process_alive(Pid) of @@ -694,82 +703,92 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  				    Error1  			    end  		    end, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  NewComment,CurrConf,Status); +	{permit_io,FromPid} -> +	    put({permit_io,FromPid},true), +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate, +				  Comment,CurrConf,Status);          {io_request,From,ReplyAs,{put_chars,io_lib,Func,[Format,Args]}}  	when is_list(Format) ->  	    Msg = (catch io_lib:Func(Format,Args)), -	    run_test_case_msgloop_io(ReplyAs,CaptureStdout,Msg,From,Func), -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs, +				     Msg,From,Func), +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);          {io_request,From,ReplyAs,{put_chars,io_lib,Func,[Format,Args]}}  	when is_atom(Format) ->  	    Msg = (catch io_lib:Func(Format,Args)), -	    run_test_case_msgloop_io(ReplyAs,CaptureStdout,Msg,From,Func), -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs, +				     Msg,From,Func), +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);          {io_request,From,ReplyAs,{put_chars,Bytes}} -> -	    run_test_case_msgloop_io( -	      ReplyAs,CaptureStdout,Bytes,From,put_chars), -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs, +				     Bytes,From,put_chars), +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);          {io_request,From,ReplyAs,{put_chars,unicode,io_lib,Func,[Format,Args]}}  	when is_list(Format) ->  	    Msg = unicode_to_latin1(catch io_lib:Func(Format,Args)), -	    run_test_case_msgloop_io(ReplyAs,CaptureStdout,Msg,From,Func), -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs, +				     Msg,From,Func), +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);          {io_request,From,ReplyAs,{put_chars,latin1,io_lib,Func,[Format,Args]}}  	when is_list(Format) ->  	    Msg = (catch io_lib:Func(Format,Args)), -	    run_test_case_msgloop_io(ReplyAs,CaptureStdout,Msg,From,Func), -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs, +				     Msg,From,Func), +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);          {io_request,From,ReplyAs,{put_chars,unicode,io_lib,Func,[Format,Args]}}  	when is_atom(Format) ->  	    Msg = unicode_to_latin1(catch io_lib:Func(Format,Args)), -	    run_test_case_msgloop_io(ReplyAs,CaptureStdout,Msg,From,Func), -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs, +				     Msg,From,Func), +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);          {io_request,From,ReplyAs,{put_chars,latin1,io_lib,Func,[Format,Args]}}  	when is_atom(Format) ->  	    Msg = (catch io_lib:Func(Format,Args)), -	    run_test_case_msgloop_io(ReplyAs,CaptureStdout,Msg,From,Func), -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs, +				     Msg,From,Func), +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);          {io_request,From,ReplyAs,{put_chars,unicode,Bytes}} -> -	    run_test_case_msgloop_io( -	      ReplyAs,CaptureStdout,unicode_to_latin1(Bytes),From,put_chars), -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs, +				     unicode_to_latin1(Bytes),From,put_chars), +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);          {io_request,From,ReplyAs,{put_chars,latin1,Bytes}} -> -	    run_test_case_msgloop_io( -	      ReplyAs,CaptureStdout,Bytes,From,put_chars), -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs, +				     Bytes,From,put_chars), +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);          IoReq when element(1, IoReq) == io_request ->  	    %% something else, just pass it on              group_leader() ! IoReq, -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);  	{structured_io,ClientPid,Msg} ->  	    output(Msg, ClientPid), -            run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +            run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);  	{capture,NewCapture} -> -            run_test_case_msgloop(Ref,Pid,NewCapture,Terminate, +            run_test_case_msgloop(Ref,Pid,NewCapture,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);  	{sync_apply,From,MFA} ->  	    sync_local_or_remote_apply(false,From,MFA), -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);  	{sync_apply_proxy,Proxy,From,MFA} ->  	    sync_local_or_remote_apply(Proxy,From,MFA), -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);  	{printout,Detail,Format,Args} ->  	    print(Detail,Format,Args), -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);  	{comment,NewComment} ->  	    NewComment1 = test_server_ctrl:to_string(NewComment), @@ -783,18 +802,20 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  		    Other ->  			Other  		end, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate1, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate1,  				  NewComment2,CurrConf,Status);  	{read_comment,From} ->  	    From ! {self(),read_comment,Comment}, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);  	{set_curr_conf,From,NewCurrConf} ->  	    From ! {self(),set_curr_conf,ok}, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,NewCurrConf,Status);  	{make_priv_dir,From} when CurrConf == undefined -> -	    From ! {self(),make_priv_dir,{error,no_priv_dir_in_config}}; +	    From ! {self(),make_priv_dir,{error,no_priv_dir_in_config}}, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate, +				  Comment,CurrConf,Status);  	{make_priv_dir,From} ->  	    Result =  		case proplists:get_value(priv_dir, element(2, CurrConf)) of @@ -811,12 +832,12 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  			end  		end,  	    From ! {self(),make_priv_dir,Result}, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,  				  Comment,CurrConf,Status);  	{'EXIT',Pid,{Ref,Time,Value,Loc,Opts}} ->  	    RetVal = {Time/1000000,Value,mod_loc(Loc),Opts,Comment}, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,{true,RetVal}, -				  Comment,undefined,Status); +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  {true,RetVal},Comment,undefined,Status);  	{'EXIT',Pid,Reason} ->  	    case Reason of  		{timetrap_timeout,TVal,Loc} -> @@ -827,7 +848,8 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  			    spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,  					  {framework_error,{timetrap,TVal}},  					  unknown,self()), -			    run_test_case_msgloop(Ref,Pid,CaptureStdout, +			    run_test_case_msgloop(Ref,Pid, +						  CaptureStdout,RejectIoReqs,  						  Terminate,Comment,  						  undefined,Status);  			Loc1 -> @@ -860,7 +882,8 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  						      Loc1,self()),  					undefined  				end, -			    run_test_case_msgloop(Ref,Pid,CaptureStdout, +			    run_test_case_msgloop(Ref,Pid, +						  CaptureStdout,RejectIoReqs,  						  Terminate,Comment,  						  NewCurrConf,Status)  		    end; @@ -877,15 +900,16 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  					  {timetrap_timeout,TVal},  					  Loc1,self())  		    end, -		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -					  Comment,CurrConf,Status); +		    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +					  Terminate,Comment,CurrConf,Status);  		{testcase_aborted,ErrorMsg={user_timetrap_error,_},AbortLoc} ->  		    %% user timetrap function caused exit  		    %% during start of test case  		    {Mod,Func} = get_mf(mod_loc(AbortLoc)),  		    spawn_fw_call(Mod,Func,CurrConf,Pid,  				  ErrorMsg,unknown,self()), -		    run_test_case_msgloop(Ref,Pid,CaptureStdout, +		    run_test_case_msgloop(Ref,Pid, +					  CaptureStdout,RejectIoReqs,  					  Terminate,Comment,  					  undefined,Status);		  		{testcase_aborted,AbortReason,AbortLoc} -> @@ -896,7 +920,8 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  			    spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,  					  {framework_error,ErrorMsg},  					  unknown,self()), -			    run_test_case_msgloop(Ref,Pid,CaptureStdout, +			    run_test_case_msgloop(Ref,Pid, +						  CaptureStdout,RejectIoReqs,  						  Terminate,Comment,  						  undefined,Status);  			Loc1 -> @@ -928,7 +953,8 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  						      ErrorMsg,Loc1,self()),  					undefined  				end, -			    run_test_case_msgloop(Ref,Pid,CaptureStdout, +			    run_test_case_msgloop(Ref,Pid, +						  CaptureStdout,RejectIoReqs,  						  Terminate,Comment,  						  NewCurrConf,Status)  		    end; @@ -943,14 +969,14 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  		    spawn_fw_call(Mod,Func,CurrConf,Pid,  				  testcase_aborted_or_killed,  				  unknown,self()), -		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -					  Comment,CurrConf,Status); +		    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +					  Terminate,Comment,CurrConf,Status);  		{fw_error,{FwMod,FwFunc,FwError}} ->  		    spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,  				  {framework_error,FwError},  				  unknown,self()), -		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -					  Comment,CurrConf,Status); +		    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +					  Terminate,Comment,CurrConf,Status);  		_Other ->  		    %% the testcase has terminated because of Reason (e.g. an exit  		    %% because a linked process failed) @@ -960,8 +986,8 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  				 end,  		    spawn_fw_call(Mod,Func,CurrConf,Pid,  				  Reason,unknown,self()), -		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -					  Comment,CurrConf,Status) +		    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +					  Terminate,Comment,CurrConf,Status)  	    end;  	{EndConfPid,{call_end_conf,Data,_Result}} ->  	    case CurrConf of @@ -969,11 +995,11 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  		    {_Mod,_Func,TCPid,TCExitReason,Loc} = Data,  		    spawn_fw_call(Mod,Func,CurrConf,TCPid,  				  TCExitReason,Loc,self()), -		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -					  Comment,undefined,Status); +		    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +					  Terminate,Comment,undefined,Status);  		_ -> -		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -					  Comment,CurrConf,Status) +		    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +					  Terminate,Comment,CurrConf,Status)  	    end;  	{_FwCallPid,fw_notify_done,{T,Value,Loc,Opts,AddToComment}} ->  	    %% the framework has been notified, we're finished @@ -993,8 +1019,8 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  			    end,  			{T,Value,Loc,Opts,Comment1}  		end, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,{true,RetVal}, -				  Comment,undefined,Status); +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  {true,RetVal},Comment,undefined,Status);   	{'EXIT',_FwCallPid,{fw_notify_done,Func,Error}} ->  	    %% a framework function failed  	    CB = os:getenv("TEST_SERVER_FRAMEWORK"), @@ -1005,13 +1031,13 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  			  {list_to_atom(CB),Func}  		  end,  	    RetVal = {died,{framework_error,Loc,Error},Loc,"Framework error"}, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,{true,RetVal}, -				  Comment,undefined,Status); +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  {true,RetVal},Comment,undefined,Status);  	{failed,File,Line} ->  	    put(test_server_detected_fail,  		[{File, Line}| get(test_server_detected_fail)]), -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -				  Comment,CurrConf,Status); +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  Terminate,Comment,CurrConf,Status);  	{user_timetrap,Pid,_TrapTime,StartTime,E={user_timetrap_error,_},_} ->  	    case update_user_timetraps(Pid, StartTime) of @@ -1020,8 +1046,8 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  		ignore ->  		    ok  	    end, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -				  Comment,CurrConf,Status); +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  Terminate,Comment,CurrConf,Status);  	{user_timetrap,Pid,TrapTime,StartTime,ElapsedTime,Scale} ->  	    %% a user timetrap is triggered, ignore it if new  	    %% timetrap has been started since @@ -1036,49 +1062,57 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate,  		ignore ->  		    ok  	    end, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -				  Comment,CurrConf,Status); +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  Terminate,Comment,CurrConf,Status);  	{timetrap_cancel_one,Handle,_From} ->  	    timetrap_cancel_one(Handle, false), -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -				  Comment,CurrConf,Status); +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  Terminate,Comment,CurrConf,Status);  	{timetrap_cancel_all,TCPid,_From} ->  	    timetrap_cancel_all(TCPid, false), -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -				  Comment,CurrConf,Status); +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  Terminate,Comment,CurrConf,Status);  	{get_timetrap_info,TCPid,From} ->  	    Info = get_timetrap_info(TCPid, false),  	    From ! {self(),get_timetrap_info,Info}, -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -				  Comment,CurrConf,Status); +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  Terminate,Comment,CurrConf,Status);  	_Other when not is_tuple(_Other) ->  	    %% ignore anything not generated by test server -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -				  Comment,CurrConf,Status); +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  Terminate,Comment,CurrConf,Status);  	_Other when element(1, _Other) /= 'EXIT',  		    element(1, _Other) /= started,  		    element(1, _Other) /= finished,  		    element(1, _Other) /= print ->  	    %% ignore anything not generated by test server -	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate, -				  Comment,CurrConf,Status) +	    run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs, +				  Terminate,Comment,CurrConf,Status)      after Timeout ->  	    ReturnValue      end. -run_test_case_msgloop_io(ReplyAs,CaptureStdout,Msg,From,Func) -> +run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs, +			 Msg,From,Func) ->      case Msg of  	{'EXIT',_} ->  	    From ! {io_reply,ReplyAs,{error,Func}};  	_ ->  	    From ! {io_reply,ReplyAs,ok}      end, -    if  CaptureStdout /= false -> -	    CaptureStdout ! {captured,Msg}; -	true -> +    Proceed = if RejectIoReqs -> get({permit_io,From}); +		 true        -> true +	      end, +    if Proceed -> +	    if CaptureStdout /= false -> +		    CaptureStdout ! {captured,Msg}; +	       true -> +		    ok +	    end, +	    output({minor,Msg},From); +       true ->  	    ok -    end, -    output({minor,Msg},From). +    end.  output(Msg,Sender) ->      local_or_remote_apply({test_server_ctrl,output,[Msg,Sender]}). @@ -1097,7 +1131,8 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->  				{'EXIT',Why} ->  				    timer:sleep(1),  				    group_leader() ! {printout,12, -						      "WARNING! ~p:end_per_testcase(~p, ~p)" +						      "WARNING! " +						      "~p:end_per_testcase(~p, ~p)"  						      " crashed!\n\tReason: ~p\n",  						      [Mod,Func,Conf,Why]};  				_ -> @@ -1213,13 +1248,18 @@ spawn_fw_call(FwMod,FwFunc,_,_Pid,{framework_error,FwError},_,SendTo) ->  	end,      spawn_link(FwCall); -spawn_fw_call(Mod,Func,_,Pid,Error,Loc,SendTo) -> +spawn_fw_call(Mod,Func,CurrConf,Pid,Error,Loc,SendTo) -> +    {Mod1,Func1} = +	case {Mod,Func,CurrConf} of +	    {undefined,undefined,{{M,F},_}} -> {M,F}; +	    _ -> {Mod,Func} +	end,	          FwCall =  	fun() ->  		%% set group leader so that printouts/comments  		%% from the framework get printed in the logs  		group_leader(SendTo, self()), -		case catch fw_error_notify(Mod,Func,[], +		case catch fw_error_notify(Mod1,Func1,[],  					   Error,Loc) of  		    {'EXIT',FwErrorNotifyErr} ->  			exit({fw_notify_done,error_notification, @@ -1228,7 +1268,7 @@ spawn_fw_call(Mod,Func,_,Pid,Error,Loc,SendTo) ->  			ok  		end,  		Conf = [{tc_status,{failed,timetrap_timeout}}], -		case catch do_end_tc_call(Mod,Func, Loc, +		case catch do_end_tc_call(Mod1,Func1, Loc,  					  {Pid,Error,[Conf]},Error) of  		    {'EXIT',FwEndTCErr} ->  			exit({fw_notify_done,end_tc,FwEndTCErr}); @@ -1959,6 +1999,13 @@ messages_get() ->      test_server_sup:messages_get([]).  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% permit_io(GroupLeader, FromPid) -> ok +%% +%% Make sure proceeding IO from FromPid won't get rejected +permit_io(GroupLeader, FromPid) -> +    GroupLeader ! {permit_io,FromPid}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% sleep(Time) -> ok  %% Time = integer() | float() | infinity  %% @@ -2061,31 +2108,40 @@ fail() ->  %% Break a test case so part of the test can be done manually.  %% Use continue/0 to continue.  break(Comment) -> -    case erase(test_server_timetraps) of -	undefined -> ok; -	List -> lists:foreach(fun({Ref,_,_}) ->  -				      timetrap_cancel(Ref) -			      end, List) -    end, +    break(?MODULE, Comment). + +break(CBM, Comment) -> +    break(CBM, '', Comment). + +break(CBM, TestCase, Comment) -> +    timetrap_cancel(), +    {TCName,CntArg,PName} = +	if TestCase == '' ->  +		{"", "", test_server_break_process}; +	   true -> +		Str = atom_to_list(TestCase), +		{[32 | Str], Str, +		 list_to_atom("test_server_break_process_" ++ Str)} +	end,      io:format(user,  	      "\n\n\n--- SEMIAUTOMATIC TESTING ---" -	      "\nThe test case executes on process ~w" +	      "\nThe test case~s executes on process ~w"  	      "\n\n\n~s"  	      "\n\n\n-----------------------------\n\n" -	      "Continue with --> test_server:continue().\n", -	      [self(),Comment]), -    case whereis(test_server_break_process) of +	      "Continue with --> ~w:continue(~s).\n", +	      [TCName,self(),Comment,CBM,CntArg]), +    case whereis(PName) of  	undefined -> -	    spawn_break_process(self()); +	    spawn_break_process(self(), PName);  	OldBreakProcess ->  	    OldBreakProcess ! cancel, -	    spawn_break_process(self()) +	    spawn_break_process(self(), PName)      end,      receive continue -> ok end. -spawn_break_process(Pid) -> +spawn_break_process(Pid, PName) ->      spawn(fun() -> -		  register(test_server_break_process,self()), +		  register(PName, self()),  		  receive  		      continue -> continue(Pid);  		      cancel -> ok @@ -2094,13 +2150,19 @@ spawn_break_process(Pid) ->  continue() ->      case whereis(test_server_break_process) of -	undefined -> -	     ok; -	BreakProcess -> -	    BreakProcess ! continue +	undefined    -> ok; +	BreakProcess -> BreakProcess ! continue      end. -continue(Pid) -> +continue(TestCase) when is_atom(TestCase) -> +    PName = list_to_atom("test_server_break_process_" ++ +			 atom_to_list(TestCase)), +    case whereis(PName) of +	undefined    -> ok; +	BreakProcess -> BreakProcess ! continue +    end;	 + +continue(Pid) when is_pid(Pid) ->      Pid ! continue.  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index 5ed296d215..df2187bc04 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -162,7 +162,7 @@  -export([jobs/0, run_test/1, wait_finish/0, idle_notify/1,  	 abort_current_testcase/1, abort/0]).  -export([start_get_totals/1, stop_get_totals/0]). --export([get_levels/0, set_levels/3]). +-export([reject_io_reqs/1, get_levels/0, set_levels/3]).  -export([multiply_timetraps/1, scale_timetraps/1, get_timetrap_parameters/0]).  -export([create_priv_dir/1]).  -export([cover/2, cover/3, cover/7, @@ -218,8 +218,9 @@  -define(auto_skip_color, "#FFA64D").  -define(user_skip_color, "#FF8000"). +-define(sortable_table_name, "SortableTable"). --record(state,{jobs=[],levels={1,19,10}, +-record(state,{jobs=[], levels={1,19,10}, reject_io_reqs=false,  	       multiply_timetraps=1, scale_timetraps=true,  	       create_priv_dir=auto_per_run, finish=false,  	       target_info, trc=false, cover=false, wait_for_node=[], @@ -498,6 +499,9 @@ get_levels() ->  set_levels(Show, Major, Minor) ->      controller_call({set_levels,Show,Major,Minor}). +reject_io_reqs(Bool) -> +    controller_call({reject_io_reqs,Bool}). +  multiply_timetraps(N) ->      controller_call({multiply_timetraps,N}). @@ -815,6 +819,7 @@ handle_call({add_job,Dir,Name,TopCase,Skip}, _From, State) ->  			    [SpecName,{State#state.multiply_timetraps,  				       State#state.scale_timetraps}],  			    LogDir, Name, State#state.levels, +			    State#state.reject_io_reqs,  			    State#state.create_priv_dir,  			    State#state.testcase_callback, ExtraTools1),  		    NewJobs = [{Name,Pid}|State#state.jobs], @@ -825,6 +830,7 @@ handle_call({add_job,Dir,Name,TopCase,Skip}, _From, State) ->  			    [SpecList,{State#state.multiply_timetraps,  				       State#state.scale_timetraps}],  			    LogDir, Name, State#state.levels, +			    State#state.reject_io_reqs,  			    State#state.create_priv_dir,  			    State#state.testcase_callback, ExtraTools1),  		    NewJobs = [{Name,Pid}|State#state.jobs], @@ -843,6 +849,7 @@ handle_call({add_job,Dir,Name,TopCase,Skip}, _From, State) ->  				     {State#state.multiply_timetraps,  				      State#state.scale_timetraps}],  				    LogDir, Name, State#state.levels, +				    State#state.reject_io_reqs,  				    State#state.create_priv_dir,  				    State#state.testcase_callback, ExtraTools1),  			    NewJobs = [{Name,Pid}|State#state.jobs], @@ -975,6 +982,15 @@ handle_call({set_levels,Show,Major,Minor}, _From, State) ->      {reply,ok,State#state{levels={Show,Major,Minor}}};  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% handle_call({reject_io_reqs,Bool}, _, State) -> ok +%% Bool = bool() +%% +%% May be used to switch off stdout printouts to the minor log file + +handle_call({reject_io_reqs,Bool}, _From, State) -> +    {reply,ok,State#state{reject_io_reqs=Bool}}; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% handle_call({multiply_timetraps,N}, _, State) -> ok  %% N = integer() | infinity  %% @@ -1340,14 +1356,15 @@ kill_all_jobs([]) ->  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% spawn_tester(Mod, Func, Args, Dir, Name, Levels, CreatePrivDir, -%%              TestCaseCallback, ExtraTools) -> Pid +%% spawn_tester(Mod, Func, Args, Dir, Name, Levels, RejectIoReqs, +%%              CreatePrivDir, TestCaseCallback, ExtraTools) -> Pid  %% Mod = atom()  %% Func = atom()  %% Args = [term(),...]  %% Dir = string()  %% Name = string()  %% Levels = {integer(),integer(),integer()} +%% RejectIoReqs = bool()  %% CreatePrivDir = auto_per_run | manual_per_tc | auto_per_tc  %% TestCaseCallback = {CBMod,CBFunc} | undefined  %% ExtraTools = [ExtraTool,...] @@ -1359,14 +1376,14 @@ kill_all_jobs([]) ->  %% When the named function is done executing, a summary of the results  %% is printed to the log files. -spawn_tester(Mod, Func, Args, Dir, Name, Levels,  +spawn_tester(Mod, Func, Args, Dir, Name, Levels, RejectIoReqs,  	     CreatePrivDir, TCCallback, ExtraTools) ->      spawn_link( -      fun() -> init_tester(Mod, Func, Args, Dir, Name, Levels, +      fun() -> init_tester(Mod, Func, Args, Dir, Name, Levels, RejectIoReqs,  			   CreatePrivDir, TCCallback, ExtraTools)        end). -init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev}, +init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev}, RejectIoReqs,  	    CreatePrivDir, TCCallback, ExtraTools) ->      process_flag(trap_exit, true),      put(test_server_name, Name), @@ -1378,6 +1395,7 @@ init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev},      put(test_server_summary_level, SumLev),      put(test_server_major_level, MajLev),      put(test_server_minor_level, MinLev), +    put(test_server_reject_io_reqs, RejectIoReqs),      put(test_server_create_priv_dir, CreatePrivDir),      put(test_server_random_seed, proplists:get_value(random_seed, ExtraTools)),      put(test_server_testcase_callback, TCCallback), @@ -1424,8 +1442,10 @@ init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev},  	end,      OkN = get(test_server_ok),      FailedN = get(test_server_failed), -    print(html,"<tr><td></td><td><b>TOTAL</b></td><td></td><td></td><td></td>" -	  "<td>~.3fs</td><td><b>~s</b></td><td>~p Ok, ~p Failed~s of ~p</td></tr>\n", +    print(html,"\n</tbody>\n<tfoot>\n" +	  "<tr><td></td><td><b>TOTAL</b></td><td></td><td></td><td></td>" +	  "<td>~.3fs</td><td><b>~s</b></td><td>~p Ok, ~p Failed~s of ~p</td></tr>\n" +	  "</tfoot>\n",  	  [Time,SuccessStr,OkN,FailedN,SkipStr,OkN+FailedN+SkippedN]).  %% timer:tc/3 @@ -1486,7 +1506,7 @@ stop_extra_tools([], _) ->  %% Reads the named test suite specification file, and executes it.  %%  %% This function is meant to be called by a process created by -%% spawn_tester/7, which sets up some necessary dictionary values. +%% spawn_tester/10, which sets up some necessary dictionary values.  do_spec(SpecName, TimetrapSpec) when is_list(SpecName) ->      case file:consult(SpecName) of @@ -1535,7 +1555,7 @@ do_spec(SpecName, TimetrapSpec) when is_list(SpecName) ->  %% should not be used. Use a configuration test case instead.  %%  %% This function is meant to be called by a process created by -%% spawn_tester/7, which sets up some necessary dictionary values. +%% spawn_tester/10, which sets up some necessary dictionary values.  do_spec_list(TermList0, TimetrapSpec) ->      Nodes = [], @@ -1702,7 +1722,7 @@ add_mod(Mod, Mods) ->  %% configuration information into the log files.  %%  %% This function is meant to be called by a process created by -%% spawn_tester/7, which sets up some necessary dictionary values. +%% spawn_tester/10, which sets up some necessary dictionary values.  do_test_cases(TopCases, SkipCases,  	      Config, MultiplyTimetrap) when is_integer(MultiplyTimetrap);  					     MultiplyTimetrap == infinity -> @@ -1741,7 +1761,8 @@ do_test_cases(TopCases, SkipCases,  	    test_server_sup:framework_call(report, [tests_start,{Test,N}]),  	    {Header,Footer} =  		case test_server_sup:framework_call(get_html_wrapper,  -						    [TestDescr,true,TestDir], "") of +						    [TestDescr,true,TestDir, +						    {[],[2,3,4,7,8],[1,6]}], "") of  		    Empty when (Empty == "") ; (element(2,Empty) == "")  ->  			put(basic_html, true),  			{["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n", @@ -1803,14 +1824,15 @@ do_test_cases(TopCases, SkipCases,  		  [?suitelog_name,?coverlog_name]),  	    print(html,  		  "<p>~s</p>\n" ++ -		   xhtml("<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">", -			 "<table>") ++ -		   "<tr><th>Num</th><th>Module</th><th>Group</th>" ++ -		   "<th>Case</th><th>Log</th><th>Time</th><th>Result</th>" ++ -		   "<th>Comment</th></tr>\n", -		  [print_if_known(N, {"<i>Executing <b>~p</b> test cases...</i>\n",[N]}, +		  xhtml("<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">", +			["<table id=\"",?sortable_table_name,"\">\n", +			 "<thead>\n"]) ++ +		      "<tr><th>Num</th><th>Module</th><th>Group</th>" ++ +		      "<th>Case</th><th>Log</th><th>Time</th><th>Result</th>" ++ +		      "<th>Comment</th></tr>\n</thead>\n<tbody>\n", +		  [print_if_known(N, {"<i>Executing <b>~p</b> test cases...</i>" ++ +				      xhtml("\n<br>\n", "\n<br />\n"),[N]},  				  {"",[]})]), -	    print(html, xhtml("<br>", "<br />")),  	    print(major, "=cases         ~p", [get(test_server_cases)]),  	    print(major, "=user          ~s", [TI#target_info.username]), @@ -1964,7 +1986,8 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName) ->      {Header,Footer} =  	case test_server_sup:framework_call(get_html_wrapper,   					    [TestDescr,false, -					     filename:dirname(AbsName)], "") of +					     filename:dirname(AbsName), +					     undefined], "") of  	    Empty when (Empty == "") ; (element(2,Empty) == "")  ->  		put(basic_html, true),  		{["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n", @@ -2094,7 +2117,7 @@ html_possibly_convert(Src, SrcInfo, Dest) ->  	    Header =  		case test_server_sup:framework_call(get_html_wrapper,   						    ["Module "++Src,false, -						     OutDir], "") of +						     OutDir,undefined], "") of  		    Empty when (Empty == "") ; (element(2,Empty) == "")  ->  			["<!DOCTYPE HTML PUBLIC",  			 "\"-//W3C//DTD HTML 3.2 Final//EN\">\n", @@ -3809,10 +3832,12 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,  	   MinorBase,MinorBase]),      do_if_parallel(Main, ok, fun erlang:yield/0), + +    RejectIoReqs = get(test_server_reject_io_reqs),      %% run the test case      {Result,DetectedFail,ProcsBefore,ProcsAfter} =  	run_test_case_apply(Num, Mod, Func, [UpdatedArgs], get_name(Mode), -			    RunInit, Where, TimetrapData), +			    RunInit, Where, TimetrapData, RejectIoReqs),      {Time,RetVal,Loc,Opts,Comment} =  	case Result of  	    Normal={_Time,_RetVal,_Loc,_Opts,_Comment} -> Normal; @@ -4431,7 +4456,7 @@ do_format_exception(Reason={Error,Stack}) ->  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, -%%                     Where, TimetrapData) -> +%%                     Where, TimetrapData, RejectIoReqs) ->  %%  {{Time,RetVal,Loc,Opts,Comment},DetectedFail,ProcessesBefore,ProcessesAfter} |  %%  {{died,Reason,unknown,Comment},DetectedFail,ProcessesBefore,ProcessesAfter}  %% Name = atom() @@ -4450,19 +4475,21 @@ do_format_exception(Reason={Error,Stack}) ->  %% sent over socket to target, and test_server runs the case and sends the  %% result back over the socket. Else test_server runs the case directly on host. -run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, host, TimetrapData) -> +run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, host, +		    TimetrapData, RejectIoReqs) ->      test_server:run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit, -				     TimetrapData}); -run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, target, TimetrapData) -> +				     TimetrapData,RejectIoReqs}); +run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, target, +		    TimetrapData, RejectIoReqs) ->      case get(test_server_ctrl_job_sock) of  	undefined ->  	    %% local target  	    test_server:run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit, -					     TimetrapData}); +					     TimetrapData,RejectIoReqs});  	JobSock ->  	    %% remote target  	    request(JobSock, {test_case,{CaseNum,Mod,Func,Args,Name,RunInit, -					 TimetrapData}}), +					 TimetrapData,RejectIoReqs}}),  	    read_job_sock_loop(JobSock)      end. | 
