aboutsummaryrefslogtreecommitdiffstats
path: root/lib/common_test/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/common_test/src')
-rw-r--r--lib/common_test/src/ct.erl1
-rw-r--r--lib/common_test/src/ct_framework.erl44
-rw-r--r--lib/common_test/src/ct_hooks.erl15
-rw-r--r--lib/common_test/src/ct_logs.erl224
-rw-r--r--lib/common_test/src/ct_run.erl14
-rw-r--r--lib/common_test/src/ct_util.erl38
-rw-r--r--lib/common_test/src/vts.erl30
7 files changed, 261 insertions, 105 deletions
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 38a2aa53ac..c016b9c66b 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -24,7 +24,7 @@
-module(ct_framework).
--export([init_tc/3, end_tc/4, get_suite/2, report/2, warn/1]).
+-export([init_tc/3, end_tc/3, end_tc/4, get_suite/2, report/2, warn/1]).
-export([error_notification/4]).
-export([overview_html_header/1]).
@@ -434,6 +434,9 @@ try_set_default(Name,Key,Info,Where) ->
%%%
%%% @doc Test server framework callback, called by the test_server
%%% when a test case is finished.
+end_tc(Mod, Fun, Args) ->
+ %% Have to keep end_tc/3 for backwards compatabilty issues
+ end_tc(Mod, Fun, Args, '$end_tc_dummy').
end_tc(?MODULE,error_in_suite,_, _) -> % bad start!
ok;
end_tc(Mod,Func,{TCPid,Result,[Args]}, Return) when is_pid(TCPid) ->
@@ -490,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
@@ -734,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 ->
@@ -764,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) ->
@@ -1170,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.
@@ -1184,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 ->
- ["&nbsp;<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 ->
+ ["&nbsp;<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).