%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2003-2009. 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% %% %%% @doc Main user interface for the Common Test framework. %%% %%%

This module implements the command line interface for running %%% tests and some basic functions for common test case issues %%% such as configuration and logging.

%%% %%%

Test Suite Support Macros

%%% %%%

The config macro is defined in ct.hrl. This %%% macro should be used to retrieve information from the %%% Config 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 Config %%% variable supplied to the test case.

%%% %%%

Possible configuration variables include:

%%% %%% @type var_name() = atom(). A variable name which is specified when %%% ct:require/2 is called, %%% e.g. ct:require(mynodename,{node,[telnet]}) %%% %%% @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). %% Command line user interface for running tests -export([install/1, run/1, run/2, run/3, run_test/1, run_testspec/1, step/3, step/4, start_interactive/0, stop_interactive/0]). %% Test suite API -export([require/1, require/2, get_config/1, get_config/2, get_config/3, reload_config/1, log/1, log/2, log/3, print/1, print/2, print/3, pal/1, pal/2, pal/3, fail/1, comment/1, testcases/2, userdata/2, userdata/3, timetrap/1, sleep/1]). %% New API for manipulating with config handlers -export([add_config/2, remove_config/2]). %% Other interface functions -export([get_status/0, abort_current_testcase/1, encrypt_config_file/2, encrypt_config_file/3, decrypt_config_file/2, decrypt_config_file/3]). -export([get_target_name/1]). -export([parse_table/1, listenv/1]). %%%----------------------------------------------------------------- %%% @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. %%% %%%

Run this function once before first test.

%%% %%%

Example:
%%% install([{config,["config_node.ctc","config_user.ctc"]}]).

%%% %%%

Note that this function is automatically run by the %%% run_test program.

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 testcase(s). %%% %%%

Requires that ct:install/1 has been run first.

%%% %%%

Suites (*_SUITE.erl) files must be stored in %%% TestDir or TestDir/test. All suites %%% will be compiled when test is run.

run(TestDir,Suite,Cases) -> ct_run:run(TestDir,Suite,Cases). %%%----------------------------------------------------------------- %%% @spec run(TestDir,Suite) -> Result %%% %%% @doc Run all testcases 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 testcases in all suites in the given directories. %%% @see run/3. run(TestDirs) -> ct_run:run(TestDirs). %%%----------------------------------------------------------------- %%% @spec run_test(Opts) -> Result %%% Opts = [OptTuples] %%% OptTuples = {config,CfgFiles} | {dir,TestDirs} | {suite,Suites} | %%% {userconfig, UserConfig} | %%% {testcase,Cases} | {group,Groups} | {spec,TestSpecs} | %%% {allow_user_terms,Bool} | {logdir,LogDir} | %%% {silent_connections,Conns} | {cover,CoverSpecFile} | %%% {step,StepOpts} | {event_handler,EventHandlers} | {include,InclDirs} | %%% {auto_compile,Bool} | {multiply_timetraps,M} | {scale_timetraps,Bool} | %%% {repeat,N} | {duration,DurTime} | {until,StopTime} | %%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} | %%% {refresh_logs,LogDir} | {basic_html,Bool} %%% CfgFiles = [string()] | string() %%% UserConfig = [{CallbackMod,CfgStrings}] | {CallbackMod,CfgStrings} %%% CallbackMod = atom() %%% CfgStrings = [string()] | string() %%% TestDirs = [string()] | string() %%% Suites = [string()] | string() %%% Cases = [atom()] | atom() %%% Groups = [atom()] | atom() %%% TestSpecs = [string()] | string() %%% LogDir = string() %%% Conns = all | [atom()] %%% CoverSpecFile = string() %%% StepOpts = [StepOpt] | [] %%% StepOpt = config | keep_inactive %%% EventHandlers = EH | [EH] %%% EH = atom() | {atom(),InitArgs} | {[atom()],InitArgs} %%% InitArgs = [term()] %%% InclDirs = [string()] | string() %%% M = integer() %%% N = integer() %%% DurTime = string(HHMMSS) %%% StopTime = string(YYMoMoDDHHMMSS) | string(HHMMSS) %%% DecryptKeyOrFile = {key,DecryptKey} | {file,DecryptFile} %%% DecryptKey = string() %%% DecryptFile = string() %%% Result = [TestResult] | {error,Reason} %%% @doc Run tests as specified by the combination of options in Opts. %%% The options are the same as those used with the run_test program. %%% Note that here a TestDir can be used to point out the path to %%% a Suite. Note also that the option testcase %%% corresponds to the -case option in the run_test %%% program. Configuration files specified in Opts will be %%% installed automatically at startup. run_test(Opts) -> ct_run:run_test(Opts). %%%----------------------------------------------------------------- %%% @spec run_testspec(TestSpec) -> Result %%% TestSpec = [term()] %%% @doc Run test specified by TestSpec. The terms are %%% the same as those used in test specification files. 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 %%% config option has been given, breakpoints will %%% be set also on the configuration functions in Suite. %%% @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. %%% %%%

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 run_test -shell %%% [-config File...].

%%% %%%

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 ct:require/2.

%%% %%%

Example:
%%% > ct:require(unix_telnet, unix).
%%% ok
%%% > ct_telnet:open(unix_telnet).
%%% {ok,<0.105.0>}
%%% > ct_telnet:cmd(unix_telnet, "ls .").
%%% {ok,["ls","file1 ...",...]}

start_interactive() -> ct_util:start(interactive). %%%----------------------------------------------------------------- %%% @spec stop_interactive() -> ok %%% %%% @doc Exit the interactive mode. %%% @see start_interactive/0 stop_interactive() -> ct_util:stop(normal). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% MISC INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%----------------------------------------------------------------- %%% @spec require(Required) -> ok | {error,Reason} %%% Required = Key | {Key,SubKeys} %%% Key = atom() %%% SubKeys = SubKey | [SubKey] %%% SubKey = atom() %%% %%% @doc Check if the required configuration is available. %%% %%%

Example: require the variable myvar:
%%% ok = ct:require(myvar)

%%% %%%

In this case the config file must at least contain:

%%%
%%% {myvar,Value}.
%%% %%%

Example: require the variable myvar with %%% subvariable sub1:
%%% ok = ct:require({myvar,sub1})

%%% %%%

In this case the config file must at least contain:

%%%
%%% {myvar,[{sub1,Value}]}.
%%% %%% @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,SubKeys} %%% Key = atom() %%% SubKeys = SubKey | [SubKey] %%% SubKey = atom() %%% %%% @doc Check if the required configuration is available, and give it %%% a name. %%% %%%

If the requested data is available, the main entry will be %%% associated with Name so that the value of the element %%% can be read with get_config/1,2 provided %%% Name instead of the Key.

%%% %%%

Example: Require one node with a telnet connection and an %%% ftp connection. Name the node a:
ok = %%% ct:require(a,{node,[telnet,ftp]}).
All references %%% to this node may then use the node name. E.g. you can fetch a %%% file over ftp like this:
%%% ok = ct:ftp_get(a,RemoteFile,LocalFile).

%%% %%%

For this to work, the config file must at least contain:

%%%
%%% {node,[{telnet,IpAddr},
%%%        {ftp,IpAddr}]}.
%%% %%% @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 = atom() %%% SubKey = atom() %%% Default = term() %%% Opts = [Opt] | [] %%% Opt = element | all %%% ValueOrElement = term() | Default %%% %%% @doc Read config data values. %%% %%%

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 require/2 or a %%% require statement).

%%% %%%

Example, given the following config file:

%%%
%%% {unix,[{telnet,IpAddr},
%%%        {username,Username},
%%%        {password,Password}]}.
%%%

get_config(unix,Default) -> %%% [{telnet,IpAddr}, %%% {username,Username}, %%% {password,Password}]
%%% get_config({unix,telnet},Default) -> IpAddr
%%% get_config({unix,ftp},Default) -> Default
%%% get_config(unknownkey,Default) -> Default

%%% %%%

If a config variable key has been associated with a name (by %%% means of require/2 or a require statement), the name %%% may be used instead of the key to read the value:

%%% %%%

require(myhost,unix) -> ok
%%% get_config(myhost,Default) -> %%% [{telnet,IpAddr}, %%% {username,Username}, %%% {password,Password}]

%%% %%%

If a config variable is defined in multiple files and you want to %%% access all possible values, use the all 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.

%%% %%%

If you want config elements (key-value tuples) returned as result %%% instead of values, use the element option. %%% The returned elements will then be on the form {KeyOrName,Value}, %%% or (in case a subkey has been specified) %%% {{KeyOrName,SubKey},Value}

%%% %%% @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 = atom() %%% SubKey = atom() %%% ValueOrElement = term() %%% %%% @doc Reload config file which contains specified configuration key. %%% %%%

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.

%%%

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.

%%% reload_config(Required)-> ct_config:reload_config(Required). %%%----------------------------------------------------------------- %%% @spec log(Format) -> ok %%% @equiv log(default,Format,[]) log(Format) -> log(default,Format,[]). %%%----------------------------------------------------------------- %%% @spec log(X1,X2) -> ok %%% X1 = Category | Format %%% X2 = Format | Args %%% @equiv log(Category,Format,Args) log(X1,X2) -> {Category,Format,Args} = if is_atom(X1) -> {X1,X2,[]}; is_list(X1) -> {default,X1,X2} end, log(Category,Format,Args). %%%----------------------------------------------------------------- %%% @spec log(Category,Format,Args) -> ok %%% Category = atom() %%% Format = string() %%% Args = list() %%% %%% @doc Printout from a testcase to the log. %%% %%%

This function is meant for printing stuff directly from a %%% testcase (i.e. not from within the CT framework) in the test %%% log.

%%% %%%

Default Category is default and %%% default Args is [].

log(Category,Format,Args) -> ct_logs:tc_log(Category,Format,Args). %%%----------------------------------------------------------------- %%% @spec print(Format) -> ok %%% @equiv print(default,Format,[]) print(Format) -> print(default,Format,[]). %%%----------------------------------------------------------------- %%% @equiv print(Category,Format,Args) print(X1,X2) -> {Category,Format,Args} = if is_atom(X1) -> {X1,X2,[]}; is_list(X1) -> {default,X1,X2} end, print(Category,Format,Args). %%%----------------------------------------------------------------- %%% @spec print(Category,Format,Args) -> ok %%% Category = atom() %%% Format = string() %%% Args = list() %%% %%% @doc Printout from a testcase to the console. %%% %%%

This function is meant for printing stuff from a testcase on %%% the console.

%%% %%%

Default Category is default and %%% default Args is [].

print(Category,Format,Args) -> ct_logs:tc_print(Category,Format,Args). %%%----------------------------------------------------------------- %%% @spec pal(Format) -> ok %%% @equiv pal(default,Format,[]) pal(Format) -> pal(default,Format,[]). %%%----------------------------------------------------------------- %%% @spec pal(X1,X2) -> ok %%% X1 = Category | Format %%% X2 = Format | Args %%% @equiv pal(Category,Format,Args) pal(X1,X2) -> {Category,Format,Args} = if is_atom(X1) -> {X1,X2,[]}; is_list(X1) -> {default,X1,X2} end, pal(Category,Format,Args). %%%----------------------------------------------------------------- %%% @spec pal(Category,Format,Args) -> ok %%% Category = atom() %%% Format = string() %%% Args = list() %%% %%% @doc Print and log from a testcase. %%% %%%

This function is meant for printing stuff from a testcase both %%% in the log and on the console.

%%% %%%

Default Category is default and %%% default Args is [].

pal(Category,Format,Args) -> ct_logs:tc_pal(Category,Format,Args). %%%----------------------------------------------------------------- %%% @spec fail(Reason) -> void() %%% Reason = term() %%% %%% @doc Terminate a test case with the given error %%% Reason. fail(Reason) -> exit({test_case_failed,Reason}). %%%----------------------------------------------------------------- %%% @spec comment(Comment) -> void() %%% Comment = term() %%% %%% @doc Print the given Comment in the comment field of %%% the table on the test suite result page. %%% %%%

If called several times, only the last comment is printed. %%% comment/1 is also overwritten by the return value %%% {comment,Comment} or by the function %%% fail/1 (which prints Reason as a %%% comment).

comment(Comment) when is_list(Comment) -> Formatted = case (catch io_lib:format("~s",[Comment])) of {'EXIT',_} -> % it's a list not a string io_lib:format("~p",[Comment]); String -> String end, send_html_comment(lists:flatten(Formatted)); comment(Comment) -> Formatted = io_lib:format("~p",[Comment]), send_html_comment(lists:flatten(Formatted)). send_html_comment(Comment) -> Html = "" ++ Comment ++ "", ct_util:set_testdata({comment,Html}), test_server:comment(Html). %%%----------------------------------------------------------------- %%% @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. %%% %%%

The printout to parse would typically be the result of a %%% select command in SQL. The returned %%% Table is a list of tuples, where each tuple is a row %%% in the table.

%%% %%%

Heading is a tuple of strings representing the %%% headings of each column in the table.

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 testcases in the specified suite. testcases(TestDir, Suite) -> case make_and_load(TestDir, Suite) of E = {error,_} -> E; _ -> case (catch Suite:all()) of {'EXIT',Reason} -> {error,Reason}; TCs -> TCs end end. make_and_load(Dir, Suite) -> EnvInclude = case os:getenv("CT_INCLUDE_PATH") of false -> []; CtInclPath -> string:tokens(CtInclPath, [$:,$ ,$,]) end, StartInclude = case init:get_argument(include) of {ok,[Dirs]} -> Dirs; _ -> [] end, UserInclude = EnvInclude ++ StartInclude, case ct_run:run_make(Dir, Suite, UserInclude) of MErr = {error,_} -> MErr; _ -> TestDir = ct_util:get_testdir(Dir, Suite), File = filename:join(TestDir, atom_to_list(Suite)), case code:soft_purge(Suite) of true -> code:load_abs(File); false -> % will use loaded {module,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 userdata %%% in the list of tuples returned from Suite:suite/0. userdata(TestDir, Suite) -> case make_and_load(TestDir, Suite) of E = {error,_} -> E; _ -> Info = (catch Suite:suite()), get_userdata(Info, "suite/0") end. get_userdata({'EXIT',{undef,_}}, Spec) -> {error,list_to_atom(Spec ++ " is not defined")}; get_userdata({'EXIT',Reason}, Spec) -> {error,{list_to_atom("error in " ++ Spec),Reason}}; get_userdata(List, _) when is_list(List) -> Fun = fun({userdata,Data}, Acc) -> [Data | Acc]; (_, Acc) -> Acc end, case lists:foldl(Fun, [], List) of Terms -> lists:flatten(lists:reverse(Terms)) end; get_userdata(_BadTerm, Spec) -> {error,list_to_atom(Spec ++ " must return a list")}. %%%----------------------------------------------------------------- %%% @spec userdata(TestDir, Suite, Case) -> TCUserData | {error,Reason} %%% TestDir = string() %%% Suite = atom() %%% Case = atom() %%% TCUserData = [term()] %%% Reason = term() %%% %%% @doc Returns any data specified with the tag userdata %%% in the list of tuples returned from Suite:Case/0. userdata(TestDir, Suite, Case) -> case make_and_load(TestDir, Suite) of E = {error,_} -> E; _ -> Info = (catch apply(Suite, Case, [])), get_userdata(Info, atom_to_list(Case)++"/0") end. %%%----------------------------------------------------------------- %%% @spec get_status() -> TestStatus | {error,Reason} %%% TestStatus = [StatusElem] %%% StatusElem = {current,{Suite,TestCase}} | {successful,Successful} | %%% {failed,Failed} | {skipped,Skipped} | {total,Total} %%% 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, as well as counters for %%% successful, failed, skipped, and total test cases so far. get_status() -> case get_testdata(curr_tc) of {ok,TestCase} -> case get_testdata(stats) of {ok,{Ok,Failed,Skipped={UserSkipped,AutoSkipped}}} -> [{current,TestCase}, {successful,Ok}, {failed,Failed}, {skipped,Skipped}, {total,Ok+Failed+UserSkipped+AutoSkipped}]; Err1 -> Err1 end; Err2 -> Err2 end. get_testdata(Key) -> case catch ct_util:get_testdata(Key) of Error = {error,_Reason} -> Error; {'EXIT',_Reason} -> no_tests_running; Data -> {ok,Data} end. %%%----------------------------------------------------------------- %%% @spec abort_current_testcase(Reason) -> ok | {error,no_testcase_running} %%% Reason = term() %%% %%% @doc

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.

%%% %%%

Reason, the reason for aborting the test case, is printed %%% in the test case log.

abort_current_testcase(Reason) -> test_server_ctrl:abort_current_testcase(Reason). %%%----------------------------------------------------------------- %%% @spec encrypt_config_file(SrcFileName, EncryptFileName) -> %%% ok | {error,Reason} %%% SrcFileName = string() %%% EncryptFileName = string() %%% Reason = term() %%% %%% @doc

This function encrypts the source config file with DES3 and %%% saves the result in file EncryptFileName. The key, %%% a string, must be available in a text file named %%% .ct_config.crypt in the current directory, or the %%% home directory of the user (it is searched for in that order).

%%%

See the Common Test User's Guide for information about using %%% encrypted config files when running tests.

%%%

See the crypto application for details on DES3 %%% encryption/decryption.

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

This function encrypts the source config file with DES3 and %%% saves the result in the target file EncryptFileName. %%% The encryption key to use is either the value in %%% {key,Key} or the value stored in the file specified %%% by {file,File}.

%%%

See the Common Test User's Guide for information about using %%% encrypted config files when running tests.

%%%

See the crypto application for details on DES3 %%% encryption/decryption.

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

This function decrypts EncryptFileName, previously %%% generated with encrypt_config_file/2/3. The original %%% file contents is saved in the target file. The encryption key, a %%% string, must be available in a text file named %%% .ct_config.crypt in the current directory, or the %%% home directory of the user (it is searched for in that order).

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

This function decrypts EncryptFileName, previously %%% generated with encrypt_config_file/2/3. The original %%% file contents is saved in the target file. The key must have the %%% the same value as that used for encryption.

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

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 %%% remove_config/2 function.

add_config(Callback, Config)-> ct_config:add_config(Callback, Config). %%%----------------------------------------------------------------- %%% @spec remove_config(Callback, Config) -> ok %%% Callback = atom() %%% Config = string() %%% Reason = term() %%% %%% @doc

This function removes configuration variables (together with %%% their aliases) which were loaded with specified callback module and %%% configuration string.

remove_config(Callback, Config) -> ct_config:remove_config(Callback, Config). %%%----------------------------------------------------------------- %%% @spec timetrap(Time) -> ok %%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity %%% Hours = integer() %%% Mins = integer() %%% Secs = integer() %%% Millisecs = integer() | float() %%% %%% @doc

Use this function to set a new timetrap for the running test case.

timetrap(Time) -> test_server:timetrap(Time). %%%----------------------------------------------------------------- %%% @spec sleep(Time) -> ok %%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity %%% Hours = integer() %%% Mins = integer() %%% Secs = integer() %%% Millisecs = integer() | float() %%% %%% @doc

This function, similar to timer:sleep/1, suspends the test %%% case for specified time. However, this function also multiplies %%% Time with the 'multiply_timetraps' value (if set) and under %%% certain circumstances also scales up the time automatically %%% if 'scale_timetraps' is set to true (default is false).

sleep({hours,Hs}) -> sleep(trunc(Hs * 1000 * 60 * 60)); sleep({minutes,Ms}) -> sleep(trunc(Ms * 1000 * 60)); sleep({seconds,Ss}) -> sleep(trunc(Ss * 1000)); sleep(Time) -> test_server:adjusted_sleep(Time).