diff options
author | Peter Andersson <[email protected]> | 2010-02-17 15:59:05 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2010-02-17 15:59:05 +0000 |
commit | 332591f03f7bc4585c8c108c192ab3bba6fec12c (patch) | |
tree | c3d06e8750d53d0f157d61cd4c5f991959a05a51 /lib/common_test/src | |
parent | f29538e8002cf0e37fa4f988fbf5484c46513bf4 (diff) | |
download | otp-332591f03f7bc4585c8c108c192ab3bba6fec12c.tar.gz otp-332591f03f7bc4585c8c108c192ab3bba6fec12c.tar.bz2 otp-332591f03f7bc4585c8c108c192ab3bba6fec12c.zip |
OTP-8311: Various updates and fixes in Common Test and Test Server
Diffstat (limited to 'lib/common_test/src')
-rw-r--r-- | lib/common_test/src/ct_framework.erl | 36 | ||||
-rw-r--r-- | lib/common_test/src/ct_run.erl | 12 | ||||
-rw-r--r-- | lib/common_test/src/ct_telnet.erl | 59 | ||||
-rw-r--r-- | lib/common_test/src/ct_telnet_client.erl | 179 | ||||
-rw-r--r-- | lib/common_test/src/ct_testspec.erl | 76 | ||||
-rw-r--r-- | lib/common_test/src/ct_util.hrl | 13 | ||||
-rw-r--r-- | lib/common_test/src/unix_telnet.erl | 39 |
7 files changed, 261 insertions, 153 deletions
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 8456251b29..ed8b564921 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-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% %% @@ -27,7 +27,7 @@ -export([init_tc/3, end_tc/3, get_suite/2, report/2, warn/1]). -export([error_notification/4]). --export([error_in_suite/1]). +-export([error_in_suite/1, ct_init_per_group/2, ct_end_per_group/2]). -include("ct_event.hrl"). -include("ct_util.hrl"). @@ -751,8 +751,15 @@ find_group(Mod, Name, Defs) -> end. make_conf(Mod, Name, Props, TestSpec) -> - {conf,[{name,Name}|Props], - {Mod,init_per_group},TestSpec,{Mod,end_per_group}}. + {InitConf,EndConf} = + case erlang:function_exported(Mod,init_per_group,2) of + true -> + {{Mod,init_per_group},{Mod,end_per_group}}; + false -> + {{?MODULE,ct_init_per_group}, + {?MODULE,ct_end_per_group}} + end, + {conf,[{name,Name}|Props],InitConf,TestSpec,EndConf}. get_all(Mod, ConfTests) -> @@ -916,6 +923,19 @@ check_multiple(Mod,Seq,TCs) -> error_in_suite(Config) -> Reason = test_server:lookup_config(error,Config), exit(Reason). + +%% 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.", + [GroupName]), + Config. + +ct_end_per_group(GroupName, _) -> + ct_logs:log("WARNING", "end_per_group/2 for ~w missing in suite, using default.", + [GroupName]), + ok. + %%%----------------------------------------------------------------- %%% @spec report(What,Data) -> ok diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index a1e2358578..6b1063f74c 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-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% %% @@ -1515,7 +1515,7 @@ run_make(Targets, TestDir0, Mod, UserInclude) -> debug_info], Result = if Mod == all ; Targets == helpmods -> - case (catch ct_make:all([noexec])) of + case (catch ct_make:all([noexec|ErlFlags])) of {'EXIT',_} = Failure -> Failure; MakeInfo -> diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl index c19d312f01..c6f5fd7df4 100644 --- a/lib/common_test/src/ct_telnet.erl +++ b/lib/common_test/src/ct_telnet.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-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% %% @@ -21,27 +21,28 @@ %%% %%% <p>Use this module to set up telnet connections, send commands and %%% perform string matching on the result. -%%% (See the <code>unix_telnet</code> manual page for information -%%% about how ct_telnet may be used specifically with unix hosts.)</p> +%%% See the <c>unix_telnet</c> manual page for information about how to use +%%% ct_telnet, and configure connections, specifically for unix hosts.</p> %%% <p>The following default values are defined in ct_telnet:</p> %%% <pre> %%% Connection timeout = 10 sec (time to wait for connection) %%% Command timeout = 10 sec (time to wait for a command to return) %%% Max no of reconnection attempts = 3 %%% Reconnection interval = 5 sek (time to wait in between reconnection attempts) -%%% </pre> +%%% Keep alive = true (will send NOP to the server every 10 sec if connection is idle)</pre> %%% <p>These parameters can be altered by the user with the following %%% configuration term:</p> %%% <pre> %%% {telnet_settings, [{connect_timeout,Millisec}, %%% {command_timeout,Millisec}, %%% {reconnection_attempts,N}, -%%% {reconnection_interval,Millisec}]}. -%%% </pre> +%%% {reconnection_interval,Millisec}, +%%% {keep_alive,Bool}]}.</pre> %%% <p><code>Millisec = integer(), N = integer()</code></p> %%% <p>Enter the <code>telnet_settings</code> term in a configuration %%% file included in the test and ct_telnet will retrieve the information -%%% automatically.</p> +%%% automatically. Note that <c>keep_alive</c> may be specified per connection if +%%% required. See <c>unix_telnet</c> for details.</p></doc> %%% @type connection_type() = telnet | ts1 | ts2 @@ -88,7 +89,9 @@ buffer=[], prompt=false, name, - target_mod,extra, + target_mod, + keep_alive, + extra, conn_to=?DEFAULT_TIMEOUT, com_to=?DEFAULT_TIMEOUT, reconns=?RECONNS, @@ -150,7 +153,7 @@ open(KeyOrName,ConnType,TargetMod) -> %%% name can only be closed with the handle value.</p> %%% %%% <p><code>TargetMod</code> is a module which exports the functions -%%% <code>connect(Ip,Port,Extra)</code> and <code>get_prompt_regexp()</code> +%%% <code>connect(Ip,Port,KeepAlive,Extra)</code> and <code>get_prompt_regexp()</code> %%% for the given <code>TargetType</code> (e.g. <code>unix_telnet</code>).</p> open(KeyOrName,ConnType,TargetMod,Extra) -> case ct:get_config({KeyOrName,ConnType}) of @@ -169,9 +172,18 @@ open(KeyOrName,ConnType,TargetMod,Extra) -> P -> {IP,P} end end, + KeepAlive = + case ct:get_config({KeyOrName,keep_alive}) of + undefined -> + case ct:get_config({telnet_settings,keep_alive}) of + undefined -> true; + Bool -> Bool + end; + Bool -> Bool + end, log(heading(open,{KeyOrName,ConnType}),"Opening connection to: ~p",[Addr1]), ct_gen_conn:start(KeyOrName,full_addr(Addr1,ConnType), - {TargetMod,Extra},?MODULE) + {TargetMod,KeepAlive,Extra},?MODULE) end. %%%----------------------------------------------------------------- @@ -373,14 +385,14 @@ expect(Connection,Patterns,Opts) -> %%%================================================================= %%% Callback functions %% @hidden -init(Name,{Ip,Port,Type},{TargetMod,Extra}) -> +init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) -> S0 = case ct:get_config(telnet_settings) of undefined -> #state{}; Settings -> set_telnet_defaults(Settings,#state{}) end, - case catch TargetMod:connect(Ip,Port,S0#state.conn_to,Extra) of + case catch TargetMod:connect(Ip,Port,S0#state.conn_to,KeepAlive,Extra) of {ok,TelnPid} -> log(heading(init,{Name,Type}), "Opened telnet connection\n" @@ -389,13 +401,15 @@ init(Name,{Ip,Port,Type},{TargetMod,Extra}) -> "Command timeout: ~p\n" "Reconnection attempts: ~p\n" "Reconnection interval: ~p\n" - "Connection timeout: ~p", + "Connection timeout: ~p\n" + "Keep alive: ~w", [Ip,Port,S0#state.com_to,S0#state.reconns, - S0#state.reconn_int,S0#state.conn_to]), + S0#state.reconn_int,S0#state.conn_to,KeepAlive]), {ok,TelnPid,S0#state{teln_pid=TelnPid, type=type(Type), name={Name,Type}, target_mod=TargetMod, + keep_alive=KeepAlive, extra=Extra, prx=TargetMod:get_prompt_regexp()}}; {'EXIT',Reason} -> @@ -415,6 +429,12 @@ set_telnet_defaults([{reconnection_attempts,Rs}|Ss],S) -> set_telnet_defaults(Ss,S#state{reconns=Rs}); set_telnet_defaults([{reconnection_interval,RInt}|Ss],S) -> set_telnet_defaults(Ss,S#state{reconn_int=RInt}); +set_telnet_defaults([{keep_alive,_}|Ss],S) -> + set_telnet_defaults(Ss,S); +set_telnet_defaults([Unknown|Ss],S) -> + log(heading(set_telnet_defaults,{telnet_settings,Unknown}), + "Bad element in telnet_settings: ~p",[Unknown]), + set_telnet_defaults(Ss,S); set_telnet_defaults([],S) -> S. @@ -527,10 +547,11 @@ handle_msg({expect,Pattern,Opts},State) -> reconnect({Ip,Port,_Type},State) -> reconnect(Ip,Port,State#state.reconns,State). reconnect(Ip,Port,N,State=#state{target_mod=TargetMod, + keep_alive=KeepAlive, extra=Extra, conn_to=ConnTo, reconn_int=ReconnInt}) -> - case TargetMod:connect(Ip,Port,ConnTo,Extra) of + case TargetMod:connect(Ip,Port,ConnTo,KeepAlive,Extra) of {ok, NewPid} -> {ok, NewPid, State#state{teln_pid=NewPid}}; Error when N==0 -> diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl index e460a50eac..1a12c5e343 100644 --- a/lib/common_test/src/ct_telnet_client.erl +++ b/lib/common_test/src/ct_telnet_client.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-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% %% @@ -32,13 +32,14 @@ -module(ct_telnet_client). --export([open/1, open/2, open/3, close/1]). +-export([open/1, open/2, open/3, open/4, close/1]). -export([send_data/2, get_data/1]). -define(DBG, false). -define(TELNET_PORT, 23). -define(OPEN_TIMEOUT,10000). +-define(IDLE_TIMEOUT,10000). %% telnet control characters -define(SE, 240). @@ -65,17 +66,20 @@ -define(TERMINAL_TYPE, 24). -define(WINDOW_SIZE, 31). --record(state,{get_data}). +-record(state,{get_data, keep_alive=true}). open(Server) -> - open(Server, ?TELNET_PORT, ?OPEN_TIMEOUT). + open(Server, ?TELNET_PORT, ?OPEN_TIMEOUT, true). open(Server, Port) -> - open(Server, Port, ?OPEN_TIMEOUT). + open(Server, Port, ?OPEN_TIMEOUT, true). open(Server, Port, Timeout) -> + open(Server, Port, Timeout, true). + +open(Server, Port, Timeout, KeepAlive) -> Self = self(), - Pid = spawn(fun() -> init(Self, Server, Port, Timeout) end), + Pid = spawn(fun() -> init(Self, Server, Port, Timeout, KeepAlive) end), receive {open,Pid} -> {ok,Pid}; @@ -100,20 +104,18 @@ get_data(Pid) -> %%%----------------------------------------------------------------- %%% Internal functions -init(Parent, Server, Port, Timeout) -> +init(Parent, Server, Port, Timeout, KeepAlive) -> case gen_tcp:connect(Server, Port, [list,{packet,0}], Timeout) of {ok,Sock} -> - dbg("Connected to: ~p\n", [Server]), + dbg("Connected to: ~p (port: ~w, keep_alive: ~w)\n", [Server,Port,KeepAlive]), send([?IAC,?DO,?SUPPRESS_GO_AHEAD], Sock), Parent ! {open,self()}, - loop(#state{get_data=10}, Sock, []), + loop(#state{get_data=10, keep_alive=KeepAlive}, Sock, []), gen_tcp:close(Sock); Error -> Parent ! {Error,self()} end. - - loop(State, Sock, Acc) -> receive {tcp_closed,_} -> @@ -137,21 +139,27 @@ loop(State, Sock, Acc) -> [] -> dbg("get_data nodata\n",[]), erlang:send_after(100,self(),{get_data_delayed,Pid}), - State#state{get_data=State#state.get_data - 1}; + if State#state.keep_alive == true -> + State#state{get_data=State#state.get_data - 1}; + State#state.keep_alive == false -> + State + end; _ -> Pid ! {data,lists:reverse(lists:append(Acc))}, State end, loop(NewState, Sock, []); {get_data_delayed,Pid} -> - NewState = case State#state.get_data of - 0 -> - send([?IAC,?DO,?NOP], Sock), - dbg("delayed after 1000\n",[]), - State#state{get_data=10}; - _ -> - State - end, + NewState = + case State of + #state{keep_alive = true, get_data = 0} -> + if Acc == [] -> send([?IAC,?NOP], Sock); + true -> ok + end, + State#state{get_data=10}; + _ -> + State + end, NewAcc = case erlang:is_process_alive(Pid) of true -> @@ -160,29 +168,38 @@ loop(State, Sock, Acc) -> false -> Acc end, - loop(NewState, Sock, NewAcc); - + loop(NewState, Sock, NewAcc); close -> dbg("Closing connection\n", []), gen_tcp:close(Sock), ok - after 1000 -> - case Acc of - [] -> % no data buffered - send([?IAC,?DO,?NOP], Sock), - dbg("after 1000\n",[]); - _ -> - true + after wait(State#state.keep_alive,?IDLE_TIMEOUT) -> + if + Acc == [] -> send([?IAC,?NOP], Sock); + true -> ok end, loop(State, Sock, Acc) end. +wait(true, Time) -> Time; +wait(false, _) -> infinity. + send(Data, Sock) -> - dbg("Sending: ~p\n", [Data]), + case Data of + [?IAC|_] = Cmd -> + cmd_dbg(Cmd); + _ -> + dbg("Sending: ~p\n", [Data]) + end, gen_tcp:send(Sock, Data), ok. -check_msg(Sock,[?IAC | Cs], Acc) -> +%% [IAC,IAC] = buffer data value 255 +check_msg(Sock, [?IAC,?IAC | T], Acc) -> + check_msg(Sock, T, [?IAC|Acc]); + +%% respond to a command +check_msg(Sock, [?IAC | Cs], Acc) -> case get_cmd(Cs) of {Cmd,Cs1} -> dbg("Got ", []), @@ -192,11 +209,15 @@ check_msg(Sock,[?IAC | Cs], Acc) -> error -> Acc end; -check_msg(Sock,[H|T],Acc) -> - check_msg(Sock,T,[H|Acc]); -check_msg(_Sock,[],Acc) -> + +%% buffer a data value +check_msg(Sock, [H|T], Acc) -> + check_msg(Sock, T, [H|Acc]); + +check_msg(_Sock, [], Acc) -> Acc. + %% Positive responses (WILL and DO). respond_cmd([?WILL,?ECHO], Sock) -> @@ -234,6 +255,11 @@ respond_cmd([?DO | Opt], Sock) -> cmd_dbg(R), gen_tcp:send(Sock, R); +%% Commands without options (which we ignore) + +respond_cmd(?NOP, _Sock) -> + ok; + %% Unexpected messages. respond_cmd([Cmd | Opt], _Sock) when Cmd >= 240, Cmd =< 255 -> @@ -246,7 +272,10 @@ respond_cmd([Cmd | Opt], _Sock) -> get_cmd([Cmd | Rest]) when Cmd == ?SB -> get_subcmd(Rest, []); -get_cmd([Cmd,Opt | Rest]) -> +get_cmd([Cmd | Rest]) when Cmd >= 240, Cmd =< 249 -> + {?NOP, Rest}; + +get_cmd([Cmd,Opt | Rest]) when Cmd >= 251, Cmd =< 254 -> {[Cmd,Opt], Rest}; get_cmd(_Other) -> @@ -259,46 +288,34 @@ get_subcmd([Opt | Rest], Acc) -> get_subcmd(Rest, [Opt | Acc]). -dbg(_Str,_Args) -> ok. -% if ?DBG -> io:format(_Str,_Args); -% true -> ok -% end. - -cmd_dbg(_Cmd) -> ok. -% if ?DBG -> -% case _Cmd of -% [?IAC|Cmd1] -> -% cmd_dbg(Cmd1); -% [Ctrl|Opts] -> -% CtrlStr = -% case Ctrl of -% ?DO -> "DO"; -% ?DONT -> "DONT"; -% ?WILL -> "WILL"; -% ?WONT -> "WONT"; -% _ -> "CMD" -% end, -% Opts1 = -% case Opts of -% [Opt] -> Opt; -% _ -> Opts -% end, -% io:format("~s(~w): ~w\n", [CtrlStr,Ctrl,Opts1]); -% Any -> -% io:format("Unexpected in cmd_dbg:~n~w~n",[Any]) -% end; -% true -> ok -% end. - - - - - - - - - - - - +dbg(_Str,_Args) -> + if ?DBG -> io:format(_Str,_Args); + true -> ok + end. +cmd_dbg(_Cmd) -> + if ?DBG -> + case _Cmd of + [?IAC|Cmd1] -> + cmd_dbg(Cmd1); + [Ctrl|Opts] -> + CtrlStr = + case Ctrl of + ?DO -> "DO"; + ?DONT -> "DONT"; + ?WILL -> "WILL"; + ?WONT -> "WONT"; + ?NOP -> "NOP"; + _ -> "CMD" + end, + Opts1 = + case Opts of + [Opt] -> Opt; + _ -> Opts + end, + io:format("~s(~w): ~w\n", [CtrlStr,Ctrl,Opts1]); + Any -> + io:format("Unexpected in cmd_dbg:~n~w~n",[Any]) + end; + true -> ok + end. diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl index 21a2f82a54..4378ec5a52 100644 --- a/lib/common_test/src/ct_testspec.erl +++ b/lib/common_test/src/ct_testspec.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2006-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% %% @@ -231,9 +231,11 @@ collect_tests_from_file(Specs,Nodes,Relaxed) when is_list(Nodes) -> catch collect_tests_from_file1(Specs,#testspec{nodes=NodeRefs},Relaxed). collect_tests_from_file1([Spec|Specs],TestSpec,Relaxed) -> + SpecDir = filename:dirname(filename:absname(Spec)), case file:consult(Spec) of {ok,Terms} -> - TestSpec1 = collect_tests(Terms,TestSpec,Relaxed), + TestSpec1 = collect_tests(Terms,TestSpec#testspec{spec_dir=SpecDir}, + Relaxed), collect_tests_from_file1(Specs,TestSpec1,Relaxed); {error,Reason} -> throw({error,{Spec,Reason}}) @@ -249,8 +251,11 @@ collect_tests_from_list(Terms,Relaxed) -> collect_tests_from_list(Terms,[node()],Relaxed). collect_tests_from_list(Terms,Nodes,Relaxed) when is_list(Nodes) -> + {ok,Cwd} = file:get_cwd(), NodeRefs = lists:map(fun(N) -> {undefined,N} end, Nodes), - case catch collect_tests(Terms,#testspec{nodes=NodeRefs},Relaxed) of + case catch collect_tests(Terms,#testspec{nodes=NodeRefs, + spec_dir=Cwd}, + Relaxed) of E = {error,_} -> E; TS -> @@ -265,17 +270,51 @@ collect_tests(Terms,TestSpec,Relaxed) -> put(relaxed,Relaxed), TestSpec1 = get_global(Terms,TestSpec), TestSpec2 = get_all_nodes(Terms,TestSpec1), + case catch evaluate(Terms,TestSpec2) of + {error,{Node,{M,F,A},Reason}} -> + io:format("Error! Common Test failed to evaluate ~w:~w/~w on ~w. " + "Reason: ~p~n~n", [M,F,A,Node,Reason]); + _ -> ok + end, add_tests(Terms,TestSpec2). +evaluate([{eval,NodeRef,{M,F,Args}}|Ts],Spec) -> + Node = ref2node(NodeRef,Spec#testspec.nodes), + case rpc:call(Node,M,F,Args) of + {badrpc,Reason} -> + throw({error,{Node,{M,F,length(Args)},Reason}}); + _ -> + ok + end, + evaluate(Ts,Spec); +evaluate([{eval,{M,F,Args}}|Ts],Spec) -> + case catch apply(M,F,Args) of + {'EXIT',Reason} -> + throw({error,{node(),{M,F,length(Args)},Reason}}); + _ -> + ok + end, + evaluate(Ts,Spec); +evaluate([],_Spec) -> + ok. + get_global([{alias,Ref,Dir}|Ts],Spec=#testspec{alias=Refs}) -> - get_global(Ts,Spec#testspec{alias=[{Ref,get_absname(Dir)}|Refs]}); + get_global(Ts,Spec#testspec{alias=[{Ref,get_absdir(Dir,Spec)}|Refs]}); get_global([{node,Ref,Node}|Ts],Spec=#testspec{nodes=Refs}) -> get_global(Ts,Spec#testspec{nodes=[{Ref,Node}|lists:keydelete(Node,2,Refs)]}); get_global([_|Ts],Spec) -> get_global(Ts,Spec); get_global([],Spec) -> Spec. -get_absname(TestDir) -> - AbsName = filename:absname(TestDir), +get_absfile(FullName,#testspec{spec_dir=SpecDir}) -> + File = filename:basename(FullName), + Dir = get_absname(filename:dirname(FullName),SpecDir), + filename:join(Dir,File). + +get_absdir(Dir,#testspec{spec_dir=SpecDir}) -> + get_absname(Dir,SpecDir). + +get_absname(TestDir,SpecDir) -> + AbsName = filename:absname(TestDir,SpecDir), TestDirName = filename:basename(AbsName), Path = filename:dirname(AbsName), TopDir = filename:basename(Path), @@ -345,16 +384,17 @@ list_nodes(#testspec{nodes=NodeRefs}) -> %% --- logdir --- add_tests([{logdir,all_nodes,Dir}|Ts],Spec) -> Dirs = Spec#testspec.logdir, - Tests = [{logdir,N,Dir} || N <- list_nodes(Spec), - lists:keymember(ref2node(N,Spec#testspec.nodes), - 1,Dirs) == false], + Tests = [{logdir,N,get_absdir(Dir,Spec)} || + N <- list_nodes(Spec), + lists:keymember(ref2node(N,Spec#testspec.nodes), + 1,Dirs) == false], add_tests(Tests++Ts,Spec); add_tests([{logdir,Nodes,Dir}|Ts],Spec) when is_list(Nodes) -> Ts1 = separate(Nodes,logdir,[Dir],Ts,Spec#testspec.nodes), add_tests(Ts1,Spec); add_tests([{logdir,Node,Dir}|Ts],Spec) -> Dirs = Spec#testspec.logdir, - Dirs1 = [{ref2node(Node,Spec#testspec.nodes),Dir} | + Dirs1 = [{ref2node(Node,Spec#testspec.nodes),get_absdir(Dir,Spec)} | lists:keydelete(ref2node(Node,Spec#testspec.nodes),1,Dirs)], add_tests(Ts,Spec#testspec{logdir=Dirs1}); add_tests([{logdir,Dir}|Ts],Spec) -> @@ -369,7 +409,7 @@ add_tests([{cover,Nodes,File}|Ts],Spec) when is_list(Nodes) -> add_tests(Ts1,Spec); add_tests([{cover,Node,File}|Ts],Spec) -> CoverFs = Spec#testspec.cover, - CoverFs1 = [{ref2node(Node,Spec#testspec.nodes),File} | + CoverFs1 = [{ref2node(Node,Spec#testspec.nodes),get_absfile(File,Spec)} | lists:keydelete(ref2node(Node,Spec#testspec.nodes),1,CoverFs)], add_tests(Ts,Spec#testspec{cover=CoverFs1}); add_tests([{cover,File}|Ts],Spec) -> @@ -385,7 +425,8 @@ add_tests([{config,Nodes,Files}|Ts],Spec) when is_list(Nodes) -> add_tests([{config,Node,[F|Fs]}|Ts],Spec) when is_list(F) -> Cfgs = Spec#testspec.config, Node1 = ref2node(Node,Spec#testspec.nodes), - add_tests([{config,Node,Fs}|Ts],Spec#testspec{config=[{Node1,F}|Cfgs]}); + add_tests([{config,Node,Fs}|Ts], + Spec#testspec{config=[{Node1,get_absfile(F,Spec)}|Cfgs]}); add_tests([{config,_Node,[]}|Ts],Spec) -> add_tests(Ts,Spec); add_tests([{config,Node,F}|Ts],Spec) -> @@ -451,7 +492,8 @@ add_tests([{include,Nodes,InclDirs}|Ts],Spec) when is_list(Nodes) -> add_tests([{include,Node,[D|Ds]}|Ts],Spec) when is_list(D) -> Dirs = Spec#testspec.include, Node1 = ref2node(Node,Spec#testspec.nodes), - add_tests([{include,Node,Ds}|Ts],Spec#testspec{include=[{Node1,D}|Dirs]}); + add_tests([{include,Node,Ds}|Ts], + Spec#testspec{include=[{Node1,get_absdir(D,Spec)}|Dirs]}); add_tests([{include,_Node,[]}|Ts],Spec) -> add_tests(Ts,Spec); add_tests([{include,Node,D}|Ts],Spec) -> diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl index 94ae2625cf..c1dc14f943 100644 --- a/lib/common_test/src/ct_util.hrl +++ b/lib/common_test/src/ct_util.hrl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-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% %% @@ -27,7 +27,8 @@ address, callback}). --record(testspec, {nodes=[], +-record(testspec, {spec_dir, + nodes=[], logdir=["."], cover=[], config=[], diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl index 14a70e9d22..25b9d4d5d2 100644 --- a/lib/common_test/src/unix_telnet.erl +++ b/lib/common_test/src/unix_telnet.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-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% %% @@ -23,10 +23,10 @@ %%% <p>It requires the following entry in the config file:</p> %%% <pre> %%% {unix,[{telnet,HostNameOrIpAddress}, -%%% {port,PortNum}, +%%% {port,PortNum}, % optional %%% {username,UserName}, -%%% {password,Password}]}. -%%% </pre> +%%% {password,Password}, +%%% {keep_alive,Bool}]}. % optional</pre> %%% %%% <p>To talk telnet to the host specified by %%% <code>HostNameOrIpAddress</code>, use the interface functions in @@ -38,8 +38,14 @@ %%% <p>or</p> %%% <pre> ct:require(Name,{unix,[telnet,username,password]}).</pre> %%% +%%% <p>The "keep alive" activity (i.e. that Common Test sends NOP to the server +%%% every 10 seconds if the connection is idle) may be enabled or disabled for one +%%% particular connection as described here. It may be disabled for all connections +%%% using <c>telnet_settings</c> (see <c>ct_telnet</c>).</p> +%%% %%% <p>Note that the <code>{port,PortNum}</code> tuple is optional and if -%%% omitted, default telnet port 23 will be used.</p> +%%% omitted, default telnet port 23 will be used. Also the <c>keep_alive</c> tuple +%%% is optional, and the value defauls to true (enabled).</p> %%% %%% @see ct %%% @see ct_telnet @@ -48,7 +54,7 @@ -compile(export_all). %% Callbacks for ct_telnet.erl --export([connect/4,get_prompt_regexp/0]). +-export([connect/5,get_prompt_regexp/0]). -import(ct_telnet,[start_log/1,cont_log/2,end_log/0]). -define(username,"login: "). @@ -70,10 +76,11 @@ get_prompt_regexp() -> %%%----------------------------------------------------------------- %%% @hidden -%%% @spec connect(Ip,Port,Timeout,Extra) -> {ok,Handle} | {error,Reason} +%%% @spec connect(Ip,Port,Timeout,KeepAlive,Extra) -> {ok,Handle} | {error,Reason} %%% Ip = string() | {integer(),integer(),integer(),integer()} %%% Port = integer() %%% Timeout = integer() +%%% KeepAlive = bool() %%% Extra = {Username,Password} %%% Username = string() %%% Password = string() @@ -82,23 +89,23 @@ get_prompt_regexp() -> %%% @doc Callback for ct_telnet.erl. %%% %%% <p>Setup telnet connection to a UNIX host.</p> -connect(Ip,Port,Timeout,Extra) -> +connect(Ip,Port,Timeout,KeepAlive,Extra) -> case Extra of {Username,Password} -> - connect(Ip,Port,Timeout,Username,Password); + connect1(Ip,Port,Timeout,KeepAlive,Username,Password); Name -> case get_username_and_password(Name) of {ok,{Username,Password}} -> - connect(Ip,Port,Timeout,Username,Password); + connect1(Ip,Port,Timeout,KeepAlive,Username,Password); Error -> Error end end. -connect(Ip,Port,Timeout,Username,Password) -> +connect1(Ip,Port,Timeout,KeepAlive,Username,Password) -> start_log("unix_telnet:connect"), Result = - case ct_telnet_client:open(Ip,Port,Timeout) of + case ct_telnet_client:open(Ip,Port,Timeout,KeepAlive) of {ok,Pid} -> case ct_telnet:silent_teln_expect(Pid,[],[prompt],?prx,[]) of {ok,{prompt,?username},_} -> |