diff options
Diffstat (limited to 'lib/common_test')
28 files changed, 818 insertions, 314 deletions
diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml index 1ee73b890b..c92566de37 100644 --- a/lib/common_test/doc/src/common_test_app.xml +++ b/lib/common_test/doc/src/common_test_app.xml @@ -296,7 +296,7 @@ </func> <func> - <name>Module:init_per_testcase(TestCase, Config) -> NewConfig | {skip,Reason}</name> + <name>Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason}</name> <fsummary>Test case initialization.</fsummary> <type> <v> TestCase = atom()</v> @@ -311,10 +311,12 @@ <p>This function is called before each test case. The <c>TestCase</c> argument is the name of the test case, and - <c>Config</c> is the configuration which can be modified - here. Whatever is returned from this function is given as - <c>Config</c> to the test case. If <c>{skip,Reason}</c> is returned, - the test case will be skipped and <c>Reason</c> printed + <c>Config</c> (list of key-value tuples) is the configuration + data that can be modified here. The <c>NewConfig</c> list returned + from this function is given as <c>Config</c> to the test case. + If <c>{fail,Reason}</c> is returned, the test case is + marked as failed without being executed. If <c>{skip,Reason}</c> is + returned, the test case will be skipped and <c>Reason</c> printed in the overview log for the suite.</p> </desc> </func> diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml index 723492d8f3..3f9fdb7121 100644 --- a/lib/common_test/doc/src/write_test_chapter.xml +++ b/lib/common_test/doc/src/write_test_chapter.xml @@ -167,12 +167,16 @@ returning <c>{fail,Reason}</c>, nor will it be able to save data with <c>{save_config,Data}</c>.</p> - <p>If <c>init_per_testcase</c> crashes, the test case itself is skipped + <p>If <c>init_per_testcase</c> crashes, the test case itself gets skipped automatically (so called <em>auto skipped</em>). If <c>init_per_testcase</c> - returns a <c>skip</c> tuple, also then will the test case be skipped (so - called <em>user skipped</em>). In either event, the <c>end_per_testcase</c> is - never called. + returns a tuple <c>{skip,Reason}</c>, also then the test case gets skipped + (so called <em>user skipped</em>). It is also possible, by returning a tuple + <c>{fail,Reason}</c> from <c>init_per_testcase</c>, to mark the test case + as failed without actually executing it. </p> + <note><p>If <c>init_per_testcase</c> crashes, or returns <c>{skip,Reason}</c> + or <c>{fail,Reason}</c>, the <c>end_per_testcase</c> function is not called. + </p></note> <p>If it is determined during execution of <c>end_per_testcase</c> that the status of a successful test case should be changed to failed, diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index dfec2b7a67..66da3ef742 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -861,6 +861,7 @@ remove_config(Callback, Config) -> %%% %%% @doc <p>Use this function to set a new timetrap for the running test case.</p> timetrap(Time) -> + test_server:timetrap_cancel(), test_server:timetrap(Time). %%%----------------------------------------------------------------- diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 3d4f674160..809616d8e3 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -493,9 +493,9 @@ end_tc(Mod,Func,TCPid,Result,Args,Return) -> case ct_hooks:end_tc( Mod, FuncSpec, Args, Result, Return) of '$ct_no_change' -> - {FinalResult = ok,Result}; - FinalResult -> - {FinalResult,FinalResult} + {ok,Result}; + FinalResult1 -> + {FinalResult1,FinalResult1} end, % send sync notification so that event handlers may print % in the log file before it gets closed @@ -636,7 +636,7 @@ error_notification(Mod,Func,_Args,{Error,Loc}) -> [{?MODULE,error_in_suite}] -> io:format(user, "Error in suite detected: ~s", [ErrStr]); - unknown -> + R when R == unknown; R == undefined -> io:format(user, "Error detected: ~s", [ErrStr]); %% if a function specified by all/0 does not exist, we @@ -737,7 +737,7 @@ get_suite(Mod, Group={conf,Props,_Init,TCs,_End}) -> %% (and only) test case so we can report Error properly [{?MODULE,error_in_suite,[[Error]]}]; [] -> - {error,{invalid_group_spec,Name}}; + []; ConfTests -> case lists:member(skipped, Props) of true -> @@ -767,23 +767,7 @@ get_suite(Mod, Name) -> find_groups(Mod, Name, TCs, GroupDefs) -> Found = find(Mod, Name, TCs, GroupDefs, [], GroupDefs, false), - Trimmed = trim(Found), - %% I cannot find a reason to why this function is called, - %% It deletes any group which is referenced in any other - %% group. i.e. - %% groups() -> - %% [{test, [], [testcase1]}, - %% {testcases, [], [{group, test}]}]. - %% Would be changed to - %% groups() -> - %% [{testcases, [], [testcase1]}]. - %% instead of what I believe is correct: - %% groups() -> - %% [{test, [], [testcase1]}, - %% {testcases, [], [testcase1]}]. - %% Have to double check with peppe - delete_subs(Trimmed, Trimmed), - Trimmed. + trim(Found). find(Mod, all, _TCs, [{Name,Props,Tests} | Gs], Known, Defs, _) when is_atom(Name), is_list(Props), is_list(Tests) -> @@ -1173,12 +1157,14 @@ error_in_suite(Config) -> %% if the group config functions are missing in the suite, %% use these instead ct_init_per_group(GroupName, Config) -> - ct_logs:log("WARNING", "init_per_group/2 for ~w missing in suite, using default.", + ct_logs:log("WARNING", "init_per_group/2 for ~w missing " + "in suite, using default.", [GroupName]), Config. ct_end_per_group(GroupName, _) -> - ct_logs:log("WARNING", "end_per_group/2 for ~w missing in suite, using default.", + ct_logs:log("WARNING", "end_per_group/2 for ~w missing " + "in suite, using default.", [GroupName]), ok. @@ -1187,6 +1173,13 @@ ct_end_per_group(GroupName, _) -> %%% @spec report(What,Data) -> ok report(What,Data) -> case What of + loginfo -> + %% logfiles and direcories have been created for a test and the + %% top level test index page needs to be refreshed + TestName = filename:basename(proplists:get_value(topdir, Data), ".logs"), + RunDir = proplists:get_value(rundir, Data), + ct_logs:make_all_suites_index({TestName,RunDir}), + ok; tests_start -> case ct_util:get_testdata(cover) of undefined -> diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl index 5eddefffce..984e04b90f 100644 --- a/lib/common_test/src/ct_hooks.erl +++ b/lib/common_test/src/ct_hooks.erl @@ -122,11 +122,11 @@ end_tc(_Mod, TC, Config, Result, _Return) -> call(fun call_generic/3, Result, [post_end_per_testcase, TC, Config], '$ct_no_change'). -on_tc_skip(How, {_Suite, Case, Reason}) -> - call(fun call_cleanup/3, {How, Reason}, [on_tc_skip, Case]). +on_tc_skip(How, {Suite, Case, Reason}) -> + call(fun call_cleanup/3, {How, Reason}, [on_tc_skip, Suite, Case]). -on_tc_fail(_How, {_Suite, Case, Reason}) -> - call(fun call_cleanup/3, Reason, [on_tc_fail, Case]). +on_tc_fail(_How, {Suite, Case, Reason}) -> + call(fun call_cleanup/3, Reason, [on_tc_fail, Suite, Case]). %% ------------------------------------------------------------------------- %% Internal Functions @@ -145,7 +145,7 @@ call_terminate({Mod, State}, _, _) -> catch_apply(Mod,terminate,[State], ok), {[],{Mod,State}}. -call_cleanup({Mod, State}, Reason, [Function | Args]) -> +call_cleanup({Mod, State}, Reason, [Function, _Suite | Args]) -> NewState = catch_apply(Mod,Function, Args ++ [Reason, State], State), {Reason, {Mod, NewState}}. @@ -229,6 +229,11 @@ scope([post_init_per_suite, SuiteName|_]) -> scope(init) -> none. +terminate_if_scope_ends(HookId, [on_tc_skip,_Suite,{end_per_group,Name}], + Hooks) -> + terminate_if_scope_ends(HookId, [post_end_per_group, Name], Hooks); +terminate_if_scope_ends(HookId, [on_tc_skip,Suite,end_per_suite], Hooks) -> + terminate_if_scope_ends(HookId, [post_end_per_suite, Suite], Hooks); terminate_if_scope_ends(HookId, [Function,Tag|T], Hooks) when T =/= [] -> terminate_if_scope_ends(HookId,[Function,Tag],Hooks); terminate_if_scope_ends(HookId, Function, Hooks) -> diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index f8ace73cbf..ba4adb8683 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -97,11 +97,11 @@ logdir_node_prefix() -> logdir_prefix()++"."++atom_to_list(node()). %%%----------------------------------------------------------------- -%%% @spec close(How) -> ok +%%% @spec close(Info) -> ok %%% %%% @doc Create index pages with test results and close the CT Log %%% (tool-internal use only). -close(How) -> +close(Info) -> make_last_run_index(), ct_event:notify(#event{name=stop_logging,node=node(),data=[]}), @@ -118,7 +118,7 @@ close(How) -> ok end, - if How == clean -> + if Info == clean -> case cleanup() of ok -> ok; @@ -427,8 +427,8 @@ logger(Parent,Mode) -> file:make_dir(Dir), ct_event:notify(#event{name=start_logging,node=node(), data=?abs(Dir)}), - make_all_suites_index(start), make_all_runs_index(start), + make_all_suites_index(start), case Mode of interactive -> interactive_link(); _ -> ok @@ -796,24 +796,29 @@ make_one_index_entry(SuiteName, LogDir, Label, All, Missing) -> {Succ,Fail,UserSkip,AutoSkip} -> NotBuilt = not_built(SuiteName, LogDir, All, Missing), NewResult = make_one_index_entry1(SuiteName, LogDir, Label, Succ, Fail, - UserSkip, AutoSkip, NotBuilt, All), + UserSkip, AutoSkip, NotBuilt, All, + normal), {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt}; error -> error end. make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip, - NotBuilt, All) -> + NotBuilt, All, Mode) -> LogFile = filename:join(Link, ?suitelog_name ++ ".html"), - CrashDumpName = SuiteName ++ "_erl_crash.dump", - CrashDumpLink = - case filelib:is_file(CrashDumpName) of - true -> - [" <A HREF=\"", CrashDumpName, - "\">(CrashDump)</A>"]; - false -> - "" - end, + CrashDumpLink = case Mode of + cached -> + ""; + normal -> + CrashDumpName = SuiteName ++ "_erl_crash.dump", + case filelib:is_file(CrashDumpName) of + true -> + [" <A HREF=\"", CrashDumpName, + "\">(CrashDump)</A>"]; + false -> + "" + end + end, {Lbl,Timestamp,Node,AllInfo} = case All of {true,OldRuns} -> @@ -975,9 +980,13 @@ index_header(Label, StartTime) -> "<th>Missing<br>Suites</th>\n" "\n"]]. + all_suites_index_header() -> {ok,Cwd} = file:get_cwd(), - LogDir = filename:basename(Cwd), + all_suites_index_header(Cwd). + +all_suites_index_header(IndexDir) -> + LogDir = filename:basename(IndexDir), AllRuns = "All test runs in \"" ++ LogDir ++ "\"", [header("Test Results") | ["<CENTER>\n", @@ -1414,15 +1423,72 @@ timestamp(Dir) -> [S,Min,H,D,M,Y] = [list_to_integer(N) || N <- lists:sublist(TsR,6)], format_time({{Y,M,D},{H,Min,S}}). -make_all_suites_index(When) -> +%% ----------------------------- NOTE -------------------------------------- +%% The top level index file is generated based on the file contents under +%% logdir. This takes place initially when the test run starts (When = start) +%% and an update takes place at the end of the test run, or when the user +%% requests an explicit refresh (When = refresh). +%% The index file needs to be updated also at the start of each individual +%% test (in order for the user to be able to track test progress by refreshing +%% the browser). Since it would be too expensive to generate a new file from +%% scratch every time (by reading the data from disk), a copy of the dir tree +%% is cached as a result of the first index file creation. This copy is then +%% used for all top level index page updates that occur during the test run. +%% This means that any changes to the dir tree under logdir during the test +%% run will not show until after the final refresh. +%% ------------------------------------------------------------------------- + +%% Creates the top level index file. When == start | refresh. +%% A copy of the dir tree under logdir is cached as a result. +make_all_suites_index(When) when is_atom(When) -> AbsIndexName = ?abs(?index_name), notify_and_lock_file(AbsIndexName), LogDirs = filelib:wildcard(logdir_prefix()++".*/*"++?logdir_ext), - Sorted = sort_logdirs(LogDirs,[]), - Result = make_all_suites_index1(When,Sorted), + Sorted = sort_logdirs(LogDirs, []), + Result = make_all_suites_index1(When, AbsIndexName, Sorted), notify_and_unlock_file(AbsIndexName), - Result. - + Result; + +%% This updates the top level index file using cached data from +%% the initial index file creation. +make_all_suites_index(NewTestData = {_TestName,DirName}) -> + %% AllLogDirs = [{TestName,Label,Missing,{LastLogDir,Summary},OldDirs}|...] + {AbsIndexName,LogDirData} = ct_util:get_testdata(test_index), + + CtRunDirPos = length(filename:split(AbsIndexName)), + CtRunDir = filename:join(lists:sublist(filename:split(DirName), + CtRunDirPos)), + + Label = case read_totals_file(filename:join(CtRunDir, ?totals_name)) of + {_,"-",_,_} -> "..."; + {_,Lbl,_,_} -> Lbl; + _ -> "..." + end, + notify_and_lock_file(AbsIndexName), + Result = + case catch make_all_suites_ix_cached(AbsIndexName, + NewTestData, + Label, + LogDirData) of + {'EXIT',Reason} -> + io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"), + io:format("~p~n", [Reason]), + {error,Reason}; + {error,Reason} -> + io:put_chars("FAILED while updating " ++ AbsIndexName ++ "\n"), + io:format("~p~n", [Reason]), + {error,Reason}; + ok -> + ok; + Err -> + io:format("Unknown internal error while updating ~s. " + "Please report.\n(Err: ~p, ID: 1)", + [AbsIndexName,Err]), + {error, Err} + end, + notify_and_unlock_file(AbsIndexName), + Result. + sort_logdirs([Dir|Dirs],Groups) -> TestName = filename:rootname(filename:basename(Dir)), case filelib:wildcard(filename:join(Dir,"run.*")) of @@ -1448,13 +1514,12 @@ sort_each_group([{Test,IxDirs}|Groups]) -> sort_each_group([]) -> []. -make_all_suites_index1(When,AllSuitesLogDirs) -> +make_all_suites_index1(When, AbsIndexName, AllLogDirs) -> IndexName = ?index_name, - AbsIndexName = ?abs(IndexName), if When == start -> ok; true -> io:put_chars("Updating " ++ AbsIndexName ++ "... ") end, - case catch make_all_suites_index2(IndexName,AllSuitesLogDirs) of + case catch make_all_suites_index2(IndexName, AllLogDirs) of {'EXIT', Reason} -> io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"), io:format("~p~n", [Reason]), @@ -1463,11 +1528,16 @@ make_all_suites_index1(When,AllSuitesLogDirs) -> io:put_chars("FAILED while updating " ++ AbsIndexName ++ "\n"), io:format("~p~n", [Reason]), {error, Reason}; - ok -> - if When == start -> ok; - true -> io:put_chars("done\n") - end, - ok; + {ok,CacheData} -> + case When of + start -> + ct_util:set_testdata_async({test_index,{AbsIndexName, + CacheData}}), + ok; + _ -> + io:put_chars("done\n"), + ok + end; Err -> io:format("Unknown internal error while updating ~s. " "Please report.\n(Err: ~p, ID: 1)", @@ -1475,56 +1545,124 @@ make_all_suites_index1(When,AllSuitesLogDirs) -> {error, Err} end. -make_all_suites_index2(IndexName,AllSuitesLogDirs) -> - {ok,Index0,_Totals} = make_all_suites_index3(AllSuitesLogDirs, - all_suites_index_header(), - 0, 0, 0, 0, 0, []), +make_all_suites_index2(IndexName, AllTestLogDirs) -> + {ok,Index0,_Totals,CacheData} = + make_all_suites_index3(AllTestLogDirs, + all_suites_index_header(), + 0, 0, 0, 0, 0, [], []), Index = [Index0|index_footer()], case force_write_file(IndexName, Index) of ok -> - ok; + {ok,CacheData}; {error, Reason} -> {error,{index_write_error, Reason}} end. -make_all_suites_index3([{SuiteName,[LastLogDir|OldDirs]}|Rest], +make_all_suites_index3([{TestName,[LastLogDir|OldDirs]}|Rest], Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, - Labels) -> + Labels, CacheData) -> [EntryDir|_] = filename:split(LastLogDir), Missing = - case file:read_file(filename:join(EntryDir,?missing_suites_info)) of + case file:read_file(filename:join(EntryDir, ?missing_suites_info)) of {ok,Bin} -> binary_to_term(Bin); _ -> [] end, {Label,Labels1} = case proplists:get_value(EntryDir, Labels) of undefined -> - case read_totals_file(filename:join(EntryDir,?totals_name)) of + case read_totals_file(filename:join(EntryDir, ?totals_name)) of {_,Lbl,_,_} -> {Lbl,[{EntryDir,Lbl}|Labels]}; _ -> {"-",[{EntryDir,"-"}|Labels]} end; Lbl -> {Lbl,Labels} end, - case make_one_index_entry(SuiteName, LastLogDir, Label, {true,OldDirs}, Missing) of + case make_one_index_entry(TestName, LastLogDir, Label, {true,OldDirs}, Missing) of {Result1,Succ,Fail,USkip,ASkip,NotBuilt} -> %% for backwards compatibility AutoSkip1 = case catch AutoSkip+ASkip of {'EXIT',_} -> undefined; Res -> Res end, + IxEntry = {TestName,Label,Missing, + {LastLogDir,{Succ,Fail,USkip,ASkip}},OldDirs}, make_all_suites_index3(Rest, [Result|Result1], TotSucc+Succ, TotFail+Fail, UserSkip+USkip, AutoSkip1, - TotNotBuilt+NotBuilt,Labels1); + TotNotBuilt+NotBuilt, Labels1, + [IxEntry|CacheData]); error -> + IxEntry = {TestName,Label,Missing,{LastLogDir,error},OldDirs}, make_all_suites_index3(Rest, Result, TotSucc, TotFail, - UserSkip, AutoSkip, TotNotBuilt,Labels1) + UserSkip, AutoSkip, TotNotBuilt, Labels1, + [IxEntry|CacheData]) end; make_all_suites_index3([], Result, TotSucc, TotFail, UserSkip, AutoSkip, - TotNotBuilt,_) -> + TotNotBuilt, _, CacheData) -> {ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,true)], - {TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}}. + {TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}, lists:reverse(CacheData)}. + + +make_all_suites_ix_cached(AbsIndexName, NewTestData, Label, AllTestLogDirs) -> + AllTestLogDirs1 = insert_new_test_data(NewTestData, Label, AllTestLogDirs), + IndexDir = filename:dirname(AbsIndexName), + Index0 = make_all_suites_ix_cached1(AllTestLogDirs1, + all_suites_index_header(IndexDir), + 0, 0, 0, 0, 0), + Index = [Index0|index_footer()], + case force_write_file(AbsIndexName, Index) of + ok -> + ok; + {error, Reason} -> + {error,{index_write_error, Reason}} + end. + +insert_new_test_data({NewTestName,NewTestDir}, NewLabel, AllTestLogDirs) -> + AllTestLogDirs1 = + case lists:keysearch(NewTestName, 1, AllTestLogDirs) of + {value,{_,_,_,{LastLogDir,_},OldDirs}} -> + [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0}}, + [LastLogDir|OldDirs]} | + lists:keydelete(NewTestName, 1, AllTestLogDirs)]; + false -> + [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0}},[]} | + AllTestLogDirs] + end, + lists:keysort(1, AllTestLogDirs1). + +make_all_suites_ix_cached1([{TestName,Label,Missing,LastLogDirData,OldDirs}|Rest], + Result, TotSucc, TotFail, UserSkip, AutoSkip, + TotNotBuilt) -> + case make_one_ix_entry_cached(TestName, LastLogDirData, + Label, {true,OldDirs}, Missing) of + {Result1,Succ,Fail,USkip,ASkip,NotBuilt} -> + %% for backwards compatibility + AutoSkip1 = case catch AutoSkip+ASkip of + {'EXIT',_} -> undefined; + Res -> Res + end, + make_all_suites_ix_cached1(Rest, [Result|Result1], TotSucc+Succ, + TotFail+Fail, UserSkip+USkip, AutoSkip1, + TotNotBuilt+NotBuilt); + error -> + make_all_suites_ix_cached1(Rest, Result, TotSucc, TotFail, + UserSkip, AutoSkip, TotNotBuilt) + end; +make_all_suites_ix_cached1([], Result, TotSucc, TotFail, UserSkip, AutoSkip, + TotNotBuilt) -> + [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, true)]. + +make_one_ix_entry_cached(TestName, {LogDir,Summary}, Label, All, Missing) -> + case Summary of + {Succ,Fail,UserSkip,AutoSkip} -> + NotBuilt = not_built(TestName, LogDir, All, Missing), + NewResult = make_one_index_entry1(TestName, LogDir, Label, + Succ, Fail, UserSkip, AutoSkip, + NotBuilt, All, cached), + {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt}; + error -> + error + end. %%----------------------------------------------------------------- %% Remove log files. diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 7bd7dc7d66..c01e97b358 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -262,15 +262,15 @@ run_or_refresh(StartOpts = #opts{logdir = LogDir}, Args) -> %% give the shell time to print version etc timer:sleep(500), io:nl(), - case catch ct_logs:make_all_suites_index(refresh) of - {'EXIT',ASReason} -> + case catch ct_logs:make_all_runs_index(refresh) of + {'EXIT',ARReason} -> file:set_cwd(Cwd), - {error,{all_suites_index,ASReason}}; + {error,{all_runs_index,ARReason}}; _ -> - case catch ct_logs:make_all_runs_index(refresh) of - {'EXIT',ARReason} -> + case catch ct_logs:make_all_suites_index(refresh) of + {'EXIT',ASReason} -> file:set_cwd(Cwd), - {error,{all_runs_index,ARReason}}; + {error,{all_suites_index,ASReason}}; _ -> file:set_cwd(Cwd), io:format("Logs in ~s refreshed!~n~n", [LogDir1]), @@ -1111,6 +1111,8 @@ run(TestDirs) -> install([]), reformat_result(catch do_run(tests(TestDirs), [])). +reformat_result({'EXIT',{user_error,Reason}}) -> + {error,Reason}; reformat_result({user_error,Reason}) -> {error,Reason}; reformat_result(Result) -> diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl index 115207beed..b3e345b4e5 100644 --- a/lib/common_test/src/ct_util.erl +++ b/lib/common_test/src/ct_util.erl @@ -37,7 +37,7 @@ read_suite_data/1, delete_suite_data/0, delete_suite_data/1, match_delete_suite_data/1, delete_testdata/0, delete_testdata/1, set_testdata/1, get_testdata/1, - update_testdata/2]). + set_testdata_async/1, update_testdata/2]). -export([override_silence_all_connections/0, override_silence_connections/1, get_overridden_silenced_connections/0, @@ -96,7 +96,8 @@ start(Mode,LogDir) -> Pid = spawn_link(fun() -> do_start(S,Mode,LogDir) end), receive {Pid,started} -> Pid; - {Pid,Error} -> exit(Error) + {Pid,Error} -> exit(Error); + {_Ref,{Pid,Error}} -> exit(Error) end; Pid -> case get_mode() of @@ -162,21 +163,19 @@ do_start(Parent,Mode,LogDir) -> end, {StartTime,TestLogDir} = ct_logs:init(Mode), - %% Initiate ct_hooks + ct_event:notify(#event{name=test_start, + node=node(), + data={StartTime, + lists:flatten(TestLogDir)}}), + %% Initialize ct_hooks case catch ct_hooks:init(Opts) of ok -> - ok; + Parent ! {self(),started}; {_,CTHReason} -> ct_logs:tc_print('Suite Callback',CTHReason,[]), - Parent ! {self(), CTHReason}, - self() ! {{stop,normal},{self(),make_ref()}} + self() ! {{stop,{self(),{user_error,CTHReason}}}, + {Parent,make_ref()}} end, - - ct_event:notify(#event{name=test_start, - node=node(), - data={StartTime, - lists:flatten(TestLogDir)}}), - Parent ! {self(),started}, loop(Mode,[],StartDir). create_table(TableName,KeyPos) -> @@ -232,6 +231,9 @@ update_testdata(Key, Fun) -> set_testdata(TestData) -> call({set_testdata, TestData}). +set_testdata_async(TestData) -> + cast({set_testdata, TestData}). + get_testdata(Key) -> call({get_testdata, Key}). @@ -317,7 +319,7 @@ loop(Mode,TestData,StartDir) -> {reset_cwd,From} -> return(From,file:set_cwd(StartDir)), loop(From,TestData,StartDir); - {{stop,How},From} -> + {{stop,Info},From} -> Time = calendar:local_time(), ct_event:sync_notify(#event{name=test_done, node=node(), @@ -330,11 +332,11 @@ loop(Mode,TestData,StartDir) -> ets:delete(?conn_table), ets:delete(?board_table), ets:delete(?suite_table), - ct_logs:close(How), + ct_logs:close(Info), ct_event:stop(), ct_config:stop(), file:set_cwd(StartDir), - return(From,ok); + return(From, Info); {Ref, _Msg} when is_reference(Ref) -> %% This clause is used when doing cast operations. loop(Mode,TestData,StartDir); @@ -537,16 +539,16 @@ reset_silent_connections() -> %%%----------------------------------------------------------------- -%%% @spec stop(How) -> ok +%%% @spec stop(Info) -> ok %%% %%% @doc Stop the ct_util_server and close all existing connections %%% (tool-internal use only). %%% %%% @see ct -stop(How) -> +stop(Info) -> case whereis(ct_util_server) of undefined -> ok; - _ -> call({stop,How}) + _ -> call({stop,Info}) end. %%%----------------------------------------------------------------- diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl index 2ee982d726..081f98e889 100644 --- a/lib/common_test/src/vts.erl +++ b/lib/common_test/src/vts.erl @@ -281,9 +281,7 @@ run_test1(State=#state{tests=Tests,current_log_dir=LogDir}) -> end, unlink(Self) end, - Pid = spawn_link(RunTest), - Total = receive {{test_info,start_info,{_,_,Cases}},From} -> @@ -480,7 +478,7 @@ create_testdir_entries([],_N) -> []. testdir_entry(Dir,Suite,Case,N) -> - NStr = integer_to_list(N), + NStr = vts_integer_to_list(N), tr([td(delete_button(NStr)), td(Dir), td(suite_select(Dir,Suite,NStr)), @@ -691,11 +689,11 @@ result_summary_frame1(State) -> result_summary_body(State) -> N = State#state.ok + State#state.fail + State#state.skip, [h2("Result Summary"), - p([b(integer_to_list(N))," cases executed (of ", - b(integer_to_list(State#state.total)),")"]), - p([green([b(integer_to_list(State#state.ok))," successful"]),br(), - red([b(integer_to_list(State#state.fail))," failed"]),br(), - orange([b(integer_to_list(State#state.skip))," skipped"])]), + p([b(vts_integer_to_list(N))," cases executed (of ", + b(vts_integer_to_list(State#state.total)),")"]), + p([green([b(vts_integer_to_list(State#state.ok))," successful"]),br(), + red([b(vts_integer_to_list(State#state.fail))," failed"]),br(), + orange([b(vts_integer_to_list(State#state.skip))," skipped"])]), executed_test_list(State)]. executed_test_list(#state{testruns=[]}) -> @@ -735,6 +733,14 @@ report1(tc_done,{_Suite,init_per_suite,_},State) -> State; report1(tc_done,{_Suite,end_per_suite,_},State) -> State; +report1(tc_done,{_Suite,init_per_group,_},State) -> + State; +report1(tc_done,{_Suite,end_per_group,_},State) -> + State; +report1(tc_done,{_Suite,ct_init_per_group,_},State) -> + State; +report1(tc_done,{_Suite,ct_end_per_group,_},State) -> + State; report1(tc_done,{_Suite,_Case,ok},State) -> State#state{ok=State#state.ok+1}; report1(tc_done,{_Suite,_Case,{failed,_Reason}},State) -> @@ -742,7 +748,9 @@ report1(tc_done,{_Suite,_Case,{failed,_Reason}},State) -> report1(tc_done,{_Suite,_Case,{skipped,_Reason}},State) -> State#state{skip=State#state.skip+1}; report1(tc_user_skip,{_Suite,_Case,_Reason},State) -> - State#state{skip=State#state.skip+1}. + State#state{skip=State#state.skip+1}; +report1(loginfo,_,State) -> + State. get_test_log(TestName,LogDir) -> [Log] = @@ -882,3 +890,7 @@ get_input_data(Input,Key)-> parse(Input) -> httpd:parse_query(Input). +vts_integer_to_list(X) when is_atom(X) -> + atom_to_list(X); +vts_integer_to_list(X) when is_integer(X) -> + integer_to_list(X). diff --git a/lib/common_test/test/ct_config_SUITE.erl b/lib/common_test/test/ct_config_SUITE.erl index b6b50f33e0..8ce75f582a 100644 --- a/lib/common_test/test/ct_config_SUITE.erl +++ b/lib/common_test/test/ct_config_SUITE.erl @@ -174,7 +174,8 @@ run_test(Name, Config, CTConfig, SuiteNames)-> TestEvents = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(Name, reformat_events(TestEvents, ?eh), - ?config(config_dir, Config)), + ?config(config_dir, Config), + Opts), ExpEvents = events_to_check(Name), ok = ct_test_support:verify_events(ExpEvents, TestEvents, Config). diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl index ad6cf1ba8f..6867e59b60 100644 --- a/lib/common_test/test/ct_error_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE.erl @@ -102,8 +102,9 @@ cfg_error(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(cfg_error, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(cfg_error), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -120,8 +121,9 @@ lib_error(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(lib_error, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(lib_error), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -138,8 +140,9 @@ no_compile(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(no_compile, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(no_compile), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -156,7 +159,8 @@ timetrap_end_conf(Config) when is_list(Config) -> ct_test_support:log_events(timetrap_end_conf, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(timetrap_end_conf), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -176,7 +180,8 @@ timetrap_normal(Config) when is_list(Config) -> ct_test_support:log_events(timetrap_normal, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(timetrap_normal), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -198,12 +203,31 @@ timetrap_extended(Config) when is_list(Config) -> ct_test_support:log_events(timetrap_extended, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(timetrap_extended), ok = ct_test_support:verify_events(TestEvents, Events, Config). %%%----------------------------------------------------------------- +%%% +timetrap_parallel(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + Join = fun(D, S) -> filename:join(D, "error/test/"++S) end, + Suite = Join(DataDir, "timetrap_3_SUITE"), + {Opts,ERPid} = setup([{suite,Suite}], Config), + ok = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(timetrap_parallel, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + + TestEvents = events_to_check(timetrap_parallel), + ok = ct_test_support:verify_events(TestEvents, Events, Config). + +%%%----------------------------------------------------------------- %%% HELP FUNCTIONS %%%----------------------------------------------------------------- @@ -236,7 +260,7 @@ test_events(cfg_error) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, - {?eh,start_info,{14,14,42}}, + {?eh,start_info,{14,14,43}}, {?eh,tc_start,{cfg_error_1_SUITE,init_per_suite}}, {?eh,tc_done, @@ -405,7 +429,6 @@ test_events(cfg_error) -> {cfg_error_8_SUITE,{init_per_group,g3,[]}, {failed,{error,{{badmatch,42}, [{cfg_error_8_SUITE,init_per_group,2}, - {cfg_error_8_SUITE,init_per_group,2}, {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, @@ -415,7 +438,6 @@ test_events(cfg_error) -> {failed,{cfg_error_8_SUITE,init_per_group, {'EXIT',{{badmatch,42}, [{cfg_error_8_SUITE,init_per_group,2}, - {cfg_error_8_SUITE,init_per_group,2}, {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, @@ -426,7 +448,6 @@ test_events(cfg_error) -> {failed,{cfg_error_8_SUITE,init_per_group, {'EXIT',{{badmatch,42}, [{cfg_error_8_SUITE,init_per_group,2}, - {cfg_error_8_SUITE,init_per_group,2}, {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, @@ -520,16 +541,19 @@ test_events(cfg_error) -> %%! end_tc failes the testcase {?eh,tc_done,{cfg_error_9_SUITE,tc6,ok}}, {?eh,test_stats,{9,2,{0,18}}}, + {?eh,tc_start,{cfg_error_9_SUITE,tc7}}, + {?eh,tc_done,{cfg_error_9_SUITE,tc7,{failed,{error,tc7_should_be_failed}}}}, + {ct_test_support_eh,test_stats,{9,3,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,tc11}}, {?eh,tc_done,{cfg_error_9_SUITE,tc11, {failed,{cfg_error_9_SUITE,end_per_testcase, {'EXIT',warning_should_be_printed}}}}}, - {?eh,test_stats,{10,2,{0,18}}}, + {?eh,test_stats,{10,3,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,tc12}}, {?eh,tc_done,{cfg_error_9_SUITE,tc12, {failed,{cfg_error_9_SUITE,end_per_testcase, {timetrap_timeout,2000}}}}}, - {?eh,test_stats,{11,2,{0,18}}}, + {?eh,test_stats,{11,3,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,tc13}}, {?eh,tc_done,{cfg_error_9_SUITE,tc13, {failed,{cfg_error_9_SUITE,end_per_testcase, @@ -539,11 +563,11 @@ test_events(cfg_error) -> {test_server,do_end_per_testcase,4}, {test_server,run_test_case_eval1,6}, {test_server,run_test_case_eval,8}]}}}}}}, - {?eh,test_stats,{12,2,{0,18}}}, + {?eh,test_stats,{12,3,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,tc14}}, {?eh,tc_done, {cfg_error_9_SUITE,tc14,{failed,{error,tc14_should_be_failed}}}}, - {?eh,test_stats,{12,3,{0,18}}}, + {?eh,test_stats,{12,4,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_9_SUITE,end_per_suite,ok}}, @@ -554,7 +578,7 @@ test_events(cfg_error) -> {?eh,tc_auto_skip,{cfg_error_10_SUITE,tc1, {failed,{cfg_error_10_SUITE,init_per_suite, {failed,fail_init_per_suite}}}}}, - {?eh,test_stats,{12,3,{0,19}}}, + {?eh,test_stats,{12,4,{0,19}}}, {?eh,tc_auto_skip,{cfg_error_10_SUITE,end_per_suite, {failed,{cfg_error_10_SUITE,init_per_suite, {failed,fail_init_per_suite}}}}}, @@ -563,40 +587,40 @@ test_events(cfg_error) -> {?eh,tc_start,{cfg_error_11_SUITE,tc1}}, {?eh,tc_done,{cfg_error_11_SUITE,tc1, {skipped,{config_name_already_in_use,[dummy0]}}}}, - {?eh,test_stats,{12,3,{1,19}}}, + {?eh,test_stats,{12,4,{1,19}}}, {?eh,tc_start,{cfg_error_11_SUITE,tc2}}, {?eh,tc_done,{cfg_error_11_SUITE,tc2,ok}}, - {?eh,test_stats,{13,3,{1,19}}}, + {?eh,test_stats,{13,4,{1,19}}}, {?eh,tc_start,{cfg_error_11_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_11_SUITE,end_per_suite,ok}}, {?eh,tc_start,{cfg_error_12_SUITE,tc1}}, {?eh,tc_done,{cfg_error_12_SUITE,tc1,{failed,{timetrap_timeout,500}}}}, - {?eh,test_stats,{13,4,{1,19}}}, + {?eh,test_stats,{13,5,{1,19}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc2}}, {?eh,tc_done,{cfg_error_12_SUITE,tc2,{failed, {cfg_error_12_SUITE,end_per_testcase, {timetrap_timeout,500}}}}}, - {?eh,test_stats,{14,4,{1,19}}}, + {?eh,test_stats,{14,5,{1,19}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc3}}, {?eh,tc_done,{cfg_error_12_SUITE,tc3,ok}}, - {?eh,test_stats,{15,4,{1,19}}}, + {?eh,test_stats,{15,5,{1,19}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc4}}, {?eh,tc_done,{cfg_error_12_SUITE,tc4,{failed, {cfg_error_12_SUITE,end_per_testcase, {timetrap_timeout,500}}}}}, - {?eh,test_stats,{16,4,{1,19}}}, + {?eh,test_stats,{16,5,{1,19}}}, {?eh,tc_start,{cfg_error_13_SUITE,init_per_suite}}, {?eh,tc_done,{cfg_error_13_SUITE,init_per_suite,ok}}, {?eh,tc_start,{cfg_error_13_SUITE,tc1}}, {?eh,tc_done,{cfg_error_13_SUITE,tc1,ok}}, - {?eh,test_stats,{17,4,{1,19}}}, + {?eh,test_stats,{17,5,{1,19}}}, {?eh,tc_start,{cfg_error_13_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_13_SUITE,end_per_suite,ok}}, {?eh,tc_start,{cfg_error_14_SUITE,init_per_suite}}, {?eh,tc_done,{cfg_error_14_SUITE,init_per_suite,ok}}, {?eh,tc_start,{cfg_error_14_SUITE,tc1}}, {?eh,tc_done,{cfg_error_14_SUITE,tc1,ok}}, - {?eh,test_stats,{18,4,{1,19}}}, + {?eh,test_stats,{18,5,{1,19}}}, {?eh,tc_start,{cfg_error_14_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_14_SUITE,end_per_suite, {comment, @@ -729,7 +753,7 @@ test_events(timetrap_normal) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, - {?eh,start_info,{1,1,3}}, + {?eh,start_info,{1,1,4}}, {?eh,tc_start,{timetrap_2_SUITE,init_per_suite}}, {?eh,tc_done,{timetrap_2_SUITE,init_per_suite,ok}}, {?eh,tc_start,{timetrap_2_SUITE,tc0}}, @@ -744,6 +768,9 @@ test_events(timetrap_normal) -> {?eh,tc_done, {timetrap_2_SUITE,tc2,{failed,{timetrap_timeout,500}}}}, {?eh,test_stats,{0,3,{0,0}}}, + {?eh,tc_start,{timetrap_2_SUITE,tc3}}, + {?eh,tc_done,{timetrap_2_SUITE,tc3,ok}}, + {?eh,test_stats,{1,3,{0,0}}}, {?eh,tc_start,{timetrap_2_SUITE,end_per_suite}}, {?eh,tc_done,{timetrap_2_SUITE,end_per_suite,ok}}, {?eh,test_done,{'DEF','STOP_TIME'}}, @@ -754,7 +781,7 @@ test_events(timetrap_extended) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, - {?eh,start_info,{1,1,3}}, + {?eh,start_info,{1,1,4}}, {?eh,tc_start,{timetrap_2_SUITE,init_per_suite}}, {?eh,tc_done,{timetrap_2_SUITE,init_per_suite,ok}}, {?eh,tc_start,{timetrap_2_SUITE,tc0}}, @@ -769,8 +796,52 @@ test_events(timetrap_extended) -> {?eh,tc_done, {timetrap_2_SUITE,tc2,{failed,{timetrap_timeout,1000}}}}, {?eh,test_stats,{0,3,{0,0}}}, + {?eh,tc_start,{timetrap_2_SUITE,tc3}}, + {?eh,tc_done,{timetrap_2_SUITE,tc3,ok}}, + {?eh,test_stats,{1,3,{0,0}}}, {?eh,tc_start,{timetrap_2_SUITE,end_per_suite}}, {?eh,tc_done,{timetrap_2_SUITE,end_per_suite,ok}}, {?eh,test_done,{'DEF','STOP_TIME'}}, {?eh,stop_logging,[]} - ]. + ]; + +test_events(timetrap_parallel) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,7}}, + {?eh,tc_done,{timetrap_3_SUITE,init_per_suite,ok}}, + {parallel, + [{?eh,tc_start, + {timetrap_3_SUITE,{init_per_group,g1,[parallel]}}}, + {?eh,tc_done, + {timetrap_3_SUITE,{init_per_group,g1,[parallel]},ok}}, + {?eh,tc_start,{timetrap_3_SUITE,tc0}}, + {?eh,tc_start,{timetrap_3_SUITE,tc1}}, + {?eh,tc_start,{timetrap_3_SUITE,tc2}}, + {?eh,tc_start,{timetrap_3_SUITE,tc3}}, + {?eh,tc_start,{timetrap_3_SUITE,tc4}}, + {?eh,tc_start,{timetrap_3_SUITE,tc6}}, + {?eh,tc_start,{timetrap_3_SUITE,tc7}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc1,{failed,{timetrap_timeout,500}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc2,{failed,{timetrap_timeout,1000}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc6,{failed,{timetrap_timeout,1000}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc7,{failed,{timetrap_timeout,1500}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc0,{failed,{timetrap_timeout,2000}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc4,{failed,{timetrap_timeout,2000}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc3,{failed,{timetrap_timeout,3000}}}}, + {?eh,test_stats,{0,7,{0,0}}}, + {?eh,tc_start, + {timetrap_3_SUITE,{end_per_group,g1,[parallel]}}}, + {?eh,tc_done, + {timetrap_3_SUITE,{end_per_group,g1,[parallel]},ok}}]}, + {?eh,tc_done,{timetrap_3_SUITE,end_per_suite,ok}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]. diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl index d73287ad62..40b7d2da47 100644 --- a/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl @@ -83,6 +83,8 @@ init_per_testcase(tc3, Config) -> Config; init_per_testcase(tc4, _) -> ok; +init_per_testcase(tc7, _) -> + {fail,tc7_should_be_failed}; init_per_testcase(_, Config) -> Config. @@ -136,7 +138,7 @@ groups() -> %% Reason = term() %%-------------------------------------------------------------------- all() -> - [tc1,tc2,tc3,tc4,tc5,tc6, + [tc1,tc2,tc3,tc4,tc5,tc6,tc7, tc11,tc12,tc13,tc14]. tc1(_) -> @@ -171,6 +173,11 @@ tc6(_) -> ct:comment("This one should succeed but then get failed by end_tc!"), fini. +tc7(_) -> + ct:comment("This one should get failed by iptc!"), + fini. + + tc11(_) -> fini. tc12(_) -> diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl index 99bb400137..7fcb631d06 100644 --- a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl @@ -77,8 +77,8 @@ init_per_testcase(tc1, Config) -> ct:timetrap({seconds,1}), Config; -init_per_testcase(tc3, Config) -> - ct:timetrap({seconds,1}), +init_per_testcase(tc2, Config) -> + ct:timetrap(250), Config; init_per_testcase(_TestCase, Config) -> @@ -90,7 +90,7 @@ init_per_testcase(_TestCase, Config) -> %% TestCase = atom() %% Config0 = Config1 = [tuple()] %%-------------------------------------------------------------------- -end_per_testcase(_, Config) -> +end_per_testcase(_, _Config) -> ok. %%-------------------------------------------------------------------- @@ -116,7 +116,7 @@ groups() -> %% Reason = term() %%-------------------------------------------------------------------- all() -> - [tc0,tc1,tc2]. + [tc0,tc1,tc2,tc3]. tc0(_) -> N = list_to_integer(ct:get_config(multiply)), @@ -131,8 +131,24 @@ tc1(_) -> ok. tc2(_) -> + ct:timetrap(500), N = list_to_integer(ct:get_config(multiply)), ct:comment(io_lib:format("TO after ~w sec", [0.5*N])), - ct:timetrap(500), ct:sleep(2000), ok. + +tc3() -> + [{timetrap,{seconds,2}}]. + +tc3(_) -> + T0 = now(), + ct:timetrap(infinity), + N = list_to_integer(ct:get_config(multiply)), + ct:comment(io_lib:format("Sleeping for ~w sec...", [4*N])), + ct:sleep(4000), + Diff = timer:now_diff(now(), T0), + if ((Diff < (N*4000000)) or (Diff > (N*4500000))) -> + exit(not_expected); + true -> + ok + end. diff --git a/lib/common_test/test/ct_event_handler_SUITE.erl b/lib/common_test/test/ct_event_handler_SUITE.erl index 5ef04c0e75..b534a7141d 100644 --- a/lib/common_test/test/ct_event_handler_SUITE.erl +++ b/lib/common_test/test/ct_event_handler_SUITE.erl @@ -102,8 +102,9 @@ start_stop(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(start_stop, - ct_test_support:reformat(Events, eh_A), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, eh_A), + ?config(priv_dir, Config), + Opts), TestEvents = [{eh_A,start_logging,{'DEF','RUNDIR'}}, @@ -148,8 +149,9 @@ results(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(results, - ct_test_support:reformat(Events, eh_A), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, eh_A), + ?config(priv_dir, Config), + Opts), TestEvents = [{eh_A,start_logging,{'DEF','RUNDIR'}}, diff --git a/lib/common_test/test/ct_groups_test_1_SUITE.erl b/lib/common_test/test/ct_groups_test_1_SUITE.erl index 7775d8a55d..e520a72227 100644 --- a/lib/common_test/test/ct_groups_test_1_SUITE.erl +++ b/lib/common_test/test/ct_groups_test_1_SUITE.erl @@ -89,8 +89,9 @@ groups_suite_1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_suite_1, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(groups_suite_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -109,8 +110,9 @@ groups_suite_2(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_suite_2, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(groups_suite_2), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -130,8 +132,9 @@ groups_suites_1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_suites_1, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(groups_suites_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -150,8 +153,9 @@ groups_dir_1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_dir_1, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(groups_dir_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -170,8 +174,9 @@ groups_dirs_1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_dirs_1, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(groups_dirs_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_groups_test_2_SUITE.erl b/lib/common_test/test/ct_groups_test_2_SUITE.erl index 2ae63f4f99..f33be8a9d4 100644 --- a/lib/common_test/test/ct_groups_test_2_SUITE.erl +++ b/lib/common_test/test/ct_groups_test_2_SUITE.erl @@ -59,7 +59,7 @@ end_per_testcase(TestCase, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [missing_conf, repeat_1]. + [missing_conf, repeat_1, empty_group]. groups() -> []. @@ -83,13 +83,14 @@ missing_conf(Config) when is_list(Config) -> Suite = filename:join(DataDir, "groups_1/missing_conf_SUITE"), - {Opts,ERPid} = setup({suite,Suite}, Config), + {Opts,ERPid} = setup([{suite,Suite}], Config), ok = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(missing_conf_SUITE, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(missing_conf), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -102,18 +103,41 @@ repeat_1(Config) when is_list(Config) -> Suite = filename:join(DataDir, "groups_1/repeat_1_SUITE"), - {Opts,ERPid} = setup({suite,Suite}, Config), + {Opts,ERPid} = setup([{suite,Suite}], Config), ok = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(repeat_1, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(repeat_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). %%%----------------------------------------------------------------- +%%% + +empty_group(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + + Suite = filename:join(DataDir, "groups_2/groups_22_SUITE"), + + {Opts,ERPid} = setup([{suite,Suite}, + {group,[test_group_8,test_group_9,test_group_10]}], + Config), + ok = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(empty_group, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + + TestEvents = events_to_check(empty_group), + ok = ct_test_support:verify_events(TestEvents, Events, Config). + +%%%----------------------------------------------------------------- %%% HELP FUNCTIONS %%%----------------------------------------------------------------- @@ -121,7 +145,7 @@ setup(Test, Config) -> Opts0 = ct_test_support:get_opts(Config), Level = ?config(trace_level, Config), EvHArgs = [{cbm,ct_test_support},{trace_level,Level}], - Opts = Opts0 ++ [Test,{event_handler,{?eh,EvHArgs}}], + Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}} | Test], ERPid = ct_test_support:start_event_receiver(Config), {Opts,ERPid}. @@ -256,4 +280,27 @@ test_events(repeat_1) -> {?eh,tc_done,{repeat_1_SUITE,end_per_suite,ok}}, {?eh,test_done,{'DEF','STOP_TIME'}}, {?eh,stop_logging,[]} + ]; + +test_events(empty_group) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,1}}, + {?eh,tc_start,{groups_22_SUITE,init_per_suite}}, + {?eh,tc_done,{groups_22_SUITE,init_per_suite,ok}}, + [{?eh,tc_start, + {groups_22_SUITE,{init_per_group,test_group_8,[]}}}, + {?eh,tc_done, + {groups_22_SUITE,{init_per_group,test_group_8,[]},ok}}, + {?eh,tc_start,{groups_22_SUITE,testcase_8}}, + {?eh,tc_done,{groups_22_SUITE,testcase_8,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_start, + {groups_22_SUITE,{end_per_group,test_group_8,[]}}}, + {?eh,tc_done, + {groups_22_SUITE,{end_per_group,test_group_8,[]},ok}}], + {?eh,tc_start,{groups_22_SUITE,end_per_suite}}, + {?eh,tc_done,{groups_22_SUITE,end_per_suite,init}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} ]. diff --git a/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl b/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl index cd517876df..14eb8769ad 100644 --- a/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl +++ b/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl @@ -31,27 +31,33 @@ suite() -> groups() -> [ - {test_group_1a, [shuffle], [testcase_1a,testcase_1b,testcase_1c]}, + {test_group_1a, [shuffle], [testcase_1a,testcase_1b,testcase_1c]}, - {test_group_1b, [parallel], [testcase_1a,testcase_1b]}, + {test_group_1b, [parallel], [testcase_1a,testcase_1b]}, - {test_group_2, [parallel], [testcase_2a, + {test_group_2, [parallel], [testcase_2a, - {test_group_3, [{repeat,1}], - [testcase_3a, testcase_3b]}, + {test_group_3, [{repeat,1}], + [testcase_3a, testcase_3b]}, - testcase_2b]}, + testcase_2b]}, - {test_group_4, [{test_group_5, [parallel], [testcase_5a, + {test_group_4, [{test_group_5, [parallel], [testcase_5a, - {group, test_group_6}, + {group, test_group_6}, - testcase_5b]}]}, + testcase_5b]}]}, - {test_group_6, [parallel], [{group, test_group_7}]}, + {test_group_6, [parallel], [{group, test_group_7}]}, - {test_group_7, [sequence], [testcase_7a,testcase_7b]} - ]. + {test_group_7, [sequence], [testcase_7a,testcase_7b]}, + + {test_group_8, [], [{group, test_group_9}, testcase_8]}, + + {test_group_9, [], []}, + + {test_group_10, [], [{group, test_group_9}]} + ]. all() -> [{group, test_group_1a}, @@ -60,7 +66,10 @@ all() -> testcase_2, {group, test_group_2}, testcase_3, - {group, test_group_4}]. + {group, test_group_4}, + {group, test_group_8}, + {group, test_group_9}, + {group, test_group_10}]. %% this func only for internal test purposes grs_and_tcs() -> @@ -68,7 +77,9 @@ grs_and_tcs() -> test_group_1a, test_group_1b, test_group_2, test_group_3, test_group_4, test_group_5, - test_group_6, test_group_7 + test_group_6, test_group_7, + test_group_8, test_group_9, + test_group_10 ], [ testcase_1a, testcase_1b, testcase_1c, @@ -78,7 +89,8 @@ grs_and_tcs() -> testcase_3a, testcase_3b, testcase_3, testcase_5a, testcase_5b, - testcase_7a, testcase_7b + testcase_7a, testcase_7b, + testcase_8 ]}. %%-------------------------------------------------------------------- @@ -107,7 +119,10 @@ init_per_group(Group, Config) -> {test_group_4,[{name,test_group_4}]} -> ok; {test_group_5,[{name,test_group_5},parallel]} -> "parallel"; {test_group_6,[{name,test_group_6},parallel]} -> "parallel"; - {test_group_7,[{name,test_group_7},sequence]} -> "sequence" + {test_group_7,[{name,test_group_7},sequence]} -> "sequence"; + {test_group_8,[{name,test_group_8}]} -> ok; + {test_group_9,[{name,test_group_9}]} -> ok; + {test_group_10,[{name,test_group_10}]} -> ok end, {Grs,_} = grs_and_tcs(), case lists:member(Group, Grs) of @@ -312,3 +327,7 @@ testcase_7b(Config) -> undefined = ?config(testcase_7a,Config), testcase_7b = ?config(testcase_7b,Config), ok. +testcase_8() -> + []. +testcase_8(_Config) -> + ok. diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl index 64f4e277ff..8574d7aabc 100644 --- a/lib/common_test/test/ct_hooks_SUITE.erl +++ b/lib/common_test/test/ct_hooks_SUITE.erl @@ -79,7 +79,8 @@ all(suite) -> scope_per_suite_cth, scope_per_group_cth, scope_suite_cth, scope_per_suite_state_cth, scope_per_group_state_cth, scope_suite_state_cth, - fail_pre_suite_cth, fail_post_suite_cth, skip_pre_suite_cth, + fail_pre_suite_cth, double_fail_pre_suite_cth, + fail_post_suite_cth, skip_pre_suite_cth, skip_post_suite_cth, recover_post_suite_cth, update_config_cth, state_update_cth, options_cth, same_id_cth, fail_n_skip_with_minimal_cth @@ -167,6 +168,11 @@ fail_pre_suite_cth(Config) when is_list(Config) -> do_test(fail_pre_suite_cth, "ct_cth_empty_SUITE.erl", [fail_pre_suite_cth],Config). +double_fail_pre_suite_cth(Config) when is_list(Config) -> + do_test(double_fail_pre_suite_cth, "{ct_scope_suite_crash_in_cth_SUITE.erl," + "ct_scope_suite_cth_SUITE.erl}", + [],Config). + fail_post_suite_cth(Config) when is_list(Config) -> do_test(fail_post_suite_cth, "ct_cth_empty_SUITE.erl", [fail_post_suite_cth],Config). @@ -225,8 +231,9 @@ do_test(Tag, SuiteWildCard, CTHs, Config, Res, EC) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(Tag, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(Tag, EC), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -259,9 +266,9 @@ events_to_check(Test, N) -> test_events(one_empty_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,cth,{empty_cth,id,[[]]}}, {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{empty_cth,pre_init_per_suite, [ct_cth_empty_SUITE,'$proplist',[]]}}, @@ -287,11 +294,11 @@ test_events(one_empty_cth) -> test_events(two_empty_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,cth,{'_',id,[[]]}}, {?eh,cth,{'_',init,['_',[]]}}, {?eh,cth,{'_',id,[[]]}}, {?eh,cth,{'_',init,['_',[]]}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, @@ -329,8 +336,8 @@ test_events(faulty_cth_no_init) -> test_events(faulty_cth_id_no_init) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',id,[[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',id,[[]]}}, {negative,{?eh,tc_start,'_'}, {?eh,test_done,{'DEF','STOP_TIME'}}}, {?eh,stop_logging,[]} @@ -339,9 +346,9 @@ test_events(faulty_cth_id_no_init) -> test_events(minimal_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {negative,{?eh,cth,{'_',id,['_',[]]}}, {?eh,cth,{'_',init,['_',[]]}}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,ok}}, @@ -357,11 +364,11 @@ test_events(minimal_cth) -> test_events(minimal_and_maximal_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {negative,{?eh,cth,{'_',id,['_',[]]}}, {?eh,cth,{'_',init,['_',[]]}}}, {?eh,cth,{'_',id,[[]]}}, {?eh,cth,{'_',init,['_',[]]}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, {?eh,cth,{'_',post_init_per_suite,[ct_cth_empty_SUITE,'$proplist','$proplist',[]]}}, @@ -387,8 +394,8 @@ test_events(faulty_cth_undef) -> {failed,FailReasonStr}}, [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite, {failed, {error,FailReasonStr}}}}, @@ -433,15 +440,15 @@ test_events(faulty_cth_exit_in_init_scope_suite) -> test_events(faulty_cth_exit_in_init) -> [{?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{empty_cth,init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{empty_cth,init,['_',[]]}}, {?eh,test_done,{'DEF','STOP_TIME'}}, {?eh,stop_logging,[]}]; test_events(faulty_cth_exit_in_id) -> [{?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{empty_cth,id,[[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{empty_cth,id,[[]]}}, {negative, {?eh,tc_start,'_'}, {?eh,test_done,{'DEF','STOP_TIME'}}}, {?eh,stop_logging,[]}]; @@ -609,9 +616,8 @@ test_events(scope_per_group_state_cth) -> test_events(fail_pre_suite_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, - + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, @@ -646,11 +652,28 @@ test_events(fail_pre_suite_cth) -> {?eh,stop_logging,[]} ]; -test_events(fail_post_suite_cth) -> +test_events(double_fail_pre_suite_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,tc_start,{'_',init_per_suite}}, {?eh,cth,{'_',init,['_',[]]}}, + {?eh,cth,{'_',pre_init_per_suite,['_','$proplist',[]]}}, + {?eh,cth,{'_',post_init_per_suite,['_','$proplist', + {fail,"Test failure"},[]]}}, + {?eh,cth, {empty_cth,terminate,[[]]}}, + + {?eh,tc_start,{'_',init_per_suite}}, + {?eh,cth,{'_',init,['_',[]]}}, + {?eh,cth, {empty_cth,terminate,[[]]}}, + {?eh,stop_logging,[]} + ]; + +test_events(fail_post_suite_cth) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, {?eh,cth,{'_',post_init_per_suite,[ct_cth_empty_SUITE,'$proplist','$proplist',[]]}}, @@ -676,8 +699,8 @@ test_events(fail_post_suite_cth) -> test_events(skip_pre_suite_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, {?eh,cth,{'_',post_init_per_suite,[ct_cth_empty_SUITE,'$proplist',{skip,"Test skip"},[]]}}, @@ -699,8 +722,8 @@ test_events(skip_pre_suite_cth) -> test_events(skip_post_suite_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, @@ -724,8 +747,8 @@ test_events(recover_post_suite_cth) -> Suite = ct_cth_fail_per_suite_SUITE, [ {?eh,start_logging,'_'}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{Suite,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[Suite,'$proplist','$proplist']}}, {?eh,cth,{'_',post_init_per_suite,[Suite,contains([tc_status]), @@ -753,8 +776,8 @@ test_events(recover_post_suite_cth) -> test_events(update_config_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_update_config_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite, @@ -864,9 +887,9 @@ test_events(update_config_cth) -> test_events(state_update_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,cth,{'_',init,['_',[]]}}, {?eh,cth,{'_',init,['_',[]]}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{'_',init_per_suite}}, {?eh,tc_done,{'_',end_per_suite,ok}}, @@ -902,8 +925,8 @@ test_events(state_update_cth) -> test_events(options_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{empty_cth,init,['_',[test]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{empty_cth,init,['_',[test]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{empty_cth,pre_init_per_suite, [ct_cth_empty_SUITE,'$proplist',[test]]}}, @@ -929,10 +952,10 @@ test_events(options_cth) -> test_events(same_id_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,cth,{'_',id,[[]]}}, {?eh,cth,{'_',init,[same_id_cth,[]]}}, {?eh,cth,{'_',id,[[]]}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, {negative, @@ -969,8 +992,8 @@ test_events(same_id_cth) -> test_events(fail_n_skip_with_minimal_cth) -> [{?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{'_',init_per_suite}}, {?eh,tc_done,{'_',end_per_suite,ok}}, diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_suite_crash_in_cth_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_suite_crash_in_cth_SUITE.erl new file mode 100644 index 0000000000..5aa6b0132d --- /dev/null +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_suite_crash_in_cth_SUITE.erl @@ -0,0 +1,50 @@ +%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ct_scope_suite_crash_in_cth_SUITE).
+
+-suite_defaults([{timetrap, {minutes, 10}}]).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("ct.hrl").
+
+%% Test server callback functions
+suite() ->
+ [{ct_hooks,[fail_pre_suite_cth]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+all() ->
+ [test_case].
+
+%% Test cases starts here.
+test_case(Config) when is_list(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_master_SUITE.erl b/lib/common_test/test/ct_master_SUITE.erl index e89b6f7de6..1471cc1e0c 100644 --- a/lib/common_test/test/ct_master_SUITE.erl +++ b/lib/common_test/test/ct_master_SUITE.erl @@ -119,8 +119,9 @@ ct_master_test(Config) when is_list(Config)-> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_suite_1, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + PrivDir, []), + find_events(NodeNames, [{tc_start,{master_SUITE,init_per_suite}}, {tc_start,{master_SUITE,first_testcase}}, {tc_start,{master_SUITE,second_testcase}}, @@ -174,7 +175,7 @@ make_spec(DataDir, FileName, NodeNames, Suites, Config)-> ct_test_support:write_testspec(N++Include++EH++C++S++LD++NS, FileName). -get_log_dir({win32,_},PrivDir, NodeName)-> +get_log_dir({win32,_}, _PrivDir, NodeName)-> case filelib:is_dir(?TEMP_DIR) of false -> file:make_dir(?TEMP_DIR); diff --git a/lib/common_test/test/ct_misc_1_SUITE.erl b/lib/common_test/test/ct_misc_1_SUITE.erl index a8bd2c2189..cb17af9ab5 100644 --- a/lib/common_test/test/ct_misc_1_SUITE.erl +++ b/lib/common_test/test/ct_misc_1_SUITE.erl @@ -111,7 +111,8 @@ beam_me_up(Config) when is_list(Config) -> ct_test_support:log_events(beam_me_up, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(beam_me_up, 1), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_repeat_1_SUITE.erl b/lib/common_test/test/ct_repeat_1_SUITE.erl index e674315526..4e842bd6d6 100644 --- a/lib/common_test/test/ct_repeat_1_SUITE.erl +++ b/lib/common_test/test/ct_repeat_1_SUITE.erl @@ -159,7 +159,8 @@ execute(TestCase, SuiteName, Group, Config) -> ct_test_support:log_events(TestCase, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(TestCase), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -561,7 +562,6 @@ test_events(repeat_cs_until_any_fail) -> {error, {{badmatch,2}, [{repeat_1_SUITE,tc_fail_1,1}, - {repeat_1_SUITE,tc_fail_1,1}, {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, diff --git a/lib/common_test/test/ct_sequence_1_SUITE.erl b/lib/common_test/test/ct_sequence_1_SUITE.erl index c7650b169c..5facf90656 100644 --- a/lib/common_test/test/ct_sequence_1_SUITE.erl +++ b/lib/common_test/test/ct_sequence_1_SUITE.erl @@ -132,7 +132,8 @@ execute(TestCase, SuiteName, Group, Config) -> ct_test_support:log_events(TestCase, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(TestCase), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_skip_SUITE.erl b/lib/common_test/test/ct_skip_SUITE.erl index 62c5f10b7c..4ba4479208 100644 --- a/lib/common_test/test/ct_skip_SUITE.erl +++ b/lib/common_test/test/ct_skip_SUITE.erl @@ -99,8 +99,9 @@ auto_skip(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(auto_skip, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(auto_skip), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -122,8 +123,9 @@ user_skip(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(user_skip, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(user_skip), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_smoke_test_SUITE.erl b/lib/common_test/test/ct_smoke_test_SUITE.erl index c3d49a5afa..49b38361e2 100644 --- a/lib/common_test/test/ct_smoke_test_SUITE.erl +++ b/lib/common_test/test/ct_smoke_test_SUITE.erl @@ -175,8 +175,9 @@ dir1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(dir1, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(dir1), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -204,8 +205,9 @@ dir2(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(dir2, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(dir2), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -234,8 +236,9 @@ dir1_2(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(dir1_2, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(dir1_2), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -264,8 +267,8 @@ suite11(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(suite11, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(suite11), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -293,8 +296,8 @@ suite21(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(suite21, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(suite21), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -324,8 +327,8 @@ suite11_21(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(suite11_21, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(suite11_21), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -355,8 +358,8 @@ tc111(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(tc111, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(tc111), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -385,8 +388,8 @@ tc211(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(tc211, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(tc211), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -416,8 +419,8 @@ tc111_112(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(tc111_112, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(tc111_112), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_test_server_if_1_SUITE.erl b/lib/common_test/test/ct_test_server_if_1_SUITE.erl index 9d3e6a9e59..4471915e69 100644 --- a/lib/common_test/test/ct_test_server_if_1_SUITE.erl +++ b/lib/common_test/test/ct_test_server_if_1_SUITE.erl @@ -98,8 +98,9 @@ ts_if_1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(ts_if_1, - reformat(Events, ?eh), - PrivDir), + reformat(Events, ?eh), + PrivDir, + Opts), TestEvents = events_to_check(ts_if_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl index b4f1a0e71f..601d5315ce 100644 --- a/lib/common_test/test/ct_test_support.erl +++ b/lib/common_test/test/ct_test_support.erl @@ -32,7 +32,8 @@ run/2, run/4, get_opts/1, wait_for_ct_stop/1]). -export([handle_event/2, start_event_receiver/1, get_events/2, - verify_events/3, reformat/2, log_events/3]). + verify_events/3, reformat/2, log_events/4, + join_abs_dirs/2]). -include_lib("kernel/include/file.hrl"). @@ -63,7 +64,6 @@ init_per_suite(Config, Level) -> start_slave(Config,Level) -> [_,Host] = string:tokens(atom_to_list(node()), "@"), - test_server:format(0, "Trying to start ~s~n", ["ct@"++Host]), case slave:start(Host, ct, []) of {error,Reason} -> @@ -72,18 +72,19 @@ start_slave(Config,Level) -> test_server:format(0, "Node ~p started~n", [CTNode]), IsCover = test_server:is_cover(), if IsCover -> - cover:start(CTNode); - true-> - ok + cover:start(CTNode); + true-> + ok end, - DataDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), + + DataDir = proplists:get_value(data_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), %% PrivDir as well as directory of Test Server suites %% have to be in code path on Common Test node. [_ | Parts] = lists:reverse(filename:split(DataDir)), TSDir = filename:join(lists:reverse(Parts)), - AddPathDirs = case ?config(path_dirs, Config) of + AddPathDirs = case proplists:get_value(path_dirs, Config) of undefined -> []; Ds -> Ds end, @@ -110,8 +111,8 @@ start_slave(Config,Level) -> %%% end_per_suite/1 end_per_suite(Config) -> - CTNode = ?config(ct_node, Config), - PrivDir = ?config(priv_dir, Config), + CTNode = proplists:get_value(ct_node, Config), + PrivDir = proplists:get_value(priv_dir, Config), true = rpc:call(CTNode, code, del_path, [filename:join(PrivDir,"")]), cover:stop(CTNode), slave:stop(CTNode), @@ -121,7 +122,9 @@ end_per_suite(Config) -> %%% init_per_testcase/2 init_per_testcase(_TestCase, Config) -> - {_,{_,LogDir}} = lists:keysearch(logdir, 1, get_opts(Config)), + Opts = get_opts(Config), + NetDir = proplists:get_value(net_dir, Opts), + LogDir = join_abs_dirs(NetDir, proplists:get_value(logdir, Opts)), case lists:keysearch(master, 1, Config) of false-> test_server:format("See Common Test logs here:\n\n" @@ -139,7 +142,7 @@ init_per_testcase(_TestCase, Config) -> %%% end_per_testcase/2 end_per_testcase(_TestCase, Config) -> - CTNode = ?config(ct_node, Config), + CTNode = proplists:get_value(ct_node, Config), case wait_for_ct_stop(CTNode) of %% Common test was not stopped to we restart node. false -> @@ -169,7 +172,7 @@ write_testspec(TestSpec, TSFile) -> %%% get_opts(Config) -> - PrivDir = ?config(priv_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), TempDir = case os:getenv("TMP") of false -> case os:getenv("TEMP") of @@ -195,20 +198,48 @@ get_opts(Config) -> _ -> TempDir end, - InitOpts = ?config(ct_opts, Config), - [{logdir,LogDir} | InitOpts]. + + %% Copy test variables to app environment on new node + CtTestVars = + case init:get_argument(ct_test_vars) of + {ok,[Vars]} -> + [begin {ok,Ts,_} = erl_scan:string(Str++"."), + {ok,Expr} = erl_parse:parse_term(Ts), + Expr + end || Str <- Vars]; + _ -> + [] + end, + %% test_server:format("Test variables added to Config: ~p\n\n", + %% [CtTestVars]), + InitOpts = + case proplists:get_value(ct_opts, Config) of + undefined -> []; + CtOpts -> CtOpts + end, + [{logdir,LogDir} | InitOpts ++ CtTestVars]. %%%----------------------------------------------------------------- %%% run(Opts, Config) -> - CTNode = ?config(ct_node, Config), - Level = ?config(trace_level, Config), + CTNode = proplists:get_value(ct_node, Config), + Level = proplists:get_value(trace_level, Config), %% use ct interface test_server:format(Level, "~n[RUN #1] Calling ct:run_test(~p) on ~p~n", [Opts, CTNode]), Result1 = rpc:call(CTNode, ct, run_test, [Opts]), + case rpc:call(CTNode, erlang, whereis, [ct_util_server]) of + undefined -> + ok; + _ -> + test_server:format(Level, + "ct_util_server not stopped on ~p yet, waiting 5 s...~n", + [CTNode]), + timer:sleep(5000), + undefined = rpc:call(CTNode, erlang, whereis, [ct_util_server]) + end, %% use run_test interface (simulated) test_server:format(Level, "Saving start opts on ~p: ~p~n", [CTNode,Opts]), rpc:call(CTNode, application, set_env, [common_test, run_test_start_opts, Opts]), @@ -224,8 +255,8 @@ run(Opts, Config) -> end. run(M, F, A, Config) -> - CTNode = ?config(ct_node, Config), - Level = ?config(trace_level, Config), + CTNode = proplists:get_value(ct_node, Config), + Level = proplists:get_value(trace_level, Config), test_server:format(Level, "~nCalling ~w:~w(~p) on ~p~n", [M, F, A, CTNode]), rpc:call(CTNode, M, F, A). @@ -261,11 +292,11 @@ handle_event(EH, Event) -> ok. start_event_receiver(Config) -> - CTNode = ?config(ct_node, Config), + CTNode = proplists:get_value(ct_node, Config), spawn_link(CTNode, fun() -> er() end). get_events(_, Config) -> - CTNode = ?config(ct_node, Config), + CTNode = proplists:get_value(ct_node, Config), {event_receiver,CTNode} ! {self(),get_events}, Events = receive {event_receiver,Evs} -> Evs end, {event_receiver,CTNode} ! stop, @@ -288,7 +319,7 @@ er_loop(Evs) -> end. verify_events(TEvs, Evs, Config) -> - Node = ?config(ct_node, Config), + Node = proplists:get_value(ct_node, Config), case catch verify_events1(TEvs, Evs, Node, Config) of {'EXIT',Reason} -> Reason; @@ -349,10 +380,15 @@ locate(TEvs, Node, Evs, Config) when is_list(TEvs) -> data={M,{init_per_group,GroupName,Props}}}}, {TEH,#event{name=tc_done, node=Node, - data={M,{init_per_group,GroupName,Props},R}}} | Evs1] -> - test_server:format("Found ~p!", [InitStart]), - test_server:format("Found ~p!", [InitDone]), - verify_events1(TEvs1, Evs1, Node, Config); + data={M,{init_per_group,GroupName,Props},Res}}} | Evs1] -> + case result_match(R, Res) of + false -> + nomatch; + true -> + test_server:format("Found ~p!", [InitStart]), + test_server:format("Found ~p!", [InitDone]), + verify_events1(TEvs1, Evs1, Node, Config) + end; _ -> nomatch end; @@ -384,9 +420,11 @@ locate({parallel,TEvs}, Node, Evs, Config) -> EvProps},EvR}}}) when TEH == EH, EvNode == Node, EvM == M, EvGroupName == GroupName, - EvProps == Props, - EvR == R -> - false; + EvProps == Props -> + case result_match(R, EvR) of + true -> false; + false -> true + end; ({EH,#event{name=stop_logging, node=EvNode,data=_}}) when EH == TEH, EvNode == Node -> @@ -466,7 +504,7 @@ locate({parallel,TEvs}, Node, Evs, Config) -> node=EvNode, data={Mod,Func,Result}}} <- Done, EH == TEH, EvNode == Node, Mod == M, - Func == F, Result == R] of + Func == F, result_match(R, Result)] of [TcDone|_] -> test_server:format("Found ~p!", [TEv]), {lists:delete(TcDone, Done),RemEvs,RemSize}; @@ -509,8 +547,13 @@ locate({parallel,TEvs}, Node, Evs, Config) -> data={Mod,{end_per_group, EvGName,EvProps},Res}}}) when EH == TEH, EvNode == Node, Mod == M, - EvGName == GroupName, EvProps == Props, Res == R -> - false; + EvGName == GroupName, EvProps == Props -> + case result_match(R, Res) of + true -> + false; + false -> + true + end; ({EH,#event{name=stop_logging, node=EvNode,data=_}}) when EH == TEH, EvNode == Node -> @@ -603,23 +646,29 @@ locate({shuffle,TEvs}, Node, Evs, Config) -> data={M,{init_per_group,GroupName,EvProps}}}}, {TEH,#event{name=tc_done, node=Node, - data={M,{init_per_group,GroupName,EvProps},R}}} | Es] -> - case proplists:get_value(shuffle, Props) of - '_' -> - case proplists:get_value(shuffle, EvProps) of - false -> - exit({no_shuffle_prop_found,{M,init_per_group, - GroupName,EvProps}}); + data={M,{init_per_group,GroupName,EvProps},Res}}} | Es] -> + case result_match(R, Res) of + true -> + case proplists:get_value(shuffle, Props) of + '_' -> + case proplists:get_value(shuffle, EvProps) of + false -> + exit({no_shuffle_prop_found, + {M,init_per_group, + GroupName,EvProps}}); + _ -> + PropsCmp = proplists:delete(shuffle, EvProps), + PropsCmp = proplists:delete(shuffle, Props) + end; _ -> - PropsCmp = proplists:delete(shuffle, EvProps), - PropsCmp = proplists:delete(shuffle, Props) - end; - _ -> - Props = EvProps - end, - test_server:format("Found ~p!", [InitStart]), - test_server:format("Found ~p!", [InitDone]), - {TEs,Es}; + Props = EvProps + end, + test_server:format("Found ~p!", [InitStart]), + test_server:format("Found ~p!", [InitDone]), + {TEs,Es}; + false -> + nomatch + end; _ -> nomatch end; @@ -670,7 +719,7 @@ locate({shuffle,TEvs}, Node, Evs, Config) -> node=EvNode, data={Mod,Func,Result}}} <- Done, EH == TEH, EvNode == Node, Mod == M, - Func == F, Result == R] of + Func == F, result_match(R, Result)] of [TcDone|_] -> test_server:format("Found ~p!", [TEv]), {lists:delete(TcDone, Done),RemEvs,RemSize}; @@ -726,8 +775,13 @@ locate({shuffle,TEvs}, Node, Evs, Config) -> data={Mod,{end_per_group, EvGName,_},Res}}}) when EH == TEH, EvNode == Node, Mod == M, - EvGName == GroupName, Res == R -> - false; + EvGName == GroupName -> + case result_match(R, Res) of + true -> + false; + false -> + true + end; ({EH,#event{name=stop_logging, node=EvNode,data=_}}) when EH == TEH, EvNode == Node -> @@ -864,25 +918,34 @@ locate({TEH,Name,{'DEF','STOP_TIME'}}, Node, [Ev|Evs], Config) -> nomatch end; -%% to match variable data as a result of a failed test case -locate({TEH,tc_done,{Mod,Func,{failed,{error,{Slogan,'_'}}}}}, Node, [Ev|Evs], Config) -> +%% to match variable data as a result of an aborted test case +locate({TEH,tc_done,{undefined,undefined,{testcase_aborted, + {abort_current_testcase,Func},'_'}}}, + Node, [Ev|Evs], Config) -> case Ev of - {TEH,#event{name=tc_done, node=Node, - data={Mod,Func,{failed,{error,{Slogan,_}}}}}} -> + {TEH,#event{name=tc_done, node=Node, + data={undefined,undefined, + {testcase_aborted,{abort_current_testcase,Func},_}}}} -> {Config,Evs}; _ -> nomatch end; -%% to match variable data as a result of an aborted test case -locate({TEH,tc_done,{undefined,undefined,{testcase_aborted, - {abort_current_testcase,Func},'_'}}}, - Node, [Ev|Evs], Config) -> +%% to match variable data as a result of a failed test case +locate({TEH,tc_done,{Mod,Func,R={SkipOrFail,{_ErrInd,ErrInfo}}}}, + Node, [Ev|Evs], Config) when ((SkipOrFail == skipped) or + (SkipOrFail == failed)) and + ((size(ErrInfo) == 2) or + (size(ErrInfo) == 3)) -> case Ev of {TEH,#event{name=tc_done, node=Node, - data={undefined,undefined, - {testcase_aborted,{abort_current_testcase,Func},_}}}} -> - {Config,Evs}; + data={Mod,Func,Result}}} -> + case result_match(R, Result) of + true -> + {Config,Evs}; + false -> + nomatch + end; _ -> nomatch end; @@ -931,14 +994,27 @@ match_data(Tuple1,Tuple2) when is_tuple(Tuple1),is_tuple(Tuple2) -> match_data([],[]) -> match. -log_events(TC, Events, PrivDir) -> - LogFile = filename:join(PrivDir, atom_to_list(TC)++".events"), +result_match({SkipOrFail,{ErrorInd,{Why,'_'}}}, + {SkipOrFail,{ErrorInd,{Why,_Stack}}}) -> + true; +result_match({SkipOrFail,{ErrorInd,{EMod,EFunc,{Why,'_'}}}}, + {SkipOrFail,{ErrorInd,{EMod,EFunc,{Why,_Stack}}}}) -> + true; +result_match(Result, Result) -> + true; +result_match(_, _) -> + false. + +log_events(TC, Events, EvLogDir, Opts) -> + LogFile = filename:join(EvLogDir, atom_to_list(TC)++".events"), {ok,Dev} = file:open(LogFile, [write]), io:format(Dev, "[~n", []), log_events1(Events, Dev, " "), file:close(Dev), + FullLogFile = join_abs_dirs(proplists:get_value(net_dir, Opts), + LogFile), io:format("Events written to logfile: <a href=\"file://~s\">~s</a>~n", - [LogFile,LogFile]), + [FullLogFile,FullLogFile]), io:format(user, "Events written to logfile: ~p~n", [LogFile]). log_events1(Evs, Dev, "") -> @@ -1024,13 +1100,25 @@ reformat([], _EH) -> %%%----------------------------------------------------------------- %%% MISC HELP FUNCTIONS +join_abs_dirs(undefined, Dir2) -> + Dir2; +join_abs_dirs(Dir1, Dir2) -> + case filename:pathtype(Dir2) of + relative -> + filename:join(Dir1, Dir2); + _ -> + [_Abs|Parts] = filename:split(Dir2), + filename:join(Dir1, filename:join(Parts)) + end. + create_tmp_logdir(Tmp) -> LogDir = filename:join(Tmp,"ct"), file:make_dir(LogDir), LogDir. delete_old_logs({win32,_}, Config) -> - case {?config(priv_dir, Config),?config(logdir, get_opts(Config))} of + case {proplists:get_value(priv_dir, Config), + proplists:get_value(logdir, get_opts(Config))} of {LogDir,LogDir} -> ignore; {_,LogDir} -> % using tmp for logs @@ -1042,7 +1130,8 @@ delete_old_logs(_, Config) -> false -> ignore; _ -> - catch delete_dirs(?config(logdir, get_opts(Config))) + catch delete_dirs(proplists:get_value(logdir, + get_opts(Config))) end. delete_dirs(LogDir) -> diff --git a/lib/common_test/test/ct_testspec_1_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE.erl index 616c2db869..b6dcf63fdf 100644 --- a/lib/common_test/test/ct_testspec_1_SUITE.erl +++ b/lib/common_test/test/ct_testspec_1_SUITE.erl @@ -612,6 +612,12 @@ setup_and_execute(TCName, TestSpec, Config) -> false -> [{spec,SpecFile},{label,TCName}] end, {Opts,ERPid} = setup(TestTerms, Config), + + FullSpecFile = ct_test_support:join_abs_dirs(?config(net_dir, Opts), + SpecFile), + io:format("~nTest spec created here~n~n<a href=\"file://~s\">~s</a>~n", + [FullSpecFile,FullSpecFile]), + ok = ct_test_support:run(Opts, Config), TestSpec1 = [{logdir,proplists:get_value(logdir,Opts)}, {label,proplists:get_value(label,TestTerms)} | TestSpec], @@ -620,7 +626,8 @@ setup_and_execute(TCName, TestSpec, Config) -> ct_test_support:log_events(TCName, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(TCName), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -631,8 +638,6 @@ create_spec_file(SpecDir, TCName, TestSpec) -> {ok,Dev} = file:open(FileName, [write]), [io:format(Dev, "~p.~n", [Term]) || Term <- TestSpec], file:close(Dev), - io:format("~nTest spec created here~n~n<a href=\"file://~s\">~s</a>~n", - [FileName,FileName]), FileName. setup(Test, Config) when is_tuple(Test) -> @@ -791,7 +796,9 @@ test_events(skip_group) -> {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_1a,[]},'_'}}, {?eh,tc_user_skip, {groups_11_SUITE,{group,test_group_1b},"SKIPPED!"}}, - {?eh,test_stats,{2,0,{1,0}}}, + {?eh,tc_user_skip, {groups_11_SUITE,{group,test_group_2},"SKIPPED!"}}, + %%! But not test_group_7 since it's a sub-group! + {?eh,test_stats,{2,0,{2,0}}}, {negative,{?eh,tc_user_skip,'_'},{?eh,stop_logging,'_'}} ]; @@ -1188,10 +1195,9 @@ test_events(sub_skipped_by_top) -> {?eh,tc_start,{groups_12_SUITE,init_per_suite}}, {?eh,tc_user_skip,{groups_12_SUITE,{group,test_group_4},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{group,test_group_4},"SKIPPED!"}}, - {negative, - {?eh,tc_user_skip,{groups_12_SUITE,{group,test_group_4},"SKIPPED!"}}, - {?eh,tc_done,{groups_12_SUITE,end_per_suite,'_'}}}, + {?eh,tc_done,{groups_12_SUITE,end_per_suite,'_'}}, {negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}} ]; |