aboutsummaryrefslogtreecommitdiffstats
path: root/lib/common_test/test
diff options
context:
space:
mode:
Diffstat (limited to 'lib/common_test/test')
-rw-r--r--lib/common_test/test/Makefile1
-rw-r--r--lib/common_test/test/common_test.cover16
-rw-r--r--lib/common_test/test/ct_cover_SUITE.erl53
-rw-r--r--lib/common_test/test/ct_hooks_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_master_SUITE.erl17
-rw-r--r--lib/common_test/test/ct_master_SUITE_data/master/master_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE.erl5
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl7
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/ns.erl21
-rw-r--r--lib/common_test/test/ct_surefire_SUITE.erl77
-rw-r--r--lib/common_test/test/ct_test_support.erl39
-rw-r--r--lib/common_test/test/ct_testspec_2_SUITE.erl20
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE.erl749
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg111
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg121
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg131
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/config2/cfg211
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs1/flat_spec14
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_join12
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_join_sep15
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_sep12
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_sep_join12
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_both12
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_both_join16
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_join11
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_sep13
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs2/flat_spec25
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_join25
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_join_sep25
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_sep25
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_sep_join25
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_both24
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_both_join29
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_join25
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_sep25
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t11_SUITE.erl175
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t12_SUITE.erl175
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t21_SUITE.erl174
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t22_SUITE.erl177
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t23_SUITE.erl158
40 files changed, 1861 insertions, 86 deletions
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index d469d03e04..760cc20410 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -40,6 +40,7 @@ MODULES= \
ct_repeat_1_SUITE \
ct_testspec_1_SUITE \
ct_testspec_2_SUITE \
+ ct_testspec_3_SUITE \
ct_skip_SUITE \
ct_error_SUITE \
ct_test_server_if_1_SUITE \
diff --git a/lib/common_test/test/common_test.cover b/lib/common_test/test/common_test.cover
index 66697854ea..3aa49623e7 100644
--- a/lib/common_test/test/common_test.cover
+++ b/lib/common_test/test/common_test.cover
@@ -1,10 +1,10 @@
%% -*- erlang -*-
{incl_app,common_test,details}.
-{cross_apps,common_test,[erl2html2,
- test_server,
- test_server_ctrl,
- test_server_gl,
- test_server_h,
- test_server_io,
- test_server_node,
- test_server_sup]}.
+{cross,common_test,[{test_server,[erl2html2,
+ test_server,
+ test_server_ctrl,
+ test_server_gl,
+ test_server_h,
+ test_server_io,
+ test_server_node,
+ test_server_sup]}]}.
diff --git a/lib/common_test/test/ct_cover_SUITE.erl b/lib/common_test/test/ct_cover_SUITE.erl
index bebfce70d0..cb49dc423f 100644
--- a/lib/common_test/test/ct_cover_SUITE.erl
+++ b/lib/common_test/test/ct_cover_SUITE.erl
@@ -77,7 +77,8 @@ all() ->
slave_start_slave,
cover_node_option,
ct_cover_add_remove_nodes,
- otp_9956
+ otp_9956,
+ cross
].
%%--------------------------------------------------------------------
@@ -161,6 +162,43 @@ otp_9956(Config) ->
check_calls(Events,{?suite,otp_9956,1},1),
ok.
+%% Test cross cover mechanism
+cross(Config) ->
+ {ok,Events1} = run_test(cross1,Config),
+ check_calls(Events1,1),
+
+ CoverFile2 = create_cover_file(cross1,[{cross,[{cross1,[?mod]}]}],Config),
+ {ok,Events2} = run_test(cross2,[{cover,CoverFile2}],Config),
+ check_calls(Events2,1),
+
+ %% Get the log dirs for each test and run cross cover analyse
+ [D11,D12] = lists:sort(get_run_dirs(Events1)),
+ [D21,D22] = lists:sort(get_run_dirs(Events2)),
+
+ ct_cover:cross_cover_analyse(details,[{cross1,D11},{cross2,D21}]),
+ ct_cover:cross_cover_analyse(details,[{cross1,D12},{cross2,D22}]),
+
+ %% Get the cross cover logs and read for each test
+ [C11,C12,C21,C22] =
+ [filename:join(D,"cross_cover.html") || D <- [D11,D12,D21,D22]],
+
+ {ok,CrossData} = file:read_file(C11),
+ {ok,CrossData} = file:read_file(C12),
+
+ {ok,Def} = file:read_file(C21),
+ {ok,Def} = file:read_file(C22),
+
+ %% A simple test: just check that the test module exists in the
+ %% log from cross1 test, and that it does not exist in the log
+ %% from cross2 test.
+ TestMod = list_to_binary(atom_to_list(?mod)),
+ {_,_} = binary:match(CrossData,TestMod),
+ nomatch = binary:match(Def,TestMod),
+ {_,_} = binary:match(Def,
+ <<"No cross cover modules exist for this application">>),
+
+ ok.
+
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
@@ -229,15 +267,18 @@ check_cover(Node) when is_atom(Node) ->
false
end.
+%% Get the log dir "run.<timestamp>" for all (both!) tests
+get_run_dirs(Events) ->
+ [filename:dirname(TCLog) ||
+ {ct_test_support_eh,
+ {event,tc_logfile,_Node,
+ {{?suite,init_per_suite},TCLog}}} <- Events].
+
%% Check that each coverlog includes N calls to ?mod:foo/0
check_calls(Events,N) ->
check_calls(Events,{?mod,foo,0},N).
check_calls(Events,MFA,N) ->
- CoverLogs =
- [filename:join(filename:dirname(TCLog),"all.coverdata") ||
- {ct_test_support_eh,
- {event,tc_logfile,ct@falco,
- {{?suite,init_per_suite},TCLog}}} <- Events],
+ CoverLogs = [filename:join(D,"all.coverdata") || D <- get_run_dirs(Events)],
do_check_logs(CoverLogs,MFA,N).
do_check_logs([CoverLog|CoverLogs],{Mod,_,_} = MFA,N) ->
diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl
index 405df1e978..796a0832d7 100644
--- a/lib/common_test/test/ct_hooks_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE.erl
@@ -64,7 +64,7 @@ end_per_testcase(TestCase, Config) ->
suite() ->
- [{timetrap,{seconds,20}}].
+ [{timetrap,{minutes,1}}].
all() ->
all(suite).
diff --git a/lib/common_test/test/ct_master_SUITE.erl b/lib/common_test/test/ct_master_SUITE.erl
index 56a343a96f..0f336d2d79 100644
--- a/lib/common_test/test/ct_master_SUITE.erl
+++ b/lib/common_test/test/ct_master_SUITE.erl
@@ -109,7 +109,7 @@ ct_master_test(Config) when is_list(Config) ->
ERPid = ct_test_support:start_event_receiver(Config),
- [{TSFile,ok}] = run_test(ct_master_test, FileName, Config),
+ [{[TSFile],ok}] = run_test(ct_master_test, FileName, Config),
Events = ct_test_support:get_events(ERPid, Config),
@@ -154,6 +154,9 @@ make_spec(DataDir, FileName, NodeNames, Suites, Config) ->
{init,NodeName,[
{node_start,[{startup_functions,[]},
{monitor_master,true},
+ {boot_timeout,10},
+ {init_timeout,10},
+ {startup_timeout,10},
{env,Env}]},
{eval,{erlang,nodes,[]}}]
}
@@ -192,12 +195,12 @@ get_log_dir(_,PrivDir,NodeName) ->
run_test(_Name, FileName, Config) ->
%% run the test twice, using different html versions
- [{FileName,ok}] = ct_test_support:run({ct_master,run,[FileName]},
- [{ct_master,basic_html,[true]}],
- Config),
- [{FileName,ok}] = ct_test_support:run({ct_master,run,[FileName]},
- [{ct_master,basic_html,[false]}],
- Config).
+ [{[FileName],ok}] = ct_test_support:run({ct_master,run,[FileName]},
+ [{ct_master,basic_html,[true]}],
+ Config),
+ [{[FileName],ok}] = ct_test_support:run({ct_master,run,[FileName]},
+ [{ct_master,basic_html,[false]}],
+ Config).
reformat(Events, EH) ->
ct_test_support:reformat(Events, EH).
diff --git a/lib/common_test/test/ct_master_SUITE_data/master/master_SUITE.erl b/lib/common_test/test/ct_master_SUITE_data/master/master_SUITE.erl
index 8a5009ad62..df54c4419c 100644
--- a/lib/common_test/test/ct_master_SUITE_data/master/master_SUITE.erl
+++ b/lib/common_test/test/ct_master_SUITE_data/master/master_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
diff --git a/lib/common_test/test/ct_netconfc_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE.erl
index 3042a924fe..c89a4cdabe 100644
--- a/lib/common_test/test/ct_netconfc_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE.erl
@@ -43,12 +43,11 @@
%% there will be clashes with logging processes etc).
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- Config1 = ct_test_support:init_per_suite(Config),
case application:load(crypto) of
- {error,Reason} ->
+ {error,Reason} when Reason=/={already_loaded,crypto} ->
{skip, Reason};
_ ->
- Config1
+ ct_test_support:init_per_suite(Config)
end.
end_per_suite(Config) ->
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
index d337158bce..54526e8e83 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
@@ -1044,12 +1044,9 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
Key = gen_dsa2(LSize, NSize),
{Key, encode_key(Key)}.
-encode_key(Key = #'RSAPrivateKey'{}) ->
- {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
- {'RSAPrivateKey', list_to_binary(Der), not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
- {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', list_to_binary(Der), not_encrypted}.
+ Der = public_key:der_encode('DSAPrivateKey', Key),
+ {'DSAPrivateKey', Der, not_encrypted}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
index 2427f37f52..09217f60a3 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -426,7 +426,7 @@ reply(ConnRef,Reply) ->
send(ConnRef, make_msg(Reply)).
from_simple(Simple) ->
- list_to_binary(xmerl:export_simple_element(Simple,xmerl_xml)).
+ unicode_c2b(xmerl:export_simple_element(Simple,xmerl_xml)).
xml(Content) ->
<<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
@@ -435,30 +435,30 @@ xml(Content) ->
rpc_reply(Content) when is_binary(Content) ->
MsgId = case erase(msg_id) of
undefined -> <<>>;
- Id -> list_to_binary([" message-id=\"",Id,"\""])
+ Id -> unicode_c2b([" message-id=\"",Id,"\""])
end,
<<"<rpc-reply xmlns=\"",?NETCONF_NAMESPACE,"\"",MsgId/binary,">\n",
Content/binary,"\n</rpc-reply>">>;
rpc_reply(Content) ->
- rpc_reply(list_to_binary(Content)).
+ rpc_reply(unicode_c2b(Content)).
session_id(no_session_id) ->
<<>>;
session_id(SessionId0) ->
- SessionId = list_to_binary(integer_to_list(SessionId0)),
+ SessionId = unicode_c2b(integer_to_list(SessionId0)),
<<"<session-id>",SessionId/binary,"</session-id>\n">>.
capabilities(undefined) ->
- CapsXml = list_to_binary([["<capability>",C,"</capability>\n"]
+ CapsXml = unicode_c2b([["<capability>",C,"</capability>\n"]
|| C <- ?CAPABILITIES]),
<<"<capabilities>\n",CapsXml/binary,"</capabilities>\n">>;
capabilities({base,Vsn}) ->
- CapsXml = list_to_binary([["<capability>",C,"</capability>\n"]
+ CapsXml = unicode_c2b([["<capability>",C,"</capability>\n"]
|| C <- ?CAPABILITIES_VSN(Vsn)]),
<<"<capabilities>\n",CapsXml/binary,"</capabilities>\n">>;
capabilities(no_base) ->
[_|Caps] = ?CAPABILITIES,
- CapsXml = list_to_binary([["<capability>",C,"</capability>\n"] || C <- Caps]),
+ CapsXml = unicode_c2b([["<capability>",C,"</capability>\n"] || C <- Caps]),
<<"<capabilities>\n",CapsXml/binary,"</capabilities>\n">>;
capabilities(no_caps) ->
<<>>.
@@ -553,3 +553,8 @@ make_msg(Xml) when is_binary(Xml) ->
xml(Xml);
make_msg(Simple) when is_tuple(Simple) ->
xml(from_simple(Simple)).
+
+%%%-----------------------------------------------------------------
+%%% Convert to unicode binary, since we use UTF-8 encoding in XML
+unicode_c2b(Characters) ->
+ unicode:characters_to_binary(Characters).
diff --git a/lib/common_test/test/ct_surefire_SUITE.erl b/lib/common_test/test/ct_surefire_SUITE.erl
index 69e98cef48..b86b47f0a2 100644
--- a/lib/common_test/test/ct_surefire_SUITE.erl
+++ b/lib/common_test/test/ct_surefire_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,6 +32,7 @@
-include_lib("common_test/include/ct_event.hrl").
-include_lib("xmerl/include/xmerl.hrl").
+-include_lib("kernel/include/file.hrl").
-define(eh, ct_test_support_eh).
@@ -77,53 +78,52 @@ all() ->
%%%-----------------------------------------------------------------
%%%
default(Config) when is_list(Config) ->
- run(default,[cth_surefire],Config),
- PrivDir = ?config(priv_dir,Config),
- XmlRe = filename:join([PrivDir,"*","junit_report.xml"]),
- check_xml(default,XmlRe).
+ run(default,[cth_surefire],"junit_report.xml",Config).
absolute_path(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir,Config),
Path = filename:join(PrivDir,"abspath.xml"),
- run(absolute_path,[{cth_surefire,[{path,Path}]}],Config),
- check_xml(absolute_path,Path).
+ run(absolute_path,[{cth_surefire,[{path,Path}]}],Path,Config).
relative_path(Config) when is_list(Config) ->
Path = "relpath.xml",
- run(relative_path,[{cth_surefire,[{path,Path}]}],Config),
- PrivDir = ?config(priv_dir,Config),
- XmlRe = filename:join([PrivDir,"*",Path]),
- check_xml(relative_path,XmlRe).
+ run(relative_path,[{cth_surefire,[{path,Path}]}],Path,Config).
url(Config) when is_list(Config) ->
Path = "url.xml",
- run(url,[{cth_surefire,[{url_base,?url_base},
- {path,Path}]}],Config),
- PrivDir = ?config(priv_dir,Config),
- XmlRe = filename:join([PrivDir,"*",Path]),
- check_xml(url,XmlRe).
+ run(url,[{cth_surefire,[{url_base,?url_base},{path,Path}]}],
+ Path,Config).
logdir(Config) when is_list(Config) ->
- PrivDir = ?config(priv_dir,Config),
- LogDir = filename:join(PrivDir,"specific_logdir"),
- file:make_dir(LogDir),
+ Opts = ct_test_support:get_opts(Config),
+ LogDir =
+ case lists:keyfind(logdir,1,Opts) of
+ {logdir,LD} -> LD;
+ false -> ?config(priv_dir,Config)
+ end,
+ MyLogDir = filename:join(LogDir,"specific_logdir"),
+ ensure_exists_empty(MyLogDir),
Path = "logdir.xml",
- run(logdir,[{cth_surefire,[{path,Path}]}],Config,[{logdir,LogDir}]),
- PrivDir = ?config(priv_dir,Config),
- XmlRe = filename:join([LogDir,"*",Path]),
- check_xml(logdir,XmlRe).
+ run(logdir,[{cth_surefire,[{path,Path}]}],Path,Config,[{logdir,MyLogDir}]).
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
-run(Case,CTHs,Config) ->
- run(Case,CTHs,Config,[]).
-run(Case,CTHs,Config,ExtraOpts) ->
+run(Case,CTHs,Report,Config) ->
+ run(Case,CTHs,Report,Config,[]).
+run(Case,CTHs,Report,Config,ExtraOpts) ->
DataDir = ?config(data_dir, Config),
Suite = filename:join(DataDir, "surefire_SUITE"),
{Opts,ERPid} = setup([{suite,Suite},{ct_hooks,CTHs},{label,Case}|ExtraOpts],
Config),
- ok = execute(Case, Opts, ERPid, Config).
+ ok = execute(Case, Opts, ERPid, Config),
+ LogDir =
+ case lists:keyfind(logdir,1,Opts) of
+ {logdir,LD} -> LD;
+ false -> ?config(priv_dir,Config)
+ end,
+ Re = filename:join([LogDir,"*",Report]),
+ check_xml(Case,Re).
setup(Test, Config) ->
Opts0 = ct_test_support:get_opts(Config),
@@ -349,3 +349,26 @@ get_numbers_from_attrs([_|A],T,E,F,S) ->
get_numbers_from_attrs(A,T,E,F,S);
get_numbers_from_attrs([],T,E,F,S) ->
{T,E,F,S}.
+
+ensure_exists_empty(Dir) ->
+ case file:list_dir(Dir) of
+ {error,enoent} ->
+ file:make_dir(Dir);
+ {ok,Files} ->
+ del_files(Dir,Files)
+ end.
+
+del_files(Dir,[F0|Fs] ) ->
+ F = filename:join(Dir,F0),
+ case file:read_file_info(F) of
+ {ok,#file_info{type=directory}} ->
+ {ok,Files} = file:list_dir(F),
+ del_files(F,Files),
+ file:del_dir(F),
+ del_files(Dir,Fs);
+ _ ->
+ file:delete(F),
+ del_files(Dir,Fs)
+ end;
+del_files(_,[]) ->
+ ok.
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index e5e2e68fcb..7c33fd404d 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -117,11 +117,7 @@ end_per_suite(Config) ->
CTNode = proplists:get_value(ct_node, Config),
PrivDir = proplists:get_value(priv_dir, Config),
true = rpc:call(CTNode, code, del_path, [filename:join(PrivDir,"")]),
- case test_server:is_cover() of
- true -> cover:flush(CTNode);
- false -> ok
- end,
- slave:stop(CTNode),
+ slave_stop(CTNode),
ok.
%%%-----------------------------------------------------------------
@@ -152,11 +148,7 @@ end_per_testcase(_TestCase, Config) ->
case wait_for_ct_stop(CTNode) of
%% Common test was not stopped to we restart node.
false ->
- case test_server:is_cover() of
- true -> cover:flush(CTNode);
- false -> ok
- end,
- slave:stop(CTNode),
+ slave_stop(CTNode),
start_slave(Config,proplists:get_value(trace_level,Config)),
{fail, "Could not stop common_test"};
true ->
@@ -1051,8 +1043,8 @@ result_match({SkipOrFail,{ErrorInd,{EMod,EFunc,{Why,'_'}}}},
true;
result_match({failed,{timetrap_timeout,{'$approx',Num}}},
{failed,{timetrap_timeout,Value}}) ->
- if Value >= trunc(Num-0.02*Num),
- Value =< trunc(Num+0.02*Num) -> true;
+ if Value >= trunc(Num-0.05*Num),
+ Value =< trunc(Num+0.05*Num) -> true;
true -> false
end;
result_match({user_timetrap_error,{Why,'_'}},
@@ -1140,6 +1132,8 @@ reformat([{_EH,#event{name=test_start,data=_}} | Events], EH) ->
[{EH,test_start,{'DEF',{'START_TIME','LOGDIR'}}} | reformat(Events, EH)];
reformat([{_EH,#event{name=test_done,data=_}} | Events], EH) ->
[{EH,test_done,{'DEF','STOP_TIME'}} | reformat(Events, EH)];
+reformat([{_EH,#event{name=tc_logfile,data=_}} | Events], EH) ->
+ reformat(Events, EH);
reformat([{_EH,#event{name=test_stats,data=Data}} | Events], EH) ->
[{EH,test_stats,Data} | reformat(Events, EH)];
%% use this to only print the last test_stats event:
@@ -1274,3 +1268,22 @@ rm_files([F | Fs]) ->
rm_files([]) ->
ok.
+%%%-----------------------------------------------------------------
+%%%
+slave_stop(Node) ->
+ Cover = test_server:is_cover(),
+ if Cover-> cover:flush(Node);
+ true -> ok
+ end,
+ erlang:monitor_node(Node, true),
+ slave:stop(Node),
+ receive
+ {nodedown, Node} ->
+ if Cover -> cover:stop(Node);
+ true -> ok
+ end
+ after 5000 ->
+ erlang:monitor_node(Node, false),
+ receive {nodedown, Node} -> ok after 0 -> ok end %flush
+ end,
+ ok.
diff --git a/lib/common_test/test/ct_testspec_2_SUITE.erl b/lib/common_test/test/ct_testspec_2_SUITE.erl
index 9d2dc84ad3..ea22312a7d 100644
--- a/lib/common_test/test/ct_testspec_2_SUITE.erl
+++ b/lib/common_test/test/ct_testspec_2_SUITE.erl
@@ -479,7 +479,7 @@ multiple_specs(_Config) ->
"multiple_specs.1.spec"),
SpecFile2 = ct_test_support:write_testspec(Spec2,SpecDir,
"multiple_specs.2.spec"),
- FileResult = ct_testspec:collect_tests_from_file([SpecFile1,SpecFile2],
+ FileResult = ct_testspec:collect_tests_from_file([[SpecFile1,SpecFile2]],
false),
ct:pal("TESTSPEC RECORD FROM FILE:~n~p~n", [rec2proplist(FileResult)]),
@@ -490,7 +490,7 @@ multiple_specs(_Config) ->
[{Node2,get_absdir(filename:join(SpecDir,CfgDir))} || CfgDir <- CfgDir2]],
LogDirV = get_absdir(filename:join(SpecDir,"../logs")),
- Verify = #testspec{merge_tests = false,
+ Verify = #testspec{merge_tests = true,
spec_dir = SpecDir,
nodes = [{undefined,Node},{n1,Node1},{n2,Node2}],
alias = [{to1,TO1V},{to2,TO2V}],
@@ -524,7 +524,7 @@ multiple_specs(_Config) ->
%%%
misc_config_terms(_Config) ->
CfgDir = "../cfgs/to1",
-
+ TODir = "../tests/to1",
Spec =
[{node,x,n1@h1},{node,y,n2@h2},
@@ -554,7 +554,9 @@ misc_config_terms(_Config) ->
{create_priv_dir,[auto_per_tc]},
{create_priv_dir,n1@h1,[manual_per_tc]},
- {create_priv_dir,n2@h2,[auto_per_run]}
+ {create_priv_dir,n2@h2,[auto_per_run]},
+
+ {suites,n1@h1,TODir,[x_SUITE]}
],
{ok,SpecDir} = file:get_cwd(),
@@ -599,7 +601,9 @@ misc_config_terms(_Config) ->
{n2@h2,CSS2}],
create_priv_dir = [{Node,[auto_per_tc]},
{n1@h1,[manual_per_tc]},
- {n2@h2,[auto_per_run]}]
+ {n2@h2,[auto_per_run]}],
+ tests = [{{n1@h1,get_absdir(filename:join(SpecDir,TODir))},
+ [{x_SUITE,[all]}]}]
},
verify_result(Verify,ListResult,FileResult).
@@ -688,10 +692,10 @@ define_names_1(_Config) ->
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
-verify_result(Verify,ListResult,FileResult) ->
+verify_result(VerificationRec,ListResult,FileResult) ->
{_,TSLTuples} = rec2proplist(ListResult),
{_,TSFTuples} = rec2proplist(FileResult),
- {_,VTuples} = rec2proplist(Verify),
+ {_,VTuples} = rec2proplist(VerificationRec),
VResult =
(catch lists:foldl(fun({Tag,Val},{[{Tag,Val}|TSL],[{Tag,Val}|TSF]}) ->
{TSL,TSF};
@@ -720,6 +724,8 @@ read_config(S) ->
rec2proplist(E={error,_What}) ->
exit({invalid_testspec_record,E});
+rec2proplist([{Specs,Rec}]) when is_list(Specs) ->
+ rec2proplist(Rec);
rec2proplist(Rec) ->
[RecName|RecList] = tuple_to_list(Rec),
FieldNames =
diff --git a/lib/common_test/test/ct_testspec_3_SUITE.erl b/lib/common_test/test/ct_testspec_3_SUITE.erl
new file mode 100644
index 0000000000..8b84b563ab
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE.erl
@@ -0,0 +1,749 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_testspec_1_SUITE
+%%%
+%%% Description:
+%%% Test test specifications
+%%%
+%%% The suites used for the test are located in the data directory.
+%%%-------------------------------------------------------------------
+-module(ct_testspec_3_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Config1 = ct_test_support:init_per_suite(Config),
+ SpecsDir1 = filename:join(DataDir, "specs1"),
+ SpecsDir2 = filename:join(DataDir, "specs2"),
+ [{specs_dir1,SpecsDir1},{specs_dir2,SpecsDir2} | Config1].
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [start_separate,
+ start_join,
+ incl_separate1,
+ incl_separate2,
+ incl_join1,
+ incl_join2,
+ incl_both1,
+ incl_both2,
+ incl_both_and_join1,
+ incl_both_and_join2,
+ rec_incl_separate1,
+ rec_incl_separate2,
+ rec_incl_join1,
+ rec_incl_join2,
+ rec_incl_separate_join1,
+ rec_incl_separate_join2,
+ rec_incl_join_separate1,
+ rec_incl_join_separate2
+ ].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+
+start_separate(Config) ->
+ Specs = [fname(specs_dir1, "flat_spec1", Config),
+ fname(specs_dir2, "flat_spec2", Config)],
+ setup_and_execute(start_separate, Specs, [], Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+start_join(Config) ->
+ Specs = [fname(specs_dir1, "flat_spec1", Config),
+ fname(specs_dir2, "flat_spec2", Config)],
+ setup_and_execute(start_join, Specs, [{join_specs,true}], Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+incl_separate1(Config) ->
+ Specs = [fname(specs_dir1, "spec_sep1", Config),
+ fname(specs_dir2, "spec_sep2", Config)],
+ setup_and_execute(incl_separate1, Specs, [], Config).
+
+incl_separate2(Config) ->
+ Specs = [fname(specs_dir1, "spec_sep1", Config),
+ fname(specs_dir2, "spec_sep2", Config)],
+ setup_and_execute(incl_separate2, Specs, [{join_specs,true}], Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+incl_join1(Config) ->
+ Specs = [fname(specs_dir1, "spec_join1", Config),
+ fname(specs_dir2, "spec_join2", Config)],
+ setup_and_execute(incl_join1, Specs, [], Config).
+
+incl_join2(Config) ->
+ Specs = [fname(specs_dir1, "spec_join1", Config),
+ fname(specs_dir2, "spec_join2", Config)],
+ setup_and_execute(incl_join2, Specs, [{join_specs,true}], Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+incl_both1(Config) ->
+ Specs = [fname(specs_dir1, "spec_both1", Config),
+ fname(specs_dir2, "spec_both2", Config)],
+ setup_and_execute(incl_both1, Specs, [], Config).
+
+incl_both2(Config) ->
+ Specs = [fname(specs_dir1, "spec_both1", Config),
+ fname(specs_dir2, "spec_both2", Config)],
+ setup_and_execute(incl_both2, Specs, [{join_specs,true}], Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+incl_both_and_join1(Config) ->
+ Specs = [fname(specs_dir1, "spec_both_join1", Config),
+ fname(specs_dir2, "spec_both_join2", Config)],
+ setup_and_execute(incl_both_and_join1, Specs, [], Config).
+
+incl_both_and_join2(Config) ->
+ Specs = [fname(specs_dir1, "spec_both_join1", Config),
+ fname(specs_dir2, "spec_both_join2", Config)],
+ setup_and_execute(incl_both_and_join2, Specs, [{join_specs,true}], Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+rec_incl_separate1(Config) ->
+ Specs = [fname(specs_dir1, "rec_spec_sep1", Config),
+ fname(specs_dir2, "rec_spec_sep2", Config)],
+ setup_and_execute(rec_incl_separate1, Specs, [], Config).
+
+rec_incl_separate2(Config) ->
+ Specs = [fname(specs_dir1, "rec_spec_sep1", Config),
+ fname(specs_dir2, "rec_spec_sep2", Config)],
+ setup_and_execute(rec_incl_separate2, Specs, [{join_specs,true}], Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+rec_incl_join1(Config) ->
+ Specs = [fname(specs_dir1, "rec_spec_join1", Config),
+ fname(specs_dir2, "rec_spec_join2", Config)],
+ setup_and_execute(rec_incl_join1, Specs, [], Config).
+
+rec_incl_join2(Config) ->
+ Specs = [fname(specs_dir1, "rec_spec_join1", Config),
+ fname(specs_dir2, "rec_spec_join2", Config)],
+ setup_and_execute(rec_incl_join2, Specs, [{join_specs,true}], Config).
+
+
+%%%-----------------------------------------------------------------
+%%%
+
+rec_incl_separate_join1(Config) ->
+ Specs = [fname(specs_dir1, "rec_spec_sep_join1", Config),
+ fname(specs_dir2, "rec_spec_sep_join2", Config)],
+ setup_and_execute(rec_incl_separate_join1, Specs, [], Config).
+
+rec_incl_separate_join2(Config) ->
+ Specs = [fname(specs_dir1, "rec_spec_sep_join1", Config),
+ fname(specs_dir2, "rec_spec_sep_join2", Config)],
+ setup_and_execute(rec_incl_separate_join2, Specs,
+ [{join_specs,true}], Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+rec_incl_join_separate1(Config) ->
+ Specs = [fname(specs_dir1, "rec_spec_join_sep1", Config),
+ fname(specs_dir2, "rec_spec_join_sep2", Config)],
+ setup_and_execute(rec_incl_join_separate1, Specs, [], Config).
+
+rec_incl_join_separate2(Config) ->
+ Specs = [fname(specs_dir1, "rec_spec_join_sep1", Config),
+ fname(specs_dir2, "rec_spec_join_sep2", Config)],
+ setup_and_execute(rec_incl_join_separate2, Specs,
+ [{join_specs,true}], Config).
+
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+fname(Tag, File, Config) ->
+ filename:join(?config(Tag, Config), File).
+
+check_parameter(TCID) ->
+ {ok,{config,TCID}}.
+
+read_config(TCID) ->
+ {ok,[{tcname,list_to_atom(TCID)}]}.
+
+setup_and_execute(TCName, Specs, TestOpts, Config) ->
+
+ TestID = {userconfig,{?MODULE,atom_to_list(TCName)}},
+ TestTerms = [TestID,{spec,Specs},{label,TCName}] ++ TestOpts,
+
+ {Opts,ERPid} = setup(TestTerms, Config),
+
+ case ct_test_support:run(Opts, Config) of
+ ok ->
+ ok;
+ Error ->
+ ct:pal("Error executing with opts: ~p", [Opts]),
+ exit(Error)
+ end,
+
+ Events = ct_test_support:get_events(ERPid, Config),
+
+ ct_test_support:log_events(TCName,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+
+ TestEvents = events_to_check(TCName),
+ ok = ct_test_support:verify_events(TestEvents, Events, Config).
+
+setup(Test, Config) when is_tuple(Test) ->
+ setup([Test], Config);
+setup(Tests, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ Tests ++ [{event_handler,{?eh,EvHArgs}}],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+%reformat(Events, _EH) ->
+% Events.
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+events_to_check(Test) ->
+ %% 2 tests (ct:run_test + script_start) is default
+ events_to_check(Test, 2).
+
+events_to_check(_, 0) ->
+ [];
+events_to_check(Test, N) ->
+ test_events(Test) ++ events_to_check(Test, N-1).
+
+test_events(start_separate) ->
+ [{?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{3,2,15}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(start_join) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(incl_separate1) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{3,2,15}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,5}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{3,2,15}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(incl_separate2) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,5}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{3,2,15}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{3,2,15}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(incl_join1) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(incl_join2) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,ok_tc}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(incl_both1) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{3,2,15}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(incl_both2) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{3,2,15}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(incl_both_and_join1) -> [];
+test_events(incl_both_and_join2) -> [];
+test_events(rec_incl_separate1) -> [];
+test_events(rec_incl_separate2) -> [];
+test_events(rec_incl_join1) -> [];
+test_events(rec_incl_join2) -> [];
+test_events(rec_incl_separate_join1) -> [];
+test_events(rec_incl_separate_join2) -> [];
+test_events(rec_incl_join_separate1) -> [];
+test_events(rec_incl_join_separate2) -> [];
+
+test_events(_) ->
+ [].
+
+
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg11 b/lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg11
new file mode 100644
index 0000000000..bc672568da
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg11
@@ -0,0 +1 @@
+{file, cfg11}. \ No newline at end of file
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg12 b/lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg12
new file mode 100644
index 0000000000..30f2cf6857
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg12
@@ -0,0 +1 @@
+{file, cfg12}. \ No newline at end of file
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg13 b/lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg13
new file mode 100644
index 0000000000..1860ec78e5
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/config1/cfg13
@@ -0,0 +1 @@
+{file, cfg13}. \ No newline at end of file
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/config2/cfg21 b/lib/common_test/test/ct_testspec_3_SUITE_data/config2/cfg21
new file mode 100644
index 0000000000..b18d35443e
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/config2/cfg21
@@ -0,0 +1 @@
+{file, cfg21}. \ No newline at end of file
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/flat_spec1 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/flat_spec1
new file mode 100644
index 0000000000..eff87222ea
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/flat_spec1
@@ -0,0 +1,4 @@
+{config, "../config1/cfg11"}.
+{suites, "../tests1", t11_SUITE}.
+{suites, "../tests1", t11_SUITE}.
+{suites, "../tests2", t21_SUITE}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_join1 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_join1
new file mode 100644
index 0000000000..a3387f48a3
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_join1
@@ -0,0 +1,2 @@
+{specs,join,"spec_join1"}.
+{specs,join,"../specs2/spec_join2"}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_join_sep1 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_join_sep1
new file mode 100644
index 0000000000..fe127eb4b9
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_join_sep1
@@ -0,0 +1,5 @@
+{specs,join,"spec_sep1"}.
+{specs,join,"../specs2/spec_sep2"}.
+
+{config, "../config1/cfg13"}.
+{suites, "../tests2", t23_SUITE}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_sep1 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_sep1
new file mode 100644
index 0000000000..c778aa68a6
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_sep1
@@ -0,0 +1,2 @@
+{specs,separate,"spec_sep1"}.
+{specs,separate,"../specs2/spec_sep2"}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_sep_join1 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_sep_join1
new file mode 100644
index 0000000000..7cb5a05fff
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/rec_spec_sep_join1
@@ -0,0 +1,2 @@
+{specs,separate,"spec_join1"}.
+{specs,separate,"../specs2/spec_join2"}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_both1 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_both1
new file mode 100644
index 0000000000..46111614dc
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_both1
@@ -0,0 +1,2 @@
+{specs, join, "../specs1/flat_spec1"}.
+{specs, separate, "../specs2/flat_spec2"}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_both_join1 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_both_join1
new file mode 100644
index 0000000000..f52b3ed030
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_both_join1
@@ -0,0 +1,6 @@
+{specs, join, "../specs1/flat_spec1"}.
+{specs, separate, "../specs2/flat_spec2"}.
+{merge_tests,false}.
+{config, "../config1/cfg12"}.
+{suites, "../tests1", t11_SUITE}.
+{suites, "../tests2", t21_SUITE}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_join1 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_join1
new file mode 100644
index 0000000000..baaaf35be4
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_join1
@@ -0,0 +1 @@
+{specs, join, ["../specs2/flat_spec2", "flat_spec1"]}. \ No newline at end of file
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_sep1 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_sep1
new file mode 100644
index 0000000000..89456c35e0
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs1/spec_sep1
@@ -0,0 +1,3 @@
+{specs, separate, "../specs2/flat_spec2"}.
+{specs, separate, "flat_spec1"}.
+
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/flat_spec2 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/flat_spec2
new file mode 100644
index 0000000000..758d1e2514
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/flat_spec2
@@ -0,0 +1,5 @@
+{merge_tests, false}.
+{config, "../config2/cfg21"}.
+{suites, "../tests1", t12_SUITE}.
+{suites, "../tests1", t12_SUITE}.
+{suites, "../tests2", t22_SUITE}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_join2 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_join2
new file mode 100644
index 0000000000..19d3a3d8e2
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_join2
@@ -0,0 +1,5 @@
+{specs,join,"spec_join2"}.
+{specs,join,"../specs1/spec_join1"}.
+
+{config, "../config1/cfg13"}.
+{suites, "../tests2", t23_SUITE}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_join_sep2 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_join_sep2
new file mode 100644
index 0000000000..930e68c847
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_join_sep2
@@ -0,0 +1,5 @@
+{specs,join,"spec_sep2"}.
+{specs,join,"../specs1/spec_sep1"}.
+
+{config, "../config1/cfg13"}.
+{suites, "../tests2", t23_SUITE}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_sep2 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_sep2
new file mode 100644
index 0000000000..5026f329a7
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_sep2
@@ -0,0 +1,5 @@
+{specs,separate,"spec_sep2"}.
+{specs,separate,"../specs1/spec_sep1"}.
+
+{config, "../config1/cfg13"}.
+{suites, "../tests2", t23_SUITE}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_sep_join2 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_sep_join2
new file mode 100644
index 0000000000..17057088b4
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/rec_spec_sep_join2
@@ -0,0 +1,5 @@
+{specs,separate,"spec_join2"}.
+{specs,separate,"../specs1/spec_join1"}.
+
+{config, "../config1/cfg13"}.
+{suites, "../tests2", t23_SUITE}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_both2 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_both2
new file mode 100644
index 0000000000..4c83115d23
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_both2
@@ -0,0 +1,4 @@
+{specs, separate, "../specs1/flat_spec1"}.
+{specs, join, "../specs2/flat_spec2"}.
+{config, "../config1/cfg12"}.
+
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_both_join2 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_both_join2
new file mode 100644
index 0000000000..ad81bfb4cc
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_both_join2
@@ -0,0 +1,9 @@
+{merge_tests,true}.
+{config, "../config1/cfg12"}.
+{suites, "../tests1", t11_SUITE}.
+{suites, "../tests2", t21_SUITE}.
+{suites, "../tests1", t12_SUITE}.
+{suites, "../tests2", t22_SUITE}.
+
+{specs, separate, "../specs1/flat_spec1"}.
+{specs, join, "../specs2/flat_spec2"}.
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_join2 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_join2
new file mode 100644
index 0000000000..d652dbd78f
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_join2
@@ -0,0 +1,5 @@
+{specs, join, ["../specs1/flat_spec1"]}.
+{specs, join, ["flat_spec2"]}.
+{config, "../config1/cfg12"}.
+{suites, "../tests2", t22_SUITE}.
+
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_sep2 b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_sep2
new file mode 100644
index 0000000000..8d37f508b8
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/specs2/spec_sep2
@@ -0,0 +1,5 @@
+{specs, separate, "../specs1/flat_spec1"}.
+{specs, separate, "flat_spec2"}.
+{config, "../config1/cfg12"}.
+{suites, "../tests2", t22_SUITE}.
+
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t11_SUITE.erl b/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t11_SUITE.erl
new file mode 100644
index 0000000000..bbe79ed3fe
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t11_SUITE.erl
@@ -0,0 +1,175 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(t11_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% @spec suite() -> Info
+%% Info = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+suite() ->
+ [{require,file},
+ {require,tcname},
+ {timetrap,{seconds,1}}].
+
+%%--------------------------------------------------------------------
+%% @spec init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ %% verify that expected config file can be read
+ case {ct:get_config(tcname),ct:get_config(file,undefined,[all])} of
+ {start_separate,[cfg11]} -> ok;
+ {start_join,[cfg11,cfg21]} -> ok;
+ {incl_separate1,[cfg11]} -> ok;
+ {incl_separate2,[cfg11]} -> ok;
+ {incl_join1,[cfg21,cfg11]} -> ok;
+ {incl_join1,[cfg12,cfg11,cfg21]} -> ok;
+ {incl_join2,[cfg21,cfg11,cfg12]} -> ok;
+ {incl_both1,[cfg11]} -> ok;
+ {incl_both2,[cfg11,cfg12,cfg21]} -> ok;
+ {incl_both2,[cfg11]} -> ok;
+ _ -> ok
+
+ end,
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_suite(Config0) -> void() | {save_config,Config1}
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_group(GroupName, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_group(GroupName, Config0) ->
+%% void() | {save_config,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_testcase(autoskip_tc, Config) ->
+ exit(kaboom),
+ Config;
+
+init_per_testcase(userskip_tc, Config) ->
+ {skip,"user skipped"};
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1} | {fail,Reason}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec groups() -> [Group]
+%% Group = {GroupName,Properties,GroupsAndTestCases}
+%% GroupName = atom()
+%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
+%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
+%% TestCase = atom()
+%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
+%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
+%% repeat_until_any_ok | repeat_until_any_fail
+%% N = integer() | forever
+%% @end
+%%--------------------------------------------------------------------
+groups() ->
+ [].
+
+%%--------------------------------------------------------------------
+%% @spec all() -> GroupsAndTestCases | {skip,Reason}
+%% GroupsAndTestCases = [{group,GroupName} | TestCase]
+%% GroupName = atom()
+%% TestCase = atom()
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+all() ->
+ [ok_tc, exit_tc, to_tc, autoskip_tc, userskip_tc].
+
+%%--------------------------------------------------------------------
+%% @spec TestCase(Config0) ->
+%% ok | exit() | {skip,Reason} | {comment,Comment} |
+%% {save_config,Config1} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% Comment = term()
+%% @end
+%%--------------------------------------------------------------------
+ok_tc(_) ->
+ ok.
+
+exit_tc(_) ->
+ exit(kaboom),
+ ok.
+
+to_tc(_) ->
+ ct:timetrap(1),
+ ct:sleep(100),
+ ok.
+
+autoskip_tc(_) ->
+ ok.
+
+userskip_tc(_) ->
+ ok.
+
+
+
+
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t12_SUITE.erl b/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t12_SUITE.erl
new file mode 100644
index 0000000000..810298d348
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t12_SUITE.erl
@@ -0,0 +1,175 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(t12_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% @spec suite() -> Info
+%% Info = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+suite() ->
+ [{require,file},
+ {require,tcname},
+ {timetrap,{seconds,30}}].
+
+%%--------------------------------------------------------------------
+%% @spec init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ %% verify that expected config file can be read
+ case {ct:get_config(tcname),ct:get_config(file,undefined,[all])} of
+ {start_separate,[cfg21]} -> ok;
+ {start_join,[cfg11,cfg21]} -> ok;
+ {incl_separate1,[cfg21]} -> ok;
+ {incl_separate2,[cfg21]} -> ok;
+ {incl_join1,[cfg21,cfg11]} -> ok;
+ {incl_join1,[cfg12,cfg11,cfg21]} -> ok;
+ {incl_join2,[cfg21,cfg11,cfg12]} -> ok;
+ {incl_both1,[cfg21]} -> ok;
+ {incl_both1,[cfg12,cfg21]} -> ok;
+ {incl_both2,[cfg11,cfg12,cfg21]} -> ok;
+ {incl_both2,[cfg21]} -> ok;
+ _ -> ok
+ end,
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_suite(Config0) -> void() | {save_config,Config1}
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_group(GroupName, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_group(GroupName, Config0) ->
+%% void() | {save_config,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_testcase(autoskip_tc, Config) ->
+ exit(kaboom),
+ Config;
+
+init_per_testcase(userskip_tc, Config) ->
+ {skip,"user skipped"};
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1} | {fail,Reason}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec groups() -> [Group]
+%% Group = {GroupName,Properties,GroupsAndTestCases}
+%% GroupName = atom()
+%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
+%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
+%% TestCase = atom()
+%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
+%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
+%% repeat_until_any_ok | repeat_until_any_fail
+%% N = integer() | forever
+%% @end
+%%--------------------------------------------------------------------
+groups() ->
+ [].
+
+%%--------------------------------------------------------------------
+%% @spec all() -> GroupsAndTestCases | {skip,Reason}
+%% GroupsAndTestCases = [{group,GroupName} | TestCase]
+%% GroupName = atom()
+%% TestCase = atom()
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+all() ->
+ [ok_tc, exit_tc, to_tc, autoskip_tc, userskip_tc].
+
+%%--------------------------------------------------------------------
+%% @spec TestCase(Config0) ->
+%% ok | exit() | {skip,Reason} | {comment,Comment} |
+%% {save_config,Config1} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% Comment = term()
+%% @end
+%%--------------------------------------------------------------------
+ok_tc(_) ->
+ ok.
+
+exit_tc(_) ->
+ exit(kaboom),
+ ok.
+
+to_tc(_) ->
+ ct:timetrap(1),
+ ct:sleep(100),
+ ok.
+
+autoskip_tc(_) ->
+ ok.
+
+userskip_tc(_) ->
+ ok.
+
+
+
+
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t21_SUITE.erl b/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t21_SUITE.erl
new file mode 100644
index 0000000000..9348cd8caf
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t21_SUITE.erl
@@ -0,0 +1,174 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(t21_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% @spec suite() -> Info
+%% Info = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+suite() ->
+ [{require,file},
+ {require,tcname},
+ {timetrap,{seconds,1}}].
+
+%%--------------------------------------------------------------------
+%% @spec init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ %% verify that expected config file can be read
+ case {ct:get_config(tcname),ct:get_config(file,undefined,[all])} of
+ {start_separate,[cfg11]} -> ok;
+ {start_join,[cfg11,cfg21]} -> ok;
+ {incl_separate1,[cfg11]} -> ok;
+ {incl_separate2,[cfg11]} -> ok;
+ {incl_join1,[cfg21,cfg11]} -> ok;
+ {incl_join1,[cfg12,cfg11,cfg21]} -> ok;
+ {incl_join2,[cfg21,cfg11,cfg12]} -> ok;
+ {incl_both1,[cfg11]} -> ok;
+ {incl_both2,[cfg11,cfg12,cfg21]} -> ok;
+ {incl_both2,[cfg11]} -> ok;
+ _ -> ok
+ end,
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_suite(Config0) -> void() | {save_config,Config1}
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_group(GroupName, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_group(GroupName, Config0) ->
+%% void() | {save_config,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_testcase(autoskip_tc, Config) ->
+ exit(kaboom),
+ Config;
+
+init_per_testcase(userskip_tc, Config) ->
+ {skip,"user skipped"};
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1} | {fail,Reason}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec groups() -> [Group]
+%% Group = {GroupName,Properties,GroupsAndTestCases}
+%% GroupName = atom()
+%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
+%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
+%% TestCase = atom()
+%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
+%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
+%% repeat_until_any_ok | repeat_until_any_fail
+%% N = integer() | forever
+%% @end
+%%--------------------------------------------------------------------
+groups() ->
+ [].
+
+%%--------------------------------------------------------------------
+%% @spec all() -> GroupsAndTestCases | {skip,Reason}
+%% GroupsAndTestCases = [{group,GroupName} | TestCase]
+%% GroupName = atom()
+%% TestCase = atom()
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+all() ->
+ [ok_tc, exit_tc, to_tc, autoskip_tc, userskip_tc].
+
+%%--------------------------------------------------------------------
+%% @spec TestCase(Config0) ->
+%% ok | exit() | {skip,Reason} | {comment,Comment} |
+%% {save_config,Config1} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% Comment = term()
+%% @end
+%%--------------------------------------------------------------------
+ok_tc(_) ->
+ ok.
+
+exit_tc(_) ->
+ exit(kaboom),
+ ok.
+
+to_tc(_) ->
+ ct:timetrap(1),
+ ct:sleep(100),
+ ok.
+
+autoskip_tc(_) ->
+ ok.
+
+userskip_tc(_) ->
+ ok.
+
+
+
+
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t22_SUITE.erl b/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t22_SUITE.erl
new file mode 100644
index 0000000000..a92018ec70
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t22_SUITE.erl
@@ -0,0 +1,177 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(t22_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% @spec suite() -> Info
+%% Info = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+suite() ->
+ [{require,file},
+ {require,tcname},
+ {timetrap,{seconds,30}}].
+
+%%--------------------------------------------------------------------
+%% @spec init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ %% verify that expected config file can be read
+ case {ct:get_config(tcname),ct:get_config(file,undefined,[all])} of
+ {start_separate,[cfg21]} -> ok;
+ {start_join,[cfg11,cfg21]} -> ok;
+ {incl_separate1,[cfg12]} -> ok;
+ {incl_separate1,[cfg21]} -> ok;
+ {incl_separate2,[cfg12]} -> ok;
+ {incl_separate2,[cfg21]} -> ok;
+ {incl_join1,[cfg21,cfg11]} -> ok;
+ {incl_join1,[cfg12,cfg11,cfg21]} -> ok;
+ {incl_join2,[cfg21,cfg11,cfg12]} -> ok;
+ {incl_both1,[cfg21]} -> ok;
+ {incl_both1,[cfg12,cfg21]} -> ok;
+ {incl_both2,[cfg11,cfg12,cfg21]} -> ok;
+ {incl_both2,[cfg21]} -> ok;
+ _ -> ok
+ end,
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_suite(Config0) -> void() | {save_config,Config1}
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_group(GroupName, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_group(GroupName, Config0) ->
+%% void() | {save_config,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_testcase(autoskip_tc, Config) ->
+ exit(kaboom),
+ Config;
+
+init_per_testcase(userskip_tc, Config) ->
+ {skip,"user skipped"};
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1} | {fail,Reason}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec groups() -> [Group]
+%% Group = {GroupName,Properties,GroupsAndTestCases}
+%% GroupName = atom()
+%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
+%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
+%% TestCase = atom()
+%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
+%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
+%% repeat_until_any_ok | repeat_until_any_fail
+%% N = integer() | forever
+%% @end
+%%--------------------------------------------------------------------
+groups() ->
+ [].
+
+%%--------------------------------------------------------------------
+%% @spec all() -> GroupsAndTestCases | {skip,Reason}
+%% GroupsAndTestCases = [{group,GroupName} | TestCase]
+%% GroupName = atom()
+%% TestCase = atom()
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+all() ->
+ [ok_tc, exit_tc, to_tc, autoskip_tc, userskip_tc].
+
+%%--------------------------------------------------------------------
+%% @spec TestCase(Config0) ->
+%% ok | exit() | {skip,Reason} | {comment,Comment} |
+%% {save_config,Config1} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% Comment = term()
+%% @end
+%%--------------------------------------------------------------------
+ok_tc(_) ->
+ ok.
+
+exit_tc(_) ->
+ exit(kaboom),
+ ok.
+
+to_tc(_) ->
+ ct:timetrap(1),
+ ct:sleep(100),
+ ok.
+
+autoskip_tc(_) ->
+ ok.
+
+userskip_tc(_) ->
+ ok.
+
+
+
+
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t23_SUITE.erl b/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t23_SUITE.erl
new file mode 100644
index 0000000000..d01fac3144
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t23_SUITE.erl
@@ -0,0 +1,158 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(t23_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% @spec suite() -> Info
+%% Info = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+suite() ->
+ [{timetrap,{seconds,30}}].
+
+%%--------------------------------------------------------------------
+%% @spec init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_suite(Config0) -> void() | {save_config,Config1}
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_group(GroupName, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_group(GroupName, Config0) ->
+%% void() | {save_config,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_testcase(autoskip_tc, Config) ->
+ exit(kaboom),
+ Config;
+
+init_per_testcase(userskip_tc, Config) ->
+ {skip,"user skipped"};
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1} | {fail,Reason}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec groups() -> [Group]
+%% Group = {GroupName,Properties,GroupsAndTestCases}
+%% GroupName = atom()
+%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
+%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
+%% TestCase = atom()
+%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
+%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
+%% repeat_until_any_ok | repeat_until_any_fail
+%% N = integer() | forever
+%% @end
+%%--------------------------------------------------------------------
+groups() ->
+ [].
+
+%%--------------------------------------------------------------------
+%% @spec all() -> GroupsAndTestCases | {skip,Reason}
+%% GroupsAndTestCases = [{group,GroupName} | TestCase]
+%% GroupName = atom()
+%% TestCase = atom()
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+all() ->
+ [ok_tc, exit_tc, to_tc, autoskip_tc, userskip_tc].
+
+%%--------------------------------------------------------------------
+%% @spec TestCase(Config0) ->
+%% ok | exit() | {skip,Reason} | {comment,Comment} |
+%% {save_config,Config1} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% Comment = term()
+%% @end
+%%--------------------------------------------------------------------
+ok_tc(_) ->
+ ok.
+
+exit_tc(_) ->
+ exit(kaboom),
+ ok.
+
+to_tc(_) ->
+ ct:timetrap(1),
+ ct:sleep(100),
+ ok.
+
+autoskip_tc(_) ->
+ ok.
+
+userskip_tc(_) ->
+ ok.
+
+
+
+