aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/common_test/src/ct_config.erl33
-rw-r--r--lib/common_test/src/ct_ftp.erl6
-rw-r--r--lib/common_test/src/ct_gen_conn.erl37
-rw-r--r--lib/common_test/src/ct_netconfc.erl8
-rw-r--r--lib/common_test/src/ct_ssh.erl6
-rw-r--r--lib/common_test/src/ct_telnet.erl17
-rw-r--r--lib/common_test/src/ct_util.erl132
-rw-r--r--lib/common_test/test/Makefile1
-rw-r--r--lib/common_test/test/ct_gen_conn_SUITE.erl135
-rw-r--r--lib/common_test/test/ct_gen_conn_SUITE_data/conn.conf8
-rw-r--r--lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl240
-rw-r--r--lib/common_test/test/ct_gen_conn_SUITE_data/proto.erl196
-rw-r--r--lib/crypto/doc/src/crypto.xml36
-rw-r--r--lib/crypto/test/crypto_SUITE.erl128
-rw-r--r--lib/stdlib/test/ets_SUITE.erl19
-rw-r--r--lib/test_server/src/test_server.erl13
16 files changed, 857 insertions, 158 deletions
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index 9bb9817001..5c80a299f8 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -46,7 +46,7 @@
decrypt_config_file/2, decrypt_config_file/3,
get_crypt_key_from_file/0, get_crypt_key_from_file/1]).
--export([get_ref_from_name/1, get_name_from_ref/1, get_key_from_name/1]).
+-export([get_key_from_name/1]).
-export([check_config_files/1, add_default_callback/1, prepare_config_list/1]).
@@ -56,7 +56,7 @@
-define(cryptfile, ".ct_config.crypt").
--record(ct_conf,{key,value,handler,config,ref,name='_UNDEF',default=false}).
+-record(ct_conf,{key,value,handler,config,name='_UNDEF',default=false}).
start(Mode) ->
case whereis(ct_config_server) of
@@ -275,7 +275,6 @@ store_config(Config, Callback, File) when is_list(Config) ->
value=Val,
handler=Callback,
config=File,
- ref=ct_util:ct_make_ref(),
default=false}) ||
{Key,Val} <- Config].
@@ -296,13 +295,11 @@ rewrite_config(Config, Callback, File) ->
#ct_conf{key=Key,
value=Value,
handler=Callback,
- config=File,
- ref=ct_util:ct_make_ref()});
+ config=File});
RowsToUpdate ->
Inserter = fun(Row) ->
ets:insert(?attr_table,
- Row#ct_conf{value=Value,
- ref=ct_util:ct_make_ref()})
+ Row#ct_conf{value=Value})
end,
lists:foreach(Inserter, RowsToUpdate)
end
@@ -314,7 +311,7 @@ set_config(Config,Default) ->
set_config(Name,Config,Default) ->
[ets:insert(?attr_table,
- #ct_conf{key=Key,value=Val,ref=ct_util:ct_make_ref(),
+ #ct_conf{key=Key,value=Val,
name=Name,default=Default}) ||
{Key,Val} <- Config].
@@ -559,26 +556,6 @@ encrypt_config_file(SrcFileName, EncryptFileName) ->
encrypt_config_file(SrcFileName, EncryptFileName, {key,Key})
end.
-get_ref_from_name(Name) ->
- case ets:select(?attr_table,[{#ct_conf{name=Name,ref='$1',_='_'},
- [],
- ['$1']}]) of
- [Ref] ->
- {ok,Ref};
- _ ->
- {error,{no_such_name,Name}}
- end.
-
-get_name_from_ref(Ref) ->
- case ets:select(?attr_table,[{#ct_conf{name='$1',ref=Ref,_='_'},
- [],
- ['$1']}]) of
- [Name] ->
- {ok,Name};
- _ ->
- {error,{no_such_ref,Ref}}
- end.
-
get_key_from_name(Name) ->
case ets:select(?attr_table,[{#ct_conf{name=Name,key='$1',_='_'},
[],
diff --git a/lib/common_test/src/ct_ftp.erl b/lib/common_test/src/ct_ftp.erl
index 8790393b36..b91a521bd4 100644
--- a/lib/common_test/src/ct_ftp.erl
+++ b/lib/common_test/src/ct_ftp.erl
@@ -348,10 +348,10 @@ terminate(FtpPid,State) ->
get_handle(Pid) when is_pid(Pid) ->
{ok,Pid};
get_handle(Name) ->
- case ct_util:get_connections(Name,?MODULE) of
- {ok,[{Pid,_}|_]} ->
+ case ct_util:get_connection(Name,?MODULE) of
+ {ok,{Pid,_}} ->
{ok,Pid};
- {ok,[]} ->
+ {error,no_registered_connection} ->
open(Name);
Error ->
Error
diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl
index 2d4b1d1f52..a5b736136f 100644
--- a/lib/common_test/src/ct_gen_conn.erl
+++ b/lib/common_test/src/ct_gen_conn.erl
@@ -26,7 +26,7 @@
-compile(export_all).
--export([start/4, stop/1]).
+-export([start/4, stop/1, get_conn_pid/1]).
-export([call/2, call/3, return/2, do_within_time/2]).
-ifdef(debug).
@@ -120,8 +120,16 @@ start(Name,Address,InitData,CallbackMod) ->
%%% Handle = handle()
%%%
%%% @doc Close the connection and stop the process managing it.
-stop(Pid) ->
- call(Pid,stop,5000).
+stop(Handle) ->
+ call(Handle,stop,5000).
+
+%%%-----------------------------------------------------------------
+%%% @spec get_conn_pid(Handle) -> ok
+%%% Handle = handle()
+%%%
+%%% @doc Return the connection pid associated with Handle
+get_conn_pid(Handle) ->
+ call(Handle,get_conn_pid).
%%%-----------------------------------------------------------------
%%% @spec log(Heading,Format,Args) -> ok
@@ -222,7 +230,8 @@ do_start(Opts) ->
receive
{connected,Pid} ->
erlang:demonitor(MRef, [flush]),
- ct_util:register_connection(Opts#gen_opts.name, Opts#gen_opts.address,
+ ct_util:register_connection(Opts#gen_opts.name,
+ Opts#gen_opts.address,
Opts#gen_opts.callback, Pid),
{ok,Pid};
{Error,Pid} ->
@@ -315,10 +324,12 @@ loop(Opts) ->
{ok, NewPid, NewState} ->
link(NewPid),
put(conn_pid,NewPid),
- loop(Opts#gen_opts{conn_pid=NewPid,cb_state=NewState});
+ loop(Opts#gen_opts{conn_pid=NewPid,
+ cb_state=NewState});
Error ->
ct_util:unregister_connection(self()),
- log("Reconnect failed. Giving up!","Reason: ~p\n",
+ log("Reconnect failed. Giving up!",
+ "Reason: ~p\n",
[Error])
end;
false ->
@@ -338,7 +349,8 @@ loop(Opts) ->
Opts#gen_opts.cb_state),
return(From,ok),
ok;
- {{retry,{Error,_Name,CPid,_Msg}}, From} when CPid == Opts#gen_opts.conn_pid ->
+ {{retry,{Error,_Name,CPid,_Msg}}, From} when
+ CPid == Opts#gen_opts.conn_pid ->
%% only retry if failure is because of a reconnection
Return = case Error of
{error,_} -> Error;
@@ -347,12 +359,16 @@ loop(Opts) ->
return(From, Return),
loop(Opts);
{{retry,{_Error,_Name,_CPid,Msg}}, From} ->
- log("Rerunning command","Connection reestablished. Rerunning command...",[]),
+ log("Rerunning command","Connection reestablished. "
+ "Rerunning command...",[]),
{Return,NewState} =
(Opts#gen_opts.callback):handle_msg(Msg,Opts#gen_opts.cb_state),
return(From, Return),
loop(Opts#gen_opts{cb_state=NewState});
- {Msg,From={Pid,_Ref}} when is_pid(Pid), Opts#gen_opts.old==true ->
+ {get_conn_pid, From} ->
+ return(From, Opts#gen_opts.conn_pid),
+ loop(Opts);
+ {Msg, From={Pid,_Ref}} when is_pid(Pid), Opts#gen_opts.old==true ->
{Return,NewState} =
(Opts#gen_opts.callback):handle_msg(Msg,Opts#gen_opts.cb_state),
return(From, Return),
@@ -372,7 +388,8 @@ loop(Opts) ->
return(From,Reply)
end;
Msg when Opts#gen_opts.forward==true ->
- case (Opts#gen_opts.callback):handle_msg(Msg,Opts#gen_opts.cb_state) of
+ case (Opts#gen_opts.callback):handle_msg(Msg,
+ Opts#gen_opts.cb_state) of
{noreply,NewState} ->
loop(Opts#gen_opts{cb_state=NewState});
{stop,NewState} ->
diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl
index 28586c310e..e094ee877a 100644
--- a/lib/common_test/src/ct_netconfc.erl
+++ b/lib/common_test/src/ct_netconfc.erl
@@ -1164,13 +1164,11 @@ call(Client, Msg, Timeout, WaitStop) ->
get_handle(Client) when is_pid(Client) ->
{ok,Client};
get_handle(Client) ->
- case ct_util:get_connections(Client, ?MODULE) of
- {ok,[{Pid,_}]} ->
+ case ct_util:get_connection(Client, ?MODULE) of
+ {ok,{Pid,_}} ->
{ok,Pid};
- {ok,[]} ->
+ {error,no_registered_connection} ->
{error,{no_connection_found,Client}};
- {ok,Conns} ->
- {error,{multiple_connections_found,Client,Conns}};
Error ->
Error
end.
diff --git a/lib/common_test/src/ct_ssh.erl b/lib/common_test/src/ct_ssh.erl
index c6ea27b10e..1adc79d358 100644
--- a/lib/common_test/src/ct_ssh.erl
+++ b/lib/common_test/src/ct_ssh.erl
@@ -1328,10 +1328,10 @@ do_recv_response(SSH, Chn, Data, End, Timeout) ->
get_handle(SSH) when is_pid(SSH) ->
{ok,SSH};
get_handle(SSH) ->
- case ct_util:get_connections(SSH, ?MODULE) of
- {ok,[{Pid,_}]} ->
+ case ct_util:get_connection(SSH, ?MODULE) of
+ {ok,{Pid,_}} ->
{ok,Pid};
- {ok,[]} ->
+ {error,no_registered_connection} ->
connect(SSH);
Error ->
Error
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index 4755d939e0..4092d33bc0 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -183,7 +183,8 @@ open(KeyOrName,ConnType,TargetMod,Extra) ->
end;
Bool -> Bool
end,
- log(heading(open,{KeyOrName,ConnType}),"Opening connection to: ~p",[Addr1]),
+ log(heading(open,{KeyOrName,ConnType}),
+ "Opening connection to: ~p",[Addr1]),
ct_gen_conn:start(KeyOrName,full_addr(Addr1,ConnType),
{TargetMod,KeepAlive,Extra},?MODULE)
end.
@@ -591,9 +592,9 @@ terminate(TelnPid,State) ->
get_handle(Pid) when is_pid(Pid) ->
{ok,Pid};
get_handle({Name,Type}) when Type==telnet;Type==ts1;Type==ts2 ->
- case ct_util:get_connections(Name,?MODULE) of
- {ok,Conns} when Conns /= [] ->
- case get_handle(Type,Conns) of
+ case ct_util:get_connection(Name,?MODULE) of
+ {ok,Conn} ->
+ case get_handle(Type,Conn) of
{ok,Pid} ->
{ok,Pid};
_Error ->
@@ -608,19 +609,15 @@ get_handle({Name,Type}) when Type==telnet;Type==ts1;Type==ts2 ->
Error
end
end;
- {ok,[]} ->
- {error,already_closed};
Error ->
Error
end;
get_handle(Name) ->
get_handle({Name,telnet}).
-get_handle(Type,[{Pid,{_,_,Type}}|_]) ->
+get_handle(Type,{Pid,{_,_,Type}}) ->
{ok,Pid};
-get_handle(Type,[_H|T]) ->
- get_handle(Type,T);
-get_handle(Type,[]) ->
+get_handle(Type,_) ->
{error,{no_such_connection,Type}}.
full_addr({Ip,Port},Type) ->
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index b77845eb5b..68e76c2396 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -25,13 +25,13 @@
%%%
-module(ct_util).
--export([start/0,start/1,start/2,start/3,
- stop/1,update_last_run_index/0]).
+-export([start/0, start/1, start/2, start/3,
+ stop/1, update_last_run_index/0]).
--export([register_connection/4,unregister_connection/1,
- does_connection_exist/3,get_key_from_name/1]).
+-export([register_connection/4, unregister_connection/1,
+ does_connection_exist/3, get_key_from_name/1]).
--export([close_connections/0]).
+-export([get_connections/1, close_connections/0]).
-export([save_suite_data/3, save_suite_data/2,
save_suite_data_async/3, save_suite_data_async/2,
@@ -56,11 +56,11 @@
-export([listenv/1]).
--export([get_target_name/1, get_connections/2]).
+-export([get_target_name/1, get_connection/2]).
-export([is_test_dir/1, get_testdir/2]).
--export([kill_attached/2, get_attached/1, ct_make_ref/0]).
+-export([kill_attached/2, get_attached/1]).
-export([warn_duplicates/1]).
@@ -417,7 +417,8 @@ loop(Mode,TestData,StartDir) ->
?MAX_IMPORTANCE,
"CT Error Notification",
"Connection process died: "
- "Pid: ~w, Address: ~p, Callback: ~w\n"
+ "Pid: ~w, Address: ~p, "
+ "Callback: ~w\n"
"Reason: ~p\n\n",
[Pid,A,CB,Reason]),
catch CB:close(Pid),
@@ -426,8 +427,8 @@ loop(Mode,TestData,StartDir) ->
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]),
+ io:format("\n\nct_util_server got EXIT "
+ "from ~w: ~p\n\n", [Pid,Reason]),
file:set_cwd(StartDir),
exit(Reason)
end
@@ -457,10 +458,13 @@ get_key_from_name(Name)->
%%% table, and ct_util will close all registered connections when the
%%% test is finished by calling <code>Callback:close/1</code>.</p>
register_connection(TargetName,Address,Callback,Handle) ->
+ %% If TargetName is a registered alias for a config
+ %% variable, use it as reference for the connection,
+ %% otherwise use the Handle value.
TargetRef =
- case ct_config:get_ref_from_name(TargetName) of
- {ok,Ref} ->
- Ref;
+ case ct_config:get_key_from_name(TargetName) of
+ {ok,_Key} ->
+ TargetName;
_ ->
%% no config name associated with connection,
%% use handle for identification instead
@@ -496,10 +500,10 @@ unregister_connection(Handle) ->
%%%
%%% @doc Check if a connection already exists.
does_connection_exist(TargetName,Address,Callback) ->
- case ct_config:get_ref_from_name(TargetName) of
- {ok,TargetRef} ->
+ case ct_config:get_key_from_name(TargetName) of
+ {ok,_Key} ->
case ets:select(?conn_table,[{#conn{handle='$1',
- targetref=TargetRef,
+ targetref=TargetName,
address=Address,
callback=Callback},
[],
@@ -514,41 +518,76 @@ does_connection_exist(TargetName,Address,Callback) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec get_connections(TargetName,Callback) ->
-%%% {ok,Connections} | {error,Reason}
+%%% @spec get_connection(TargetName,Callback) ->
+%%% {ok,Connection} | {error,Reason}
%%% TargetName = ct:target_name()
%%% Callback = atom()
-%%% Connections = [Connection]
%%% Connection = {Handle,Address}
%%% Handle = term()
%%% Address = term()
%%%
-%%% @doc Return all connections for the <code>Callback</code> on the
+%%% @doc Return the connection for <code>Callback</code> on the
%%% given target (<code>TargetName</code>).
-get_connections(TargetName,Callback) ->
- case ct_config:get_ref_from_name(TargetName) of
- {ok,Ref} ->
- {ok,ets:select(?conn_table,[{#conn{handle='$1',
- address='$2',
- targetref=Ref,
- callback=Callback},
- [],
- [{{'$1','$2'}}]}])};
+get_connection(TargetName,Callback) ->
+ %% check that TargetName is a registered alias
+ case ct_config:get_key_from_name(TargetName) of
+ {ok,_Key} ->
+ case ets:select(?conn_table,[{#conn{handle='$1',
+ address='$2',
+ targetref=TargetName,
+ callback=Callback},
+ [],
+ [{{'$1','$2'}}]}]) of
+ [Result] ->
+ {ok,Result};
+ [] ->
+ {error,no_registered_connection}
+ end;
Error ->
Error
end.
%%%-----------------------------------------------------------------
+%%% @spec get_connections(ConnPid) ->
+%%% {ok,Connections} | {error,Reason}
+%%% Connections = [Connection]
+%%% Connection = {TargetName,Handle,Callback,Address}
+%%% TargetName = ct:target_name() | undefined
+%%% Handle = term()
+%%% Callback = atom()
+%%% Address = term()
+%%%
+%%% @doc Get data for all connections associated with a particular
+%%% connection pid (see Callback:init/3).
+get_connections(ConnPid) ->
+ Conns = ets:tab2list(?conn_table),
+ lists:flatmap(fun(#conn{targetref=TargetName,
+ handle=Handle,
+ callback=Callback,
+ address=Address}) ->
+ case ct_gen_conn:get_conn_pid(Handle) of
+ ConnPid when is_atom(TargetName) ->
+ [{TargetName,Handle,
+ Callback,Address}];
+ ConnPid ->
+ [{undefined,Handle,
+ Callback,Address}];
+ _ ->
+ []
+ end
+ end, Conns).
+
+%%%-----------------------------------------------------------------
%%% @hidden
%%% @equiv ct:get_target_name/1
-get_target_name(ConnPid) ->
- case ets:select(?conn_table,[{#conn{handle=ConnPid,targetref='$1',_='_'},
+get_target_name(Handle) ->
+ case ets:select(?conn_table,[{#conn{handle=Handle,targetref='$1',_='_'},
[],
['$1']}]) of
- [TargetRef] ->
- ct_config:get_name_from_ref(TargetRef);
- [] ->
- {error,{unknown_connection,ConnPid}}
+ [TargetName] when is_atom(TargetName) ->
+ {ok,TargetName};
+ _ ->
+ {error,{unknown_connection,Handle}}
end.
%%%-----------------------------------------------------------------
@@ -922,29 +961,6 @@ cast(Msg) ->
seconds(T) ->
test_server:seconds(T).
-ct_make_ref() ->
- Pid = case whereis(ct_make_ref) of
- undefined ->
- spawn_link(fun() -> ct_make_ref_init() end);
- P ->
- P
- end,
- Pid ! {self(),ref_req},
- receive
- {Pid,Ref} -> Ref
- end.
-
-ct_make_ref_init() ->
- register(ct_make_ref,self()),
- ct_make_ref_loop(0).
-
-ct_make_ref_loop(N) ->
- receive
- {From,ref_req} ->
- From ! {self(),N},
- ct_make_ref_loop(N+1)
- end.
-
abs_name("/") ->
"/";
abs_name(Dir0) ->
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index 31ab28c41d..9d2edcd653 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -30,6 +30,7 @@ MODULES= \
ct_userconfig_callback \
telnet_server \
ct_smoke_test_SUITE \
+ ct_gen_conn_SUITE \
ct_priv_dir_SUITE \
ct_event_handler_SUITE \
ct_config_info_SUITE \
diff --git a/lib/common_test/test/ct_gen_conn_SUITE.erl b/lib/common_test/test/ct_gen_conn_SUITE.erl
new file mode 100644
index 0000000000..2a2183854e
--- /dev/null
+++ b/lib/common_test/test/ct_gen_conn_SUITE.erl
@@ -0,0 +1,135 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2012. 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_gen_conn_SUITE
+%%%
+%%% Description:
+%%% Test that the generic connection handling in CT works as expected.
+%%%
+%%% The suite used for the test is located in the data directory.
+%%%-------------------------------------------------------------------
+-module(ct_gen_conn_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ ct_test_support:init_per_suite(Config).
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [handles_to_multi_conn_pids, handles_to_single_conn_pids,
+ names_to_multi_conn_pids, names_to_single_conn_pids].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+handles_to_multi_conn_pids(Config) ->
+ run_test(handles_to_multi_conn_pids, Config).
+
+handles_to_single_conn_pids(Config) ->
+ run_test(handles_to_single_conn_pids, Config).
+
+names_to_multi_conn_pids(Config) ->
+ run_test(names_to_multi_conn_pids, Config).
+
+names_to_single_conn_pids(Config) ->
+ run_test(names_to_single_conn_pids, Config).
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+run_test(TestCase, Config) ->
+ DataDir = ?config(data_dir, Config),
+ {Opts,ERPid} = setup_env([{dir,DataDir},
+ {suite,conn_SUITE},
+ {testcase,TestCase},
+ {config,filename:join(DataDir,"conn.conf")}],
+ Config),
+ ok = ct_test_support:run(Opts, Config),
+ TestEvents = ct_test_support:get_events(ERPid, Config),
+ ct_test_support:log_events(TestCase,
+ reformat_events(TestEvents, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+ ExpEvents = events_to_check(TestCase),
+ ok = ct_test_support:verify_events(ExpEvents, TestEvents, Config).
+
+setup_env(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}} | Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+reformat_events(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+events_to_check(Test) ->
+ %% 2 tests (ct:run_test + script_start) is default
+ events_to_check(Test, 2).
+
+events_to_check(_, 0) ->
+ [];
+events_to_check(Test, N) ->
+ test_events(Test) ++ events_to_check(Test, N-1).
+
+test_events(Name) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,1}},
+ {?eh,tc_start,{conn_SUITE,init_per_suite}},
+ {?eh,tc_done,{conn_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{conn_SUITE,Name}},
+ {?eh,tc_done,{conn_SUITE,Name,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{conn_SUITE,end_per_suite}},
+ {?eh,tc_done,{conn_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ].
diff --git a/lib/common_test/test/ct_gen_conn_SUITE_data/conn.conf b/lib/common_test/test/ct_gen_conn_SUITE_data/conn.conf
new file mode 100644
index 0000000000..09f3c11e10
--- /dev/null
+++ b/lib/common_test/test/ct_gen_conn_SUITE_data/conn.conf
@@ -0,0 +1,8 @@
+{multi_conn_pid, [{addr,"localhost"},
+ {port,8383},
+ {multiple_conn_pids,true}]}.
+
+{single_conn_pid, [{addr,"localhost"},
+ {port,8383},
+ {multiple_conn_pids,false},
+ {conn_mgr_name,conn_mgr}]}.
diff --git a/lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl b/lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl
new file mode 100644
index 0000000000..6877e0c2d2
--- /dev/null
+++ b/lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl
@@ -0,0 +1,240 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : conn_SUITE
+%%% Description : Check that the generic connection handling in CT
+%%% works as expected.
+%%%-------------------------------------------------------------------
+-module(conn_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% COMMON TEST CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+suite() ->
+ [{timetrap,{seconds,5}}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+all() ->
+ [handles_to_multi_conn_pids, handles_to_single_conn_pids,
+ names_to_multi_conn_pids, names_to_single_conn_pids].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+handles_to_multi_conn_pids() ->
+ [{require,multi_conn_pid}].
+
+handles_to_multi_conn_pids(_Config) ->
+ application:set_env(ct_test, reconnect, true),
+
+ Handle1 = proto:open(multi_conn_pid),
+ ConnPid1 = ct_gen_conn:get_conn_pid(Handle1),
+ {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
+ Handle2 = proto:open(multi_conn_pid),
+ ConnPid2 = ct_gen_conn:get_conn_pid(Handle2),
+ {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
+ Handle3 = proto:open(multi_conn_pid),
+ ConnPid3 = ct_gen_conn:get_conn_pid(Handle3),
+ {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
+
+ ok = proto:close(Handle1),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
+ {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
+
+ ok = proto:kill_conn_proc(Handle2),
+ timer:sleep(100),
+ {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
+ ConnPid2x = ct_gen_conn:get_conn_pid(Handle2),
+ true = is_process_alive(ConnPid2x),
+
+ ok = proto:close(Handle2),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2x)},
+
+ application:set_env(ct_test, reconnect, false),
+ ok = proto:kill_conn_proc(Handle3),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
+
+ ok.
+
+handles_to_single_conn_pids() ->
+ [{require,single_conn_pid}].
+
+handles_to_single_conn_pids(_Config) ->
+ application:set_env(ct_test, reconnect, true),
+
+ Handle1 = proto:open(single_conn_pid),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle1),
+ {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
+ Handle2 = proto:open(single_conn_pid),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle2),
+ {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid)},
+ Handle3 = proto:open(single_conn_pid),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle3),
+ {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid)},
+
+ Conns = [{undefined,Handle1,_,_},
+ {undefined,Handle2,_,_},
+ {undefined,Handle3,_,_}] = lists:sort(ct_util:get_connections(ConnPid)),
+ ct:pal("CONNS = ~n~p", [Conns]),
+
+ ok = proto:close(Handle1),
+ timer:sleep(100),
+ {false,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
+
+ ok = proto:kill_conn_proc(Handle2),
+ timer:sleep(100),
+ NewConnPid = ct_gen_conn:get_conn_pid(Handle2),
+ NewConnPid = ct_gen_conn:get_conn_pid(Handle3),
+ true = is_process_alive(Handle2),
+ true = is_process_alive(Handle3),
+
+ ok = proto:close(Handle2),
+ timer:sleep(100),
+ {false,true} = {is_process_alive(Handle2),is_process_alive(NewConnPid)},
+
+ application:set_env(ct_test, reconnect, false),
+ ok = proto:kill_conn_proc(Handle3),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle3),is_process_alive(NewConnPid)},
+
+ ok.
+
+names_to_multi_conn_pids() ->
+ [{require,mconn1,multi_conn_pid},
+ {require,mconn2,multi_conn_pid},
+ {require,mconn3,multi_conn_pid}].
+
+names_to_multi_conn_pids(_Config) ->
+ application:set_env(ct_test, reconnect, true),
+
+ Handle1 = proto:open(mconn1),
+ ConnPid1 = ct_gen_conn:get_conn_pid(Handle1),
+ {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
+ Handle2 = proto:open(mconn2),
+ ConnPid2 = ct_gen_conn:get_conn_pid(Handle2),
+ {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
+ Handle3 = proto:open(mconn3),
+ ConnPid3 = ct_gen_conn:get_conn_pid(Handle3),
+ {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
+
+ Handle1 = proto:open(mconn1),
+
+ ok = proto:close(mconn1),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
+
+ ok = proto:kill_conn_proc(Handle2),
+ timer:sleep(100),
+ Handle2 = proto:open(mconn2), % should've been reconnected already
+ {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
+ ConnPid2x = ct_gen_conn:get_conn_pid(Handle2),
+ true = is_process_alive(ConnPid2x),
+
+ ok = proto:close(mconn2),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2x)},
+ Handle2y = proto:open(mconn2),
+ ConnPid2y = ct_gen_conn:get_conn_pid(Handle2y),
+ {true,true} = {is_process_alive(Handle2y),is_process_alive(ConnPid2y)},
+ ok = proto:close(mconn2),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle2y),is_process_alive(ConnPid2y)},
+
+ application:set_env(ct_test, reconnect, false),
+ ok = proto:kill_conn_proc(Handle3),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
+
+ ok.
+
+names_to_single_conn_pids() ->
+ [{require,sconn1,single_conn_pid},
+ {require,sconn2,single_conn_pid},
+ {require,sconn3,single_conn_pid}].
+
+names_to_single_conn_pids(_Config) ->
+ application:set_env(ct_test, reconnect, true),
+
+ Handle1 = proto:open(sconn1),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle1),
+ {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
+ Handle2 = proto:open(sconn2),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle2),
+ {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid)},
+ Handle3 = proto:open(sconn3),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle3),
+ {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid)},
+
+ Handle1 = proto:open(sconn1),
+
+ Conns = [{sconn1,Handle1,_,_},
+ {sconn2,Handle2,_,_},
+ {sconn3,Handle3,_,_}] = lists:sort(ct_util:get_connections(ConnPid)),
+ ct:pal("CONNS on ~p = ~n~p", [ConnPid,Conns]),
+
+ ok = proto:close(sconn1),
+ timer:sleep(100),
+ {false,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
+
+ ok = proto:kill_conn_proc(Handle2),
+ timer:sleep(100),
+ {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid)},
+ Handle2 = proto:open(sconn2), % should've been reconnected already
+ NewConnPid = ct_gen_conn:get_conn_pid(Handle2),
+ true = is_process_alive(NewConnPid),
+
+ Conns1 = [{sconn2,Handle2,_,_},
+ {sconn3,Handle3,_,_}] =
+ lists:sort(ct_util:get_connections(NewConnPid)),
+ ct:pal("CONNS on ~p = ~n~p", [NewConnPid,Conns1]),
+
+ ok = proto:close(sconn2),
+ timer:sleep(100),
+ {false,true} = {is_process_alive(Handle2),is_process_alive(NewConnPid)},
+
+ application:set_env(ct_test, reconnect, false),
+ ok = proto:kill_conn_proc(Handle3),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle3),is_process_alive(NewConnPid)},
+
+ ok.
+
+
diff --git a/lib/common_test/test/ct_gen_conn_SUITE_data/proto.erl b/lib/common_test/test/ct_gen_conn_SUITE_data/proto.erl
new file mode 100644
index 0000000000..8fcd35e0a4
--- /dev/null
+++ b/lib/common_test/test/ct_gen_conn_SUITE_data/proto.erl
@@ -0,0 +1,196 @@
+%%% @author Peter Andersson <[email protected]>
+%%% @copyright (C) 2013, Peter Andersson
+%%% @doc
+%%%
+%%% @end
+%%% Created : 24 May 2013 by Peter Andersson <[email protected]>
+
+-module(proto).
+
+-compile(export_all).
+
+-record(conn_state, {id, pid, ref, data}).
+
+%% TEST1: N connections (same key) -> N conn pids
+%% TEST2: N connections (same key) -> 1 conn pid
+%% TEST3: N aliases (same key) -> N conn pids
+%% TEST4: N aliases (same key) -> 1 conn pid
+
+open(KeyOrAlias) ->
+ case ct:get_config(KeyOrAlias) of
+ undefined ->
+ {error,{not_available,KeyOrAlias}};
+ ConnData ->
+ io:format("Opening connection with ~p~n", [ConnData]),
+
+ %% if KeyOrAlias == Key, each call returns unique handle
+ %% if KeyOrAlias == Alias, successive calls return same handle
+ {ok,Handle} = ct_gen_conn:start(ConnData,
+ [],
+ ?MODULE,
+ [{name,KeyOrAlias}]),
+ io:format("Handle for ~p = ~p~n", [KeyOrAlias,Handle]),
+ Handle
+ end.
+
+close(AliasOrHandle) ->
+ Handle = get_handle(AliasOrHandle),
+ io:format("Closing connection for ~p (~p)~n", [AliasOrHandle,Handle]),
+ case ct_gen_conn:stop(Handle) of
+ E = {error,_} ->
+ E;
+ Result ->
+ Result
+ end.
+
+kill_conn_proc(AliasOrHandle) ->
+ ConnPid = ct_gen_conn:get_conn_pid(get_handle(AliasOrHandle)),
+ io:format("Killing connection process ~p~n", [ConnPid]),
+ ConnPid ! fail,
+ ok.
+
+send(_) ->
+ ok.
+
+%%%-----------------------------------------------------------------
+%%%
+
+init(KeyOrAlias, ConnData, []) ->
+ Addr = proplists:get_value(addr, ConnData),
+ Port = proplists:get_value(port, ConnData),
+ Ref = make_ref(),
+ Starter = self(),
+ MultConnPids = proplists:get_value(multiple_conn_pids, ConnData),
+ ConnPid =
+ case MultConnPids of
+ true ->
+ spawn(fun() -> active_conn(Starter, KeyOrAlias, Ref,
+ ConnData) end);
+ _ ->
+ ConnMgr = proplists:get_value(conn_mgr_name, ConnData),
+ case whereis(ConnMgr) of
+ undefined ->
+ MgrPid =
+ spawn(fun() -> active_conn(Starter, KeyOrAlias,
+ Ref, ConnData) end),
+ receive MgrPid ->
+ MgrPid
+ end;
+ MgrPid when is_pid(MgrPid) ->
+ MgrPid ! {connect,Ref},
+ MgrPid
+ end
+ end,
+ io:format("Connection ~p opened on ~p:~p -> ~p (~p)~n",
+ [KeyOrAlias,Addr,Port,ConnPid,Ref]),
+ {ok,ConnPid,#conn_state{id=KeyOrAlias, pid=ConnPid, ref=Ref, data=ConnData}}.
+
+
+terminate(ConnPid, #conn_state{id=Id, pid=ConnPid, ref = Ref, data=Data}) ->
+ case proplists:get_value(multiple_conn_pids, Data) of
+ true ->
+ ConnPid ! close;
+ _ ->
+ ConnPid ! {close,Ref}
+ end,
+ io:format("Connection ~p on ~p (~p) closing!~n", [Id,ConnPid,Ref]),
+ ok.
+
+
+reconnect(ConnData, State = #conn_state{id=Id, ref=DeadRef}) ->
+ io:format("Reconnect for ~p initiated...~n", [DeadRef]),
+ case application:get_env(ct_test, reconnect) of
+ {ok,true} ->
+ ConnMgr = proplists:get_value(conn_mgr_name, ConnData),
+ NewRef = make_ref(),
+ Starter = self(),
+ ConnPid =
+ case proplists:get_value(multiple_conn_pids, ConnData) of
+ true ->
+ spawn(fun() ->
+ active_conn(Starter, Id, NewRef,
+ ConnData)
+ end);
+ _ ->
+ case whereis(ConnMgr) of
+ undefined ->
+ MgrPid =
+ spawn(fun() ->
+ active_conn(Starter, Id,
+ NewRef, ConnData)
+ end),
+ receive MgrPid ->
+ MgrPid
+ end;
+ MgrPid ->
+ MgrPid ! {reconnect,DeadRef,NewRef},
+ MgrPid
+ end
+ end,
+ io:format("Connection ~p reopened on ~p (~p)~n",
+ [Id,ConnPid,NewRef]),
+ {ok,ConnPid,State#conn_state{pid=ConnPid, ref=NewRef}};
+ _ ->
+ {error,no_reconnection_allowed}
+ end.
+
+%%%-----------------------------------------------------------------
+%%%
+
+active_conn(Starter, Id, Ref, ConnData) ->
+ ConnMgr = proplists:get_value(conn_mgr_name, ConnData),
+ case proplists:get_value(multiple_conn_pids, ConnData) of
+ true ->
+ ok;
+ _ ->
+ register(ConnMgr,self()),
+ io:format("Connection manager ~p on ~p started for "
+ "~p and ~p~n",
+ [ConnMgr,self(),Id,Ref])
+ end,
+ Starter ! self(),
+ active_conn_loop(ConnData, [Ref]).
+
+active_conn_loop(ConnData, Conns) ->
+ receive
+ {connect,Ref} ->
+ io:format("Connecting ~p on ~p~n",
+ [Ref,self()]),
+ active_conn_loop(ConnData, [Ref | Conns]);
+ {reconnect,DeadRef,NewRef} ->
+ Conns1 = [NewRef | lists:delete(DeadRef, Conns)],
+ io:format("Reconnecting on ~p: ~p -> ~p~n",
+ [self(),DeadRef,NewRef]),
+ active_conn_loop(ConnData, Conns1);
+ close ->
+ io:format("Conn process ~p shutting down~n", [self()]),
+ ok;
+ {close,Ref} ->
+ io:format("Closing connection ~p on ~p~n", [Ref,self()]),
+ case proplists:delete(Ref, Conns) of
+ [] ->
+ io:format("Last connection on ~p closed, "
+ "now stopping~n", [self()]),
+ ok;
+ Conns1 ->
+ active_conn_loop(ConnData, Conns1)
+ end;
+ fail ->
+ io:format("Connection process not feeling good...~n", []),
+ exit(kaboom);
+ {respond,To} ->
+ To ! {self(),hello},
+ active_conn_loop(ConnData, Conns)
+ end.
+
+%%%-----------------------------------------------------------------
+%%%
+
+get_handle(AliasOrHandle) when is_pid(AliasOrHandle) ->
+ AliasOrHandle;
+
+get_handle(AliasOrHandle) ->
+ {ok,{H,_}} = ct_util:get_connection(AliasOrHandle,
+ ?MODULE),
+ H.
+
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index bdccfee341..2df407018e 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -249,7 +249,7 @@
<name>hash(Type, Data) -> Digest</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | message_digest_algorithms()</v>
+ <v>Type = md4 | hash_algorithms()</v>
<v>Data = iodata()</v>
<v>Digest = binary()</v>
</type>
@@ -264,7 +264,7 @@
<name>hash_init(Type) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | message_digest_algorithms()</v>
+ <v>Type = md4 | hash_algorithms()</v>
</type>
<desc>
<p>Initializes the context for streaming hash operations. <c>Type</c> determines
@@ -308,7 +308,7 @@
<name>hmac(Type, Key, Data, MacLength) -> Mac</name>
<fsummary></fsummary>
<type>
- <v>Type = message_digest_algorithms() </v>
+ <v>Type = hash_algorithms() - except ripemd160</v>
<v>Key = iodata()</v>
<v>Data = iodata()</v>
<v>MacLength = integer()</v>
@@ -325,7 +325,7 @@
<name>hmac_init(Type, Key) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = message_digest_algorithms()</v>
+ <v>Type = hash_algorithms() - except ripemd160</v>
<v>Key = iodata()</v>
<v>Context = binary()</v>
</type>
@@ -475,7 +475,7 @@
used mode.
The size of the <c>Msg</c> must be less than <c>byte_size(N)-11</c> if
<c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used.
+ is used, where N is public modulus of the RSA key.
See also <seealso marker="public_key:public_key#encrypt_private/2">public_key:encrypt_private/[2,3]</seealso>
</p>
</desc>
@@ -513,18 +513,20 @@
<v>ChipherText = binary()</v>
</type>
<desc>
- <p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c>
- and returns the <c>CipherText</c>. The <c>Padding</c> decides what padding mode is used,
- <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
- used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as
- defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding
- parameter. This mode is recommended for all new applications.
- The size of the <c>Msg</c> must be less
- than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if
- <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used.
- See also <seealso marker="public_key:public_key#encrypt_public/2">public_key:encrypt_public/[2,3]</seealso>
+ <p>Encrypts the <c>PlainText</c> (usually a session key) using
+ the <c>PublicKey</c> and returns the <c>CipherText</c>. The
+ <c>Padding</c> decides what padding mode is used,
+ <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
+ used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as
+ defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding
+ parameter. This mode is recommended for all new
+ applications. The size of the <c>Msg</c> must be less than
+ <c>byte_size(N)-11</c> if <c>rsa_pkcs1_padding</c> is
+ used, <c>byte_size(N)-41</c> if
+ <c>rsa_pkcs1_oaep_padding</c> is used and
+ <c>byte_size(N)</c> if <c>rsa_no_padding</c> is used, where N is public modulus of the RSA key.
+ See also <seealso
+ marker="public_key:public_key#encrypt_public/2">public_key:encrypt_public/[2,3]</seealso>
</p>
</desc>
</func>
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index c007ecac86..b3bb5dbd17 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -48,7 +48,7 @@ all() ->
{group, des_cfb},
{group, des3_cbc},
{group, des3_cbf},
- %%{group, des_ede3},
+ {group, des_ede3},
{group, blowfish_cbc},
{group, blowfish_ecb},
{group, blowfish_cfb64},
@@ -60,7 +60,8 @@ all() ->
{group, rc4},
{group, aes_ctr},
mod_pow,
- exor
+ exor,
+ rand_uniform
].
groups() ->
@@ -83,6 +84,7 @@ groups() ->
{des_cbc, [], [block]},
{des_cfb, [], [block]},
{des3_cbc,[], [block]},
+ {des_ede3,[], [block]},
{des3_cbf,[], [block]},
{rc2_cbc,[], [block]},
{aes_cbc128,[], [block]},
@@ -220,7 +222,13 @@ exor(Config) when is_list(Config) ->
Z2 = crypto:exor(B2, B2),
R = xor_bytes(B1, B2),
R = crypto:exor(B1, B2).
-
+%%--------------------------------------------------------------------
+rand_uniform() ->
+ [{doc, "rand_uniform and random_bytes testing"}].
+rand_uniform(Config) when is_list(Config) ->
+ rand_uniform_aux_test(10),
+ 10 = byte_size(crypto:rand_bytes(10)),
+ 10 = byte_size(crypto:strong_rand_bytes(10)).
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
@@ -398,16 +406,19 @@ negative_verify(Type, Hash, Msg, Signature, Public) ->
end.
do_public_encrypt({Type, Public, Private, Msg, Padding}) ->
- PublicEcn = crypto:public_encrypt(Type, Msg, Public, Padding),
+ PublicEcn = (catch crypto:public_encrypt(Type, Msg, Public, Padding)),
case crypto:private_decrypt(Type, PublicEcn, Private, Padding) of
Msg ->
ok;
Other ->
ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, Other}})
end.
+
+do_private_encrypt({_Type, _Public, _Private, _Msg, rsa_pkcs1_oaep_padding}) ->
+ ok; %% Not supported by openssl
do_private_encrypt({Type, Public, Private, Msg, Padding}) ->
- PrivEcn = crypto:private_encrypt(Type, Msg, Private, Padding),
- case crypto:public_decrypt(Type, PrivEcn, Public, Padding) of
+ PrivEcn = (catch crypto:private_encrypt(Type, Msg, Private, Padding)),
+ case crypto:public_decrypt(rsa, PrivEcn, Public, Padding) of
Msg ->
ok;
Other ->
@@ -451,8 +462,6 @@ mkint(C) when $A =< C, C =< $F ->
mkint(C) when $a =< C, C =< $f ->
C - $a + 10.
-is_supported(cipher) ->
- true;
is_supported(Group) ->
lists:member(Group, lists:append([Algo || {_, Algo} <- crypto:supports()])).
@@ -472,6 +481,8 @@ do_block_iolistify({des3_cbc = Type, Key, IV, PlainText}) ->
{Type, Key, IV, des_iolistify(PlainText)};
do_block_iolistify({des3_cbf = Type, Key, IV, PlainText}) ->
{Type, Key, IV, des_iolistify(PlainText)};
+do_block_iolistify({des_ede3 = Type, Key, IV, PlainText}) ->
+ {Type, Key, IV, des_iolistify(PlainText)};
do_block_iolistify({Type, Key, PlainText}) ->
{Type, iolistify(Key), iolistify(PlainText)};
do_block_iolistify({Type, Key, IV, PlainText}) ->
@@ -545,6 +556,25 @@ xor_bytes([], [], Acc) ->
lists:reverse(Acc);
xor_bytes([N1 | Tl1], [N2 | Tl2], Acc) ->
xor_bytes(Tl1, Tl2, [N1 bxor N2 | Acc]).
+rand_uniform_aux_test(0) ->
+ ok;
+rand_uniform_aux_test(N) ->
+ L = N*1000,
+ H = N*100000+1,
+ crypto_rand_uniform(L, H),
+ crypto_rand_uniform(-L, L),
+ crypto_rand_uniform(-H, -L),
+ crypto_rand_uniform(-H, L),
+ rand_uniform_aux_test(N-1).
+
+crypto_rand_uniform(L,H) ->
+ R1 = crypto:rand_uniform(L, H),
+ case (R1 >= L) and (R1 < H) of
+ true ->
+ ok;
+ false ->
+ ct:fail({"Not in interval", R1, L, H})
+ end.
%%--------------------------------------------------------------------
%% Test data ------------------------------------------------
@@ -603,17 +633,13 @@ group_config(rsa = Type, Config) ->
Msg = rsa_plain(),
Public = rsa_public(),
Private = rsa_private(),
- SignVerify = [{Type, md5, Public, Private, Msg},
- {Type, sha, Public, Private, Msg},
- {Type, sha224, Public, Private,Msg},
- {Type, sha256, Public, Private,Msg}
- %% {Type, sha384, Public, Private,Msg},
- %% {Type, sha512, Public, Private, Msg}
- ],
+ PublicS = rsa_public_stronger(),
+ PrivateS = rsa_private_stronger(),
+ SignVerify = sign_verify_tests(Type, Msg, Public, Private, PublicS, PrivateS),
MsgPubEnc = <<"7896345786348 Asldi">>,
- PubPrivEnc = [{rsa, Public, Private, MsgPubEnc, rsa_pkcs1_padding}
- %%{rsa, Public, Private, MsgPubEnc, rsa_pkcs1_oaep_padding}
- %%{rsa, Public, Private, MsgPubEnc, rsa_no_padding}
+ PubPrivEnc = [{rsa, Public, Private, MsgPubEnc, rsa_pkcs1_padding},
+ rsa_oaep(),
+ no_padding()
],
[{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
group_config(dss = Type, Config) ->
@@ -649,6 +675,9 @@ group_config(des3_cbc, Config) ->
group_config(des3_cbf, Config) ->
Block = des3_cbf(),
[{block, Block} | Config];
+group_config(des_ede3, Config) ->
+ Block = des_ede3(),
+ [{block, Block} | Config];
group_config(rc2_cbc, Config) ->
Block = rc2_cbc(),
[{block, Block} | Config];
@@ -682,6 +711,20 @@ group_config(aes_ctr, Config) ->
group_config(_, Config) ->
Config.
+sign_verify_tests(Type, Msg, Public, Private, PublicS, PrivateS) ->
+ sign_verify_tests(Type, [md5, sha, sha224, sha256], Msg, Public, Private) ++
+ sign_verify_tests(Type, [sha384, sha512], Msg, PublicS, PrivateS).
+
+sign_verify_tests(Type, Hashs, Msg, Public, Private) ->
+ lists:foldl(fun(Hash, Acc) ->
+ case is_supported(Hash) of
+ true ->
+ [{Type, Hash, Public, Private, Msg}|Acc];
+ false ->
+ Acc
+ end
+ end, [], Hashs).
+
rfc_1321_msgs() ->
[<<"">>,
<<"a">>,
@@ -950,6 +993,15 @@ des3_cbc() ->
<<"Now is the time for all ">>
}].
+des_ede3() ->
+ [{des_ede3,
+ [hexstr2bin("8000000000000000"),
+ hexstr2bin("4000000000000000"),
+ hexstr2bin("2000000000000000")],
+ hexstr2bin("7AD16FFB79C45926"),
+ hexstr2bin("0000000000000000")
+ }].
+
des3_cbf() ->
[{des3_cbf,
[hexstr2bin("0123456789abcdef"),
@@ -1196,6 +1248,12 @@ rsa_public() ->
rsa_private() ->
rsa_public() ++ [7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945].
+rsa_public_stronger() ->
+ [65537, 24629450921918866883077380602720734920775458960049554761386137065662137652635369332143446151320538248280934442179850504891395344346514465469955766163141133564033962851182759993807898821114734943339732032639891483186089941567854227407119560631150779000222837755424893038740314247760600374970909894211201220612920040986106639419467243909950276018045907029941478599124238353052062083560294570722081552510960894164859765695309596889747541376908786225647625736062865138957717982693312699025417086612046330464651009693307624955796202070510577399561730651967517158452930742355327167632521808183383868100102455048819375344881].
+
+rsa_private_stronger() ->
+ rsa_public_stronger() ++ [13565232776562604620467234237694854016819673873109064019820773052201665024482754648718278717031083946624786145611240731564761987114634269887293030432042088547345315212418830656522115993209293567218379960177754901461542373481136856927955012596579314262051109321754382091434920473734937991286600905464814063189230779981494358415076362038786197620360127262110530926733754185204773610295221669711309000953136320804528874719105049753061737780710448207922456570922652651354760939379096788728229638142403068102990416717272880560951246813789730402978652924934794503277969128609831043469924881848849409122972426787999886557185].
+
dss_plain() ->
rsa_plain().
dss_public() ->
@@ -1355,3 +1413,37 @@ ecdh() ->
dh() ->
{dh, 0087761979513264537414556992123116644042638206717762626089877284926656954974893442000747478454809111207351620687968672207938731607963470779396984752680274820156266685080223616226905101126463253150237669547023934604953898814222890239130021414026118792251620881355456432549881723310342870016961804255746630219, 2}.
+
+rsa_oaep() ->
+ %% ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15crypt-vectors.txt
+ Public = [hexstr2bin("010001"),
+ hexstr2bin("a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb")],
+ Private = Public ++ [hexstr2bin("53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1"),
+ hexstr2bin("d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c2f26a471dcad212eac7ca39d"),
+ hexstr2bin("cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af72bfe9a030e860b0288b5d77"),
+ hexstr2bin("0e12bf1718e9cef5599ba1c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305fbecbd2d76819967d4671acc6431e4037968db37878e695c1"),
+ hexstr2bin("95297b0f95a2fa67d00707d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda866efef13c459e1a631386b7e354c899f5f112ca85d71583"),
+ hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
+ %%Msg = hexstr2bin("6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"),
+ Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
+ {rsa, Public, Private, Msg, rsa_pkcs1_oaep_padding}.
+
+no_padding() ->
+ Public = [_, Mod] = rsa_public(),
+ Private = rsa_private(),
+ MsgLen = erlang:byte_size(int_to_bin(Mod)),
+ Msg = list_to_binary(lists:duplicate(MsgLen, $X)),
+ {rsa, Public, Private, Msg, rsa_no_padding}.
+
+int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
+int_to_bin(X) -> int_to_bin_pos(X, []).
+
+int_to_bin_pos(0,Ds=[_|_]) ->
+ list_to_binary(Ds);
+int_to_bin_pos(X,Ds) ->
+ int_to_bin_pos(X bsr 8, [(X band 255)|Ds]).
+
+int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 ->
+ list_to_binary(Ds);
+int_to_bin_neg(X,Ds) ->
+ int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 7550503376..2b29566942 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -5626,16 +5626,25 @@ etsmem() ->
MemInfo ->
CS = lists:foldl(
fun ({instance, _, L}, Acc) ->
- {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L),
- {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L),
- [MBCS,SBCS | Acc]
+ {value,{mbcs,MBCS}} = lists:keysearch(mbcs, 1, L),
+ {value,{sbcs,SBCS}} = lists:keysearch(sbcs, 1, L),
+ NewAcc = [MBCS, SBCS | Acc],
+ case lists:keysearch(mbcs_pool, 1, L) of
+ {value,{mbcs_pool, MBCS_POOL}} ->
+ [MBCS_POOL|NewAcc];
+ _ -> NewAcc
+ end
end,
[],
MemInfo),
lists:foldl(
fun(L, {Bl0,BlSz0}) ->
- {value,{_,Bl,_,_}} = lists:keysearch(blocks, 1, L),
- {value,{_,BlSz,_,_}} = lists:keysearch(blocks_size, 1, L),
+ {value,BlTup} = lists:keysearch(blocks, 1, L),
+ blocks = element(1, BlTup),
+ Bl = element(2, BlTup),
+ {value,BlSzTup} = lists:keysearch(blocks_size, 1, L),
+ blocks_size = element(1, BlSzTup),
+ BlSz = element(2, BlSzTup),
{Bl0+Bl,BlSz0+BlSz}
end, {0,0}, CS)
end},
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index 8b0be51be3..c350f758ce 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -716,6 +716,16 @@ end_conf_timeout(_, _) ->
call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
Starter = self(),
Data = {Mod,Func,TCPid,TCExitReason,Loc},
+ case erlang:function_exported(Mod,end_per_testcase,2) of
+ false ->
+ spawn_link(fun() ->
+ Starter ! {self(),{call_end_conf,Data,ok}}
+ end);
+ true ->
+ do_call_end_conf(Starter,Mod,Func,Data,Conf,TVal)
+ end.
+
+do_call_end_conf(Starter,Mod,Func,Data,Conf,TVal) ->
EndConfProc =
fun() ->
process_flag(trap_exit,true), % to catch timetraps
@@ -753,7 +763,8 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
end,
spawn_link(EndConfProc).
-spawn_fw_call(Mod,{init_per_testcase,Func},CurrConf,Pid,{timetrap_timeout,TVal}=Why,
+spawn_fw_call(Mod,{init_per_testcase,Func},CurrConf,Pid,
+ {timetrap_timeout,TVal}=Why,
Loc,SendTo) ->
FwCall =
fun() ->