Date: Tue, 13 Apr 2010 09:11:59 +0200
Subject: Change monitor_master option to false by default
---
lib/common_test/src/ct_master.erl | 5 ++---
lib/common_test/src/ct_slave.erl | 4 ++--
2 files changed, 4 insertions(+), 5 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_master.erl b/lib/common_test/src/ct_master.erl
index b14e7527e5..ecf516bd98 100644
--- a/lib/common_test/src/ct_master.erl
+++ b/lib/common_test/src/ct_master.erl
@@ -710,12 +710,11 @@ start_nodes([{NodeName, Options}|Rest])->
Host=list_to_atom(HostS),
{value, {callback_module, Callback}, Options2}=
lists:keytake(callback_module, 1, Options),
- io:format("Starting node ~p on host ~p with callback ~p...~n", [Node, Host, Callback]),
case Callback:start(Host, Node, Options2) of
{ok, NodeName} ->
- io:format("Node ~p started successfully~n", [NodeName]);
+ io:format("Node ~p started successfully with callback ~p~n", [NodeName,Callback]);
{error, Reason, _NodeName} ->
- io:format("Failed to start node ~p! Reason: ~p~n", [NodeName, Reason])
+ io:format("Failed to start node ~p with callback ~p! Reason: ~p~n", [NodeName, Callback, Reason])
end,
start_nodes(Rest).
diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl
index 09d8820731..476815895c 100644
--- a/lib/common_test/src/ct_slave.erl
+++ b/lib/common_test/src/ct_slave.erl
@@ -134,7 +134,7 @@ start(Host, Node)->
%%%
%%%
%%% Option monitor_master
specifies, if the slave node should be
-%%% stopped in case of master node stop. Defaults to true.
+%%% stopped in case of master node stop. Defaults to false.
%%%
%%% Option kill_if_fail
specifies, if the slave node should be
%%% killed in case of a timeout during initialization or startup.
@@ -222,7 +222,7 @@ fetch_options(Options)->
InitTimeout = get_option_value(init_timeout, Options, 1),
StartupTimeout = get_option_value(startup_timeout, Options, 1),
StartupFunctions = get_option_value(startup_functions, Options, []),
- Monitor = get_option_value(monitor_master, Options, true),
+ Monitor = get_option_value(monitor_master, Options, false),
KillIfFail = get_option_value(kill_if_fail, Options, true),
ErlFlags = get_option_value(erl_flags, Options, []),
#options{username=UserName, password=Password,
--
cgit v1.2.3
From 1327bd8956b2d0f6b5a9201ce9ecf361f94733aa Mon Sep 17 00:00:00 2001
From: Andrey Pampukha
Date: Mon, 19 Apr 2010 17:28:07 +0200
Subject: Move 'node_start' and 'eval' terms into new 'init' term
node_start+eval -> init(node_start, eval)
Also include some documentation updates.
---
lib/common_test/src/ct_config_xml.erl | 3 -
lib/common_test/src/ct_master.erl | 113 ++++++++++++++++++-------
lib/common_test/src/ct_slave.erl | 1 -
lib/common_test/src/ct_testspec.erl | 155 +++++++++++++---------------------
lib/common_test/src/ct_util.hrl | 2 +-
5 files changed, 141 insertions(+), 133 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_config_xml.erl b/lib/common_test/src/ct_config_xml.erl
index 111d1426c9..4ced80aeac 100755
--- a/lib/common_test/src/ct_config_xml.erl
+++ b/lib/common_test/src/ct_config_xml.erl
@@ -24,9 +24,6 @@
-module(ct_config_xml).
-export([read_config/1, check_parameter/1]).
-% DEBUG ONLY
--export([list_to_term/1]).
-
% read config file
read_config(ConfigFile) ->
case catch do_read_xml_config(ConfigFile) of
diff --git a/lib/common_test/src/ct_master.erl b/lib/common_test/src/ct_master.erl
index ecf516bd98..6cabe4c7a2 100644
--- a/lib/common_test/src/ct_master.erl
+++ b/lib/common_test/src/ct_master.erl
@@ -101,12 +101,12 @@ run([TS|TestSpecs],AllowUserTerms,InclNodes,ExclNodes) when is_list(TS),
TSRec=#testspec{logdir=AllLogDirs,
config=StdCfgFiles,
userconfig=UserCfgFiles,
- node_start=AllNSOpts,
+ init=AllInitOpts,
event_handler=AllEvHs} ->
AllCfgFiles = {StdCfgFiles, UserCfgFiles},
RunSkipPerNode = ct_testspec:prepare_tests(TSRec),
RunSkipPerNode2 = exclude_nodes(ExclNodes,RunSkipPerNode),
- run_all(RunSkipPerNode2,AllLogDirs,AllCfgFiles,AllEvHs,[],[],AllNSOpts,TS1)
+ run_all(RunSkipPerNode2,AllLogDirs,AllCfgFiles,AllEvHs,[],[],AllInitOpts,TS1)
end,
[{TS,Result} | run(TestSpecs,AllowUserTerms,InclNodes,ExclNodes)];
run([],_,_,_) ->
@@ -162,12 +162,12 @@ run_on_node([TS|TestSpecs],AllowUserTerms,Node) when is_list(TS),is_atom(Node) -
{error,Reason};
TSRec=#testspec{logdir=AllLogDirs,
config=StdCfgFiles,
- node_start=AllNSOpts,
+ init=AllInitOpts,
userconfig=UserCfgFiles,
event_handler=AllEvHs} ->
AllCfgFiles = {StdCfgFiles, UserCfgFiles},
{Run,Skip} = ct_testspec:prepare_tests(TSRec,Node),
- run_all([{Node,Run,Skip}],AllLogDirs,AllCfgFiles,AllEvHs,[],[],AllNSOpts,TS1)
+ run_all([{Node,Run,Skip}],AllLogDirs,AllCfgFiles,AllEvHs,[],[],AllInitOpts,TS1)
end,
[{TS,Result} | run_on_node(TestSpecs,AllowUserTerms,Node)];
run_on_node([],_,_) ->
@@ -189,7 +189,7 @@ run_on_node(TestSpecs,Node) ->
run_all([{Node,Run,Skip}|Rest],AllLogDirs,
{AllStdCfgFiles, AllUserCfgFiles}=AllCfgFiles,
- AllEvHs,NodeOpts,LogDirs,NSOptions,Specs) ->
+ AllEvHs,NodeOpts,LogDirs,InitOptions,Specs) ->
LogDir =
lists:foldl(fun({N,Dir},_Found) when N == Node ->
Dir;
@@ -221,15 +221,15 @@ run_all([{Node,Run,Skip}|Rest],AllLogDirs,
{logdir,LogDir},
{config,StdCfgFiles},
{event_handler,EvHs}] ++ UserCfgFiles},
- run_all(Rest,AllLogDirs,AllCfgFiles,AllEvHs,[NO|NodeOpts],[LogDir|LogDirs],NSOptions,Specs);
-run_all([],AllLogDirs,_,AllEvHs,NodeOpts,LogDirs,NSOptions,Specs) ->
+ run_all(Rest,AllLogDirs,AllCfgFiles,AllEvHs,[NO|NodeOpts],[LogDir|LogDirs],InitOptions,Specs);
+run_all([],AllLogDirs,_,AllEvHs,NodeOpts,LogDirs,InitOptions,Specs) ->
Handlers = [{H,A} || {Master,H,A} <- AllEvHs, Master == master],
MasterLogDir = case lists:keysearch(master,1,AllLogDirs) of
{value,{_,Dir}} -> Dir;
false -> "."
end,
log(tty,"Master Logdir","~s",[MasterLogDir]),
- start_master(lists:reverse(NodeOpts),Handlers,MasterLogDir,LogDirs,NSOptions,Specs),
+ start_master(lists:reverse(NodeOpts),Handlers,MasterLogDir,LogDirs,InitOptions,Specs),
ok.
@@ -269,15 +269,15 @@ progress() ->
start_master(NodeOptsList) ->
start_master(NodeOptsList,[],".",[],[],[]).
-start_master(NodeOptsList,EvHandlers,MasterLogDir,LogDirs,NSOptions,Specs) ->
+start_master(NodeOptsList,EvHandlers,MasterLogDir,LogDirs,InitOptions,Specs) ->
Master = spawn_link(?MODULE,init_master,[self(),NodeOptsList,EvHandlers,
- MasterLogDir,LogDirs,NSOptions,Specs]),
+ MasterLogDir,LogDirs,InitOptions,Specs]),
receive
{Master,Result} -> Result
end.
%%% @hidden
-init_master(Parent,NodeOptsList,EvHandlers,MasterLogDir,LogDirs,NSOptions,Specs) ->
+init_master(Parent,NodeOptsList,EvHandlers,MasterLogDir,LogDirs,InitOptions,Specs) ->
case whereis(ct_master) of
undefined ->
register(ct_master,self()),
@@ -330,11 +330,10 @@ init_master(Parent,NodeOptsList,EvHandlers,MasterLogDir,LogDirs,NSOptions,Specs)
Pid when is_pid(Pid) ->
ok
end,
- init_master1(Parent,NodeOptsList,NSOptions,LogDirs).
+ init_master1(Parent,NodeOptsList,InitOptions,LogDirs).
-init_master1(Parent,NodeOptsList,NSOptions,LogDirs) ->
- start_nodes(NSOptions),
- {Inaccessible,NodeOptsList1} = ping_nodes(NodeOptsList,[],[]),
+init_master1(Parent,NodeOptsList,InitOptions,LogDirs) ->
+ {Inaccessible,NodeOptsList1,InitOptions1} = init_nodes(NodeOptsList,InitOptions),
case Inaccessible of
[] ->
init_master2(Parent,NodeOptsList,LogDirs);
@@ -348,7 +347,7 @@ init_master1(Parent,NodeOptsList,NSOptions,LogDirs) ->
"Proceeding without: ~p",[Inaccessible]),
init_master2(Parent,NodeOptsList1,LogDirs);
"r\n" ->
- init_master1(Parent,NodeOptsList,NSOptions,LogDirs);
+ init_master1(Parent,NodeOptsList,InitOptions1,LogDirs);
_ ->
log(html,"Aborting Tests","",[]),
ct_master_event:stop(),
@@ -559,6 +558,9 @@ get_pid(Node,NodeCtrlPids) ->
undefined
end.
+ping_nodes(NodeOptions)->
+ ping_nodes(NodeOptions, [], []).
+
ping_nodes([NO={Node,_Opts}|NOs],Inaccessible,NodeOpts) ->
case net_adm:ping(Node) of
pong ->
@@ -702,21 +704,72 @@ reply(Result,To) ->
To ! {self(),Result},
ok.
-start_nodes([])->
- ok;
-start_nodes([{NodeName, Options}|Rest])->
- [NodeS,HostS]=string:tokens(atom_to_list(NodeName), "@"),
- Node=list_to_atom(NodeS),
- Host=list_to_atom(HostS),
- {value, {callback_module, Callback}, Options2}=
- lists:keytake(callback_module, 1, Options),
- case Callback:start(Host, Node, Options2) of
- {ok, NodeName} ->
- io:format("Node ~p started successfully with callback ~p~n", [NodeName,Callback]);
- {error, Reason, _NodeName} ->
- io:format("Failed to start node ~p with callback ~p! Reason: ~p~n", [NodeName, Callback, Reason])
+init_nodes(NodeOptions, InitOptions)->
+ ping_nodes(NodeOptions),
+ start_nodes(InitOptions),
+ eval_on_nodes(InitOptions),
+ {Inaccessible, NodeOptions1}=ping_nodes(NodeOptions),
+ InitOptions1 = filter_accessible(InitOptions, Inaccessible),
+ {Inaccessible, NodeOptions1, InitOptions1}.
+
+% only nodes which are inaccessible now, should be initiated later
+filter_accessible(InitOptions, Inaccessible)->
+ [{Node,Option}||{Node,Option}<-InitOptions, lists:member(Node, Inaccessible)].
+
+start_nodes(InitOptions)->
+ lists:foreach(fun({NodeName, Options})->
+ [NodeS,HostS]=string:tokens(atom_to_list(NodeName), "@"),
+ Node=list_to_atom(NodeS),
+ Host=list_to_atom(HostS),
+ HasNodeStart = lists:keymember(node_start, 1, Options),
+ IsAlive = lists:member(NodeName, nodes()),
+ case {HasNodeStart, IsAlive} of
+ {false, false}->
+ io:format("WARNING: Node ~p is not alive but has no node_start option~n", [NodeName]);
+ {false, true}->
+ io:format("Node ~p is alive~n", [NodeName]);
+ {true, false}->
+ {node_start, NodeStart} = lists:keyfind(node_start, 1, Options),
+ {value, {callback_module, Callback}, NodeStart2}=
+ lists:keytake(callback_module, 1, NodeStart),
+ case Callback:start(Host, Node, NodeStart2) of
+ {ok, NodeName} ->
+ io:format("Node ~p started successfully with callback ~p~n", [NodeName,Callback]);
+ {error, Reason, _NodeName} ->
+ io:format("Failed to start node ~p with callback ~p! Reason: ~p~n", [NodeName, Callback, Reason])
+ end;
+ {true, true}->
+ io:format("WARNING: Node ~p is alive but has node_start option~n", [NodeName])
+ end
+ end,
+ InitOptions).
+
+eval_on_nodes(InitOptions)->
+ lists:foreach(fun({NodeName, Options})->
+ HasEval = lists:keymember(eval, 1, Options),
+ IsAlive = lists:member(NodeName, nodes()),
+ case {HasEval, IsAlive} of
+ {false,_}->
+ ok;
+ {true,false}->
+ io:format("WARNING: Node ~p is not alive but has eval option ~n", [NodeName]);
+ {true,true}->
+ {eval, MFAs} = lists:keyfind(eval, 1, Options),
+ evaluate(NodeName, MFAs)
+ end
end,
- start_nodes(Rest).
+ InitOptions).
+
+evaluate(Node, [{M,F,A}|MFAs])->
+ case rpc:call(Node, M, F, A) of
+ {badrpc,Reason}->
+ io:format("WARNING: Failed to call ~p:~p/~p on node ~p due to ~p~n", [M,F,length(A),Node,Reason]);
+ Result->
+ io:format("Called ~p:~p/~p on node ~p, result: ~p~n", [M,F,length(A),Node,Result])
+ end,
+ evaluate(Node, MFAs);
+evaluate(_Node, [])->
+ ok.
%cast(Msg) ->
% cast(whereis(ct_master),Msg).
diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl
index 476815895c..22cb17e55d 100644
--- a/lib/common_test/src/ct_slave.erl
+++ b/lib/common_test/src/ct_slave.erl
@@ -359,7 +359,6 @@ get_cmd(Node, Flags)->
spawn_local_node(Node, Options)->
ErlFlags = Options#options.erl_flags,
Cmd = get_cmd(Node, ErlFlags),
- %io:format("Running cmd: ~p~n", [Cmd]),
open_port({spawn, Cmd}, [stream]).
% start crypto and ssh if not yet started
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index db3efb16e8..4e34c1513e 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -270,52 +270,8 @@ collect_tests(Terms,TestSpec,Relaxed) ->
put(relaxed,Relaxed),
TestSpec1 = get_global(Terms,TestSpec),
TestSpec2 = get_all_nodes(Terms,TestSpec1),
- % filter out node_start options and save them into the specification
- {Terms2, TestSpec3} = filter_nodestart_specs(Terms, [], TestSpec2),
- % only save the 'global' evals and evals for nodes which have no node_start
- {Terms3, TestSpec4} = filter_evals(Terms2, [], TestSpec3),
- % after evaluation, only valid terms exist in the specification list
- Terms4 = case catch evaluate(Terms3, [], TestSpec4) 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]),
- Terms3;
- NewTerms -> NewTerms
- end,
- add_tests(Terms4,TestSpec4).
-
-evaluate([{eval,Node,[{_,_,_}|_]=Mfas}|Ts],NewTerms,Spec)->
- EvalTerms = lists:map(fun(Mfa)->
- {eval, Node, Mfa}
- end,
- Mfas),
- evaluate([EvalTerms|Ts], NewTerms, Spec);
-evaluate([{eval,[{_,_,_}|_]=Mfas}|Ts],NewTerms,Spec)->
- EvalTerms = lists:map(fun(Mfa)->
- {eval, Mfa}
- end,
- Mfas),
- evaluate([EvalTerms|Ts], NewTerms, Spec);
-evaluate([{eval,Node,{M,F,Args}}|Ts],NewTerms,Spec) ->
- case rpc:call(Node,M,F,Args) of
- {badrpc,Reason} ->
- throw({error,{Node,{M,F,length(Args)},Reason}});
- _ ->
- ok
- end,
- evaluate(Ts,NewTerms,Spec);
-evaluate([{eval,{M,F,Args}}|Ts],NewTerms,Spec) ->
- case catch apply(M,F,Args) of
- {'EXIT',Reason} ->
- throw({error,{node(),{M,F,length(Args)},Reason}});
- _ ->
- ok
- end,
- evaluate(Ts,NewTerms,Spec);
-evaluate([Term|Ts], NewTerms, Spec)->
- evaluate(Ts, [Term|NewTerms], Spec);
-evaluate([], NewTerms, _Spec) ->
- NewTerms.
+ {Terms2, TestSpec3} = filter_init_terms(Terms, [], TestSpec2),
+ add_tests(Terms2,TestSpec3).
get_global([{alias,Ref,Dir}|Ts],Spec=#testspec{alias=Refs}) ->
get_global(Ts,Spec#testspec{alias=[{Ref,get_absdir(Dir,Spec)}|Refs]});
@@ -392,64 +348,67 @@ get_all_nodes([_|Ts],Spec) ->
get_all_nodes([],Spec) ->
Spec.
-filter_nodestart_specs([{node_start, Options}|Ts], NewTerms, Spec) ->
- filter_nodestart_specs([{node_start, list_nodes(Spec), Options}|Ts], NewTerms, Spec);
-filter_nodestart_specs([{node_start, NodeRef, Options}|Ts], NewTerms, Spec) when is_atom(NodeRef) ->
- filter_nodestart_specs([{node_start, [NodeRef], Options}|Ts], NewTerms, Spec);
-filter_nodestart_specs([{node_start, NodeRefs, Options}|Ts], NewTerms, Spec=#testspec{node_start=NodeStart})->
- Options2 = case lists:keyfind(callback_module, 1, Options) of
+filter_init_terms([{init, InitOptions}|Ts], NewTerms, Spec)->
+ filter_init_terms([{init, list_nodes(Spec), InitOptions}|Ts], NewTerms, Spec);
+filter_init_terms([{init, NodeRef, InitOptions}|Ts], NewTerms, Spec)
+ when is_atom(NodeRef)->
+ filter_init_terms([{init, [NodeRef], InitOptions}|Ts], NewTerms, Spec);
+filter_init_terms([{init, NodeRefs, InitOption}|Ts], NewTerms, Spec) when is_tuple(InitOption) ->
+ filter_init_terms([{init, NodeRefs, [InitOption]}|Ts], NewTerms, Spec);
+filter_init_terms([{init, [NodeRef|NodeRefs], InitOptions}|Ts], NewTerms, Spec=#testspec{init=InitData})->
+ NodeStartOptions = case lists:keyfind(node_start, 1, InitOptions) of
+ {node_start, NSOptions}->
+ case lists:keyfind(callback_module, 1, NSOptions) of
+ {callback_module, _Callback}->
+ NSOptions;
+ false->
+ [{callback_module, ct_slave}|NSOptions]
+ end;
false->
- [{callback_module, ct_slave}|Options];
- {callback_module, _Callback}->
- Options
+ []
end,
- NSSAdder = fun(NodeRef, NodeStartAcc)->
- Node=ref2node(NodeRef,Spec#testspec.nodes),
- case lists:keyfind(Node, 1, NodeStartAcc) of
- false->
- [{Node, Options2}|NodeStartAcc];
- {Node, OtherOptions}->
- io:format("~nWarning: There are other options defined for node ~p:"
- "~n~w, skipping ~n~w...~n", [Node, OtherOptions, Options2]),
- NodeStartAcc
- end
+ EvalTerms = case lists:keyfind(eval, 1, InitOptions) of
+ {eval, MFA} when is_tuple(MFA)->
+ [MFA];
+ {eval, MFAs} when is_list(MFAs)->
+ MFAs;
+ false->
+ []
end,
- NodeStart2 = lists:foldl(NSSAdder, NodeStart, NodeRefs),
- filter_nodestart_specs(Ts, NewTerms, Spec#testspec{node_start=NodeStart2});
-filter_nodestart_specs([Term|Ts], NewTerms, Spec)->
- filter_nodestart_specs(Ts, [Term|NewTerms], Spec);
-filter_nodestart_specs([], NewTerms, Spec) ->
+ Node = ref2node(NodeRef,Spec#testspec.nodes),
+ InitData2 = add_option({node_start, NodeStartOptions}, Node, InitData, true),
+ InitData3 = add_option({eval, EvalTerms}, Node, InitData2, false),
+ filter_init_terms([{init, NodeRefs, InitOptions}|Ts], NewTerms, Spec#testspec{init=InitData3});
+filter_init_terms([{init, [], _}|Ts], NewTerms, Spec)->
+ filter_init_terms(Ts, NewTerms, Spec);
+filter_init_terms([Term|Ts], NewTerms, Spec)->
+ filter_init_terms(Ts, [Term|NewTerms], Spec);
+filter_init_terms([], NewTerms, Spec)->
{NewTerms, Spec}.
-filter_evals([{eval,NodeRefs,Mfa}|Ts], NewTerms, Spec) when is_list(NodeRefs)->
- EvalTerms = lists:map(fun(NodeRef)->
- {eval, NodeRef, Mfa}
- end,
- NodeRefs),
- filter_evals(EvalTerms++Ts, NewTerms, Spec);
-filter_evals([{eval,NodeRef,{_,_,_}=Mfa}|Ts],NewTerms,Spec)->
- filter_evals([{eval,NodeRef,[Mfa]}|Ts],NewTerms,Spec);
-filter_evals([{eval,NodeRef,[{_,_,_}|_]=Mfas}=EvalTerm|Ts],
- NewTerms,Spec=#testspec{node_start=NodeStart})->
- Node=ref2node(NodeRef,Spec#testspec.nodes),
- case lists:keyfind(Node, 1, NodeStart) of
- false->
- filter_evals(Ts, [EvalTerm|NewTerms], Spec);
+add_option([], _, List, _)->
+ List;
+add_option({Key, Value}, Node, List, WarnIfExists) when is_list(Value)->
+ OldOptions = case lists:keyfind(Node, 1, List) of
{Node, Options}->
- Options2 = case lists:keyfind(startup_functions, 1, Options) of
- false->
- [{startup_functions, Mfas}|Options];
- {startup_functions, StartupFunctions}->
- lists:keyreplace(startup_functions, 1, Options,
- {startup_functions, StartupFunctions ++ Mfas})
- end,
- NodeStart2 = lists:keyreplace(Node, 1, NodeStart, {Node, Options2}),
- filter_evals(Ts, NewTerms, Spec#testspec{node_start=NodeStart2})
- end;
-filter_evals([Term|Ts], NewTerms, Spec)->
- filter_evals(Ts, [Term|NewTerms], Spec);
-filter_evals([], NewTerms, Spec)->
- {NewTerms, Spec}.
+ Options;
+ false->
+ []
+ end,
+ NewOption = case lists:keyfind(Key, 1, OldOptions) of
+ {Key, OldOption} when WarnIfExists, OldOption/=[]->
+ io:format("There is an option ~w=~w already defined for node ~p, skipping new ~w~n",
+ [Key, OldOption, Node, Value]),
+ OldOption;
+ {Key, OldOption}->
+ OldOption ++ Value;
+ false->
+ Value
+ end,
+ lists:keystore(Node, 1, List,
+ {Node, lists:keystore(Key, 1, OldOptions, {Key, NewOption})});
+add_option({Key, Value}, Node, List, WarnIfExists)->
+ add_option({Key, [Value]}, Node, List, WarnIfExists).
save_nodes(Nodes,Spec=#testspec{nodes=NodeRefs}) ->
NodeRefs1 =
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index 7c8fd67e1d..7ddb7d8c2b 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -29,7 +29,7 @@
-record(testspec, {spec_dir,
nodes=[],
- node_start=[],
+ init=[],
logdir=["."],
cover=[],
config=[],
--
cgit v1.2.3
From 215cdbcb6312caf49cd1fd1b37f0fb5842b5e13d Mon Sep 17 00:00:00 2001
From: Andrey Pampukha
Date: Wed, 28 Apr 2010 16:00:12 +0200
Subject: Documentation update
---
lib/common_test/src/ct_slave.erl | 8 ++++++++
lib/common_test/src/ct_testspec.erl | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl
index 22cb17e55d..d2a491e079 100644
--- a/lib/common_test/src/ct_slave.erl
+++ b/lib/common_test/src/ct_slave.erl
@@ -15,6 +15,14 @@
%% under the License.
%%
%% %CopyrightEnd%
+
+%%% @doc Common Test Framework functions for starting and stopping nodes for
+%%% Large Scale Testing.
+%%%
+%%% This module exports functions which are used by the Common Test Master
+%%% to start and stop "slave" nodes. It is the default callback module for the
+%%% {init, node_start}
term of the Test Specification.
+
%%----------------------------------------------------------------------
%% File : ct_slave.erl
%% Description : CT module for starting nodes for large-scale testing.
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index 4e34c1513e..582ce5e49f 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -17,7 +17,7 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework functions handlig test specifikations.
+%%% @doc Common Test Framework functions handlig test specifications.
%%%
%%% This module exports functions that are used within CT to
%%% scan and parse test specifikations.
--
cgit v1.2.3
From 5cf552a62742c6ddc974ba5491188576d512254e Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Mon, 24 May 2010 17:38:19 +0200
Subject: Add run_test program for Common Test
Common Test may now be started with the program run_test instead of the legacy shell script with the same name.
Minor updates have also been made to the Webtool application.
---
lib/common_test/src/ct.erl | 8 ++++----
lib/common_test/src/ct_config.erl | 0
lib/common_test/src/ct_config_plain.erl | 0
lib/common_test/src/ct_config_xml.erl | 0
lib/common_test/src/ct_repeat.erl | 2 +-
lib/common_test/src/ct_run.erl | 4 ++--
6 files changed, 7 insertions(+), 7 deletions(-)
mode change 100755 => 100644 lib/common_test/src/ct_config.erl
mode change 100755 => 100644 lib/common_test/src/ct_config_plain.erl
mode change 100755 => 100644 lib/common_test/src/ct_config_xml.erl
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index c32075332b..2d71a3812d 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -96,7 +96,7 @@
%%% install([{config,["config_node.ctc","config_user.ctc"]}])
.
%%%
%%% Note that this function is automatically run by the
-%%% run_test
script.
+%%% run_test
program.
install(Opts) ->
ct_run:install(Opts).
@@ -169,11 +169,11 @@ run(TestDirs) ->
%%% DecryptFile = string()
%%% Result = [TestResult] | {error,Reason}
%%% @doc Run tests as specified by the combination of options in Opts
.
-%%% The options are the same as those used with the run_test
script.
+%%% The options are the same as those used with the run_test
program.
%%% Note that here a TestDir
can be used to point out the path to
%%% a Suite
. Note also that the option testcase
%%% corresponds to the -case
option in the run_test
-%%% script. Configuration files specified in Opts
will be
+%%% program. Configuration files specified in Opts
will be
%%% installed automatically at startup.
run_test(Opts) ->
ct_run:run_test(Opts).
@@ -215,7 +215,7 @@ step(TestDir,Suite,Case,Opts) ->
%%%
%%% From this mode all test case support functions can be executed
%%% directly from the erlang shell. The interactive mode can also be
-%%% started from the unix command line with run_test -shell
+%%% started from the OS command line with run_test -shell
%%% [-config File...]
.
%%%
%%% If any functions using "required config data" (e.g. telnet or
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
old mode 100755
new mode 100644
diff --git a/lib/common_test/src/ct_config_plain.erl b/lib/common_test/src/ct_config_plain.erl
old mode 100755
new mode 100644
diff --git a/lib/common_test/src/ct_config_xml.erl b/lib/common_test/src/ct_config_xml.erl
old mode 100755
new mode 100644
diff --git a/lib/common_test/src/ct_repeat.erl b/lib/common_test/src/ct_repeat.erl
index 7ac6e045d7..2bd265caf9 100644
--- a/lib/common_test/src/ct_repeat.erl
+++ b/lib/common_test/src/ct_repeat.erl
@@ -20,7 +20,7 @@
%%% @doc Common Test Framework module that handles repeated test runs
%%%
%%%
This module exports functions for repeating tests. The following
-%%% script flags (or equivalent ct:run_test/1 options) are supported:
+%%% start flags (or equivalent ct:run_test/1 options) are supported:
%%% -until , StopTime = YYMoMoDDHHMMSS | HHMMSS
%%% -duration , DurTime = HHMMSS
%%% -force_stop
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 5fd89bc499..4f8e3e1a98 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -49,7 +49,7 @@
%%%-----------------------------------------------------------------
%%% @spec script_start() -> void()
%%%
-%%% @doc Start tests via the run_test script.
+%%% @doc Start tests via the run_test program or script.
%%%
%%% Example:
./run_test -config config.ctc -dir
%%% $TEST_DIR
@@ -390,7 +390,7 @@ script_start4(shell, _ConfigFiles, _EvHandlers, _Test, _Step, _Args, _LogDir) ->
%%%-----------------------------------------------------------------
%%% @spec script_usage() -> ok
-%%% @doc Print script usage information for run_test
.
+%%% @doc Print usage information for run_test
.
script_usage() ->
io:format("\n\nUsage:\n\n"),
io:format("Run tests in web based GUI:\n\n"
--
cgit v1.2.3
From 7b33aa92bb2558ba04a6436203638fd46592b8d2 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Thu, 27 May 2010 00:46:37 +0200
Subject: Improve documentation and fix minor problems
General documentation and code updates.
---
lib/common_test/src/ct_config_plain.erl | 2 +-
lib/common_test/src/ct_config_xml.erl | 5 ++--
lib/common_test/src/ct_run.erl | 46 +--------------------------------
3 files changed, 4 insertions(+), 49 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_config_plain.erl b/lib/common_test/src/ct_config_plain.erl
index 0fed58e45a..3fbc8af9fb 100644
--- a/lib/common_test/src/ct_config_plain.erl
+++ b/lib/common_test/src/ct_config_plain.erl
@@ -65,7 +65,7 @@ read_config(ConfigFile) ->
end
end.
-% check against existence of config file
+% check if config file exists
check_parameter(File)->
case filelib:is_file(File) of
true->
diff --git a/lib/common_test/src/ct_config_xml.erl b/lib/common_test/src/ct_config_xml.erl
index 4ced80aeac..8a6e75e635 100644
--- a/lib/common_test/src/ct_config_xml.erl
+++ b/lib/common_test/src/ct_config_xml.erl
@@ -33,7 +33,7 @@ read_config(ConfigFile) ->
{error, Error, ErroneousString}
end.
-% check against existence of the file
+% check file exists
check_parameter(File)->
case filelib:is_file(File) of
true->
@@ -107,8 +107,7 @@ transform_entity({Tag, String})->
throw(Error)
end.
-% transform a string with Erlang terms to the terms
-% stolen from trapexit.org :-)
+% transform a string with Erlang terms
list_to_term(String) ->
{ok, T, _} = erl_scan:string(String++"."),
case catch erl_parse:parse_term(T) of
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 4f8e3e1a98..021bda2951 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -101,11 +101,6 @@ script_start() ->
Res.
script_start1(Parent, Args) ->
- case lists:keymember(preload, 1, Args) of
- true -> preload();
- false -> ok
- end,
-
VtsOrShell =
case lists:keymember(vts, 1, Args) of
true ->
@@ -467,7 +462,7 @@ install(Opts, LogDir) ->
case whereis(ct_util_server) of
undefined ->
VarFile = variables_file_name(LogDir),
- io:format("Varfile=~p~n", [VarFile]),
+ %% io:format("Varfile=~p~n", [VarFile]),
case file:open(VarFile, [write]) of
{ok,Fd} ->
[io:format(Fd, "~p.\n", [Opt]) || Opt <- Opts],
@@ -1780,45 +1775,6 @@ stop_trace(true) ->
dbg:stop_clear();
stop_trace(false) ->
ok.
-
-preload() ->
- io:format("~nLoading Common Test and Test Server modules...~n~n"),
- preload_mod([ct_logs,
- ct_make,
- ct_telnet,
- ct,
- ct_master,
- ct_testspec,
- ct_cover,
- ct_master_event,
- ct_util,
- ct_event,
- ct_master_logs,
- ct_framework,
- teln,
- ct_ftp,
- ct_rpc,
- unix_telnet,
- ct_gen_conn,
- ct_line,
- ct_snmp,
- test_server_sup,
- test_server,
- test_server_ctrl,
- test_server_h,
- test_server_line,
- test_server_node]).
-
-preload_mod([M|Ms]) ->
- case code:is_loaded(M) of
- false ->
- {module,M} = code:load_file(M),
- preload_mod(Ms);
- _ ->
- ok
- end;
-preload_mod([]) ->
- ok.
ensure_atom(Atom) when is_atom(Atom) ->
Atom;
--
cgit v1.2.3
From c3a1e56608ebe08f1ddc07273d85ff9c2779de9b Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Thu, 3 Jun 2010 14:14:38 +0200
Subject: Implement support for user controllable timetrap parameters (multiply
and scale)
Documentation still missing.
---
lib/common_test/src/ct.erl | 39 +-
lib/common_test/src/ct_run.erl | 1226 +++++++++++++++++++++-------------------
2 files changed, 691 insertions(+), 574 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 2d71a3812d..57035719e2 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -64,7 +64,8 @@
print/1, print/2, print/3,
pal/1, pal/2, pal/3,
fail/1, comment/1,
- testcases/2, userdata/2, userdata/3]).
+ testcases/2, userdata/2, userdata/3,
+ sleep/1]).
%% New API for manipulating with config handlers
-export([add_config/2, remove_config/2]).
@@ -143,8 +144,9 @@ run(TestDirs) ->
%%% {allow_user_terms,Bool} | {logdir,LogDir} |
%%% {silent_connections,Conns} | {cover,CoverSpecFile} |
%%% {step,StepOpts} | {event_handler,EventHandlers} | {include,InclDirs} |
-%%% {auto_compile,Bool} | {repeat,N} | {duration,DurTime} |
-%%% {until,StopTime} | {force_stop,Bool} | {decrypt,DecryptKeyOrFile} |
+%%% {auto_compile,Bool} | {multiply_timetraps,M} | {scale_timetraps,Bool} |
+%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
+%%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} |
%%% {refresh_logs,LogDir} | {basic_html,Bool}
%%% CfgFiles = [string()] | string()
%%% TestDirs = [string()] | string()
@@ -161,6 +163,7 @@ run(TestDirs) ->
%%% EH = atom() | {atom(),InitArgs} | {[atom()],InitArgs}
%%% InitArgs = [term()]
%%% InclDirs = [string()] | string()
+%%% M = integer()
%%% N = integer()
%%% DurTime = string(HHMMSS)
%%% StopTime = string(YYMoMoDDHHMMSS) | string(HHMMSS)
@@ -812,8 +815,7 @@ decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) ->
%%%-----------------------------------------------------------------
-%%% @spec add_config(Callback, Config) ->
-%%% ok | {error, Reason}
+%%% @spec add_config(Callback, Config) -> ok | {error, Reason}
%%% Callback = atom()
%%% Config = string()
%%% Reason = term()
@@ -827,8 +829,7 @@ add_config(Callback, Config)->
ct_config:add_config(Callback, Config).
%%%-----------------------------------------------------------------
-%%% @spec remove_config(Callback, Config) ->
-%%% ok
+%%% @spec remove_config(Callback, Config) -> ok
%%% Callback = atom()
%%% Config = string()
%%% Reason = term()
@@ -836,5 +837,27 @@ add_config(Callback, Config)->
%%% @doc This function removes configuration variables (together with
%%% their aliases) which were loaded with specified callback module and
%%% configuration string.
-remove_config(Callback, Config)->
+remove_config(Callback, Config) ->
ct_config:remove_config(Callback, Config).
+
+%%%-----------------------------------------------------------------
+%%% @spec sleep(Time) -> ok
+%%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity
+%%% Hours = integer()
+%%% Mins = integer()
+%%% Secs = integer()
+%%% Millisecs = integer() | float()
+%%%
+%%% @doc This function, similar to timer:sleep/1, suspends the test
+%%% case for specified time. However, this function also multiplies
+%%% Time with the 'multiply_timetraps' value (if set) and under
+%%% certain circumstances also scales up the time automatically
+%%% if 'scale_timetraps' is set to true (default is false).
+sleep({hours,Hs}) ->
+ sleep(trunc(Hs * 1000 * 60 * 60));
+sleep({minutes,Ms}) ->
+ sleep(trunc(Ms * 1000 * 60));
+sleep({seconds,Ss}) ->
+ sleep(trunc(Ss * 1000));
+sleep(Time) ->
+ test_server:adjusted_sleep(Time).
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 021bda2951..96703031d2 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -24,7 +24,6 @@
-module(ct_run).
-
%% Script interface
-export([script_start/0,script_usage/0]).
@@ -46,11 +45,26 @@
-define(abs(Name), filename:absname(Name)).
-define(testdir(Name, Suite), ct_util:get_testdir(Name, Suite)).
+-record(opts, {vts,
+ shell,
+ cover,
+ coverspec,
+ step,
+ logdir,
+ config = [],
+ event_handlers = [],
+ include = [],
+ silent_connections,
+ multiply_timetraps = 1,
+ scale_timetraps = false,
+ testspecs = [],
+ tests}).
+
%%%-----------------------------------------------------------------
%%% @spec script_start() -> void()
%%%
%%% @doc Start tests via the run_test program or script.
-%%%
+%%%
%%% Example:
./run_test -config config.ctc -dir
%%% $TEST_DIR
%%%
@@ -60,12 +74,18 @@
script_start() ->
process_flag(trap_exit, true),
Args = merge_arguments(init:get_arguments()),
+ case proplists:get_value(help, Args) of
+ undefined -> script_start(Args);
+ _ -> script_usage()
+ end.
+
+script_start(Args) ->
Tracing = start_trace(Args),
- Res =
+ Res =
case ct_repeat:loop_test(script, Args) of
- false ->
+ false ->
{ok,Cwd} = file:get_cwd(),
- CTVsn =
+ CTVsn =
case filename:basename(code:lib_dir(common_test)) of
CTBase when is_list(CTBase) ->
case string:tokens(CTBase, "-") of
@@ -76,7 +96,7 @@ script_start() ->
io:format("~nCommon Test~s starting (cwd is ~s)~n~n", [CTVsn,Cwd]),
Self = self(),
Pid = spawn_link(fun() -> script_start1(Self, Args) end),
- receive
+ receive
{'EXIT',Pid,Reason} ->
case Reason of
{user_error,What} ->
@@ -101,287 +121,285 @@ script_start() ->
Res.
script_start1(Parent, Args) ->
- VtsOrShell =
- case lists:keymember(vts, 1, Args) of
- true ->
- vts;
- false ->
- case lists:keymember(shell, 1, Args) of
- true -> shell;
- false -> false
- end
- end,
- LogDir =
- case lists:keysearch(logdir, 1, Args) of
- {value,{logdir,[LogD]}} -> LogD;
- false -> "."
- end,
- EvHandlers =
- case lists:keysearch(event_handler, 1, Args) of
- {value,{event_handler,Handlers}} ->
- lists:map(fun(H) -> {list_to_atom(H),[]} end, Handlers);
- false ->
- []
- end,
- Cover =
- case lists:keysearch(cover, 1, Args) of
- {value,{cover,CoverFile}} ->
- {cover,?abs(CoverFile)};
- false ->
- false
- end,
-
- case lists:keysearch(ct_decrypt_key, 1, Args) of
- {value,{_,[DecryptKey]}} ->
+ %% read general start flags
+ Vts = get_start_opt(vts, true, Args),
+ Shell = get_start_opt(shell, true, Args),
+ Cover = get_start_opt(cover, fun(CoverFile) -> ?abs(CoverFile) end, Args),
+ LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args),
+ MultTT = get_start_opt(multiply_timetraps, fun(MT) -> MT end, Args),
+ ScaleTT = get_start_opt(scale_timetraps, fun(CT) -> CT end, Args),
+ EvHandlers = get_start_opt(event_handler,
+ fun(Handlers) ->
+ lists:map(fun(H) ->
+ {list_to_atom(H),[]}
+ end, Handlers) end,
+ [], Args),
+
+ %% check flags and set corresponding application env variables
+
+ %% ct_decrypt_key | ct_decrypt_file
+ case proplists:get_value(ct_decrypt_key, Args) of
+ [DecryptKey] ->
application:set_env(common_test, decrypt, {key,DecryptKey});
- false ->
- case lists:keysearch(ct_decrypt_file, 1, Args) of
- {value,{_,[DecryptFile]}} ->
- application:set_env(common_test, decrypt,
+ undefined ->
+ case proplists:get_value(ct_decrypt_file, Args) of
+ [DecryptFile] ->
+ application:set_env(common_test, decrypt,
{file,filename:absname(DecryptFile)});
- false ->
+ undefined ->
application:unset_env(common_test, decrypt)
end
end,
-
- case lists:keysearch(no_auto_compile, 1, Args) of
- {value,_} ->
- application:set_env(common_test, auto_compile, false);
- false ->
- application:set_env(common_test, auto_compile, true),
-
- InclDirs =
- case lists:keysearch(include,1,Args) of
- {value,{include,Incl}} when is_list(hd(Incl)) ->
- Incl;
- {value,{include,Incl}} when is_list(Incl) ->
- [Incl];
+ %% no_auto_compile + include
+ IncludeDirs =
+ case proplists:get_value(no_auto_compile, Args) of
+ undefined ->
+ application:set_env(common_test, auto_compile, true),
+ InclDirs =
+ case proplists:get_value(include, Args) of
+ {include,Incl} when is_list(hd(Incl)) ->
+ Incl;
+ {include,Incl} when is_list(Incl) ->
+ [Incl];
+ undefined ->
+ []
+ end,
+ case os:getenv("CT_INCLUDE_PATH") of
false ->
- []
- end,
- case os:getenv("CT_INCLUDE_PATH") of
- false ->
- application:set_env(common_test, include, InclDirs);
- CtInclPath ->
- InclDirs1 = string:tokens(CtInclPath,[$:,$ ,$,]),
- application:set_env(common_test, include, InclDirs1++InclDirs)
- end
+ application:set_env(common_test, include, InclDirs),
+ InclDirs;
+ CtInclPath ->
+ AllInclDirs =
+ string:tokens(CtInclPath,[$:,$ ,$,]) ++ InclDirs,
+ application:set_env(common_test, include, AllInclDirs),
+ AllInclDirs
+ end;
+ _ ->
+ application:set_env(common_test, auto_compile, false),
+ []
+ end,
+ %% basic_html - used by ct_logs
+ case proplists:get_value(basic_html, Args) of
+ undefined ->
+ application:set_env(common_test, basic_html, false);
+ _ ->
+ application:set_env(common_test, basic_html, true)
end,
- case lists:keysearch(basic_html, 1, Args) of
- {value,_} ->
- application:set_env(common_test, basic_html, true);
- false ->
- application:set_env(common_test, basic_html, false)
- end,
+ StartOpts = #opts({vts = Vts, shell = Shell, cover = Cover,
+ logdir = LogDir, event_handlers = EvHandlers,
+ include = IncludeDirs,
+ multiply_timetraps = MultTT,
+ scale_timetraps = ScaleTT}),
- Result =
- case lists:keysearch(refresh_logs, 1, Args) of
- {value,{refresh_logs,Refresh}} ->
- LogDir1 = case Refresh of
- [] -> LogDir;
- [RefreshDir] -> ?abs(RefreshDir)
- end,
- {ok,Cwd} = file:get_cwd(),
- file:set_cwd(LogDir1),
- timer:sleep(500), % give the shell time to print version etc
- io:nl(),
- case catch ct_logs:make_all_suites_index(refresh) of
- {'EXIT',ASReason} ->
- file:set_cwd(Cwd),
- {error,{all_suites_index,ASReason}};
- _ ->
- case catch ct_logs:make_all_runs_index(refresh) of
- {'EXIT',ARReason} ->
- file:set_cwd(Cwd),
- {error,{all_runs_index,ARReason}};
- _ ->
- file:set_cwd(Cwd),
- io:format("Logs in ~s refreshed!~n~n", [LogDir1]),
- timer:sleep(500), % time to flush io before quitting
- ok
- end
- end;
- false ->
- Config = ct_config:prepare_config_list(Args),
- case Config of
- [] ->
- case install([{config,[]},
- {event_handler,EvHandlers}],
- LogDir) of
- ok ->
- script_start2(VtsOrShell, [], EvHandlers,
- Args, LogDir, Cover);
- Error ->
- Error
- end;
- Config ->
- case lists:keysearch(spec, 1, Args) of
- false ->
- case check_and_install_configfiles(Config,
- LogDir, EvHandlers) of
- ok ->
- script_start2(VtsOrShell, Config,
- EvHandlers, Args, LogDir,
- Cover);
- Error ->
- Error
- end;
- _ ->
- script_start2(VtsOrShell, Config,
- EvHandlers, Args, LogDir, Cover)
- end
- end
- end,
+ %% check if log files should be refreshed or go on to run tests...
+ Result = run_or_refresh(StartOpts, Args),
+ %% send final results to starting process waiting in script_start/0
Parent ! {self(), Result}.
-check_and_install_configfiles(Configs, LogDir, EvHandlers) ->
- case ct_config:check_config_files(Configs) of
- false->
- install([{config,Configs},
- {event_handler,EvHandlers}], LogDir);
- {value, {error, {nofile, File}}} ->
- {error,{cant_read_config_file,File}};
- {value, {error, {wrong_config, Message}}}->
- {error,{wrong_config, Message}};
- {value, {error, {callback, File}}} ->
- {error,{cant_load_callback_module,File}}
+run_or_refresh(StartOpts = #opts{logdir = LogDir}, Args) ->
+ case proplists:get_value(refresh_logs, Args) of
+ undefined ->
+ script_start2(StartOpts, Args);
+ Refresh ->
+ LogDir1 = case Refresh of
+ [] -> which_logdir(LogDir);
+ [RefreshDir] -> ?abs(RefreshDir)
+ end,
+ {ok,Cwd} = file:get_cwd(),
+ file:set_cwd(LogDir1),
+ %% give the shell time to print version etc
+ timer:sleep(500),
+ io:nl(),
+ case catch ct_logs:make_all_suites_index(refresh) of
+ {'EXIT',ASReason} ->
+ file:set_cwd(Cwd),
+ {error,{all_suites_index,ASReason}};
+ _ ->
+ case catch ct_logs:make_all_runs_index(refresh) of
+ {'EXIT',ARReason} ->
+ file:set_cwd(Cwd),
+ {error,{all_runs_index,ARReason}};
+ _ ->
+ file:set_cwd(Cwd),
+ io:format("Logs in ~s refreshed!~n~n", [LogDir1]),
+ timer:sleep(500), % time to flush io before quitting
+ ok
+ end
+ end
end.
-script_start2(false, ConfigFiles, EvHandlers, Args, LogDir, Cover) ->
- case lists:keysearch(spec, 1, Args) of
- {value,{spec,[]}} ->
+script_start2(StartOpts = #opts{vts = undefined,
+ shell = undefined}, Args) ->
+ TestSpec = proplists:get_value(spec, Args),
+ Opts =
+ case TestSpec of
+ Specs when Specs =/= [], Specs =/= undefined ->
+ %% using testspec as input for test
+ Relaxed = get_start_opt(allow_user_terms, true, false, Args),
+ case catch ct_testspec:collect_tests_from_file(Specs, Relaxed) of
+ {error,Reason} ->
+ {error,Reason};
+ TS ->
+ SpecStartOpts = get_data_for_node(TS, node()),
+
+ LogDir = choose_val(StartOpts#opts.logdir,
+ SpecStartOpts#opts.logdir),
+
+ Cover = choose_val(StartOpts#opts.cover,
+ SpecStartOpts#opts.cover),
+ MultTT = choose_val(StartOpts#opts.multiply_timetraps,
+ SpecStartOpts#opts.multiply_timetraps),
+ ScaleTT = choose_val(StartOpts#opts.scale_timetraps,
+ SpecStartOpts#opts.scale_timetraps),
+ AllEvHs = merge_vals([StartOpts#opts.event_handlers,
+ SpecStartOpts#opts.event_handlers]),
+ AllInclude = merge_vals([StartOpts#opts.include,
+ SpecStartOpts#opts.include]),
+ application:set_env(common_test, include, AllInclude),
+
+ StartOpts#opts{testspecs = Specs,
+ cover = Cover,
+ logdir = LogDir,
+ config = SpecStartOpts#opts.config,
+ event_handlers = AllEvHs,
+ include = AllInclude,
+ multiply_timetraps = MultTT,
+ scale_timetraps = ScaleTT}
+ end;
+ _ ->
+ StartOpts
+ end,
+ %% read config/userconfig from start flags
+ InitConfig = ct_config:prepare_config_list(Args),
+ case TestSpec of
+ [] ->
{error,no_testspec_specified};
- {value,{spec,Specs}} ->
- Relaxed = lists:keymember(allow_user_terms, 1, Args),
- %% using testspec as input for test
- case catch ct_testspec:collect_tests_from_file(Specs, Relaxed) of
- {error,Reason} ->
- {error,Reason};
- TS ->
- {LogDir1,TSCoverFile,ConfigFiles1,EvHandlers1,Include1} =
- get_data_for_node(TS,node()),
- UserInclude =
- case application:get_env(common_test, include) of
- {ok,Include} -> Include++Include1;
- _ -> Include1
- end,
- application:set_env(common_test, include, UserInclude),
- LogDir2 = which_logdir(LogDir,LogDir1),
- CoverOpt = case {Cover,TSCoverFile} of
- {false,undef} -> [];
- {_,undef} -> [Cover];
- {false,_} -> [{cover,TSCoverFile}]
- end,
- case check_and_install_configfiles(
- ConfigFiles++ConfigFiles1, LogDir2,
- EvHandlers++EvHandlers1) of
- ok ->
- {Run,Skip} = ct_testspec:prepare_tests(TS, node()),
- do_run(Run, Skip, CoverOpt, Args, LogDir2);
- Error ->
- Error
- end
+ undefined -> % no testspec used
+ case check_and_install_configfiles(InitConfig,
+ which(logdir,Opts#opts.logdir),
+ Opts#opts.event_handlers) of
+ ok -> % go on read tests from start flags
+ script_start3(Opts#opts{config=InitConfig}, Args);
+ Error ->
+ Error
end;
- false ->
- script_start3(false, ConfigFiles, EvHandlers, Args, LogDir, Cover)
+ _ -> % testspec used
+ %% merge config from start flags with config from testspec
+ AllConfig = merge_vals([InitConfig, Opts#opts.config]),
+ case check_and_install_configfiles(AllConfig,
+ which(logdir,Opts#opts.logdir),
+ Opts#opts.event_handlers) of
+ ok -> % read tests from spec
+ {Run,Skip} = ct_testspec:prepare_tests(TS, node()),
+ do_run(Run, Skip, Opts#opts{config=AllConfig}, Args);
+ Error ->
+ Error
+ end
end;
-script_start2(VtsOrShell, ConfigFiles, EvHandlers, Args, LogDir, Cover) ->
- script_start3(VtsOrShell, ConfigFiles, EvHandlers, Args, LogDir, Cover).
-script_start3(VtsOrShell, ConfigFiles, EvHandlers, Args, LogDir, Cover) ->
- case lists:keysearch(dir, 1, Args) of
- {value,{dir,[]}} ->
- {error,no_dir_specified};
- {value,{dir,Dirs}} ->
- script_start4(VtsOrShell, ConfigFiles, EvHandlers, tests(Dirs),
- Cover, Args, LogDir);
+script_start2(StartOpts, Args) ->
+ script_start3(StartOpts, Args).
+
+check_and_install_configfiles(Configs, LogDir, EvHandlers) ->
+ case ct_config:check_config_files(Configs) of
false ->
- case lists:keysearch(suite, 1, Args) of
- {value,{suite,[]}} ->
+ install([{config,Configs},
+ {event_handler,EvHandlers}], LogDir);
+ {value,{error,{nofile,File}}} ->
+ {error,{cant_read_config_file,File}};
+ {value,{error,{wrong_config,Message}}}->
+ {error,{wrong_config,Message}};
+ {value,{error,{callback,File}}} ->
+ {error,{cant_load_callback_module,File}}
+ end.
+
+script_start3(StartOpts = #opts{cover = Cover}, Args) ->
+ case proplists:get_value(dir, Args) of
+ [] ->
+ {error,no_dir_specified};
+ Dirs when is_list(Dirs) ->
+ script_start4(StartOpts#opts{tests = tests(Dirs)}, Args);
+ undefined ->
+ case proplists:get_value(suite, Args) of
+ [] ->
{error,no_suite_specified};
- {value,{suite,Suites}} ->
- StepOrCover =
- case lists:keysearch(step, 1, Args) of
- {value,Step} -> Step;
- false -> Cover
- end,
- S2M = fun(S) ->
- {filename:dirname(S),
- list_to_atom(
- filename:rootname(filename:basename(S)))}
- end,
- DirMods = lists:map(S2M, Suites),
- {Specified,GroupsAndCases} =
- case {lists:keysearch(group, 1, Args),
- lists:keysearch('case', 1, Args)} of
- {{value,{_,Gs}},{value,{_,Cs}}} -> {true,Gs++Cs};
- {{value,{_,Gs}},_} -> {true,Gs};
- {_,{value,{_,Cs}}} -> {true,Cs};
- _ -> {false,[]}
- end,
- if Specified, length(GroupsAndCases) == 0 ->
- {error,no_case_or_group_specified};
- Specified, length(DirMods) > 1 ->
+ Suites when is_list(Suites) ->
+ StartOpts1 =
+ get_start_opt(step,
+ fun(Step) ->
+ StartOpts#opts{step = Step,
+ cover = undefined}
+ end, StartOpts, Args),
+ DirMods = [suite_to_test(S) || S <- Suites],
+ case groups_and_cases(proplist:get_value(group, Args),
+ proplist:get_value(testcase, Args)) of
+ Error = {error,_} ->
+ Error;
+ [] when DirMods =/= [] ->
+ Ts = tests(DirMods),
+ script_start4(StartOpts1#opts{tests = Ts}, Args);
+ GroupsAndCases when length(DirMods) == 1 ->
+ Ts = tests(DirMods, GroupsAndCases),
+ script_start4(StartOpts1#opts{tests = Ts}, Args);
+ [_,_|_] when length(DirMods) > 1 ->
{error,multiple_suites_and_cases};
- length(GroupsAndCases) > 0, length(DirMods) == 1 ->
- GsAndCs = lists:map(fun(C) -> list_to_atom(C) end,
- GroupsAndCases),
- script_start4(VtsOrShell, ConfigFiles, EvHandlers,
- tests(DirMods, GsAndCs),
- StepOrCover, Args, LogDir);
- not Specified, length(DirMods) > 0 ->
- script_start4(VtsOrShell, ConfigFiles, EvHandlers,
- tests(DirMods),
- StepOrCover, Args, LogDir);
- true ->
- {error,incorrect_suite_and_case_options}
+ _ ->
+ {error,incorrect_suite_option}
end;
- false when VtsOrShell=/=false ->
- script_start4(VtsOrShell, ConfigFiles, EvHandlers,
- [], Cover, Args, LogDir);
- false ->
- script_usage(),
- {error,incorrect_usage}
+ undefined ->
+ if StartOpts#opts.vts ; StartOpts#opts.shell ->
+ script_start4(StartOpts#opts{tests = []}, Args);
+ true ->
+ script_usage(),
+ {error,incorrect_usage}
+ end
end
end.
-script_start4(vts, ConfigFiles, EvHandlers, Tests, false, _Args, LogDir) ->
- vts:init_data(ConfigFiles, EvHandlers, ?abs(LogDir), Tests);
-script_start4(shell, ConfigFiles, EvHandlers, _Tests, false, Args, LogDir) ->
- Opts = [{config,ConfigFiles},{event_handler,EvHandlers}],
+script_start4(#opts{vts = true, config = Config, event_handler = EvHandlers,
+ tests = Tests, logdir = LogDir}, Args) ->
+ vts:init_data(Config, EvHandlers, ?abs(LogDir), Tests);
+
+script_start4(#opts{shell = true, config = Config, event_handlers = EvHandlers,
+ logdir = LogDir, testspecs = Specs}, Args) ->
+ InstallOpts = [{config,Config},{event_handler,EvHandlers}],
if ConfigFiles == [] ->
ok;
true ->
- io:format("\nInstalling: ~p\n\n", [ConfigFiles])
+ io:format("\nInstalling: ~p\n\n", [Config])
end,
- case install(Opts) of
+ case install(InstallOpts) of
ok ->
ct_util:start(interactive, LogDir),
- log_ts_names(Args),
+ log_ts_names(Specs),
io:nl(),
ok;
Error ->
Error
end;
-script_start4(vts, _CfgFs, _EvHs, _Tests, _Cover={cover,_}, _Args, _LogDir) ->
- %% Add support later (maybe).
- script_usage(),
- erlang:halt();
-script_start4(shell, _CfgFs, _EvHs, _Tests, _Cover={cover,_}, _Args, _LogDir) ->
- %% Add support later (maybe).
- script_usage();
-script_start4(false, _CfgFs, _EvHs, Tests, Cover={cover,_}, Args, LogDir) ->
- do_run(Tests, [], [Cover], Args, LogDir);
-script_start4(false, _ConfigFiles, _EvHandlers, Tests, false, Args, LogDir) ->
- do_run(Tests, [], [], Args, LogDir);
-script_start4(false, _ConfigFiles, _EvHandlers, Test, Step, Args, LogDir) ->
- do_run(Test, [], [Step], Args, LogDir);
-script_start4(vts, _ConfigFiles, _EvHandlers, _Test, _Step, _Args, _LogDir) ->
- script_usage(),
+
+script_start4(#opts{vts = true, cover = Cover}, _) ->
+ case Cover of
+ undefined ->
+ script_usage();
+ _ ->
+ %% Add support later (maybe).
+ io:format("\nCan't run cover in vts mode.\n\n", [])
+ end,
erlang:halt();
-script_start4(shell, _ConfigFiles, _EvHandlers, _Test, _Step, _Args, _LogDir) ->
- script_usage().
+
+script_start4(#opts{shell = true, cover = Cover}, _) ->
+ case Cover of
+ undefined ->
+ script_usage();
+ _ ->
+ %% Add support later (maybe).
+ io:format("\nCan't run cover in interactive mode.\n\n", [])
+ end;
+
+script_start4(Opts = #opts{tests = Tests}, Args) ->
+ do_run(Tests, [], Opts, Args).
%%%-----------------------------------------------------------------
%%% @spec script_usage() -> ok
@@ -394,8 +412,10 @@ script_usage() ->
"\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]"
"\n\t[-dir TestDir1 TestDir2 .. TestDirN] |"
"\n\t[-suite Suite [-case Case]]"
- "\n\t[-include InclDir1 InclDir2 .. InclDirN]"
+ "\n\t[-include InclDir1 InclDir2 .. InclDirN]"
"\n\t[-no_auto_compile]"
+ "\n\t[-multiply_timetraps]"
+ "\n\t[-scale_timetraps]"
"\n\t[-basic_html]\n\n"),
io:format("Run tests from command line:\n\n"
"\trun_test [-dir TestDir1 TestDir2 .. TestDirN] |"
@@ -409,10 +429,12 @@ script_usage() ->
"\n\t[-stylesheet CSSFile]"
"\n\t[-cover CoverCfgFile]"
"\n\t[-event_handler EvHandler1 EvHandler2 .. EvHandlerN]"
- "\n\t[-include InclDir1 InclDir2 .. InclDirN]"
+ "\n\t[-include InclDir1 InclDir2 .. InclDirN]"
"\n\t[-no_auto_compile]"
- "\n\t[-basic_html]"
- "\n\t[-repeat N [-force_stop]] |"
+ "\n\t[-multiply_timetraps]"
+ "\n\t[-scale_timetraps]"
+ "\n\t[-basic_html]"
+ "\n\t[-repeat N [-force_stop]] |"
"\n\t[-duration HHMMSS [-force_stop]] |"
"\n\t[-until [YYMoMoDD]HHMMSS [-force_stop]]\n\n"),
io:format("Run tests using test specification:\n\n"
@@ -425,10 +447,12 @@ script_usage() ->
"\n\t[-stylesheet CSSFile]"
"\n\t[-cover CoverCfgFile]"
"\n\t[-event_handler EvHandler1 EvHandler2 .. EvHandlerN]"
- "\n\t[-include InclDir1 InclDir2 .. InclDirN]"
+ "\n\t[-include InclDir1 InclDir2 .. InclDirN]"
"\n\t[-no_auto_compile]"
- "\n\t[-basic_html]"
- "\n\t[-repeat N [-force_stop]] |"
+ "\n\t[-multiply_timetraps]"
+ "\n\t[-scale_timetraps]"
+ "\n\t[-basic_html]"
+ "\n\t[-repeat N [-force_stop]] |"
"\n\t[-duration HHMMSS [-force_stop]] |"
"\n\t[-until [YYMoMoDD]HHMMSS [-force_stop]]\n\n"),
io:format("Refresh the HTML index files:\n\n"
@@ -439,7 +463,6 @@ script_usage() ->
"\trun_test -shell"
"\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
"\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]\n\n").
-
%%%-----------------------------------------------------------------
%%% @hidden
@@ -462,13 +485,13 @@ install(Opts, LogDir) ->
case whereis(ct_util_server) of
undefined ->
VarFile = variables_file_name(LogDir),
- %% io:format("Varfile=~p~n", [VarFile]),
+ io:format("Varfile=~p~n", [VarFile]),
case file:open(VarFile, [write]) of
{ok,Fd} ->
[io:format(Fd, "~p.\n", [Opt]) || Opt <- Opts],
file:close(Fd),
ok;
- {error,Reason} ->
+ {error,Reason} ->
io:format("CT failed to install configuration data. Please "
"verify that the log directory exists and that "
"write permission is set.\n\n", []),
@@ -487,59 +510,58 @@ variables_file_name(Dir) ->
filename:join(Dir, "variables-"++atom_to_list(node())).
%%%-----------------------------------------------------------------
-%%% @hidden
+%%% @spec run_test(Opts) -> Result
+%%% Opts = [tuple()]
+%%% Result = [TestResult] | {error,Reason}
+%%%
+%%% @doc Start tests from the erlang shell or from an erlang program.
%%% @equiv ct:run_test/1
+%%%-----------------------------------------------------------------
-%% Opts = [OptTuples]
-%% OptTuples = {config,CfgFiles} | {dir,TestDirs} | {suite,Suites} |
-%% {testcase,Cases} | {spec,TestSpecs} | {allow_user_terms,Bool} |
-%% {logdir,LogDir} | {cover,CoverSpecFile} | {step,StepOpts} |
-%% {silent_connections,Conns} | {event_handler,EventHandlers} |
-%% {include,InclDirs} | {auto_compile,Bool} |
-%% {repeat,N} | {duration,DurTime} | {until,StopTime} | {force_stop,Bool} |
-%% {decrypt,KeyOrFile}
-
-run_test(Opt) when is_tuple(Opt) ->
- run_test([Opt]);
-
-run_test(Opts) when is_list(Opts) ->
- case lists:keysearch(refresh_logs, 1, Opts) of
- {value,{_,RefreshDir}} ->
- refresh_logs(?abs(RefreshDir)),
- ok;
- false ->
- Tracing = start_trace(Opts),
+run_test(StartOpt) when is_tuple(StartOpt) ->
+ run_test([StartOpt]);
+
+run_test(StartOpts) when is_list(StartOpts) ->
+ case proplist:get_value(refresh_logs, StartOpts) of
+ undefined ->
+ Tracing = start_trace(StartOpts),
{ok,Cwd} = file:get_cwd(),
- io:format("~nCommon Test starting (cwd is ~s)~n~n", [Cwd]),
+ io:format("~nCommon Test starting (cwd is ~s)~n~n", [Cwd]),
Res =
- case ct_repeat:loop_test(func, Opts) of
+ case ct_repeat:loop_test(func, StartOpts) of
false ->
- case catch run_test1(Opts) of
- {'EXIT',Reason} ->
+ case catch run_test1(StartOpts) of
+ {'EXIT',Reason} ->
file:set_cwd(Cwd),
{error,Reason};
- Result ->
+ Result ->
Result
end;
Result ->
Result
end,
stop_trace(Tracing),
- Res
+ Res;
+ RefreshDir ->
+ refresh_logs(?abs(RefreshDir)),
+ ok
end.
-run_test1(Opts) ->
- LogDir =
- case lists:keysearch(logdir, 1, Opts) of
- {value,{_,LD}} when is_list(LD) -> LD;
- false -> "."
- end,
- CfgFiles = ct_config:get_config_file_list(Opts),
+run_test1(StartOpts) ->
+ %% logdir
+ LogDir = get_start_opt(logdir, fun(LD) when is_list(LD) -> LD end,
+ ".", StartOpts),
+ %% config & userconfig
+ CfgFiles = ct_config:get_config_file_list(StartOpts),
+
+ %% event handlers
EvHandlers =
- case lists:keysearch(event_handler, 1, Opts) of
- {value,{_,H}} when is_atom(H) ->
+ case proplists:get_value(event_handler, StartOpts) of
+ undefined ->
+ [];
+ H when is_atom(H) ->
[{H,[]}];
- {value,{_,H}} ->
+ H ->
Hs =
if is_tuple(H) -> [H];
is_list(H) -> H;
@@ -554,41 +576,34 @@ run_test1(Opts) ->
{EH,Args};
(_) ->
[]
- end, Hs));
- _ ->
- []
- end,
- SilentConns =
- case lists:keysearch(silent_connections, 1, Opts) of
- {value,{_,all}} ->
- [];
- {value,{_,Conns}} ->
- Conns;
- _ ->
- undefined
- end,
- Cover =
- case lists:keysearch(cover, 1, Opts) of
- {value,{_,CoverFile}} ->
- [{cover,?abs(CoverFile)}];
- _ ->
- []
+ end, Hs))
end,
+
+ %% silent connections
+ SilentConns = get_start_opt(silent_connections,
+ fun(all) -> [];
+ (Conns) -> Conns
+ end, StartOpts),
+ %% code coverage
+ Cover = get_start_opt(cover, fun(CoverFile) -> ?abs(CoverFile) end, StartOpts),
+
+ %% timetrap manipulation
+ MultiplyTT = get_start_opt(multiply_timetraps, value, 1, StartOpts),
+ ScaleTT = get_start_opt(scale_timetraps, value, false, StartOpts),
+
+ %% auto compile & include files
Include =
- case lists:keysearch(auto_compile, 1, Opts) of
- {value,{auto_compile,ACBool}} ->
- application:set_env(common_test, auto_compile, ACBool),
- [];
- _ ->
+ case proplists:get_value(auto_compile, StartOpts) of
+ undefined ->
application:set_env(common_test, auto_compile, true),
InclDirs =
- case lists:keysearch(include, 1, Opts) of
- {value,{include,Incl}} when is_list(hd(Incl)) ->
- Incl;
- {value,{include,Incl}} when is_list(Incl) ->
- [Incl];
- false ->
- []
+ case proplists:get_value(include, StartOpts) of
+ undefined ->
+ [];
+ Incl when is_list(hd(Incl)) ->
+ Incl;
+ Incl when is_list(Incl) ->
+ [Incl]
end,
case os:getenv("CT_INCLUDE_PATH") of
false ->
@@ -599,10 +614,14 @@ run_test1(Opts) ->
AllInclDirs = InclDirs1++InclDirs,
application:set_env(common_test, include, AllInclDirs),
AllInclDirs
- end
+ end;
+ ACBool ->
+ application:set_env(common_test, auto_compile, ACBool),
+ []
end,
- case lists:keysearch(decrypt, 1, Opts) of
+ %% decrypt config file
+ case lists:keysearch(decrypt, 1, StartOpts) of
{value,{_,Key={key,_}}} ->
application:set_env(common_test, decrypt, Key);
{value,{_,{file,KeyFile}}} ->
@@ -611,39 +630,35 @@ run_test1(Opts) ->
application:unset_env(common_test, decrypt)
end,
- case lists:keysearch(basic_html, 1, Opts) of
- {value,{basic_html,BasicHtmlBool}} ->
- application:set_env(common_test, basic_html, BasicHtmlBool);
- _ ->
- application:set_env(common_test, basic_html, false)
+ %% basic html - used by ct_logs
+ case proplists:get_value(basic_html, StartOpts) of
+ undefined ->
+ application:set_env(common_test, basic_html, false);
+ BasicHtmlBool ->
+ application:set_env(common_test, basic_html, BasicHtmlBool)
end,
- case lists:keysearch(spec, 1, Opts) of
- {value,{_,Specs}} ->
- Relaxed =
- case lists:keysearch(allow_user_terms, 1, Opts) of
- {value,{_,true}} -> true;
- _ -> false
- end,
+ %% stepped execution
+ Step = get_start_opt(step, value, StepOpts),
+
+ Opts = #opts{cover = Cover, step = Step, logdir = LogDir, config = CfgFiles,
+ event_handlers = EvHandlers, include = Include,
+ silent_connections = SilentConns, multiply_timetraps = MultiplyTT,
+ scale_timetraps = ScaleTT},
+
+ %% test specification
+ case proplists:get_value(spec, StartOpts) of
+ undefined ->
+ case proplists:get_value(prepared_tests, StartOpts) of
+ undefined -> % use dir|suite|case
+ run_dir(Opts, StartOpts);
+ {{Run,Skip},Specs} -> % use prepared tests
+ run_prepared(Run, Skip, Opts#opts{testspecs = Specs}, StartOpts)
+ end;
+ Specs ->
+ Relaxed = get_start_opt(allow_user_term, value, false),
%% using testspec(s) as input for test
- run_spec_file(LogDir, CfgFiles, EvHandlers, Include, Specs, Relaxed, Cover,
- replace_opt([{silent_connections,SilentConns}], Opts));
- false ->
- case lists:keysearch(prepared_tests, 1, Opts) of
- {value,{_,{Run,Skip},Specs}} -> % use prepared tests
- run_prepared(LogDir, CfgFiles, EvHandlers,
- Run, Skip, Cover,
- replace_opt([{silent_connections,SilentConns},
- {spec,Specs}],Opts));
- false -> % use dir|suite|case
- StepOrCover =
- case lists:keysearch(step, 1, Opts) of
- {value,Step} -> [Step];
- false -> Cover
- end,
- run_dir(LogDir, CfgFiles, EvHandlers, StepOrCover,
- replace_opt([{silent_connections,SilentConns}], Opts))
- end
+ run_spec_file(Relaxed, Opts#opts{testspecs = Specs}, StartOpts)
end.
replace_opt([O={Key,_Val}|Os], Opts) ->
@@ -651,83 +666,105 @@ replace_opt([O={Key,_Val}|Os], Opts) ->
replace_opt([], Opts) ->
Opts.
-run_spec_file(LogDir, CfgFiles, EvHandlers, Include, Specs, Relaxed, Cover, Opts) ->
+run_spec_file(Relaxed,
+ Opts = #opts{testspecs = Specs, config = CfgFiles},
+ StartOpts) ->
Specs1 = case Specs of
[X|_] when is_integer(X) -> [Specs];
_ -> Specs
end,
- AbsSpecs = lists:map(fun(SF) -> ?abs(SF) end, Specs1),
+ AbsSpecs = lists:map(fun(SF) -> ?abs(SF) end, Specs1),
log_ts_names(AbsSpecs),
case catch ct_testspec:collect_tests_from_file(AbsSpecs, Relaxed) of
{error,CTReason} ->
exit(CTReason);
TS ->
- {LogDir1,TSCoverFile,CfgFiles1,EvHandlers1,Include1} =
- get_data_for_node(TS, node()),
- application:set_env(common_test, include, Include++Include1),
- LogDir2 = which_logdir(LogDir, LogDir1),
- CoverOpt = case {Cover,TSCoverFile} of
- {[],undef} -> [];
- {_,undef} -> Cover;
- {[],_} -> [{cover,TSCoverFile}]
- end,
- case check_and_install_configfiles(CfgFiles++CfgFiles1, LogDir2,
- EvHandlers++EvHandlers1) of
+ SpecOpts = get_data_for_node(TS, node()),
+ LogDir = choose_val(Opts#opts.logdir,
+ SpecOpts#opts.logdir),
+ AllConfig = merge_vals([CfgFiles, SpecOpts#opts.config]),
+ Cover = choose_val(Opts#opts.cover,
+ SpecOpts#opts.cover),
+ MultTT = choose_val(Opts#opts.multiply_timetraps,
+ SpecOpts#opts.multiply_timetraps),
+ ScaleTT = choose_val(Opts#opts.scale_timetraps,
+ SpecOpts#opts.scale_timetraps),
+ AllEvHs = merge_vals([Opts#opts.event_handlers,
+ SpecOpts#opts.event_handlers]),
+ AllInclude = merge_vals([Opts#opts.include,
+ SpecOpts#opts.include]),
+ application:set_env(common_test, include, AllInclude),
+
+ case check_and_install_configfiles(AllConfig,
+ which(logdir,LogDir),
+ AllEvHs) of
ok ->
+ Opts1 = Opts#opts{testspecs = Specs,
+ cover = Cover,
+ logdir = LogDir,
+ config = AllConfig,
+ event_handlers = AllEvHs,
+ include = AllInclude,
+ testspecs = AbsSpecs,
+ multiply_timetraps = MultTT,
+ scale_timetraps = ScaleTT}
+
{Run,Skip} = ct_testspec:prepare_tests(TS, node()),
- do_run(Run, Skip, CoverOpt,
- replace_opt([{spec,AbsSpecs}], Opts),
- LogDir2);
+ do_run(Run, Skip, Opts1, StartOpts);
{error,GCFReason} ->
exit(GCFReason)
end
end.
-run_prepared(LogDir, CfgFiles, EvHandlers, Run, Skip, Cover, Opts) ->
+run_prepared(Run, Skip, Opts = #opts{logdir = LogDir,
+ config = CfgFiles,
+ event_handlers = EvHandlers},
+ StartOpts) ->
case check_and_install_configfiles(CfgFiles, LogDir, EvHandlers) of
ok ->
- do_run(Run, Skip, Cover, Opts, LogDir);
+ do_run(Run, Skip, Opts, StartOpts);
{error,Reason} ->
exit(Reason)
- end.
+ end.
check_config_file(Callback, File)->
case Callback:check_parameter(File) of
- {ok, {file, File}}->
+ {ok,{file,File}}->
?abs(File);
- {ok, {config, _}}->
+ {ok,{config,_}}->
File;
- {error, {wrong_config, Message}}->
- exit({wrong_config, {Callback, Message}});
- {error, {nofile, File}}->
- exit({no_such_file, ?abs(File)})
+ {nok,{wrong_config,Message}}->
+ exit({wrong_config,{Callback,Message}});
+ {nok,{nofile,File}}->
+ exit({no_such_file,?abs(File)})
end.
-run_dir(LogDir, CfgFiles, EvHandlers, StepOrCover, Opts) ->
- AbsCfgFiles =
- lists:map(fun({Callback, FileList})->
- case code:is_loaded(Callback) of
- {file, _Path}->
- ok;
- false->
- case code:load_file(Callback) of
- {module, Callback}->
- ok;
- {error, _}->
- exit({no_such_module, Callback})
- end
- end,
- {Callback,
- lists:map(fun(File)->
- check_config_file(Callback, File)
- end, FileList)}
- end,
- CfgFiles),
+run_dir(Opts = #opts{logdir = LogDir,
+ config = CfgFiles,
+ event_handlers = EvHandlers}, StartOpts) ->
+ AbsCfgFiles =
+ lists:map(fun({Callback,FileList})->
+ case code:is_loaded(Callback) of
+ {file,_Path}->
+ ok;
+ false ->
+ case code:load_file(Callback) of
+ {module,Callback}->
+ ok;
+ {error,_}->
+ exit({no_such_module,Callback})
+ end
+ end,
+ {Callback,
+ lists:map(fun(File)->
+ check_config_file(Callback, File)
+ end, FileList)}
+ end, CfgFiles),
case install([{config,AbsCfgFiles},{event_handler,EvHandlers}], LogDir) of
ok -> ok;
{error,IReason} -> exit(IReason)
end,
- case lists:keysearch(dir,1,Opts) of
+ case lists:keysearch(dir, 1, Opts) of
{value,{_,Dirs=[Dir|_]}} when not is_integer(Dir),
length(Dirs)>1 ->
%% multiple dirs (no suite)
@@ -754,12 +791,12 @@ run_dir(LogDir, CfgFiles, EvHandlers, StepOrCover, Opts) ->
do_run(tests(lists:map(S2M, Suites)), [], StepOrCover, Opts, LogDir);
_ ->
exit(no_tests_specified)
- end;
+ end;
{value,{_,Dir}} ->
case lists:keysearch(suite, 1, Opts) of
{value,{_,Suite}} when is_integer(hd(Suite)) ; is_atom(Suite) ->
- Mod = if is_atom(Suite) -> Suite;
- true -> list_to_atom(Suite)
+ Mod = if is_atom(Suite) -> Suite;
+ true -> list_to_atom(Suite)
end,
case listify(proplists:get_value(group, Opts, [])) ++
listify(proplists:get_value(testcase, Opts, [])) of
@@ -770,77 +807,90 @@ run_dir(LogDir, CfgFiles, EvHandlers, StepOrCover, Opts) ->
end;
{value,{_,Suites=[Suite|_]}} when is_list(Suite) ->
Mods = lists:map(fun(Str) -> list_to_atom(Str) end, Suites),
- do_run(tests(delistify(Dir), Mods), [], StepOrCover, Opts, LogDir);
+ do_run(tests(delistify(Dir), Mods), [], StepOrCover, Opts, LogDir);
{value,{_,Suites}} ->
- do_run(tests(delistify(Dir), Suites), [], StepOrCover, Opts, LogDir);
+ do_run(tests(delistify(Dir), Suites), [], StepOrCover, Opts, LogDir);
false -> % no suite, only dir
do_run(tests(listify(Dir)), [], StepOrCover, Opts, LogDir)
- end
+ end
end.
%%%-----------------------------------------------------------------
-%%% @hidden
+%%% @spec run_testspec(TestSpec) -> Result
+%%% TestSpec = [term()]
%%%
+%%% @doc Run test specified by TestSpec
. The terms are
+%%% the same as those used in test specification files.
+%%% @equiv ct:run_testspec/1
+%%%-----------------------------------------------------------------
-%% using testspec(s) as input for test
run_testspec(TestSpec) ->
{ok,Cwd} = file:get_cwd(),
io:format("~nCommon Test starting (cwd is ~s)~n~n", [Cwd]),
case catch run_testspec1(TestSpec) of
- {'EXIT',Reason} ->
+ {'EXIT',Reason} ->
file:set_cwd(Cwd),
{error,Reason};
- Result ->
+ Result ->
Result
end.
run_testspec1(TestSpec) ->
- case ct_testspec:collect_tests_from_list(TestSpec,false) of
+ case ct_testspec:collect_tests_from_list(TestSpec, false) of
{error,CTReason} ->
exit(CTReason);
TS ->
- {LogDir,TSCoverFile,CfgFiles,EvHandlers,Include} =
- get_data_for_node(TS,node()),
- case os:getenv("CT_INCLUDE_PATH") of
- false ->
- application:set_env(common_test, include, Include);
- CtInclPath ->
- EnvInclude = string:tokens(CtInclPath, [$:,$ ,$,]),
- application:set_env(common_test, include, EnvInclude++Include)
- end,
- CoverOpt = if TSCoverFile == undef -> [];
- true -> [{cover,TSCoverFile}]
- end,
- case check_and_install_configfiles(CfgFiles,LogDir,EvHandlers) of
+ Opts = get_data_for_node(TS, node()),
+
+ AllInclude =
+ case os:getenv("CT_INCLUDE_PATH") of
+ false ->
+ Opts#opts.include;
+ CtInclPath ->
+ EnvInclude = string:tokens(CtInclPath, [$:,$ ,$,]),
+ EnvInclude++Opts#opts.include,
+ end,
+ application:set_env(common_test, include, AllInclude),
+
+ case check_and_install_configfiles(Opts#opts.config,
+ which(logdir,Opts#opts.logdir),
+ Opts#opts.event_handlers) of
ok ->
- {Run,Skip} = ct_testspec:prepare_tests(TS,node()),
- do_run(Run,Skip,CoverOpt,[],LogDir);
+ Opts1 = Opts#opts{testspecs = [TestSpec],
+ include = AllInclude},
+ {Run,Skip} = ct_testspec:prepare_tests(TS, node()),
+ do_run(Run, Skip, Opts1, []);
{error,GCFReason} ->
exit(GCFReason)
end
end.
-
get_data_for_node(#testspec{logdir=LogDirs,
cover=CoverFs,
config=Cfgs,
userconfig=UsrCfgs,
event_handler=EvHs,
- include=Incl}, Node) ->
- LogDir = case lists:keysearch(Node,1,LogDirs) of
- {value,{Node,Dir}} -> Dir;
- false -> "."
+ include=Incl,
+ multiply_timetraps=MTs,
+ scale_timetraps=STs}, Node) ->
+ LogDir = case proplists:get_value(Node, LogDirs) of
+ undefined -> ".";
+ Dir -> Dir
end,
- Cover = case lists:keysearch(Node,1,CoverFs) of
- {value,{Node,CovFile}} -> CovFile;
- false -> undef
- end,
- ConfigFiles = [{?ct_config_txt, F} || {N,F} <- Cfgs, N==Node] ++
- [CBF || {N, CBF} <- UsrCfgs, N==Node],
+ Cover = proplists:get_value(Node, CoverFs),
+ MT = proplists:get_value(Node, MTs),
+ ST = proplists:get_value(Node, STs),
+ ConfigFiles = [{?ct_config_txt,F} || {N,F} <- Cfgs, N==Node] ++
+ [CBF || {N,CBF} <- UsrCfgs, N==Node],
EvHandlers = [{H,A} || {N,H,A} <- EvHs, N==Node],
Include = [I || {N,I} <- Incl, N==Node],
- {LogDir,Cover,ConfigFiles,EvHandlers,Include}.
-
+ #opts{logdir = LogDir,
+ cover = Cover,
+ config = ConfigFiles,
+ event_handlers = EvHandlers,
+ include = Include,
+ multiply_timetraps = MT,
+ scale_timetraps = ST}.
refresh_logs(LogDir) ->
{ok,Cwd} = file:get_cwd(),
@@ -865,11 +915,27 @@ refresh_logs(LogDir) ->
end
end.
-which_logdir(".",Dir) ->
+which(logdir, undefined) ->
+ ".";
+which(logdir, Dir) ->
Dir;
-which_logdir(Dir,_) ->
- Dir.
-
+which(multiply_timetraps, undefined) ->
+ 1;
+which(multiply_timetraps, MT) ->
+ MT;
+which(scale_timetraps, undefined) ->
+ false;
+which(scale_timetraps, ST) ->
+ ST.
+
+choose_val(undefined, V1) ->
+ V1;
+choose_val(V0, _V1) ->
+ V0.
+
+merge_vals(Vs) ->
+ lists:append(Vs).
+
listify([C|_]=Str) when is_integer(C) -> [Str];
listify(L) when is_list(L) -> L;
listify(E) -> [E].
@@ -899,6 +965,22 @@ run(TestDirs) ->
install([]),
do_run(tests(TestDirs), []).
+suite_to_test(Suite) ->
+ {filename:dirname(Suite),list_to_atom(filename:rootname(filename:basename(Suite)))}.
+
+groups_and_cases(Gs, Cs) when (Gs == undefined ; Gs == []),
+ (Cs == undefined ; Cs == []) ->
+ [];
+groups_and_cases(Gs, Cs) when Gs == undefined ; Gs == [] ->
+ [list_to_atom(C) || C <- Cs];
+groups_and_cases(Gs, Cs) when Cs == undefined ; Cs == [] ->
+ [{list_to_atom(G),all} || G <- Gs];
+groups_and_cases([G], Cs) ->
+ [{list_to_atom(G),[list_to_atom(C) || C <- Cs]}];
+groups_and_cases([_,_|_] , Cs) when Cs =/= [] ->
+ {error,multiple_groups_and_cases};
+groups_and_cases(Gs, Cs) ->
+ {error,incorrect_group_or_case_option}.
tests(TestDir, Suites, []) when is_list(TestDir), is_integer(hd(TestDir)) ->
[{?testdir(TestDir,Suites),ensure_atom(Suites),all}];
@@ -915,30 +997,25 @@ tests(TestDir) when is_list(TestDir), is_integer(hd(TestDir)) ->
tests(TestDirs) when is_list(TestDirs), is_list(hd(TestDirs)) ->
[{?testdir(TestDir,all),all,all} || TestDir <- TestDirs].
-do_run(Tests, Opt) ->
- do_run(Tests, [], Opt, [], ".").
-
-do_run(Tests, Opt, LogDir) ->
- do_run(Tests, [], Opt, [], LogDir).
+do_run(Tests, Opt, LogDir) when is_list(Opt) ->
+ do_run(Tests, [], #opts{tests = Tests, logdir = LogDir}, []).
-do_run(Tests, Skip, Opt, Args, LogDir) ->
+do_run(Tests, Skip, Opts, Args) ->
+ #opts{cover = Cover} = Opts
case code:which(test_server) of
non_existing ->
exit({error,no_path_to_test_server});
_ ->
- Opt1 =
- case lists:keysearch(cover, 1, Opt) of
- {value,{_,CoverFile}} ->
- case ct_cover:get_spec(CoverFile) of
- {error,Reason} ->
- exit({error,Reason});
- Spec ->
- [{cover_spec,Spec} |
- lists:keydelete(cover, 1, Opt)]
- end;
- _ ->
- Opt
- end,
+ Opts1 = if Cover == undefined ->
+ Opts;
+ true ->
+ case ct_cover:get_spec(Cover) of
+ {error,Reason} ->
+ exit({error,Reason});
+ CoverSpec ->
+ Opts#opts{coverspec = CoverSpec}
+ end
+ end,
%% This env variable is used by test_server to determine
%% which framework it runs under.
case os:getenv("TEST_SERVER_FRAMEWORK") of
@@ -956,7 +1033,6 @@ do_run(Tests, Skip, Opt, Args, LogDir) ->
"To enter the interactive mode again, "
"run ct:start_interactive()\n\n",[]),
{error,interactive_mode};
-
_Pid ->
%% save style sheet info
case lists:keysearch(stylesheet, 1, Args) of
@@ -982,7 +1058,7 @@ do_run(Tests, Skip, Opt, Args, LogDir) ->
_ ->
ok
end,
- log_ts_names(Args),
+ log_ts_names(Opts1#opts.testspecs),
TestSuites = suite_tuples(Tests),
{SuiteMakeErrors,AllMakeErrors} =
@@ -1000,7 +1076,7 @@ do_run(Tests, Skip, Opt, Args, LogDir) ->
SavedErrors = save_make_errors(SuiteMakeErrors),
ct_repeat:log_loop_info(Args),
{Tests1,Skip1} = final_tests(Tests,[],Skip,SavedErrors),
- R = do_run_test(Tests1, Skip1, Opt1),
+ R = do_run_test(Tests1, Skip1, Opts1),
ct_util:stop(normal),
R;
false ->
@@ -1026,7 +1102,7 @@ auto_compile(TestSuites) ->
case application:get_env(common_test, include) of
{ok,UserInclDirs} when length(UserInclDirs) > 0 ->
io:format("Including the following directories:~n"),
- [begin io:format("~p~n",[UserInclDir]), {i,UserInclDir} end ||
+ [begin io:format("~p~n",[UserInclDir]), {i,UserInclDir} end ||
UserInclDir <- UserInclDirs];
_ ->
[]
@@ -1034,11 +1110,11 @@ auto_compile(TestSuites) ->
SuiteMakeErrors =
lists:flatmap(fun({TestDir,Suite} = TS) ->
case run_make(suites, TestDir, Suite, UserInclude) of
- {error,{make_failed,Bad}} ->
+ {error,{make_failed,Bad}} ->
[{TS,Bad}];
- {error,_} ->
+ {error,_} ->
[{TS,[filename:join(TestDir,"*_SUITE")]}];
- _ ->
+ _ ->
[]
end
end, TestSuites),
@@ -1062,13 +1138,13 @@ auto_compile(TestSuites) ->
true -> % already visited
{Done,Failed}
end
- end, {[],[]}, TestSuites),
+ end, {[],[]}, TestSuites),
{SuiteMakeErrors,lists:reverse(HelpMakeErrors)}.
%% verify that specified test suites exist (if auto compile is disabled)
verify_suites(TestSuites) ->
io:nl(),
- Verify =
+ Verify =
fun({Dir,Suite},NotFound) ->
case locate_test_dir(Dir, Suite) of
{ok,TestDir} ->
@@ -1077,11 +1153,11 @@ verify_suites(TestSuites) ->
true ->
Beam = filename:join(TestDir, atom_to_list(Suite)++".beam"),
case filelib:is_regular(Beam) of
- true ->
+ true ->
NotFound;
- false ->
+ false ->
Name = filename:join(TestDir, atom_to_list(Suite)),
- io:format("Suite ~w not found in directory ~s~n",
+ io:format("Suite ~w not found in directory ~s~n",
[Suite,TestDir]),
[{{Dir,Suite},[Name]} | NotFound]
end
@@ -1093,8 +1169,7 @@ verify_suites(TestSuites) ->
end
end,
lists:reverse(lists:foldl(Verify, [], TestSuites)).
-
-
+
save_make_errors([]) ->
[];
save_make_errors(Errors) ->
@@ -1110,7 +1185,7 @@ get_bad_suites([{{_TestDir,_Suite},Failed}|Errors], BadSuites) ->
get_bad_suites([], BadSuites) ->
BadSuites.
-
+
%%%-----------------------------------------------------------------
%%% @hidden
@@ -1121,7 +1196,7 @@ step(TestDir, Suite, Case) ->
%%%-----------------------------------------------------------------
%%% @hidden
%%% @equiv ct:step/4
-step(TestDir, Suite, Case, Opts) when is_list(TestDir), is_atom(Suite), is_atom(Case),
+step(TestDir, Suite, Case, Opts) when is_list(TestDir), is_atom(Suite), is_atom(Case),
Suite =/= all, Case =/= all ->
do_run([{TestDir,Suite,Case}], [{step,Opts}]).
@@ -1154,7 +1229,7 @@ final_tests([{TestDir,Suites,_}|Tests],
Skip1 = [{TD,S,"Make failed"} || {{TD,S},_} <- Bad, S1 <- Suites,
S == S1, TD == TestDir],
- Final1 = [{TestDir,S,all} || S <- Suites],
+ Final1 = [{TestDir,S,all} || S <- Suites],
final_tests(Tests, lists:reverse(Final1)++Final, Skip++Skip1, Bad);
final_tests([{TestDir,all,all}|Tests], Final, Skip, Bad) ->
@@ -1187,7 +1262,7 @@ final_tests([{TestDir,Suite,Cases}|Tests], Final, Skip, Bad) ->
final_tests([], Final, Skip, _Bad) ->
{lists:reverse(Final),Skip}.
-continue([]) ->
+continue([]) ->
true;
continue(_MakeErrors) ->
io:nl(),
@@ -1228,7 +1303,7 @@ set_group_leader_same_as_shell() ->
false
end
end,
- case [P || P <- processes(), GS2or3(P),
+ case [P || P <- processes(), GS2or3(P),
true == lists:keymember(shell,1,element(2,process_info(P,dictionary)))] of
[GL|_] ->
group_leader(GL, self());
@@ -1252,29 +1327,29 @@ check_and_add([{TestDir0,M,_} | Tests], Added) ->
check_and_add([], _) ->
ok.
-do_run_test(Tests, Skip, Opt) ->
+do_run_test(Tests, Skip, Opts) ->
case check_and_add(Tests, []) of
ok ->
ct_util:set_testdata({stats,{0,0,{0,0}}}),
ct_util:set_testdata({cover,undefined}),
test_server_ctrl:start_link(local),
- case lists:keysearch(cover_spec, 1, Opt) of
- {value,{_,CovData={CovFile,
- CovNodes,
- _CovImport,
- CovExport,
- #cover{app = CovApp,
- level = CovLevel,
- excl_mods = CovExcl,
- incl_mods = CovIncl,
- cross = CovCross,
- src = _CovSrc}}}} ->
+ case Opts#opts.coverspec of
+ CovData={CovFile,
+ CovNodes,
+ _CovImport,
+ CovExport,
+ #cover{app = CovApp,
+ level = CovLevel,
+ excl_mods = CovExcl,
+ incl_mods = CovIncl,
+ cross = CovCross,
+ src = _CovSrc}} ->
ct_logs:log("COVER INFO","Using cover specification file: ~s~n"
"App: ~w~n"
"Cross cover: ~w~n"
"Including ~w modules~n"
"Excluding ~w modules",
- [CovFile,CovApp,CovCross,length(CovIncl),length(CovExcl)]),
+ [CovFile,CovApp,CovCross,length(CovIncl),length(CovExcl)]),
%% cover export file will be used for export and import
%% between tests so make sure it doesn't exist initially
@@ -1307,33 +1382,37 @@ do_run_test(Tests, Skip, Opt) ->
true;
_ ->
false
- end,
+ end,
%% let test_server expand the test tuples and count no of cases
{Suites,NoOfCases} = count_test_cases(Tests, Skip),
Suites1 = delete_dups(Suites),
NoOfTests = length(Tests),
NoOfSuites = length(Suites1),
- ct_util:warn_duplicates(Suites1),
+ ct_util:warn_duplicates(Suites1),
{ok,Cwd} = file:get_cwd(),
io:format("~nCWD set to: ~p~n", [Cwd]),
if NoOfCases == unknown ->
- io:format("~nTEST INFO: ~w test(s), ~w suite(s)~n~n",
+ io:format("~nTEST INFO: ~w test(s), ~w suite(s)~n~n",
[NoOfTests,NoOfSuites]),
- ct_logs:log("TEST INFO","~w test(s), ~w suite(s)",
+ ct_logs:log("TEST INFO","~w test(s), ~w suite(s)",
[NoOfTests,NoOfSuites]);
true ->
- io:format("~nTEST INFO: ~w test(s), ~w case(s) in ~w suite(s)~n~n",
+ io:format("~nTEST INFO: ~w test(s), ~w case(s) in ~w suite(s)~n~n",
[NoOfTests,NoOfCases,NoOfSuites]),
- ct_logs:log("TEST INFO","~w test(s), ~w case(s) in ~w suite(s)",
+ ct_logs:log("TEST INFO","~w test(s), ~w case(s) in ~w suite(s)",
[NoOfTests,NoOfCases,NoOfSuites])
end,
+
+ test_server_ctrl:multiply_timetraps(Opts#opts.multiply_timetraps),
+ test_server_ctrl:scale_timetraps(Opts#opts.scale_timetraps),
+
ct_event:notify(#event{name=start_info,
node=node(),
data={NoOfTests,NoOfSuites,NoOfCases}}),
- CleanUp = add_jobs(Tests, Skip, Opt, []),
+ CleanUp = add_jobs(Tests, Skip, Opts, []),
unlink(whereis(test_server_ctrl)),
- catch test_server_ctrl:wait_finish(),
- %% check if last testcase has left a "dead" trace window
+ catch test_server_ctrl:wait_finish(),
+ %% check if last testcase has left a "dead" trace window
%% behind, and if so, kill it
case ct_util:get_testdata(interpret) of
{_What,kill,{TCPid,AttPid}} ->
@@ -1341,8 +1420,8 @@ do_run_test(Tests, Skip, Opt) ->
_ ->
ok
end,
- lists:foreach(fun(Suite) ->
- maybe_cleanup_interpret(Suite, Opt)
+ lists:foreach(fun(Suite) ->
+ maybe_cleanup_interpret(Suite, Opt)
end, CleanUp);
Error ->
Error
@@ -1358,7 +1437,7 @@ count_test_cases(Tests, Skip) ->
SendResult = fun(Me, Result) -> Me ! {no_of_cases,Result} end,
TSPid = test_server_ctrl:start_get_totals(SendResult),
Ref = erlang:monitor(process, TSPid),
- add_jobs(Tests, Skip, [], []),
+ add_jobs(Tests, Skip, #opts{}, []),
{Suites,NoOfCases} = count_test_cases1(length(Tests), 0, [], Ref),
erlang:demonitor(Ref),
test_server_ctrl:stop_get_totals(),
@@ -1368,11 +1447,11 @@ count_test_cases1(0, N, Suites, _) ->
{lists:flatten(Suites), N};
count_test_cases1(Jobs, N, Suites, Ref) ->
receive
- {no_of_cases,{Ss,N1}} ->
+ {no_of_cases,{Ss,N1}} ->
count_test_cases1(Jobs-1, add_known(N,N1), [Ss|Suites], Ref);
- {'DOWN', Ref, _, _, _} ->
+ {'DOWN', Ref, _, _, _} ->
{[],0}
- end.
+ end.
add_known(unknown, _) ->
unknown;
@@ -1381,72 +1460,72 @@ add_known(_, unknown) ->
add_known(N, N1) ->
N+N1.
-add_jobs([{TestDir,all,_}|Tests], Skip, Opt, CleanUp) ->
+add_jobs([{TestDir,all,_}|Tests], Skip, Opts, CleanUp) ->
Name = get_name(TestDir),
case catch test_server_ctrl:add_dir_with_skip(Name, TestDir,
skiplist(TestDir,Skip)) of
- {'EXIT',_} ->
+ {'EXIT',_} ->
CleanUp;
_ ->
wait_for_idle(),
- add_jobs(Tests, Skip, Opt, CleanUp)
+ add_jobs(Tests, Skip, Opts, CleanUp)
end;
-add_jobs([{TestDir,[Suite],all}|Tests], Skip, Opt, CleanUp) when is_atom(Suite) ->
- add_jobs([{TestDir,Suite,all}|Tests], Skip, Opt, CleanUp);
-add_jobs([{TestDir,Suites,all}|Tests], Skip, Opt, CleanUp) when is_list(Suites) ->
+add_jobs([{TestDir,[Suite],all}|Tests], Skip, Opts, CleanUp) when is_atom(Suite) ->
+ add_jobs([{TestDir,Suite,all}|Tests], Skip, Opts, CleanUp);
+add_jobs([{TestDir,Suites,all}|Tests], Skip, Opts, CleanUp) when is_list(Suites) ->
Name = get_name(TestDir) ++ ".suites",
case catch test_server_ctrl:add_module_with_skip(Name, Suites,
skiplist(TestDir,Skip)) of
- {'EXIT',_} ->
+ {'EXIT',_} ->
CleanUp;
_ ->
wait_for_idle(),
- add_jobs(Tests, Skip, Opt, CleanUp)
+ add_jobs(Tests, Skip, Opts, CleanUp)
end;
-add_jobs([{TestDir,Suite,all}|Tests], Skip, Opt, CleanUp) ->
- case maybe_interpret(Suite, all, Opt) of
+add_jobs([{TestDir,Suite,all}|Tests], Skip, Opts, CleanUp) ->
+ case maybe_interpret(Suite, all, Opts) of
ok ->
Name = get_name(TestDir) ++ "." ++ atom_to_list(Suite),
case catch test_server_ctrl:add_module_with_skip(Name, [Suite],
skiplist(TestDir,Skip)) of
- {'EXIT',_} ->
+ {'EXIT',_} ->
CleanUp;
_ ->
wait_for_idle(),
- add_jobs(Tests, Skip, Opt, [Suite|CleanUp])
+ add_jobs(Tests, Skip, Opts, [Suite|CleanUp])
end;
Error ->
Error
end;
-add_jobs([{TestDir,Suite,[Case]}|Tests], Skip, Opt, CleanUp) when is_atom(Case) ->
- add_jobs([{TestDir,Suite,Case}|Tests], Skip, Opt, CleanUp);
-add_jobs([{TestDir,Suite,Cases}|Tests], Skip, Opt, CleanUp) when is_list(Cases) ->
- case maybe_interpret(Suite, Cases, Opt) of
+add_jobs([{TestDir,Suite,[Case]}|Tests], Skip, Opts, CleanUp) when is_atom(Case) ->
+ add_jobs([{TestDir,Suite,Case}|Tests], Skip, Opts, CleanUp);
+add_jobs([{TestDir,Suite,Cases}|Tests], Skip, Opts, CleanUp) when is_list(Cases) ->
+ case maybe_interpret(Suite, Cases, Opts) of
ok ->
Name = get_name(TestDir) ++ "." ++ atom_to_list(Suite) ++ ".cases",
case catch test_server_ctrl:add_cases_with_skip(Name, Suite, Cases,
skiplist(TestDir,Skip)) of
- {'EXIT',_} ->
+ {'EXIT',_} ->
CleanUp;
_ ->
wait_for_idle(),
- add_jobs(Tests, Skip, Opt, [Suite|CleanUp])
+ add_jobs(Tests, Skip, Opts, [Suite|CleanUp])
end;
Error ->
Error
end;
-add_jobs([{TestDir,Suite,Case}|Tests], Skip, Opt, CleanUp) when is_atom(Case) ->
- case maybe_interpret(Suite, Case, Opt) of
+add_jobs([{TestDir,Suite,Case}|Tests], Skip, Opts, CleanUp) when is_atom(Case) ->
+ case maybe_interpret(Suite, Case, Opts) of
ok ->
- Name = get_name(TestDir) ++ "." ++ atom_to_list(Suite) ++ "." ++
+ Name = get_name(TestDir) ++ "." ++ atom_to_list(Suite) ++ "." ++
atom_to_list(Case),
case catch test_server_ctrl:add_case_with_skip(Name, Suite, Case,
skiplist(TestDir,Skip)) of
- {'EXIT',_} ->
+ {'EXIT',_} ->
CleanUp;
_ ->
wait_for_idle(),
- add_jobs(Tests, Skip, Opt, [Suite|CleanUp])
+ add_jobs(Tests, Skip, Opts, [Suite|CleanUp])
end;
Error ->
Error
@@ -1496,7 +1575,7 @@ get_name(Dir) ->
end,
Base = filename:basename(TestDir),
case filename:basename(filename:dirname(TestDir)) of
- "" ->
+ "" ->
Base;
TopDir ->
TopDir ++ "." ++ Base
@@ -1527,10 +1606,10 @@ run_make(Targets, TestDir0, Mod, UserInclude) ->
{i,CtInclude},
{i,XmerlInclude},
debug_info],
- Result =
+ Result =
if Mod == all ; Targets == helpmods ->
case (catch ct_make:all([noexec|ErlFlags])) of
- {'EXIT',_} = Failure ->
+ {'EXIT',_} = Failure ->
Failure;
MakeInfo ->
FileTest = fun(F, suites) -> is_suite(F);
@@ -1549,7 +1628,7 @@ run_make(Targets, TestDir0, Mod, UserInclude) ->
true ->
(catch ct_make:files([Mod], [load|ErlFlags]))
end,
-
+
ok = file:set_cwd(Cwd),
%% send finished_make notification
ct_event:notify(#event{name=finished_make,
@@ -1563,7 +1642,7 @@ run_make(Targets, TestDir0, Mod, UserInclude) ->
{error,{make_crashed,TestDir,Reason}};
{error,ModInfo} ->
io:format("{error,make_failed}\n", []),
- Bad = [filename:join(TestDir, M) || {M,R} <- ModInfo,
+ Bad = [filename:join(TestDir, M) || {M,R} <- ModInfo,
R == error],
{error,{make_failed,Bad}}
end;
@@ -1575,8 +1654,8 @@ run_make(Targets, TestDir0, Mod, UserInclude) ->
get_dir(App, Dir) ->
filename:join(code:lib_dir(App), Dir).
-maybe_interpret(Suite, Cases, [{step,StepOpts}]) ->
- %% if other suite has run before this one, check if last testcase
+maybe_interpret(Suite, Cases, #opts{step = StepOpts}) when StepOpts =/= undefined ->
+ %% if other suite has run before this one, check if last testcase
%% has left a "dead" trace window behind, and if so, kill it
case ct_util:get_testdata(interpret) of
{_What,kill,{TCPid,AttPid}} ->
@@ -1619,7 +1698,7 @@ maybe_interpret2(Suite, Cases, StepOpts) ->
WinOp = case lists:member(keep_inactive, ensure_atom(StepOpts)) of
true -> no_kill;
false -> kill
- end,
+ end,
ct_util:set_testdata({interpret,{{Suite,Cases},WinOp,
{undefined,undefined}}}),
ok.
@@ -1640,18 +1719,15 @@ maybe_cleanup_interpret(Suite, [{step,_}]) ->
maybe_cleanup_interpret(_, _) ->
ok.
-log_ts_names(Args) ->
- case lists:keysearch(spec, 1, Args) of
- {value,{_,Specs}} ->
- List = lists:map(fun(Name) ->
- Name ++ " "
- end, Specs),
- ct_logs:log("Test Specification file(s)", "~s",
- [lists:flatten(List)]);
- _ ->
- ok
- end.
-
+log_ts_names([]) ->
+ ok;
+log_ts_names(Specs) ->
+ List = lists:map(fun(Name) ->
+ Name ++ " "
+ end, Specs),
+ ct_logs:log("Test Specification file(s)", "~s",
+ [lists:flatten(List)]).
+
merge_arguments(Args) ->
merge_arguments(Args, []).
@@ -1659,6 +1735,8 @@ merge_arguments([LogDir={logdir,_}|Args], Merged) ->
merge_arguments(Args, handle_arg(replace, LogDir, Merged));
merge_arguments([CoverFile={cover,_}|Args], Merged) ->
merge_arguments(Args, handle_arg(replace, CoverFile, Merged));
+merge_arguments([{'case',TC}|Args], Merged) ->
+ merge_arguments(Args, handle_arg(merge, {testcase,TC}, Merged));
merge_arguments([Arg={_,_}|Args], Merged) ->
merge_arguments(Args, handle_arg(merge, Arg, Merged));
merge_arguments([], Merged) ->
@@ -1673,6 +1751,23 @@ handle_arg(Op, Arg, [Other|Merged]) ->
handle_arg(_,Arg,[]) ->
[Arg].
+get_start_opt(Key, IfExists, Args) ->
+ get_start_opt(Key, IfExists, undefined, Args);
+
+get_start_opt(Key, IfExists, IfNotExists, Args) ->
+ case lists:keysearch(Key, 1, Args) of
+ {value,{Key,Val}} when is_function(IfExists) ->
+ IfExists(Val);
+ {value,{Key,Val}} when IfExists == value ->
+ Val;
+ {value,{Key,_Val}} ->
+ IfExists;
+ _ when is_function(IfNotExists) ->
+ IfNotExists();
+ _ ->
+ IfNotExists
+ end.
+
locate_test_dir(Dir, Suite) ->
TestDir = case ct_util:is_test_dir(Dir) of
true -> Dir;
@@ -1737,18 +1832,18 @@ start_trace(Args) ->
case file:consult(TraceSpec) of
{ok,Terms} ->
case catch do_trace(Terms) of
- ok ->
+ ok ->
true;
{_,Error} ->
io:format("Warning! Tracing not started. Reason: ~p~n~n",
[Error]),
false
- end;
+ end;
{_,Error} ->
io:format("Warning! Tracing not started. Reason: ~p~n~n",
[Error]),
false
- end;
+ end;
false ->
false
end.
@@ -1760,22 +1855,22 @@ do_trace(Terms) ->
case dbg:tpl(M,[{'_',[],[{return_trace}]}]) of
{error,What} -> exit({error,{tracing_failed,What}});
_ -> ok
- end;
+ end;
({f,M,F}) ->
case dbg:tpl(M,F,[{'_',[],[{return_trace}]}]) of
{error,What} -> exit({error,{tracing_failed,What}});
_ -> ok
- end;
+ end;
(Huh) ->
exit({error,{unrecognized_trace_term,Huh}})
end, Terms),
ok.
-
+
stop_trace(true) ->
dbg:stop_clear();
stop_trace(false) ->
ok.
-
+
ensure_atom(Atom) when is_atom(Atom) ->
Atom;
ensure_atom(String) when is_list(String), is_integer(hd(String)) ->
@@ -1784,4 +1879,3 @@ ensure_atom(List) when is_list(List) ->
[ensure_atom(Item) || Item <- List];
ensure_atom(Other) ->
Other.
-
--
cgit v1.2.3
From 4da38a84f7540856fa590afdba2eb7958978788c Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Thu, 3 Jun 2010 14:27:21 +0200
Subject: Make it possible to run ts tests for Common Test via the
ct_run:script_start() interface
The possibility to pass start arguments to ct_run:start_script/0 by means of an application environment variable has been implemented. This will be used by ct_test_support for automatic testing of all common_test start interfaces.
---
lib/common_test/src/ct_config.erl | 119 ++++++++---------
lib/common_test/src/ct_run.erl | 273 +++++++++++++++++++++++++-------------
lib/common_test/src/ct_util.hrl | 2 +
3 files changed, 244 insertions(+), 150 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index 6314361b35..ee84164ad7 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -164,10 +164,10 @@ delete_default_config(Scope) ->
update_config(Name, Config) ->
call({update_config, {Name, Config}}).
-reload_config(KeyOrName)->
+reload_config(KeyOrName) ->
call({reload_config, KeyOrName}).
-process_default_configs(Opts)->
+process_default_configs(Opts) ->
case lists:keysearch(config, 1, Opts) of
{value,{_,Files=[File|_]}} when is_list(File) ->
Files;
@@ -179,21 +179,21 @@ process_default_configs(Opts)->
[]
end.
-process_user_configs(Opts, Acc)->
+process_user_configs(Opts, Acc) ->
case lists:keytake(userconfig, 1, Opts) of
false->
Acc;
{value, {userconfig, {Callback, []}}, NewOpts}->
process_user_configs(NewOpts, [{Callback, []} | Acc]);
{value, {userconfig, {Callback, Files=[File|_]}}, NewOpts} when
- is_list(File)->
+ is_list(File) ->
process_user_configs(NewOpts, [{Callback, Files} | Acc]);
{value, {userconfig, {Callback, File=[C|_]}}, NewOpts} when
- is_integer(C)->
+ is_integer(C) ->
process_user_configs(NewOpts, [{Callback, [File]} | Acc])
end.
-get_config_file_list(Opts)->
+get_config_file_list(Opts) ->
DefaultConfigs = process_default_configs(Opts),
CfgFiles =
if
@@ -206,16 +206,16 @@ get_config_file_list(Opts)->
CfgFiles.
read_config_files(Opts) ->
- AddCallback = fun(CallBack, [])->
+ AddCallback = fun(CallBack, []) ->
[{CallBack, []}];
- (CallBack, [F|_]=Files) when is_integer(F)->
+ (CallBack, [F|_]=Files) when is_integer(F) ->
[{CallBack, Files}];
- (CallBack, [F|_]=Files) when is_list(F)->
- lists:map(fun(X)-> {CallBack, X} end, Files)
+ (CallBack, [F|_]=Files) when is_list(F) ->
+ lists:map(fun(X) -> {CallBack, X} end, Files)
end,
ConfigFiles = case lists:keyfind(config, 1, Opts) of
{config, ConfigLists}->
- lists:foldr(fun({Callback,Files}, Acc)->
+ lists:foldr(fun({Callback,Files}, Acc) ->
AddCallback(Callback,Files) ++ Acc
end,
[],
@@ -225,18 +225,18 @@ read_config_files(Opts) ->
end,
read_config_files_int(ConfigFiles, fun store_config/3).
-read_config_files_int([{Callback, File}|Files], FunToSave)->
+read_config_files_int([{Callback, File}|Files], FunToSave) ->
case Callback:read_config(File) of
- {ok, Config}->
+ {ok, Config} ->
FunToSave(Config, Callback, File),
read_config_files_int(Files, FunToSave);
{error, ErrorName, ErrorDetail}->
{user_error, {ErrorName, File, ErrorDetail}}
end;
-read_config_files_int([], _FunToSave)->
+read_config_files_int([], _FunToSave) ->
ok.
-store_config(Config, Callback, File)->
+store_config(Config, Callback, File) ->
[ets:insert(?attr_table,
#ct_conf{key=Key,
value=Val,
@@ -246,35 +246,34 @@ store_config(Config, Callback, File)->
default=false}) ||
{Key,Val} <- Config].
-keyfindall(Key, Pos, List)->
+keyfindall(Key, Pos, List) ->
[E || E <- List, element(Pos, E) =:= Key].
-rewrite_config(Config, Callback, File)->
+rewrite_config(Config, Callback, File) ->
OldRows = ets:match_object(?attr_table,
#ct_conf{handler=Callback,
config=File,_='_'}),
ets:match_delete(?attr_table,
#ct_conf{handler=Callback,
config=File,_='_'}),
- Updater = fun({Key, Value})->
+ Updater = fun({Key, Value}) ->
case keyfindall(Key, #ct_conf.key, OldRows) of
[]->
ets:insert(?attr_table,
#ct_conf{key=Key,
- value=Value,
- handler=Callback,
- config=File,
- ref=ct_util:ct_make_ref()});
+ value=Value,
+ handler=Callback,
+ config=File,
+ ref=ct_util:ct_make_ref()});
RowsToUpdate ->
- Inserter = fun(Row)->
- ets:insert(?attr_table,
- Row#ct_conf{value=Value,
- ref=ct_util:ct_make_ref()})
- end,
+ Inserter = fun(Row) ->
+ ets:insert(?attr_table,
+ Row#ct_conf{value=Value,
+ ref=ct_util:ct_make_ref()})
+ end,
lists:foreach(Inserter, RowsToUpdate)
end
- end,
-
+ end,
[Updater({Key, Value})||{Key, Value}<-Config].
set_config(Config,Default) ->
@@ -397,9 +396,9 @@ lookup_key(Key) ->
[],
[{{'$1','$2'}}]}]).
-lookup_handler_for_config({Key, _Subkey})->
+lookup_handler_for_config({Key, _Subkey}) ->
lookup_handler_for_config(Key);
-lookup_handler_for_config(KeyOrName)->
+lookup_handler_for_config(KeyOrName) ->
case lookup_handler_for_name(KeyOrName) of
[] ->
lookup_handler_for_key(KeyOrName);
@@ -407,12 +406,12 @@ lookup_handler_for_config(KeyOrName)->
Values
end.
-lookup_handler_for_name(Name)->
+lookup_handler_for_name(Name) ->
ets:select(?attr_table,[{#ct_conf{handler='$1',config='$2',name=Name,_='_'},
[],
[{{'$1','$2'}}]}]).
-lookup_handler_for_key(Key)->
+lookup_handler_for_key(Key) ->
ets:select(?attr_table,[{#ct_conf{handler='$1',config='$2',key=Key,_='_'},
[],
[{{'$1','$2'}}]}]).
@@ -685,7 +684,7 @@ random_bytes(N) ->
random_bytes_1(0, Acc) -> Acc;
random_bytes_1(N, Acc) -> random_bytes_1(N-1, [random:uniform(255)|Acc]).
-check_callback_load(Callback)->
+check_callback_load(Callback) ->
case code:is_loaded(Callback) of
{file, _Filename}->
{ok, Callback};
@@ -698,16 +697,16 @@ check_callback_load(Callback)->
end
end.
-check_config_files(Configs)->
+check_config_files(Configs) ->
ConfigChecker = fun
- ({Callback, [F|_R]=Files})->
+ ({Callback, [F|_R]=Files}) ->
case check_callback_load(Callback) of
{ok, Callback}->
if
- is_integer(F)->
+ is_integer(F) ->
Callback:check_parameter(Files);
- is_list(F)->
- lists:map(fun(File)->
+ is_list(F) ->
+ lists:map(fun(File) ->
Callback:check_parameter(File)
end,
Files)
@@ -715,7 +714,7 @@ check_config_files(Configs)->
{error, _}->
{error, {callback, Callback}}
end;
- ({Callback, []})->
+ ({Callback, []}) ->
case check_callback_load(Callback) of
{ok, Callback}->
Callback:check_parameter([]);
@@ -725,46 +724,46 @@ check_config_files(Configs)->
end,
lists:keysearch(error, 1, lists:flatten(lists:map(ConfigChecker, Configs))).
-prepare_user_configs([ConfigString|UserConfigs], Acc, new)->
+prepare_user_configs([ConfigString|UserConfigs], Acc, new) ->
prepare_user_configs(UserConfigs,
[{list_to_atom(ConfigString), []}|Acc],
cur);
-prepare_user_configs(["and"|UserConfigs], Acc, _)->
+prepare_user_configs(["and"|UserConfigs], Acc, _) ->
prepare_user_configs(UserConfigs, Acc, new);
-prepare_user_configs([ConfigString|UserConfigs], [{LastMod, LastList}|Acc], cur)->
+prepare_user_configs([ConfigString|UserConfigs], [{LastMod, LastList}|Acc], cur) ->
prepare_user_configs(UserConfigs,
[{LastMod, [ConfigString|LastList]}|Acc],
cur);
-prepare_user_configs([], Acc, _)->
+prepare_user_configs([], Acc, _) ->
Acc.
-prepare_config_list(Args)->
+prepare_config_list(Args) ->
ConfigFiles = case lists:keysearch(ct_config, 1, Args) of
- {value,{ct_config,Files}}->
- [{?ct_config_txt, Files}];
- false->
- []
- end,
+ {value,{ct_config,Files}}->
+ [{?ct_config_txt,[filename:absname(F) || F <- Files]}];
+ false->
+ []
+ end,
UserConfigs = case lists:keysearch(userconfig, 1, Args) of
- {value,{userconfig,UserConfigFiles}}->
- prepare_user_configs(UserConfigFiles, [], new);
- false->
- []
- end,
+ {value,{userconfig,UserConfigFiles}}->
+ prepare_user_configs(UserConfigFiles, [], new);
+ false->
+ []
+ end,
ConfigFiles ++ UserConfigs.
% TODO: add logging of the loaded configuration file to the CT FW log!!!
-add_config(Callback, [])->
+add_config(Callback, []) ->
read_config_files_int([{Callback, []}], fun store_config/3);
-add_config(Callback, [File|_Files]=Config) when is_list(File)->
- lists:foreach(fun(CfgStr)->
+add_config(Callback, [File|_Files]=Config) when is_list(File) ->
+ lists:foreach(fun(CfgStr) ->
read_config_files_int([{Callback, CfgStr}], fun store_config/3) end,
Config);
-add_config(Callback, [C|_]=Config) when is_integer(C)->
+add_config(Callback, [C|_]=Config) when is_integer(C) ->
read_config_files_int([{Callback, Config}], fun store_config/3),
ok.
-remove_config(Callback, Config)->
+remove_config(Callback, Config) ->
ets:match_delete(?attr_table,
#ct_conf{handler=Callback,
config=Config,_='_'}),
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 96703031d2..2c7d72c812 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -73,7 +73,25 @@
%%%
script_start() ->
process_flag(trap_exit, true),
- Args = merge_arguments(init:get_arguments()),
+ Init = init:get_arguments(),
+ CtArgs = lists:takewhile(fun({ct_erl_args,_}) -> false;
+ (_) -> true end, Init),
+ Args = case application:get_env(common_test, run_test_start_opts) of
+ {ok,EnvStartOpts} ->
+ merge_arguments(CtArgs ++ opts2args(EnvStartOpts));
+ _ ->
+ merge_arguments(CtArgs)
+ end,
+
+ %%! --- Mon May 31 12:32:48 2010 --- peppe was here!
+ io:format(user, "~nInit:~n~p~n", [Init]),
+
+ %%! --- Mon May 31 12:32:48 2010 --- peppe was here!
+ io:format(user, "~nCtArgs:~n~p~n", [CtArgs]),
+
+ %%! --- Mon May 31 12:32:48 2010 --- peppe was here!
+ io:format(user, "~nArgs:~n~p~n", [Args]),
+
case proplists:get_value(help, Args) of
undefined -> script_start(Args);
_ -> script_usage()
@@ -126,8 +144,8 @@ script_start1(Parent, Args) ->
Shell = get_start_opt(shell, true, Args),
Cover = get_start_opt(cover, fun(CoverFile) -> ?abs(CoverFile) end, Args),
LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args),
- MultTT = get_start_opt(multiply_timetraps, fun(MT) -> MT end, Args),
- ScaleTT = get_start_opt(scale_timetraps, fun(CT) -> CT end, Args),
+ MultTT = get_start_opt(multiply_timetraps, fun(MT) -> MT end, 1, Args),
+ ScaleTT = get_start_opt(scale_timetraps, fun(CT) -> CT end, false, Args),
EvHandlers = get_start_opt(event_handler,
fun(Handlers) ->
lists:map(fun(H) ->
@@ -186,11 +204,11 @@ script_start1(Parent, Args) ->
application:set_env(common_test, basic_html, true)
end,
- StartOpts = #opts({vts = Vts, shell = Shell, cover = Cover,
- logdir = LogDir, event_handlers = EvHandlers,
- include = IncludeDirs,
- multiply_timetraps = MultTT,
- scale_timetraps = ScaleTT}),
+ StartOpts = #opts{vts = Vts, shell = Shell, cover = Cover,
+ logdir = LogDir, event_handlers = EvHandlers,
+ include = IncludeDirs,
+ multiply_timetraps = MultTT,
+ scale_timetraps = ScaleTT},
%% check if log files should be refreshed or go on to run tests...
Result = run_or_refresh(StartOpts, Args),
@@ -203,7 +221,7 @@ run_or_refresh(StartOpts = #opts{logdir = LogDir}, Args) ->
script_start2(StartOpts, Args);
Refresh ->
LogDir1 = case Refresh of
- [] -> which_logdir(LogDir);
+ [] -> which(logdir,LogDir);
[RefreshDir] -> ?abs(RefreshDir)
end,
{ok,Cwd} = file:get_cwd(),
@@ -232,14 +250,14 @@ run_or_refresh(StartOpts = #opts{logdir = LogDir}, Args) ->
script_start2(StartOpts = #opts{vts = undefined,
shell = undefined}, Args) ->
TestSpec = proplists:get_value(spec, Args),
- Opts =
+ {Terms,Opts} =
case TestSpec of
Specs when Specs =/= [], Specs =/= undefined ->
%% using testspec as input for test
Relaxed = get_start_opt(allow_user_terms, true, false, Args),
case catch ct_testspec:collect_tests_from_file(Specs, Relaxed) of
- {error,Reason} ->
- {error,Reason};
+ {E,Reason} when E == error ; E == 'EXIT' ->
+ {{error,Reason},StartOpts};
TS ->
SpecStartOpts = get_data_for_node(TS, node()),
@@ -258,40 +276,42 @@ script_start2(StartOpts = #opts{vts = undefined,
SpecStartOpts#opts.include]),
application:set_env(common_test, include, AllInclude),
- StartOpts#opts{testspecs = Specs,
- cover = Cover,
- logdir = LogDir,
- config = SpecStartOpts#opts.config,
- event_handlers = AllEvHs,
- include = AllInclude,
- multiply_timetraps = MultTT,
- scale_timetraps = ScaleTT}
+ {TS,StartOpts#opts{testspecs = Specs,
+ cover = Cover,
+ logdir = LogDir,
+ config = SpecStartOpts#opts.config,
+ event_handlers = AllEvHs,
+ include = AllInclude,
+ multiply_timetraps = MultTT,
+ scale_timetraps = ScaleTT}}
end;
_ ->
- StartOpts
+ {undefined,StartOpts}
end,
%% read config/userconfig from start flags
InitConfig = ct_config:prepare_config_list(Args),
- case TestSpec of
- [] ->
+ case {TestSpec,Terms} of
+ {_,{error,_}=Error} ->
+ Error;
+ {[],_} ->
{error,no_testspec_specified};
- undefined -> % no testspec used
+ {undefined,_} -> % no testspec used
case check_and_install_configfiles(InitConfig,
which(logdir,Opts#opts.logdir),
Opts#opts.event_handlers) of
- ok -> % go on read tests from start flags
+ ok -> % go on read tests from start flags
script_start3(Opts#opts{config=InitConfig}, Args);
Error ->
Error
end;
- _ -> % testspec used
+ {_,_} -> % testspec used
%% merge config from start flags with config from testspec
AllConfig = merge_vals([InitConfig, Opts#opts.config]),
case check_and_install_configfiles(AllConfig,
which(logdir,Opts#opts.logdir),
Opts#opts.event_handlers) of
- ok -> % read tests from spec
- {Run,Skip} = ct_testspec:prepare_tests(TS, node()),
+ ok -> % read tests from spec
+ {Run,Skip} = ct_testspec:prepare_tests(Terms, node()),
do_run(Run, Skip, Opts#opts{config=AllConfig}, Args);
Error ->
Error
@@ -314,7 +334,7 @@ check_and_install_configfiles(Configs, LogDir, EvHandlers) ->
{error,{cant_load_callback_module,File}}
end.
-script_start3(StartOpts = #opts{cover = Cover}, Args) ->
+script_start3(StartOpts, Args) ->
case proplists:get_value(dir, Args) of
[] ->
{error,no_dir_specified};
@@ -332,8 +352,8 @@ script_start3(StartOpts = #opts{cover = Cover}, Args) ->
cover = undefined}
end, StartOpts, Args),
DirMods = [suite_to_test(S) || S <- Suites],
- case groups_and_cases(proplist:get_value(group, Args),
- proplist:get_value(testcase, Args)) of
+ case groups_and_cases(proplists:get_value(group, Args),
+ proplists:get_value(testcase, Args)) of
Error = {error,_} ->
Error;
[] when DirMods =/= [] ->
@@ -357,14 +377,14 @@ script_start3(StartOpts = #opts{cover = Cover}, Args) ->
end
end.
-script_start4(#opts{vts = true, config = Config, event_handler = EvHandlers,
- tests = Tests, logdir = LogDir}, Args) ->
+script_start4(#opts{vts = true, config = Config, event_handlers = EvHandlers,
+ tests = Tests, logdir = LogDir}, _Args) ->
vts:init_data(Config, EvHandlers, ?abs(LogDir), Tests);
script_start4(#opts{shell = true, config = Config, event_handlers = EvHandlers,
- logdir = LogDir, testspecs = Specs}, Args) ->
+ logdir = LogDir, testspecs = Specs}, _Args) ->
InstallOpts = [{config,Config},{event_handler,EvHandlers}],
- if ConfigFiles == [] ->
+ if Config == [] ->
ok;
true ->
io:format("\nInstalling: ~p\n\n", [Config])
@@ -485,7 +505,7 @@ install(Opts, LogDir) ->
case whereis(ct_util_server) of
undefined ->
VarFile = variables_file_name(LogDir),
- io:format("Varfile=~p~n", [VarFile]),
+ io:format("Varfile = ~p~n", [VarFile]),
case file:open(VarFile, [write]) of
{ok,Fd} ->
[io:format(Fd, "~p.\n", [Opt]) || Opt <- Opts],
@@ -522,7 +542,7 @@ run_test(StartOpt) when is_tuple(StartOpt) ->
run_test([StartOpt]);
run_test(StartOpts) when is_list(StartOpts) ->
- case proplist:get_value(refresh_logs, StartOpts) of
+ case proplists:get_value(refresh_logs, StartOpts) of
undefined ->
Tracing = start_trace(StartOpts),
{ok,Cwd} = file:get_cwd(),
@@ -621,13 +641,13 @@ run_test1(StartOpts) ->
end,
%% decrypt config file
- case lists:keysearch(decrypt, 1, StartOpts) of
- {value,{_,Key={key,_}}} ->
+ case proplists:get_value(decrypt, StartOpts) of
+ undefined ->
+ application:unset_env(common_test, decrypt);
+ Key={key,_} ->
application:set_env(common_test, decrypt, Key);
- {value,{_,{file,KeyFile}}} ->
- application:set_env(common_test, decrypt, {file,filename:absname(KeyFile)});
- false ->
- application:unset_env(common_test, decrypt)
+ {file,KeyFile} ->
+ application:set_env(common_test, decrypt, {file,filename:absname(KeyFile)})
end,
%% basic html - used by ct_logs
@@ -639,7 +659,7 @@ run_test1(StartOpts) ->
end,
%% stepped execution
- Step = get_start_opt(step, value, StepOpts),
+ Step = get_start_opt(step, value, StartOpts),
Opts = #opts{cover = Cover, step = Step, logdir = LogDir, config = CfgFiles,
event_handlers = EvHandlers, include = Include,
@@ -661,11 +681,6 @@ run_test1(StartOpts) ->
run_spec_file(Relaxed, Opts#opts{testspecs = Specs}, StartOpts)
end.
-replace_opt([O={Key,_Val}|Os], Opts) ->
- [O | replace_opt(Os, lists:keydelete(Key, 1, Opts))];
-replace_opt([], Opts) ->
- Opts.
-
run_spec_file(Relaxed,
Opts = #opts{testspecs = Specs, config = CfgFiles},
StartOpts) ->
@@ -676,7 +691,7 @@ run_spec_file(Relaxed,
AbsSpecs = lists:map(fun(SF) -> ?abs(SF) end, Specs1),
log_ts_names(AbsSpecs),
case catch ct_testspec:collect_tests_from_file(AbsSpecs, Relaxed) of
- {error,CTReason} ->
+ {Error,CTReason} when Error == error ; Error == 'EXIT' ->
exit(CTReason);
TS ->
SpecOpts = get_data_for_node(TS, node()),
@@ -699,16 +714,14 @@ run_spec_file(Relaxed,
which(logdir,LogDir),
AllEvHs) of
ok ->
- Opts1 = Opts#opts{testspecs = Specs,
- cover = Cover,
+ Opts1 = Opts#opts{cover = Cover,
logdir = LogDir,
config = AllConfig,
event_handlers = AllEvHs,
include = AllInclude,
testspecs = AbsSpecs,
multiply_timetraps = MultTT,
- scale_timetraps = ScaleTT}
-
+ scale_timetraps = ScaleTT},
{Run,Skip} = ct_testspec:prepare_tests(TS, node()),
do_run(Run, Skip, Opts1, StartOpts);
{error,GCFReason} ->
@@ -768,7 +781,7 @@ run_dir(Opts = #opts{logdir = LogDir,
{value,{_,Dirs=[Dir|_]}} when not is_integer(Dir),
length(Dirs)>1 ->
%% multiple dirs (no suite)
- do_run(tests(Dirs), [], StepOrCover, Opts, LogDir);
+ do_run(tests(Dirs), [], Opts, StartOpts);
false -> % no dir
%% fun for converting suite name to {Dir,Mod} tuple
S2M = fun(S) when is_list(S) ->
@@ -783,12 +796,12 @@ run_dir(Opts = #opts{logdir = LogDir,
case listify(proplists:get_value(group, Opts, [])) ++
listify(proplists:get_value(testcase, Opts, [])) of
[] ->
- do_run(tests(Dir, listify(Mod)), [], StepOrCover, Opts, LogDir);
+ do_run(tests(Dir, listify(Mod)), [], Opts, StartOpts);
GsAndCs ->
- do_run(tests(Dir, Mod, GsAndCs), [], StepOrCover, Opts, LogDir)
+ do_run(tests(Dir, Mod, GsAndCs), [], Opts, StartOpts)
end;
{value,{_,Suites}} ->
- do_run(tests(lists:map(S2M, Suites)), [], StepOrCover, Opts, LogDir);
+ do_run(tests(lists:map(S2M, Suites)), [], Opts, StartOpts);
_ ->
exit(no_tests_specified)
end;
@@ -801,17 +814,17 @@ run_dir(Opts = #opts{logdir = LogDir,
case listify(proplists:get_value(group, Opts, [])) ++
listify(proplists:get_value(testcase, Opts, [])) of
[] ->
- do_run(tests(Dir, listify(Mod)), [], StepOrCover, Opts, LogDir);
+ do_run(tests(Dir, listify(Mod)), [], Opts, StartOpts);
GsAndCs ->
- do_run(tests(Dir, Mod, GsAndCs), [], StepOrCover, Opts, LogDir)
+ do_run(tests(Dir, Mod, GsAndCs), [], Opts, StartOpts)
end;
{value,{_,Suites=[Suite|_]}} when is_list(Suite) ->
Mods = lists:map(fun(Str) -> list_to_atom(Str) end, Suites),
- do_run(tests(delistify(Dir), Mods), [], StepOrCover, Opts, LogDir);
+ do_run(tests(delistify(Dir), Mods), [], Opts, StartOpts);
{value,{_,Suites}} ->
- do_run(tests(delistify(Dir), Suites), [], StepOrCover, Opts, LogDir);
+ do_run(tests(delistify(Dir), Suites), [], Opts, StartOpts);
false -> % no suite, only dir
- do_run(tests(listify(Dir)), [], StepOrCover, Opts, LogDir)
+ do_run(tests(listify(Dir)), [], Opts, StartOpts)
end
end.
@@ -836,8 +849,8 @@ run_testspec(TestSpec) ->
end.
run_testspec1(TestSpec) ->
- case ct_testspec:collect_tests_from_list(TestSpec, false) of
- {error,CTReason} ->
+ case catch ct_testspec:collect_tests_from_list(TestSpec, false) of
+ {E,CTReason} when E == error ; E == 'EXIT' ->
exit(CTReason);
TS ->
Opts = get_data_for_node(TS, node()),
@@ -848,7 +861,7 @@ run_testspec1(TestSpec) ->
Opts#opts.include;
CtInclPath ->
EnvInclude = string:tokens(CtInclPath, [$:,$ ,$,]),
- EnvInclude++Opts#opts.include,
+ EnvInclude++Opts#opts.include
end,
application:set_env(common_test, include, AllInclude),
@@ -968,8 +981,8 @@ run(TestDirs) ->
suite_to_test(Suite) ->
{filename:dirname(Suite),list_to_atom(filename:rootname(filename:basename(Suite)))}.
-groups_and_cases(Gs, Cs) when (Gs == undefined ; Gs == []),
- (Cs == undefined ; Cs == []) ->
+groups_and_cases(Gs, Cs) when ((Gs == undefined) or (Gs == [])) and
+ ((Cs == undefined) or (Cs == [])) ->
[];
groups_and_cases(Gs, Cs) when Gs == undefined ; Gs == [] ->
[list_to_atom(C) || C <- Cs];
@@ -979,7 +992,7 @@ groups_and_cases([G], Cs) ->
[{list_to_atom(G),[list_to_atom(C) || C <- Cs]}];
groups_and_cases([_,_|_] , Cs) when Cs =/= [] ->
{error,multiple_groups_and_cases};
-groups_and_cases(Gs, Cs) ->
+groups_and_cases(_Gs, _Cs) ->
{error,incorrect_group_or_case_option}.
tests(TestDir, Suites, []) when is_list(TestDir), is_integer(hd(TestDir)) ->
@@ -997,11 +1010,28 @@ tests(TestDir) when is_list(TestDir), is_integer(hd(TestDir)) ->
tests(TestDirs) when is_list(TestDirs), is_list(hd(TestDirs)) ->
[{?testdir(TestDir,all),all,all} || TestDir <- TestDirs].
-do_run(Tests, Opt, LogDir) when is_list(Opt) ->
- do_run(Tests, [], #opts{tests = Tests, logdir = LogDir}, []).
+do_run(Tests, Misc) when is_list(Misc) ->
+ do_run(Tests, Misc, ".").
+
+do_run(Tests, Misc, LogDir) when is_list(Misc) ->
+ Opts =
+ case proplists:get_value(step, Misc) of
+ undefined ->
+ #opts{};
+ StepOpts ->
+ #opts{step = StepOpts}
+ end,
+ Opts1 =
+ case proplists:get_value(cover, Misc) of
+ undefined ->
+ Opts;
+ CoverFile ->
+ Opts#opts{cover = CoverFile}
+ end,
+ do_run(Tests, [], Opts1#opts{tests = Tests, logdir = LogDir}, []).
do_run(Tests, Skip, Opts, Args) ->
- #opts{cover = Cover} = Opts
+ #opts{cover = Cover} = Opts,
case code:which(test_server) of
non_existing ->
exit({error,no_path_to_test_server});
@@ -1026,7 +1056,7 @@ do_run(Tests, Skip, Opts, Args) ->
Other ->
erlang:display(list_to_atom("Note: TEST_SERVER_FRAMEWORK = " ++ Other))
end,
- case ct_util:start(LogDir) of
+ case ct_util:start(Opts#opts.logdir) of
{error,interactive_mode} ->
io:format("CT is started in interactive mode. "
"To exit this mode, run ct:stop_interactive().\n"
@@ -1421,7 +1451,7 @@ do_run_test(Tests, Skip, Opts) ->
ok
end,
lists:foreach(fun(Suite) ->
- maybe_cleanup_interpret(Suite, Opt)
+ maybe_cleanup_interpret(Suite, Opts#opts.step)
end, CleanUp);
Error ->
Error
@@ -1714,10 +1744,10 @@ set_break_on_config(Suite, StepOpts) ->
ok
end.
-maybe_cleanup_interpret(Suite, [{step,_}]) ->
- i:iq(Suite);
-maybe_cleanup_interpret(_, _) ->
- ok.
+maybe_cleanup_interpret(_, undefined) ->
+ ok;
+maybe_cleanup_interpret(Suite, _) ->
+ i:iq(Suite).
log_ts_names([]) ->
ok;
@@ -1729,17 +1759,42 @@ log_ts_names(Specs) ->
[lists:flatten(List)]).
merge_arguments(Args) ->
- merge_arguments(Args, []).
-
-merge_arguments([LogDir={logdir,_}|Args], Merged) ->
- merge_arguments(Args, handle_arg(replace, LogDir, Merged));
-merge_arguments([CoverFile={cover,_}|Args], Merged) ->
- merge_arguments(Args, handle_arg(replace, CoverFile, Merged));
-merge_arguments([{'case',TC}|Args], Merged) ->
- merge_arguments(Args, handle_arg(merge, {testcase,TC}, Merged));
-merge_arguments([Arg={_,_}|Args], Merged) ->
- merge_arguments(Args, handle_arg(merge, Arg, Merged));
-merge_arguments([], Merged) ->
+ case proplists:get_value(ct_ignore, Args) of
+ undefined ->
+ merge_arguments(Args, [], []);
+ Ignore ->
+ merge_arguments(Args, [], [list_to_atom(I) || I <- Ignore])
+ end.
+
+merge_arguments([LogDir={logdir,_}|Args], Merged, Ignore) ->
+ case lists:member(logdir, Ignore) of
+ true ->
+ merge_arguments(Args, Merged, Ignore);
+ false ->
+ merge_arguments(Args, handle_arg(replace, LogDir, Merged), Ignore)
+ end;
+merge_arguments([CoverFile={cover,_}|Args], Merged, Ignore) ->
+ case lists:member(cover, Ignore) of
+ true ->
+ merge_arguments(Args, Merged, Ignore);
+ false ->
+ merge_arguments(Args, handle_arg(replace, CoverFile, Merged), Ignore)
+ end;
+merge_arguments([{'case',TC}|Args], Merged, Ignore) ->
+ case lists:member('case', Ignore) of
+ true ->
+ merge_arguments(Args, Merged, Ignore);
+ false ->
+ merge_arguments(Args, handle_arg(merge, {testcase,TC}, Merged), Ignore)
+ end;
+merge_arguments([Arg={Opt,_}|Args], Merged, Ignore) ->
+ case lists:member(Opt, Ignore) of
+ true ->
+ merge_arguments(Args, Merged, Ignore);
+ false ->
+ merge_arguments(Args, handle_arg(merge, Arg, Merged), Ignore)
+ end;
+merge_arguments([], Merged, _Ignore) ->
Merged.
handle_arg(replace, {Key,Elems}, [{Key,_}|Merged]) ->
@@ -1752,7 +1807,7 @@ handle_arg(_,Arg,[]) ->
[Arg].
get_start_opt(Key, IfExists, Args) ->
- get_start_opt(Key, IfExists, undefined, Args);
+ get_start_opt(Key, IfExists, undefined, Args).
get_start_opt(Key, IfExists, IfNotExists, Args) ->
case lists:keysearch(Key, 1, Args) of
@@ -1768,6 +1823,44 @@ get_start_opt(Key, IfExists, IfNotExists, Args) ->
IfNotExists
end.
+%% this function translates ct:run_test/1 start options
+%% to run_test start arguments (on the init arguments format) -
+%% this is useful mainly for testing the ct_run start functions
+opts2args(EnvStartOpts) ->
+ lists:flatmap(fun({config,CfgFiles}) ->
+ [{ct_config,CfgFiles}];
+ ({testcase,Cases}) ->
+ [{'case',[atom_to_list(C) || C <- Cases]}];
+ ({'case',Cases}) ->
+ [{'case',[atom_to_list(C) || C <- Cases]}];
+ ({allow_user_terms,true}) ->
+ [{allow_user_terms,[]}];
+ ({allow_user_terms,false}) ->
+ [];
+ ({auto_compile,false}) ->
+ [{no_auto_compile,[]}];
+ ({auto_compile,true}) ->
+ [];
+ ({scale_timetraps,true}) ->
+ [{scale_timetraps,[]}];
+ ({scale_timetraps,false}) ->
+ [];
+ ({force_stop,true}) ->
+ [{force_stop,[]}];
+ ({force_stop,false}) ->
+ [];
+ ({decrypt,{key,Key}}) ->
+ [{ct_decrypt_key,Key}];
+ ({decrypt,{file,File}}) ->
+ [{ct_decrypt_file,File}];
+ ({basic_html,true}) ->
+ ({basic_html,[]});
+ ({basic_html,false}) ->
+ [];
+ (Opt) ->
+ Opt
+ end, EnvStartOpts).
+
locate_test_dir(Dir, Suite) ->
TestDir = case ct_util:is_test_dir(Dir) of
true -> Dir;
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index 7ddb7d8c2b..d9c5631f88 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -36,6 +36,8 @@
userconfig=[],
event_handler=[],
include=[],
+ multiply_timetraps,
+ scale_timetraps,
alias=[],
tests=[]}).
--
cgit v1.2.3
From 7c6504029f84c52de40a6b29b2fd1b17c053ccec Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Thu, 3 Jun 2010 14:34:09 +0200
Subject: Add event_handler_init start flag that can pass init arguments to
event handlers
Also changed: The userconfig option in ct:run_test/1 from 3-tuple to 2-tuple.
---
lib/common_test/src/ct.erl | 5 +-
lib/common_test/src/ct_config.erl | 21 ++++--
lib/common_test/src/ct_run.erl | 154 +++++++++++++++++++++++++-------------
3 files changed, 120 insertions(+), 60 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 57035719e2..307d10428d 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -139,7 +139,7 @@ run(TestDirs) ->
%%% @spec run_test(Opts) -> Result
%%% Opts = [OptTuples]
%%% OptTuples = {config,CfgFiles} | {dir,TestDirs} | {suite,Suites} |
-%%% {userconfig, Callback, CfgFiles} |
+%%% {userconfig, UserConfig} |
%%% {testcase,Cases} | {group,Groups} | {spec,TestSpecs} |
%%% {allow_user_terms,Bool} | {logdir,LogDir} |
%%% {silent_connections,Conns} | {cover,CoverSpecFile} |
@@ -149,6 +149,9 @@ run(TestDirs) ->
%%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} |
%%% {refresh_logs,LogDir} | {basic_html,Bool}
%%% CfgFiles = [string()] | string()
+%%% UserConfig = [{CallbackMod,CfgStrings}] | {CallbackMod,CfgStrings}
+%%% CallbackMod = atom()
+%%% CfgStrings = [string()] | string()
%%% TestDirs = [string()] | string()
%%% Suites = [string()] | string()
%%% Cases = [atom()] | atom()
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index ee84164ad7..a7b8a9e906 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -181,15 +181,22 @@ process_default_configs(Opts) ->
process_user_configs(Opts, Acc) ->
case lists:keytake(userconfig, 1, Opts) of
- false->
- Acc;
- {value, {userconfig, {Callback, []}}, NewOpts}->
+ false ->
+ lists:reverse(Acc);
+ {value, {userconfig, Config=[{_,_}|_]}, NewOpts} ->
+ Acc1 = lists:map(fun({_Callback, []}=Cfg) ->
+ Cfg;
+ ({Callback, Files=[File|_]}) when is_list(File) ->
+ {Callback, Files};
+ ({Callback, File=[C|_]}) when is_integer(C) ->
+ {Callback, [File]}
+ end, Config),
+ process_user_configs(NewOpts, lists:reverse(Acc1)++Acc);
+ {value, {userconfig, {Callback, []}}, NewOpts} ->
process_user_configs(NewOpts, [{Callback, []} | Acc]);
- {value, {userconfig, {Callback, Files=[File|_]}}, NewOpts} when
- is_list(File) ->
+ {value, {userconfig, {Callback, Files=[File|_]}}, NewOpts} when is_list(File) ->
process_user_configs(NewOpts, [{Callback, Files} | Acc]);
- {value, {userconfig, {Callback, File=[C|_]}}, NewOpts} when
- is_integer(C) ->
+ {value, {userconfig, {Callback, File=[C|_]}}, NewOpts} when is_integer(C) ->
process_user_configs(NewOpts, [{Callback, [File]} | Acc])
end.
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 2c7d72c812..ec9351f346 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -78,6 +78,9 @@ script_start() ->
(_) -> true end, Init),
Args = case application:get_env(common_test, run_test_start_opts) of
{ok,EnvStartOpts} ->
+ %%! --- Mon May 31 22:59:29 2010 --- peppe was here!
+ io:format(user, "~nEnv1:~n~p~n~n~p~n", [EnvStartOpts,opts2args(EnvStartOpts)]),
+
merge_arguments(CtArgs ++ opts2args(EnvStartOpts));
_ ->
merge_arguments(CtArgs)
@@ -146,12 +149,10 @@ script_start1(Parent, Args) ->
LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args),
MultTT = get_start_opt(multiply_timetraps, fun(MT) -> MT end, 1, Args),
ScaleTT = get_start_opt(scale_timetraps, fun(CT) -> CT end, false, Args),
- EvHandlers = get_start_opt(event_handler,
- fun(Handlers) ->
- lists:map(fun(H) ->
- {list_to_atom(H),[]}
- end, Handlers) end,
- [], Args),
+ EvHandlers = event_handler_args2opts(Args),
+
+ %%! --- Mon May 31 23:16:45 2010 --- peppe was here!
+ io:format(user, "~nEvHandlers = ~p~n~n", [EvHandlers]),
%% check flags and set corresponding application env variables
@@ -505,7 +506,10 @@ install(Opts, LogDir) ->
case whereis(ct_util_server) of
undefined ->
VarFile = variables_file_name(LogDir),
+
+ %%! --- Tue Jun 1 00:20:33 2010 --- peppe was here!
io:format("Varfile = ~p~n", [VarFile]),
+
case file:open(VarFile, [write]) of
{ok,Fd} ->
[io:format(Fd, "~p.\n", [Opt]) || Opt <- Opts],
@@ -599,6 +603,10 @@ run_test1(StartOpts) ->
end, Hs))
end,
+ %%! --- Mon May 31 23:16:45 2010 --- peppe was here!
+ io:format("~nEvHandlers = ~p~n~n", [EvHandlers]),
+ io:format(user, "~nEvHandlers = ~p~n~n", [EvHandlers]),
+
%% silent connections
SilentConns = get_start_opt(silent_connections,
fun(all) -> [];
@@ -777,7 +785,7 @@ run_dir(Opts = #opts{logdir = LogDir,
ok -> ok;
{error,IReason} -> exit(IReason)
end,
- case lists:keysearch(dir, 1, Opts) of
+ case lists:keysearch(dir, 1, StartOpts) of
{value,{_,Dirs=[Dir|_]}} when not is_integer(Dir),
length(Dirs)>1 ->
%% multiple dirs (no suite)
@@ -790,11 +798,11 @@ run_dir(Opts = #opts{logdir = LogDir,
(A) ->
{".",A}
end,
- case lists:keysearch(suite, 1, Opts) of
+ case lists:keysearch(suite, 1, StartOpts) of
{value,{_,Suite}} when is_integer(hd(Suite)) ; is_atom(Suite) ->
{Dir,Mod} = S2M(Suite),
- case listify(proplists:get_value(group, Opts, [])) ++
- listify(proplists:get_value(testcase, Opts, [])) of
+ case listify(proplists:get_value(group, StartOpts, [])) ++
+ listify(proplists:get_value(testcase, StartOpts, [])) of
[] ->
do_run(tests(Dir, listify(Mod)), [], Opts, StartOpts);
GsAndCs ->
@@ -806,13 +814,13 @@ run_dir(Opts = #opts{logdir = LogDir,
exit(no_tests_specified)
end;
{value,{_,Dir}} ->
- case lists:keysearch(suite, 1, Opts) of
+ case lists:keysearch(suite, 1, StartOpts) of
{value,{_,Suite}} when is_integer(hd(Suite)) ; is_atom(Suite) ->
Mod = if is_atom(Suite) -> Suite;
true -> list_to_atom(Suite)
end,
- case listify(proplists:get_value(group, Opts, [])) ++
- listify(proplists:get_value(testcase, Opts, [])) of
+ case listify(proplists:get_value(group, StartOpts, [])) ++
+ listify(proplists:get_value(testcase, StartOpts, [])) of
[] ->
do_run(tests(Dir, listify(Mod)), [], Opts, StartOpts);
GsAndCs ->
@@ -1028,7 +1036,7 @@ do_run(Tests, Misc, LogDir) when is_list(Misc) ->
CoverFile ->
Opts#opts{cover = CoverFile}
end,
- do_run(Tests, [], Opts1#opts{tests = Tests, logdir = LogDir}, []).
+ do_run(Tests, [], Opts1#opts{logdir = LogDir}, []).
do_run(Tests, Skip, Opts, Args) ->
#opts{cover = Cover} = Opts,
@@ -1759,46 +1767,29 @@ log_ts_names(Specs) ->
[lists:flatten(List)]).
merge_arguments(Args) ->
- case proplists:get_value(ct_ignore, Args) of
- undefined ->
- merge_arguments(Args, [], []);
- Ignore ->
- merge_arguments(Args, [], [list_to_atom(I) || I <- Ignore])
- end.
+ merge_arguments(Args, []).
-merge_arguments([LogDir={logdir,_}|Args], Merged, Ignore) ->
- case lists:member(logdir, Ignore) of
- true ->
- merge_arguments(Args, Merged, Ignore);
- false ->
- merge_arguments(Args, handle_arg(replace, LogDir, Merged), Ignore)
- end;
-merge_arguments([CoverFile={cover,_}|Args], Merged, Ignore) ->
- case lists:member(cover, Ignore) of
- true ->
- merge_arguments(Args, Merged, Ignore);
- false ->
- merge_arguments(Args, handle_arg(replace, CoverFile, Merged), Ignore)
- end;
-merge_arguments([{'case',TC}|Args], Merged, Ignore) ->
- case lists:member('case', Ignore) of
- true ->
- merge_arguments(Args, Merged, Ignore);
- false ->
- merge_arguments(Args, handle_arg(merge, {testcase,TC}, Merged), Ignore)
- end;
-merge_arguments([Arg={Opt,_}|Args], Merged, Ignore) ->
- case lists:member(Opt, Ignore) of
- true ->
- merge_arguments(Args, Merged, Ignore);
- false ->
- merge_arguments(Args, handle_arg(merge, Arg, Merged), Ignore)
- end;
-merge_arguments([], Merged, _Ignore) ->
+merge_arguments([LogDir={logdir,_}|Args], Merged) ->
+ merge_arguments(Args, handle_arg(replace, LogDir, Merged));
+
+merge_arguments([CoverFile={cover,_}|Args], Merged) ->
+ merge_arguments(Args, handle_arg(replace, CoverFile, Merged));
+
+merge_arguments([{'case',TC}|Args], Merged) ->
+ merge_arguments(Args, handle_arg(merge, {testcase,TC}, Merged));
+
+merge_arguments([Arg|Args], Merged) ->
+ merge_arguments(Args, handle_arg(merge, Arg, Merged));
+
+merge_arguments([], Merged) ->
Merged.
handle_arg(replace, {Key,Elems}, [{Key,_}|Merged]) ->
[{Key,Elems}|Merged];
+handle_arg(merge, {event_handler_init,Elems}, [{event_handler_init,PrevElems}|Merged]) ->
+ [{event_handler_init,PrevElems++["add"|Elems]}|Merged];
+handle_arg(merge, {userconfig,Elems}, [{userconfig,PrevElems}|Merged]) ->
+ [{userconfig,PrevElems++["add"|Elems]}|Merged];
handle_arg(merge, {Key,Elems}, [{Key,PrevElems}|Merged]) ->
[{Key,PrevElems++Elems}|Merged];
handle_arg(Op, Arg, [Other|Merged]) ->
@@ -1823,12 +1814,47 @@ get_start_opt(Key, IfExists, IfNotExists, Args) ->
IfNotExists
end.
+event_handler_args2opts(Args) ->
+ case proplists:get_value(event_handler, Args) of
+ undefined ->
+ event_handler_args2opts([], Args);
+ EHs ->
+ event_handler_args2opts([{list_to_atom(EH),[]} || EH <- EHs], Args)
+ end.
+event_handler_args2opts(Default, Args) ->
+ case proplists:get_value(event_handler_init, Args) of
+ undefined ->
+ Default;
+ EHs ->
+ event_handler_init_args2opts(EHs)
+ end.
+event_handler_init_args2opts([EH, Arg, "and" | EHs]) ->
+ [{list_to_atom(EH),lists:flatten(io_lib:format("~s",[Arg]))} |
+ event_handler_init_args2opts(EHs)];
+event_handler_init_args2opts([EH, Arg]) ->
+ [{list_to_atom(EH),lists:flatten(io_lib:format("~s",[Arg]))}];
+event_handler_init_args2opts([]) ->
+ [].
+
%% this function translates ct:run_test/1 start options
%% to run_test start arguments (on the init arguments format) -
%% this is useful mainly for testing the ct_run start functions
opts2args(EnvStartOpts) ->
lists:flatmap(fun({config,CfgFiles}) ->
- [{ct_config,CfgFiles}];
+ [{ct_config,[CfgFiles]}];
+ ({userconfig,{CBM,CfgStr=[X|_]}}) when is_integer(X) ->
+ [{userconfig,[atom_to_list(CBM),CfgStr]}];
+ ({userconfig,{CBM,CfgStrs}}) when is_list(CfgStrs) ->
+ [{userconfig,[atom_to_list(CBM) | CfgStrs]}];
+ ({userconfig,UserCfg}) when is_list(UserCfg) ->
+ Strs =
+ lists:map(fun({CBM,CfgStr=[X|_]}) when is_integer(X) ->
+ [atom_to_list(CBM),CfgStr,"and"];
+ ({CBM,CfgStrs}) when is_list(CfgStrs) ->
+ [atom_to_list(CBM) | CfgStrs] ++ ["and"]
+ end, UserCfg),
+ [_LastAnd|StrsR] = lists:reverse(lists:flatten(Strs)),
+ [{userconfig,lists:reverse(StrsR)}];
({testcase,Cases}) ->
[{'case',[atom_to_list(C) || C <- Cases]}];
({'case',Cases}) ->
@@ -1850,13 +1876,37 @@ opts2args(EnvStartOpts) ->
({force_stop,false}) ->
[];
({decrypt,{key,Key}}) ->
- [{ct_decrypt_key,Key}];
+ [{ct_decrypt_key,[Key]}];
({decrypt,{file,File}}) ->
- [{ct_decrypt_file,File}];
+ [{ct_decrypt_file,[File]}];
({basic_html,true}) ->
({basic_html,[]});
({basic_html,false}) ->
[];
+ ({event_handler,EH}) when is_atom(EH) ->
+ [{event_handler,[atom_to_list(EH)]}];
+ ({event_handler,EHs}) when is_list(EHs) ->
+ [{event_handler,[atom_to_list(EH) || EH <- EHs]}];
+ ({event_handler,{EH,Arg}}) when is_atom(EH) ->
+ ArgStr = lists:flatten(io_lib:format("~p", [Arg])),
+ [{event_handler_init,[atom_to_list(EH),ArgStr]}];
+ ({event_handler,{EHs,Arg}}) when is_list(EHs) ->
+ ArgStr = lists:flatten(io_lib:format("~p", [Arg])),
+ Strs = lists:map(fun(EH) ->
+ [atom_to_list(EH),ArgStr,"and"]
+ end, EHs),
+ [_LastAnd|StrsR] = lists:reverse(lists:flatten(Strs)),
+ [{event_handler_init,lists:reverse(StrsR)}];
+ ({Opt,As=[A|_]}) when is_atom(A) ->
+ [{Opt,[atom_to_list(Atom) || Atom <- As]}];
+ ({Opt,Strs=[S|_]}) when is_list(S) ->
+ [{Opt,[Strs]}];
+ ({Opt,A}) when is_atom(A) ->
+ [{Opt,[atom_to_list(A)]}];
+ ({Opt,I}) when is_integer(I) ->
+ [{Opt,[integer_to_list(I)]}];
+ ({Opt,S}) when is_list(S) ->
+ [{Opt,[S]}];
(Opt) ->
Opt
end, EnvStartOpts).
--
cgit v1.2.3
From 5d01bdc2c4c3cc18150711ebfab4c84abdfc0b45 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Thu, 3 Jun 2010 14:40:16 +0200
Subject: Improve and fix various test suites
---
lib/common_test/src/ct_run.erl | 58 +++++++++++++++++++------------------
lib/common_test/src/ct_testspec.erl | 38 ++++++++++++++++++++----
lib/common_test/src/ct_util.hrl | 4 +--
3 files changed, 64 insertions(+), 36 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index ec9351f346..7037ac7c1e 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -76,25 +76,32 @@ script_start() ->
Init = init:get_arguments(),
CtArgs = lists:takewhile(fun({ct_erl_args,_}) -> false;
(_) -> true end, Init),
- Args = case application:get_env(common_test, run_test_start_opts) of
- {ok,EnvStartOpts} ->
- %%! --- Mon May 31 22:59:29 2010 --- peppe was here!
- io:format(user, "~nEnv1:~n~p~n~n~p~n", [EnvStartOpts,opts2args(EnvStartOpts)]),
-
- merge_arguments(CtArgs ++ opts2args(EnvStartOpts));
- _ ->
- merge_arguments(CtArgs)
- end,
-
- %%! --- Mon May 31 12:32:48 2010 --- peppe was here!
- io:format(user, "~nInit:~n~p~n", [Init]),
-
- %%! --- Mon May 31 12:32:48 2010 --- peppe was here!
- io:format(user, "~nCtArgs:~n~p~n", [CtArgs]),
-
- %%! --- Mon May 31 12:32:48 2010 --- peppe was here!
- io:format(user, "~nArgs:~n~p~n", [Args]),
-
+ Args =
+ case application:get_env(common_test, run_test_start_opts) of
+ {ok,EnvStartOpts} ->
+ FlagFilter = fun(Flags) ->
+ lists:filter(fun({root,_}) -> false;
+ ({progname,_}) -> false;
+ ({home,_}) -> false;
+ ({noshell,_}) -> false;
+ ({noinput,_}) -> false;
+ (_) -> true
+ end, Flags)
+ end,
+ %% used for purpose of testing the run_test interface
+ io:format(user, "~n--------------- START ARGS ---------------~n", []),
+ io:format(user, "--- Init args:~n~p~n", [FlagFilter(Init)]),
+ io:format(user, "--- CT args:~n~p~n", [FlagFilter(CtArgs)]),
+ EnvArgs = opts2args(EnvStartOpts),
+ io:format(user, "--- Env opts -> args:~n~p~n =>~n~p~n",
+ [EnvStartOpts,EnvArgs]),
+ Merged = merge_arguments(CtArgs ++ EnvArgs),
+ io:format(user, "--- Merged args:~n~p~n", [FlagFilter(Merged)]),
+ io:format(user, "------------------------------------------~n~n", []),
+ Merged;
+ _ ->
+ merge_arguments(CtArgs)
+ end,
case proplists:get_value(help, Args) of
undefined -> script_start(Args);
_ -> script_usage()
@@ -151,9 +158,6 @@ script_start1(Parent, Args) ->
ScaleTT = get_start_opt(scale_timetraps, fun(CT) -> CT end, false, Args),
EvHandlers = event_handler_args2opts(Args),
- %%! --- Mon May 31 23:16:45 2010 --- peppe was here!
- io:format(user, "~nEvHandlers = ~p~n~n", [EvHandlers]),
-
%% check flags and set corresponding application env variables
%% ct_decrypt_key | ct_decrypt_file
@@ -603,10 +607,6 @@ run_test1(StartOpts) ->
end, Hs))
end,
- %%! --- Mon May 31 23:16:45 2010 --- peppe was here!
- io:format("~nEvHandlers = ~p~n~n", [EvHandlers]),
- io:format(user, "~nEvHandlers = ~p~n~n", [EvHandlers]),
-
%% silent connections
SilentConns = get_start_opt(silent_connections,
fun(all) -> [];
@@ -684,7 +684,7 @@ run_test1(StartOpts) ->
run_prepared(Run, Skip, Opts#opts{testspecs = Specs}, StartOpts)
end;
Specs ->
- Relaxed = get_start_opt(allow_user_term, value, false),
+ Relaxed = get_start_opt(allow_user_terms, value, false, StartOpts),
%% using testspec(s) as input for test
run_spec_file(Relaxed, Opts#opts{testspecs = Specs}, StartOpts)
end.
@@ -1855,6 +1855,8 @@ opts2args(EnvStartOpts) ->
end, UserCfg),
[_LastAnd|StrsR] = lists:reverse(lists:flatten(Strs)),
[{userconfig,lists:reverse(StrsR)}];
+ ({testcase,Case}) when is_atom(Case) ->
+ [{'case',[atom_to_list(Case)]}];
({testcase,Cases}) ->
[{'case',[atom_to_list(C) || C <- Cases]}];
({'case',Cases}) ->
@@ -1900,7 +1902,7 @@ opts2args(EnvStartOpts) ->
({Opt,As=[A|_]}) when is_atom(A) ->
[{Opt,[atom_to_list(Atom) || Atom <- As]}];
({Opt,Strs=[S|_]}) when is_list(S) ->
- [{Opt,[Strs]}];
+ [{Opt,Strs}];
({Opt,A}) when is_atom(A) ->
[{Opt,[atom_to_list(A)]}];
({Opt,I}) when is_integer(I) ->
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index 582ce5e49f..1ab9242e4b 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -17,7 +17,7 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework functions handlig test specifications.
+%%% @doc Common Test Framework functions handling test specifications.
%%%
%%% This module exports functions that are used within CT to
%%% scan and parse test specifikations.
@@ -384,7 +384,7 @@ filter_init_terms([{init, [], _}|Ts], NewTerms, Spec)->
filter_init_terms([Term|Ts], NewTerms, Spec)->
filter_init_terms(Ts, [Term|NewTerms], Spec);
filter_init_terms([], NewTerms, Spec)->
- {NewTerms, Spec}.
+ {lists:reverse(NewTerms), Spec}.
add_option([], _, List, _)->
List;
@@ -472,6 +472,36 @@ add_tests([{cover,Node,File}|Ts],Spec) ->
add_tests([{cover,File}|Ts],Spec) ->
add_tests([{cover,all_nodes,File}|Ts],Spec);
+%% --- multiply_timetraps ---
+add_tests([{multiply_timetraps,all_nodes,MT}|Ts],Spec) ->
+ Tests = lists:map(fun(N) -> {multiply_timetraps,N,MT} end, list_nodes(Spec)),
+ add_tests(Tests++Ts,Spec);
+add_tests([{multiply_timetraps,Nodes,MT}|Ts],Spec) when is_list(Nodes) ->
+ Ts1 = separate(Nodes,multiply_timetraps,[MT],Ts,Spec#testspec.nodes),
+ add_tests(Ts1,Spec);
+add_tests([{multiply_timetraps,Node,MT}|Ts],Spec) ->
+ MTs = Spec#testspec.multiply_timetraps,
+ MTs1 = [{ref2node(Node,Spec#testspec.nodes),MT} |
+ lists:keydelete(ref2node(Node,Spec#testspec.nodes),1,MTs)],
+ add_tests(Ts,Spec#testspec{multiply_timetraps=MTs1});
+add_tests([{multiply_timetraps,MT}|Ts],Spec) ->
+ add_tests([{multiply_timetraps,all_nodes,MT}|Ts],Spec);
+
+%% --- scale_timetraps ---
+add_tests([{scale_timetraps,all_nodes,ST}|Ts],Spec) ->
+ Tests = lists:map(fun(N) -> {scale_timetraps,N,ST} end, list_nodes(Spec)),
+ add_tests(Tests++Ts,Spec);
+add_tests([{scale_timetraps,Nodes,ST}|Ts],Spec) when is_list(Nodes) ->
+ Ts1 = separate(Nodes,scale_timetraps,[ST],Ts,Spec#testspec.nodes),
+ add_tests(Ts1,Spec);
+add_tests([{scale_timetraps,Node,ST}|Ts],Spec) ->
+ STs = Spec#testspec.scale_timetraps,
+ STs1 = [{ref2node(Node,Spec#testspec.nodes),ST} |
+ lists:keydelete(ref2node(Node,Spec#testspec.nodes),1,STs)],
+ add_tests(Ts,Spec#testspec{scale_timetraps=STs1});
+add_tests([{scale_timetraps,ST}|Ts],Spec) ->
+ add_tests([{scale_timetraps,all_nodes,ST}|Ts],Spec);
+
%% --- config ---
add_tests([{config,all_nodes,Files}|Ts],Spec) ->
Tests = lists:map(fun(N) -> {config,N,Files} end, list_nodes(Spec)),
@@ -895,7 +925,3 @@ common_letters([L|Ls],Term,Count) ->
end;
common_letters([],_,Count) ->
Count.
-
-
-
-
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index d9c5631f88..54eed29415 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -36,8 +36,8 @@
userconfig=[],
event_handler=[],
include=[],
- multiply_timetraps,
- scale_timetraps,
+ multiply_timetraps=[],
+ scale_timetraps=[],
alias=[],
tests=[]}).
--
cgit v1.2.3
From 13fab1dd93fba14e55fea0a343650dbaa54e8725 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Thu, 3 Jun 2010 13:21:38 +0200
Subject: Add new tests for test case groups and test specifications
---
lib/common_test/src/ct_testspec.erl | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index 1ab9242e4b..dc017921cc 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -624,6 +624,25 @@ add_tests([{suites,Node,Dir,Ss}|Ts],Spec) ->
Ss,Tests),
add_tests(Ts,Spec#testspec{tests=Tests1});
+%% --- groups ---
+%% Later make it possible to specify group execution properties
+%% that will override thse in the suite. Also make it possible
+%% create dynamic groups in specification, i.e. to group test cases
+%% by means of groups defined only in the test specification.
+add_tests([{groups,all_nodes,Dir,Suite,Gs}|Ts],Spec) ->
+ add_tests([{groups,list_nodes(Spec),Dir,Suite,Gs}|Ts],Spec);
+add_tests([{groups,Dir,Suite,Gs}|Ts],Spec) ->
+ add_tests([{groups,all_nodes,Dir,Suite,Gs}|Ts],Spec);
+add_tests([{groups,Nodes,Dir,Suite,Gs}|Ts],Spec) when is_list(Nodes) ->
+ Ts1 = separate(Nodes,groups,[Dir,Suite,Gs],Ts,Spec#testspec.nodes),
+ add_tests(Ts1,Spec);
+add_tests([{groups,Node,Dir,Suite,Gs}|Ts],Spec) ->
+ Tests = Spec#testspec.tests,
+ Tests1 = insert_cases(ref2node(Node,Spec#testspec.nodes),
+ ref2dir(Dir,Spec#testspec.alias),
+ Suite,Gs,Tests),
+ add_tests(Ts,Spec#testspec{tests=Tests1});
+
%% --- cases ---
add_tests([{cases,all_nodes,Dir,Suite,Cs}|Ts],Spec) ->
add_tests([{cases,list_nodes(Spec),Dir,Suite,Cs}|Ts],Spec);
@@ -654,6 +673,21 @@ add_tests([{skip_suites,Node,Dir,Ss,Cmt}|Ts],Spec) ->
Ss,Cmt,Tests),
add_tests(Ts,Spec#testspec{tests=Tests1});
+%% --- skip_groups ---
+add_tests([{skip_groups,all_nodes,Dir,Suite,Gs,Cmt}|Ts],Spec) ->
+ add_tests([{skip_groups,list_nodes(Spec),Dir,Suite,Gs,Cmt}|Ts],Spec);
+add_tests([{skip_groups,Dir,Suite,Gs,Cmt}|Ts],Spec) ->
+ add_tests([{skip_groups,all_nodes,Dir,Suite,Gs,Cmt}|Ts],Spec);
+add_tests([{skip_groups,Nodes,Dir,Suite,Gs,Cmt}|Ts],Spec) when is_list(Nodes) ->
+ Ts1 = separate(Nodes,skip_groups,[Dir,Suite,Gs,Cmt],Ts,Spec#testspec.nodes),
+ add_tests(Ts1,Spec);
+add_tests([{skip_groups,Node,Dir,Suite,Gs,Cmt}|Ts],Spec) ->
+ Tests = Spec#testspec.tests,
+ Tests1 = skip_cases(ref2node(Node,Spec#testspec.nodes),
+ ref2dir(Dir,Spec#testspec.alias),
+ Suite,Gs,Cmt,Tests),
+ add_tests(Ts,Spec#testspec{tests=Tests1});
+
%% --- skip_cases ---
add_tests([{skip_cases,all_nodes,Dir,Suite,Cs,Cmt}|Ts],Spec) ->
add_tests([{skip_cases,list_nodes(Spec),Dir,Suite,Cs,Cmt}|Ts],Spec);
--
cgit v1.2.3
From 7ce6aa16313d159b1994bf1d2f18b52bd91e9075 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Fri, 4 Jun 2010 11:21:41 +0200
Subject: Add groups in test specifications
Ongoing work...
---
lib/common_test/src/ct_framework.erl | 10 ++-
lib/common_test/src/ct_run.erl | 22 +++++--
lib/common_test/src/ct_testspec.erl | 120 +++++++++++++++++++++++++++++++++--
3 files changed, 137 insertions(+), 15 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 89bbc2448f..60978209b3 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -631,7 +631,7 @@ group_or_func(Func, _Config) ->
%%% and every test case. If the former, all test cases in the suite
%%% should be returned.
-get_suite(Mod, all) ->
+get_suite(Mod, all) ->
case catch apply(Mod, groups, []) of
{'EXIT',_} ->
get_all(Mod, []);
@@ -667,12 +667,18 @@ get_suite(Mod, Name) ->
%% (and only) test case so we can report Error properly
[{?MODULE,error_in_suite,[[Error]]}];
ConfTests ->
+
+ %%! --- Thu Jun 3 19:13:22 2010 --- peppe was here!
+ %%! HEERE!
+ %%! Must be able to search recursively for group Name,
+ %%! this only handles top level groups!
+
FindConf = fun({conf,Props,_,_,_}) ->
case proplists:get_value(name, Props) of
Name -> true;
_ -> false
end
- end,
+ end,
case lists:filter(FindConf, ConfTests) of
[] -> % must be a test case
get_seq(Mod, Name);
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 7037ac7c1e..0d4a5b31dc 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -510,10 +510,6 @@ install(Opts, LogDir) ->
case whereis(ct_util_server) of
undefined ->
VarFile = variables_file_name(LogDir),
-
- %%! --- Tue Jun 1 00:20:33 2010 --- peppe was here!
- io:format("Varfile = ~p~n", [VarFile]),
-
case file:open(VarFile, [write]) of
{ok,Fd} ->
[io:format(Fd, "~p.\n", [Opt]) || Opt <- Opts],
@@ -1535,13 +1531,27 @@ add_jobs([{TestDir,Suite,all}|Tests], Skip, Opts, CleanUp) ->
Error ->
Error
end;
+
+%% group
+add_jobs([{TestDir,Suite,[{GroupName,_Cases}]}|Tests], Skip, Opts, CleanUp) when
+ is_atom(GroupName) ->
+ add_jobs([{TestDir,Suite,GroupName}|Tests], Skip, Opts, CleanUp);
+add_jobs([{TestDir,Suite,{GroupName,_Cases}}|Tests], Skip, Opts, CleanUp) when
+ is_atom(GroupName) ->
+ add_jobs([{TestDir,Suite,GroupName}|Tests], Skip, Opts, CleanUp);
+
+%% test case
add_jobs([{TestDir,Suite,[Case]}|Tests], Skip, Opts, CleanUp) when is_atom(Case) ->
add_jobs([{TestDir,Suite,Case}|Tests], Skip, Opts, CleanUp);
+
add_jobs([{TestDir,Suite,Cases}|Tests], Skip, Opts, CleanUp) when is_list(Cases) ->
- case maybe_interpret(Suite, Cases, Opts) of
+ Cases1 = lists:map(fun({GroupName,_}) when is_atom(GroupName) -> GroupName;
+ (Case) -> Case
+ end, Cases),
+ case maybe_interpret(Suite, Cases1, Opts) of
ok ->
Name = get_name(TestDir) ++ "." ++ atom_to_list(Suite) ++ ".cases",
- case catch test_server_ctrl:add_cases_with_skip(Name, Suite, Cases,
+ case catch test_server_ctrl:add_cases_with_skip(Name, Suite, Cases1,
skiplist(TestDir,Skip)) of
{'EXIT',_} ->
CleanUp;
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index dc017921cc..0f68b062f6 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -631,16 +631,29 @@ add_tests([{suites,Node,Dir,Ss}|Ts],Spec) ->
%% by means of groups defined only in the test specification.
add_tests([{groups,all_nodes,Dir,Suite,Gs}|Ts],Spec) ->
add_tests([{groups,list_nodes(Spec),Dir,Suite,Gs}|Ts],Spec);
+add_tests([{groups,all_nodes,Dir,Suite,Gs,{cases,TCs}}|Ts],Spec) ->
+ add_tests([{groups,list_nodes(Spec),Dir,Suite,Gs,{cases,TCs}}|Ts],Spec);
add_tests([{groups,Dir,Suite,Gs}|Ts],Spec) ->
add_tests([{groups,all_nodes,Dir,Suite,Gs}|Ts],Spec);
+add_tests([{groups,Dir,Suite,Gs,{cases,TCs}}|Ts],Spec) ->
+ add_tests([{groups,all_nodes,Dir,Suite,Gs,{cases,TCs}}|Ts],Spec);
add_tests([{groups,Nodes,Dir,Suite,Gs}|Ts],Spec) when is_list(Nodes) ->
Ts1 = separate(Nodes,groups,[Dir,Suite,Gs],Ts,Spec#testspec.nodes),
add_tests(Ts1,Spec);
+add_tests([{groups,Nodes,Dir,Suite,Gs,{cases,TCs}}|Ts],Spec) when is_list(Nodes) ->
+ Ts1 = separate(Nodes,groups,[Dir,Suite,Gs,{cases,TCs}],Ts,Spec#testspec.nodes),
+ add_tests(Ts1,Spec);
add_tests([{groups,Node,Dir,Suite,Gs}|Ts],Spec) ->
Tests = Spec#testspec.tests,
- Tests1 = insert_cases(ref2node(Node,Spec#testspec.nodes),
+ Tests1 = insert_groups(ref2node(Node,Spec#testspec.nodes),
+ ref2dir(Dir,Spec#testspec.alias),
+ Suite,Gs,all,Tests),
+ add_tests(Ts,Spec#testspec{tests=Tests1});
+add_tests([{groups,Node,Dir,Suite,Gs,{cases,TCs}}|Ts],Spec) ->
+ Tests = Spec#testspec.tests,
+ Tests1 = insert_groups(ref2node(Node,Spec#testspec.nodes),
ref2dir(Dir,Spec#testspec.alias),
- Suite,Gs,Tests),
+ Suite,Gs,TCs,Tests),
add_tests(Ts,Spec#testspec{tests=Tests1});
%% --- cases ---
@@ -676,16 +689,29 @@ add_tests([{skip_suites,Node,Dir,Ss,Cmt}|Ts],Spec) ->
%% --- skip_groups ---
add_tests([{skip_groups,all_nodes,Dir,Suite,Gs,Cmt}|Ts],Spec) ->
add_tests([{skip_groups,list_nodes(Spec),Dir,Suite,Gs,Cmt}|Ts],Spec);
+add_tests([{skip_groups,all_nodes,Dir,Suite,Gs,{cases,TCs},Cmt}|Ts],Spec) ->
+ add_tests([{skip_groups,list_nodes(Spec),Dir,Suite,Gs,{cases,TCs},Cmt}|Ts],Spec);
add_tests([{skip_groups,Dir,Suite,Gs,Cmt}|Ts],Spec) ->
add_tests([{skip_groups,all_nodes,Dir,Suite,Gs,Cmt}|Ts],Spec);
+add_tests([{skip_groups,Dir,Suite,Gs,{cases,TCs},Cmt}|Ts],Spec) ->
+ add_tests([{skip_groups,all_nodes,Dir,Suite,Gs,{cases,TCs},Cmt}|Ts],Spec);
add_tests([{skip_groups,Nodes,Dir,Suite,Gs,Cmt}|Ts],Spec) when is_list(Nodes) ->
Ts1 = separate(Nodes,skip_groups,[Dir,Suite,Gs,Cmt],Ts,Spec#testspec.nodes),
add_tests(Ts1,Spec);
+add_tests([{skip_groups,Nodes,Dir,Suite,Gs,{cases,TCs},Cmt}|Ts],Spec) when is_list(Nodes) ->
+ Ts1 = separate(Nodes,skip_groups,[Dir,Suite,Gs,{cases,TCs},Cmt],Ts,Spec#testspec.nodes),
+ add_tests(Ts1,Spec);
add_tests([{skip_groups,Node,Dir,Suite,Gs,Cmt}|Ts],Spec) ->
Tests = Spec#testspec.tests,
- Tests1 = skip_cases(ref2node(Node,Spec#testspec.nodes),
- ref2dir(Dir,Spec#testspec.alias),
- Suite,Gs,Cmt,Tests),
+ Tests1 = skip_groups(ref2node(Node,Spec#testspec.nodes),
+ ref2dir(Dir,Spec#testspec.alias),
+ Suite,Gs,all,Cmt,Tests),
+ add_tests(Ts,Spec#testspec{tests=Tests1});
+add_tests([{skip_groups,Node,Dir,Suite,Gs,{cases,TCs},Cmt}|Ts],Spec) ->
+ Tests = Spec#testspec.tests,
+ Tests1 = skip_groups(ref2node(Node,Spec#testspec.nodes),
+ ref2dir(Dir,Spec#testspec.alias),
+ Suite,Gs,TCs,Cmt,Tests),
add_tests(Ts,Spec#testspec{tests=Tests1});
%% --- skip_cases ---
@@ -756,8 +782,11 @@ separate([],_,_,_) ->
%% Representation:
-%% {{Node,Dir},[{Suite1,[case11,case12,...]},{Suite2,[case21,case22,...]},...]}
-%% {{Node,Dir},[{Suite1,{skip,Cmt}},{Suite2,[{case21,{skip,Cmt}},case22,...]},...]}
+%% {{Node,Dir},[{Suite1,[GrOrCase11,GrOrCase12,...]},
+%% {Suite2,[GrOrCase21,GrOrCase22,...]},...]}
+%% {{Node,Dir},[{Suite1,{skip,Cmt}},
+%% {Suite2,[{GrOrCase21,{skip,Cmt}},GrOrCase22,...]},...]}
+%% GrOrCase = {GroupName,[Case1,Case2,...]} | Case
insert_suites(Node,Dir,[S|Ss],Tests) ->
Tests1 = insert_cases(Node,Dir,S,all,Tests),
@@ -767,6 +796,54 @@ insert_suites(_Node,_Dir,[],Tests) ->
insert_suites(Node,Dir,S,Tests) ->
insert_suites(Node,Dir,[S],Tests).
+insert_groups(Node,Dir,Suite,Group,Cases,Tests) when is_atom(Group) ->
+ insert_groups(Node,Dir,Suite,[Group],Cases,Tests);
+insert_groups(Node,Dir,Suite,Groups,Cases,Tests) when
+ ((Cases == all) or is_list(Cases)) and is_list(Groups) ->
+ case lists:keysearch({Node,Dir},1,Tests) of
+ {value,{{Node,Dir},[{all,_}]}} ->
+ Tests;
+ {value,{{Node,Dir},Suites0}} ->
+ Suites1 = insert_groups1(Suite,
+ [{Gr,Cases} || Gr <- Groups],
+ Suites0),
+ insert_in_order({{Node,Dir},Suites1},Tests);
+ false ->
+ Groups1 = [{Gr,Cases} || Gr <- Groups],
+ insert_in_order({{Node,Dir},[{Suite,Groups1}]},Tests)
+ end;
+insert_groups(Node,Dir,Suite,Groups,Case,Tests) when is_atom(Case) ->
+ Cases = if Case == all -> all; true -> [Case] end,
+ insert_groups(Node,Dir,Suite,Groups,Cases,Tests).
+
+insert_groups1(_Suite,_Groups,all) ->
+ all;
+insert_groups1(Suite,Groups,Suites0) ->
+ case lists:keysearch(Suite,1,Suites0) of
+ {value,{Suite,all}} ->
+ Suites0;
+ {value,{Suite,GrAndCases0}} ->
+ GrAndCases = insert_groups2(Groups,GrAndCases0),
+ insert_in_order({Suite,GrAndCases},Suites0);
+ false ->
+ insert_in_order({Suite,Groups},Suites0)
+ end.
+
+insert_groups2(_Groups,all) ->
+ all;
+insert_groups2([Group={GrName,Cases}|Groups],GrAndCases) ->
+ case lists:keysearch(GrName,1,GrAndCases) of
+ {value,{GrName,all}} ->
+ GrAndCases;
+ {value,{GrName,Cases0}} ->
+ Cases1 = insert_in_order(Cases,Cases0),
+ insert_groups2(Groups,insert_in_order({GrName,Cases1},GrAndCases));
+ false ->
+ insert_groups2(Groups,insert_in_order(Group,GrAndCases))
+ end;
+insert_groups2([],GrAndCases) ->
+ GrAndCases.
+
insert_cases(Node,Dir,Suite,Cases,Tests) when is_list(Cases) ->
case lists:keysearch({Node,Dir},1,Tests) of
{value,{{Node,Dir},[{all,_}]}} ->
@@ -801,6 +878,35 @@ skip_suites(_Node,_Dir,[],_Cmt,Tests) ->
skip_suites(Node,Dir,S,Cmt,Tests) ->
skip_suites(Node,Dir,[S],Cmt,Tests).
+skip_groups(Node,Dir,Suite,Group,Case,Cmt,Tests) when is_atom(Group) ->
+ skip_groups(Node,Dir,Suite,[Group],[Case],Cmt,Tests);
+skip_groups(Node,Dir,Suite,Groups,Cases,Cmt,Tests) when
+ ((Cases == all) or is_list(Cases)) and is_list(Groups) ->
+ Suites =
+ case lists:keysearch({Node,Dir},1,Tests) of
+ {value,{{Node,Dir},Suites0}} ->
+ Suites0;
+ false ->
+ []
+ end,
+ Suites1 = skip_groups1(Suite,[{Gr,Cases} || Gr <- Groups],Cmt,Suites),
+ insert_in_order({{Node,Dir},Suites1},Tests);
+skip_groups(Node,Dir,Suite,Groups,Case,Cmt,Tests) when is_atom(Case) ->
+ Cases = if Case == all -> all; true -> [Case] end,
+ skip_groups(Node,Dir,Suite,Groups,Cases,Cmt,Tests).
+
+skip_groups1(Suite,Groups,Cmt,Suites0) ->
+ SkipGroups = lists:map(fun(Group) ->
+ {Group,{skip,Cmt}}
+ end,Groups),
+ case lists:keysearch(Suite,1,Suites0) of
+ {value,{Suite,GrAndCases0}} ->
+ GrAndCases1 = GrAndCases0 ++ SkipGroups,
+ insert_in_order({Suite,GrAndCases1},Suites0);
+ false ->
+ insert_in_order({Suite,SkipGroups},Suites0)
+ end.
+
skip_cases(Node,Dir,Suite,Cases,Cmt,Tests) when is_list(Cases) ->
Suites =
case lists:keysearch({Node,Dir},1,Tests) of
--
cgit v1.2.3
From 470063d25f6128ef83cba6864533fc05e45cca74 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Thu, 3 Jun 2010 22:48:10 +0200
Subject: Flush old DOWN messages in demonitor
---
lib/common_test/src/ct_config.erl | 2 +-
lib/common_test/src/ct_gen_conn.erl | 4 ++--
lib/common_test/src/ct_logs.erl | 4 ++--
lib/common_test/src/ct_master.erl | 2 +-
lib/common_test/src/ct_master_logs.erl | 4 ++--
lib/common_test/src/ct_run.erl | 4 ++--
lib/common_test/src/ct_util.erl | 2 +-
lib/common_test/src/vts.erl | 4 ++--
8 files changed, 13 insertions(+), 13 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index a7b8a9e906..a6ade3f66b 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -111,7 +111,7 @@ call(Msg) ->
ct_config_server ! {Msg,{self(),Ref}},
receive
{Ref, Result} ->
- erlang:demonitor(MRef),
+ erlang:demonitor(MRef, [flush]),
Result;
{'DOWN',MRef,process,_,Reason} ->
{error,{ct_util_server_down,Reason}}
diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl
index a31e57c7ea..f3c040c933 100644
--- a/lib/common_test/src/ct_gen_conn.erl
+++ b/lib/common_test/src/ct_gen_conn.erl
@@ -76,7 +76,7 @@ start(Name,Address,InitData,CallbackMod) ->
MRef = erlang:monitor(process,Pid),
receive
{connected,Pid} ->
- erlang:demonitor(MRef),
+ erlang:demonitor(MRef, [flush]),
ct_util:register_connection(Name,Address,CallbackMod,Pid),
{ok,Pid};
{Error,Pid} ->
@@ -182,7 +182,7 @@ call(Pid,Msg) ->
Pid ! {Msg,{self(),Ref}},
receive
{Ref, Result} ->
- erlang:demonitor(MRef),
+ erlang:demonitor(MRef, [flush]),
case Result of
{retry,_Data} ->
call(Pid,Result);
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index bd1a89ae1f..bd6fdfcd4f 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -80,7 +80,7 @@ init(Mode) ->
MRef = erlang:monitor(process,Pid),
receive
{started,Pid,Result} ->
- erlang:demonitor(MRef),
+ erlang:demonitor(MRef, [flush]),
Result;
{'DOWN',MRef,process,_,Reason} ->
exit({could_not_start_process,?MODULE,Reason})
@@ -163,7 +163,7 @@ call(Msg) ->
?MODULE ! {Msg,{self(),Ref}},
receive
{Ref, Result} ->
- erlang:demonitor(MRef),
+ erlang:demonitor(MRef, [flush]),
Result;
{'DOWN',MRef,process,_,Reason} ->
{error,{process_down,?MODULE,Reason}}
diff --git a/lib/common_test/src/ct_master.erl b/lib/common_test/src/ct_master.erl
index 6cabe4c7a2..5c4ef70271 100644
--- a/lib/common_test/src/ct_master.erl
+++ b/lib/common_test/src/ct_master.erl
@@ -697,7 +697,7 @@ call(Pid,Msg) ->
{'DOWN', Ref, _, _, _} ->
{error,master_died}
end,
- erlang:demonitor(Ref),
+ erlang:demonitor(Ref, [flush]),
Return.
reply(Result,To) ->
diff --git a/lib/common_test/src/ct_master_logs.erl b/lib/common_test/src/ct_master_logs.erl
index 63f60b1182..18e9eb528b 100644
--- a/lib/common_test/src/ct_master_logs.erl
+++ b/lib/common_test/src/ct_master_logs.erl
@@ -44,7 +44,7 @@ start(LogDir,Nodes) ->
MRef = erlang:monitor(process,Pid),
receive
{started,Pid,Result} ->
- erlang:demonitor(MRef),
+ erlang:demonitor(MRef, [flush]),
{Pid,Result};
{'DOWN',MRef,process,_,Reason} ->
exit({could_not_start_process,?MODULE,Reason})
@@ -435,7 +435,7 @@ call(Msg) ->
?MODULE ! {Msg,{self(),Ref}},
receive
{Ref, Result} ->
- erlang:demonitor(MRef),
+ erlang:demonitor(MRef, [flush]),
Result;
{'DOWN',MRef,process,_,Reason} ->
{error,{process_down,?MODULE,Reason}}
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 0d4a5b31dc..c2fe2ababd 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -1473,7 +1473,7 @@ count_test_cases(Tests, Skip) ->
Ref = erlang:monitor(process, TSPid),
add_jobs(Tests, Skip, #opts{}, []),
{Suites,NoOfCases} = count_test_cases1(length(Tests), 0, [], Ref),
- erlang:demonitor(Ref),
+ erlang:demonitor(Ref, [flush]),
test_server_ctrl:stop_get_totals(),
{Suites,NoOfCases}.
@@ -1594,7 +1594,7 @@ wait_for_idle() ->
idle -> ok;
{'DOWN', Ref, _, _, _} -> error
end,
- erlang:demonitor(Ref),
+ erlang:demonitor(Ref, [flush]),
ct_util:update_last_run_index(),
Result
end.
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index 2b06338479..f1692caf24 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -679,7 +679,7 @@ call(Msg) ->
ct_util_server ! {Msg,{self(),Ref}},
receive
{Ref, Result} ->
- erlang:demonitor(MRef),
+ erlang:demonitor(MRef, [flush]),
Result;
{'DOWN',MRef,process,_,Reason} ->
{error,{ct_util_server_down,Reason}}
diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl
index c94a796ab8..22399aff2a 100644
--- a/lib/common_test/src/vts.erl
+++ b/lib/common_test/src/vts.erl
@@ -100,7 +100,7 @@ start_link() ->
MRef = erlang:monitor(process,Pid),
receive
{Pid,started} ->
- erlang:demonitor(MRef),
+ erlang:demonitor(MRef, [flush]),
{ok,Pid};
{'DOWN',MRef,process,_,Reason} ->
{error,{vts,died,Reason}}
@@ -259,7 +259,7 @@ call(Msg) ->
Pid ! {Msg,{self(),Ref}},
receive
{Ref, Result} ->
- erlang:demonitor(MRef),
+ erlang:demonitor(MRef, [flush]),
Result;
{'DOWN',MRef,process,_,Reason} ->
{error,{process_down,Pid,Reason}}
--
cgit v1.2.3
From a3af252253c1fbc642cf6229ff1e23f095b75b59 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Fri, 4 Jun 2010 01:06:03 +0200
Subject: Have end_per_testcase run even after timetrap_timeout and
abort_testcase
---
lib/common_test/src/ct_run.erl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index c2fe2ababd..f993985f52 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -89,7 +89,7 @@ script_start() ->
end, Flags)
end,
%% used for purpose of testing the run_test interface
- io:format(user, "~n--------------- START ARGS ---------------~n", []),
+ io:format(user, "~n-------------------- START ARGS --------------------~n", []),
io:format(user, "--- Init args:~n~p~n", [FlagFilter(Init)]),
io:format(user, "--- CT args:~n~p~n", [FlagFilter(CtArgs)]),
EnvArgs = opts2args(EnvStartOpts),
@@ -97,7 +97,7 @@ script_start() ->
[EnvStartOpts,EnvArgs]),
Merged = merge_arguments(CtArgs ++ EnvArgs),
io:format(user, "--- Merged args:~n~p~n", [FlagFilter(Merged)]),
- io:format(user, "------------------------------------------~n~n", []),
+ io:format(user, "----------------------------------------------------~n~n", []),
Merged;
_ ->
merge_arguments(CtArgs)
--
cgit v1.2.3
From 34cf18550ff792ed9da884b00a49d6accd1bd5f5 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Fri, 4 Jun 2010 15:34:42 +0200
Subject: Add support for dynamic timetrap handling
---
lib/common_test/src/ct.erl | 14 +++++++++++++-
lib/common_test/src/ct_config.erl | 35 ++++++++++++++++++++++-------------
lib/common_test/src/ct_run.erl | 25 ++++++++++++++++++-------
3 files changed, 53 insertions(+), 21 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 307d10428d..77bcf34981 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -65,7 +65,7 @@
pal/1, pal/2, pal/3,
fail/1, comment/1,
testcases/2, userdata/2, userdata/3,
- sleep/1]).
+ timetrap/1, sleep/1]).
%% New API for manipulating with config handlers
-export([add_config/2, remove_config/2]).
@@ -843,6 +843,18 @@ add_config(Callback, Config)->
remove_config(Callback, Config) ->
ct_config:remove_config(Callback, Config).
+%%%-----------------------------------------------------------------
+%%% @spec timetrap(Time) -> ok
+%%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity
+%%% Hours = integer()
+%%% Mins = integer()
+%%% Secs = integer()
+%%% Millisecs = integer() | float()
+%%%
+%%% @doc Use this function to set a new timetrap for the running test case.
+timetrap(Time) ->
+ test_server:timetrap(Time).
+
%%%-----------------------------------------------------------------
%%% @spec sleep(Time) -> ok
%%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index a6ade3f66b..dc6fcc66e5 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -694,39 +694,48 @@ random_bytes_1(N, Acc) -> random_bytes_1(N-1, [random:uniform(255)|Acc]).
check_callback_load(Callback) ->
case code:is_loaded(Callback) of
{file, _Filename}->
- {ok, Callback};
+ check_exports(Callback);
false->
case code:load_file(Callback) of
{module, Callback}->
- {ok, Callback};
+ check_exports(Callback);
{error, Error}->
{error, Error}
end
end.
+check_exports(Callback) ->
+ Fs = Callback:module_info(exports),
+ case {lists:member({check_parameter,1},Fs),
+ lists:member({read_config,1},Fs)} of
+ {true, true} ->
+ {ok, Callback};
+ _ ->
+ {error, missing_callback_functions}
+ end.
+
check_config_files(Configs) ->
ConfigChecker = fun
({Callback, [F|_R]=Files}) ->
case check_callback_load(Callback) of
- {ok, Callback}->
- if
- is_integer(F) ->
+ {ok, Callback} ->
+ if is_integer(F) ->
Callback:check_parameter(Files);
- is_list(F) ->
+ is_list(F) ->
lists:map(fun(File) ->
- Callback:check_parameter(File)
- end,
- Files)
+ Callback:check_parameter(File)
+ end,
+ Files)
end;
- {error, _}->
- {error, {callback, Callback}}
+ {error, Why}->
+ {error, {callback, {Callback,Why}}}
end;
({Callback, []}) ->
case check_callback_load(Callback) of
{ok, Callback}->
Callback:check_parameter([]);
- {error, _}->
- {error, {callback, Callback}}
+ {error, Why}->
+ {error, {callback, {Callback,Why}}}
end
end,
lists:keysearch(error, 1, lists:flatten(lists:map(ConfigChecker, Configs))).
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index f993985f52..ab900734f2 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -152,10 +152,12 @@ script_start1(Parent, Args) ->
%% read general start flags
Vts = get_start_opt(vts, true, Args),
Shell = get_start_opt(shell, true, Args),
- Cover = get_start_opt(cover, fun(CoverFile) -> ?abs(CoverFile) end, Args),
+ Cover = get_start_opt(cover, fun([CoverFile]) -> ?abs(CoverFile) end, Args),
LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args),
- MultTT = get_start_opt(multiply_timetraps, fun(MT) -> MT end, 1, Args),
- ScaleTT = get_start_opt(scale_timetraps, fun(CT) -> CT end, false, Args),
+ MultTT = get_start_opt(multiply_timetraps,
+ fun([MT]) -> list_to_integer(MT) end, 1, Args),
+ ScaleTT = get_start_opt(scale_timetraps,
+ fun([CT]) -> list_to_atom(CT) end, false, Args),
EvHandlers = event_handler_args2opts(Args),
%% check flags and set corresponding application env variables
@@ -335,8 +337,8 @@ check_and_install_configfiles(Configs, LogDir, EvHandlers) ->
{error,{cant_read_config_file,File}};
{value,{error,{wrong_config,Message}}}->
{error,{wrong_config,Message}};
- {value,{error,{callback,File}}} ->
- {error,{cant_load_callback_module,File}}
+ {value,{error,{callback,Info}}} ->
+ {error,{cant_load_callback_module,Info}}
end.
script_start3(StartOpts, Args) ->
@@ -745,14 +747,23 @@ run_prepared(Run, Skip, Opts = #opts{logdir = LogDir,
end.
check_config_file(Callback, File)->
+ case code:is_loaded(Callback) of
+ false ->
+ case code:load_file(Callback) of
+ {module,_} -> ok;
+ {error,Why} -> exit({cant_load_callback_module,Why})
+ end;
+ _ ->
+ ok
+ end,
case Callback:check_parameter(File) of
{ok,{file,File}}->
?abs(File);
{ok,{config,_}}->
File;
- {nok,{wrong_config,Message}}->
+ {error,{wrong_config,Message}}->
exit({wrong_config,{Callback,Message}});
- {nok,{nofile,File}}->
+ {error,{nofile,File}}->
exit({no_such_file,?abs(File)})
end.
--
cgit v1.2.3
From 1358ccecd1169d0c534137fb2c65759c7089cd0a Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Fri, 4 Jun 2010 18:21:13 +0200
Subject: Add support for config info functions (e.g. init_per_suite/0)
Also fixed bug: return value {fail,Reason} from end_tc(init_per_suite) was ignored.
---
lib/common_test/src/ct_framework.erl | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 60978209b3..3dd1026f13 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -161,6 +161,7 @@ init_tc2(Mod,Func,SuiteInfo,MergeResult,Config,DoInit) ->
_ ->
MergeResult
end,
+
%% timetrap must be handled before require
MergedInfo1 = timetrap_first(MergedInfo, [], []),
%% tell logger to use specified style sheet
@@ -244,8 +245,8 @@ add_defaults(Mod,Func,FuncInfo,DoInit) ->
_ ->
{suite0_failed,bad_return_value}
end.
-
-add_defaults1(_Mod,init_per_suite,[],SuiteInfo,_) ->
+
+add_defaults1(_Mod,init_per_suite,[],SuiteInfo,_DoInit) ->
SuiteInfo;
add_defaults1(Mod,Func,FuncInfo,SuiteInfo,DoInit) ->
@@ -253,15 +254,27 @@ add_defaults1(Mod,Func,FuncInfo,SuiteInfo,DoInit) ->
%% can result in weird behaviour (suite values get overwritten)
SuiteReqs =
[SDDef || SDDef <- SuiteInfo,
- require == element(1,SDDef)],
- case [element(2,Clash) || Clash <- SuiteReqs,
- true == lists:keymember(element(2,Clash),2,FuncInfo)] of
+ ((require == element(1,SDDef)) or
+ (default_config == element(1,SDDef)))],
+ FuncReqs =
+ [FIDef || FIDef <- FuncInfo,
+ require == element(1,FIDef)],
+ case [element(2,Clash) || Clash <- SuiteReqs,
+ require == element(1, Clash),
+ true == lists:keymember(element(2,Clash),2,
+ FuncReqs)] of
[] ->
add_defaults2(Mod,Func,FuncInfo,SuiteInfo,SuiteReqs,DoInit);
Clashes ->
{error,{config_name_already_in_use,Clashes}}
end.
+add_defaults2(Mod,init_per_suite,IPSInfo,SuiteInfo,SuiteReqs,false) ->
+ %% not common practise to use a test case info function for
+ %% init_per_suite (usually handled by suite/0), but let's support
+ %% it just in case...
+ add_defaults2(Mod,init_per_suite,IPSInfo,SuiteInfo,SuiteReqs,true);
+
add_defaults2(_Mod,_Func,FuncInfo,SuiteInfo,_,false) ->
%% include require elements from test case info, but not from suite/0
%% (since we've already required those vars)
--
cgit v1.2.3
From d3a6ecb105706b66f1c0c6b8a515370df5e29bd3 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Sat, 5 Jun 2010 18:35:37 +0200
Subject: Add support for executing pre-loaded suites (e.g. modules loaded as
binaries)
Also fixed bug in test_server that calls end_per_testcase after test case timeout or abortion.
---
lib/common_test/src/ct_run.erl | 58 ++++++++++++++++++++++++++++++------------
1 file changed, 42 insertions(+), 16 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index ab900734f2..3d9b579a0c 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -1106,14 +1106,15 @@ do_run(Tests, Skip, Opts, Args) ->
log_ts_names(Opts1#opts.testspecs),
TestSuites = suite_tuples(Tests),
- {SuiteMakeErrors,AllMakeErrors} =
+ {_TestSuites1,SuiteMakeErrors,AllMakeErrors} =
case application:get_env(common_test, auto_compile) of
{ok,false} ->
- SuitesNotFound = verify_suites(TestSuites),
- {SuitesNotFound,SuitesNotFound};
+ {TestSuites1,SuitesNotFound} =
+ verify_suites(TestSuites),
+ {TestSuites1,SuitesNotFound,SuitesNotFound};
_ ->
{SuiteErrs,HelpErrs} = auto_compile(TestSuites),
- {SuiteErrs,SuiteErrs++HelpErrs}
+ {TestSuites,SuiteErrs,SuiteErrs++HelpErrs}
end,
case continue(AllMakeErrors) of
@@ -1190,30 +1191,55 @@ auto_compile(TestSuites) ->
verify_suites(TestSuites) ->
io:nl(),
Verify =
- fun({Dir,Suite},NotFound) ->
+ fun({Dir,Suite}=DS,{Found,NotFound}) ->
case locate_test_dir(Dir, Suite) of
{ok,TestDir} ->
if Suite == all ->
- NotFound;
+ {[DS|Found],NotFound};
true ->
- Beam = filename:join(TestDir, atom_to_list(Suite)++".beam"),
+ Beam = filename:join(TestDir,
+ atom_to_list(Suite)++".beam"),
case filelib:is_regular(Beam) of
true ->
- NotFound;
+ {[DS|Found],NotFound};
false ->
- Name = filename:join(TestDir, atom_to_list(Suite)),
- io:format("Suite ~w not found in directory ~s~n",
- [Suite,TestDir]),
- [{{Dir,Suite},[Name]} | NotFound]
+ case code:is_loaded(Suite) of
+ {file,SuiteFile} ->
+ %% test suite is already loaded and
+ %% since auto_compile == false,
+ %% let's assume the user has
+ %% loaded the beam file explicitly
+ ActualDir = filename:dirname(SuiteFile),
+ {[{ActualDir,Suite}|Found],NotFound};
+ false ->
+ Name =
+ filename:join(TestDir,
+ atom_to_list(Suite)),
+ io:format(user,
+ "Suite ~w not found"
+ "in directory ~s~n",
+ [Suite,TestDir]),
+ {Found,[{DS,[Name]}|NotFound]}
+ end
end
end;
{error,_Reason} ->
- io:format("Directory ~s is invalid~n", [Dir]),
- Name = filename:join(Dir, atom_to_list(Suite)),
- [{{Dir,Suite},[Name]} | NotFound]
+ case code:is_loaded(Suite) of
+ {file,SuiteFile} ->
+ %% test suite is already loaded and since
+ %% auto_compile == false, let's assume the
+ %% user has loaded the beam file explicitly
+ ActualDir = filename:dirname(SuiteFile),
+ {[{ActualDir,Suite}|Found],NotFound};
+ false ->
+ io:format(user, "Directory ~s is invalid~n", [Dir]),
+ Name = filename:join(Dir, atom_to_list(Suite)),
+ {Found,[{DS,[Name]}|NotFound]}
+ end
end
end,
- lists:reverse(lists:foldl(Verify, [], TestSuites)).
+ {ActualFound,Missing} = lists:foldl(Verify, {[],[]}, TestSuites),
+ {lists:reverse(ActualFound),lists:reverse(Missing)}.
save_make_errors([]) ->
[];
--
cgit v1.2.3
From 331bb449c72078c315eff558158478445c4cb888 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Sat, 5 Jun 2010 20:57:10 +0200
Subject: Minor fixes in code and test suites
---
lib/common_test/src/ct.erl | 6 ++-
lib/common_test/src/ct_logs.erl | 2 +-
lib/common_test/src/ct_run.erl | 83 ++++++++++++++++++++++++++++-------------
lib/common_test/src/ct_util.erl | 3 +-
lib/common_test/src/vts.erl | 6 +--
5 files changed, 67 insertions(+), 33 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 77bcf34981..eb16a04c7b 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -142,8 +142,9 @@ run(TestDirs) ->
%%% {userconfig, UserConfig} |
%%% {testcase,Cases} | {group,Groups} | {spec,TestSpecs} |
%%% {allow_user_terms,Bool} | {logdir,LogDir} |
-%%% {silent_connections,Conns} | {cover,CoverSpecFile} |
-%%% {step,StepOpts} | {event_handler,EventHandlers} | {include,InclDirs} |
+%%% {silent_connections,Conns} | {stylesheet,CSSFile} |
+%%% {cover,CoverSpecFile} | {step,StepOpts} |
+%%% {event_handler,EventHandlers} | {include,InclDirs} |
%%% {auto_compile,Bool} | {multiply_timetraps,M} | {scale_timetraps,Bool} |
%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
%%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} |
@@ -159,6 +160,7 @@ run(TestDirs) ->
%%% TestSpecs = [string()] | string()
%%% LogDir = string()
%%% Conns = all | [atom()]
+%%% CSSFile = string()
%%% CoverSpecFile = string()
%%% StepOpts = [StepOpt] | []
%%% StepOpt = config | keep_inactive
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index bd6fdfcd4f..8a4432ef08 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -505,7 +505,7 @@ logger_loop(State) ->
logger_loop(State);
{set_stylesheet,TC,SSFile} ->
Fd = State#logger_state.ct_log_fd,
- io:format(Fd, "~p uses external style sheet: ~s~n", [TC,SSFile]),
+ io:format(Fd, "~p loading external style sheet: ~s~n", [TC,SSFile]),
logger_loop(State#logger_state{stylesheet=SSFile});
{clear_stylesheet,_} when State#logger_state.stylesheet == undefined ->
logger_loop(State);
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 3d9b579a0c..4b9c9b6981 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -55,6 +55,7 @@
event_handlers = [],
include = [],
silent_connections,
+ stylesheet,
multiply_timetraps = 1,
scale_timetraps = false,
testspecs = [],
@@ -170,7 +171,7 @@ script_start1(Parent, Args) ->
case proplists:get_value(ct_decrypt_file, Args) of
[DecryptFile] ->
application:set_env(common_test, decrypt,
- {file,filename:absname(DecryptFile)});
+ {file,?abs(DecryptFile)});
undefined ->
application:unset_env(common_test, decrypt)
end
@@ -182,9 +183,9 @@ script_start1(Parent, Args) ->
application:set_env(common_test, auto_compile, true),
InclDirs =
case proplists:get_value(include, Args) of
- {include,Incl} when is_list(hd(Incl)) ->
+ Incl when is_list(hd(Incl)) ->
Incl;
- {include,Incl} when is_list(Incl) ->
+ Incl when is_list(Incl) ->
[Incl];
undefined ->
[]
@@ -203,6 +204,15 @@ script_start1(Parent, Args) ->
application:set_env(common_test, auto_compile, false),
[]
end,
+ %% silent connections
+ SilentConns =
+ get_start_opt(silent_connections,
+ fun(["all"]) -> [];
+ (Conns) -> [list_to_atom(Conn) || Conn <- Conns]
+ end, Args),
+ %% stylesheet
+ Stylesheet = get_start_opt(stylesheet,
+ fun([SS]) -> ?abs(SS) end, Args),
%% basic_html - used by ct_logs
case proplists:get_value(basic_html, Args) of
undefined ->
@@ -214,6 +224,8 @@ script_start1(Parent, Args) ->
StartOpts = #opts{vts = Vts, shell = Shell, cover = Cover,
logdir = LogDir, event_handlers = EvHandlers,
include = IncludeDirs,
+ silent_connections = SilentConns,
+ stylesheet = Stylesheet,
multiply_timetraps = MultTT,
scale_timetraps = ScaleTT},
@@ -326,7 +338,16 @@ script_start2(StartOpts = #opts{vts = undefined,
end;
script_start2(StartOpts, Args) ->
- script_start3(StartOpts, Args).
+ %% read config/userconfig from start flags
+ InitConfig = ct_config:prepare_config_list(Args),
+ case check_and_install_configfiles(InitConfig,
+ which(logdir,StartOpts#opts.logdir),
+ StartOpts#opts.event_handlers) of
+ ok -> % go on read tests from start flags
+ script_start3(StartOpts#opts{config=InitConfig}, Args);
+ Error ->
+ Error
+ end.
check_and_install_configfiles(Configs, LogDir, EvHandlers) ->
case ct_config:check_config_files(Configs) of
@@ -386,7 +407,17 @@ script_start3(StartOpts, Args) ->
script_start4(#opts{vts = true, config = Config, event_handlers = EvHandlers,
tests = Tests, logdir = LogDir}, _Args) ->
- vts:init_data(Config, EvHandlers, ?abs(LogDir), Tests);
+ ConfigFiles =
+ lists:foldl(fun({ct_config_plain,CfgFiles}, AllFiles) when
+ is_list(hd(CfgFiles)) ->
+ AllFiles ++ CfgFiles;
+ ({ct_config_plain,CfgFile}, AllFiles) when
+ is_integer(hd(CfgFile)) ->
+ AllFiles ++ [CfgFile];
+ (_, AllFiles) ->
+ AllFiles
+ end, [], Config),
+ vts:init_data(ConfigFiles, EvHandlers, ?abs(LogDir), Tests);
script_start4(#opts{shell = true, config = Config, event_handlers = EvHandlers,
logdir = LogDir, testspecs = Specs}, _Args) ->
@@ -396,6 +427,12 @@ script_start4(#opts{shell = true, config = Config, event_handlers = EvHandlers,
true ->
io:format("\nInstalling: ~p\n\n", [Config])
end,
+
+ %%! --- Sun Jun 6 00:58:41 2010 --- peppe was here!
+ %%! HERE!!
+ %%! Something's not right here. Can't start shell mode
+ %%! properly!
+
case install(InstallOpts) of
ok ->
ct_util:start(interactive, LogDir),
@@ -610,8 +647,13 @@ run_test1(StartOpts) ->
fun(all) -> [];
(Conns) -> Conns
end, StartOpts),
+ %% stylesheet
+ Stylesheet = get_start_opt(stylesheet,
+ fun(SS) -> ?abs(SS) end,
+ StartOpts),
%% code coverage
- Cover = get_start_opt(cover, fun(CoverFile) -> ?abs(CoverFile) end, StartOpts),
+ Cover = get_start_opt(cover,
+ fun(CoverFile) -> ?abs(CoverFile) end, StartOpts),
%% timetrap manipulation
MultiplyTT = get_start_opt(multiply_timetraps, value, 1, StartOpts),
@@ -653,7 +695,7 @@ run_test1(StartOpts) ->
Key={key,_} ->
application:set_env(common_test, decrypt, Key);
{file,KeyFile} ->
- application:set_env(common_test, decrypt, {file,filename:absname(KeyFile)})
+ application:set_env(common_test, decrypt, {file,?abs(KeyFile)})
end,
%% basic html - used by ct_logs
@@ -669,7 +711,9 @@ run_test1(StartOpts) ->
Opts = #opts{cover = Cover, step = Step, logdir = LogDir, config = CfgFiles,
event_handlers = EvHandlers, include = Include,
- silent_connections = SilentConns, multiply_timetraps = MultiplyTT,
+ silent_connections = SilentConns,
+ stylesheet = Stylesheet,
+ multiply_timetraps = MultiplyTT,
scale_timetraps = ScaleTT},
%% test specification
@@ -1079,25 +1123,14 @@ do_run(Tests, Skip, Opts, Args) ->
"run ct:start_interactive()\n\n",[]),
{error,interactive_mode};
_Pid ->
- %% save style sheet info
- case lists:keysearch(stylesheet, 1, Args) of
- {value,{_,SSFile}} ->
- ct_util:set_testdata({stylesheet,SSFile});
- _ ->
- ct_util:set_testdata({stylesheet,undefined})
- end,
-
- case lists:keysearch(silent_connections, 1, Args) of
- {value,{silent_connections,undefined}} ->
- ok;
- {value,{silent_connections,[]}} ->
+ %% save stylesheet info
+ ct_util:set_testdata({stylesheet,Opts#opts.stylesheet}),
+ %% enable silent connections
+ case Opts#opts.silent_connections of
+ [] ->
Conns = ct_util:override_silence_all_connections(),
ct_logs:log("Silent connections", "~p", [Conns]);
- {value,{silent_connections,Cs}} ->
- Conns = lists:map(fun(S) when is_list(S) ->
- list_to_atom(S);
- (A) -> A
- end, Cs),
+ Conns when is_list(Conns) ->
ct_util:override_silence_connections(Conns),
ct_logs:log("Silent connections", "~p", [Conns]);
_ ->
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index f1692caf24..40925b761a 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -125,7 +125,6 @@ do_start(Parent,Mode,LogDir) ->
Parent ! {self(),Error},
exit(Error)
end,
-
%% start an event manager (if not already started by master)
case ct_event:start_link() of
{error,{already_started,_}} ->
@@ -305,9 +304,9 @@ loop(Mode,TestData,StartDir) ->
ets:delete(?board_table),
ets:delete(?suite_table),
ct_logs:close(How),
- file:set_cwd(StartDir),
ct_event:stop(),
ct_config:stop(),
+ file:set_cwd(StartDir),
return(From,ok);
{get_mode,From} ->
return(From,Mode),
diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl
index 22399aff2a..eb6d82d601 100644
--- a/lib/common_test/src/vts.erl
+++ b/lib/common_test/src/vts.erl
@@ -160,9 +160,9 @@ init(Parent) ->
loop(State) ->
receive
- {{init_data,ConfigFiles,EvHandlers,LogDir,Tests},From} ->
- ct:pal("State#state.current_log_dir=~p", [State#state.current_log_dir]),
- NewState = State#state{config=ConfigFiles,event_handler=EvHandlers,
+ {{init_data,Config,EvHandlers,LogDir,Tests},From} ->
+ %% ct:pal("State#state.current_log_dir=~p", [State#state.current_log_dir]),
+ NewState = State#state{config=Config,event_handler=EvHandlers,
current_log_dir=LogDir,tests=Tests},
ct_install(NewState),
return(From,ok),
--
cgit v1.2.3
From e2698f918a4ec969593181fdad7d86064ef462f0 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Mon, 7 Jun 2010 10:34:11 +0200
Subject: Fix bug that prevents the interactive shell mode to start properly
---
lib/common_test/src/ct_run.erl | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 4b9c9b6981..2d79021ce4 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -154,7 +154,7 @@ script_start1(Parent, Args) ->
Vts = get_start_opt(vts, true, Args),
Shell = get_start_opt(shell, true, Args),
Cover = get_start_opt(cover, fun([CoverFile]) -> ?abs(CoverFile) end, Args),
- LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args),
+ LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, ".", Args),
MultTT = get_start_opt(multiply_timetraps,
fun([MT]) -> list_to_integer(MT) end, 1, Args),
ScaleTT = get_start_opt(scale_timetraps,
@@ -427,12 +427,6 @@ script_start4(#opts{shell = true, config = Config, event_handlers = EvHandlers,
true ->
io:format("\nInstalling: ~p\n\n", [Config])
end,
-
- %%! --- Sun Jun 6 00:58:41 2010 --- peppe was here!
- %%! HERE!!
- %%! Something's not right here. Can't start shell mode
- %%! properly!
-
case install(InstallOpts) of
ok ->
ct_util:start(interactive, LogDir),
--
cgit v1.2.3
From 2dbeff631ce93744972cb04039d434aa172d28f4 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Mon, 7 Jun 2010 17:28:01 +0200
Subject: Fix so that ct_run converts relative diretories in the code path to
absolute
Directories added with run_test -pa or -pz in the pre erl_args part of the command line will be converted from relative to absolute, this to avoid confusion when Common Test switches working directory during the test run.
Also fixed in this commit: Problem with timeouts during init_tc or end_tc (in the Test Server framework).
---
lib/common_test/src/ct_run.erl | 52 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 50 insertions(+), 2 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 2d79021ce4..9dc0bff26a 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -77,6 +77,12 @@ script_start() ->
Init = init:get_arguments(),
CtArgs = lists:takewhile(fun({ct_erl_args,_}) -> false;
(_) -> true end, Init),
+
+ %% convert relative dirs added with pa or pz (pre erl_args on
+ %% the run_test command line) to absolute so that app modules
+ %% can be found even after CT changes CWD to logdir
+ rel_to_abs(CtArgs),
+
Args =
case application:get_env(common_test, run_test_start_opts) of
{ok,EnvStartOpts} ->
@@ -1910,9 +1916,51 @@ event_handler_init_args2opts([EH, Arg]) ->
event_handler_init_args2opts([]) ->
[].
-%% this function translates ct:run_test/1 start options
+%% This function reads pa and pz arguments, converts dirs from relative
+%% to absolute, and re-inserts them in the code path. The order of the
+%% dirs in the code path remain the same. Note however that since this
+%% function is only used for arguments "pre run_test erl_args", the order
+%% relative dirs "post run_test erl_args" is not kept!
+rel_to_abs(CtArgs) ->
+ {PA,PZ} = get_pa_pz(CtArgs, [], []),
+ io:format(user, "~n", []),
+ [begin
+ code:del_path(filename:basename(D)),
+ Abs = filename:absname(D),
+ code:add_pathz(Abs),
+ if D /= Abs ->
+ io:format(user, "Converting ~p to ~p and re-inserting "
+ "with add_pathz/1~n",
+ [D, Abs]);
+ true ->
+ ok
+ end
+ end || D <- PZ],
+ [begin
+ code:del_path(filename:basename(D)),
+ Abs = filename:absname(D),
+ code:add_patha(Abs),
+ if D /= Abs ->
+ io:format(user, "Converting ~p to ~p and re-inserting "
+ "with add_patha/1~n",
+ [D, Abs]);
+ true ->ok
+ end
+ end || D <- PA],
+ io:format(user, "~n", []).
+
+get_pa_pz([{pa,Dirs} | Args], PA, PZ) ->
+ get_pa_pz(Args, PA ++ Dirs, PZ);
+get_pa_pz([{pz,Dirs} | Args], PA, PZ) ->
+ get_pa_pz(Args, PA, PZ ++ Dirs);
+get_pa_pz([_ | Args], PA, PZ) ->
+ get_pa_pz(Args, PA, PZ);
+get_pa_pz([], PA, PZ) ->
+ {PA,PZ}.
+
+%% This function translates ct:run_test/1 start options
%% to run_test start arguments (on the init arguments format) -
-%% this is useful mainly for testing the ct_run start functions
+%% this is useful mainly for testing the ct_run start functions.
opts2args(EnvStartOpts) ->
lists:flatmap(fun({config,CfgFiles}) ->
[{ct_config,[CfgFiles]}];
--
cgit v1.2.3
From aef5c74eba885b7c28d310b4a2522de854012e33 Mon Sep 17 00:00:00 2001
From: Peter Andersson
Date: Tue, 8 Jun 2010 12:41:57 +0200
Subject: Add documentation for run_test program
---
lib/common_test/src/ct_run.erl | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
(limited to 'lib/common_test/src')
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 9dc0bff26a..6a9c42d1b9 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -164,7 +164,9 @@ script_start1(Parent, Args) ->
MultTT = get_start_opt(multiply_timetraps,
fun([MT]) -> list_to_integer(MT) end, 1, Args),
ScaleTT = get_start_opt(scale_timetraps,
- fun([CT]) -> list_to_atom(CT) end, false, Args),
+ fun([CT]) -> list_to_atom(CT);
+ ([]) -> true
+ end, false, Args),
EvHandlers = event_handler_args2opts(Args),
%% check flags and set corresponding application env variables
@@ -478,7 +480,7 @@ script_usage() ->
"\n\t[-suite Suite [-case Case]]"
"\n\t[-include InclDir1 InclDir2 .. InclDirN]"
"\n\t[-no_auto_compile]"
- "\n\t[-multiply_timetraps]"
+ "\n\t[-multiply_timetraps N]"
"\n\t[-scale_timetraps]"
"\n\t[-basic_html]\n\n"),
io:format("Run tests from command line:\n\n"
@@ -495,7 +497,7 @@ script_usage() ->
"\n\t[-event_handler EvHandler1 EvHandler2 .. EvHandlerN]"
"\n\t[-include InclDir1 InclDir2 .. InclDirN]"
"\n\t[-no_auto_compile]"
- "\n\t[-multiply_timetraps]"
+ "\n\t[-multiply_timetraps N]"
"\n\t[-scale_timetraps]"
"\n\t[-basic_html]"
"\n\t[-repeat N [-force_stop]] |"
@@ -513,7 +515,7 @@ script_usage() ->
"\n\t[-event_handler EvHandler1 EvHandler2 .. EvHandlerN]"
"\n\t[-include InclDir1 InclDir2 .. InclDirN]"
"\n\t[-no_auto_compile]"
- "\n\t[-multiply_timetraps]"
+ "\n\t[-multiply_timetraps N]"
"\n\t[-scale_timetraps]"
"\n\t[-basic_html]"
"\n\t[-repeat N [-force_stop]] |"
--
cgit v1.2.3