diff options
Diffstat (limited to 'lib/common_test')
-rw-r--r-- | lib/common_test/doc/src/ct_slave.xml | 139 | ||||
-rw-r--r-- | lib/common_test/src/ct_config.erl | 38 | ||||
-rw-r--r-- | lib/common_test/src/ct_logs.erl | 19 | ||||
-rw-r--r-- | lib/common_test/src/ct_run.erl | 45 | ||||
-rw-r--r-- | lib/common_test/src/ct_slave.erl | 58 | ||||
-rw-r--r-- | lib/common_test/test/Makefile | 4 | ||||
-rw-r--r-- | lib/common_test/test/ct_config_SUITE.erl | 29 | ||||
-rw-r--r-- | lib/common_test/test/ct_master_SUITE.erl | 2 | ||||
-rw-r--r-- | lib/common_test/test/ct_repeat_1_SUITE.erl | 1537 | ||||
-rw-r--r-- | lib/common_test/test/ct_repeat_1_SUITE_data/repeat_1_SUITE.erl | 373 | ||||
-rw-r--r-- | lib/common_test/test/ct_sequence_1_SUITE.erl | 300 | ||||
-rw-r--r-- | lib/common_test/test/ct_sequence_1_SUITE_data/subgroups_1_SUITE.erl | 108 |
12 files changed, 2576 insertions, 76 deletions
diff --git a/lib/common_test/doc/src/ct_slave.xml b/lib/common_test/doc/src/ct_slave.xml new file mode 100644 index 0000000000..ceebf51f1a --- /dev/null +++ b/lib/common_test/doc/src/ct_slave.xml @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> +<erlref> +<header> +<title>ct_slave</title> +<prepared></prepared> +<responsible></responsible> +<docno>1</docno> +<approved></approved> +<checked></checked> +<date></date> +<rev>A</rev> +<file>ct_slave.xml</file></header> +<module>ct_slave</module> +<modulesummary>Common Test Framework functions for starting and stopping nodes for +Large Scale Testing.</modulesummary> +<description> +<p>Common Test Framework functions for starting and stopping nodes for +Large Scale Testing.</p> + + <p>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 + <c>{init, node_start}</c> term of the Test Specification.</p></description> +<funcs> +<func> +<name>start(Node) -> Result</name> +<fsummary>Starts an Erlang node with name Node on the local host.</fsummary> +<type> +<v>Node = atom()</v><v>Result = {ok, NodeName} | {error, already_started, NodeName} | {error, started_not_connected, NodeName} | {error, boot_timeout, NodeName} | {error, init_timeout, NodeName} | {error, startup_timeout, NodeName} | {error, not_alive, NodeName}</v><v>NodeName = atom()</v></type> +<desc><marker id="start-1"/> + +<p>Starts an Erlang node with name <c>Node</c> on the local host.</p> +<p><em>See also:</em> <seealso marker="#start-3">start/3</seealso>.</p> +</desc></func> +<func> +<name>start(Host, Node) -> Result</name> +<fsummary>Starts an Erlang node with name Node on host + Host with the default options.</fsummary> +<type> +<v>Node = atom()</v><v>Host = atom()</v><v>Result = {ok, NodeName} | {error, already_started, NodeName} | {error, started_not_connected, NodeName} | {error, boot_timeout, NodeName} | {error, init_timeout, NodeName} | {error, startup_timeout, NodeName} | {error, not_alive, NodeName}</v><v>NodeName = atom()</v></type> +<desc><marker id="start-2"/> + +<p>Starts an Erlang node with name <c>Node</c> on host + <c>Host</c> with the default options.</p> +<p><em>See also:</em> <seealso marker="#start-3">start/3</seealso>.</p> +</desc></func> +<func> +<name>start(Host, Node, Options::Opts) -> Result</name> +<fsummary>Starts an Erlang node with name Node on host + Host as specified by the combination of options in + Opts.</fsummary> +<type> +<v>Node = atom()</v><v>Host = atom()</v><v>Opts = [OptTuples]</v><v>OptTuples = {username, Username} | {password, Password} | {boot_timeout, BootTimeout} | {init_timeout, InitTimeout} | {startup_timeout, StartupTimeout} | {startup_functions, StartupFunctions} | {monitor_master, Monitor} | {kill_if_fail, KillIfFail} | {erl_flags, ErlangFlags}</v><v>Username = string()</v><v>Password = string()</v><v>BootTimeout = integer()</v><v>InitTimeout = integer()</v><v>StartupTimeout = integer()</v><v>StartupFunctions = [StartupFunctionSpec]</v><v>StartupFunctionSpec = {Module, Function, Arguments}</v><v>Module = atom()</v><v>Function = atom()</v><v>Arguments = [term]</v><v>Monitor = bool()</v><v>KillIfFail = bool()</v><v>ErlangFlags = string()</v><v>Result = {ok, NodeName} | {error, already_started, NodeName} | {error, started_not_connected, NodeName} | {error, boot_timeout, NodeName} | {error, init_timeout, NodeName} | {error, startup_timeout, NodeName} | {error, not_alive, NodeName}</v><v>NodeName = atom()</v></type> +<desc><marker id="start-3"/> + +<p>Starts an Erlang node with name <c>Node</c> on host + <c>Host</c> as specified by the combination of options in + <c>Opts</c>.</p> + + <p>Options <c>Username</c> and <c>Password</c> will be used + to log in onto the remote host <c>Host</c>. + Username, if omitted, defaults to the current user name, + and password is empty by default.</p> + + <p>A list of functions specified in the <c>Startup</c> option will be + executed after startup of the node. Note that all used modules should be + present in the code path on the <c>Host</c>.</p> + + <p>The timeouts are applied as follows: + <list> + <item> + <c>BootTimeout</c> - time to start the Erlang node, in seconds. + Defaults to 3 seconds. If node does not become pingable within this time, + the result <c>{error, boot_timeout, NodeName}</c> is returned; + </item> + <item> + <c>InitTimeout</c> - time to wait for the node until it calls the + internal callback function informing master about successfull startup. + Defaults to one second. + In case of timed out message the result + <c>{error, init_timeout, NodeName}</c> is returned; + </item> + <item> + <c>StartupTimeout</c> - time to wait intil the node finishes to run + the <c>StartupFunctions</c>. Defaults to one second. + If this timeout occurs, the result + <c>{error, startup_timeout, NodeName}</c> is returned. + </item> + </list></p> + + <p>Option <c>monitor_master</c> specifies, if the slave node should be + stopped in case of master node stop. Defaults to false.</p> + + <p>Option <c>kill_if_fail</c> specifies, if the slave node should be + killed in case of a timeout during initialization or startup. + Defaults to true. Note that node also may be still alive it the boot + timeout occurred, but it will not be killed in this case.</p> + + <p>Option <c>erlang_flags</c> specifies, which flags will be added + to the parameters of the <c>erl</c> executable.</p> + + <p>Special return values are: + <list> + <item><c>{error, already_started, NodeName}</c> - if the node with + the given name is already started on a given host;</item> + <item><c>{error, started_not_connected, NodeName}</c> - if node is + started, but not connected to the master node.</item> + <item><c>{error, not_alive, NodeName}</c> - if node on which the + <c>ct_slave:start/3</c> is called, is not alive. Note that + <c>NodeName</c> is the name of current node in this case.</item> + </list></p> + +</desc></func> +<func> +<name>stop(Node) -> Result</name> +<fsummary>Stops the running Erlang node with name Node on + the localhost.</fsummary> +<type> +<v>Node = atom()</v><v>Result = {ok, NodeName} | {error, not_started, NodeName} | {error, not_connected, NodeName} | {error, stop_timeout, NodeName}</v><v>NodeName = atom()</v></type> +<desc><marker id="stop-1"/> + +<p>Stops the running Erlang node with name <c>Node</c> on + the localhost.</p> +</desc></func> +<func> +<name>stop(Host, Node) -> Result</name> +<fsummary>Stops the running Erlang node with name Node on + host Host.</fsummary> +<type> +<v>Host = atom()</v><v>Node = atom()</v><v>Result = {ok, NodeName} | {error, not_started, NodeName} | {error, not_connected, NodeName} | {error, stop_timeout, NodeName}</v><v>NodeName = atom()</v></type> +<desc><marker id="stop-2"/> + +<p>Stops the running Erlang node with name <c>Node</c> on + host <c>Host</c>.</p> +</desc></func></funcs> + +<authors> +<aname> </aname> +<email> </email></authors></erlref>
\ No newline at end of file diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl index dc6fcc66e5..6b75937668 100644 --- a/lib/common_test/src/ct_config.erl +++ b/lib/common_test/src/ct_config.erl @@ -48,7 +48,7 @@ -export([get_ref_from_name/1, get_name_from_ref/1, get_key_from_name/1]). --export([check_config_files/1, prepare_config_list/1]). +-export([check_config_files/1, add_default_callback/1, prepare_config_list/1]). -export([add_config/2, remove_config/2]). @@ -212,6 +212,24 @@ get_config_file_list(Opts) -> process_user_configs(Opts, []), CfgFiles. +add_default_callback(Opts) -> + case lists:keytake(config, 1, Opts) of + {value, {config, [File | _] = Files}, NoConfigOpts} + when is_integer(File) =/= true -> + [{config, lists:flatmap(fun add_def_cb/1, Files)} | NoConfigOpts]; + {value, {config, File}, NoConfigOpts} -> + [{config, add_def_cb(File)} | NoConfigOpts]; + false -> + Opts + end. + +add_def_cb([]) -> + []; +add_def_cb(Config) when is_tuple(Config) -> + [Config]; +add_def_cb([H|_T] = Config ) when is_integer(H) -> + [{?ct_config_txt, [Config]}]. + read_config_files(Opts) -> AddCallback = fun(CallBack, []) -> [{CallBack, []}]; @@ -220,16 +238,16 @@ read_config_files(Opts) -> (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) -> - AddCallback(Callback,Files) ++ Acc - end, - [], - ConfigLists); - false-> - [] - end, + {config,ConfigLists}-> + lists:foldr(fun({Callback,Files}, Acc) -> + AddCallback(Callback,Files) + ++ Acc + end,[],ConfigLists); + false-> + [] + end, read_config_files_int(ConfigFiles, fun store_config/3). read_config_files_int([{Callback, File}|Files], FunToSave) -> diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index f8ae7202e6..f8ace73cbf 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -384,11 +384,14 @@ maybe_log_timestamp() -> [{"<i>~s</i>",[log_timestamp({MS,S,US})]}]}) end. -log_timestamp(Now) -> - put(log_timestamp,Now), - {_,{H,M,S}} = calendar:now_to_local_time(Now), - lists:flatten(io_lib:format("~2.2.0w:~2.2.0w:~2.2.0w", - [H,M,S])). +log_timestamp({MS,S,US}) -> + put(log_timestamp, {MS,S,US}), + {{Year,Month,Day}, {Hour,Min,Sec}} = + calendar:now_to_local_time({MS,S,US}), + MilliSec = trunc(US/1000), + lists:flatten(io_lib:format("~4.10.0B-~2.10.0B-~2.10.0B " + "~2.10.0B:~2.10.0B:~2.10.0B.~3.10.0B", + [Year,Month,Day,Hour,Min,Sec,MilliSec])). %%%----------------------------------------------------------------- %%% The logger server @@ -461,9 +464,11 @@ logger_loop(State) -> {'EXIT',_Reason} -> Fd = State#logger_state.ct_log_fd, io:format(Fd, - "Logging fails! Str: ~p, Args: ~p~n", + "Logging fails! " + "Str: ~p, Args: ~p~n", [Str,Args]), - %% stop the testcase, we need to see the fault + %% stop the testcase, we need + %% to see the fault exit(Pid,logging_failed), ok; IoStr when IoList == [] -> diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index c5bfd01642..586b3893f1 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -550,6 +550,9 @@ install(Opts) -> install(Opts, "."). install(Opts, LogDir) -> + + ConfOpts = ct_config:add_default_callback(Opts), + case application:get_env(common_test, decrypt) of {ok,_} -> ok; @@ -566,7 +569,7 @@ install(Opts, LogDir) -> VarFile = variables_file_name(LogDir), case file:open(VarFile, [write]) of {ok,Fd} -> - [io:format(Fd, "~p.\n", [Opt]) || Opt <- Opts], + [io:format(Fd, "~p.\n", [Opt]) || Opt <- ConfOpts ], file:close(Fd), ok; {error,Reason} -> @@ -739,11 +742,12 @@ run_test1(StartOpts) -> %% 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) + case lists:keysearch(prepared_tests, 1, StartOpts) of + {value,{_,{Run,Skip},Specs}} -> % use prepared tests + run_prepared(Run, Skip, Opts#opts{testspecs = Specs}, + StartOpts); + false -> + run_dir(Opts, StartOpts) end; Specs -> Relaxed = get_start_opt(allow_user_terms, value, false, StartOpts), @@ -879,8 +883,10 @@ run_dir(Opts = #opts{logdir = LogDir, 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, StartOpts, [])) ++ - listify(proplists:get_value(testcase, StartOpts, [])) of + case groups_and_cases(proplists:get_value(group, StartOpts), + proplists:get_value(testcase, StartOpts)) of + Error = {error,_} -> + exit(Error); [] -> reformat_result(catch do_run(tests(Dir, listify(Mod)), [], Opts1, StartOpts)); @@ -900,8 +906,10 @@ run_dir(Opts = #opts{logdir = LogDir, Mod = if is_atom(Suite) -> Suite; true -> list_to_atom(Suite) end, - case listify(proplists:get_value(group, StartOpts, [])) ++ - listify(proplists:get_value(testcase, StartOpts, [])) of + case groups_and_cases(proplists:get_value(group, StartOpts), + proplists:get_value(testcase, StartOpts)) of + Error = {error,_} -> + exit(Error); [] -> reformat_result(catch do_run(tests(Dir, listify(Mod)), [], Opts1, StartOpts)); @@ -1087,11 +1095,13 @@ 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]; + [ensure_atom(C) || C <- listify(Cs)]; groups_and_cases(Gs, Cs) when Cs == undefined ; Cs == [] -> - [{list_to_atom(G),all} || G <- Gs]; + [{ensure_atom(G),all} || G <- listify(Gs)]; +groups_and_cases(G, Cs) when is_atom(G) -> + [{G,[ensure_atom(C) || C <- listify(Cs)]}]; groups_and_cases([G], Cs) -> - [{list_to_atom(G),[list_to_atom(C) || C <- Cs]}]; + [{ensure_atom(G),[ensure_atom(C) || C <- listify(Cs)]}]; groups_and_cases([_,_|_] , Cs) when Cs =/= [] -> {error,multiple_groups_and_cases}; groups_and_cases(_Gs, _Cs) -> @@ -1377,17 +1387,8 @@ suite_tuples([]) -> []. final_tests(Tests, Skip, Bad) -> - - %%! --- Thu Jun 24 15:47:27 2010 --- peppe was here! - %%! io:format(user, "FINAL0 = ~p~nSKIP0 = ~p~n", [Tests, Skip]), - {Tests1,Skip1} = final_tests1(Tests, [], Skip, Bad), Skip2 = final_skip(Skip1, []), - - - %%! --- Thu Jun 24 15:47:27 2010 --- peppe was here! - %%! io:format(user, "FINAL1 = ~p~nSKIP1 = ~p~n", [Tests1, Skip2]), - {Tests1,Skip2}. final_tests1([{TestDir,Suites,_}|Tests], Final, Skip, Bad) when diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl index d2a491e079..aa3413fa89 100644 --- a/lib/common_test/src/ct_slave.erl +++ b/lib/common_test/src/ct_slave.erl @@ -52,7 +52,7 @@ %%% NodeName = atom() %%% @doc Starts an Erlang node with name <code>Node</code> on the local host. %%% @see start/3 -start(Node)-> +start(Node) -> start(gethostname(), Node). %%%----------------------------------------------------------------- @@ -70,7 +70,7 @@ start(Node)-> %%% @doc Starts an Erlang node with name <code>Node</code> on host %%% <code>Host</code> with the default options. %%% @see start/3 -start(Host, Node)-> +start(Host, Node) -> start(Host, Node, []). %%%----------------------------------------------------------------- @@ -163,7 +163,7 @@ start(Host, Node)-> %%% <code>NodeName</code> is the name of current node in this case.</item> %%% </list></p> %%% -start(Host, Node, Options)-> +start(Host, Node, Options) -> ENode = enodename(Host, Node), case erlang:is_alive() of false-> @@ -189,7 +189,7 @@ start(Host, Node, Options)-> %%% NodeName = atom() %%% @doc Stops the running Erlang node with name <code>Node</code> on %%% the localhost. -stop(Node)-> +stop(Node) -> stop(gethostname(), Node). %%% @spec stop(Host, Node) -> Result @@ -202,7 +202,7 @@ stop(Node)-> %%% NodeName = atom() %%% @doc Stops the running Erlang node with name <code>Node</code> on %%% host <code>Host</code>. -stop(Host, Node)-> +stop(Host, Node) -> ENode = enodename(Host, Node), case is_started(ENode) of {true, connected}-> @@ -214,7 +214,7 @@ stop(Host, Node)-> end. %%% fetch an option value from the tagged tuple list with default -get_option_value(Key, OptionList, Default)-> +get_option_value(Key, OptionList, Default) -> case lists:keyfind(Key, 1, OptionList) of false-> Default; @@ -223,7 +223,7 @@ get_option_value(Key, OptionList, Default)-> end. %%% convert option list to the option record, fill all defaults -fetch_options(Options)-> +fetch_options(Options) -> UserName = get_option_value(username, Options, []), Password = get_option_value(password, Options, []), BootTimeout = get_option_value(boot_timeout, Options, 3), @@ -240,23 +240,23 @@ fetch_options(Options)-> % send a message when slave node is started % @hidden -slave_started(ENode, MasterPid)-> +slave_started(ENode, MasterPid) -> MasterPid ! {node_started, ENode}, ok. % send a message when slave node has finished startup % @hidden -slave_ready(ENode, MasterPid)-> +slave_ready(ENode, MasterPid) -> MasterPid ! {node_ready, ENode}, ok. % start monitoring of the master node % @hidden -monitor_master(MasterNode)-> - spawn(fun()->monitor_master_int(MasterNode) end). +monitor_master(MasterNode) -> + spawn(fun() -> monitor_master_int(MasterNode) end). % code of the masterdeath-waiter process -monitor_master_int(MasterNode)-> +monitor_master_int(MasterNode) -> erlang:monitor_node(MasterNode, true), receive {nodedown, MasterNode}-> @@ -264,11 +264,11 @@ monitor_master_int(MasterNode)-> end. % check if node is listed in the nodes() -is_connected(ENode)-> +is_connected(ENode) -> [N||N<-nodes(), N==ENode] == [ENode]. % check if node is alive (ping and disconnect if pingable) -is_started(ENode)-> +is_started(ENode) -> case is_connected(ENode) of true-> {true, connected}; @@ -283,11 +283,11 @@ is_started(ENode)-> end. % make a Erlang node name from name and hostname -enodename(Host, Node)-> +enodename(Host, Node) -> list_to_atom(atom_to_list(Node)++"@"++atom_to_list(Host)). % performs actual start of the "slave" node -do_start(Host, Node, Options)-> +do_start(Host, Node, Options) -> ENode = enodename(Host, Node), Functions = lists:concat([[{ct_slave, slave_started, [ENode, self()]}], @@ -338,7 +338,7 @@ do_start(Host, Node, Options)-> Result. % are we using fully qualified hostnames -long_or_short()-> +long_or_short() -> case net_kernel:longnames() of true-> " -name "; @@ -347,7 +347,7 @@ long_or_short()-> end. % get the localhost's name, depending on the using name policy -gethostname()-> +gethostname() -> Hostname = case net_kernel:longnames() of true-> net_adm:localhost(); @@ -358,19 +358,19 @@ gethostname()-> list_to_atom(Hostname). % get cmd for starting Erlang -get_cmd(Node, Flags)-> +get_cmd(Node, Flags) -> Cookie = erlang:get_cookie(), "erl -detached -noinput -setcookie "++ atom_to_list(Cookie) ++ long_or_short() ++ atom_to_list(Node) ++ " " ++ Flags. % spawn node locally -spawn_local_node(Node, Options)-> +spawn_local_node(Node, Options) -> ErlFlags = Options#options.erl_flags, Cmd = get_cmd(Node, ErlFlags), open_port({spawn, Cmd}, [stream]). % start crypto and ssh if not yet started -check_for_ssh_running()-> +check_for_ssh_running() -> case application:get_application(crypto) of undefined-> application:start(crypto), @@ -385,7 +385,7 @@ check_for_ssh_running()-> end. % spawn node remotely -spawn_remote_node(Host, Node, Options)-> +spawn_remote_node(Host, Node, Options) -> Username = Options#options.username, Password = Options#options.password, ErlFlags = Options#options.erl_flags, @@ -403,16 +403,16 @@ spawn_remote_node(Host, Node, Options)-> ssh_connection:exec(SSHConnRef, SSHChannelId, get_cmd(Node, ErlFlags), infinity). % call functions on a remote Erlang node -call_functions(_Node, [])-> +call_functions(_Node, []) -> ok; -call_functions(Node, [{M, F, A}|Functions])-> +call_functions(Node, [{M, F, A}|Functions]) -> rpc:call(Node, M, F, A), call_functions(Node, Functions). % wait N seconds until node is pingable -wait_for_node_alive(_Node, 0)-> +wait_for_node_alive(_Node, 0) -> pang; -wait_for_node_alive(Node, N)-> +wait_for_node_alive(Node, N) -> timer:sleep(1000), case net_adm:ping(Node) of pong-> @@ -422,14 +422,14 @@ wait_for_node_alive(Node, N)-> end. % call init:stop on a remote node -do_stop(ENode)-> +do_stop(ENode) -> spawn(ENode, init, stop, []), wait_for_node_dead(ENode, 5). % wait N seconds until node is disconnected -wait_for_node_dead(Node, 0)-> +wait_for_node_dead(Node, 0) -> {error, stop_timeout, Node}; -wait_for_node_dead(Node, N)-> +wait_for_node_dead(Node, N) -> timer:sleep(1000), case lists:member(Node, nodes()) of true-> diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile index 3fb0d627a0..f2fe3390cf 100644 --- a/lib/common_test/test/Makefile +++ b/lib/common_test/test/Makefile @@ -32,6 +32,8 @@ MODULES= \ ct_event_handler_SUITE \ ct_groups_test_1_SUITE \ ct_groups_test_2_SUITE \ + ct_sequence_1_SUITE \ + ct_repeat_1_SUITE \ ct_testspec_1_SUITE \ ct_skip_SUITE \ ct_error_SUITE \ @@ -92,7 +94,7 @@ release_spec: opt release_tests_spec: $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(ERL_FILES) $(COVERFILE) $(RELSYSDIR) - $(INSTALL_PROGRAM) common_test.spec $(RELSYSDIR) + $(INSTALL_DATA) common_test.spec $(RELSYSDIR) chmod -f -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) diff --git a/lib/common_test/test/ct_config_SUITE.erl b/lib/common_test/test/ct_config_SUITE.erl index 72ff781f82..fc15abc5bc 100644 --- a/lib/common_test/test/ct_config_SUITE.erl +++ b/lib/common_test/test/ct_config_SUITE.erl @@ -58,6 +58,9 @@ end_per_suite(Config) -> init_per_testcase(TestCase, Config) -> ct_test_support:init_per_testcase(TestCase, Config). +end_per_testcase(install_config = TestCase, Config) -> + ok = rpc:call(proplists:get_value(ct_node, Config), ct_config, stop, []), + ct_test_support:end_per_testcase(TestCase, Config); end_per_testcase(TestCase, Config) -> ct_test_support:end_per_testcase(TestCase, Config). @@ -66,12 +69,13 @@ all(doc) -> all(suite) -> [ - require, - userconfig_static, - userconfig_dynamic, - testspec_legacy, - testspec_static, - testspec_dynamic + require, + install_config, + userconfig_static, + userconfig_dynamic, + testspec_legacy, + testspec_static, + testspec_dynamic ]. %%-------------------------------------------------------------------- @@ -84,6 +88,17 @@ require(Config) when is_list(Config) -> {config, filename:join(DataDir, "config/config.txt")}, ["config_static_SUITE"]). +install_config(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + CTNode = proplists:get_value(ct_node, Config), + rpc:call(CTNode, ct, install, + [[{config, [filename:join(DataDir, "config/config.txt")]}]]), + case rpc:call(CTNode, ct_config, start, [interactive]) of + Pid when is_pid(Pid) -> + ok + end. + + userconfig_static(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), run_test(config_static_SUITE, @@ -135,6 +150,8 @@ testspec_dynamic(Config) when is_list(Config) -> []), file:delete(filename:join(ConfigDir, "spec_dynamic.spec")). + + %%%----------------------------------------------------------------- %%% HELP FUNCTIONS %%%----------------------------------------------------------------- diff --git a/lib/common_test/test/ct_master_SUITE.erl b/lib/common_test/test/ct_master_SUITE.erl index 87e2c3049a..e0e1f93db2 100644 --- a/lib/common_test/test/ct_master_SUITE.erl +++ b/lib/common_test/test/ct_master_SUITE.erl @@ -101,7 +101,7 @@ make_spec(DataDir, FileName, NodeNames, Suites, Config)-> NS = lists:map(fun(NodeName)-> {init, NodeName, [ - {node_start, [{startup_functions, []}, {monitor_master, false}]}, + {node_start, [{startup_functions, []}, {monitor_master, true}]}, {eval, {erlang, nodes, []}} ] } diff --git a/lib/common_test/test/ct_repeat_1_SUITE.erl b/lib/common_test/test/ct_repeat_1_SUITE.erl new file mode 100644 index 0000000000..1b4cafc9d3 --- /dev/null +++ b/lib/common_test/test/ct_repeat_1_SUITE.erl @@ -0,0 +1,1537 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%%------------------------------------------------------------------- +%%% File: ct_repeat_1_SUITE.erl +%%% +%%% Description: +%%% Test some simple test case group scenarios with repeat. +%%% +%%% The suites used for the test are located in the data directory. +%%%------------------------------------------------------------------- +-module(ct_repeat_1_SUITE). + +-compile(export_all). + +-include_lib("test_server/include/test_server.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) -> + Config1 = ct_test_support:init_per_suite(Config), + 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). + +all(doc) -> + []; + +all(suite) -> + [repeat_cs, + repeat_cs_and_grs, + repeat_seq, + repeat_cs_until_any_ok, + repeat_gr_until_any_ok, + repeat_cs_until_any_fail, + repeat_gr_until_any_fail, + repeat_cs_until_all_ok, + repeat_gr_until_all_ok, + repeat_cs_until_all_fail, + repeat_gr_until_all_fail, + repeat_seq_until_any_fail, + repeat_shuffled_seq_until_any_fail + ]. + +%%-------------------------------------------------------------------- +%% TEST CASES +%%-------------------------------------------------------------------- + +repeat_cs(Config) when is_list(Config) -> + execute(repeat_cs, + "repeat_1_SUITE", repeat_cs, + Config). +%%%------------------------------------------------------------------- +repeat_cs_and_grs(Config) when is_list(Config) -> + execute(repeat_cs_and_grs, + "repeat_1_SUITE", repeat_cs_and_grs, + Config). +%%%------------------------------------------------------------------- +repeat_seq(Config) when is_list(Config) -> + execute(repeat_seq, + "repeat_1_SUITE", repeat_seq, + Config). +%%%------------------------------------------------------------------- +repeat_cs_until_any_ok(Config) when is_list(Config) -> + execute(repeat_cs_until_any_ok, + "repeat_1_SUITE", repeat_cs_until_any_ok, + Config). +%%%------------------------------------------------------------------- +repeat_gr_until_any_ok(Config) when is_list(Config) -> + execute(repeat_gr_until_any_ok, + "repeat_1_SUITE", repeat_gr_until_any_ok, + Config). +%%%------------------------------------------------------------------- +repeat_cs_until_any_fail(Config) when is_list(Config) -> + execute(repeat_cs_until_any_fail, + "repeat_1_SUITE", repeat_cs_until_any_fail, + Config). +%%%------------------------------------------------------------------- +repeat_gr_until_any_fail(Config) when is_list(Config) -> + execute(repeat_gr_until_any_fail, + "repeat_1_SUITE", repeat_gr_until_any_fail, + Config). +%%%------------------------------------------------------------------- +repeat_cs_until_all_ok(Config) when is_list(Config) -> + execute(repeat_cs_until_all_ok, + "repeat_1_SUITE", repeat_cs_until_all_ok, + Config). +%%%------------------------------------------------------------------- +repeat_gr_until_all_ok(Config) when is_list(Config) -> + execute(repeat_gr_until_all_ok, + "repeat_1_SUITE", repeat_gr_until_all_ok, + Config). +%%%------------------------------------------------------------------- +repeat_cs_until_all_fail(Config) when is_list(Config) -> + execute(repeat_cs_until_all_fail, + "repeat_1_SUITE", repeat_cs_until_all_fail, + Config). +%%%------------------------------------------------------------------- +repeat_gr_until_all_fail(Config) when is_list(Config) -> + execute(repeat_gr_until_all_fail, + "repeat_1_SUITE", repeat_gr_until_all_fail, + Config). +%%%------------------------------------------------------------------- +repeat_seq_until_any_fail(Config) when is_list(Config) -> + execute(repeat_seq_until_any_fail, + "repeat_1_SUITE", repeat_seq_until_any_fail, + Config). +%%%------------------------------------------------------------------- +repeat_shuffled_seq_until_any_fail(Config) when is_list(Config) -> + execute(repeat_shuffled_seq_until_any_fail, + "repeat_1_SUITE", repeat_shuffled_seq_until_any_fail, + Config). + +%%%----------------------------------------------------------------- +%%% HELP FUNCTIONS +%%%----------------------------------------------------------------- +execute(TestCase, SuiteName, Group, Config) -> + DataDir = ?config(data_dir, Config), + Suite = filename:join(DataDir, SuiteName), + + {Opts,ERPid} = setup([{suite,Suite},{group,Group},{label,TestCase}], Config), + ok = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(TestCase, + reformat(Events, ?eh), + ?config(priv_dir, Config)), + + TestEvents = events_to_check(TestCase), + ok = ct_test_support:verify_events(TestEvents, Events, Config). + +setup(Test, Config) -> + Opts0 = ct_test_support:get_opts(Config), + Level = ?config(trace_level, Config), + EvHArgs = [{cbm,ct_test_support},{trace_level,Level}], + Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}} | Test], + ERPid = ct_test_support:start_event_receiver(Config), + {Opts,ERPid}. + +reformat(Events, 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(repeat_cs) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,repeat_cs,[]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,repeat_cs_1,[]},ok}}, + {?eh,test_stats,{2,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,repeat_cs_1,[]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,repeat_cs_2,[{repeat,2}]},ok}}, + {?eh,test_stats,{4,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,repeat_cs_2,[{repeat,2}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,repeat_cs_2,[]},ok}}, + {?eh,test_stats,{6,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,repeat_cs_2,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,repeat_cs,[]},ok}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +test_events(repeat_cs_and_grs) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,repeat_cs_and_grs,[{repeat,2}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE,tc_fail_1,{failed,{error,{{badmatch,2},'_'}}}}}, + {?eh,test_stats,{1,1,{0,0}}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_fail_result,[]},ok}}, + {?eh,test_stats,{2,1,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,test_stats,{3,1,{0,0}}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_fail_init,[]}, + {failed,{error,fails_on_purpose}}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',fails_on_purpose}}}}}, + {?eh,test_stats,{3,1,{0,1}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',fails_on_purpose}}}}}], + {?eh,test_stats,{4,1,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,repeat_cs_and_grs,[{repeat,2}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,repeat_cs_and_grs,[]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,test_stats,{5,1,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE,tc_fail_1,{failed,{error,{{badmatch,2},'_'}}}}}, + {?eh,test_stats,{5,2,{0,1}}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_fail_result,[]},ok}}, + {?eh,test_stats,{6,2,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,test_stats,{7,2,{0,1}}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_fail_init,[]}, + {failed,{error,fails_on_purpose}}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',fails_on_purpose}}}}}, + {?eh,test_stats,{7,2,{0,2}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',fails_on_purpose}}}}}], + {?eh,test_stats,{8,2,{0,2}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,repeat_cs_and_grs,[]},ok}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]; + +test_events(repeat_seq) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,start_info,{1,1,unknown}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,repeat_seq,[]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_1,[sequence,{repeat,2}]}, + ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,test_stats,{1,1,{0,0}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_2, + {failed,{repeat_1_SUITE,tc_fail_1}}}}, + {?eh,test_stats,{1,1,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_1,[sequence,{repeat,2}]}, + ok}}], + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,repeat_seq_1, + [sequence]},ok}}, + {?eh,test_stats,{2,2,{0,2}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,repeat_seq_1, + [sequence]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_2,[sequence,{repeat,2}]}, + ok}}, + {?eh,test_stats,{3,2,{0,2}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_result,[]},ok}}, + {?eh,test_stats,{4,2,{0,2}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_2, + {group_result,gr_fail_result,failed}}}, + {?eh,test_stats,{4,2,{0,3}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_2,[sequence,{repeat,2}]}, + ok}}], + [{?eh,tc_done, + {repeat_1_SUITE,{init_per_group,repeat_seq_2,[sequence]},ok}}, + {?eh,test_stats,{6,2,{0,4}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,repeat_seq_2, + [sequence]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_3,[sequence,{repeat,2}]}, + ok}}, + {?eh,test_stats,{7,2,{0,4}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_init,[]}, + {failed,{error,fails_on_purpose}}}}, + {?eh,test_stats,{7,2,{0,5}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed, + {repeat_1_SUITE,init_per_group, + {'EXIT',fails_on_purpose}}}}}], + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_2, + {group_result,gr_fail_init,failed}}}, + {?eh,test_stats,{7,2,{0,6}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_3,[sequence,{repeat,2}]}, + ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_3,[sequence]},ok}}, + {?eh,test_stats,{8,2,{0,8}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_3,[sequence]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_4,[sequence,{repeat,2}]}, + ok}}, + {?eh,test_stats,{8,3,{0,8}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE, + tc_ok_1,{failed,{repeat_1_SUITE,tc_fail_1}}}}, + {?eh,test_stats,{8,3,{0,9}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE, + tc_ok_1,{failed,{repeat_1_SUITE,tc_fail_1}}}}, + {?eh,test_stats,{8,3,{0,10}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_4,[sequence,{repeat,2}]}, + ok}}], + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,repeat_seq_4,[sequence]},ok}}, + {?eh,test_stats,{8,4,{0,12}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_4,[sequence]},ok}}], + + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,repeat_seq,[]},ok}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +test_events(repeat_cs_until_any_ok) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_any_ok,[]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_any_ok_1, + [{repeat_until_any_ok,3}]},ok}}, + {?eh,test_stats,{0,2,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{0,3,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_any_ok_1, + [{repeat_until_any_ok,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_any_ok_1, + [{repeat_until_any_ok,2}]},ok}}, + {?eh,test_stats,{0,5,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_1,ok}}, + {?eh,test_stats,{1,5,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_any_ok_1, + [{repeat_until_any_ok,2}]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_any_ok_2, + [{repeat_until_any_ok,3}]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{2,5,{0,0}}}, + {?eh,test_stats,{2,6,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_any_ok_2, + [{repeat_until_any_ok,3}]},ok}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_any_ok,[]},ok}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +test_events(repeat_gr_until_any_ok) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + [{?eh,tc_done, + {repeat_1_SUITE,{init_per_group,repeat_gr_until_any_ok,[]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_ok_1, + [{repeat_until_any_ok,3}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_result,[]},ok}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,tc_done,{repeat_1_SUITE,tc_fail_1, + {failed,{error,{{badmatch,2},'_'}}}}}, + {?eh,test_stats,{1,1,{0,0}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_init,[]}, + {failed,{error,fails_on_purpose}}}}, + {?eh,test_stats,{1,1,{0,1}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',fails_on_purpose}}}}}], + {?eh,test_stats,{1,2,{0,1}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_result_then_ok,[]},ok}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_fail_result_then_ok,[]}, + {return_group_result,failed}}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_ok_1, + [{repeat_until_any_ok,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_ok_1, + [{repeat_until_any_ok,2}]},ok}}, + %% ... + {?eh,test_stats,{3,4,{0,2}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_result_then_ok,[]},ok}}, + {?eh,test_stats,{4,4,{0,2}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_fail_result_then_ok,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_ok_1, + [{repeat_until_any_ok,2}]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_ok_2, + [{repeat_until_any_ok,3}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,tc_done,{repeat_1_SUITE,tc_fail_1, + {failed,{error,{{badmatch,2},'_'}}}}}, + {?eh,test_stats,{5,5,{0,2}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{5,6,{0,2}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_init,[]}, + {failed,{error,fails_on_purpose}}}}, + {?eh,test_stats,{5,6,{0,3}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',fails_on_purpose}}}}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_ok_2, + [{repeat_until_any_ok,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_ok_2, + [{repeat_until_any_ok,2}]},ok}}, + {?eh,test_stats,{6,7,{0,3}}}, + {?eh,tc_start,{repeat_1_SUITE,tc_fail_then_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_1,ok}}, + {?eh,test_stats,{7,7,{0,3}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_init,[]}, + {failed,{error,fails_on_purpose}}}}, + {?eh,test_stats,{7,7,{0,4}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',fails_on_purpose}}}}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_ok_2, + [{repeat_until_any_ok,2}]},ok}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_ok,[]},ok}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +test_events(repeat_cs_until_any_fail) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + {?eh,tc_start,{repeat_1_SUITE,init_per_suite}}, + {?eh,tc_done,{repeat_1_SUITE,init_per_suite,ok}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,repeat_cs_until_any_fail,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,repeat_cs_until_any_fail,[]},ok}}, + [{?eh,tc_start, + {repeat_1_SUITE, + {init_per_group,repeat_cs_until_any_fail_1, + [{repeat_until_any_fail,3}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {init_per_group,repeat_cs_until_any_fail_1, + [{repeat_until_any_fail,3}]}, + ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_2}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + {?eh,test_stats,{2,0,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_then_fail_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1,ok}}, + {?eh,test_stats,{3,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE, + {end_per_group,repeat_cs_until_any_fail_1, + [{repeat_until_any_fail,3}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {end_per_group,repeat_cs_until_any_fail_1, + [{repeat_until_any_fail,3}]}, + ok}}], + [{?eh,tc_start, + {repeat_1_SUITE, + {init_per_group,repeat_cs_until_any_fail_1, + [{repeat_until_any_fail,2}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {init_per_group,repeat_cs_until_any_fail_1, + [{repeat_until_any_fail,2}]}, + ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{4,0,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_2}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + {?eh,test_stats,{5,0,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_then_fail_1}}, + {?eh,tc_done, + {repeat_1_SUITE,tc_ok_then_fail_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{5,1,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE, + {end_per_group,repeat_cs_until_any_fail_1, + [{repeat_until_any_fail,2}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {end_per_group,repeat_cs_until_any_fail_1, + [{repeat_until_any_fail,2}]}, + ok}}], + [{?eh,tc_start, + {repeat_1_SUITE, + {init_per_group,repeat_cs_until_any_fail_2, + [{repeat_until_any_fail,3}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {init_per_group,repeat_cs_until_any_fail_2, + [{repeat_until_any_fail,3}]}, + ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_fail_1}}, + {?eh,tc_done, + {repeat_1_SUITE,tc_fail_1, + {failed, + {error, + {{badmatch,2}, + [{repeat_1_SUITE,tc_fail_1,1}, + {repeat_1_SUITE,tc_fail_1,1}, + {test_server,my_apply,3}, + {test_server,ts_tc,3}, + {test_server,run_test_case_eval1,6}, + {test_server,run_test_case_eval,8}]}}}}}, + {?eh,test_stats,{5,2,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE,tc_fail_2}}, + {?eh,tc_done, + {repeat_1_SUITE,tc_fail_2,{failed,{error,exit_on_purpose}}}}, + {?eh,test_stats,{5,3,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE, + {end_per_group,repeat_cs_until_any_fail_2, + [{repeat_until_any_fail,3}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {end_per_group,repeat_cs_until_any_fail_2, + [{repeat_until_any_fail,3}]}, + ok}}], + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,repeat_cs_until_any_fail,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{end_per_group,repeat_cs_until_any_fail,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,end_per_suite}}, + {?eh,tc_done,{repeat_1_SUITE,end_per_suite,ok}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +test_events(repeat_gr_until_any_fail) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + {?eh,tc_start,{repeat_1_SUITE,init_per_suite}}, + {?eh,tc_done,{repeat_1_SUITE,init_per_suite,ok}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,repeat_gr_until_any_fail,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,repeat_gr_until_any_fail,[]},ok}}, + [{?eh,tc_start, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_1, + [{repeat_until_any_fail,3}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_1, + [{repeat_until_any_fail,3}]}, + ok}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{2,0,{0,0}}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,gr_ok_then_fail_result,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,gr_ok_then_fail_result,[]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{3,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,gr_ok_then_fail_result,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{end_per_group,gr_ok_then_fail_result,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,tc_ok_2}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + {?eh,test_stats,{4,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_1, + [{repeat_until_any_fail,3}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_1, + [{repeat_until_any_fail,3}]}, + ok}}], + [{?eh,tc_start, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_1, + [{repeat_until_any_fail,2}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_1, + [{repeat_until_any_fail,2}]}, + ok}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{5,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{6,0,{0,0}}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,gr_ok_then_fail_result,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,gr_ok_then_fail_result,[]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{7,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,gr_ok_then_fail_result,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {end_per_group,gr_ok_then_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,tc_start,{repeat_1_SUITE,tc_ok_2}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + {?eh,test_stats,{8,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_1, + [{repeat_until_any_fail,2}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_1, + [{repeat_until_any_fail,2}]}, + ok}}], + [{?eh,tc_start, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_2, + [{repeat_until_any_fail,3}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_2, + [{repeat_until_any_fail,3}]}, + ok}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{9,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{10,0,{0,0}}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,gr_ok_then_fail_init,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,gr_ok_then_fail_init,[]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{11,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,gr_ok_then_fail_init,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{end_per_group,gr_ok_then_fail_init,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,tc_ok_2}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + {?eh,test_stats,{12,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_2, + [{repeat_until_any_fail,3}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_2, + [{repeat_until_any_fail,3}]}, + ok}}], + [{?eh,tc_start, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_2, + [{repeat_until_any_fail,2}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_2, + [{repeat_until_any_fail,2}]}, + ok}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{13,0,{0,0}}}, + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{14,0,{0,0}}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,gr_ok_then_fail_init,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {init_per_group,gr_ok_then_fail_init,[]}, + {failed,{error,failing_this_time}}}}, + {?eh,tc_auto_skip, + {repeat_1_SUITE,tc_ok_1, + {failed, + {repeat_1_SUITE,init_per_group, + {'EXIT',failing_this_time}}}}}, + {?eh,test_stats,{14,0,{0,1}}}, + {?eh,tc_auto_skip, + {repeat_1_SUITE,end_per_group, + {failed, + {repeat_1_SUITE,init_per_group, + {'EXIT',failing_this_time}}}}}], + {?eh,tc_start,{repeat_1_SUITE,tc_ok_2}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + {?eh,test_stats,{15,0,{0,1}}}, + {?eh,tc_start, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_2, + [{repeat_until_any_fail,2}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_2, + [{repeat_until_any_fail,2}]}, + ok}}], + [{?eh,tc_start, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_3, + [{repeat_until_any_fail,3}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_3, + [{repeat_until_any_fail,3}]}, + ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_then_fail_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1,ok}}, + {?eh,test_stats,{16,0,{0,1}}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{17,0,{0,1}}}, + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{18,0,{0,1}}}, + {?eh,tc_start, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_3, + [{repeat_until_any_fail,3}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_3, + [{repeat_until_any_fail,3}]}, + ok}}], + [{?eh,tc_start, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_3, + [{repeat_until_any_fail,2}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {init_per_group,repeat_gr_until_any_fail_3, + [{repeat_until_any_fail,2}]}, + ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_then_fail_1}}, + {?eh,tc_done, + {repeat_1_SUITE,tc_ok_then_fail_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{18,1,{0,1}}}, + [{?eh,tc_start, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{19,1,{0,1}}}, + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{20,1,{0,1}}}, + {?eh,tc_start, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_3, + [{repeat_until_any_fail,2}]}}}, + {?eh,tc_done, + {repeat_1_SUITE, + {end_per_group,repeat_gr_until_any_fail_3, + [{repeat_until_any_fail,2}]}, + ok}}], + {?eh,tc_start, + {repeat_1_SUITE,{end_per_group,repeat_gr_until_any_fail,[]}}}, + {?eh,tc_done, + {repeat_1_SUITE,{end_per_group,repeat_gr_until_any_fail,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,end_per_suite}}, + {?eh,tc_done,{repeat_1_SUITE,end_per_suite,ok}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +test_events(repeat_cs_until_all_ok) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,repeat_cs_until_all_ok,[]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_all_ok_1, + [{repeat_until_all_ok,3}]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{0,1,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{1,1,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_2, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{1,2,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_all_ok_1, + [{repeat_until_all_ok,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_all_ok_1, + [{repeat_until_all_ok,2}]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_1,ok}}, + {?eh,test_stats,{2,2,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{3,2,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_2,ok}}, + {?eh,test_stats,{4,2,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_all_ok_1, + [{repeat_until_all_ok,2}]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_all_ok_2, + [{repeat_until_all_ok,3}]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + {?eh,test_stats,{6,2,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_all_ok_2, + [{repeat_until_all_ok,3}]},ok}}], + + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_all_ok,[]},ok}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +test_events(repeat_gr_until_all_ok) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_ok,[]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_ok_1, + [{repeat_until_all_ok,3}]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{2,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{2,1,{0,0}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_result_then_ok,[]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{3,1,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_fail_result_then_ok,[]}, + {return_group_result,failed}}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_ok_1, + [{repeat_until_all_ok,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_ok_1, + [{repeat_until_all_ok,2}]},ok}}, + {?eh,test_stats,{5,1,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_1,ok}}, + {?eh,test_stats,{6,1,{0,0}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_result_then_ok,[]},ok}}, + {?eh,test_stats,{7,1,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_fail_result_then_ok,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_ok_1, + [{repeat_until_all_ok,2}]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_ok_2, + [{repeat_until_all_ok,3}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_init_then_ok,[]}, + {failed,{error,failing_this_time}}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',failing_this_time}}}}}, + {?eh,test_stats,{7,1,{0,1}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',failing_this_time}}}}}], + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{8,1,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_ok_2, + [{repeat_until_all_ok,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_ok_2, + [{repeat_until_all_ok,2}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_init_then_ok,[]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{9,1,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_fail_init_then_ok,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{10,1,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_ok_2, + [{repeat_until_all_ok,2}]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_ok_3, + [{repeat_until_all_ok,3}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{11,1,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{11,2,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_ok_3, + [{repeat_until_all_ok,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_ok_3, + [{repeat_until_all_ok,2}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_ok_1,[]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{12,2,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE,tc_fail_then_ok_1,ok}}, + {?eh,test_stats,{13,2,{0,1}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_ok_3, + [{repeat_until_all_ok,2}]},ok}}], + + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_ok,[]},ok}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +test_events(repeat_cs_until_all_fail) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_all_fail,[]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_all_fail_1, + [{repeat_until_all_fail,3}]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE,tc_fail_1}}, + {?eh,test_stats,{1,1,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_2,ok}}, + {?eh,test_stats,{2,1,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_all_fail_1, + [{repeat_until_all_fail,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_all_fail_1, + [{repeat_until_all_fail,2}]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{2,2,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE,tc_fail_1}}, + {?eh,test_stats,{2,3,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_2, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{2,4,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_all_fail_1, + [{repeat_until_all_fail,2}]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_cs_until_all_fail_2, + [{repeat_until_all_fail,3}]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_fail_1}}, + {?eh,test_stats,{2,5,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_all_fail_2, + [{repeat_until_all_fail,3}]},ok}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_cs_until_all_fail,[]},ok}}], + + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +test_events(repeat_gr_until_all_fail) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_fail,[]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_fail_1, + [{repeat_until_all_fail,3}]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_fail_1}}, + {?eh,test_stats,{0,1,{0,0}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_init,[]}, + {failed,{error,fails_on_purpose}}}}, + {?eh,test_stats,{0,1,{0,1}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',fails_on_purpose}}}}}], + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1,ok}}, + {?eh,test_stats,{1,1,{0,1}}}, + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group, + gr_ok_then_fail_result,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_fail_1, + [{repeat_until_all_fail,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_fail_1, + [{repeat_until_all_fail,2}]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_fail_1}}, + {?eh,test_stats,{2,2,{0,1}}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_fail_init,[]}, + {failed,{error,fails_on_purpose}}}}, + {?eh,test_stats,{2,2,{0,2}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',fails_on_purpose}}}}}], + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{2,3,{0,2}}}, + [{?eh,tc_done,{repeat_1_SUITE,{init_per_group, + gr_ok_then_fail_result,[]},ok}}, + {?eh,test_stats,{3,3,{0,2}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_ok_then_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_fail_1, + [{repeat_until_all_fail,2}]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_fail_2, + [{repeat_until_all_fail,3}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_then_fail_init,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE,tc_fail_1}}, + {?eh,test_stats,{4,4,{0,2}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_fail_2, + [{repeat_until_all_fail,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_fail_2, + [{repeat_until_all_fail,2}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_ok_then_fail_init,[]}, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{4,4,{0,3}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',failing_this_time}}}}}], + {?eh,tc_start,{repeat_1_SUITE,tc_fail_1}}, + {?eh,test_stats,{4,5,{0,3}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_fail_2, + [{repeat_until_all_fail,2}]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_fail_3, + [{repeat_until_all_fail,3}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1,ok}}, + {?eh,test_stats,{6,5,{0,3}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_fail_3, + [{repeat_until_all_fail,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_gr_until_all_fail_3, + [{repeat_until_all_fail,2}]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{7,6,{0,3}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_fail_3, + [{repeat_until_all_fail,2}]},ok}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_gr_until_all_fail,[]},ok}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +test_events(repeat_seq_until_any_fail) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_until_any_fail,[]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_until_any_fail_1, + [sequence,{repeat_until_any_fail,2}]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + {?eh,test_stats,{2,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_until_any_fail_1, + [sequence,{repeat_until_any_fail,2}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group, + repeat_seq_until_any_fail_1,[sequence]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + {?eh,test_stats,{4,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group, + repeat_seq_until_any_fail_1,[sequence]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_until_any_fail_2, + [{repeat_until_any_fail,2},sequence]},ok}}, + {?eh,test_stats,{5,0,{0,0}}}, + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,test_stats,{7,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_until_any_fail_2, + [{repeat_until_any_fail,2},sequence]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_until_any_fail_2,[sequence]}, + ok}}, + {?eh,test_stats,{8,0,{0,0}}}, + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,test_stats,{10,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_until_any_fail_2,[sequence]}, + ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_until_any_fail_3, + [sequence,{repeat_until_any_fail,3}]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{11,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1,ok}}, + {?eh,test_stats,{12,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + {?eh,test_stats,{13,0,{0,0}}}, + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_until_any_fail_3, + [sequence,{repeat_until_any_fail,3}]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_until_any_fail_3, + [{repeat_until_any_fail,2},sequence]},ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{15,0,{0,0}}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{15,1,{0,0}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_2, + {failed,{repeat_1_SUITE,tc_ok_then_fail_1}}}}, + {?eh,test_stats,{15,1,{0,1}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {failed,{repeat_1_SUITE,tc_ok_then_fail_1}}}}, + {?eh,test_stats,{15,1,{0,2}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_until_any_fail_3, + [{repeat_until_any_fail,2},sequence]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_until_any_fail_4, + [{repeat_until_any_fail,3},sequence]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group, + gr_ok_then_fail_result,[]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{18,1,{0,2}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_until_any_fail_4, + [{repeat_until_any_fail,3},sequence]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_until_any_fail_4, + [{repeat_until_any_fail,2},sequence]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_ok_then_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {group_result,gr_ok_then_fail_result,failed}}}, + {?eh,test_stats,{19,1,{0,3}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {group_result,gr_ok_then_fail_result,failed}}}, + {?eh,test_stats,{19,1,{0,4}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_until_any_fail_4, + [{repeat_until_any_fail,2},sequence]},ok}}], + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_until_any_fail_5, + [{repeat_until_any_fail,3},sequence]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_then_fail_init,[]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_2,[]},ok}}], + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,test_stats,{23,1,{0,4}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_until_any_fail_5, + [{repeat_until_any_fail,3},sequence]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_seq_until_any_fail_5, + [{repeat_until_any_fail,2},sequence]},ok}}, + [{?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,gr_ok_then_fail_init,[]}, + {failed,{error,failing_this_time}}}}, + {?eh,test_stats,{24,1,{0,5}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',failing_this_time}}}}}], + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {group_result,gr_ok_then_fail_init,failed}}}, + {?eh,test_stats,{24,1,{0,6}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {group_result,gr_ok_then_fail_init,failed}}}, + {?eh,test_stats,{24,1,{0,7}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_until_any_fail_5, + [{repeat_until_any_fail,2},sequence]},ok}}], + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_seq_until_any_fail,[]},ok}}], + + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]; + +%%! Note that when testing shuffled groups, ct_test_support expects +%%! both the start and done event for cases and init/end_per_group +test_events(repeat_shuffled_seq_until_any_fail) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,unknown}}, + + [{?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail,[]}, + ok}}, + + {shuffle, + [{?eh,tc_start,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_1, + [{shuffle,'_'},sequence, + {repeat_until_any_fail,2}]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_1, + [{shuffle,'_'},sequence, + {repeat_until_any_fail,2}]},ok}}, + {?eh,test_stats,{2,0,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_1, + [sequence,shuffle,{repeat_until_any_fail,2}]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_1, + [sequence,shuffle,{repeat_until_any_fail,2}]},ok}}]}, + {shuffle, + [{?eh,tc_start,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_1, + [{shuffle,'_'},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_1, + [{shuffle,'_'},sequence]},ok}}, + {?eh,test_stats,{4,0,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_1, + [{shuffle,repeated},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_1, + [{shuffle,repeated},sequence]},ok}}]}, + + {shuffle, + [{?eh,tc_start,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_2, + [{shuffle,{1,2,3}},{repeat_until_any_fail,2},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_2, + [{shuffle,{1,2,3}},{repeat_until_any_fail,2},sequence]}, + ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_2}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + [{?eh,tc_start,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,test_stats,{7,0,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_2, + [{repeat_until_any_fail,2},{shuffle,{1,2,3}},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_2, + [{repeat_until_any_fail,2},{shuffle,{1,2,3}},sequence]}, + ok}}]}, + {shuffle, + [{?eh,tc_start,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_2, + [{shuffle,'_'},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_2, + [{shuffle,'_'},sequence]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_2}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + [{?eh,tc_start,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_2, + [{shuffle,repeated},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_2, + [{shuffle,repeated},sequence]},ok}}]}, + + {shuffle, + [{?eh,tc_start,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_3, + [{shuffle,'_'},sequence, + {repeat_until_any_fail,3}]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_3, + [{shuffle,'_'},sequence, + {repeat_until_any_fail,3}]},ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_then_fail_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1,ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_2}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_2,ok}}, + [{?eh,tc_start,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + {?eh,test_stats,{14,0,{0,0}}}, + {?eh,tc_start,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_3, + [shuffle,sequence,{repeat_until_any_fail,3}]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_3, + [shuffle,sequence,{repeat_until_any_fail,3}]},ok}}]}, + {shuffle, + [{?eh,tc_start,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_3, + [{shuffle,'_'},{repeat_until_any_fail,2},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_3, + [{shuffle,'_'},{repeat_until_any_fail,2},sequence]}, + ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_then_fail_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1, + {failed,{error,failing_this_time}}}}, + {?eh,tc_start,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_3, + [{shuffle,repeated},{repeat_until_any_fail,2},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_3, + [{shuffle,repeated},{repeat_until_any_fail,2},sequence]}, + ok}}]}, + + {shuffle, + [{?eh,tc_start,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_4, + [{shuffle,{1,2,3}},{repeat_until_any_fail,3},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_4, + [{shuffle,{1,2,3}},{repeat_until_any_fail,3},sequence]}, + ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + [{?eh,tc_start,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + [{?eh,tc_start,{repeat_1_SUITE,{end_per_group, + gr_ok_then_fail_result,[]}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group, + gr_ok_then_fail_result,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_4, + [{repeat_until_any_fail,3},sequence,{shuffle,{1,2,3}}]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_4, + [{repeat_until_any_fail,3},sequence,{shuffle,{1,2,3}}]}, + ok}}]}, + {shuffle, + [{?eh,tc_start,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_4, + [{shuffle,'_'},{repeat_until_any_fail,2},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_4, + [{shuffle,'_'},{repeat_until_any_fail,2},sequence]}, + ok}}, + [{?eh,tc_start,{repeat_1_SUITE, + {end_per_group,gr_ok_then_fail_result,[]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,gr_ok_then_fail_result,[]}, + {return_group_result,failed}}}], + {?eh,tc_start,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_4, + [{shuffle,repeated},{repeat_until_any_fail,2},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_4, + [{shuffle,repeated},{repeat_until_any_fail,2},sequence]}, + ok}}]}, + + {shuffle, + [{?eh,tc_start,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_5, + [{shuffle,{1,2,3}},{repeat_until_any_fail,3},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_5, + [{shuffle,{1,2,3}},{repeat_until_any_fail,3},sequence]}, + ok}}, + {?eh,tc_start,{repeat_1_SUITE,tc_ok_1}}, + {?eh,tc_done,{repeat_1_SUITE,tc_ok_1,ok}}, + [{?eh,tc_start,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_1,[]},ok}}], + [{?eh,tc_start,{repeat_1_SUITE,{end_per_group,gr_ok_2,[]}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group,gr_ok_2,[]},ok}}], + [{?eh,tc_start,{repeat_1_SUITE,{end_per_group, + gr_ok_then_fail_init,[]}}}, + {?eh,tc_done,{repeat_1_SUITE,{end_per_group, + gr_ok_then_fail_init,[]},ok}}], + {?eh,tc_start,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_5, + [{repeat_until_any_fail,3},sequence,{shuffle,{1,2,3}}]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_5, + [{repeat_until_any_fail,3},sequence,{shuffle,{1,2,3}}]}, + ok}}]}, + {shuffle, + [{?eh,tc_start,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_5, + [{shuffle,'_'},{repeat_until_any_fail,2}, + sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {init_per_group,repeat_shuffled_seq_until_any_fail_5, + [{shuffle,'_'},{repeat_until_any_fail,2}, + sequence]},ok}}, + [{?eh,tc_auto_skip,{repeat_1_SUITE,end_per_group, + {failed,{repeat_1_SUITE,init_per_group, + {'EXIT',failing_this_time}}}}}], + {?eh,tc_start,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_5, + [{shuffle,repeated},{repeat_until_any_fail,2},sequence]}}}, + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail_5, + [{shuffle,repeated},{repeat_until_any_fail,2},sequence]}, + ok}}]}, + + {?eh,tc_done,{repeat_1_SUITE, + {end_per_group,repeat_shuffled_seq_until_any_fail,[]}, + ok}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]. diff --git a/lib/common_test/test/ct_repeat_1_SUITE_data/repeat_1_SUITE.erl b/lib/common_test/test/ct_repeat_1_SUITE_data/repeat_1_SUITE.erl new file mode 100644 index 0000000000..fb8d31edd4 --- /dev/null +++ b/lib/common_test/test/ct_repeat_1_SUITE_data/repeat_1_SUITE.erl @@ -0,0 +1,373 @@ +%%%------------------------------------------------------------------- +%%% @author Peter Andersson <[email protected]> +%%% @copyright (C) 2010, Peter Andersson +%%% @doc +%%% +%%% @end +%%% Created : 11 Aug 2010 by Peter Andersson <[email protected]> +%%%------------------------------------------------------------------- +-module(repeat_1_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) -> + spawn(fun() -> db() end), + Config. +%%-------------------------------------------------------------------- +%% @spec end_per_suite(Config0) -> void() | {save_config,Config1} +%% Config0 = Config1 = [tuple()] +%% @end +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + db(stop, ok), + ok. + +db() -> + register(?MODULE, self()), + db_loop([]). + +db_loop(Dict) -> + receive + {insert,From,Key,Val} -> + From ! {?MODULE,ok}, + db_loop([{Key,Val} | proplists:delete(Key, Dict)]); + {lookup,From,Key} -> + From ! {?MODULE,proplists:get_value(Key, Dict)}, + db_loop(Dict); + {delete,From,Key} -> + From ! {?MODULE,ok}, + db_loop(proplists:delete(Key, Dict)); + {stop,From,_} -> + From ! {?MODULE,ok} + end. + + db(Op, Key, Val) -> + ?MODULE ! {Op,self(),Key,Val}, + receive {?MODULE,Result} -> Result end. + + db(Op, Key) -> + ?MODULE ! {Op,self(),Key}, + receive {?MODULE,Result} -> Result end. + +%%-------------------------------------------------------------------- +%% @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(G, Config) when G == gr_ok_1 ; G == gr_ok_2 ; + G == gr_fail_result; + G == gr_ok_then_fail_result -> + ct:comment(G), + Config; + +init_per_group(G, _Config) when G == gr_fail_init -> + ct:comment(G), + exit(fails_on_purpose); + +init_per_group(G, Config) when G == gr_ok_then_fail_init -> + ct:comment(G), + do_2nd_time(G, + fun() -> exit(failing_this_time) end, + fun() -> Config end); + +init_per_group(G, Config) when G == gr_fail_init_then_ok -> + ct:comment(G), + do_2nd_time(G, + fun() -> Config end, + fun() -> exit(failing_this_time) end); + +init_per_group(G, Config) -> + ct:comment(G), + Config. + +%%-------------------------------------------------------------------- +%% @spec end_per_group(GroupName, Config0) -> +%% void() | {save_config,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%% @end +%%-------------------------------------------------------------------- +end_per_group(G, _Config) when G == gr_fail_result -> + ct:comment(G), + {return_group_result,failed}; + +end_per_group(G, _Config) when G == gr_ok_then_fail_result -> + ct:comment(G), + do_2nd_time(G, + fun() -> {return_group_result,failed} end, + fun() -> ok end); + +end_per_group(G, _Config) when G == gr_fail_result_then_ok -> + ct:comment(G), + do_2nd_time(G, + fun() -> ok end, + fun() -> {return_group_result,failed} end); + +end_per_group(G, _Config) -> + ct:comment(G), + 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(_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() -> + [ + %%--------------------------------------------------------------- + {repeat_cs, [], [{group,repeat_cs_0}, + {group,repeat_cs_1}, + {group,repeat_cs_2}]}, + {repeat_cs_0, [{repeat,0}], [tc_ok_1,tc_ok_2]}, + {repeat_cs_1, [{repeat,1}], [tc_ok_1,tc_ok_2]}, + {repeat_cs_2, [{repeat,2}], [tc_ok_1,tc_ok_2]}, + + {repeat_cs_and_grs, [{repeat,2}], [{group,gr_ok_1},tc_fail_1, + {group,gr_fail_result},tc_ok_1, + {group,gr_fail_init},tc_ok_2]}, + + %%--------------------------------------------------------------- + {repeat_seq, [], [{group,repeat_seq_1}, + {group,repeat_seq_2}, + {group,repeat_seq_3}, + {group,repeat_seq_4}]}, + {repeat_seq_1, [sequence,{repeat,2}], [tc_ok_1,tc_fail_1,tc_ok_2]}, + {repeat_seq_2, [sequence,{repeat,2}], [tc_ok_1,{group,gr_fail_result},tc_ok_2]}, + {repeat_seq_3, [sequence,{repeat,2}], [tc_ok_1,{group,gr_fail_init},tc_ok_2]}, + {repeat_seq_4, [sequence,{repeat,2}], [tc_fail_1,{group,gr_ok_1},tc_ok_1]}, + + %%--------------------------------------------------------------- + {repeat_cs_until_any_ok, [], [{group,repeat_cs_until_any_ok_1}, + {group,repeat_cs_until_any_ok_2}]}, + {repeat_cs_until_any_ok_1, [{repeat_until_any_ok,3}], [tc_fail_1, + tc_fail_2, + tc_fail_then_ok_1]}, + {repeat_cs_until_any_ok_2, [{repeat_until_any_ok,3}], [tc_ok_1,tc_fail_1]}, + + %%--------------------------------------------------------------- + {repeat_gr_until_any_ok, [], [{group,repeat_gr_until_any_ok_1}, + {group,repeat_gr_until_any_ok_2}]}, + {repeat_gr_until_any_ok_1, [{repeat_until_any_ok,3}], + [{group,gr_fail_result}, tc_fail_1, {group,gr_fail_init}, tc_fail_2, + {group,gr_fail_result_then_ok}]}, + {repeat_gr_until_any_ok_2, [{repeat_until_any_ok,3}], + [{group,gr_fail_result}, tc_fail_1, tc_fail_then_ok_1, + {group,gr_fail_init}]}, + + %%--------------------------------------------------------------- + {repeat_cs_until_any_fail, [], [{group,repeat_cs_until_any_fail_1}, + {group,repeat_cs_until_any_fail_2}]}, + {repeat_cs_until_any_fail_1, [{repeat_until_any_fail,3}], [tc_ok_1, + tc_ok_2, + tc_ok_then_fail_1]}, + {repeat_cs_until_any_fail_2, [{repeat_until_any_fail,3}], [tc_fail_1,tc_fail_2]}, + + %%--------------------------------------------------------------- + {repeat_gr_until_any_fail, [], [{group,repeat_gr_until_any_fail_1}, + {group,repeat_gr_until_any_fail_2}, + {group,repeat_gr_until_any_fail_3}]}, + {repeat_gr_until_any_fail_1, [{repeat_until_any_fail,3}], + [{group,gr_ok_1}, tc_ok_1, {group,gr_ok_then_fail_result}, tc_ok_2]}, + {repeat_gr_until_any_fail_2, [{repeat_until_any_fail,3}], + [{group,gr_ok_1}, tc_ok_1, {group,gr_ok_then_fail_init}, tc_ok_2]}, + {repeat_gr_until_any_fail_3, [{repeat_until_any_fail,3}], [tc_ok_then_fail_1, + {group,gr_ok_1}, + tc_ok_1]}, + + %%--------------------------------------------------------------- + {repeat_cs_until_all_ok, [], [{group,repeat_cs_until_all_ok_1}, + {group,repeat_cs_until_all_ok_2}]}, + {repeat_cs_until_all_ok_1, [{repeat_until_all_ok,3}], [tc_fail_then_ok_1, + tc_ok_1, + tc_fail_then_ok_2]}, + {repeat_cs_until_all_ok_2, [{repeat_until_all_ok,3}], [tc_ok_1,tc_ok_2]}, + + %%--------------------------------------------------------------- + {repeat_gr_until_all_ok, [], [{group,repeat_gr_until_all_ok_1}, + {group,repeat_gr_until_all_ok_2}, + {group,repeat_gr_until_all_ok_3}]}, + {repeat_gr_until_all_ok_1, [{repeat_until_all_ok,3}], + [tc_ok_1, {group,gr_ok_1}, tc_fail_then_ok_1, {group,gr_fail_result_then_ok}]}, + {repeat_gr_until_all_ok_2, [{repeat_until_all_ok,3}], + [{group,gr_fail_init_then_ok}, tc_ok_1]}, + {repeat_gr_until_all_ok_3, [{repeat_until_all_ok,3}], + [{group,gr_ok_1}, tc_fail_then_ok_1]}, + + %%--------------------------------------------------------------- + {repeat_cs_until_all_fail, [], [{group,repeat_cs_until_all_fail_1}, + {group,repeat_cs_until_all_fail_2}]}, + {repeat_cs_until_all_fail_1, [{repeat_until_all_fail,3}], [tc_ok_then_fail_1, + tc_fail_1, + tc_ok_then_fail_2]}, + {repeat_cs_until_all_fail_2, [{repeat_until_all_fail,3}], [tc_fail_1]}, + + %%--------------------------------------------------------------- + {repeat_gr_until_all_fail, [], [{group,repeat_gr_until_all_fail_1}, + {group,repeat_gr_until_all_fail_2}, + {group,repeat_gr_until_all_fail_3}]}, + {repeat_gr_until_all_fail_1, [{repeat_until_all_fail,3}], + [tc_fail_1, {group,gr_fail_init}, tc_ok_then_fail_1, {group,gr_ok_then_fail_result}]}, + {repeat_gr_until_all_fail_2, [{repeat_until_all_fail,3}], + [{group,gr_ok_then_fail_init}, tc_fail_1]}, + {repeat_gr_until_all_fail_3, [{repeat_until_all_fail,3}], + [{group,gr_fail_result}, tc_ok_then_fail_1]}, + + %%--------------------------------------------------------------- + {repeat_seq_until_any_fail, [], [{group,repeat_seq_until_any_fail_1}, + {group,repeat_seq_until_any_fail_2}, + {group,repeat_seq_until_any_fail_3}, + {group,repeat_seq_until_any_fail_4}, + {group,repeat_seq_until_any_fail_5}]}, + {repeat_seq_until_any_fail_1, [sequence,{repeat_until_any_fail,2}], + [tc_ok_1, tc_ok_2]}, + {repeat_seq_until_any_fail_2, [{repeat_until_any_fail,2},sequence], + [tc_ok_1, {group,gr_ok_1}, tc_ok_2]}, + {repeat_seq_until_any_fail_3, [sequence,{repeat_until_any_fail,3}], + [tc_ok_1, tc_ok_then_fail_1, tc_ok_2, {group,gr_ok_1}]}, + {repeat_seq_until_any_fail_4, [{repeat_until_any_fail,3},sequence], + [{group,gr_ok_then_fail_result}, {group,gr_ok_1}, tc_ok_1]}, + {repeat_seq_until_any_fail_5, [{repeat_until_any_fail,3},sequence], + [{group,gr_ok_1}, {group,gr_ok_then_fail_init}, {group,gr_ok_2}, tc_ok_1]}, + + %%--------------------------------------------------------------- + {repeat_shuffled_seq_until_any_fail, [], [{group,repeat_shuffled_seq_until_any_fail_1}, + {group,repeat_shuffled_seq_until_any_fail_2}, + {group,repeat_shuffled_seq_until_any_fail_3}, + {group,repeat_shuffled_seq_until_any_fail_4}, + {group,repeat_shuffled_seq_until_any_fail_5}]}, + {repeat_shuffled_seq_until_any_fail_1, [sequence,shuffle,{repeat_until_any_fail,2}], + [tc_ok_1, tc_ok_2]}, + {repeat_shuffled_seq_until_any_fail_2, [{repeat_until_any_fail,2},{shuffle,{1,2,3}},sequence], + [tc_ok_1, {group,gr_ok_1}, tc_ok_2]}, + {repeat_shuffled_seq_until_any_fail_3, [shuffle,sequence,{repeat_until_any_fail,3}], + [tc_ok_1, tc_ok_then_fail_1, tc_ok_2, {group,gr_ok_1}]}, + {repeat_shuffled_seq_until_any_fail_4, [{repeat_until_any_fail,3},sequence,{shuffle,{1,2,3}}], + [{group,gr_ok_then_fail_result}, {group,gr_ok_1}, tc_ok_1]}, + {repeat_shuffled_seq_until_any_fail_5, [{repeat_until_any_fail,3},sequence,{shuffle,{1,2,3}}], + [{group,gr_ok_1}, {group,gr_ok_then_fail_init}, {group,gr_ok_2}, tc_ok_1]}, + + %%--------------------------------------------------------------- + {gr_ok_1, [], [tc_ok_1]}, + + {gr_ok_2, [], [tc_ok_1]}, + + {gr_fail_init, [], [tc_ok_1]}, + + {gr_fail_result, [], [tc_ok_1]}, + + {gr_ok_then_fail_init, [], [tc_ok_1]}, + + {gr_ok_then_fail_result, [], [tc_ok_1]}, + + {gr_fail_result_then_ok, [], [tc_ok_1]}, + + {gr_fail_init_then_ok, [], [tc_ok_1]} + ]. + +%%-------------------------------------------------------------------- +%% @spec all() -> GroupsAndTestCases | {skip,Reason} +%% GroupsAndTestCases = [{group,GroupName} | TestCase] +%% GroupName = atom() +%% TestCase = atom() +%% Reason = term() +%% @end +%%-------------------------------------------------------------------- +all() -> + []. + +tc_ok_1(_) -> + ok. + +tc_ok_2(_) -> + ok. + +tc_fail_1(_) -> + x=2. + +tc_fail_2(_) -> + exit(exit_on_purpose). + +tc_ok_then_fail_1(_) -> + do_2nd_time(tc_ok_then_fail_1, + fun() -> exit(failing_this_time) end, + fun() -> ok end), + ok. + +tc_ok_then_fail_2(_) -> + do_2nd_time(tc_ok_then_fail_2, + fun() -> exit(failing_this_time) end, + fun() -> ok end), + ok. + +tc_fail_then_ok_1(_) -> + do_2nd_time(tc_fail_then_ok_1, + fun() -> ok end, + fun() -> exit(failing_this_time) end), + ok. + +tc_fail_then_ok_2(_) -> + do_2nd_time(tc_fail_then_ok_2, + fun() -> ok end, + fun() -> exit(failing_this_time) end), + ok. + +do_2nd_time(Case, True, False) -> + case db(lookup, Case) of + undefined -> + db(insert, Case, 1), + False(); + 1 -> + ct:log("This is the second call...", []), + db(delete, Case), + True() + end. diff --git a/lib/common_test/test/ct_sequence_1_SUITE.erl b/lib/common_test/test/ct_sequence_1_SUITE.erl new file mode 100644 index 0000000000..0cf40f106a --- /dev/null +++ b/lib/common_test/test/ct_sequence_1_SUITE.erl @@ -0,0 +1,300 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%%------------------------------------------------------------------- +%%% File: ct_sequence_1_SUITE +%%% +%%% Description: +%%% Test sequences +%%% +%%% The suites used for the test are located in the data directory. +%%%------------------------------------------------------------------- +-module(ct_sequence_1_SUITE). + +-compile(export_all). + +-include_lib("test_server/include/test_server.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) -> + Config1 = ct_test_support:init_per_suite(Config), + 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). + +all(suite) -> + [subgroup_return_fail, + subgroup_init_fail, + subgroup_after_failed_case, + case_after_subgroup_return_fail, + case_after_subgroup_fail_init]. + +%%-------------------------------------------------------------------- +%% TEST CASES +%%-------------------------------------------------------------------- + +%%%----------------------------------------------------------------- +%%% + +subgroup_return_fail(Config) when is_list(Config) -> + execute(subgroup_return_fail, + "subgroups_1_SUITE", subgroup_return_fail, + Config). + +%%%----------------------------------------------------------------- +%%% + +subgroup_init_fail(Config) when is_list(Config) -> + execute(subgroup_init_fail, + "subgroups_1_SUITE", subgroup_init_fail, + Config). + +%%%----------------------------------------------------------------- +%%% + +subgroup_after_failed_case(Config) when is_list(Config) -> + execute(subgroup_after_failed_case, + "subgroups_1_SUITE", subgroup_after_failed_case, + Config). + +%%%----------------------------------------------------------------- +%%% + +case_after_subgroup_return_fail(Config) when is_list(Config) -> + execute(case_after_subgroup_return_fail, + "subgroups_1_SUITE", case_after_subgroup_return_fail, + Config). + +%%%----------------------------------------------------------------- +%%% + +case_after_subgroup_fail_init(Config) when is_list(Config) -> + execute(case_after_subgroup_fail_init, + "subgroups_1_SUITE", case_after_subgroup_fail_init, + Config). + +%%%----------------------------------------------------------------- +%%% HELP FUNCTIONS +%%%----------------------------------------------------------------- + +execute(TestCase, SuiteName, Group, Config) -> + DataDir = ?config(data_dir, Config), + Suite = filename:join(DataDir, SuiteName), + + {Opts,ERPid} = setup([{suite,Suite},{group,Group},{label,TestCase}], Config), + ok = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(TestCase, + reformat(Events, ?eh), + ?config(priv_dir, Config)), + + TestEvents = events_to_check(TestCase), + ok = ct_test_support:verify_events(TestEvents, Events, Config). + +setup(Test, Config) -> + Opts0 = ct_test_support:get_opts(Config), + Level = ?config(trace_level, Config), + EvHArgs = [{cbm,ct_test_support},{trace_level,Level}], + Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}} | Test], + ERPid = ct_test_support:start_event_receiver(Config), + {Opts,ERPid}. + +reformat(Events, 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(subgroup_return_fail) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,2}}, + [{?eh,tc_start, + {subgroups_1_SUITE,{init_per_group,subgroup_return_fail,[sequence]}}}, + {?eh,tc_done, + {subgroups_1_SUITE,{init_per_group,subgroup_return_fail,[sequence]},ok}}, + [{?eh,tc_start, + {subgroups_1_SUITE,{init_per_group,return_fail,[]}}}, + {?eh,tc_done, + {subgroups_1_SUITE,{init_per_group,return_fail,[]},ok}}, + {?eh,tc_start,{subgroups_1_SUITE,failing_tc}}, + {?eh,tc_done, + {subgroups_1_SUITE,failing_tc,{failed,{error,{{badmatch,3},'_'}}}}}, + {?eh,test_stats,{0,1,{0,0}}}, + {?eh,tc_start, + {subgroups_1_SUITE,{end_per_group,return_fail,[]}}}, + {?eh,tc_done,{subgroups_1_SUITE,{end_per_group,return_fail,[]}, + {return_group_result,failed}}}], + {?eh,tc_auto_skip, + {subgroups_1_SUITE,ok_tc,{group_result,return_fail,failed}}}, + {?eh,test_stats,{0,1,{0,1}}}, + {?eh,tc_start, + {subgroups_1_SUITE,{end_per_group,subgroup_return_fail,[sequence]}}}, + {?eh,tc_done, + {subgroups_1_SUITE,{end_per_group,subgroup_return_fail,[sequence]}, + {return_group_result,failed}}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]; + +test_events(subgroup_init_fail) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,2}}, + [{?eh,tc_start, + {subgroups_1_SUITE,{init_per_group,subgroup_init_fail,[sequence]}}}, + {?eh,tc_done, + {subgroups_1_SUITE,{init_per_group,subgroup_init_fail,[sequence]},ok}}, + [{?eh,tc_start,{subgroups_1_SUITE,{init_per_group,fail_init,[]}}}, + {?eh,tc_done,{subgroups_1_SUITE,{init_per_group,fail_init,[]}, + {failed,{error,init_per_group_fails_on_purpose}}}}, + {?eh,tc_auto_skip,{subgroups_1_SUITE,ok_tc, + {failed,{subgroups_1_SUITE,init_per_group, + {'EXIT',init_per_group_fails_on_purpose}}}}}, + {?eh,test_stats,{0,0,{0,1}}}, + {?eh,tc_auto_skip,{subgroups_1_SUITE,end_per_group, + {failed,{subgroups_1_SUITE,init_per_group, + {'EXIT',init_per_group_fails_on_purpose}}}}}], + {?eh,tc_auto_skip,{subgroups_1_SUITE,ok_tc,{group_result,fail_init,failed}}}, + {?eh,test_stats,{0,0,{0,2}}}, + {?eh,tc_start,{subgroups_1_SUITE,{end_per_group,subgroup_init_fail,[sequence]}}}, + {?eh,tc_done,{subgroups_1_SUITE, + {end_per_group,subgroup_init_fail,[sequence]}, + {return_group_result,failed}}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]; + +test_events(subgroup_after_failed_case) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,2}}, + [{?eh,tc_start,{subgroups_1_SUITE, + {init_per_group,subgroup_after_failed_case,[sequence]}}}, + {?eh,tc_done,{subgroups_1_SUITE, + {init_per_group,subgroup_after_failed_case,[sequence]},ok}}, + {?eh,tc_start,{subgroups_1_SUITE,failing_tc}}, + {?eh,tc_done,{subgroups_1_SUITE,failing_tc,{failed,{error,{{badmatch,3},'_'}}}}}, + {?eh,test_stats,{0,1,{0,0}}}, + {?eh,tc_auto_skip,{subgroups_1_SUITE,ok_tc,{failed,{subgroups_1_SUITE,failing_tc}}}}, + {?eh,test_stats,{0,1,{0,1}}}, + {?eh,tc_start,{subgroups_1_SUITE, + {end_per_group,subgroup_after_failed_case,[sequence]}}}, + {?eh,tc_done,{subgroups_1_SUITE, + {end_per_group,subgroup_after_failed_case,[sequence]}, + {return_group_result,failed}}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} +]; + +test_events(case_after_subgroup_return_fail) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,2}}, + [{?eh,tc_start,{subgroups_1_SUITE, + {init_per_group,case_after_subgroup_return_fail,[sequence]}}}, + {?eh,tc_done,{subgroups_1_SUITE, + {init_per_group,case_after_subgroup_return_fail,[sequence]},ok}}, + [{?eh,tc_start,{subgroups_1_SUITE,{init_per_group,return_fail,[]}}}, + {?eh,tc_done,{subgroups_1_SUITE,{init_per_group,return_fail,[]},ok}}, + {?eh,tc_start,{subgroups_1_SUITE,failing_tc}}, + {?eh,tc_done,{subgroups_1_SUITE,failing_tc,{failed,{error,{{badmatch,3},'_'}}}}}, + {?eh,test_stats,{0,1,{0,0}}}, + {?eh,tc_start,{subgroups_1_SUITE,{end_per_group,return_fail,[]}}}, + {?eh,tc_done,{subgroups_1_SUITE,{end_per_group,return_fail,[]}, + {return_group_result,failed}}}], + {?eh,tc_auto_skip,{subgroups_1_SUITE,ok_tc,{group_result,return_fail,failed}}}, + {?eh,test_stats,{0,1,{0,1}}}, + {?eh,tc_start,{subgroups_1_SUITE, + {end_per_group,case_after_subgroup_return_fail,[sequence]}}}, + {?eh,tc_done,{subgroups_1_SUITE, + {end_per_group,case_after_subgroup_return_fail,[sequence]}, + {return_group_result,failed}}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]; + +test_events(case_after_subgroup_fail_init) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,2}}, + [{?eh,tc_start,{subgroups_1_SUITE, + {init_per_group,case_after_subgroup_fail_init,[sequence]}}}, + {?eh,tc_done,{subgroups_1_SUITE, + {init_per_group,case_after_subgroup_fail_init,[sequence]},ok}}, + [{?eh,tc_start,{subgroups_1_SUITE,{init_per_group,fail_init,[]}}}, + {?eh,tc_done,{subgroups_1_SUITE, + {init_per_group,fail_init,[]}, + {failed,{error,init_per_group_fails_on_purpose}}}}, + {?eh,tc_auto_skip,{subgroups_1_SUITE,ok_tc, + {failed, + {subgroups_1_SUITE,init_per_group, + {'EXIT',init_per_group_fails_on_purpose}}}}}, + {?eh,test_stats,{0,0,{0,1}}}, + {?eh,tc_auto_skip,{subgroups_1_SUITE,end_per_group, + {failed, + {subgroups_1_SUITE,init_per_group, + {'EXIT',init_per_group_fails_on_purpose}}}}}], + + {?eh,tc_auto_skip, + {subgroups_1_SUITE,ok_tc,{group_result,fail_init,failed}}}, + {?eh,test_stats,{0,0,{0,2}}}, + {?eh,tc_start,{subgroups_1_SUITE, + {end_per_group,case_after_subgroup_fail_init,[sequence]}}}, + {?eh,tc_done,{subgroups_1_SUITE, + {end_per_group,case_after_subgroup_fail_init,[sequence]}, + {return_group_result,failed}}}], + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]. diff --git a/lib/common_test/test/ct_sequence_1_SUITE_data/subgroups_1_SUITE.erl b/lib/common_test/test/ct_sequence_1_SUITE_data/subgroups_1_SUITE.erl new file mode 100644 index 0000000000..741b1165c1 --- /dev/null +++ b/lib/common_test/test/ct_sequence_1_SUITE_data/subgroups_1_SUITE.erl @@ -0,0 +1,108 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009-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(subgroups_1_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +all() -> + [{group, subgroup_return_fail}, + {group, subgroup_init_fail}, + {group, subgroup_after_failed_case}, + {group, case_after_subgroup_return_fail}, + {group, case_after_subgroup_fail_init}]. + +groups() -> + [{return_fail, [], [failing_tc]}, + {fail_init, [], [ok_tc]}, + {ok_group, [], [ok_tc]}, + + {subgroup_return_fail, [sequence], [{group, return_fail}, {group, ok_group}]}, + + {subgroup_init_fail, [sequence], [{group, fail_init}, {group, ok_group}]}, + + {subgroup_after_failed_case, [sequence], [failing_tc, {group, ok_group}]}, + + {case_after_subgroup_return_fail, [sequence], [{group, return_fail}, ok_tc]}, + + {case_after_subgroup_fail_init, [sequence], [{group, fail_init}, ok_tc]} + ]. + +failed_subgroup(subgroup_return_fail) -> return_fail; +failed_subgroup(subgroup_init_fail) -> fail_init; +failed_subgroup(case_after_subgroup_return_fail) -> return_fail; +failed_subgroup(case_after_subgroup_fail_init) -> fail_init; +failed_subgroup(_) -> undefined. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(fail_init, Config) -> + ct:comment(fail_init), + exit(init_per_group_fails_on_purpose); + +init_per_group(Group, Config) -> + ct:comment(Group), + [{Group,failed_subgroup(Group)} | Config]. + +end_per_group(subgroup_after_failed_case, Config) -> + ct:comment(subgroup_after_failed_case), + Status = ?config(tc_group_result, Config), + [{subgroups_1_SUITE,failing_tc}] = proplists:get_value(failed, Status), + {return_group_result,failed}; + +end_per_group(Group, Config) when Group == subgroup_return_fail; + Group == subgroup_init_fail; + Group == case_after_subgroup_return_fail; + Group == case_after_subgroup_fail_init -> + ct:comment(Group), + Status = ?config(tc_group_result, Config), + Failed = proplists:get_value(failed, Status), + true = lists:member({group_result,?config(Group,Config)}, Failed), + {return_group_result,failed}; + +end_per_group(return_fail, Config) -> + ct:comment(return_fail), + Status = ?config(tc_group_result, Config), + [{subgroups_1_SUITE,failing_tc}] = proplists:get_value(failed, Status), + {return_group_result,failed}; + +end_per_group(Group, _Config) -> + ct:comment(Group), + ok. + +init_per_testcase(_TestCase, Config) -> + Config. + +end_per_testcase(failing_tc, Config) -> + {failed,_} = proplists:get_value(tc_status, Config), + ok; + +end_per_testcase(_TestCase, _Config) -> + ok. + +failing_tc(_Config) -> + 2=3. + +ok_tc(_Config) -> + ok. |