diff options
Diffstat (limited to 'lib/common_test/src/ct.erl')
-rw-r--r-- | lib/common_test/src/ct.erl | 953 |
1 files changed, 18 insertions, 935 deletions
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index 4c4dc8bede..778ea2e9e2 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2017. All Rights Reserved. +%% Copyright Ericsson AB 2003-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -18,38 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc Main user interface for the Common Test framework. -%%% -%%% <p> This module implements the command line interface for running -%%% tests and some basic functions for common test case issues -%%% such as configuration and logging. </p> -%%% -%%% <p><strong>Test Suite Support Macros</strong></p> -%%% -%%% <p>The <c>config</c> macro is defined in <c>ct.hrl</c>. This -%%% macro should be used to retrieve information from the -%%% <c>Config</c> variable sent to all test cases. It is used with two -%%% arguments, where the first is the name of the configuration -%%% variable you wish to retrieve, and the second is the <c>Config</c> -%%% variable supplied to the test case.</p> -%%% -%%% <p>Possible configuration variables include:</p> -%%% <ul> -%%% <li><c>data_dir</c> - Data file directory.</li> -%%% <li><c>priv_dir</c> - Scratch file directory.</li> -%%% <li>Whatever added by <c>init_per_suite/1</c> or -%%% <c>init_per_testcase/2</c> in the test suite.</li> -%%% </ul> - -%%% @type var_name() = atom(). A variable name which is specified when -%%% <c>ct:require/2</c> is called, -%%% e.g. <c>ct:require(mynodename,{node,[telnet]})</c> -%%% -%%% @type target_name() = var_name(). The name of a target. -%%% -%%% @type handle() = ct_gen_conn:handle() | term(). The identity of a -%%% specific connection. - -module(ct). -include("ct.hrl"). @@ -87,6 +55,7 @@ decrypt_config_file/2, decrypt_config_file/3]). -export([get_target_name/1]). +-export([get_progname/0]). -export([parse_table/1, listenv/1]). -export([remaining_test_procs/0]). @@ -120,209 +89,34 @@ %%---------------------------------------------------------------------- - -%%%----------------------------------------------------------------- -%%% @spec install(Opts) -> ok | {error,Reason} -%%% Opts = [Opt] -%%% Opt = {config,ConfigFiles} | {event_handler,Modules} | -%%% {decrypt,KeyOrFile} -%%% ConfigFiles = [ConfigFile] -%%% ConfigFile = string() -%%% Modules = [atom()] -%%% KeyOrFile = {key,Key} | {file,KeyFile} -%%% Key = string() -%%% KeyFile = string() -%%% @doc Install config files and event handlers. -%%% -%%% <p>Run this function once before first test.</p> -%%% -%%% <p>Example:<br/> -%%% <c>install([{config,["config_node.ctc","config_user.ctc"]}])</c>.</p> -%%% -%%% <p>Note that this function is automatically run by the -%%% <c>ct_run</c> program.</p> install(Opts) -> ct_run:install(Opts). -%%%----------------------------------------------------------------- -%%% @spec run(TestDir,Suite,Cases) -> Result -%%% TestDir = string() -%%% Suite = atom() -%%% Cases = atom() | [atom()] -%%% Result = [TestResult] | {error,Reason} -%%% -%%% @doc Run the given test case(s). -%%% -%%% <p>Requires that <c>ct:install/1</c> has been run first.</p> -%%% -%%% <p>Suites (*_SUITE.erl) files must be stored in -%%% <c>TestDir</c> or <c>TestDir/test</c>. All suites -%%% will be compiled when test is run.</p> run(TestDir,Suite,Cases) -> ct_run:run(TestDir,Suite,Cases). -%%%----------------------------------------------------------------- -%%% @spec run(TestDir,Suite) -> Result -%%% -%%% @doc Run all test cases in the given suite. -%%% @see run/3. run(TestDir,Suite) -> ct_run:run(TestDir,Suite). -%%%----------------------------------------------------------------- -%%% @spec run(TestDirs) -> Result -%%% TestDirs = TestDir | [TestDir] -%%% -%%% @doc Run all test cases in all suites in the given directories. -%%% @see run/3. run(TestDirs) -> ct_run:run(TestDirs). -%%%----------------------------------------------------------------- -%%% @spec run_test(Opts) -> Result -%%% Opts = [OptTuples] -%%% OptTuples = {dir,TestDirs} | {suite,Suites} | {group,Groups} | -%%% {testcase,Cases} | {spec,TestSpecs} | {join_specs,Bool} | -%%% {label,Label} | {config,CfgFiles} | {userconfig, UserConfig} | -%%% {allow_user_terms,Bool} | {logdir,LogDir} | -%%% {silent_connections,Conns} | {stylesheet,CSSFile} | -%%% {cover,CoverSpecFile} | {cover_stop,Bool} | {step,StepOpts} | -%%% {event_handler,EventHandlers} | {include,InclDirs} | -%%% {auto_compile,Bool} | {abort_if_missing_suites,Bool} | -%%% {create_priv_dir,CreatePrivDir} | -%%% {multiply_timetraps,M} | {scale_timetraps,Bool} | -%%% {repeat,N} | {duration,DurTime} | {until,StopTime} | -%%% {force_stop,ForceStop} | {decrypt,DecryptKeyOrFile} | -%%% {refresh_logs,LogDir} | {logopts,LogOpts} | -%%% {verbosity,VLevels} | {basic_html,Bool} | -%%% {esc_chars,Bool} | {ct_hooks, CTHs} | -%%% {enable_builtin_hooks,Bool} | {release_shell,Bool} -%%% TestDirs = [string()] | string() -%%% Suites = [string()] | [atom()] | string() | atom() -%%% Cases = [atom()] | atom() -%%% Groups = GroupNameOrPath | [GroupNameOrPath] -%%% GroupNameOrPath = [atom()] | atom() | all -%%% TestSpecs = [string()] | string() -%%% Label = string() | atom() -%%% CfgFiles = [string()] | string() -%%% UserConfig = [{CallbackMod,CfgStrings}] | {CallbackMod,CfgStrings} -%%% CallbackMod = atom() -%%% CfgStrings = [string()] | string() -%%% LogDir = string() -%%% Conns = all | [atom()] -%%% CSSFile = string() -%%% CoverSpecFile = string() -%%% StepOpts = [StepOpt] | [] -%%% StepOpt = config | keep_inactive -%%% EventHandlers = EH | [EH] -%%% EH = atom() | {atom(),InitArgs} | {[atom()],InitArgs} -%%% InitArgs = [term()] -%%% InclDirs = [string()] | string() -%%% CreatePrivDir = auto_per_run | auto_per_tc | manual_per_tc -%%% M = integer() -%%% N = integer() -%%% DurTime = string(HHMMSS) -%%% StopTime = string(YYMoMoDDHHMMSS) | string(HHMMSS) -%%% ForceStop = skip_rest | Bool -%%% DecryptKeyOrFile = {key,DecryptKey} | {file,DecryptFile} -%%% DecryptKey = string() -%%% DecryptFile = string() -%%% LogOpts = [LogOpt] -%%% LogOpt = no_nl | no_src -%%% VLevels = VLevel | [{Category,VLevel}] -%%% VLevel = integer() -%%% Category = atom() -%%% CTHs = [CTHModule | {CTHModule, CTHInitArgs}] -%%% CTHModule = atom() -%%% CTHInitArgs = term() -%%% Result = {Ok,Failed,{UserSkipped,AutoSkipped}} | TestRunnerPid | {error,Reason} -%%% Ok = integer() -%%% Failed = integer() -%%% UserSkipped = integer() -%%% AutoSkipped = integer() -%%% TestRunnerPid = pid() -%%% Reason = term() -%%% @doc <p>Run tests as specified by the combination of options in <c>Opts</c>. -%%% The options are the same as those used with the -%%% <seealso marker="ct_run#ct_run"><c>ct_run</c></seealso> program. -%%% Note that here a <c>TestDir</c> can be used to point out the path to -%%% a <c>Suite</c>. Note also that the option <c>testcase</c> -%%% corresponds to the <c>-case</c> option in the <c>ct_run</c> -%%% program. Configuration files specified in <c>Opts</c> will be -%%% installed automatically at startup.</p> -%%% <p><c>TestRunnerPid</c> is returned if <c>release_shell == true</c> -%%% (see <c>break/1</c> for details).</p> -%%% <p><c>Reason</c> indicates what type of error has been encountered.</p> run_test(Opts) -> ct_run:run_test(Opts). -%%%----------------------------------------------------------------- -%%% @spec run_testspec(TestSpec) -> Result -%%% TestSpec = [term()] -%%% Result = {Ok,Failed,{UserSkipped,AutoSkipped}} | {error,Reason} -%%% Ok = integer() -%%% Failed = integer() -%%% UserSkipped = integer() -%%% AutoSkipped = integer() -%%% Reason = term() -%%% @doc Run test specified by <c>TestSpec</c>. The terms are -%%% the same as those used in test specification files. -%%% <p><c>Reason</c> indicates what type of error has been encountered.</p> run_testspec(TestSpec) -> ct_run:run_testspec(TestSpec). -%%%----------------------------------------------------------------- -%%% @spec step(TestDir,Suite,Case) -> Result -%%% Case = atom() -%%% -%%% @doc Step through a test case with the debugger. -%%% @see run/3 step(TestDir,Suite,Case) -> ct_run:step(TestDir,Suite,Case). -%%%----------------------------------------------------------------- -%%% @spec step(TestDir,Suite,Case,Opts) -> Result -%%% Case = atom() -%%% Opts = [Opt] | [] -%%% Opt = config | keep_inactive -%%% -%%% @doc Step through a test case with the debugger. If the -%%% <c>config</c> option has been given, breakpoints will -%%% be set also on the configuration functions in <c>Suite</c>. -%%% @see run/3 step(TestDir,Suite,Case,Opts) -> ct_run:step(TestDir,Suite,Case,Opts). -%%%----------------------------------------------------------------- -%%% @spec start_interactive() -> ok -%%% -%%% @doc Start CT in interactive mode. -%%% -%%% <p>From this mode all test case support functions can be executed -%%% directly from the erlang shell. The interactive mode can also be -%%% started from the OS command line with <c>ct_run -shell -%%% [-config File...]</c>.</p> -%%% -%%% <p>If any functions using "required config data" (e.g. telnet or -%%% ftp functions) are to be called from the erlang shell, config data -%%% must first be required with <c>ct:require/2</c>.</p> -%%% -%%% <p>Example:<br/> -%%% <c>> ct:require(unix_telnet, unix).</c><br/> -%%% <c>ok</c><br/> -%%% <c>> ct_telnet:open(unix_telnet).</c><br/> -%%% <c>{ok,<0.105.0>}</c><br/> -%%% <c>> ct_telnet:cmd(unix_telnet, "ls .").</c><br/> -%%% <c>{ok,["ls","file1 ...",...]}</c></p> start_interactive() -> _ = ct_util:start(interactive), ok. -%%%----------------------------------------------------------------- -%%% @spec stop_interactive() -> ok -%%% -%%% @doc Exit the interactive mode. -%%% @see start_interactive/0 stop_interactive() -> ct_util:stop(normal), ok. @@ -331,181 +125,24 @@ stop_interactive() -> %%% MISC INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%----------------------------------------------------------------- -%%% @spec require(Required) -> ok | {error,Reason} -%%% Required = Key | {Key,SubKeys} | {Key,SubKey,SubKeys} -%%% Key = atom() -%%% SubKeys = SubKey | [SubKey] -%%% SubKey = atom() -%%% -%%% @doc Check if the required configuration is available. It is possible -%%% to specify arbitrarily deep tuples as <c>Required</c>. Note that it is -%%% only the last element of the tuple which can be a list of <c>SubKey</c>s. -%%% -%%% <p>Example 1: require the variable <c>myvar</c>:</p> -%%% <pre>ok = ct:require(myvar).</pre> -%%% -%%% <p>In this case the config file must at least contain:</p> -%%% <pre>{myvar,Value}.</pre> -%%% -%%% <p>Example 2: require the key <c>myvar</c> with -%%% subkeys <c>sub1</c> and <c>sub2</c>:</p> -%%% <pre>ok = ct:require({myvar,[sub1,sub2]}).</pre> -%%% -%%% <p>In this case the config file must at least contain:</p> -%%% <pre>{myvar,[{sub1,Value},{sub2,Value}]}.</pre> -%%% -%%% <p>Example 3: require the key <c>myvar</c> with -%%% subkey <c>sub1</c> with <c>subsub1</c>:</p> -%%% <pre>ok = ct:require({myvar,sub1,sub2}).</pre> -%%% -%%% <p>In this case the config file must at least contain:</p> -%%% <pre>{myvar,[{sub1,[{sub2,Value}]}]}.</pre> -%%% -%%% @see require/2 -%%% @see get_config/1 -%%% @see get_config/2 -%%% @see get_config/3 require(Required) -> ct_config:require(Required). -%%%----------------------------------------------------------------- -%%% @spec require(Name,Required) -> ok | {error,Reason} -%%% Name = atom() -%%% Required = Key | {Key,SubKey} | {Key,SubKey,SubKey} -%%% SubKey = Key -%%% Key = atom() -%%% -%%% @doc Check if the required configuration is available, and give it -%%% a name. The semantics for <c>Required</c> is the same as in -%%% <c>required/1</c> except that it is not possible to specify a list -%%% of <c>SubKey</c>s. -%%% -%%% <p>If the requested data is available, the sub entry will be -%%% associated with <c>Name</c> so that the value of the element -%%% can be read with <c>get_config/1,2</c> provided -%%% <c>Name</c> instead of the whole <c>Required</c> term.</p> -%%% -%%% <p>Example: Require one node with a telnet connection and an -%%% ftp connection. Name the node <c>a</c>: -%%% <pre>ok = ct:require(a,{machine,node}).</pre> -%%% All references to this node may then use the node name. -%%% E.g. you can fetch a file over ftp like this:</p> -%%% <pre>ok = ct:ftp_get(a,RemoteFile,LocalFile).</pre> -%%% -%%% <p>For this to work, the config file must at least contain:</p> -%%% <pre>{machine,[{node,[{telnet,IpAddr},{ftp,IpAddr}]}]}.</pre> -%%% -%%% <note><p>The behaviour of this function changed radically in common_test -%%% 1.6.2. In order too keep some backwards compatability it is still possible -%%% to do: <br/><c>ct:require(a,{node,[telnet,ftp]}).</c><br/> -%%% This will associate the name <c>a</c> with the top level <c>node</c> entry. -%%% For this to work, the config file must at least contain:<br/> -%%% <c>{node,[{telnet,IpAddr},{ftp,IpAddr}]}.</c></p></note> -%%% -%%% @see require/1 -%%% @see get_config/1 -%%% @see get_config/2 -%%% @see get_config/3 require(Name,Required) -> ct_config:require(Name,Required). -%%%----------------------------------------------------------------- -%%% @spec get_config(Required) -> Value -%%% @equiv get_config(Required,undefined,[]) get_config(Required) -> ct_config:get_config(Required,undefined,[]). -%%%----------------------------------------------------------------- -%%% @spec get_config(Required,Default) -> Value -%%% @equiv get_config(Required,Default,[]) get_config(Required,Default) -> ct_config:get_config(Required,Default,[]). -%%%----------------------------------------------------------------- -%%% @spec get_config(Required,Default,Opts) -> ValueOrElement -%%% Required = KeyOrName | {KeyOrName,SubKey} | {KeyOrName,SubKey,SubKey} -%%% KeyOrName = atom() -%%% SubKey = atom() -%%% Default = term() -%%% Opts = [Opt] | [] -%%% Opt = element | all -%%% ValueOrElement = term() | Default -%%% -%%% @doc Read config data values. -%%% -%%% <p>This function returns the matching value(s) or config element(s), -%%% given a config variable key or its associated name -%%% (if one has been specified with <c>require/2</c> or a -%%% require statement).</p> -%%% -%%% <p>Example, given the following config file:</p> -%%% <pre> -%%% {unix,[{telnet,IpAddr}, -%%% {user,[{username,Username}, -%%% {password,Password}]}]}.</pre> -%%% <p><c>ct:get_config(unix,Default) -> -%%% [{telnet,IpAddr}, -%%% {user, [{username,Username}, -%%% {password,Password}]}]</c><br/> -%%% <c>ct:get_config({unix,telnet},Default) -> IpAddr</c><br/> -%%% <c>ct:get_config({unix,user,username},Default) -> Username</c><br/> -%%% <c>ct:get_config({unix,ftp},Default) -> Default</c><br/> -%%% <c>ct:get_config(unknownkey,Default) -> Default</c></p> -%%% -%%% <p>If a config variable key has been associated with a name (by -%%% means of <c>require/2</c> or a require statement), the name -%%% may be used instead of the key to read the value:</p> -%%% -%%% <p><c>ct:require(myuser,{unix,user}) -> ok.</c><br/> -%%% <c>ct:get_config(myuser,Default) -> -%%% [{username,Username}, -%%% {password,Password}]</c></p> -%%% -%%% <p>If a config variable is defined in multiple files and you want to -%%% access all possible values, use the <c>all</c> option. The -%%% values will be returned in a list and the order of the elements -%%% corresponds to the order that the config files were specified at -%%% startup.</p> -%%% -%%% <p>If you want config elements (key-value tuples) returned as result -%%% instead of values, use the <c>element</c> option. -%%% The returned elements will then be on the form <c>{Required,Value}</c></p> -%%% -%%% @see get_config/1 -%%% @see get_config/2 -%%% @see require/1 -%%% @see require/2 get_config(Required,Default,Opts) -> ct_config:get_config(Required,Default,Opts). -%%%----------------------------------------------------------------- -%%% @spec reload_config(Required) -> ValueOrElement -%%% Required = KeyOrName | {KeyOrName,SubKey} | {KeyOrName,SubKey,SubKey} -%%% KeyOrName = atom() -%%% SubKey = atom() -%%% ValueOrElement = term() -%%% -%%% @doc Reload config file which contains specified configuration key. -%%% -%%% <p>This function performs updating of the configuration data from which the -%%% given configuration variable was read, and returns the (possibly) new -%%% value of this variable.</p> -%%% <p>Note that if some variables were present in the configuration but are not loaded -%%% using this function, they will be removed from the configuration table together -%%% with their aliases.</p> -%%% reload_config(Required)-> ct_config:reload_config(Required). -%%%----------------------------------------------------------------- -%%% @spec get_testspec_terms() -> TestSpecTerms | undefined -%%% TestSpecTerms = [{Tag,Value}] -%%% Value = [term()] -%%% -%%% @doc Get a list of all test specification terms used to -%%% configure and run this test. -%%% get_testspec_terms() -> case ct_util:get_testdata(testspec) of undefined -> @@ -514,25 +151,6 @@ get_testspec_terms() -> ct_testspec:testspec_rec2list(CurrSpecRec) end. -%%%----------------------------------------------------------------- -%%% @spec get_testspec_terms(Tags) -> TestSpecTerms | undefined -%%% Tags = [Tag] | Tag -%%% Tag = atom() -%%% TestSpecTerms = [{Tag,Value}] | {Tag,Value} -%%% Value = [{Node,term()}] | [term()] -%%% Node = atom() -%%% -%%% @doc Read one or more terms from the test specification used -%%% to configure and run this test. Tag is any valid test specification -%%% tag, such as e.g. <c>label</c>, <c>config</c>, <c>logdir</c>. -%%% User specific terms are also available to read if the -%%% <c>allow_user_terms</c> option has been set. Note that all value tuples -%%% returned, except user terms, will have the node name as first element. -%%% Note also that in order to read test terms, use <c>Tag = tests</c> -%%% (rather than <c>suites</c>, <c>groups</c> or <c>cases</c>). Value is -%%% then the list of *all* tests on the form: -%%% <c>[{Node,Dir,[{TestSpec,GroupsAndCases1},...]},...], where -%%% GroupsAndCases = [{Group,[Case]}] | [Case]</c>. get_testspec_terms(Tags) -> case ct_util:get_testdata(testspec) of undefined -> @@ -541,24 +159,9 @@ get_testspec_terms(Tags) -> ct_testspec:testspec_rec2list(Tags, CurrSpecRec) end. - -%%%----------------------------------------------------------------- -%%% @spec escape_chars(IoList1) -> IoList2 | {error,Reason} -%%% IoList1 = iolist() -%%% IoList2 = iolist() -%%% -%%% @doc Escape special characters to be printed in html log -%%% escape_chars(IoList) -> ct_logs:escape_chars(IoList). -%%%----------------------------------------------------------------- -%%% @spec escape_chars(Format, Args) -> IoList | {error,Reason} -%%% Format = string() -%%% Args = list() -%%% -%%% @doc Escape special characters to be printed in html log -%%% escape_chars(Format, Args) -> try io_lib:format(Format, Args) of IoList -> @@ -568,17 +171,9 @@ escape_chars(Format, Args) -> {error,Reason} end. -%%%----------------------------------------------------------------- -%%% @spec log(Format) -> ok -%%% @equiv log(default,50,Format,[],[]) log(Format) -> log(default,?STD_IMPORTANCE,Format,[],[]). -%%%----------------------------------------------------------------- -%%% @spec log(X1,X2) -> ok -%%% X1 = Category | Importance | Format -%%% X2 = Format | Args -%%% @equiv log(Category,Importance,Format,Args,[]) log(X1,X2) -> {Category,Importance,Format,Args} = if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]}; @@ -587,12 +182,6 @@ log(X1,X2) -> end, log(Category,Importance,Format,Args,[]). -%%%----------------------------------------------------------------- -%%% @spec log(X1,X2,X3) -> ok -%%% X1 = Category | Importance | Format -%%% X2 = Importance | Format | Args -%%% X3 = Format | Args | Opts -%%% @equiv log(Category,Importance,Format,Args,Opts) log(X1,X2,X3) -> {Category,Importance,Format,Args,Opts} = if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]}; @@ -602,13 +191,6 @@ log(X1,X2,X3) -> end, log(Category,Importance,Format,Args,Opts). -%%%----------------------------------------------------------------- -%%% @spec log(X1,X2,X3,X4) -> ok -%%% X1 = Category | Importance -%%% X2 = Importance | Format -%%% X3 = Format | Args -%%% X4 = Args | Opts -%%% @equiv log(Category,Importance,Format,Args,Opts) log(X1,X2,X3,X4) -> {Category,Importance,Format,Args,Opts} = if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]}; @@ -617,40 +199,12 @@ log(X1,X2,X3,X4) -> end, log(Category,Importance,Format,Args,Opts). -%%%----------------------------------------------------------------- -%%% @spec log(Category,Importance,Format,Args,Opts) -> ok -%%% Category = atom() -%%% Importance = integer() -%%% Format = string() -%%% Args = list() -%%% Opts = [Opt] -%%% Opt = {heading,string()} | esc_chars | no_css -%%% -%%% @doc Printout from a test case to the log file. -%%% -%%% <p>This function is meant for printing a string directly from a -%%% test case to the test case log file.</p> -%%% -%%% <p>Default <c>Category</c> is <c>default</c>, -%%% default <c>Importance</c> is <c>?STD_IMPORTANCE</c>, -%%% and default value for <c>Args</c> is <c>[]</c>.</p> -%%% <p>Please see the User's Guide for details on <c>Category</c> -%%% and <c>Importance</c>.</p> log(Category,Importance,Format,Args,Opts) -> ct_logs:tc_log(Category,Importance,Format,Args,Opts). - -%%%----------------------------------------------------------------- -%%% @spec print(Format) -> ok -%%% @equiv print(default,50,Format,[],[]) print(Format) -> print(default,?STD_IMPORTANCE,Format,[],[]). -%%%----------------------------------------------------------------- -%%% @spec print(X1,X2) -> ok -%%% X1 = Category | Importance | Format -%%% X2 = Format | Args -%%% @equiv print(Category,Importance,Format,Args,[]) print(X1,X2) -> {Category,Importance,Format,Args} = if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]}; @@ -659,12 +213,6 @@ print(X1,X2) -> end, print(Category,Importance,Format,Args,[]). -%%%----------------------------------------------------------------- -%%% @spec print(X1,X2,X3) -> ok -%%% X1 = Category | Importance | Format -%%% X2 = Importance | Format | Args -%%% X3 = Format | Args | Opts -%%% @equiv print(Category,Importance,Format,Args,Opts) print(X1,X2,X3) -> {Category,Importance,Format,Args,Opts} = if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]}; @@ -674,13 +222,6 @@ print(X1,X2,X3) -> end, print(Category,Importance,Format,Args,Opts). -%%%----------------------------------------------------------------- -%%% @spec print(X1,X2,X3,X4) -> ok -%%% X1 = Category | Importance -%%% X2 = Importance | Format -%%% X3 = Format | Args -%%% X4 = Args | Opts -%%% @equiv print(Category,Importance,Format,Args,Opts) print(X1,X2,X3,X4) -> {Category,Importance,Format,Args,Opts} = if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]}; @@ -689,40 +230,12 @@ print(X1,X2,X3,X4) -> end, print(Category,Importance,Format,Args,Opts). -%%%----------------------------------------------------------------- -%%% @spec print(Category,Importance,Format,Args,Opts) -> ok -%%% Category = atom() -%%% Importance = integer() -%%% Format = string() -%%% Args = list() -%%% Opts = [Opt] -%%% Opt = {heading,string()} -%%% -%%% @doc Printout from a test case to the console. -%%% -%%% <p>This function is meant for printing a string from a test case -%%% to the console.</p> -%%% -%%% <p>Default <c>Category</c> is <c>default</c>, -%%% default <c>Importance</c> is <c>?STD_IMPORTANCE</c>, -%%% and default value for <c>Args</c> is <c>[]</c>.</p> -%%% <p>Please see the User's Guide for details on <c>Category</c> -%%% and <c>Importance</c>.</p> print(Category,Importance,Format,Args,Opts) -> ct_logs:tc_print(Category,Importance,Format,Args,Opts). - -%%%----------------------------------------------------------------- -%%% @spec pal(Format) -> ok -%%% @equiv pal(default,50,Format,[],[]) pal(Format) -> pal(default,?STD_IMPORTANCE,Format,[]). -%%%----------------------------------------------------------------- -%%% @spec pal(X1,X2) -> ok -%%% X1 = Category | Importance | Format -%%% X2 = Format | Args -%%% @equiv pal(Category,Importance,Format,Args,[]) pal(X1,X2) -> {Category,Importance,Format,Args} = if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]}; @@ -731,12 +244,6 @@ pal(X1,X2) -> end, pal(Category,Importance,Format,Args,[]). -%%%----------------------------------------------------------------- -%%% @spec pal(X1,X2,X3) -> ok -%%% X1 = Category | Importance | Format -%%% X2 = Importance | Format | Args -%%% X3 = Format | Args | Opts -%%% @equiv pal(Category,Importance,Format,Args,Opts) pal(X1,X2,X3) -> {Category,Importance,Format,Args,Opts} = if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]}; @@ -746,13 +253,6 @@ pal(X1,X2,X3) -> end, pal(Category,Importance,Format,Args,Opts). -%%%----------------------------------------------------------------- -%%% @spec pal(X1,X2,X3,X4) -> ok -%%% X1 = Category | Importance -%%% X2 = Importance | Format -%%% X3 = Format | Args -%%% X4 = Args | Opts -%%% @equiv pal(Category,Importance,Format,Args,Opts) pal(X1,X2,X3,X4) -> {Category,Importance,Format,Args,Opts} = if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]}; @@ -761,91 +261,25 @@ pal(X1,X2,X3,X4) -> end, pal(Category,Importance,Format,Args,Opts). -%%%----------------------------------------------------------------- -%%% @spec pal(Category,Importance,Format,Args,Opts) -> ok -%%% Category = atom() -%%% Importance = integer() -%%% Format = string() -%%% Args = list() -%%% Opts = [Opt] -%%% Opt = {heading,string()} | no_css -%%% -%%% @doc Print and log from a test case. -%%% -%%% <p>This function is meant for printing a string from a test case, -%%% both to the test case log file and to the console.</p> -%%% -%%% <p>Default <c>Category</c> is <c>default</c>, -%%% default <c>Importance</c> is <c>?STD_IMPORTANCE</c>, -%%% and default value for <c>Args</c> is <c>[]</c>.</p> -%%% <p>Please see the User's Guide for details on <c>Category</c> -%%% and <c>Importance</c>.</p> pal(Category,Importance,Format,Args,Opts) -> ct_logs:tc_pal(Category,Importance,Format,Args,Opts). -%%%----------------------------------------------------------------- -%%% @spec set_verbosity(Category, Level) -> ok -%%% Category = default | atom() -%%% Level = integer() -%%% -%%% @doc Set the verbosity level for a category set_verbosity(Category, Level) -> ct_util:set_verbosity({Category,Level}). -%%%----------------------------------------------------------------- -%%% @spec get_verbosity(Category) -> Level | undefined -%%% Category = default | atom() -%%% Level = integer() -%%% -%%% @doc Read the verbosity level for a category get_verbosity(Category) -> ct_util:get_verbosity(Category). -%%%----------------------------------------------------------------- -%%% @spec capture_start() -> ok -%%% -%%% @doc Start capturing all text strings printed to stdout during -%%% execution of the test case. -%%% -%%% @see capture_stop/0 -%%% @see capture_get/1 capture_start() -> test_server:capture_start(). -%%%----------------------------------------------------------------- -%%% @spec capture_stop() -> ok -%%% -%%% @doc Stop capturing text strings (a session started with -%%% <c>capture_start/0</c>). -%%% -%%% @see capture_start/0 -%%% @see capture_get/1 capture_stop() -> test_server:capture_stop(). -%%%----------------------------------------------------------------- -%%% @spec capture_get() -> ListOfStrings -%%% ListOfStrings = [string()] -%%% -%%% @equiv capture_get([default]) capture_get() -> %% remove default log printouts (e.g. ct:log/2 printouts) capture_get([default]). -%%%----------------------------------------------------------------- -%%% @spec capture_get(ExclCategories) -> ListOfStrings -%%% ExclCategories = [atom()] -%%% ListOfStrings = [string()] -%%% -%%% @doc Return and purge the list of text strings buffered -%%% during the latest session of capturing printouts to stdout. -%%% With <c>ExclCategories</c> it's possible to specify -%%% log categories that should be ignored in <c>ListOfStrings</c>. -%%% If <c>ExclCategories = []</c>, no filtering takes place. -%%% -%%% @see capture_start/0 -%%% @see capture_stop/0 -%%% @see log/3 capture_get([ExclCat | ExclCategories]) -> Strs = test_server:capture_get(), CatsStr = [atom_to_list(ExclCat) | @@ -862,40 +296,26 @@ capture_get([ExclCat | ExclCategories]) -> capture_get([]) -> test_server:capture_get(). -%%%----------------------------------------------------------------- -%%% @spec fail(Reason) -> ok -%%% Reason = term() -%%% -%%% @doc Terminate a test case with the given error -%%% <c>Reason</c>. fail(Reason) -> try exit({test_case_failed,Reason}) catch - Class:R -> - case erlang:get_stacktrace() of + Class:R:S -> + case S of [{?MODULE,fail,1,_}|Stk] -> ok; Stk -> ok end, erlang:raise(Class, R, Stk) end. -%%%----------------------------------------------------------------- -%%% @spec fail(Format, Args) -> ok -%%% Format = string() -%%% Args = list() -%%% -%%% @doc Terminate a test case with an error message specified -%%% by a format string and a list of values (used as arguments to -%%% <c>io_lib:format/2</c>). fail(Format, Args) -> try io_lib:format(Format, Args) of Str -> try exit({test_case_failed,lists:flatten(Str)}) catch - Class:R -> - case erlang:get_stacktrace() of + Class:R:S -> + case S of [{?MODULE,fail,2,_}|Stk] -> ok; Stk -> ok end, @@ -906,16 +326,6 @@ fail(Format, Args) -> exit({BadArgs,{?MODULE,fail,[Format,Args]}}) end. -%%%----------------------------------------------------------------- -%%% @spec comment(Comment) -> ok -%%% Comment = term() -%%% -%%% @doc Print the given <c>Comment</c> in the comment field in -%%% the table on the test suite result page. -%%% -%%% <p>If called several times, only the last comment is printed. -%%% The test case return value <c>{comment,Comment}</c> -%%% overwrites the string set by this function.</p> comment(Comment) when is_list(Comment) -> Formatted = case (catch io_lib:format("~ts",[Comment])) of @@ -929,19 +339,6 @@ comment(Comment) -> Formatted = io_lib:format("~tp",[Comment]), send_html_comment(lists:flatten(Formatted)). -%%%----------------------------------------------------------------- -%%% @spec comment(Format, Args) -> ok -%%% Format = string() -%%% Args = list() -%%% -%%% @doc Print the formatted string in the comment field in -%%% the table on the test suite result page. -%%% -%%% <p>The <c>Format</c> and <c>Args</c> arguments are -%%% used in call to <c>io_lib:format/2</c> in order to create -%%% the comment string. The behaviour of <c>comment/2</c> is -%%% otherwise the same as the <c>comment/1</c> function (see -%%% above for details).</p> comment(Format, Args) when is_list(Format), is_list(Args) -> Formatted = case (catch io_lib:format(Format, Args)) of @@ -957,64 +354,28 @@ send_html_comment(Comment) -> ct_util:set_testdata({{comment,group_leader()},Html}), test_server:comment(Html). -%%%----------------------------------------------------------------- -%%% @spec make_priv_dir() -> ok | {error,Reason} -%%% Reason = term() -%%% @doc If the test has been started with the create_priv_dir -%%% option set to manual_per_tc, in order for the test case to use -%%% the private directory, it must first create it by calling -%%% this function. make_priv_dir() -> test_server:make_priv_dir(). -%%%----------------------------------------------------------------- -%%% @spec get_target_name(Handle) -> {ok,TargetName} | {error,Reason} -%%% Handle = handle() -%%% TargetName = target_name() -%%% @doc Return the name of the target that the given connection -%%% belongs to. get_target_name(Handle) -> ct_util:get_target_name(Handle). - -%%%----------------------------------------------------------------- -%%% @spec parse_table(Data) -> {Heading,Table} -%%% Data = [string()] -%%% Heading = tuple() -%%% Table = [tuple()] -%%% -%%% @doc Parse the printout from an SQL table and return a list of tuples. -%%% -%%% <p>The printout to parse would typically be the result of a -%%% <c>select</c> command in SQL. The returned -%%% <c>Table</c> is a list of tuples, where each tuple is a row -%%% in the table.</p> -%%% -%%% <p><c>Heading</c> is a tuple of strings representing the -%%% headings of each column in the table.</p> + +-spec get_progname() -> string(). + +get_progname() -> + case init:get_argument(progname) of + {ok, [[Prog]]} -> + Prog; + _Other -> + "no_prog_name" + end. + parse_table(Data) -> ct_util:parse_table(Data). -%%%----------------------------------------------------------------- -%%% @spec listenv(Telnet) -> [Env] -%%% Telnet = term() -%%% Env = {Key,Value} -%%% Key = string() -%%% Value = string() -%%% -%%% @doc Performs the listenv command on the given telnet connection -%%% and returns the result as a list of Key-Value pairs. listenv(Telnet) -> ct_util:listenv(Telnet). - -%%%----------------------------------------------------------------- -%%% @spec testcases(TestDir, Suite) -> Testcases | {error,Reason} -%%% TestDir = string() -%%% Suite = atom() -%%% Testcases = list() -%%% Reason = term() -%%% -%%% @doc Returns all test cases in the specified suite. testcases(TestDir, Suite) -> case make_and_load(TestDir, Suite) of E = {error,_} -> @@ -1032,7 +393,7 @@ make_and_load(Dir, Suite) -> EnvInclude = case os:getenv("CT_INCLUDE_PATH") of false -> []; - CtInclPath -> string:tokens(CtInclPath, [$:,$ ,$,]) + CtInclPath -> string:lexemes(CtInclPath, [$:,$ ,$,]) end, StartInclude = case init:get_argument(include) of @@ -1054,15 +415,6 @@ make_and_load(Dir, Suite) -> end end. -%%%----------------------------------------------------------------- -%%% @spec userdata(TestDir, Suite) -> SuiteUserData | {error,Reason} -%%% TestDir = string() -%%% Suite = atom() -%%% SuiteUserData = [term()] -%%% Reason = term() -%%% -%%% @doc Returns any data specified with the tag <c>userdata</c> -%%% in the list of tuples returned from <c>Suite:suite/0</c>. userdata(TestDir, Suite) -> case make_and_load(TestDir, Suite) of E = {error,_} -> @@ -1088,18 +440,6 @@ get_userdata(List, _) when is_list(List) -> get_userdata(_BadTerm, Spec) -> {error,list_to_atom(Spec ++ " must return a list")}. -%%%----------------------------------------------------------------- -%%% @spec userdata(TestDir, Suite, GroupOrCase) -> TCUserData | {error,Reason} -%%% TestDir = string() -%%% Suite = atom() -%%% GroupOrCase = {group,GroupName} | atom() -%%% GroupName = atom() -%%% TCUserData = [term()] -%%% Reason = term() -%%% -%%% @doc Returns any data specified with the tag <c>userdata</c> -%%% in the list of tuples returned from <c>Suite:group(GroupName)</c> -%%% or <c>Suite:Case()</c>. userdata(TestDir, Suite, {group,GroupName}) -> case make_and_load(TestDir, Suite) of E = {error,_} -> @@ -1118,27 +458,6 @@ userdata(TestDir, Suite, Case) when is_atom(Case) -> get_userdata(Info, atom_to_list(Case)++"/0") end. - -%%%----------------------------------------------------------------- -%%% @spec get_status() -> TestStatus | {error,Reason} | no_tests_running -%%% TestStatus = [StatusElem] -%%% StatusElem = {current,TestCaseInfo} | {successful,Successful} | -%%% {failed,Failed} | {skipped,Skipped} | {total,Total} -%%% TestCaseInfo = {Suite,TestCase} | [{Suite,TestCase}] -%%% Suite = atom() -%%% TestCase = atom() -%%% Successful = integer() -%%% Failed = integer() -%%% Skipped = {UserSkipped,AutoSkipped} -%%% UserSkipped = integer() -%%% AutoSkipped = integer() -%%% Total = integer() -%%% Reason = term() -%%% -%%% @doc Returns status of ongoing test. The returned list contains info about -%%% which test case is currently executing (a list of cases when a -%%% parallel test case group is executing), as well as counters for -%%% successful, failed, skipped, and total test cases so far. get_status() -> case get_testdata(curr_tc) of {ok,TestCase} -> @@ -1170,176 +489,37 @@ get_testdata(Key) -> {ok,Data} end. -%%%----------------------------------------------------------------- -%%% @spec abort_current_testcase(Reason) -> ok | {error,ErrorReason} -%%% Reason = term() -%%% ErrorReason = no_testcase_running | parallel_group -%%% -%%% @doc <p>When calling this function, the currently executing test case will be aborted. -%%% It is the user's responsibility to know for sure which test case is currently -%%% executing. The function is therefore only safe to call from a function which -%%% has been called (or synchronously invoked) by the test case.</p> -%%% -%%% <p><c>Reason</c>, the reason for aborting the test case, is printed -%%% in the test case log.</p> abort_current_testcase(Reason) -> test_server_ctrl:abort_current_testcase(Reason). -%%%----------------------------------------------------------------- -%%% @spec get_event_mgr_ref() -> EvMgrRef -%%% EvMgrRef = atom() -%%% -%%% @doc <p>Call this function in order to get a reference to the -%%% CT event manager. The reference can be used to e.g. add -%%% a user specific event handler while tests are running. -%%% Example: -%%% <c>gen_event:add_handler(ct:get_event_mgr_ref(), my_ev_h, [])</c></p> get_event_mgr_ref() -> ?CT_EVMGR_REF. -%%%----------------------------------------------------------------- -%%% @spec encrypt_config_file(SrcFileName, EncryptFileName) -> -%%% ok | {error,Reason} -%%% SrcFileName = string() -%%% EncryptFileName = string() -%%% Reason = term() -%%% -%%% @doc <p>This function encrypts the source config file with DES3 and -%%% saves the result in file <c>EncryptFileName</c>. The key, -%%% a string, must be available in a text file named -%%% <c>.ct_config.crypt</c> in the current directory, or the -%%% home directory of the user (it is searched for in that order).</p> -%%% <p>See the Common Test User's Guide for information about using -%%% encrypted config files when running tests.</p> -%%% <p>See the <c>crypto</c> application for details on DES3 -%%% encryption/decryption.</p> encrypt_config_file(SrcFileName, EncryptFileName) -> ct_config:encrypt_config_file(SrcFileName, EncryptFileName). -%%%----------------------------------------------------------------- -%%% @spec encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) -> -%%% ok | {error,Reason} -%%% SrcFileName = string() -%%% EncryptFileName = string() -%%% KeyOrFile = {key,string()} | {file,string()} -%%% Reason = term() -%%% -%%% @doc <p>This function encrypts the source config file with DES3 and -%%% saves the result in the target file <c>EncryptFileName</c>. -%%% The encryption key to use is either the value in -%%% <c>{key,Key}</c> or the value stored in the file specified -%%% by <c>{file,File}</c>.</p> -%%% <p>See the Common Test User's Guide for information about using -%%% encrypted config files when running tests.</p> -%%% <p>See the <c>crypto</c> application for details on DES3 -%%% encryption/decryption.</p> encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) -> ct_config:encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile). -%%%----------------------------------------------------------------- -%%% @spec decrypt_config_file(EncryptFileName, TargetFileName) -> -%%% ok | {error,Reason} -%%% EncryptFileName = string() -%%% TargetFileName = string() -%%% Reason = term() -%%% -%%% @doc <p>This function decrypts <c>EncryptFileName</c>, previously -%%% generated with <c>encrypt_config_file/2/3</c>. The original -%%% file contents is saved in the target file. The encryption key, a -%%% string, must be available in a text file named -%%% <c>.ct_config.crypt</c> in the current directory, or the -%%% home directory of the user (it is searched for in that order).</p> decrypt_config_file(EncryptFileName, TargetFileName) -> ct_config:decrypt_config_file(EncryptFileName, TargetFileName). -%%%----------------------------------------------------------------- -%%% @spec decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) -> -%%% ok | {error,Reason} -%%% EncryptFileName = string() -%%% TargetFileName = string() -%%% KeyOrFile = {key,string()} | {file,string()} -%%% Reason = term() -%%% -%%% @doc <p>This function decrypts <c>EncryptFileName</c>, previously -%%% generated with <c>encrypt_config_file/2/3</c>. The original -%%% file contents is saved in the target file. The key must have the -%%% the same value as that used for encryption.</p> decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) -> ct_config:decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile). - -%%%----------------------------------------------------------------- -%%% @spec add_config(Callback, Config) -> ok | {error, Reason} -%%% Callback = atom() -%%% Config = string() -%%% Reason = term() -%%% -%%% @doc <p>This function loads configuration variables using the -%%% given callback module and configuration string. Callback module -%%% should be either loaded or present in the code part. Loaded -%%% configuration variables can later be removed using -%%% <c>remove_config/2</c> function.</p> add_config(Callback, Config)-> ct_config:add_config(Callback, Config). -%%%----------------------------------------------------------------- -%%% @spec remove_config(Callback, Config) -> ok -%%% Callback = atom() -%%% Config = string() -%%% Reason = term() -%%% -%%% @doc <p>This function removes configuration variables (together with -%%% their aliases) which were loaded with specified callback module and -%%% configuration string.</p> remove_config(Callback, Config) -> ct_config:remove_config(Callback, Config). -%%%----------------------------------------------------------------- -%%% @spec timetrap(Time) -> ok -%%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity | Func -%%% Hours = integer() -%%% Mins = integer() -%%% Secs = integer() -%%% Millisecs = integer() | float() -%%% Func = {M,F,A} | fun() -%%% M = atom() -%%% F = atom() -%%% A = list() -%%% -%%% @doc <p>Use this function to set a new timetrap for the running test case. -%%% If the argument is <c>Func</c>, the timetrap will be triggered -%%% when this function returns. <c>Func</c> may also return a new -%%% <c>Time</c> value, which in that case will be the value for the -%%% new timetrap.</p> timetrap(Time) -> test_server:timetrap_cancel(), test_server:timetrap(Time). -%%%----------------------------------------------------------------- -%%% @spec get_timetrap_info() -> {Time,Scale} -%%% Time = integer() | infinity -%%% Scale = true | false -%%% -%%% @doc <p>Read info about the timetrap set for the current test case. -%%% <c>Scale</c> indicates if Common Test will attempt to automatically -%%% compensate timetraps for runtime delays introduced by e.g. tools like -%%% cover.</p> get_timetrap_info() -> test_server:get_timetrap_info(). -%%%----------------------------------------------------------------- -%%% @spec sleep(Time) -> ok -%%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity -%%% Hours = integer() -%%% Mins = integer() -%%% Secs = integer() -%%% Millisecs = integer() | float() -%%% -%%% @doc <p>This function, similar to <c>timer:sleep/1</c>, suspends the test -%%% case for specified time. However, this function also multiplies -%%% <c>Time</c> with the 'multiply_timetraps' value (if set) and under -%%% certain circumstances also scales up the time automatically -%%% if 'scale_timetraps' is set to true (default is false).</p> sleep({hours,Hs}) -> sleep(trunc(Hs * 1000 * 60 * 60)); sleep({minutes,Ms}) -> @@ -1349,52 +529,12 @@ sleep({seconds,Ss}) -> sleep(Time) -> test_server:adjusted_sleep(Time). -%%%----------------------------------------------------------------- -%%% @spec notify(Name,Data) -> ok -%%% Name = atom() -%%% Data = term() -%%% -%%% @doc <p>Sends a asynchronous notification of type <c>Name</c> with -%%% <c>Data</c>to the common_test event manager. This can later be -%%% caught by any installed event manager. </p> -%%% @see //stdlib/gen_event notify(Name,Data) -> ct_event:notify(Name, Data). -%%%----------------------------------------------------------------- -%%% @spec sync_notify(Name,Data) -> ok -%%% Name = atom() -%%% Data = term() -%%% -%%% @doc <p>Sends a synchronous notification of type <c>Name</c> with -%%% <c>Data</c>to the common_test event manager. This can later be -%%% caught by any installed event manager. </p> -%%% @see //stdlib/gen_event sync_notify(Name,Data) -> ct_event:sync_notify(Name, Data). -%%%----------------------------------------------------------------- -%%% @spec break(Comment) -> ok | {error,Reason} -%%% Comment = string() -%%% Reason = {multiple_cases_running,TestCases} | -%%% 'enable break with release_shell option' -%%% TestCases = [atom()] -%%% -%%% @doc <p>This function will cancel any active timetrap and pause the -%%% execution of the current test case until the user calls the -%%% <c>continue/0</c> function. It gives the user the opportunity -%%% to interact with the erlang node running the tests, e.g. for -%%% debugging purposes or for manually executing a part of the -%%% test case. If a parallel group is executing, <c>break/2</c> -%%% should be called instead.</p> -%%% <p>A cancelled timetrap will not be automatically -%%% reactivated after the break, but must be started exlicitly with -%%% <c>ct:timetrap/1</c></p> -%%% <p>In order for the break/continue functionality to work, -%%% Common Test must release the shell process controlling stdin. -%%% This is done by setting the <c>release_shell</c> start option -%%% to <c>true</c>. See the User's Guide for more information.</p> - break(Comment) -> case {ct_util:get_testdata(starter), ct_util:get_testdata(release_shell)} of @@ -1417,19 +557,6 @@ break(Comment) -> end end. -%%%----------------------------------------------------------------- -%%% @spec break(TestCase, Comment) -> ok | {error,Reason} -%%% TestCase = atom() -%%% Comment = string() -%%% Reason = 'test case not running' | -%%% 'enable break with release_shell option' -%%% -%%% @doc <p>This function works the same way as <c>break/1</c>, -%%% only the <c>TestCase</c> argument makes it possible to -%%% pause a test case executing in a parallel group. The -%%% <c>continue/1</c> function should be used to resume -%%% execution of <c>TestCase</c>.</p> -%%% <p>See <c>break/1</c> for more details.</p> break(TestCase, Comment) -> case {ct_util:get_testdata(starter), ct_util:get_testdata(release_shell)} of @@ -1456,56 +583,12 @@ break(TestCase, Comment) -> end end. -%%%----------------------------------------------------------------- -%%% @spec continue() -> ok -%%% -%%% @doc <p>This function must be called in order to continue after a -%%% test case (not executing in a parallel group) has called -%%% <c>break/1</c>.</p> continue() -> test_server:continue(). -%%%----------------------------------------------------------------- -%%% @spec continue(TestCase) -> ok -%%% TestCase = atom() -%%% -%%% @doc <p>This function must be called in order to continue after a -%%% test case has called <c>break/2</c>. If the paused test case, -%%% <c>TestCase</c>, executes in a parallel group, this -%%% function - rather than <c>continue/0</c> - must be used -%%% in order to let the test case proceed.</p> continue(TestCase) -> test_server:continue(TestCase). -%%%----------------------------------------------------------------- -%%% @spec remaining_test_procs() -> {TestProcs,SharedGL,OtherGLs} -%%% TestProcs = [{pid(),GL}] -%%% GL = SharedGL = pid() -%%% OtherGLs = [pid()] -%%% -%%% @doc <p>This function will return the identity of test- and group -%%% leader processes that are still running at the time of this call. -%%% TestProcs are processes in the system that have a Common Test IO -%%% process as group leader. SharedGL is the central Common Test -%%% IO process, responsible for printing to log files for configuration -%%% functions and sequentially executing test cases. OtherGLs are -%%% Common Test IO processes that print to log files for test cases -%%% in parallel test case groups.</p> -%%% <p>The process information returned by this function may be -%%% used to locate and terminate remaining processes after tests have -%%% finished executing. The function would typically by called from -%%% Common Test Hook functions.</p> -%%% <p>Note that processes that execute configuration functions or -%%% test cases are never included in TestProcs. It is therefore safe -%%% to use post configuration hook functions (such as post_end_per_suite, -%%% post_end_per_group, post_end_per_testcase) to terminate all processes -%%% in TestProcs that have the current group leader process as its group -%%% leader.</p> -%%% <p>Note also that the shared group leader (SharedGL) must never be -%%% terminated by the user, only by Common Test. Group leader processes -%%% for parallel test case groups (OtherGLs) may however be terminated -%%% in post_end_per_group hook functions.</p> -%%% remaining_test_procs() -> ct_util:remaining_test_procs(). |