aboutsummaryrefslogtreecommitdiffstats
path: root/lib/common_test/src/ct_util.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/common_test/src/ct_util.erl')
-rw-r--r--lib/common_test/src/ct_util.erl129
1 files changed, 77 insertions, 52 deletions
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index f5eb3a72f0..3c0fead5b2 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2017. 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/.
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
%%
-%% 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.
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
%%
%% %CopyrightEnd%
%%
@@ -37,7 +38,7 @@
save_suite_data_async/3, save_suite_data_async/2,
read_suite_data/1,
delete_suite_data/0, delete_suite_data/1, match_delete_suite_data/1,
- delete_testdata/0, delete_testdata/1,
+ delete_testdata/0, delete_testdata/1, match_delete_testdata/1,
set_testdata/1, get_testdata/1, get_testdata/2,
set_testdata_async/1, update_testdata/2, update_testdata/3,
set_verbosity/1, get_verbosity/1]).
@@ -130,14 +131,14 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
create_table(?suite_table,#suite_data.key),
create_table(?verbosity_table,1),
- [ets:insert(?verbosity_table,{Cat,Lvl}) || {Cat,Lvl} <- Verbosity],
+ _ = [ets:insert(?verbosity_table,{Cat,Lvl}) || {Cat,Lvl} <- Verbosity],
{ok,StartDir} = file:get_cwd(),
case file:set_cwd(LogDir) of
ok -> ok;
E -> exit(E)
end,
- DoExit = fun(Reason) -> file:set_cwd(StartDir), exit(Reason) end,
+ DoExit = fun(Reason) -> ok = file:set_cwd(StartDir), exit(Reason) end,
Opts = case read_opts() of
{ok,Opts1} ->
Opts1;
@@ -168,7 +169,7 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
end,
%% add user event handlers
- case lists:keysearch(event_handler,1,Opts) of
+ _ = case lists:keysearch(event_handler,1,Opts) of
{value,{_,Handlers}} ->
Add = fun({H,Args}) ->
case catch gen_event:add_handler(?CT_EVMGR_REF,H,Args) of
@@ -187,6 +188,8 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
ok
end,
+ ct_default_gl:start_link(group_leader()),
+
{StartTime,TestLogDir} = ct_logs:init(Mode, Verbosity),
ct_event:notify(#event{name=test_start,
@@ -194,24 +197,17 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
data={StartTime,
lists:flatten(TestLogDir)}}),
%% Initialize ct_hooks
- try ct_hooks:init(Opts) of
+ _ = try ct_hooks:init(Opts) of
ok ->
Parent ! {self(),started};
{fail,CTHReason} ->
- ErrorInfo = if is_atom(CTHReason) ->
- io_lib:format("{~p,~p}",
- [CTHReason,
- erlang:get_stacktrace()]);
- true ->
- CTHReason
- end,
- ct_logs:tc_print('Suite Callback',ErrorInfo,[]),
+ ct_logs:tc_print('Suite Callback',CTHReason,[]),
self() ! {{stop,{self(),{user_error,CTHReason}}},
{Parent,make_ref()}}
catch
_:CTHReason ->
ErrorInfo = if is_atom(CTHReason) ->
- io_lib:format("{~p,~p}",
+ io_lib:format("{~tp,~tp}",
[CTHReason,
erlang:get_stacktrace()]);
true ->
@@ -227,7 +223,8 @@ create_table(TableName,KeyPos) ->
create_table(TableName,set,KeyPos).
create_table(TableName,Type,KeyPos) ->
catch ets:delete(TableName),
- ets:new(TableName,[Type,named_table,public,{keypos,KeyPos}]).
+ _ = ets:new(TableName,[Type,named_table,public,{keypos,KeyPos}]),
+ ok.
read_opts() ->
case file:consult(ct_run:variables_file_name("./")) of
@@ -270,6 +267,9 @@ delete_testdata() ->
delete_testdata(Key) ->
call({delete_testdata, Key}).
+match_delete_testdata(KeyPat) ->
+ call({match_delete_testdata, KeyPat}).
+
update_testdata(Key, Fun) ->
update_testdata(Key, Fun, []).
@@ -361,7 +361,25 @@ loop(Mode,TestData,StartDir) ->
{{delete_testdata,Key},From} ->
TestData1 = lists:keydelete(Key,1,TestData),
return(From,ok),
- loop(From,TestData1,StartDir);
+ loop(From,TestData1,StartDir);
+ {{match_delete_testdata,{Key1,Key2}},From} ->
+ %% handles keys with 2 elements
+ TestData1 =
+ lists:filter(fun({Key,_}) when not is_tuple(Key) ->
+ true;
+ ({Key,_}) when tuple_size(Key) =/= 2 ->
+ true;
+ ({{_,KeyB},_}) when Key1 == '_' ->
+ KeyB =/= Key2;
+ ({{KeyA,_},_}) when Key2 == '_' ->
+ KeyA =/= Key1;
+ (_) when Key1 == '_' ; Key2 == '_' ->
+ false;
+ (_) ->
+ true
+ end, TestData),
+ return(From,ok),
+ loop(From,TestData1,StartDir);
{{set_testdata,New = {Key,_Val}},From} ->
TestData1 = lists:keydelete(Key,1,TestData),
return(From,ok),
@@ -437,6 +455,7 @@ loop(Mode,TestData,StartDir) ->
error:badarg -> []
end,
ct_hooks:terminate(Callbacks),
+
close_connections(ets:tab2list(?conn_table)),
ets:delete(?conn_table),
ets:delete(?board_table),
@@ -450,7 +469,8 @@ loop(Mode,TestData,StartDir) ->
ct_logs:close(Info, StartDir),
ct_event:stop(),
ct_config:stop(),
- file:set_cwd(StartDir),
+ ct_default_gl:stop(),
+ ok = file:set_cwd(StartDir),
return(From, Info);
{Ref, _Msg} when is_reference(Ref) ->
%% This clause is used when doing cast operations.
@@ -463,15 +483,17 @@ loop(Mode,TestData,StartDir) ->
{'EXIT',Pid,Reason} ->
case ets:lookup(?conn_table,Pid) of
[#conn{address=A,callback=CB}] ->
+ ErrorStr = io_lib:format("~tp", [Reason]),
+ ErrorHtml = ct_logs:escape_chars(ErrorStr),
%% A connection crashed - remove the connection but don't die
ct_logs:tc_log_async(ct_error_notify,
?MAX_IMPORTANCE,
"CT Error Notification",
"Connection process died: "
- "Pid: ~w, Address: ~p, "
+ "Pid: ~w, Address: ~tp, "
"Callback: ~w\n"
- "Reason: ~p\n\n",
- [Pid,A,CB,Reason]),
+ "Reason: ~ts\n\n",
+ [Pid,A,CB,ErrorHtml]),
catch CB:close(Pid),
%% in case CB:close failed to do this:
unregister_connection(Pid),
@@ -479,8 +501,8 @@ loop(Mode,TestData,StartDir) ->
_ ->
%% Let process crash in case of error, this shouldn't happen!
io:format("\n\nct_util_server got EXIT "
- "from ~w: ~p\n\n", [Pid,Reason]),
- file:set_cwd(StartDir),
+ "from ~w: ~tp\n\n", [Pid,Reason]),
+ ok = file:set_cwd(StartDir),
exit(Reason)
end
end.
@@ -773,25 +795,25 @@ parse_table(Data) ->
{Heading,Lines}.
get_headings(["|" ++ Headings | Rest]) ->
- {remove_space(string:tokens(Headings, "|"),[]), Rest};
+ {remove_space(string:lexemes(Headings, "|"),[]), Rest};
get_headings([_ | Rest]) ->
get_headings(Rest);
get_headings([]) ->
{{},[]}.
parse_row(["|" ++ _ = Row | T], Rows, NumCols) when NumCols > 1 ->
- case string:tokens(Row, "|") of
+ case string:lexemes(Row, "|") of
Values when length(Values) =:= NumCols ->
parse_row(T,[remove_space(Values,[])|Rows], NumCols);
Values when length(Values) < NumCols ->
parse_row([Row ++"\n"++ hd(T) | tl(T)], Rows, NumCols)
end;
-parse_row(["|" ++ _ = Row | T], Rows, 1 = NumCols) ->
- case string:rchr(Row, $|) of
- 1 ->
+parse_row(["|" ++ X = Row | T], Rows, 1 = NumCols) ->
+ case string:find(X, [$|]) of
+ nomatch ->
parse_row([Row ++"\n"++hd(T) | tl(T)], Rows, NumCols);
_Else ->
- parse_row(T, [remove_space(string:tokens(Row,"|"),[])|Rows],
+ parse_row(T, [remove_space(string:lexemes(Row,"|"),[])|Rows],
NumCols)
end;
parse_row([_Skip | T], Rows, NumCols) ->
@@ -800,7 +822,7 @@ parse_row([], Rows, _NumCols) ->
lists:reverse(Rows).
remove_space([Str|Rest],Acc) ->
- remove_space(Rest,[string:strip(string:strip(Str),both,$')|Acc]);
+ remove_space(Rest,[string:trim(string:trim(Str,both,[$\s]),both,[$'])|Acc]);
remove_space([],Acc) ->
list_to_tuple(lists:reverse(Acc)).
@@ -810,7 +832,7 @@ remove_space([],Acc) ->
%%%
%%% @doc
is_test_dir(Dir) ->
- lists:last(string:tokens(filename:basename(Dir), "_")) == "test".
+ lists:last(string:lexemes(filename:basename(Dir), "_")) == "test".
%%%-----------------------------------------------------------------
%%% @spec
@@ -900,7 +922,8 @@ warn_duplicates(Suites) ->
[] ->
ok;
_ ->
- io:format(user,"~nWARNING! Deprecated function: ~w:sequences/0.~n"
+ io:format(?def_gl,
+ "~nWARNING! Deprecated function: ~w:sequences/0.~n"
" Use group with sequence property instead.~n",[Mod])
end
end,
@@ -954,12 +977,12 @@ get_profile_data(Profile, Key, StartDir) ->
end,
case Result of
{error,enoent} when Profile /= default ->
- io:format(user, "~nERROR! Missing profile file ~p~n", [File]),
+ io:format(?def_gl, "~nERROR! Missing profile file ~tp~n", [File]),
undefined;
{error,enoent} when Profile == default ->
undefined;
{error,Reason} ->
- io:format(user,"~nERROR! Error in profile file ~p: ~p~n",
+ io:format(?def_gl,"~nERROR! Error in profile file ~tp: ~tp~n",
[WhichFile,Reason]),
undefined;
{ok,Data} ->
@@ -969,8 +992,8 @@ get_profile_data(Profile, Key, StartDir) ->
_ when is_list(Data) ->
Data;
_ ->
- io:format(user,
- "~nERROR! Invalid profile data in ~p~n",
+ io:format(?def_gl,
+ "~nERROR! Invalid profile data in ~tp~n",
[WhichFile]),
[]
end,
@@ -1010,10 +1033,12 @@ call(Msg, Timeout) ->
end.
return({To,Ref},Result) ->
- To ! {Ref, Result}.
+ To ! {Ref, Result},
+ ok.
cast(Msg) ->
- ct_util_server ! {Msg, {ct_util_server, make_ref()}}.
+ ct_util_server ! {Msg, {ct_util_server, make_ref()}},
+ ok.
seconds(T) ->
test_server:seconds(T).
@@ -1049,15 +1074,15 @@ abs_name2([],Acc) ->
open_url(iexplore, Args, URL) ->
{ok,R} = win32reg:open([read]),
ok = win32reg:change_key(R,"applications\\iexplore.exe\\shell\\open\\command"),
- case win32reg:values(R) of
+ _ = case win32reg:values(R) of
{ok, Paths} ->
Path = proplists:get_value(default, Paths),
- [Cmd | _] = string:tokens(Path, "%"),
+ [Cmd | _] = string:lexemes(Path, "%"),
Cmd1 = Cmd ++ " " ++ Args ++ " " ++ URL,
- io:format(user, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd1]),
+ io:format(?def_gl, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd1]),
open_port({spawn,Cmd1}, []);
_ ->
- io:format("~nNo path to iexplore.exe~n",[])
+ io:format(?def_gl, "~nNo path to iexplore.exe~n",[])
end,
win32reg:close(R),
ok;
@@ -1067,6 +1092,6 @@ open_url(Prog, Args, URL) ->
is_list(Prog) -> Prog
end,
Cmd = ProgStr ++ " " ++ Args ++ " " ++ URL,
- io:format(user, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd]),
+ io:format(?def_gl, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd]),
open_port({spawn,Cmd},[]),
ok.