aboutsummaryrefslogtreecommitdiffstats
path: root/lib/test_server
diff options
context:
space:
mode:
authorPeter Andersson <[email protected]>2011-09-30 11:24:26 +0200
committerPeter Andersson <[email protected]>2011-09-30 11:26:11 +0200
commit1f17c7bea8fe17cc450b6e9c72234e249d4931b4 (patch)
treed83ea1f0215112404e3a494518a8db7daa34d6f4 /lib/test_server
parentae69c5d45911607b1a162a141d193a04ee6dc213 (diff)
parent345992c1e82eb2e876139248cc50eb4df029a5f5 (diff)
downloadotp-1f17c7bea8fe17cc450b6e9c72234e249d4931b4.tar.gz
otp-1f17c7bea8fe17cc450b6e9c72234e249d4931b4.tar.bz2
otp-1f17c7bea8fe17cc450b6e9c72234e249d4931b4.zip
Merge remote branch 'origin/peppe/common_test/r14b04_tickets.fix' into dev
* origin/peppe/common_test/r14b04_tickets.fix: (35 commits) Create temporary fix for problem with parallel test cases Correct "Missing Suites" link Add documentation on timetraps and start flags Add missing tests for timetrap handling and fix remaining errors Solve problem with ct_init/end_per_group being counted as test cases Fix errors in test suites Fix invalid call to undefined function Fix problem with test_server_ctrl creating invalid conf test Improve info in CT framework log Update vsn.mk for common_test and test_server Enhance logging performance Change order of include files Add link to last executed test suite on index page Fix problem with location value when init config func calls help func Fix crash when CTHook init fails Correct error in test suite Fix error with incorrect notification after end_per_testcase craches Fix problem with error message not being printed correctly Add cases to check test case status versus end_per_testcase failure Fix incorrect call to end_tc when tc_status=ok and end_per_testcase times out ... OTP-9600 OTP-9593 OTP-9592 OTP-9585 OTP-9584 OTP-9575 OTP-9520 OTP-9518 OTP-9501 OTP-9429 OTP-9398 OTP-9397 OTP-9396 OTP-9379 OTP-9372 OTP-9371 OTP-9370 OTP-9369 OTP-9311 OTP-9237 OTP-9155 OTP-8933
Diffstat (limited to 'lib/test_server')
-rw-r--r--lib/test_server/src/test_server.erl348
-rw-r--r--lib/test_server/src/test_server_ctrl.erl135
-rw-r--r--lib/test_server/src/test_server_sup.erl12
-rw-r--r--lib/test_server/src/ts_erl_config.erl5
-rw-r--r--lib/test_server/test/test_server_SUITE.erl6
-rw-r--r--lib/test_server/vsn.mk2
6 files changed, 355 insertions, 153 deletions
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index 591329b361..244207e140 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -612,6 +612,7 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) ->
print(minor, "Current directory is ~p\n", [Cwd]),
print_timestamp(minor,"Started at "),
TCCallback = get(test_server_testcase_callback),
+ LogOpts = get(test_server_logopts),
Ref = make_ref(),
OldGLeader = group_leader(),
%% Set ourself to group leader for the spawned process
@@ -621,7 +622,7 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) ->
fun() ->
run_test_case_eval(Mod, Func, Args, Name, Ref,
RunInit, TimetrapData,
- TCCallback)
+ LogOpts, TCCallback)
end),
group_leader(OldGLeader, self()),
put(test_server_detected_fail, []),
@@ -733,15 +734,23 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
print(Detail,Format,Args),
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
{comment,NewComment} ->
+ NewComment1 = test_server_ctrl:to_string(NewComment),
+ NewComment2 = test_server_sup:framework_call(format_comment,
+ [NewComment1],
+ NewComment1),
Terminate1 =
case Terminate of
{true,{Time,Value,Loc,Opts,_OldComment}} ->
- {true,{Time,Value,mod_loc(Loc),Opts,NewComment}};
+ {true,{Time,Value,mod_loc(Loc),Opts,NewComment2}};
Other ->
Other
end,
- run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate1,NewComment,CurrConf);
- {set_curr_conf,NewCurrConf} ->
+ run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate1,NewComment2,CurrConf);
+ {read_comment,From} ->
+ From ! {self(),read_comment,Comment},
+ run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
+ {set_curr_conf,From,NewCurrConf} ->
+ From ! {self(),set_curr_conf,ok},
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,NewCurrConf);
{'EXIT',Pid,{Ref,Time,Value,Loc,Opts}} ->
RetVal = {Time/1000000,Value,mod_loc(Loc),Opts,Comment},
@@ -753,7 +762,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
case mod_loc(Loc) of
{FwMod,FwFunc,framework} ->
%% timout during framework call
- spawn_fw_call(FwMod,FwFunc,Pid,
+ spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,
{framework_error,{timetrap,TVal}},
unknown,self(),Comment),
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,
@@ -779,7 +788,8 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
%% group leader process or io will cause deadlock,
%% so we spawn a dedicated process for the operation
%% and let the group leader go back to handle io.
- spawn_fw_call(Mod,Func,Pid,{timetrap_timeout,TVal},
+ spawn_fw_call(Mod,Func,CurrConf,Pid,
+ {timetrap_timeout,TVal},
Loc1,self(),Comment),
undefined
end,
@@ -790,12 +800,13 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
case mod_loc(Loc) of
{FwMod,FwFunc,framework} ->
%% timout during framework call
- spawn_fw_call(FwMod,FwFunc,Pid,
+ spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,
{framework_error,{timetrap,TVal}},
unknown,self(),Comment);
Loc1 ->
{Mod,_Func} = get_mf(Loc1),
- spawn_fw_call(Mod,InitOrEnd,Pid,{timetrap_timeout,TVal},
+ spawn_fw_call(Mod,InitOrEnd,CurrConf,Pid,
+ {timetrap_timeout,TVal},
Loc1,self(),Comment)
end,
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
@@ -804,7 +815,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
case mod_loc(AbortLoc) of
{FwMod,FwFunc,framework} ->
%% abort during framework call
- spawn_fw_call(FwMod,FwFunc,Pid,
+ spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,
{framework_error,ErrorMsg},
unknown,self(),Comment),
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,
@@ -828,7 +839,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
TVal),
{EndConfPid,{Mod,Func},Conf};
_ ->
- spawn_fw_call(Mod,Func,Pid,ErrorMsg,
+ spawn_fw_call(Mod,Func,CurrConf,Pid,ErrorMsg,
Loc1,self(),Comment),
undefined
end,
@@ -839,17 +850,18 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
%% result of an exit(TestCase,kill) call, which is the
%% only way to abort a testcase process that traps exits
%% (see abort_current_testcase)
- spawn_fw_call(undefined,undefined,Pid,testcase_aborted_or_killed,
+ spawn_fw_call(undefined,undefined,CurrConf,Pid,
+ testcase_aborted_or_killed,
unknown,self(),Comment),
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
{fw_error,{FwMod,FwFunc,FwError}} ->
- spawn_fw_call(FwMod,FwFunc,Pid,{framework_error,FwError},
+ spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,{framework_error,FwError},
unknown,self(),Comment),
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
_Other ->
%% the testcase has terminated because of Reason (e.g. an exit
%% because a linked process failed)
- spawn_fw_call(undefined,undefined,Pid,Reason,
+ spawn_fw_call(undefined,undefined,CurrConf,Pid,Reason,
unknown,self(),Comment),
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf)
end;
@@ -857,7 +869,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
case CurrConf of
{EndConfPid,{Mod,Func},_Conf} ->
{_Mod,_Func,TCPid,TCExitReason,Loc} = Data,
- spawn_fw_call(Mod,Func,TCPid,TCExitReason,Loc,self(),Comment),
+ spawn_fw_call(Mod,Func,CurrConf,TCPid,TCExitReason,Loc,self(),Comment),
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,undefined);
_ ->
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf)
@@ -928,7 +940,7 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
ok
end,
Supervisor ! {self(),end_conf}
- end,
+ end,
Pid = spawn_link(EndConfApply),
receive
{Pid,end_conf} ->
@@ -941,50 +953,72 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
end,
spawn_link(EndConfProc).
-spawn_fw_call(Mod,{init_per_testcase,Func},Pid,{timetrap_timeout,TVal}=Why,
+spawn_fw_call(Mod,{init_per_testcase,Func},_,Pid,{timetrap_timeout,TVal}=Why,
Loc,SendTo,Comment) ->
FwCall =
fun() ->
- Skip = {skip,{failed,{Mod,init_per_testcase,Why}}},
- %% if init_per_testcase fails, the test case
- %% should be skipped
- case catch do_end_tc_call(Mod,Func,{Pid,Skip,[[]]},Why) of
- {'EXIT',FwEndTCErr} ->
- exit({fw_notify_done,end_tc,FwEndTCErr});
- _ ->
- ok
- end,
- %% finished, report back
- SendTo ! {self(),fw_notify_done,
- {TVal/1000,Skip,Loc,[],Comment}}
+ Skip = {skip,{failed,{Mod,init_per_testcase,Why}}},
+ %% if init_per_testcase fails, the test case
+ %% should be skipped
+ case catch do_end_tc_call(Mod,Func, Loc, {Pid,Skip,[[]]}, Why) of
+ {'EXIT',FwEndTCErr} ->
+ exit({fw_notify_done,end_tc,FwEndTCErr});
+ _ ->
+ ok
+ end,
+ %% finished, report back
+ SendTo ! {self(),fw_notify_done,
+ {TVal/1000,Skip,Loc,[],Comment}}
end,
spawn_link(FwCall);
-spawn_fw_call(Mod,{end_per_testcase,Func},Pid,{timetrap_timeout,TVal}=Why,
- Loc,SendTo,_Comment) ->
+spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid,
+ {timetrap_timeout,TVal}=Why,_Loc,SendTo,Comment) ->
+ %%! This is a temporary fix that keeps Test Server alive during
+ %%! execution of a parallel test case group, when sometimes
+ %%! this clause gets called with EndConf == undefined. See OTP-9594
+ %%! for more info.
+ EndConf1 = if EndConf == undefined ->
+ [{tc_status,{failed,{Mod,end_per_testcase,Why}}}];
+ true ->
+ EndConf
+ end,
FwCall =
fun() ->
- Conf = [{tc_status,ok}],
- %% if end_per_testcase fails, the test case should be
- %% reported successful with a warning printed as comment
- case catch do_end_tc_call(Mod,Func,{Pid,
- {failed,{Mod,end_per_testcase,Why}},
- [Conf]}, Why) of
- {'EXIT',FwEndTCErr} ->
- exit({fw_notify_done,end_tc,FwEndTCErr});
- _ ->
- ok
- end,
- %% finished, report back
- SendTo ! {self(),fw_notify_done,
- {TVal/1000,{error,{Mod,end_per_testcase,Why}},Loc,[],
- ["<font color=\"red\">"
- "WARNING: end_per_testcase timed out!"
- "</font>"]}}
+ {RetVal,Report} =
+ case proplists:get_value(tc_status, EndConf1) of
+ undefined ->
+ E = {failed,{Mod,end_per_testcase,Why}},
+ {E,E};
+ E = {failed,Reason} ->
+ {E,{error,Reason}};
+ Result ->
+ E = {failed,{Mod,end_per_testcase,Why}},
+ {Result,E}
+ end,
+ FailLoc = proplists:get_value(tc_fail_loc, EndConf1),
+ case catch do_end_tc_call(Mod,Func, FailLoc,
+ {Pid,Report,[EndConf1]}, Why) of
+ {'EXIT',FwEndTCErr} ->
+ exit({fw_notify_done,end_tc,FwEndTCErr});
+ _ ->
+ ok
+ end,
+ %% if end_per_testcase fails a warning should be
+ %% printed as comment
+ Comment1 = if Comment == "" -> "";
+ true -> Comment ++ "<br>"
+ end,
+ %% finished, report back
+ SendTo ! {self(),fw_notify_done,
+ {TVal/1000,RetVal,FailLoc,[],
+ [Comment1,"<font color=\"red\">"
+ "WARNING: end_per_testcase timed out!"
+ "</font>"]}}
end,
spawn_link(FwCall);
-spawn_fw_call(FwMod,FwFunc,_Pid,{framework_error,FwError},_,SendTo,_Comment) ->
+spawn_fw_call(FwMod,FwFunc,_,_Pid,{framework_error,FwError},_,SendTo,_Comment) ->
FwCall =
fun() ->
test_server_sup:framework_call(report, [framework_error,
@@ -999,7 +1033,7 @@ spawn_fw_call(FwMod,FwFunc,_Pid,{framework_error,FwError},_,SendTo,_Comment) ->
end,
spawn_link(FwCall);
-spawn_fw_call(Mod,Func,Pid,Error,Loc,SendTo,Comment) ->
+spawn_fw_call(Mod,Func,_,Pid,Error,Loc,SendTo,Comment) ->
FwCall =
fun() ->
case catch fw_error_notify(Mod,Func,[],
@@ -1011,7 +1045,8 @@ spawn_fw_call(Mod,Func,Pid,Error,Loc,SendTo,Comment) ->
ok
end,
Conf = [{tc_status,{failed,timetrap_timeout}}],
- case catch do_end_tc_call(Mod,Func,{Pid,Error,[Conf]},Error) of
+ case catch do_end_tc_call(Mod,Func, Loc,
+ {Pid,Error,[Conf]},Error) of
{'EXIT',FwEndTCErr} ->
exit({fw_notify_done,end_tc,FwEndTCErr});
_ ->
@@ -1072,8 +1107,9 @@ job_proxy_msgloop() ->
%% or sends a message {failed, File, Line} to it's group_leader
run_test_case_eval(Mod, Func, Args0, Name, Ref, RunInit,
- TimetrapData, TCCallback) ->
- put(test_server_multiply_timetraps,TimetrapData),
+ TimetrapData, LogOpts, TCCallback) ->
+ put(test_server_multiply_timetraps, TimetrapData),
+ put(test_server_logopts, LogOpts),
{{Time,Value},Loc,Opts} =
case test_server_sup:framework_call(init_tc,[?pl2a(Mod),Func,Args0],
@@ -1081,22 +1117,26 @@ run_test_case_eval(Mod, Func, Args0, Name, Ref, RunInit,
{ok,Args} ->
run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback);
Error = {error,_Reason} ->
- NewResult = do_end_tc_call(Mod,Func,{Error,Args0},
+ Where = {Mod,Func},
+ NewResult = do_end_tc_call(Mod,Func, Where, {Error,Args0},
{skip,{failed,Error}}),
- {{0,NewResult},{Mod,Func},[]};
+ {{0,NewResult},Where,[]};
{fail,Reason} ->
Conf = [{tc_status,{failed,Reason}} | hd(Args0)],
+ Where = {Mod,Func},
fw_error_notify(Mod, Func, Conf, Reason),
- NewResult = do_end_tc_call(Mod,Func, {{error,Reason},[Conf]},
+ NewResult = do_end_tc_call(Mod,Func, Where, {{error,Reason},[Conf]},
{fail,Reason}),
- {{0,NewResult},{Mod,Func},[]};
+ {{0,NewResult},Where,[]};
Skip = {skip,_Reason} ->
- NewResult = do_end_tc_call(Mod,Func,{Skip,Args0},Skip),
- {{0,NewResult},{Mod,Func},[]};
+ Where = {Mod,Func},
+ NewResult = do_end_tc_call(Mod,Func, Where, {Skip,Args0}, Skip),
+ {{0,NewResult},Where,[]};
{auto_skip,Reason} ->
- NewResult = do_end_tc_call(Mod, Func, {{skip,Reason},Args0},
+ Where = {Mod,Func},
+ NewResult = do_end_tc_call(Mod,Func, Where, {{skip,Reason},Args0},
{skip,{fw_auto_skip,Reason}}),
- {{0,NewResult},{Mod,Func},[]}
+ {{0,NewResult},Where,[]}
end,
exit({Ref,Time,Value,Loc,Opts}).
@@ -1110,18 +1150,19 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) ->
Skip = {skip,Reason} ->
Line = get_loc(),
Conf = [{tc_status,{skipped,Reason}}],
- NewRes = do_end_tc_call(Mod,Func,{Skip,[Conf]}, Skip),
+ NewRes = do_end_tc_call(Mod,Func, Line, {Skip,[Conf]}, Skip),
{{0,NewRes},Line,[]};
{skip_and_save,Reason,SaveCfg} ->
Line = get_loc(),
Conf = [{tc_status,{skipped,Reason}},{save_config,SaveCfg}],
- NewRes = do_end_tc_call(Mod, Func, {{skip,Reason},[Conf]},
- {skip, Reason}),
+ NewRes = do_end_tc_call(Mod,Func, Line, {{skip,Reason},[Conf]},
+ {skip,Reason}),
{{0,NewRes},Line,[]};
FailTC = {fail,Reason} -> % user fails the testcase
EndConf = [{tc_status,{failed,Reason}} | hd(Args)],
fw_error_notify(Mod, Func, EndConf, Reason),
- NewRes = do_end_tc_call(Mod, Func, {{error,Reason},[EndConf]},
+ NewRes = do_end_tc_call(Mod,Func, {Mod,Func},
+ {{error,Reason},[EndConf]},
FailTC),
{{0,NewRes},{Mod,Func},[]};
{ok,NewConf} ->
@@ -1129,47 +1170,61 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) ->
%% call user callback function if defined
NewConf1 = user_callback(TCCallback, Mod, Func, init, NewConf),
%% save current state in controller loop
- group_leader() ! {set_curr_conf,{{Mod,Func},NewConf1}},
+ sync_send(group_leader(),set_curr_conf,{{Mod,Func},NewConf1},
+ 5000, fun() -> exit(no_answer_from_group_leader) end),
put(test_server_loc, {Mod,Func}),
%% execute the test case
{{T,Return},Loc} = {ts_tc(Mod, Func, [NewConf1]),get_loc()},
{EndConf,TSReturn,FWReturn} =
case Return of
{E,TCError} when E=='EXIT' ; E==failed ->
+ ModLoc = mod_loc(Loc),
fw_error_notify(Mod, Func, NewConf1,
- TCError, mod_loc(Loc)),
- {[{tc_status,{failed,TCError}}|NewConf1],
+ TCError, ModLoc),
+ {[{tc_status,{failed,TCError}},
+ {tc_fail_loc,ModLoc}|NewConf1],
Return,{error,TCError}};
SaveCfg={save_config,_} ->
{[{tc_status,ok},SaveCfg|NewConf1],Return,ok};
{skip_and_save,Why,SaveCfg} ->
Skip = {skip,Why},
- {[{tc_status,{skipped,Why}},{save_config,SaveCfg}|NewConf1],
+ {[{tc_status,{skipped,Why}},
+ {save_config,SaveCfg}|NewConf1],
Skip,Skip};
{skip,Why} ->
{[{tc_status,{skipped,Why}}|NewConf1],Return,Return};
_ ->
{[{tc_status,ok}|NewConf1],Return,ok}
end,
- %% clear current state in controller loop
- group_leader() ! {set_curr_conf,undefined},
%% call user callback function if defined
EndConf1 = user_callback(TCCallback, Mod, Func, 'end', EndConf),
+ %% update current state in controller loop
+ sync_send(group_leader(),set_curr_conf,EndConf1,
+ 5000, fun() -> exit(no_answer_from_group_leader) end),
{FWReturn1,TSReturn1,EndConf2} =
case end_per_testcase(Mod, Func, EndConf1) of
SaveCfg1={save_config,_} ->
{FWReturn,TSReturn,[SaveCfg1|lists:keydelete(save_config,1,
EndConf1)]};
- {fail,ReasonToFail} -> % user has failed the testcase
+ {fail,ReasonToFail} ->
+ %% user has failed the testcase
fw_error_notify(Mod, Func, EndConf1, ReasonToFail),
{{error,ReasonToFail},{failed,ReasonToFail},EndConf1};
- {failed,{_,end_per_testcase,_}} = Failure -> % unexpected termination
+ {failed,{_,end_per_testcase,_}} = Failure when FWReturn == ok ->
+ %% unexpected termination in end_per_testcase
+ %% report this as the result to the framework
{Failure,TSReturn,EndConf1};
_ ->
+ %% test case result should be reported to framework
+ %% no matter the status of end_per_testcase
{FWReturn,TSReturn,EndConf1}
end,
+ %% clear current state in controller loop
+ sync_send(group_leader(),set_curr_conf,undefined,
+ 5000, fun() -> exit(no_answer_from_group_leader) end),
put(test_server_init_or_end_conf,undefined),
- case do_end_tc_call(Mod, Func, {FWReturn1,[EndConf2]}, TSReturn1) of
+ case do_end_tc_call(Mod,Func, Loc,
+ {FWReturn1,[EndConf2]}, TSReturn1) of
{failed,Reason} = NewReturn ->
fw_error_notify(Mod,Func,EndConf2, Reason),
{{T,NewReturn},{Mod,Func},[]};
@@ -1193,18 +1248,43 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) ->
%% call user callback function if defined
Return1 = user_callback(TCCallback, Mod, Func, 'end', Return),
{Return2,Opts} = process_return_val([Return1], Mod, Func,
- Args1, Loc, Return1),
+ Args1, {Mod,Func}, Return1),
{{T,Return2},Loc,Opts}
end.
-do_end_tc_call(M,F,Res,Return) ->
+do_end_tc_call(M,F, Loc, Res, Return) ->
+ FwMod = os:getenv("TEST_SERVER_FRAMEWORK"),
+ {Mod,Func} =
+ if FwMod == M ; FwMod == "undefined"; FwMod == false ->
+ {M,F};
+ is_list(Loc) and (length(Loc)>1) ->
+ %% If failure in other module (M) than suite, try locate
+ %% suite name in Loc list and call end_tc with Suite:TestCase
+ %% instead of M:F.
+ GetSuite = fun(S,TC) ->
+ case lists:reverse(atom_to_list(S)) of
+ [$E,$T,$I,$U,$S,$_|_] -> [{S,TC}];
+ _ -> []
+ end
+ end,
+ case lists:flatmap(fun({S,TC,_}) -> GetSuite(S,TC);
+ ({{S,TC},_}) -> GetSuite(S,TC);
+ ({S,TC}) -> GetSuite(S,TC);
+ (_) -> []
+ end, Loc) of
+ [] ->
+ {M,F};
+ [FoundSuite|_] ->
+ FoundSuite
+ end;
+ true ->
+ {M,F}
+ end,
+
Ref = make_ref(),
- case os:getenv("TEST_SERVER_FRAMEWORK") of
- FW when FW == "ct_framework";
- FW == "undefined";
- FW == false ->
+ if FwMod == "ct_framework" ; FwMod == "undefined"; FwMod == false ->
case test_server_sup:framework_call(
- end_tc, [?pl2a(M),F,Res, Return], ok) of
+ end_tc, [?pl2a(Mod),Func,Res, Return], ok) of
{fail,FWReason} ->
{failed,FWReason};
ok ->
@@ -1217,9 +1297,9 @@ do_end_tc_call(M,F,Res,Return) ->
NewReturn ->
NewReturn
end;
- Other ->
- case test_server_sup:framework_call(
- end_tc, [Other,F,Res], Ref) of
+ true ->
+ case test_server_sup:framework_call(FwMod, end_tc,
+ [?pl2a(Mod),Func,Res], Ref) of
{fail,FWReason} ->
{failed,FWReason};
_Else ->
@@ -1242,7 +1322,7 @@ process_return_val([Return], M,F,A, Loc, Final) when is_list(Return) ->
true -> % must be return value from end conf case
process_return_val1(Return, M,F,A, Loc, Final, []);
false -> % must be Config value from init conf case
- case do_end_tc_call(M,F,{ok,A}, Return) of
+ case do_end_tc_call(M, F, Loc, {ok,A}, Return) of
{failed, FWReason} = Failed ->
fw_error_notify(M,F,A, FWReason),
{Failed, []};
@@ -1259,8 +1339,9 @@ process_return_val1([Failed={E,TCError}|_], M,F,A=[Args], Loc, _, SaveOpts)
when E=='EXIT';
E==failed ->
fw_error_notify(M,F,A, TCError, mod_loc(Loc)),
- case do_end_tc_call(M,F,{{error,TCError},
- [[{tc_status,{failed,TCError}}|Args]]}, Failed) of
+ case do_end_tc_call(M,F, Loc, {{error,TCError},
+ [[{tc_status,{failed,TCError}}|Args]]},
+ Failed) of
{failed,FWReason} ->
{{failed,FWReason},SaveOpts};
NewReturn ->
@@ -1277,8 +1358,8 @@ process_return_val1([RetVal={Tag,_}|Opts], M,F,A, Loc, _, SaveOpts) when Tag==sk
process_return_val1(Opts, M,F,A, Loc, RetVal, SaveOpts);
process_return_val1([_|Opts], M,F,A, Loc, Final, SaveOpts) ->
process_return_val1(Opts, M,F,A, Loc, Final, SaveOpts);
-process_return_val1([], M,F,A, _Loc, Final, SaveOpts) ->
- case do_end_tc_call(M,F,{Final,A}, Final) of
+process_return_val1([], M,F,A, Loc, Final, SaveOpts) ->
+ case do_end_tc_call(M,F, Loc, {Final,A}, Final) of
{failed,FWReason} ->
{{failed,FWReason},SaveOpts};
NewReturn ->
@@ -1383,9 +1464,13 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) ->
{'$test_server_ok',_} ->
ok;
{'EXIT',Reason} = Why ->
- comment(io_lib:format("<font color=\"red\">"
+ Comment0 = case read_comment() of
+ "" -> "";
+ Cmt -> Cmt ++ "<br>"
+ end,
+ comment(io_lib:format("~s<font color=\"red\">"
"WARNING: ~w crashed!"
- "</font>\n",[EndFunc])),
+ "</font>\n",[Comment0,EndFunc])),
group_leader() ! {printout,12,
"WARNING: ~w crashed!\n"
"Reason: ~p\n"
@@ -1395,9 +1480,13 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) ->
mod_loc(get_loc()))]},
{failed,{Mod,end_per_testcase,Why}};
Other ->
- comment(io_lib:format("<font color=\"red\">"
+ Comment0 = case read_comment() of
+ "" -> "";
+ Cmt -> Cmt ++ "<br>"
+ end,
+ comment(io_lib:format("~s<font color=\"red\">"
"WARNING: ~w thrown!"
- "</font>\n",[EndFunc])),
+ "</font>\n",[Comment0,EndFunc])),
group_leader() ! {printout,12,
"WARNING: ~w thrown!\n"
"Reason: ~p\n"
@@ -1845,11 +1934,54 @@ time_ms({seconds,N}) -> seconds(N);
time_ms({Other,_N}) ->
format("=== ERROR: Invalid time specification: ~p. "
"Should be seconds, minutes, or hours.~n", [Other]),
- exit({invalid_time_spec,Other});
+ exit({invalid_time_format,Other});
time_ms(Ms) when is_integer(Ms) -> Ms;
time_ms(infinity) -> infinity;
-time_ms(Other) -> exit({invalid_time_spec,Other}).
+time_ms(Fun) when is_function(Fun) ->
+ time_ms_apply(Fun);
+time_ms({M,F,A}=MFA) when is_atom(M), is_atom(F), is_list(A) ->
+ time_ms_apply(MFA);
+time_ms(Other) -> exit({invalid_time_format,Other}).
+
+time_ms_apply(Func) ->
+ time_ms_apply(Func, [5000,30000,60000,infinity]).
+
+time_ms_apply(Func, TOs) ->
+ Apply = fun() ->
+ case Func of
+ {M,F,A} ->
+ exit({self(),apply(M, F, A)});
+ Fun ->
+ exit({self(),Fun()})
+ end
+ end,
+ Pid = spawn(Apply),
+ Ref = monitor(process, Pid),
+ time_ms_wait(Func, Pid, Ref, TOs).
+time_ms_wait(Func, Pid, Ref, [TO|TOs]) ->
+ receive
+ {'DOWN',Ref,process,Pid,{Pid,Result}} ->
+ time_ms_check(Result);
+ {'DOWN',Ref,process,Pid,Error} ->
+ exit({timetrap_error,Error})
+ after
+ TO ->
+ format("=== WARNING: No return from timetrap function ~p~n", [Func]),
+ time_ms_wait(Func, Pid, Ref, TOs)
+ end;
+%% this clause will never execute if 'infinity' is in TOs list, that's ok!
+time_ms_wait(Func, Pid, Ref, []) ->
+ demonitor(Ref),
+ exit(Pid, kill),
+ exit({timetrap_error,{no_return_from_timetrap_function,Func}}).
+
+time_ms_check(MFA = {M,F,A}) when is_atom(M), is_atom(F), is_list(A) ->
+ exit({invalid_time_format,MFA});
+time_ms_check(Fun) when is_function(Fun) ->
+ exit({invalid_time_format,Fun});
+time_ms_check(Other) ->
+ time_ms(Other).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% timetrap_cancel(Handle) -> ok
@@ -1897,6 +2029,19 @@ hours(N) -> trunc(N * 1000 * 60 * 60).
minutes(N) -> trunc(N * 1000 * 60).
seconds(N) -> trunc(N * 1000).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% sync_send(Pid,Tag,Msg,Timeout,DoAfter) -> Result
+%%
+sync_send(Pid,Tag,Msg,Timeout,DoAfter) ->
+ Pid ! {Tag,self(),Msg},
+ receive
+ {Pid,Tag,Result} ->
+ Result
+ after Timeout ->
+ DoAfter()
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% timecall(M,F,A) -> {Time,Val}
%% Time = float()
@@ -2283,6 +2428,21 @@ comment(String) ->
group_leader() ! {comment,String},
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% read_comment() -> string()
+%%
+%% Read the current comment string stored in
+%% state during test case execution.
+read_comment() ->
+ MsgLooper = group_leader(),
+ MsgLooper ! {read_comment,self()},
+ receive
+ {MsgLooper,read_comment,Comment} ->
+ Comment
+ after
+ 5000 ->
+ ""
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% os_type() -> OsType
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index f3445b742b..4fad86d16d 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -173,7 +173,7 @@
%%% TEST_SERVER INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([output/2, print/2, print/3, print_timestamp/2]).
-export([start_node/3, stop_node/1, wait_for_node/1, is_release_available/1]).
--export([format/1, format/2, format/3]).
+-export([format/1, format/2, format/3, to_string/1]).
-export([get_target_info/0]).
-export([get_hosts/0]).
-export([get_target_os_type/0]).
@@ -1297,6 +1297,7 @@ terminate(_Reason, State) ->
end,
kill_all_jobs(State#state.jobs),
test_server_node:stop(State#state.target_info),
+ test_server_h:restore(),
ok.
kill_all_jobs([{_Name,JobPid}|Jobs]) ->
@@ -1349,6 +1350,10 @@ init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev},
put(test_server_minor_level, MinLev),
put(test_server_random_seed, proplists:get_value(random_seed, ExtraTools)),
put(test_server_testcase_callback, TCCallback),
+ %% before first print, read and set logging options
+ LogOpts = test_server_sup:framework_call(get_logopts, [], []),
+ put(test_server_logopts, LogOpts),
+ put(test_server_log_nl, not lists:member(no_nl, LogOpts)),
StartedExtraTools = start_extra_tools(ExtraTools),
{TimeMy,Result} = ts_tc(Mod, Func, Args),
put(test_server_common_io_handler, undefined),
@@ -1664,6 +1669,11 @@ do_test_cases(TopCases, SkipCases,
Config, TimetrapData) when is_list(TopCases),
is_tuple(TimetrapData) ->
start_log_file(),
+ FwMod =
+ case os:getenv("TEST_SERVER_FRAMEWORK") of
+ FW when FW =:= false; FW =:= "undefined" -> ?MODULE;
+ FW -> list_to_atom(FW)
+ end,
case collect_all_cases(TopCases, SkipCases) of
{error,Why} ->
print(1, "Error starting: ~p", [Why]),
@@ -1676,11 +1686,11 @@ do_test_cases(TopCases, SkipCases,
put(test_server_cases, N),
put(test_server_case_num, 0),
TestSpec =
- add_init_and_end_per_suite(TestSpec0, undefined, undefined),
-
+ add_init_and_end_per_suite(TestSpec0, undefined, undefined, FwMod),
TI = get_target_info(),
- print(1, "Starting test~s", [print_if_known(N, {", ~w test cases",[N]},
- {" (with repeated test cases)",[]})]),
+ print(1, "Starting test~s",
+ [print_if_known(N, {", ~w test cases",[N]},
+ {" (with repeated test cases)",[]})]),
Test = get(test_server_name),
test_server_sup:framework_call(report, [tests_start,{Test,N}]),
@@ -1709,13 +1719,12 @@ do_test_cases(TopCases, SkipCases,
print(html, "<br>Used Erlang ~s in <tt>~s</tt>.\n",
[erlang:system_info(version), code:root_dir()]),
- case os:getenv("TEST_SERVER_FRAMEWORK") of
- FW when FW =:= false; FW =:= "undefined" ->
+ if FwMod == ?MODULE ->
print(html, "<p>Target:<br>\n"),
print_who(TI#target_info.host, TI#target_info.username),
print(html, "<br>Used Erlang ~s in <tt>~s</tt>.\n",
[TI#target_info.version, TI#target_info.root_dir]);
- _ ->
+ true ->
case test_server_sup:framework_call(target_info, []) of
TargetInfo when is_list(TargetInfo),
length(TargetInfo) > 0 ->
@@ -1884,11 +1893,12 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName) ->
[]),
SrcListing = downcase(cast_to_list(Mod)) ++ ?src_listing_ext,
- case filelib:is_file(filename:join(LogDir, SrcListing)) of
- true ->
+ case {filelib:is_file(filename:join(LogDir, SrcListing)),
+ lists:member(no_src, get(test_server_logopts))} of
+ {true,false} ->
print(Lev, "<a href=\"~s#~s\">source code for ~p:~p/1</a>\n",
[SrcListing,Func,Mod,Func]);
- false -> ok
+ _ -> ok
end,
io:fwrite(Fd, "<pre>\n", []),
@@ -2005,54 +2015,69 @@ copy_html_file(Src, DestDir) ->
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% add_init_and_end_per_suite(TestSpec, Mod, Ref) -> NewTestSpec
+%% add_init_and_end_per_suite(TestSpec, Mod, Ref, FwMod) -> NewTestSpec
%%
%% Expands TestSpec with an initial init_per_suite, and a final
%% end_per_suite element, per each discovered suite in the list.
-add_init_and_end_per_suite([{make,_,_}=Case|Cases], LastMod, LastRef) ->
- [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef)];
-add_init_and_end_per_suite([{skip_case,{{Mod,all},_}}=Case|Cases], LastMod, LastRef)
- when Mod =/= LastMod ->
+add_init_and_end_per_suite([{make,_,_}=Case|Cases], LastMod, LastRef, FwMod) ->
+ [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)];
+add_init_and_end_per_suite([{skip_case,{{Mod,all},_}}=Case|Cases], LastMod,
+ LastRef, FwMod) when Mod =/= LastMod ->
{PreCases, NextMod, NextRef} =
do_add_end_per_suite_and_skip(LastMod, LastRef, Mod),
- PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)];
-add_init_and_end_per_suite([{skip_case,{{Mod,_},_}}=Case|Cases], LastMod, LastRef)
- when Mod =/= LastMod ->
+ PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)];
+add_init_and_end_per_suite([{skip_case,{{Mod,_},_}}=Case|Cases], LastMod,
+ LastRef, FwMod) when Mod =/= LastMod ->
{PreCases, NextMod, NextRef} =
do_add_init_and_end_per_suite(LastMod, LastRef, Mod),
- PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)];
-add_init_and_end_per_suite([{skip_case,{conf,_,{Mod,_},_}}=Case|Cases], LastMod, LastRef)
- when Mod =/= LastMod ->
+ PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)];
+add_init_and_end_per_suite([{skip_case,{conf,_,{Mod,_},_}}=Case|Cases], LastMod,
+ LastRef, FwMod) when Mod =/= LastMod ->
{PreCases, NextMod, NextRef} =
do_add_init_and_end_per_suite(LastMod, LastRef, Mod),
- PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)];
-add_init_and_end_per_suite([{skip_case,_}=Case|Cases], LastMod, LastRef) ->
- [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef)];
-add_init_and_end_per_suite([{conf,_,_,{Mod,_}}=Case|Cases], LastMod, LastRef)
- when Mod =/= LastMod ->
+ PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)];
+add_init_and_end_per_suite([{skip_case,_}=Case|Cases], LastMod, LastRef, FwMod) ->
+ [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)];
+add_init_and_end_per_suite([{conf,Ref,Props,{FwMod,Func}}=Case|Cases], LastMod,
+ LastRef, FwMod) ->
+ %% if Mod == FwMod, this conf test is (probably) a test case group where
+ %% the init- and end-functions are missing in the suite, and if so,
+ %% the suite name should be stored as {suite,Suite} in Props
+ case proplists:get_value(suite, Props) of
+ Suite when Suite =/= undefined, Suite =/= LastMod ->
+ {PreCases, NextMod, NextRef} =
+ do_add_init_and_end_per_suite(LastMod, LastRef, Suite),
+ Case1 = {conf,Ref,proplists:delete(suite,Props),{FwMod,Func}},
+ PreCases ++ [Case1|add_init_and_end_per_suite(Cases, NextMod,
+ NextRef, FwMod)];
+ _ ->
+ [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)]
+ end;
+add_init_and_end_per_suite([{conf,_,_,{Mod,_}}=Case|Cases], LastMod,
+ LastRef, FwMod) when Mod =/= LastMod, Mod =/= FwMod ->
{PreCases, NextMod, NextRef} =
do_add_init_and_end_per_suite(LastMod, LastRef, Mod),
- PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)];
-add_init_and_end_per_suite([{conf,_,_,_}=Case|Cases], LastMod, LastRef) ->
- [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef)];
-add_init_and_end_per_suite([{Mod,_}=Case|Cases], LastMod, LastRef)
- when Mod =/= LastMod ->
+ PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)];
+add_init_and_end_per_suite([{conf,_,_,_}=Case|Cases], LastMod, LastRef, FwMod) ->
+ [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)];
+add_init_and_end_per_suite([{Mod,_}=Case|Cases], LastMod, LastRef, FwMod)
+ when Mod =/= LastMod, Mod =/= FwMod ->
{PreCases, NextMod, NextRef} =
do_add_init_and_end_per_suite(LastMod, LastRef, Mod),
- PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)];
-add_init_and_end_per_suite([{Mod,_,_}=Case|Cases], LastMod, LastRef)
- when Mod =/= LastMod ->
+ PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)];
+add_init_and_end_per_suite([{Mod,_,_}=Case|Cases], LastMod, LastRef, FwMod)
+ when Mod =/= LastMod, Mod =/= FwMod ->
{PreCases, NextMod, NextRef} =
do_add_init_and_end_per_suite(LastMod, LastRef, Mod),
- PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)];
-add_init_and_end_per_suite([Case|Cases], LastMod, LastRef)->
- [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef)];
-add_init_and_end_per_suite([], _LastMod, undefined) ->
+ PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)];
+add_init_and_end_per_suite([Case|Cases], LastMod, LastRef, FwMod)->
+ [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)];
+add_init_and_end_per_suite([], _LastMod, undefined, _FwMod) ->
[];
-add_init_and_end_per_suite([], _LastMod, skipped_suite) ->
+add_init_and_end_per_suite([], _LastMod, skipped_suite, _FwMod) ->
[];
-add_init_and_end_per_suite([], LastMod, LastRef) ->
+add_init_and_end_per_suite([], LastMod, LastRef, _FwMod) ->
[{conf,LastRef,[],{LastMod,end_per_suite}}].
do_add_init_and_end_per_suite(LastMod, LastRef, Mod) ->
@@ -2101,7 +2126,12 @@ run_test_cases(TestSpec, Config, TimetrapData) ->
maybe_open_job_sock(),
- html_convert_modules(TestSpec, Config),
+ case lists:member(no_src, get(test_server_logopts)) of
+ true ->
+ ok;
+ false ->
+ html_convert_modules(TestSpec, Config)
+ end,
run_test_cases_loop(TestSpec, [Config], TimetrapData, [], []),
@@ -2310,7 +2340,8 @@ run_test_cases_loop([{auto_skip_case,{Type,Ref,Case,Comment},SkipMode}|Cases],
handle_test_case_io_and_status(),
set_io_buffering(undefined),
{Mod,Func} = skip_case(auto, Ref, 0, Case, Comment, false, SkipMode),
- test_server_sup:framework_call(report, [tc_auto_skip,{?pl2a(Mod),Func,Comment}]),
+ test_server_sup:framework_call(report, [tc_auto_skip,
+ {?pl2a(Mod),Func,Comment}]),
run_test_cases_loop(Cases, Config, TimetrapData, ParentMode,
delete_status(Ref, Status));
_ ->
@@ -2318,7 +2349,8 @@ run_test_cases_loop([{auto_skip_case,{Type,Ref,Case,Comment},SkipMode}|Cases],
%% parallel group (io buffering is active)
wait_for_cases(Ref),
{Mod,Func} = skip_case(auto, Ref, 0, Case, Comment, true, SkipMode),
- test_server_sup:framework_call(report, [tc_auto_skip,{?pl2a(Mod),Func,Comment}]),
+ test_server_sup:framework_call(report, [tc_auto_skip,
+ {?pl2a(Mod),Func,Comment}]),
case CurrIOHandler of
{Ref,_} ->
%% current_io_handler was set by start conf of this
@@ -3959,8 +3991,11 @@ progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time,
case RetVal of
{comment,RetComment} ->
String = to_string(RetComment),
+ HtmlCmt = test_server_sup:framework_call(format_comment,
+ [String],
+ String),
print(major, "=result ok: ~s", [String]),
- "<td>" ++ String ++ "</td>";
+ "<td>" ++ HtmlCmt ++ "</td>";
_ ->
print(major, "=result ok", []),
case Comment0 of
@@ -4345,14 +4380,18 @@ output_to_fd(Fd, [$=|Msg], internal) ->
io:put_chars(Fd, [$=]),
io:put_chars(Fd, Msg),
io:put_chars(Fd, "\n");
+
output_to_fd(Fd, Msg, internal) ->
io:put_chars(Fd, [$=,$=,$=,$ ]),
io:put_chars(Fd, Msg),
io:put_chars(Fd, "\n");
+
output_to_fd(Fd, Msg, _Sender) ->
io:put_chars(Fd, Msg),
- io:put_chars(Fd, "\n").
-
+ case get(test_server_log_nl) of
+ false -> ok;
+ _ -> io:put_chars(Fd, "\n")
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% timestamp_filename_get(Leader) -> string()
@@ -4665,7 +4704,7 @@ collect_case_invoke(Mod, Case, MFA, St) ->
collect_subcases(Mod, Case, MFA, St, Suite)
end;
_ ->
- Suite = test_server_sup:framework_call(get_suite, [?pl2a(Mod),Case],[]),
+ Suite = test_server_sup:framework_call(get_suite, [?pl2a(Mod),Case], []),
collect_subcases(Mod, Case, MFA, St, Suite)
end.
diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl
index 53dfb45e3a..77d364d5cb 100644
--- a/lib/test_server/src/test_server_sup.erl
+++ b/lib/test_server/src/test_server_sup.erl
@@ -26,7 +26,7 @@
cleanup_crash_dumps/0, crash_dump_dir/0, tar_crash_dumps/0,
get_username/0, get_os_family/0,
hostatom/0, hostatom/1, hoststr/0, hoststr/1,
- framework_call/2,framework_call/3,
+ framework_call/2,framework_call/3,framework_call/4,
format_loc/1, package_str/1, package_atom/1,
call_trace/1]).
-include("test_server_internal.hrl").
@@ -540,8 +540,9 @@ format_loc({Mod,Func}) when is_atom(Func) ->
format_loc({Mod,Line}) when is_integer(Line) ->
%% ?line macro is used
ModStr = package_str(Mod),
- case lists:reverse(ModStr) of
- [$E,$T,$I,$U,$S,$_|_] ->
+ case {lists:member(no_src, get(test_server_logopts)),
+ lists:reverse(ModStr)} of
+ {false,[$E,$T,$I,$U,$S,$_|_]} ->
io_lib:format("{~s,<a href=\"~s~s#~w\">~w</a>}",
[ModStr,downcase(ModStr),?src_listing_ext,
round_to_10(Line),Line]);
@@ -557,8 +558,9 @@ format_loc1([{Mod,Func,Line}|Rest]) ->
[" ",format_loc1({Mod,Func,Line}),",\n"|format_loc1(Rest)];
format_loc1({Mod,Func,Line}) ->
ModStr = package_str(Mod),
- case lists:reverse(ModStr) of
- [$E,$T,$I,$U,$S,$_|_] ->
+ case {lists:member(no_src, get(test_server_logopts)),
+ lists:reverse(ModStr)} of
+ {false,[$E,$T,$I,$U,$S,$_|_]} ->
io_lib:format("{~s,~w,<a href=\"~s~s#~w\">~w</a>}",
[ModStr,Func,downcase(ModStr),?src_listing_ext,
round_to_10(Line),Line]);
diff --git a/lib/test_server/src/ts_erl_config.erl b/lib/test_server/src/ts_erl_config.erl
index 640c8ddc9f..3b41f90d55 100644
--- a/lib/test_server/src/ts_erl_config.erl
+++ b/lib/test_server/src/ts_erl_config.erl
@@ -222,7 +222,6 @@ erl_interface(Vars,OsType) ->
end,
CrossCompile = case OsType of
vxworks -> "true";
- ose -> "true";
_ -> "false"
end,
[{erl_interface_libpath, filename:nativename(LibPath)},
@@ -329,8 +328,6 @@ sock_libraries({win32, _}) ->
sock_libraries({unix, _}) ->
""; % Included in general libraries if needed.
sock_libraries(vxworks) ->
- "";
-sock_libraries(ose) ->
"".
link_library(LibName,{win32, _}) ->
@@ -339,8 +336,6 @@ link_library(LibName,{unix, _}) ->
"lib" ++ LibName ++ ".a";
link_library(LibName,vxworks) ->
"lib" ++ LibName ++ ".a";
-link_library(_LibName,ose) ->
- "";
link_library(_LibName,_Other) ->
exit({link_library, not_supported}).
diff --git a/lib/test_server/test/test_server_SUITE.erl b/lib/test_server/test/test_server_SUITE.erl
index 4c344717f0..a8532b08ab 100644
--- a/lib/test_server/test/test_server_SUITE.erl
+++ b/lib/test_server/test/test_server_SUITE.erl
@@ -119,6 +119,11 @@ test_server_conf02_SUITE(Config) ->
run_test_server_tests(SuiteName, NCases, NFail, NExpected, NSucc,
NUsrSkip, NAutoSkip,
NActualSkip, NActualFail, NActualSucc, Config) ->
+
+ ct:log("See test case log files under:~n~p~n",
+ [filename:join([proplists:get_value(priv_dir, Config),
+ SuiteName++".logs"])]),
+
Node = proplists:get_value(node, Config),
{ok,_Pid} = rpc:call(Node,test_server_ctrl, start, []),
rpc:call(Node,
@@ -132,6 +137,7 @@ run_test_server_tests(SuiteName, NCases, NFail, NExpected, NSucc,
end),
rpc:call(Node,test_server_ctrl, stop, []),
+
{ok,#suite{ n_cases = NCases,
n_cases_failed = NFail,
n_cases_expected = NExpected,
diff --git a/lib/test_server/vsn.mk b/lib/test_server/vsn.mk
index 1dd4a84ce9..563c1b6db6 100644
--- a/lib/test_server/vsn.mk
+++ b/lib/test_server/vsn.mk
@@ -1,2 +1,2 @@
-TEST_SERVER_VSN = 3.4.4
+TEST_SERVER_VSN = 3.4.5