720
736
print(Detail,Format,Args),
721
737
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
722
738
{comment,NewComment} ->
739
NewComment1 = test_server_ctrl:to_string(NewComment),
740
NewComment2 = test_server_sup:framework_call(format_comment,
724
744
case Terminate of
725
745
{true,{Time,Value,Loc,Opts,_OldComment}} ->
726
{true,{Time,Value,mod_loc(Loc),Opts,NewComment}};
746
{true,{Time,Value,mod_loc(Loc),Opts,NewComment2}};
730
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate1,NewComment,CurrConf);
731
{set_curr_conf,NewCurrConf} ->
750
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate1,NewComment2,CurrConf);
751
{read_comment,From} ->
752
From ! {self(),read_comment,Comment},
753
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
754
{set_curr_conf,From,NewCurrConf} ->
755
From ! {self(),set_curr_conf,ok},
732
756
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,NewCurrConf);
733
757
{'EXIT',Pid,{Ref,Time,Value,Loc,Opts}} ->
734
758
RetVal = {Time/1000000,Value,mod_loc(Loc),Opts,Comment},
826
852
%% result of an exit(TestCase,kill) call, which is the
827
853
%% only way to abort a testcase process that traps exits
828
854
%% (see abort_current_testcase)
829
spawn_fw_call(undefined,undefined,Pid,testcase_aborted_or_killed,
855
spawn_fw_call(undefined,undefined,CurrConf,Pid,
856
testcase_aborted_or_killed,
830
857
unknown,self(),Comment),
831
858
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
832
859
{fw_error,{FwMod,FwFunc,FwError}} ->
833
spawn_fw_call(FwMod,FwFunc,Pid,{framework_error,FwError},
860
spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,{framework_error,FwError},
834
861
unknown,self(),Comment),
835
862
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
837
864
%% the testcase has terminated because of Reason (e.g. an exit
838
865
%% because a linked process failed)
839
spawn_fw_call(undefined,undefined,Pid,Reason,
866
spawn_fw_call(undefined,undefined,CurrConf,Pid,Reason,
840
867
unknown,self(),Comment),
841
868
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf)
929
956
spawn_link(EndConfProc).
931
spawn_fw_call(Mod,{init_per_testcase,Func},Pid,{timetrap_timeout,TVal}=Why,
958
spawn_fw_call(Mod,{init_per_testcase,Func},_,Pid,{timetrap_timeout,TVal}=Why,
932
959
Loc,SendTo,Comment) ->
935
Skip = {skip,{failed,{Mod,init_per_testcase,Why}}},
936
%% if init_per_testcase fails, the test case
938
case catch test_server_sup:framework_call(
939
end_tc,[?pl2a(Mod),Func,{Pid,Skip,[[]]}]) of
940
{'EXIT',FwEndTCErr} ->
941
exit({fw_notify_done,end_tc,FwEndTCErr});
945
%% finished, report back
946
SendTo ! {self(),fw_notify_done,
947
{TVal/1000,Skip,Loc,[],Comment}}
962
Skip = {skip,{failed,{Mod,init_per_testcase,Why}}},
963
%% if init_per_testcase fails, the test case
965
case catch do_end_tc_call(Mod,Func, Loc, {Pid,Skip,[[]]}, Why) of
966
{'EXIT',FwEndTCErr} ->
967
exit({fw_notify_done,end_tc,FwEndTCErr});
971
%% finished, report back
972
SendTo ! {self(),fw_notify_done,
973
{TVal/1000,Skip,Loc,[],Comment}}
949
975
spawn_link(FwCall);
951
spawn_fw_call(Mod,{end_per_testcase,Func},Pid,{timetrap_timeout,TVal}=Why,
952
Loc,SendTo,_Comment) ->
977
spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid,
978
{timetrap_timeout,TVal}=Why,_Loc,SendTo,Comment) ->
979
%%! This is a temporary fix that keeps Test Server alive during
980
%%! execution of a parallel test case group, when sometimes
981
%%! this clause gets called with EndConf == undefined. See OTP-9594
983
EndConf1 = if EndConf == undefined ->
984
[{tc_status,{failed,{Mod,end_per_testcase,Why}}}];
955
Conf = [{tc_status,ok}],
956
%% if end_per_testcase fails, the test case should be
957
%% reported successful with a warning printed as comment
958
case catch test_server_sup:framework_call(end_tc,
961
{failed,{Mod,end_per_testcase,Why}},
963
{'EXIT',FwEndTCErr} ->
964
exit({fw_notify_done,end_tc,FwEndTCErr});
968
%% finished, report back
969
SendTo ! {self(),fw_notify_done,
970
{TVal/1000,{error,{Mod,end_per_testcase,Why}},Loc,[],
971
["<font color=\"red\">"
972
"WARNING: end_per_testcase timed out!"
991
case proplists:get_value(tc_status, EndConf1) of
993
E = {failed,{Mod,end_per_testcase,Why}},
995
E = {failed,Reason} ->
998
E = {failed,{Mod,end_per_testcase,Why}},
1001
FailLoc = proplists:get_value(tc_fail_loc, EndConf1),
1002
case catch do_end_tc_call(Mod,Func, FailLoc,
1003
{Pid,Report,[EndConf1]}, Why) of
1004
{'EXIT',FwEndTCErr} ->
1005
exit({fw_notify_done,end_tc,FwEndTCErr});
1009
%% if end_per_testcase fails a warning should be
1010
%% printed as comment
1011
Comment1 = if Comment == "" ->
1014
Comment ++ test_server_ctrl:xhtml("<br>",
1017
%% finished, report back
1018
SendTo ! {self(),fw_notify_done,
1019
{TVal/1000,RetVal,FailLoc,[],
1020
[Comment1,"<font color=\"red\">"
1021
"WARNING: end_per_testcase timed out!"
975
1024
spawn_link(FwCall);
977
spawn_fw_call(FwMod,FwFunc,_Pid,{framework_error,FwError},_,SendTo,_Comment) ->
1026
spawn_fw_call(FwMod,FwFunc,_,_Pid,{framework_error,FwError},_,SendTo,_Comment) ->
980
1029
test_server_sup:framework_call(report, [framework_error,
1074
1123
run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback);
1075
1124
Error = {error,_Reason} ->
1076
test_server_sup:framework_call(end_tc,[?pl2a(Mod),Func,{Error,Args0}]),
1077
{{0,{skip,{failed,Error}}},{Mod,Func},[]};
1126
NewResult = do_end_tc_call(Mod,Func, Where, {Error,Args0},
1127
{skip,{failed,Error}}),
1128
{{0,NewResult},Where,[]};
1078
1129
{fail,Reason} ->
1080
Conf1 = [{tc_status,{failed,Reason}} | Conf],
1130
Conf = [{tc_status,{failed,Reason}} | hd(Args0)],
1081
1132
fw_error_notify(Mod, Func, Conf, Reason),
1082
test_server_sup:framework_call(end_tc,[?pl2a(Mod),Func,
1083
{{error,Reason},[Conf1]}]),
1084
{{0,{failed,Reason}},{Mod,Func},[]};
1133
NewResult = do_end_tc_call(Mod,Func, Where, {{error,Reason},[Conf]},
1135
{{0,NewResult},Where,[]};
1085
1136
Skip = {skip,_Reason} ->
1086
test_server_sup:framework_call(end_tc,[?pl2a(Mod),Func,{Skip,Args0}]),
1087
{{0,Skip},{Mod,Func},[]};
1138
NewResult = do_end_tc_call(Mod,Func, Where, {Skip,Args0}, Skip),
1139
{{0,NewResult},Where,[]};
1088
1140
{auto_skip,Reason} ->
1089
test_server_sup:framework_call(end_tc,[?pl2a(Mod),
1091
{{skip,Reason},Args0}]),
1092
{{0,{skip,{fw_auto_skip,Reason}}},{Mod,Func},[]}
1142
NewResult = do_end_tc_call(Mod,Func, Where, {{skip,Reason},Args0},
1144
{{0,NewResult},Where,[]}
1094
1146
exit({Ref,Time,Value,Loc,Opts}).
1103
1155
Skip = {skip,Reason} ->
1104
1156
Line = get_loc(),
1105
1157
Conf = [{tc_status,{skipped,Reason}}],
1106
test_server_sup:framework_call(end_tc,[?pl2a(Mod),Func,{Skip,[Conf]}]),
1107
{{0,{skip,Reason}},Line,[]};
1158
NewRes = do_end_tc_call(Mod,Func, Line, {Skip,[Conf]}, Skip),
1159
{{0,NewRes},Line,[]};
1108
1160
{skip_and_save,Reason,SaveCfg} ->
1109
1161
Line = get_loc(),
1110
1162
Conf = [{tc_status,{skipped,Reason}},{save_config,SaveCfg}],
1111
test_server_sup:framework_call(end_tc,[?pl2a(Mod),Func,
1112
{{skip,Reason},[Conf]}]),
1113
{{0,{skip,Reason}},Line,[]};
1163
NewRes = do_end_tc_call(Mod,Func, Line, {{skip,Reason},[Conf]},
1165
{{0,NewRes},Line,[]};
1166
FailTC = {fail,Reason} -> % user fails the testcase
1167
EndConf = [{tc_status,{failed,Reason}} | hd(Args)],
1168
fw_error_notify(Mod, Func, EndConf, Reason),
1169
NewRes = do_end_tc_call(Mod,Func, {Mod,Func},
1170
{{error,Reason},[EndConf]},
1172
{{0,NewRes},{Mod,Func},[]};
1114
1173
{ok,NewConf} ->
1115
1174
put(test_server_init_or_end_conf,undefined),
1116
1175
%% call user callback function if defined
1117
1176
NewConf1 = user_callback(TCCallback, Mod, Func, init, NewConf),
1118
1177
%% save current state in controller loop
1119
group_leader() ! {set_curr_conf,{{Mod,Func},NewConf1}},
1178
sync_send(group_leader(),set_curr_conf,{{Mod,Func},NewConf1},
1179
5000, fun() -> exit(no_answer_from_group_leader) end),
1120
1180
put(test_server_loc, {Mod,Func}),
1121
1181
%% execute the test case
1122
1182
{{T,Return},Loc} = {ts_tc(Mod, Func, [NewConf1]),get_loc()},
1123
1183
{EndConf,TSReturn,FWReturn} =
1125
1185
{E,TCError} when E=='EXIT' ; E==failed ->
1186
ModLoc = mod_loc(Loc),
1126
1187
fw_error_notify(Mod, Func, NewConf1,
1127
TCError, mod_loc(Loc)),
1128
{[{tc_status,{failed,TCError}}|NewConf1],
1189
{[{tc_status,{failed,TCError}},
1190
{tc_fail_loc,ModLoc}|NewConf1],
1129
1191
Return,{error,TCError}};
1130
1192
SaveCfg={save_config,_} ->
1131
1193
{[{tc_status,ok},SaveCfg|NewConf1],Return,ok};
1132
1194
{skip_and_save,Why,SaveCfg} ->
1133
1195
Skip = {skip,Why},
1134
{[{tc_status,{skipped,Why}},{save_config,SaveCfg}|NewConf1],
1196
{[{tc_status,{skipped,Why}},
1197
{save_config,SaveCfg}|NewConf1],
1137
1200
{[{tc_status,{skipped,Why}}|NewConf1],Return,Return};
1139
1202
{[{tc_status,ok}|NewConf1],Return,ok}
1141
%% clear current state in controller loop
1142
group_leader() ! {set_curr_conf,undefined},
1143
1204
%% call user callback function if defined
1144
1205
EndConf1 = user_callback(TCCallback, Mod, Func, 'end', EndConf),
1206
%% update current state in controller loop
1207
sync_send(group_leader(),set_curr_conf,EndConf1,
1208
5000, fun() -> exit(no_answer_from_group_leader) end),
1145
1209
{FWReturn1,TSReturn1,EndConf2} =
1146
1210
case end_per_testcase(Mod, Func, EndConf1) of
1147
1211
SaveCfg1={save_config,_} ->
1148
{FWReturn,TSReturn,[SaveCfg1|lists:keydelete(save_config, 1, EndConf1)]};
1149
{fail,ReasonToFail} -> % user has failed the testcase
1212
{FWReturn,TSReturn,[SaveCfg1|lists:keydelete(save_config,1,
1214
{fail,ReasonToFail} ->
1215
%% user has failed the testcase
1150
1216
fw_error_notify(Mod, Func, EndConf1, ReasonToFail),
1151
1217
{{error,ReasonToFail},{failed,ReasonToFail},EndConf1};
1152
{failed,{_,end_per_testcase,_}} = Failure -> % unexpected termination
1218
{failed,{_,end_per_testcase,_}} = Failure when FWReturn == ok ->
1219
%% unexpected termination in end_per_testcase
1220
%% report this as the result to the framework
1153
1221
{Failure,TSReturn,EndConf1};
1223
%% test case result should be reported to framework
1224
%% no matter the status of end_per_testcase
1155
1225
{FWReturn,TSReturn,EndConf1}
1227
%% clear current state in controller loop
1228
sync_send(group_leader(),set_curr_conf,undefined,
1229
5000, fun() -> exit(no_answer_from_group_leader) end),
1157
1230
put(test_server_init_or_end_conf,undefined),
1158
case test_server_sup:framework_call(end_tc, [?pl2a(Mod), Func,
1159
{FWReturn1,[EndConf2]}]) of
1161
fw_error_notify(Mod, Func, EndConf2, Reason),
1162
{{T,{failed,Reason}},{Mod,Func},[]};
1164
{{T,TSReturn1},Loc,[]}
1231
case do_end_tc_call(Mod,Func, Loc,
1232
{FWReturn1,[EndConf2]}, TSReturn1) of
1233
{failed,Reason} = NewReturn ->
1234
fw_error_notify(Mod,Func,EndConf2, Reason),
1235
{{T,NewReturn},{Mod,Func},[]};
1237
{{T,NewReturn},Loc,[]}
1179
1252
{{T,Return},Loc} = {ts_tc(Mod, Func, Args2),get_loc()},
1180
1253
%% call user callback function if defined
1181
1254
Return1 = user_callback(TCCallback, Mod, Func, 'end', Return),
1182
{Return2,Opts} = process_return_val([Return1], Mod,Func,Args1, Loc, Return1),
1255
{Return2,Opts} = process_return_val([Return1], Mod, Func,
1256
Args1, {Mod,Func}, Return1),
1183
1257
{{T,Return2},Loc,Opts}
1260
do_end_tc_call(M,F, Loc, Res, Return) ->
1261
IsSuite = case lists:reverse(atom_to_list(M)) of
1262
[$E,$T,$I,$U,$S,$_|_] -> true;
1265
FwMod = os:getenv("TEST_SERVER_FRAMEWORK"),
1267
if FwMod == M ; FwMod == "undefined"; FwMod == false ->
1269
(not IsSuite) and is_list(Loc) and (length(Loc)>1) ->
1270
%% If failure in other module (M) than suite, try locate
1271
%% suite name in Loc list and call end_tc with Suite:TestCase
1273
GetSuite = fun(S,TC) ->
1274
case lists:reverse(atom_to_list(S)) of
1275
[$E,$T,$I,$U,$S,$_|_] -> [{S,TC}];
1279
case lists:flatmap(fun({S,TC,_}) -> GetSuite(S,TC);
1280
({{S,TC},_}) -> GetSuite(S,TC);
1281
({S,TC}) -> GetSuite(S,TC);
1294
if FwMod == "ct_framework" ; FwMod == "undefined"; FwMod == false ->
1295
case test_server_sup:framework_call(
1296
end_tc, [?pl2a(Mod),Func,Res, Return], ok) of
1310
case test_server_sup:framework_call(FwMod, end_tc,
1311
[?pl2a(Mod),Func,Res], Ref) of
1186
1319
%% the return value is a list and we have to check if it contains
1187
1320
%% the result of an end conf case or if it's a Config list
1188
1321
process_return_val([Return], M,F,A, Loc, Final) when is_list(Return) ->
1211
1344
process_return_val(Return, M,F,A, Loc, Final) ->
1212
1345
process_return_val1(Return, M,F,A, Loc, Final, []).
1214
process_return_val1([Failed={E,TCError}|_], M,F,A=[Args], Loc, _, SaveOpts) when E=='EXIT';
1347
process_return_val1([Failed={E,TCError}|_], M,F,A=[Args], Loc, _, SaveOpts)
1216
1350
fw_error_notify(M,F,A, TCError, mod_loc(Loc)),
1217
case test_server_sup:framework_call(end_tc,
1218
[?pl2a(M),F,{{error,TCError},
1219
[[{tc_status,{failed,TCError}}|Args]]}]) of
1351
case do_end_tc_call(M,F, Loc, {{error,TCError},
1352
[[{tc_status,{failed,TCError}}|Args]]},
1354
{failed,FWReason} ->
1221
1355
{{failed,FWReason},SaveOpts};
1357
{NewReturn,SaveOpts}
1225
1359
process_return_val1([SaveCfg={save_config,_}|Opts], M,F,[Args], Loc, Final, SaveOpts) ->
1226
1360
process_return_val1(Opts, M,F,[[SaveCfg|Args]], Loc, Final, SaveOpts);
1233
1367
process_return_val1(Opts, M,F,A, Loc, RetVal, SaveOpts);
1234
1368
process_return_val1([_|Opts], M,F,A, Loc, Final, SaveOpts) ->
1235
1369
process_return_val1(Opts, M,F,A, Loc, Final, SaveOpts);
1236
process_return_val1([], M,F,A, _Loc, Final, SaveOpts) ->
1237
case test_server_sup:framework_call(end_tc, [?pl2a(M),F,{Final,A}]) of
1370
process_return_val1([], M,F,A, Loc, Final, SaveOpts) ->
1371
case do_end_tc_call(M,F, Loc, {Final,A}, Final) of
1372
{failed,FWReason} ->
1239
1373
{{failed,FWReason},SaveOpts};
1241
{Final,lists:reverse(SaveOpts)}
1375
{NewReturn,lists:reverse(SaveOpts)}
1244
1378
user_callback(undefined, _, _, _, Args) ->
1263
1397
false -> code:load_file(Mod);
1266
%% init_per_testcase defined, returns new configuration
1267
case erlang:function_exported(Mod,init_per_testcase,2) of
1400
case erlang:function_exported(Mod, init_per_testcase, 2) of
1269
case catch my_apply(Mod, init_per_testcase, [Func|Args]) of
1270
{'$test_server_ok',{Skip,Reason}} when Skip==skip;
1273
{'$test_server_ok',Res={skip_and_save,_,_}} ->
1275
{'$test_server_ok',NewConf} when is_list(NewConf) ->
1276
case lists:filter(fun(T) when is_tuple(T) -> false;
1277
(_) -> true end, NewConf) of
1281
group_leader() ! {printout,12,
1282
"ERROR! init_per_testcase has returned "
1283
"bad elements in Config: ~p\n",[Bad]},
1284
{skip,{failed,{Mod,init_per_testcase,bad_return}}}
1286
{'$test_server_ok',_Other} ->
1287
group_leader() ! {printout,12,
1288
"ERROR! init_per_testcase did not return "
1289
"a Config list.\n",[]},
1290
{skip,{failed,{Mod,init_per_testcase,bad_return}}};
1293
FormattedLoc = test_server_sup:format_loc(mod_loc(Line)),
1294
group_leader() ! {printout,12,
1295
"ERROR! init_per_testcase crashed!\n"
1296
"\tLocation: ~s\n\tReason: ~p\n",
1297
[FormattedLoc,Reason]},
1298
{skip,{failed,{Mod,init_per_testcase,Reason}}};
1301
FormattedLoc = test_server_sup:format_loc(mod_loc(Line)),
1302
group_leader() ! {printout,12,
1303
"ERROR! init_per_testcase thrown!\n"
1304
"\tLocation: ~s\n\tReason: ~p\n",
1305
[FormattedLoc, Other]},
1306
{skip,{failed,{Mod,init_per_testcase,Other}}}
1402
do_init_per_testcase(Mod, [Func|Args]);
1309
%% Optional init_per_testcase not defined
1404
%% Optional init_per_testcase is not defined -- keep quiet.
1311
1405
[Config] = Args,
1409
do_init_per_testcase(Mod, Args) ->
1410
try apply(Mod, init_per_testcase, Args) of
1411
{Skip,Reason} when Skip =:= skip; Skip =:= skipped ->
1413
{skip_and_save,_,_}=Res ->
1415
NewConf when is_list(NewConf) ->
1416
case lists:filter(fun(T) when is_tuple(T) -> false;
1417
(_) -> true end, NewConf) of
1421
group_leader() ! {printout,12,
1422
"ERROR! init_per_testcase has returned "
1423
"bad elements in Config: ~p\n",[Bad]},
1424
{skip,{failed,{Mod,init_per_testcase,bad_return}}}
1426
{fail,_Reason}=Res ->
1429
group_leader() ! {printout,12,
1430
"ERROR! init_per_testcase did not return "
1431
"a Config list.\n",[]},
1432
{skip,{failed,{Mod,init_per_testcase,bad_return}}}
1435
set_loc(erlang:get_stacktrace()),
1437
FormattedLoc = test_server_sup:format_loc(mod_loc(Line)),
1438
group_leader() ! {printout,12,
1439
"ERROR! init_per_testcase thrown!\n"
1440
"\tLocation: ~s\n\tReason: ~p\n",
1441
[FormattedLoc, Other]},
1442
{skip,{failed,{Mod,init_per_testcase,Other}}};
1444
Stk = erlang:get_stacktrace(),
1445
Reason = {Reason0,Stk},
1448
FormattedLoc = test_server_sup:format_loc(mod_loc(Line)),
1449
group_leader() ! {printout,12,
1450
"ERROR! init_per_testcase crashed!\n"
1451
"\tLocation: ~s\n\tReason: ~p\n",
1452
[FormattedLoc,Reason]},
1453
{skip,{failed,{Mod,init_per_testcase,Reason}}}
1315
1456
end_per_testcase(Mod, Func, Conf) ->
1316
1457
case erlang:function_exported(Mod,end_per_testcase,2) of
1329
1470
do_end_per_testcase(Mod,EndFunc,Func,Conf) ->
1330
1471
put(test_server_init_or_end_conf,{EndFunc,Func}),
1331
1472
put(test_server_loc, {Mod,{EndFunc,Func}}),
1332
case catch my_apply(Mod, EndFunc, [Func,Conf]) of
1333
{'$test_server_ok',SaveCfg={save_config,_}} ->
1473
try Mod:EndFunc(Func, Conf) of
1474
{save_config,_}=SaveCfg ->
1335
{'$test_server_ok',{fail,_}=Fail} ->
1337
{'$test_server_ok',_} ->
1339
{'EXIT',Reason} = Why ->
1340
comment(io_lib:format("<font color=\"red\">"
1482
Comment0 = case read_comment() of
1484
Cmt -> Cmt ++ test_server_ctrl:xhtml("<br>",
1487
set_loc(erlang:get_stacktrace()),
1488
comment(io_lib:format("~s<font color=\"red\">"
1489
"WARNING: ~w thrown!"
1490
"</font>\n",[Comment0,EndFunc])),
1491
group_leader() ! {printout,12,
1492
"WARNING: ~w thrown!\n"
1496
test_server_sup:format_loc(
1497
mod_loc(get_loc()))]},
1498
{failed,{Mod,end_per_testcase,Other}};
1500
Stk = erlang:get_stacktrace(),
1503
exit -> {'EXIT',Reason};
1504
error -> {'EXIT',{Reason,Stk}}
1506
Comment0 = case read_comment() of
1508
Cmt -> Cmt ++ test_server_ctrl:xhtml("<br>",
1511
comment(io_lib:format("~s<font color=\"red\">"
1341
1512
"WARNING: ~w crashed!"
1342
"</font>\n",[EndFunc])),
1513
"</font>\n",[Comment0,EndFunc])),
1343
1514
group_leader() ! {printout,12,
1344
1515
"WARNING: ~w crashed!\n"
1347
1518
[EndFunc, Reason,
1348
1519
test_server_sup:format_loc(
1349
1520
mod_loc(get_loc()))]},
1350
{failed,{Mod,end_per_testcase,Why}};
1352
comment(io_lib:format("<font color=\"red\">"
1353
"WARNING: ~w thrown!"
1354
"</font>\n",[EndFunc])),
1355
group_leader() ! {printout,12,
1356
"WARNING: ~w thrown!\n"
1360
test_server_sup:format_loc(
1361
mod_loc(get_loc()))]},
1362
{failed,{Mod,end_per_testcase,Other}}
1521
{failed,{Mod,end_per_testcase,Why}}
1366
case catch test_server_line:get_lines() of
1368
get(test_server_loc);
1370
get(test_server_loc);
1525
get(test_server_loc).
1375
1527
get_loc(Pid) ->
1376
{dictionary,Dict} = process_info(Pid, dictionary),
1377
lists:foreach(fun({Key,Val}) -> put(Key,Val) end,Dict),
1528
[{current_stacktrace,Stk0},{dictionary,Dict}] =
1529
process_info(Pid, [current_stacktrace,dictionary]),
1530
lists:foreach(fun({Key,Val}) -> put(Key, Val) end, Dict),
1531
Stk = [rewrite_loc_item(Loc) || Loc <- Stk0],
1532
case get(test_server_loc) of
1533
undefined -> put(test_server_loc, Stk);
1380
get_mf([{M,F,_}|_]) -> {M,F};
1381
get_mf([{M,F}|_]) -> {M,F};
1382
get_mf(_) -> {undefined,undefined}.
1538
%% find the latest known Suite:Testcase
1540
get_mf(MFs, {undefined,undefined}).
1542
get_mf([MF|MFs], _Found) when is_tuple(MF) ->
1543
ModFunc = {Mod,_} = case MF of
1547
case is_suite(Mod) of
1549
false -> get_mf(MFs, ModFunc)
1555
case lists:reverse(atom_to_list(Mod)) of
1556
"ETIUS" ++ _ -> true;
1384
1560
mod_loc(Loc) ->
1385
1561
%% handle diff line num versions
1793
2008
time_ms({Other,_N}) ->
1794
2009
format("=== ERROR: Invalid time specification: ~p. "
1795
2010
"Should be seconds, minutes, or hours.~n", [Other]),
1796
exit({invalid_time_spec,Other});
2011
exit({invalid_time_format,Other});
1797
2012
time_ms(Ms) when is_integer(Ms) -> Ms;
1798
time_ms(Other) -> exit({invalid_time_spec,Other}).
2013
time_ms(infinity) -> infinity;
2014
time_ms(Fun) when is_function(Fun) ->
2016
time_ms({M,F,A}=MFA) when is_atom(M), is_atom(F), is_list(A) ->
2018
time_ms(Other) -> exit({invalid_time_format,Other}).
2020
time_ms_apply(Func) ->
2021
time_ms_apply(Func, [5000,30000,60000,infinity]).
2023
time_ms_apply(Func, TOs) ->
2027
exit({self(),apply(M, F, A)});
2029
exit({self(),Fun()})
2033
Ref = monitor(process, Pid),
2034
time_ms_wait(Func, Pid, Ref, TOs).
2036
time_ms_wait(Func, Pid, Ref, [TO|TOs]) ->
2038
{'DOWN',Ref,process,Pid,{Pid,Result}} ->
2039
time_ms_check(Result);
2040
{'DOWN',Ref,process,Pid,Error} ->
2041
exit({timetrap_error,Error})
2044
format("=== WARNING: No return from timetrap function ~p~n", [Func]),
2045
time_ms_wait(Func, Pid, Ref, TOs)
2047
%% this clause will never execute if 'infinity' is in TOs list, that's ok!
2048
time_ms_wait(Func, Pid, Ref, []) ->
2051
exit({timetrap_error,{no_return_from_timetrap_function,Func}}).
2053
time_ms_check(MFA = {M,F,A}) when is_atom(M), is_atom(F), is_list(A) ->
2054
exit({invalid_time_format,MFA});
2055
time_ms_check(Fun) when is_function(Fun) ->
2056
exit({invalid_time_format,Fun});
2057
time_ms_check(Other) ->
1801
2060
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802
2061
%% timetrap_cancel(Handle) -> ok