aboutsummaryrefslogblamecommitdiffstats
path: root/lib/eldap/test/eldap_connections_SUITE.erl
blob: fb859c009bb8173a17c214ff6c2379f7dae67eb6 (plain) (tree)




























                                                                         



























                                                                              

                       

      








                                    
 


                                          
 


                             












































                                                                                                   









                                                                      

                                      
                                                                      






                                                                   


                                                     

                                                  
                                                            





                                                                           
 













































                                                                        
 





                                                                   










                                                                           
                                                                                

























                                                                                              
























































                                                                                             
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2012-2014. 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(eldap_connections_SUITE).

-compile(export_all).

-include_lib("common_test/include/ct.hrl").
%-include_lib("eldap/include/eldap.hrl").


all() ->
    [
     {group, v4},
     {group, v6}
    ].

     
init_per_group(v4, Config) ->
    [{listen_opts,  []},
     {listen_host,  "localhost"},
     {connect_opts, []}
     |  Config];
init_per_group(v6, Config) ->
    {ok, Hostname} = inet:gethostname(),
    case lists:member(list_to_atom(Hostname), ct:get_config(ipv6_hosts,[])) of
	true -> 
	    [{listen_opts,  [inet6]},
	     {listen_host,  "::"},
	     {connect_opts, [{tcpopts,[inet6]}]}
	     |  Config];
	false -> 
	    {skip, io_lib:format("~p is not an ipv6_host",[Hostname])}
    end.


end_per_group(_GroupName, Config) ->
    Config.


groups() ->
    [{v4, [], tests()},
     {v6, [], tests()}
    ].

tests() ->
    [tcp_connection, 
     tcp_connection_option, 
     ssl_connection,
     client_side_start_tls_timeout, 
     client_side_bind_timeout, 
     client_side_add_timeout,
     client_side_search_timeout
    ].

init_per_suite(Config) -> 
    HasSSL = init_ssl_certs_et_al(Config),
    [{has_ssl,HasSSL} | Config].

end_per_suite(_Config) -> ok.


init_per_testcase(ssl_connection, Config) ->
    case ?config(has_ssl,Config) of
	true ->
	    SSL_Port = 9999,
	    CertFile = filename:join(?config(data_dir,Config), "certs/server/cert.pem"),
	    KeyFile = filename:join(?config(data_dir,Config), "certs/server/key.pem"),

	    Parent = self(),
	    Listener = spawn_link(
			 fun() ->
				 case ssl:listen(SSL_Port, [{certfile, CertFile},
							    {keyfile, KeyFile},
							    {reuseaddr, true}]) of
				     {ok,SSL_LSock} ->
					 Parent ! {ok,self()},
					 (fun L() ->
						ct:log("ssl server waiting for connections...",[]),
						{ok, S} = ssl:transport_accept(SSL_LSock),
						ct:log("ssl:transport_accept/1 ok",[]),
						ok = ssl:ssl_accept(S),
						ct:log("ssl:ssl_accept/1 ok",[]),
						L()
				          end)();
				     Other ->
					 Parent ! {not_ok,Other,self()}
				 end
			 end),
	    receive
		{ok,Listener} ->
		    ct:log("SSL listening to port ~p (process ~p)",[SSL_Port, Listener]),
		    [{ssl_listener,Listener},
		     {ssl_listen_port,SSL_Port},
		     {ssl_connect_opts,[]}
		     | Config];
		{no_ok,SSL_Other,Listener} ->
		    ct:log("ssl:listen on port ~p failed: ~p",[SSL_Port,SSL_Other]),
		    {fail, "ssl:listen/2 failed"}
	    after 5000 ->
		    {fail, "Waiting for ssl:listen timeout"}
	    end;
	false ->
	    {skip, "ssl not available"}
    end;

init_per_testcase(_, Config) ->
    case gen_tcp:listen(0, proplists:get_value(listen_opts,Config)) of
	{ok,LSock} ->
	    {ok,{_,Port}} = inet:sockname(LSock),
	    [{listen_socket,LSock},
	     {listen_port,Port}
	     | Config];
	Other ->
	    {fail, Other}
    end.


end_per_testcase(_TestCase, Config) ->
    catch gen_tcp:close( proplists:get_value(listen_socket, Config) ).

%%%================================================================
%%%
%%% Test cases
%%% 
%%%----------------------------------------------------------------
tcp_connection(Config) ->
    Host = proplists:get_value(listen_host, Config),
    Port = proplists:get_value(listen_port, Config),
    Opts = proplists:get_value(connect_opts, Config),
    case eldap:open([Host], [{port,Port}|Opts]) of
	{ok,_H} ->
	    Sl = proplists:get_value(listen_socket, Config),
	    case gen_tcp:accept(Sl,1000) of
		{ok,_S} -> ok;
		{error,timeout} -> ct:fail("server side accept timeout",[])
	    end;
	Other -> ct:fail("eldap:open failed: ~p",[Other])
    end.

%%%----------------------------------------------------------------
ssl_connection(Config) ->
    Host = proplists:get_value(listen_host, Config),
    Port = proplists:get_value(ssl_listen_port, Config),
    Opts = proplists:get_value(connect_opts, Config),
    SSLOpts = proplists:get_value(ssl_connect_opts, Config),
    case eldap:open([Host], [{port,Port},{ssl,true},
			     {timeout,5000},
			     {sslopts,SSLOpts}|Opts]) of
	{ok,_H} -> ok;
	Other -> ct:fail("eldap:open failed: ~p",[Other])
    end.

%%%----------------------------------------------------------------
client_side_add_timeout(Config) ->
    client_timeout(
      fun(H) ->
	      eldap:add(H, "cn=Foo Bar,dc=host,dc=ericsson,dc=se",
			[{"objectclass", ["person"]},
			 {"cn", ["Foo Bar"]}, 
			 {"sn", ["Bar"]}, 
			 {"telephoneNumber", ["555-1232", "555-5432"]}])
      end, Config).

%%%----------------------------------------------------------------
client_side_bind_timeout(Config) ->
    client_timeout(
      fun(H) ->
	      eldap:simple_bind(H, anon, anon)
      end, Config).

%%%----------------------------------------------------------------
client_side_search_timeout(Config) ->
    client_timeout(
      fun(H) ->
	      eldap:search(H, [{base,"dc=host,dc=ericsson,dc=se"},
			       {filter, eldap:present("objectclass")},
			       {scope,  eldap:wholeSubtree()}])
      end, Config).

%%%----------------------------------------------------------------
client_side_start_tls_timeout(Config) ->
    client_timeout(
      fun(H) ->
	      eldap:start_tls(H, [])
      end, Config).

%%%----------------------------------------------------------------
tcp_connection_option(Config) -> 
    Host = proplists:get_value(listen_host, Config),
    Port = proplists:get_value(listen_port, Config),
    Opts = proplists:get_value(connect_opts, Config),
    Sl = proplists:get_value(listen_socket, Config),

    %% Make an option value to test.  The option must be implemented on all
    %% platforms that we test on.  Must check what the default value is
    %% so we don't happen to choose that particular value.
    {ok,[{linger,DefaultLinger}]} = inet:getopts(Sl, [linger]),
    TestLinger = case DefaultLinger of
		     {false,_} -> {true,5};
		     {true,_} -> {false,0}
		 end,

    case catch eldap:open([Host], 
			  [{port,Port},{tcpopts,[{linger,TestLinger}]}|Opts]) of
	{ok,H} ->
	    case gen_tcp:accept(Sl,1000) of
		{ok,_} -> 
		    case eldap:getopts(H, [{tcpopts,[linger]}]) of
			{ok,[{tcpopts,[{linger,ActualLinger}]}]} ->
			    case ActualLinger of
				TestLinger -> 
				    ok;
				DefaultLinger ->
				    ct:fail("eldap:getopts: 'linger' didn't change,"
					    " got ~p (=default) expected ~p",
					    [ActualLinger,TestLinger]);
				_ ->
				    ct:fail("eldap:getopts: bad 'linger', got ~p expected ~p",
					    [ActualLinger,TestLinger])
			    end;
			Other ->
			    ct:fail("eldap:getopts: bad result ~p",[Other])
		    end;
		{error,timeout} -> 
		    ct:fail("server side accept timeout",[])
	    end;

	Other ->
	    ct:fail("eldap:open failed: ~p",[Other])
    end.


%%%================================================================
%%%
%%% Private
%%% 

client_timeout(Fun, Config) ->
    Host = proplists:get_value(listen_host, Config),
    Port = proplists:get_value(listen_port, Config),
    Opts = proplists:get_value(connect_opts, Config),
    T = 1000,
    case eldap:open([Host], [{timeout,T},{port,Port}|Opts]) of
	{ok,H} -> 
	    T0 = now(),
	    {error,{gen_tcp_error,timeout}} = Fun(H),
	    T_op = diff(T0,now()),
	    ct:log("Time = ~p, Timeout spec = ~p",[T_op,T]),
	    if 
		T_op < T -> 
		    {fail, "Timeout too early"};
		true ->
		    ok
	    end;
		    
	Other -> ct:fail("eldap:open failed: ~p",[Other])
    end.

diff({M1,S1,U1},{M2,S2,U2}) ->
    ( ((M2-M1)*1000 + (S2-S1))*1000 + (U2-U1) ).
%%%----------------------------------------------------------------
init_ssl_certs_et_al(Config) ->
    try ssl:start()
    of
	R when R==ok ; R=={error,{already_started,ssl}} ->
	    try make_certs:all("/dev/null", 
			       filename:join(?config(data_dir,Config), "certs"))
	    of
		{ok,_} -> true;
		Other -> 
		    ct:comment("make_certs failed"),
		    ct:log("make_certs failed ~p", [Other]),
		    false
	    catch
		C:E -> 
		    ct:comment("make_certs crashed"),
		    ct:log("make_certs failed ~p:~p", [C,E]),
		    false
	    end;
	_ ->
	    false
    catch
	Error:Reason ->
	    ct:comment("ssl failed to start"),
	    ct:log("init_per_suite failed to start ssl Error=~p Reason=~p", [Error, Reason]),
	    false
    end.