diff options
Diffstat (limited to 'lib/common_test/src')
43 files changed, 713 insertions, 3689 deletions
diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile index 9d751996ad..80eaed70bd 100644 --- a/lib/common_test/src/Makefile +++ b/lib/common_test/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2016. 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. @@ -165,3 +165,5 @@ release_tests_spec: opt release_docs_spec: docs +# Include dependencies -- list below added by Kostis Sagonas +$(EBIN)/cth_log_redirect.beam: ../../kernel/include/logger.hrl ../../kernel/src/logger_internal.hrl diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src index 0aa4aacf16..efebea896c 100644 --- a/lib/common_test/src/common_test.app.src +++ b/lib/common_test/src/common_test.app.src @@ -1,7 +1,7 @@ % This is an -*- erlang -*- file. %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2017. All Rights Reserved. +%% Copyright Ericsson AB 2009-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. @@ -85,6 +85,7 @@ "crypto-3.6", "debugger-4.1", "erts-7.0", + "ftp-1.0.0", "inets-6.0", "kernel-4.0", "observer-2.1", @@ -92,7 +93,7 @@ "sasl-2.4.2", "snmp-5.1.2", "ssh-4.0", - "stdlib-3.4", + "stdlib-3.5", "syntax_tools-1.7", "tools-2.8", "xmerl-1.3.8" 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(). diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl index 9cb9b0ba16..a10d939919 100644 --- a/lib/common_test/src/ct_config.erl +++ b/lib/common_test/src/ct_config.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2017. All Rights Reserved. +%% Copyright Ericsson AB 2010-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. @@ -660,7 +660,7 @@ decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) -> get_crypt_key_from_file(File) -> case file:read_file(File) of {ok,Bin} -> - case catch string:tokens(binary_to_list(Bin), [$\n,$\r]) of + case catch string:lexemes(binary_to_list(Bin), [$\n, [$\r,$\n]]) of [Key] -> Key; _ -> @@ -694,7 +694,7 @@ get_crypt_key_from_file() -> noent -> Result; _ -> - case catch string:tokens(binary_to_list(Result), [$\n,$\r]) of + case catch string:lexemes(binary_to_list(Result), [$\n, [$\r,$\n]]) of [Key] -> io:format("~nCrypt key file: ~ts~n", [FullName]), Key; diff --git a/lib/common_test/src/ct_config_plain.erl b/lib/common_test/src/ct_config_plain.erl index e72b55971b..7b68ac6597 100644 --- a/lib/common_test/src/ct_config_plain.erl +++ b/lib/common_test/src/ct_config_plain.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% Copyright Ericsson AB 2010-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. @@ -106,7 +106,7 @@ read_config_terms1({done,{eof,EL},_}, L, _, _) -> read_config_terms1({done,{error,Info,EL},_}, L, _, _) -> {error,{Info,{L,EL}}}; read_config_terms1({more,_}, L, Terms, Rest) -> - case string:tokens(Rest, [$\n,$\r,$\t]) of + case string:lexemes(Rest, [$\n,[$\r,$\n],$\t]) of [] -> lists:reverse(Terms); _ -> diff --git a/lib/common_test/src/ct_conn_log_h.erl b/lib/common_test/src/ct_conn_log_h.erl index cf0a228e1b..3e83020f45 100644 --- a/lib/common_test/src/ct_conn_log_h.erl +++ b/lib/common_test/src/ct_conn_log_h.erl @@ -224,7 +224,7 @@ now_to_time({_,_,MicroS}=Now) -> {calendar:now_to_local_time(Now),MicroS}. pretty_head({{{Y,Mo,D},{H,Mi,S}},MicroS},ConnMod,Text0) -> - Text = string:to_upper(atom_to_list(ConnMod) ++ Text0), + Text = string:uppercase(atom_to_list(ConnMod) ++ Text0), io_lib:format("= ~s ==== ~s-~s-~w::~s:~s:~s,~s ", [Text,t(D),month(Mo),Y,t(H),t(Mi),t(S), micro2milli(MicroS)]). @@ -275,7 +275,7 @@ pad0(N,Str) -> lists:duplicate(N-M,$0) ++ Str. pad_char_end(N,Str,Char) -> - case length(lists:flatten(Str)) of + case string:length(Str) of M when M<N -> Str ++ lists:duplicate(N-M,Char); _ -> Str end. diff --git a/lib/common_test/src/ct_cover.erl b/lib/common_test/src/ct_cover.erl index c258516915..d286f20a4d 100644 --- a/lib/common_test/src/ct_cover.erl +++ b/lib/common_test/src/ct_cover.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2016. All Rights Reserved. +%% Copyright Ericsson AB 2006-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,11 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework code coverage support module. -%%% -%%% <p>This module exports help functions for performing code -%%% coverage analysis.</p> - -module(ct_cover). -export([get_spec/1, add_nodes/1, remove_nodes/1, cross_cover_analyse/2]). @@ -31,16 +26,6 @@ -include_lib("kernel/include/file.hrl"). -%%%----------------------------------------------------------------- -%%% @spec add_nodes(Nodes) -> {ok,StartedNodes} | {error,Reason} -%%% Nodes = [atom()] -%%% StartedNodes = [atom()] -%%% Reason = cover_not_running | not_main_node -%%% -%%% @doc Add nodes to current cover test (only works if cover support -%%% is active!). To have effect, this function should be called -%%% from init_per_suite/1 before any actual tests are performed. -%%% add_nodes([]) -> {ok,[]}; add_nodes(Nodes) -> @@ -67,17 +52,6 @@ add_nodes(Nodes) -> end end. - -%%%----------------------------------------------------------------- -%%% @spec remove_nodes(Nodes) -> ok | {error,Reason} -%%% Nodes = [atom()] -%%% Reason = cover_not_running | not_main_node -%%% -%%% @doc Remove nodes from current cover test. Call this function -%%% to stop cover test on nodes previously added with add_nodes/1. -%%% Results on the remote node are transferred to the Common Test -%%% node. -%%% remove_nodes([]) -> ok; remove_nodes(Nodes) -> @@ -103,25 +77,11 @@ remove_nodes(Nodes) -> end end. - -%%%----------------------------------------------------------------- -%%% @spec cross_cover_analyse(Level,Tests) -> ok -%%% Level = overview | details -%%% Tests = [{Tag,Dir}] -%%% Tag = atom() -%%% Dir = string() -%%% -%%% @doc Accumulate cover results over multiple tests. -%%% See the chapter about <seealso -%%% marker="cover_chapter#cross_cover">cross cover -%%% analysis</seealso> in the users's guide. -%%% cross_cover_analyse(Level,Tests) -> test_server_ctrl:cross_cover_analyse(Level,Tests). %%%----------------------------------------------------------------- -%%% @hidden %% Read cover specification file and return the parsed info. %% -> CoverSpec: {CoverFile,Nodes,Import,Export,AppCoverInfo} diff --git a/lib/common_test/src/ct_default_gl.erl b/lib/common_test/src/ct_default_gl.erl index 9ae430c546..cf1bcc058d 100644 --- a/lib/common_test/src/ct_default_gl.erl +++ b/lib/common_test/src/ct_default_gl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012-2016. All Rights Reserved. +%% Copyright Ericsson AB 2012-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. diff --git a/lib/common_test/src/ct_event.erl b/lib/common_test/src/ct_event.erl index 8b5bba7600..3689c6bc45 100644 --- a/lib/common_test/src/ct_event.erl +++ b/lib/common_test/src/ct_event.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2017. All Rights Reserved. +%% Copyright Ericsson AB 2006-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,14 +18,14 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework Event Handler +%%% doc Common Test Framework Event Handler %%% -%%% <p>This module implements an event handler that CT uses to +%%% This module implements an event handler that CT uses to %%% handle status and progress notifications during test runs. %%% The notifications are handled locally (per node) and passed %%% on to ct_master when CT runs in distributed mode. This %%% module may be used as a template for other event handlers -%%% that can be plugged in to handle local logging and reporting.</p> +%%% that can be plugged in to handle local logging and reporting. -module(ct_event). -behaviour(gen_event). diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 6066470233..134ae0e1cc 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2017. All Rights Reserved. +%% Copyright Ericsson AB 2004-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,10 +18,10 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework callback module. +%%% Common Test Framework callback module. %%% -%%% <p>This module exports framework callback functions which are -%%% called from the test_server.</p> +%%% This module exports framework callback functions which are +%%% called from the test_server. -module(ct_framework). @@ -42,7 +42,7 @@ -define(rev(L), lists:reverse(L)). %%%----------------------------------------------------------------- -%%% @spec init_tc(Mod,Func,Args) -> {ok,NewArgs} | {error,Reason} | +%%% -spec init_tc(Mod,Func,Args) -> {ok,NewArgs} | {error,Reason} | %%% {skip,Reason} | {auto_skip,Reason} %%% Mod = atom() %%% Func = atom() @@ -50,7 +50,7 @@ %%% NewArgs = list() %%% Reason = term() %%% -%%% @doc Test server framework callback, called by the test_server +%%% Test server framework callback, called by the test_server %%% when a new test case is started. init_tc(_,{end_per_testcase_not_run,_},[Config]) -> %% Testcase is completed (skipped or failed), but end_per_testcase @@ -649,7 +649,7 @@ try_set_default(Name,Key,Info,Where) -> %%%----------------------------------------------------------------- -%%% @spec end_tc(Mod,Func,Args) -> {ok,NewArgs}| {error,Reason} | +%%% -spec end_tc(Mod,Func,Args) -> {ok,NewArgs}| {error,Reason} | %%% {skip,Reason} | {auto_skip,Reason} %%% Mod = atom() %%% Func = atom() @@ -657,7 +657,7 @@ try_set_default(Name,Key,Info,Where) -> %%% NewArgs = list() %%% Reason = term() %%% -%%% @doc Test server framework callback, called by the test_server +%%% Test server framework callback, called by the test_server %%% when a test case is finished. end_tc(Mod, Fun, Args) -> %% Have to keep end_tc/3 for backwards compatibility issues @@ -903,15 +903,15 @@ tag(_Other) -> ok. %%%----------------------------------------------------------------- -%%% @spec error_notification(Mod,Func,Args,Error) -> ok +%%% -spec error_notification(Mod,Func,Args,Error) -> ok %%% Mod = atom() %%% Func = atom() %%% Args = list() %%% Error = term() %%% -%%% @doc This function is called as the result of testcase -%%% <code>Func</code> in suite <code>Mod</code> crashing. -%%% <code>Error</code> specifies the reason for failing. +%%% This function is called as the result of testcase +%%% Func in suite Mod crashing. +%%% Error specifies the reason for failing. error_notification(Mod,Func,_Args,{Error,Loc}) -> ErrorSpec = case Error of {What={_E,_R},Trace} when is_list(Trace) -> @@ -921,9 +921,10 @@ error_notification(Mod,Func,_Args,{Error,Loc}) -> end, ErrorStr = case ErrorSpec of {badmatch,Descr} -> - Descr1 = lists:flatten(io_lib:format("~tP",[Descr,10])), - if length(Descr1) > 50 -> - Descr2 = string:substr(Descr1,1,50), + Descr1 = io_lib:format("~tP",[Descr,10]), + DescrLength = string:length(Descr1), + if DescrLength > 50 -> + Descr2 = string:slice(Descr1,0,50), io_lib:format("{badmatch,~ts...}",[Descr2]); true -> io_lib:format("{badmatch,~ts}",[Descr1]) @@ -1048,11 +1049,11 @@ group_or_func(Func, _Config) -> Func. %%%----------------------------------------------------------------- -%%% @spec get_suite(Mod, Func) -> Tests +%%% -spec get_suite(Mod, Func) -> Tests %%% -%%% @doc Called from test_server for every suite (<code>Func==all</code>) -%%% and every test case. If the former, all test cases in the suite -%%% should be returned. +%%% Called from test_server for every suite (Func==all) +%%% and every test case. If the former, all test cases in the suite +%%% should be returned. get_suite(Mod, all) -> case catch apply(Mod, groups, []) of @@ -1354,7 +1355,7 @@ end_per_group(GroupName, _) -> ok. %%%----------------------------------------------------------------- -%%% @spec report(What,Data) -> ok +%%% -spec report(What,Data) -> ok report(What,Data) -> case What of loginfo -> @@ -1518,14 +1519,14 @@ add_to_stats(Result) -> ct_util:update_testdata(stats, Update). %%%----------------------------------------------------------------- -%%% @spec warn(What) -> true | false +%%% -spec warn(What) -> true | false warn(What) when What==nodes; What==processes -> false; warn(_What) -> true. %%%----------------------------------------------------------------- -%%% @spec add_data_dir(File0, Config) -> File1 +%%% -spec add_data_dir(File0, Config) -> File1 add_data_dir(File,Config) when is_atom(File) -> add_data_dir(atom_to_list(File),Config); @@ -1544,7 +1545,7 @@ add_data_dir(File,Config) when is_list(File) -> end. %%%----------------------------------------------------------------- -%%% @spec get_logopts() -> [LogOpt] +%%% -spec get_logopts() -> [LogOpt] get_logopts() -> case ct_util:get_testdata(logopts) of undefined -> @@ -1554,12 +1555,12 @@ get_logopts() -> end. %%%----------------------------------------------------------------- -%%% @spec format_comment(Comment) -> HtmlComment +%%% -spec format_comment(Comment) -> HtmlComment format_comment(Comment) -> "<font color=\"green\">" ++ Comment ++ "</font>". %%%----------------------------------------------------------------- -%%% @spec get_html_wrapper(TestName, PrintLabel, Cwd) -> Header +%%% -spec get_html_wrapper(TestName, PrintLabel, Cwd) -> Header get_html_wrapper(TestName, PrintLabel, Cwd, TableCols) -> get_html_wrapper(TestName, PrintLabel, Cwd, TableCols, utf8). @@ -1567,6 +1568,6 @@ get_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) -> ct_logs:get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding). %%%----------------------------------------------------------------- -%%% @spec get_log_dir() -> {ok,LogDir} +%%% -spec get_log_dir() -> {ok,LogDir} get_log_dir() -> ct_logs:get_log_dir(true). diff --git a/lib/common_test/src/ct_ftp.erl b/lib/common_test/src/ct_ftp.erl index 8effb06e7e..93d1f88041 100644 --- a/lib/common_test/src/ct_ftp.erl +++ b/lib/common_test/src/ct_ftp.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,12 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc FTP client module (based on the FTP support of the INETS application). -%%% -%%% @type connection() = handle() | ct:target_name() -%%% @type handle() = ct_gen_conn:handle(). Handle for a specific -%%% ftp connection. - -module(ct_ftp). %% API @@ -42,76 +36,14 @@ %%%================================================================= %%% API -%%%----------------------------------------------------------------- -%%% @spec put(KeyOrName,LocalFile,RemoteFile) -> ok | {error,Reason} -%%% KeyOrName = Key | Name -%%% Key = atom() -%%% Name = ct:target_name() -%%% LocalFile = string() -%%% RemoteFile = string() -%%% -%%% @doc Open a ftp connection and send a file to the remote host. -%%% -%%% <p><code>LocalFile</code> and <code>RemoteFile</code> must be -%%% absolute paths.</p> -%%% -%%% <p>If the target host is a "special" node, the ftp address must be -%%% specified in the config file like this:</p> -%%% <pre> -%%% {node,[{ftp,IpAddr}]}.</pre> -%%% -%%% <p>If the target host is something else, e.g. a unix host, the -%%% config file must also include the username and password (both -%%% strings):</p> -%%% <pre> -%%% {unix,[{ftp,IpAddr}, -%%% {username,Username}, -%%% {password,Password}]}.</pre> -%%% @see ct:require/2 put(KeyOrName,LocalFile,RemoteFile) -> Fun = fun(Ftp) -> send(Ftp,LocalFile,RemoteFile) end, open_and_do(KeyOrName,Fun). -%%%----------------------------------------------------------------- -%%% @spec get(KeyOrName,RemoteFile,LocalFile) -> ok | {error,Reason} -%%% KeyOrName = Key | Name -%%% Key = atom() -%%% Name = ct:target_name() -%%% RemoteFile = string() -%%% LocalFile = string() -%%% -%%% @doc Open a ftp connection and fetch a file from the remote host. -%%% -%%% <p><code>RemoteFile</code> and <code>LocalFile</code> must be -%%% absolute paths.</p> -%%% -%%% <p>The config file must be as for put/3.</p> -%%% @see put/3 -%%% @see ct:require/2 get(KeyOrName,RemoteFile,LocalFile) -> Fun = fun(Ftp) -> recv(Ftp,RemoteFile,LocalFile) end, open_and_do(KeyOrName,Fun). - -%%%----------------------------------------------------------------- -%%% @spec open(KeyOrName) -> {ok,Handle} | {error,Reason} -%%% KeyOrName = Key | Name -%%% Key = atom() -%%% Name = ct:target_name() -%%% Handle = handle() -%%% -%%% @doc Open an FTP connection to the specified node. -%%% <p>You can open one connection for a particular <code>Name</code> and -%%% use the same name as reference for all subsequent operations. If you -%%% want the connection to be associated with <code>Handle</code> instead -%%% (in case you need to open multiple connections to a host for example), -%%% simply use <code>Key</code>, the configuration variable name, to -%%% specify the target. Note that a connection that has no associated target -%%% name can only be closed with the handle value.</p> -%%% -%%% <p>See <c>ct:require/2</c> for how to create a new <c>Name</c></p> -%%% -%%% @see ct:require/2 open(KeyOrName) -> case ct_util:get_key_from_name(KeyOrName) of {ok,node} -> @@ -152,25 +84,9 @@ open(KeyOrName,Username,Password) -> ct_gen_conn:start(KeyOrName,full_addr(Addr),{Username,Password},?MODULE) end. - -%%%----------------------------------------------------------------- -%%% @spec send(Connection,LocalFile) -> ok | {error,Reason} -%%% -%%% @doc Send a file over FTP. -%%% <p>The file will get the same name on the remote host.</p> -%%% @see send/3 send(Connection,LocalFile) -> send(Connection,LocalFile,filename:basename(LocalFile)). -%%%----------------------------------------------------------------- -%%% @spec send(Connection,LocalFile,RemoteFile) -> ok | {error,Reason} -%%% Connection = connection() -%%% LocalFile = string() -%%% RemoteFile = string() -%%% -%%% @doc Send a file over FTP. -%%% -%%% <p>The file will be named <code>RemoteFile</code> on the remote host.</p> send(Connection,LocalFile,RemoteFile) -> case get_handle(Connection) of {ok,Pid} -> @@ -179,24 +95,9 @@ send(Connection,LocalFile,RemoteFile) -> Error end. -%%%----------------------------------------------------------------- -%%% @spec recv(Connection,RemoteFile) -> ok | {error,Reason} -%%% -%%% @doc Fetch a file over FTP. -%%% <p>The file will get the same name on the local host.</p> -%%% @see recv/3 recv(Connection,RemoteFile) -> recv(Connection,RemoteFile,filename:basename(RemoteFile)). -%%%----------------------------------------------------------------- -%%% @spec recv(Connection,RemoteFile,LocalFile) -> ok | {error,Reason} -%%% Connection = connection() -%%% RemoteFile = string() -%%% LocalFile = string() -%%% -%%% @doc Fetch a file over FTP. -%%% -%%% <p>The file will be named <code>LocalFile</code> on the local host.</p> recv(Connection,RemoteFile,LocalFile) -> case get_handle(Connection) of {ok,Pid} -> @@ -205,12 +106,6 @@ recv(Connection,RemoteFile,LocalFile) -> Error end. -%%%----------------------------------------------------------------- -%%% @spec cd(Connection,Dir) -> ok | {error,Reason} -%%% Connection = connection() -%%% Dir = string() -%%% -%%% @doc Change directory on remote host. cd(Connection,Dir) -> case get_handle(Connection) of {ok,Pid} -> @@ -219,13 +114,6 @@ cd(Connection,Dir) -> Error end. -%%%----------------------------------------------------------------- -%%% @spec ls(Connection,Dir) -> {ok,Listing} | {error,Reason} -%%% Connection = connection() -%%% Dir = string() -%%% Listing = string() -%%% -%%% @doc List the directory Dir. ls(Connection,Dir) -> case get_handle(Connection) of {ok,Pid} -> @@ -234,12 +122,6 @@ ls(Connection,Dir) -> Error end. -%%%----------------------------------------------------------------- -%%% @spec type(Connection,Type) -> ok | {error,Reason} -%%% Connection = connection() -%%% Type = ascii | binary -%%% -%%% @doc Change file transfer type type(Connection,Type) -> case get_handle(Connection) of {ok,Pid} -> @@ -248,12 +130,6 @@ type(Connection,Type) -> Error end. -%%%----------------------------------------------------------------- -%%% @spec delete(Connection,File) -> ok | {error,Reason} -%%% Connection = connection() -%%% File = string() -%%% -%%% @doc Delete a file on remote host delete(Connection,File) -> case get_handle(Connection) of {ok,Pid} -> @@ -262,11 +138,6 @@ delete(Connection,File) -> Error end. -%%%----------------------------------------------------------------- -%%% @spec close(Connection) -> ok | {error,Reason} -%%% Connection = connection() -%%% -%%% @doc Close the FTP connection. close(Connection) -> case get_handle(Connection) of {ok,Pid} -> @@ -279,21 +150,20 @@ close(Connection) -> %%%================================================================= %%% Callback functions -%% @hidden init(KeyOrName,{IP,Port},{Username,Password}) -> case ftp_connect(IP,Port,Username,Password) of {ok,FtpPid} -> log(heading(init,KeyOrName), "Opened ftp connection:\nIP: ~tp\nUsername: ~tp\nPassword: ~p\n", - [IP,Username,lists:duplicate(length(Password),$*)]), + [IP,Username,lists:duplicate(string:length(Password),$*)]), {ok,FtpPid,#state{ftp_pid=FtpPid,target_name=KeyOrName}}; Error -> Error end. ftp_connect(IP,Port,Username,Password) -> - _ = inets:start(), - case inets:start(ftpc,[{host,IP},{port,Port}]) of + _ = ftp:start(), + case ftp:start_service([{host,IP},{port,Port}]) of {ok,FtpPid} -> case ftp:user(FtpPid,Username,Password) of ok -> @@ -305,7 +175,6 @@ ftp_connect(IP,Port,Username,Password) -> {error,{open,Reason}} end. -%% @hidden handle_msg({send,LocalFile,RemoteFile},State) -> log(heading(send,State#state.target_name), "LocalFile: ~tp\nRemoteFile: ~tp\n",[LocalFile,RemoteFile]), @@ -333,15 +202,13 @@ handle_msg({delete,File},State) -> Result = ftp:delete(State#state.ftp_pid,File), {Result,State}. -%% @hidden reconnect(_Addr,_State) -> {error,no_reconnection_of_ftp}. -%% @hidden terminate(FtpPid,State) -> log(heading(terminate,State#state.target_name), "Closing FTP connection.\nHandle: ~p\n",[FtpPid]), - inets:stop(ftpc,FtpPid). + ftp:stop_service(FtpPid). %%%================================================================= diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl index 456bfd8bd1..1ab9946d96 100644 --- a/lib/common_test/src/ct_gen_conn.erl +++ b/lib/common_test/src/ct_gen_conn.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,9 +18,9 @@ %% %CopyrightEnd% %% -%%% @doc Generic connection owner process. +%%% Generic connection owner process. %%% -%%% @type handle() = pid(). A handle for using a connection implemented +%%% -type handle() = pid(). A handle for using a connection implemented %%% with ct_gen_conn.erl. -module(ct_gen_conn). @@ -48,7 +48,7 @@ ct_util_server}). %%%----------------------------------------------------------------- -%%% @spec start(Address,InitData,CallbackMod,Opts) -> +%%% -spec start(Address,InitData,CallbackMod,Opts) -> %%% {ok,Handle} | {error,Reason} %%% Name = term() %%% CallbackMod = atom() @@ -58,57 +58,52 @@ %%% Opt = {name,Name} | {use_existing_connection,boolean()} | %%% {reconnect,boolean()} | {forward_messages,boolean()} %%% -%%% @doc Open a connection and start the generic connection owner process. +%%% Open a connection and start the generic connection owner process. %%% -%%% <p>The <code>CallbackMod</code> is a specific callback module for +%%% The CallbackMod is a specific callback module for %%% each type of connection (e.g. telnet, ftp,...). It must export the -%%% function <code>init/3</code> which takes the arguments -%%% <code>Name</code>, <code>Addresse</code>) and -%%% <code>InitData</code> and returna -%%% <code>{ok,ConnectionPid,State}</code> or -%%% <code>{error,Reason}</code>.</p> +%%% function init/3 which takes the arguments +%%% Name, Addresse) and +%%% InitData and returna +%%% {ok,ConnectionPid,State} or +%%% {error,Reason}. %%% -%%% If no name is given, the <code>Name</code> argument in init/3 will -%%% have the value <code>undefined</code>. +%%% If no name is given, the Name argument in init/3 will +%%% have the value undefined. %%% %%% The callback modules must also export -%%% ``` +%%% %%% handle_msg(Msg,From,State) -> {reply,Reply,State} | %%% {noreply,State} | %%% {stop,Reply,State} %%% terminate(ConnectionPid,State) -> term() %%% close(Handle) -> term() -%%% ''' %%% -%%% The <code>close/1</code> callback function is actually a callback +%%% The close/1 callback function is actually a callback %%% for ct_util, for closing registered connections when -%%% ct_util_server is terminated. <code>Handle</code> is the Pid of +%%% ct_util_server is terminated. Handle is the Pid of %%% the ct_gen_conn process. %%% -%%% If option <code>reconnect</code> is <code>true</code>, then the +%%% If option reconnect is true, then the %%% callback must also export -%%% ``` +%%% %%% reconnect(Address,State) -> {ok,ConnectionPid,State} -%%% ''' %%% -%%% If option <code>forward_messages</code> is <ocde>true</code>, then +%%% If option forward_messages is <ocde>true, then %%% the callback must also export -%%% ``` +%%% %%% handle_msg(Msg,State) -> {noreply,State} | {stop,State} -%%% ''' %%% %%% An old interface still exists. This is used by ct_telnet, ct_ftp %%% and ct_ssh. The start function then has an explicit -%%% <code>Name</code> argument, and no <code>Opts</code> argument. The +%%% Name argument, and no Opts argument. The %%% callback must export: %%% -%%% ``` %%% init(Name,Address,InitData) -> {ok,ConnectionPid,State} %%% handle_msg(Msg,State) -> {Reply,State} %%% reconnect(Address,State) -> {ok,ConnectionPid,State} %%% terminate(ConnectionPid,State) -> term() %%% close(Handle) -> term() -%%% ''' %%% start(Address,InitData,CallbackMod,Opts) when is_list(Opts) -> do_start(Address,InitData,CallbackMod,Opts); @@ -116,73 +111,73 @@ start(Name,Address,InitData,CallbackMod) -> do_start(Address,InitData,CallbackMod,[{name,Name},{old,true}]). %%%----------------------------------------------------------------- -%%% @spec stop(Handle) -> ok +%%% -spec stop(Handle) -> ok %%% Handle = handle() %%% -%%% @doc Close the connection and stop the process managing it. +%%% Close the connection and stop the process managing it. stop(Handle) -> call(Handle,stop,5000). %%%----------------------------------------------------------------- -%%% @spec get_conn_pid(Handle) -> ok +%%% -spec get_conn_pid(Handle) -> ok %%% Handle = handle() %%% -%%% @doc Return the connection pid associated with Handle +%%% Return the connection pid associated with Handle get_conn_pid(Handle) -> call(Handle,get_conn_pid). %%%----------------------------------------------------------------- -%%% @spec log(Heading,Format,Args) -> ok +%%% -spec log(Heading,Format,Args) -> ok %%% -%%% @doc Log activities on the current connection (tool-internal use only). -%%% @see ct_logs:log/3 +%%% Log activities on the current connection (tool-internal use only). +%%% See ct_logs:log/3 log(Heading,Format,Args) -> log(log,[Heading,Format,Args]). %%%----------------------------------------------------------------- -%%% @spec start_log(Heading) -> ok +%%% -spec start_log(Heading) -> ok %%% -%%% @doc Log activities on the current connection (tool-internal use only). -%%% @see ct_logs:start_log/1 +%%% Log activities on the current connection (tool-internal use only). +%%% See ct_logs:start_log/1 start_log(Heading) -> log(start_log,[Heading]). %%%----------------------------------------------------------------- -%%% @spec cont_log(Format,Args) -> ok +%%% -spec cont_log(Format,Args) -> ok %%% -%%% @doc Log activities on the current connection (tool-internal use only). -%%% @see ct_logs:cont_log/2 +%%% Log activities on the current connection (tool-internal use only). +%%% See ct_logs:cont_log/2 cont_log(Format,Args) -> log(cont_log,[Format,Args]). %%%----------------------------------------------------------------- -%%% @spec cont_log_no_timestamp(Format,Args) -> ok +%%% -spec cont_log_no_timestamp(Format,Args) -> ok %%% -%%% @doc Log activities on the current connection (tool-internal use only). -%%% @see ct_logs:cont_log/2 +%%% Log activities on the current connection (tool-internal use only). +%%% See ct_logs:cont_log/2 cont_log_no_timestamp(Format,Args) -> log(cont_log_no_timestamp,[Format,Args]). %%%----------------------------------------------------------------- -%%% @spec end_log() -> ok +%%% -spec end_log() -> ok %%% -%%% @doc Log activities on the current connection (tool-internal use only). -%%% @see ct_logs:end_log/0 +%%% Log activities on the current connection (tool-internal use only). +%%% See ct_logs:end_log/0 end_log() -> log(end_log,[]). %%%----------------------------------------------------------------- -%%% @spec do_within_time(Fun,Timeout) -> FunResult | {error,Reason} +%%% -spec do_within_time(Fun,Timeout) -> FunResult | {error,Reason} %%% Fun = function() %%% Timeout = integer() %%% -%%% @doc Execute a function within a limited time (tool-internal use only). +%%% Execute a function within a limited time (tool-internal use only). %%% -%%% <p>Execute the given <code>Fun</code>, but interrupt if it takes -%%% more than <code>Timeout</code> milliseconds.</p> +%%% Execute the given Fun, but interrupt if it takes +%%% more than Timeout milliseconds. %%% -%%% <p>The execution is also interrupted if the connection is -%%% closed.</p> +%%% The execution is also interrupted if the connection is +%%% closed. do_within_time(Fun,Timeout) -> Self = self(), Silent = get(silent), diff --git a/lib/common_test/src/ct_groups.erl b/lib/common_test/src/ct_groups.erl index 2235365a0e..d867069dce 100644 --- a/lib/common_test/src/ct_groups.erl +++ b/lib/common_test/src/ct_groups.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2017. All Rights Reserved. +%% Copyright Ericsson AB 2004-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,11 +18,9 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework callback module. -%%% -%%% <p>This module contains CT internal help functions for searching -%%% through groups specification trees and producing resulting -%%% tests.</p> +%%% This module contains CT internal help functions for searching +%%% through groups specification trees and producing resulting +%%% tests. -module(ct_groups). diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl index f0592a40be..49587b3edd 100644 --- a/lib/common_test/src/ct_hooks.erl +++ b/lib/common_test/src/ct_hooks.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2017. All Rights Reserved. +%% Copyright Ericsson AB 2004-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,10 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework test execution control module. -%%% -%%% <p>This module is a proxy for calling and handling common test hooks.</p> - -module(ct_hooks). %% API Exports @@ -47,14 +43,12 @@ %% API Functions %% ------------------------------------------------------------------------- -%% @doc Called before any suites are started -spec init(State :: term()) -> ok | {fail, Reason :: term()}. init(Opts) -> call(get_builtin_hooks(Opts) ++ get_new_hooks(Opts, undefined), ok, init, []). -%% @doc Called after all suites are done. -spec terminate(Hooks :: term()) -> ok. terminate(Hooks) -> @@ -63,8 +57,6 @@ terminate(Hooks) -> ct_hooks_terminate_dummy, terminate, Hooks), ok. -%% @doc Called as each test case is started. This includes all configuration -%% tests. -spec init_tc(Mod :: atom(), FuncSpec :: atom() | {ConfigFunc :: init_per_testcase | end_per_testcase, @@ -104,8 +96,6 @@ init_tc(Mod, {end_per_testcase,TC}, Config) -> init_tc(Mod, TC = error_in_suite, Config) -> call(fun call_generic_fallback/3, Config, [pre_init_per_testcase, Mod, TC]). -%% @doc Called as each test case is completed. This includes all configuration -%% tests. -spec end_tc(Mod :: atom(), FuncSpec :: atom() | {ConfigFunc :: init_per_testcase | end_per_testcase, @@ -233,8 +223,7 @@ call([{Hook, call_id, NextFun} | Rest], Config, Meta, Hooks) -> Rest ++ [{NewId, call_init}, {NewId,NextFun}]} end, call(resort(NewRest,NewHooks,Meta), Config, Meta, NewHooks) - catch Error:Reason -> - Trace = erlang:get_stacktrace(), + catch Error:Reason:Trace -> ct_logs:log("Suite Hook","Failed to start a CTH: ~tp:~tp", [Error,{Reason,Trace}]), call([], {fail,"Failed to start CTH" @@ -422,8 +411,7 @@ catch_apply(M,F,A, Default, Fallback) -> catch_apply(M,F,A) -> try erlang:apply(M,F,A) - catch _:Reason -> - Trace = erlang:get_stacktrace(), + catch _:Reason:Trace -> ct_logs:log("Suite Hook","Call to CTH failed: ~w:~tp", [error,{Reason,Trace}]), throw({error_in_cth_call, diff --git a/lib/common_test/src/ct_hooks_lock.erl b/lib/common_test/src/ct_hooks_lock.erl index a82be288e1..be50a33e01 100644 --- a/lib/common_test/src/ct_hooks_lock.erl +++ b/lib/common_test/src/ct_hooks_lock.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-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,11 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework test execution control module. -%%% -%%% <p>This module is a proxy for calling and handling locks in -%%% common test hooks.</p> - -module(ct_hooks_lock). -behaviour(gen_server). @@ -42,7 +37,6 @@ %%% API %%%=================================================================== -%% @doc Starts the server start(Id) -> case gen_server:start({local, ?SERVER}, ?MODULE, Id, []) of {error,{already_started, Pid}} -> @@ -76,12 +70,10 @@ release() -> %%% gen_server callbacks %%%=================================================================== -%% @doc Initiates the server init(Id) -> ct_util:mark_process(), {ok, #state{ id = Id }}. -%% @doc Handling call messages handle_call({stop,Id}, _From, #state{ id = Id, requests = Reqs } = State) -> _ = [gen_server:reply(Req, locker_stopped) || {Req,_ReqId} <- Reqs], {stop, normal, stopped, State}; @@ -108,11 +100,9 @@ handle_call({release, Pid}, _From, handle_call({release, _Pid}, _From, State) -> {reply, not_locked, State}. -%% @doc Handling cast messages handle_cast(_Msg, State) -> {noreply, State}. -%% @doc Handling all non call/cast messages handle_info({'DOWN',Ref,process,Pid,_}, #state{ locked = {true, Pid, Ref}, requests = [{NextFrom,NextPid}|Rest] } = State) -> @@ -121,11 +111,9 @@ handle_info({'DOWN',Ref,process,Pid,_}, {noreply,State#state{ locked = {true, NextPid, NextRef}, requests = Rest } }. -%% @doc This function is called by a gen_server when it is about to terminate. terminate(_Reason, _State) -> ok. -%% @doc Convert process state when code is changed code_change(_OldVsn, State, _Extra) -> {ok, State}. diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index fb6a095b57..07a1693d5d 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.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,14 +18,12 @@ %% %CopyrightEnd% %% -%%% @doc Logging functionality for Common Test Framework. +%%% Logging functionality for Common Test Framework. %%% -%%% <p>This module implements -%%% <ul> -%%% <li>Internal logging of activities in Common Test Framework</li> -%%% <li>Compilation of test results into index pages on several levels</li> -%%% </ul> -%%% </p> +%%% This module implements: +%%% +%%% Internal logging of activities in Common Test Framework, and +%%% Compilation of test results into index pages on several levels -module(ct_logs). @@ -84,17 +82,17 @@ tests = []}). %%%----------------------------------------------------------------- -%%% @spec init(Mode, Verbosity) -> Result +%%% -spec init(Mode, Verbosity) -> Result %%% Mode = normal | interactive %%% Result = {StartTime,LogDir} %%% StartTime = term() %%% LogDir = string() %%% -%%% @doc Initiate the logging mechanism (tool-internal use only). +%%% Initiate the logging mechanism (tool-internal use only). %%% -%%% <p>This function is called by ct_util.erl when testing is -%%% started. A new directory named ct_run.<timestamp> is created -%%% and all logs are stored under this directory.</p> +%%% This function is called by ct_util.erl when testing is +%%% started. A new directory named ct_run.<timestamp> is created +%%% and all logs are stored under this directory. %%% init(Mode, Verbosity) -> Self = self(), @@ -129,9 +127,9 @@ datestr_from_dirname([]) -> "". %%%----------------------------------------------------------------- -%%% @spec close(Info, StartDir) -> ok +%%% -spec close(Info, StartDir) -> ok %%% -%%% @doc Create index pages with test results and close the CT Log +%%% Create index pages with test results and close the CT Log %%% (tool-internal use only). close(Info, StartDir) -> %% close executes on the ct_util process, not on the logger process @@ -204,22 +202,22 @@ close(Info, StartDir) -> ok. %%%----------------------------------------------------------------- -%%% @spec set_stylesheet(TC,SSFile) -> ok +%%% -spec set_stylesheet(TC,SSFile) -> ok set_stylesheet(TC, SSFile) -> cast({set_stylesheet,TC,SSFile}). %%%----------------------------------------------------------------- -%%% @spec clear_stylesheet(TC) -> ok +%%% -spec clear_stylesheet(TC) -> ok clear_stylesheet(TC) -> cast({clear_stylesheet,TC}). %%%----------------------------------------------------------------- -%%% @spec get_log_dir() -> {ok,Dir} | {error,Reason} +%%% -spec get_log_dir() -> {ok,Dir} | {error,Reason} get_log_dir() -> get_log_dir(false). %%%----------------------------------------------------------------- -%%% @spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason} +%%% -spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason} get_log_dir(ReturnAbsName) -> case call({get_log_dir,ReturnAbsName}) of {error,does_not_exist} when ReturnAbsName == true -> @@ -278,58 +276,58 @@ get_format_args(Content) -> end, Content). %%%----------------------------------------------------------------- -%%% @spec init_tc(RefreshLog) -> ok +%%% -spec init_tc(RefreshLog) -> ok %%% -%%% @doc Test case initiation (tool-internal use only). +%%% Test case initiation (tool-internal use only). %%% -%%% <p>This function is called by ct_framework:init_tc/3</p> +%%% This function is called by ct_framework:init_tc/3 init_tc(RefreshLog) -> call({init_tc,self(),group_leader(),RefreshLog}), tc_io_format(group_leader(), xhtml("", "<br />"), []), ok. %%%----------------------------------------------------------------- -%%% @spec end_tc(TCPid) -> ok +%%% -spec end_tc(TCPid) -> ok %%% -%%% @doc Test case clean up (tool-internal use only). +%%% Test case clean up (tool-internal use only). %%% -%%% <p>This function is called by ct_framework:end_tc/3</p> +%%% This function is called by ct_framework:end_tc/3 end_tc(TCPid) -> %% use call here so that the TC process will wait and receive %% possible exit signals from ct_logs before end_tc returns ok call({end_tc,TCPid}). %%%----------------------------------------------------------------- -%%% @spec register_groupleader(Pid,GroupLeader) -> ok +%%% -spec register_groupleader(Pid,GroupLeader) -> ok %%% -%%% @doc To enable logging to a group leader (tool-internal use only). +%%% To enable logging to a group leader (tool-internal use only). %%% -%%% <p>This function is called by ct_framework:report/2</p> +%%% This function is called by ct_framework:report/2 register_groupleader(Pid,GroupLeader) -> call({register_groupleader,Pid,GroupLeader}), ok. %%%----------------------------------------------------------------- -%%% @spec unregister_groupleader(Pid) -> ok +%%% -spec unregister_groupleader(Pid) -> ok %%% -%%% @doc To disable logging to a group leader (tool-internal use only). +%%% To disable logging to a group leader (tool-internal use only). %%% -%%% <p>This function is called by ct_framework:report/2</p> +%%% This function is called by ct_framework:report/2 unregister_groupleader(Pid) -> call({unregister_groupleader,Pid}), ok. %%%----------------------------------------------------------------- -%%% @spec log(Heading,Format,Args) -> ok +%%% -spec log(Heading,Format,Args) -> ok %%% -%%% @doc Log internal activity (tool-internal use only). +%%% Log internal activity (tool-internal use only). %%% -%%% <p>This function writes an entry to the currently active log, -%%% i.e. either the CT log or a test case log.</p> +%%% This function writes an entry to the currently active log, +%%% i.e. either the CT log or a test case log. %%% -%%% <p><code>Heading</code> is a short string indicating what type of -%%% activity it is. <code>Format</code> and <code>Args</code> is the -%%% data to log (as in <code>io:format(Format,Args)</code>).</p> +%%% Heading is a short string indicating what type of +%%% activity it is. Format and Args is the +%%% data to log (as in io:format(Format,Args)). log(Heading,Format,Args) -> cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE, [{hd,int_header(),[log_timestamp(?now),Heading]}, @@ -339,32 +337,29 @@ log(Heading,Format,Args) -> ok. %%%----------------------------------------------------------------- -%%% @spec start_log(Heading) -> ok +%%% -spec start_log(Heading) -> ok %%% -%%% @doc Starts the logging of an activity (tool-internal use only). +%%% Starts the logging of an activity (tool-internal use only). %%% -%%% <p>This function must be used in combination with -%%% <code>cont_log/2</code> and <code>end_log/0</code>. The intention -%%% is to call <code>start_log</code> once, then <code>cont_log</code> -%%% any number of times and finally <code>end_log</code> once.</p> +%%% This function must be used in combination with +%%% cont_log/2 and end_log/0. The intention +%%% is to call start_log once, then cont_log +%%% any number of times and finally end_log once. %%% -%%% <p>For information about the parameters, see <code>log/3</code>.</p> +%%% For information about the parameters, see log/3. %%% -%%% @see log/3 -%%% @see cont_log/2 -%%% @see end_log/0 +%%% See log/3, cont_log/2, and end_log/0. start_log(Heading) -> cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE, [{hd,int_header(),[log_timestamp(?now),Heading]}],false}), ok. %%%----------------------------------------------------------------- -%%% @spec cont_log(Format,Args) -> ok +%%% -spec cont_log(Format,Args) -> ok %%% -%%% @doc Adds information about an activity (tool-internal use only). +%%% Adds information about an activity (tool-internal use only). %%% -%%% @see start_log/1 -%%% @see end_log/0 +%%% See start_log/1 and end_log/0. cont_log([],[]) -> ok; cont_log(Format,Args) -> @@ -374,12 +369,11 @@ cont_log(Format,Args) -> ok. %%%----------------------------------------------------------------- -%%% @spec cont_log_no_timestamp(Format,Args) -> ok +%%% -spec cont_log_no_timestamp(Format,Args) -> ok %%% -%%% @doc Adds information about an activity (tool-internal use only). +%%% Adds information about an activity (tool-internal use only). %%% -%%% @see start_log/1 -%%% @see end_log/0 +%%% See start_log/1 and end_log/0. cont_log_no_timestamp([],[]) -> ok; cont_log_no_timestamp(Format,Args) -> @@ -388,12 +382,11 @@ cont_log_no_timestamp(Format,Args) -> ok. %%%----------------------------------------------------------------- -%%% @spec end_log() -> ok +%%% -spec end_log() -> ok %%% -%%% @doc Ends the logging of an activity (tool-internal use only). +%%% Ends the logging of an activity (tool-internal use only). %%% -%%% @see start_log/1 -%%% @see cont_log/2 +%%% See start_log/1 and cont_log/2. end_log() -> cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE, [{ft,int_footer(), []}],false}), @@ -401,15 +394,15 @@ end_log() -> %%%----------------------------------------------------------------- -%%% @spec add_external_logs(Logs) -> ok +%%% -spec add_external_logs(Logs) -> ok %%% Logs = [Log] %%% Log = string() %%% -%%% @doc Print a link to each given <code>Log</code> in the test case +%%% Print a link to each given Log in the test case %%% log. %%% -%%% <p>The given <code>Logs</code> must exist in the priv dir of the -%%% calling test suite.</p> +%%% The given Logs must exist in the priv dir of the +%%% calling test suite. add_external_logs(Logs) -> start_log("External Logs"), [cont_log("<a href=\"~ts\">~ts</a>\n", @@ -417,12 +410,12 @@ add_external_logs(Logs) -> end_log(). %%%----------------------------------------------------------------- -%%% @spec add_link(Heading,File,Type) -> ok +%%% -spec add_link(Heading,File,Type) -> ok %%% Heading = string() %%% File = string() %%% Type = string() %%% -%%% @doc Print a link to a given file stored in the priv_dir of the +%%% Print a link to a given file stored in the priv_dir of the %%% calling test suite. add_link(Heading,File,Type) -> log(Heading,"<a href=\"~ts\" type=~tp>~ts</a>\n", @@ -430,25 +423,25 @@ add_link(Heading,File,Type) -> %%%----------------------------------------------------------------- -%%% @spec tc_log(Category,Format,Args) -> ok -%%% @equiv tc_log(Category,?STD_IMPORTANCE,Format,Args) +%%% -spec tc_log(Category,Format,Args) -> ok +%%% Equivalent to tc_log(Category,?STD_IMPORTANCE,Format,Args) tc_log(Category,Format,Args) -> tc_log(Category,?STD_IMPORTANCE,"User",Format,Args,[]). %%%----------------------------------------------------------------- -%%% @spec tc_log(Category,Importance,Format,Args) -> ok -%%% @equiv tc_log(Category,Importance,"User",Format,Args) +%%% -spec tc_log(Category,Importance,Format,Args) -> ok +%%% Equivalent to tc_log(Category,Importance,"User",Format,Args) tc_log(Category,Importance,Format,Args) -> tc_log(Category,Importance,"User",Format,Args,[]). %%%----------------------------------------------------------------- -%%% @spec tc_log(Category,Importance,Format,Args) -> ok -%%% @equiv tc_log(Category,Importance,"User",Format,Args) +%%% -spec tc_log(Category,Importance,Format,Args) -> ok +%%% Equivalent to tc_log(Category,Importance,"User",Format,Args) tc_log(Category,Importance,Format,Args,Opts) -> tc_log(Category,Importance,"User",Format,Args,Opts). %%%----------------------------------------------------------------- -%%% @spec tc_log(Category,Importance,Heading,Format,Args,Opts) -> ok +%%% -spec tc_log(Category,Importance,Heading,Format,Args,Opts) -> ok %%% Category = atom() %%% Importance = integer() %%% Heading = string() @@ -456,11 +449,11 @@ tc_log(Category,Importance,Format,Args,Opts) -> %%% Args = list() %%% Opts = list() %%% -%%% @doc Printout from a testcase. +%%% Printout from a testcase. %%% -%%% <p>This function is called by <code>ct</code> when logging +%%% This function is called by ct when logging %%% stuff directly from a testcase (i.e. not from within the CT -%%% framework).</p> +%%% framework). tc_log(Category,Importance,Heading,Format,Args,Opts) -> Data = case lists:member(no_css, Opts) of @@ -481,26 +474,26 @@ tc_log(Category,Importance,Heading,Format,Args,Opts) -> ok. %%%----------------------------------------------------------------- -%%% @spec tc_log_async(Category,Format,Args) -> ok -%%% @equiv tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args) +%%% -spec tc_log_async(Category,Format,Args) -> ok +%%% Equivalent to tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args) tc_log_async(Category,Format,Args) -> tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args). %%%----------------------------------------------------------------- -%%% @spec tc_log_async(Category,Importance,Format,Args) -> ok +%%% -spec tc_log_async(Category,Importance,Format,Args) -> ok %%% Category = atom() %%% Importance = integer() %%% Heading = string() %%% Format = string() %%% Args = list() %%% -%%% @doc Internal use only. +%%% Internal use only. %%% -%%% <p>This function is used to perform asynchronous printouts +%%% This function is used to perform asynchronous printouts %%% towards the test server IO handler. This is necessary in order %%% to avoid deadlocks when e.g. the hook that handles SASL printouts %%% prints to the test case log file at the same time test server -%%% asks ct_logs for an html wrapper.</p> +%%% asks ct_logs for an html wrapper. tc_log_async(Category,Importance,Heading,Format,Args) -> cast({log,async,self(),group_leader(),Category,Importance, [{hd,div_header(Category,Heading),[]}, @@ -509,29 +502,29 @@ tc_log_async(Category,Importance,Heading,Format,Args) -> true}), ok. %%%----------------------------------------------------------------- -%%% @spec tc_print(Category,Format,Args) -%%% @equiv tc_print(Category,?STD_IMPORTANCE,Format,Args,[]) +%%% -spec tc_print(Category,Format,Args) +%%% Equivalent to tc_print(Category,?STD_IMPORTANCE,Format,Args,[]) tc_print(Category,Format,Args) -> tc_print(Category,?STD_IMPORTANCE,Format,Args,[]). %%%----------------------------------------------------------------- -%%% @spec tc_print(Category,Importance,Format,Args) -%%% @equiv tc_print(Category,Importance,Format,Args,[]) +%%% -spec tc_print(Category,Importance,Format,Args) +%%% Equivalent to tc_print(Category,Importance,Format,Args,[]) tc_print(Category,Importance,Format,Args) -> tc_print(Category,Importance,Format,Args,[]). %%%----------------------------------------------------------------- -%%% @spec tc_print(Category,Importance,Format,Args,Opts) -> ok +%%% -spec tc_print(Category,Importance,Format,Args,Opts) -> ok %%% Category = atom() %%% Importance = integer() %%% Format = string() %%% Args = list() %%% Opts = list() %%% -%%% @doc Console printout from a testcase. +%%% Console printout from a testcase. %%% -%%% <p>This function is called by <code>ct</code> when printing -%%% stuff from a testcase on the user console.</p> +%%% This function is called by ct when printing +%%% stuff from a testcase on the user console. tc_print(Category,Importance,Format,Args,Opts) -> VLvl = case ct_util:get_verbosity(Category) of undefined -> @@ -572,44 +565,44 @@ get_header(Heading) -> %%%----------------------------------------------------------------- -%%% @spec tc_pal(Category,Format,Args) -> ok -%%% @equiv tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]) -> ok +%%% -spec tc_pal(Category,Format,Args) -> ok +%%% Equivalent to tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]) -> ok tc_pal(Category,Format,Args) -> tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]). %%%----------------------------------------------------------------- -%%% @spec tc_pal(Category,Importance,Format,Args) -> ok -%%% @equiv tc_pal(Category,Importance,Format,Args,[]) -> ok +%%% -spec tc_pal(Category,Importance,Format,Args) -> ok +%%% Equivalent to tc_pal(Category,Importance,Format,Args,[]) -> ok tc_pal(Category,Importance,Format,Args) -> tc_pal(Category,Importance,Format,Args,[]). %%%----------------------------------------------------------------- -%%% @spec tc_pal(Category,Importance,Format,Args,Opts) -> ok +%%% -spec tc_pal(Category,Importance,Format,Args,Opts) -> ok %%% Category = atom() %%% Importance = integer() %%% Format = string() %%% Args = list() %%% Opts = list() %%% -%%% @doc Print and log from a testcase. +%%% Print and log from a testcase. %%% -%%% <p>This function is called by <code>ct</code> when logging +%%% This function is called by ct when logging %%% stuff directly from a testcase. The info is written both in the -%%% log and on the console.</p> +%%% log and on the console. tc_pal(Category,Importance,Format,Args,Opts) -> tc_print(Category,Importance,Format,Args,Opts), tc_log(Category,Importance,"User",Format,Args,[esc_chars|Opts]). %%%----------------------------------------------------------------- -%%% @spec ct_log(Category,Format,Args) -> ok +%%% -spec ct_log(Category,Format,Args) -> ok %%% Category = atom() %%% Format = string() %%% Args = list() %%% -%%% @doc Print to the ct framework log +%%% Print to the ct framework log %%% -%%% <p>This function is called by internal ct functions to -%%% force logging to the ct framework log</p> +%%% This function is called by internal ct functions to +%%% force logging to the ct framework log ct_log(Category,Format,Args) -> cast({ct_log,[{hd,div_header(Category),[]}, {Format,Args}, @@ -1191,26 +1184,23 @@ print_style(Fd, IoFormat, StyleSheet) -> case file:read_file(StyleSheet) of {ok,Bin} -> Str = b2s(Bin,encoding(StyleSheet)), - Pos0 = case string:str(Str,"<style>") of - 0 -> string:str(Str,"<STYLE>"); - N0 -> N0 - end, - Pos1 = case string:str(Str,"</style>") of - 0 -> string:str(Str,"</STYLE>"); - N1 -> N1 - end, - if (Pos0 == 0) and (Pos1 /= 0) -> - print_style_error(Fd, IoFormat, - StyleSheet, missing_style_start_tag); - (Pos0 /= 0) and (Pos1 == 0) -> - print_style_error(Fd, IoFormat, - StyleSheet,missing_style_end_tag); - Pos0 /= 0 -> - Style = string:sub_string(Str,Pos0,Pos1+7), - IoFormat(Fd,"~ts\n",[Style]); - Pos0 == 0 -> - IoFormat(Fd,"<style>\n~ts</style>\n",[Str]) - end; + case re:run(Str,"<style>.*</style>", + [dotall,caseless,{capture,all,list}]) of + nomatch -> + case re:run(Str,"</?style>",[caseless,{capture,all,list}]) of + nomatch -> + IoFormat(Fd,"<style>\n~ts</style>\n",[Str]); + {match,["</"++_]} -> + print_style_error(Fd, IoFormat, + StyleSheet, + missing_style_start_tag); + {match,[_]} -> + print_style_error(Fd, IoFormat, + StyleSheet,missing_style_end_tag) + end; + {match,[Style]} -> + IoFormat(Fd,"~ts\n",[Style]) + end; {error,Reason} -> print_style_error(Fd,IoFormat,StyleSheet,Reason) end. @@ -1417,9 +1407,9 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip, {Lbl,Timestamp,Node,AllInfo} = case All of {true,OldRuns} -> - [_Prefix,NodeOrDate|_] = string:tokens(Link,"."), - Node1 = case string:chr(NodeOrDate,$@) of - 0 -> "-"; + [_Prefix,NodeOrDate|_] = string:lexemes(Link,"."), + Node1 = case string:find(NodeOrDate,[$@]) of + nomatch -> "-"; _ -> NodeOrDate end, @@ -1526,7 +1516,7 @@ not_built(BaseName,_LogDir,_All,Missing) -> %% Top.ObjDir | Top.ObjDir.suites | Top.ObjDir.Suite | %% Top.ObjDir.Suite.cases | Top.ObjDir.Suite.Case Failed = - case string:tokens(BaseName,".") of + case string:lexemes(BaseName,".") of [T,O] when is_list(T) -> % all under Top.ObjDir locate_info({T,O},all,Missing); [T,O,"suites"] -> @@ -2054,9 +2044,9 @@ sort_all_runs(Dirs) -> %% "YYYY-MM-DD_HH.MM.SS" lists:sort(fun(Dir1,Dir2) -> [SS1,MM1,HH1,Date1|_] = - lists:reverse(string:tokens(Dir1,[$.,$_])), + lists:reverse(string:lexemes(Dir1,[$.,$_])), [SS2,MM2,HH2,Date2|_] = - lists:reverse(string:tokens(Dir2,[$.,$_])), + lists:reverse(string:lexemes(Dir2,[$.,$_])), {Date1,HH1,MM1,SS1} > {Date2,HH2,MM2,SS2} end, Dirs). @@ -2066,9 +2056,9 @@ sort_ct_runs(Dirs) -> lists:sort( fun(Dir1,Dir2) -> [SS1,MM1,DateHH1 | _] = - lists:reverse(string:tokens(filename:dirname(Dir1),[$.])), + lists:reverse(string:lexemes(filename:dirname(Dir1),[$.])), [SS2,MM2,DateHH2 | _] = - lists:reverse(string:tokens(filename:dirname(Dir2),[$.])), + lists:reverse(string:lexemes(filename:dirname(Dir2),[$.])), {DateHH1,MM1,SS1} =< {DateHH2,MM2,SS2} end, Dirs). @@ -2214,27 +2204,15 @@ runentry(Dir, Totals={Node,Label,Logs, 0 -> "-"; N -> integer_to_list(N) end, - StripExt = - fun(File) -> - string:sub_string(File,1, - length(File)- - length(?logdir_ext)) ++ ", " - end, - Polish = fun(S) -> case lists:reverse(S) of - [32,$,|Rev] -> lists:reverse(Rev); - [$,|Rev] -> lists:reverse(Rev); - _ -> S - end - end, - TestNames = Polish(lists:flatten(lists:map(StripExt,Logs))), + + RootNames = lists:map(fun(F) -> filename:rootname(F,?logdir_ext) end, Logs), + TestNames = lists:flatten(lists:join(", ", RootNames)), TestNamesTrunc = - if TestNames=="" -> - ""; - length(TestNames) < ?testname_width -> + if length(TestNames) < ?testname_width -> TestNames; true -> - Trunc = Polish(string:substr(TestNames,1, - ?testname_width-3)), + Trunc = string:trim(string:slice(TestNames,0,?testname_width-3), + trailing,",\s"), lists:flatten(io_lib:format("~ts...",[Trunc])) end, TotMissingStr = @@ -2377,7 +2355,7 @@ force_rename(From,To,Number) -> timestamp(Dir) -> - TsR = lists:reverse(string:tokens(Dir,".-_")), + TsR = lists:reverse(string:lexemes(Dir,".-_")), [S,Min,H,D,M,Y] = [list_to_integer(N) || N <- lists:sublist(TsR,6)], format_time({{Y,M,D},{H,Min,S}}). @@ -2926,7 +2904,7 @@ cache_vsn() -> VSNfile = filename:join([EbinDir,"..","vsn.mk"]), case file:read_file(VSNfile) of {ok,Bin} -> - [_,VSN] = string:tokens(binary_to_list(Bin),[$=,$\n,$ ]), + [_,VSN] = string:lexemes(binary_to_list(Bin),[$=,$\n,$ ]), VSN; _ -> undefined @@ -3008,13 +2986,13 @@ rm_files([]) -> ok. %%%----------------------------------------------------------------- -%%% @spec simulate() -> pid() +%%% -spec simulate() -> pid() %%% -%%% @doc Simulate the logger process. +%%% Simulate the logger process. %%% -%%% <p>Simulate the logger process - for use when testing code using +%%% Simulate the logger process - for use when testing code using %%% ct_logs logging mechanism without using the ct -%%% environment. (E.g. when testing code with ts)</p> +%%% environment. (E.g. when testing code with ts) simulate() -> cast(stop), S = self(), @@ -3042,9 +3020,7 @@ simulate_logger_loop() -> end. %%%----------------------------------------------------------------- -%%% @spec notify_and_lock_file(Files) -> ok -%%% -%%% @doc +%%% -spec notify_and_lock_file(Files) -> ok %%% notify_and_lock_file(File) -> case ct_event:is_alive() of @@ -3057,9 +3033,7 @@ notify_and_lock_file(File) -> end. %%%----------------------------------------------------------------- -%%% @spec notify_and_unlock_file(Files) -> ok -%%% -%%% @doc +%%% -spec notify_and_unlock_file(Files) -> ok %%% notify_and_unlock_file(File) -> case ct_event:is_alive() of @@ -3072,9 +3046,7 @@ notify_and_unlock_file(File) -> end. %%%----------------------------------------------------------------- -%%% @spec get_run_dirs(Dir) -> [string()] | false -%%% -%%% @doc +%%% -spec get_run_dirs(Dir) -> [string()] | false %%% get_run_dirs(Dir) -> case filelib:wildcard(filename:join(Dir, "run.[1-2]*")) of @@ -3085,9 +3057,7 @@ get_run_dirs(Dir) -> end. %%%----------------------------------------------------------------- -%%% @spec xhtml(HTML, XHTML) -> HTML | XHTML -%%% -%%% @doc +%%% -spec xhtml(HTML, XHTML) -> HTML | XHTML %%% xhtml(HTML, XHTML) when is_function(HTML), is_function(XHTML) -> @@ -3102,9 +3072,7 @@ xhtml(HTML, XHTML) -> end. %%%----------------------------------------------------------------- -%%% @spec odd_or_even() -> "odd" | "even" -%%% -%%% @doc +%%% -spec odd_or_even() -> "odd" | "even" %%% odd_or_even() -> case get(odd_or_even) of @@ -3117,9 +3085,7 @@ odd_or_even() -> end. %%%----------------------------------------------------------------- -%%% @spec basic_html() -> true | false -%%% -%%% @doc +%%% -spec basic_html() -> true | false %%% basic_html() -> case application:get_env(common_test, basic_html) of @@ -3130,9 +3096,7 @@ basic_html() -> end. %%%----------------------------------------------------------------- -%%% @spec locate_priv_file(FileName) -> PrivFile -%%% -%%% @doc +%%% -spec locate_priv_file(FileName) -> PrivFile %%% locate_priv_file(FileName) -> {ok,CWD} = file:get_cwd(), @@ -3162,13 +3126,13 @@ locate_priv_file(FileName) -> end. %%%----------------------------------------------------------------- -%%% @spec make_relative(AbsDir, Cwd) -> RelDir +%%% -spec make_relative(AbsDir, Cwd) -> RelDir %%% -%%% @doc Return directory path to File (last element of AbsDir), which -%%% is the path relative to Cwd. Examples when Cwd == "/ldisk/test/logs": -%%% make_relative("/ldisk/test/logs/run/trace.log") -> "run/trace.log" -%%% make_relative("/ldisk/test/trace.log") -> "../trace.log" -%%% make_relative("/ldisk/test/logs/trace.log") -> "trace.log" +%%% Return directory path to File (last element of AbsDir), which +%%% is the path relative to Cwd. Examples when Cwd == "/ldisk/test/logs": +%%% make_relative("/ldisk/test/logs/run/trace.log") -> "run/trace.log" +%%% make_relative("/ldisk/test/trace.log") -> "../trace.log" +%%% make_relative("/ldisk/test/logs/trace.log") -> "trace.log" make_relative(AbsDir) -> {ok,Cwd} = file:get_cwd(), make_relative(AbsDir, Cwd). @@ -3192,11 +3156,9 @@ make_relative1(DirTs, CwdTs) -> Ups ++ DirTs. %%%----------------------------------------------------------------- -%%% @spec get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) +%%% -spec get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) %%% -> {Mode,Header,Footer} %%% -%%% @doc -%%% get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) -> get_ts_html_wrapper(TestName, undefined, PrintLabel, Cwd, TableCols, Encoding). @@ -3332,7 +3294,7 @@ insert_javascript({tablesorter,TableName, end, [{"CTDateSorter",DateCols}, {"CTTextSorter",TextCols}, {"CTValSorter",ValCols}]))), - Headers1 = string:substr(Headers, 1, length(Headers)-2), + Headers1 = string:trim(Headers, trailing, ",\n"), ["<script type=\"text/javascript\">\n", "// Parser for date format, e.g: Wed Jul 4 2012 11:24:15\n", diff --git a/lib/common_test/src/ct_master.erl b/lib/common_test/src/ct_master.erl index ef2aff69b7..fd33ee2280 100644 --- a/lib/common_test/src/ct_master.erl +++ b/lib/common_test/src/ct_master.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2017. All Rights Reserved. +%% Copyright Ericsson AB 2006-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,9 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc Distributed test execution control for Common Test. -%%% <p>This module exports functions for running Common Test nodes -%%% on multiple hosts in parallel.</p> -module(ct_master). -export([run/1,run/3,run/4]). @@ -45,50 +42,14 @@ blocked=[] }). -%%%----------------------------------------------------------------- -%%% @spec run_test(Node,Opts) -> ok -%%% Node = atom() -%%% Opts = [OptTuples] -%%% OptTuples = {config,CfgFiles} | {dir,TestDirs} | {suite,Suites} | -%%% {testcase,Cases} | {spec,TestSpecs} | {allow_user_terms,Bool} | -%%% {logdir,LogDir} | {event_handler,EventHandlers} | -%%% {silent_connections,Conns} | {cover,CoverSpecFile} | -%%% {cover_stop,Bool} | {userconfig, UserCfgFiles} -%%% CfgFiles = string() | [string()] -%%% TestDirs = string() | [string()] -%%% Suites = atom() | [atom()] -%%% Cases = atom() | [atom()] -%%% TestSpecs = string() | [string()] -%%% LogDir = string() -%%% EventHandlers = EH | [EH] -%%% EH = atom() | {atom(),InitArgs} | {[atom()],InitArgs} -%%% InitArgs = [term()] -%%% Conns = all | [atom()] -%%% -%%% @doc Tests are spawned on <code>Node</code> using <code>ct:run_test/1</code>. run_test(Node,Opts) -> run_test([{Node,Opts}]). -%%% @hidden run_test({Node,Opts}) -> run_test([{Node,Opts}]); run_test(NodeOptsList) when is_list(NodeOptsList) -> start_master(NodeOptsList). -%%%----------------------------------------------------------------- -%%% @spec run(TestSpecs,AllowUserTerms,InclNodes,ExclNodes) -> ok -%%% TestSpecs = string() | [SeparateOrMerged] -%%% SeparateOrMerged = string() | [string()] -%%% AllowUserTerms = bool() -%%% InclNodes = [atom()] -%%% ExclNodes = [atom()] -%%% -%%% @doc Tests are spawned on the nodes as specified in <code>TestSpecs</code>. -%%% Each specification in TestSpec will be handled separately. It is however -%%% possible to also specify a list of specifications that should be merged -%%% into one before the tests are executed. Any test without a particular node -%%% specification will also be executed on the nodes in <code>InclNodes</code>. -%%% Nodes in the <code>ExclNodes</code> list will be excluded from the test. run([TS|TestSpecs],AllowUserTerms,InclNodes,ExclNodes) when is_list(TS), is_list(InclNodes), is_list(ExclNodes) -> @@ -128,22 +89,9 @@ run(TS,AllowUserTerms,InclNodes,ExclNodes) when is_list(InclNodes), is_list(ExclNodes) -> run([TS],AllowUserTerms,InclNodes,ExclNodes). -%%%----------------------------------------------------------------- -%%% @spec run(TestSpecs,InclNodes,ExclNodes) -> ok -%%% TestSpecs = string() | [SeparateOrMerged] -%%% SeparateOrMerged = string() | [string()] -%%% InclNodes = [atom()] -%%% ExclNodes = [atom()] -%%% -%%% @equiv run(TestSpecs,false,InclNodes,ExclNodes) run(TestSpecs,InclNodes,ExclNodes) -> run(TestSpecs,false,InclNodes,ExclNodes). -%%%----------------------------------------------------------------- -%%% @spec run(TestSpecs) -> ok -%%% TestSpecs = string() | [SeparateOrMerged] -%%% -%%% @equiv run(TestSpecs,false,[],[]) run(TestSpecs=[TS|_]) when is_list(TS) -> run(TestSpecs,false,[],[]); run(TS) -> @@ -156,15 +104,6 @@ exclude_nodes([],RunSkipPerNode) -> RunSkipPerNode. -%%%----------------------------------------------------------------- -%%% @spec run_on_node(TestSpecs,AllowUserTerms,Node) -> ok -%%% TestSpecs = string() | [SeparateOrMerged] -%%% SeparateOrMerged = string() | [string()] -%%% AllowUserTerms = bool() -%%% Node = atom() -%%% -%%% @doc Tests are spawned on <code>Node</code> according to -%%% <code>TestSpecs</code>. run_on_node([TS|TestSpecs],AllowUserTerms,Node) when is_list(TS),is_atom(Node) -> case catch ct_testspec:collect_tests_from_file([TS],[Node], AllowUserTerms) of @@ -194,13 +133,6 @@ run_on_node([],_,_) -> run_on_node(TS,AllowUserTerms,Node) when is_atom(Node) -> run_on_node([TS],AllowUserTerms,Node). -%%%----------------------------------------------------------------- -%%% @spec run_on_node(TestSpecs,Node) -> ok -%%% TestSpecs = string() | [SeparateOrMerged] -%%% SeparateOrMerged = string() | [string()] -%%% Node = atom() -%%% -%%% @equiv run_on_node(TestSpecs,false,Node) run_on_node(TestSpecs,Node) -> run_on_node(TestSpecs,false,Node). @@ -264,64 +196,25 @@ run_all([],AllLogDirs,_,AllEvHs,_AllIncludes, ok. -%%%----------------------------------------------------------------- -%%% @spec abort() -> ok -%%% -%%% @doc Stops all running tests. abort() -> call(abort). -%%%----------------------------------------------------------------- -%%% @spec abort(Nodes) -> ok -%%% Nodes = atom() | [atom()] -%%% -%%% @doc Stops tests on specified nodes. abort(Nodes) when is_list(Nodes) -> call({abort,Nodes}); abort(Node) when is_atom(Node) -> abort([Node]). -%%%----------------------------------------------------------------- -%%% @spec progress() -> [{Node,Status}] -%%% Node = atom() -%%% Status = finished_ok | ongoing | aborted | {error,Reason} -%%% Reason = term() -%%% -%%% @doc Returns test progress. If <code>Status</code> is <code>ongoing</code>, -%%% tests are running on the node and have not yet finished. progress() -> call(progress). -%%%----------------------------------------------------------------- -%%% @spec get_event_mgr_ref() -> MasterEvMgrRef -%%% MasterEvMgrRef = atom() -%%% -%%% @doc <p>Call this function in order to get a reference to the -%%% CT master 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_master:get_event_mgr_ref(), my_ev_h, [])</c></p> get_event_mgr_ref() -> ?CT_MEVMGR_REF. -%%%----------------------------------------------------------------- -%%% @spec basic_html(Bool) -> ok -%%% Bool = true | false -%%% -%%% @doc If set to true, the ct_master logs will be written on a -%%% primitive html format, not using the Common Test CSS style -%%% sheet. basic_html(Bool) -> application:set_env(common_test_master, basic_html, Bool), ok. -%%%----------------------------------------------------------------- -%%% @spec esc_chars(Bool) -> ok -%%% Bool = true | false -%%% -%%% @doc If set to false, the ct_master logs will be written without -%%% special characters being escaped in the HTML logs. esc_chars(Bool) -> application:set_env(common_test_master, esc_chars, Bool), ok. @@ -340,7 +233,6 @@ start_master(NodeOptsList,EvHandlers,MasterLogDir,LogDirs,InitOptions,Specs) -> {Master,Result} -> Result end. -%%% @hidden init_master(Parent,NodeOptsList,EvHandlers,MasterLogDir,LogDirs, InitOptions,Specs) -> case whereis(ct_master) of @@ -687,7 +579,6 @@ refresh_logs([],Refreshed) -> %%%----------------------------------------------------------------- %%% NODE CONTROLLER, runs and controls tests on a test node. %%%----------------------------------------------------------------- -%%% @hidden init_node_ctrl(MasterPid,Cookie,Opts) -> %% make sure tests proceed even if connection to master is lost process_flag(trap_exit, true), @@ -742,7 +633,6 @@ start_ct_event() -> %%%----------------------------------------------------------------- %%% Event handling %%%----------------------------------------------------------------- -%%% @hidden status(MasterPid,Event=#event{name=start_make}) -> call(MasterPid,Event); status(MasterPid,Event=#event{name=finished_make}) -> @@ -809,7 +699,7 @@ filter_accessible(InitOptions, Inaccessible)-> start_nodes(InitOptions)-> lists:foreach(fun({NodeName, Options})-> - [NodeS,HostS]=string:tokens(atom_to_list(NodeName), "@"), + [NodeS,HostS]=string:lexemes(atom_to_list(NodeName), "@"), Node=list_to_atom(NodeS), Host=list_to_atom(HostS), HasNodeStart = lists:keymember(node_start, 1, Options), diff --git a/lib/common_test/src/ct_master_event.erl b/lib/common_test/src/ct_master_event.erl index bd4d1efc92..a6ec5a7a75 100644 --- a/lib/common_test/src/ct_master_event.erl +++ b/lib/common_test/src/ct_master_event.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2017. All Rights Reserved. +%% Copyright Ericsson AB 2006-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,13 +18,13 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework Event Handler +%%% Common Test Framework Event Handler %%% -%%% <p>This module implements an event handler that the CT Master +%%% This module implements an event handler that the CT Master %%% uses to handle status and progress notifications sent to the %%% master node during test runs. This module may be used as a %%% template for other event handlers that can be plugged in to -%%% handle logging and reporting on the master node.</p> +%%% handle logging and reporting on the master node. -module(ct_master_event). -behaviour(gen_event). diff --git a/lib/common_test/src/ct_master_logs.erl b/lib/common_test/src/ct_master_logs.erl index c4bb2cc69f..ea6f93b565 100644 --- a/lib/common_test/src/ct_master_logs.erl +++ b/lib/common_test/src/ct_master_logs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2017. All Rights Reserved. +%% Copyright Ericsson AB 2006-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,10 +18,10 @@ %% %CopyrightEnd% %% -%%% @doc Logging functionality for Common Test Master. +%%% Logging functionality for Common Test Master. %%% -%%% <p>This module implements a logger for the master -%%% node.</p> +%%% This module implements a logger for the master +%%% node. -module(ct_master_logs). -export([start/2, make_all_runs_index/0, log/3, nodedir/2, @@ -298,7 +298,7 @@ sort_all_runs(Dirs) -> %% "YYYY-MM-DD_HH.MM.SS" KeyList = lists:map(fun(Dir) -> - case lists:reverse(string:tokens(Dir,[$.,$_])) of + case lists:reverse(string:lexemes(Dir,[$.,$_])) of [SS,MM,HH,Date|_] -> {{Date,HH,MM,SS},Dir}; _Other -> @@ -313,18 +313,8 @@ runentry(Dir) -> {MasterStr,NodesStr} = case read_details_file(Dir) of {Master,Nodes} when is_list(Nodes) -> - [_,Host] = string:tokens(atom_to_list(Master),"@"), - NodesList = - lists:reverse(lists:map(fun(N) -> - atom_to_list(N) ++ ", " - end,Nodes)), - case NodesList of - [N|NListR] -> - N1 = string:sub_string(N,1,length(N)-2), - {Host,lists:flatten(lists:reverse([N1|NListR]))}; - [] -> - {Host,""} - end; + [_,Host] = string:lexemes(atom_to_list(Master),"@"), + {Host,lists:concat(lists:join(", ",Nodes))}; _Error -> {"unknown",""} end, @@ -349,7 +339,7 @@ all_runs_header() -> xhtml("", "</tr></thead>\n<tbody>\n")]]. timestamp(Dir) -> - [S,Min,H,D,M,Y|_] = lists:reverse(string:tokens(Dir,".-_")), + [S,Min,H,D,M,Y|_] = lists:reverse(string:lexemes(Dir,".-_")), [S1,Min1,H1,D1,M1,Y1] = [list_to_integer(N) || N <- [S,Min,H,D,M,Y]], format_time({{Y1,M1,D1},{H1,Min1,S1}}). diff --git a/lib/common_test/src/ct_master_status.erl b/lib/common_test/src/ct_master_status.erl index b27fdd341e..cb01220121 100644 --- a/lib/common_test/src/ct_master_status.erl +++ b/lib/common_test/src/ct_master_status.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2017. All Rights Reserved. +%% Copyright Ericsson AB 2006-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,12 +18,12 @@ %% %CopyrightEnd% %% -%%% @doc Logging functionality for Common Test Master. +%%% doc Logging functionality for Common Test Master. %%% -%%% <p>This module keeps a list of <code>{Node,Status}</code> +%%% This module keeps a list of {Node,Status} %%% tuples. It is possible to anytime during a test run get %%% a snapshot of the test status. The module is an event -%%% handler for the master event manager.</p> +%%% handler for the master event manager. -module(ct_master_status). -behaviour(gen_event). diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl index 2c4b97df20..29188a648e 100644 --- a/lib/common_test/src/ct_netconfc.erl +++ b/lib/common_test/src/ct_netconfc.erl @@ -1467,7 +1467,7 @@ decode_data(Other) -> {error,{unexpected_rpc_reply,Other}}. get_qualified_name(Tag) -> - case string:tokens(atom_to_list(Tag),":") of + case string:lexemes(atom_to_list(Tag),":") of [TagStr] -> {[],TagStr}; [PrefixStr,TagStr] -> {PrefixStr,TagStr} end. diff --git a/lib/common_test/src/ct_netconfc.hrl b/lib/common_test/src/ct_netconfc.hrl index 5eeeafa318..1d81c762ba 100644 --- a/lib/common_test/src/ct_netconfc.hrl +++ b/lib/common_test/src/ct_netconfc.hrl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012-2016. All Rights Reserved. +%% Copyright Ericsson AB 2012-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. @@ -24,9 +24,7 @@ %% This file defines constant values and records used by the %% netconf client ct_netconfc. %% -%% @author Support -%% @doc Netconf Client Interface. -%% @end +%% Netconf Client Interface. %%---------------------------------------------------------------------- %%---------------------------------------------------------------------- diff --git a/lib/common_test/src/ct_property_test.erl b/lib/common_test/src/ct_property_test.erl index 94ccb59af9..f51f454d08 100644 --- a/lib/common_test/src/ct_property_test.erl +++ b/lib/common_test/src/ct_property_test.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. @@ -28,46 +28,6 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%% @doc EXPERIMENTAL support in common-test for calling property based tests. -%%% -%%% <p>This module is a first step towards running Property Based testing in the -%%% Common Test framework. A property testing tool like QuickCheck or PropEr is -%%% assumed to be installed.</p> -%%% -%%% <p>The idea is to have a common_test testsuite calling a property testing -%%% tool with special property test suites as defined by that tool. In this manual -%%% we assume the usual Erlang Application directory structure. The tests are -%%% collected in the application's <c>test</c> directory. The test directory -%%% has a sub-directory called <c>property_test</c> where everything needed for -%%% the property tests are collected.</p> -%%% -%%% <p>A typical ct test suite using <c>ct_property_test</c> is organized as follows: -%%% </p> -%%% ``` -%%% -include_lib("common_test/include/ct.hrl"). -%%% -%%% all() -> [prop_ftp_case]. -%%% -%%% init_per_suite(Config) -> -%%% ct_property_test:init_per_suite(Config). -%%% -%%% %%%---- test case -%%% prop_ftp_case(Config) -> -%%% ct_property_test:quickcheck( -%%% ftp_simple_client_server:prop_ftp(Config), -%%% Config -%%% ). -%%% ''' -%%% -%%% <warning> -%%% <p> -%%% This is experimental code which may be changed or removed -%%% anytime without any warning. -%%% </p> -%%% </warning> -%%% -%%% @end - -module(ct_property_test). %% API @@ -76,19 +36,6 @@ -include_lib("common_test/include/ct.hrl"). -%%%----------------------------------------------------------------- -%%% @spec init_per_suite(Config) -> Config | {skip,Reason} -%%% -%%% @doc Initializes Config for property testing. -%%% -%%% <p>The function investigates if support is available for either Quickcheck, PropEr, -%%% or Triq. -%%% The options <c>{property_dir,AbsPath}</c> and -%%% <c>{property_test_tool,Tool}</c> is set in the Config returned.</p> -%%% <p>The function is intended to be called in the init_per_suite in the test suite.</p> -%%% <p>The property tests are assumed to be in the subdirectory <c>property_test</c>.</p> -%%% @end - init_per_suite(Config) -> case which_module_exists([eqc,proper,triq]) of {ok,ToolModule} -> @@ -108,14 +55,6 @@ init_per_suite(Config) -> {skip, "No property testing tool found"} end. -%%%----------------------------------------------------------------- -%%% @spec quickcheck(Property, Config) -> true | {fail,Reason} -%%% -%%% @doc Call quickcheck and return the result in a form suitable for common_test. -%%% -%%% <p>The function is intended to be called in the test cases in the test suite.</p> -%%% @end - quickcheck(Property, Config) -> Tool = proplists:get_value(property_test_tool,Config), F = function_name(quickcheck, Tool), diff --git a/lib/common_test/src/ct_release_test.erl b/lib/common_test/src/ct_release_test.erl index 551a7e06d7..60d17f43dc 100644 --- a/lib/common_test/src/ct_release_test.erl +++ b/lib/common_test/src/ct_release_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2014-2017. All Rights Reserved. +%% Copyright Ericsson AB 2014-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,7 +18,7 @@ %% %CopyrightEnd% %% %%----------------------------------------------------------------- -%% @doc EXPERIMENTAL support for testing of upgrade. +%% EXPERIMENTAL support for testing of upgrade. %% %% This is a library module containing support for test of release %% related activities in one or more applications. Currenty it @@ -27,7 +27,7 @@ %% == Configuration == %% %% In order to find version numbers of applications to upgrade from, -%% `{@module}' needs to access and start old OTP +%% ct_release_test needs to access and start old OTP %% releases. A `common_test' configuration file can be used for %% specifying the location of such releases, for example: %% @@ -39,48 +39,45 @@ %% The configuration file should preferably point out the latest patch %% level on each major release. %% -%% If no such configuration file is given, {@link init/1} will return -%% `{skip,Reason}' and any attempt at running {@link upgrade/4} +%% If no such configuration file is given, init/1 will return +%% {skip,Reason} and any attempt at running upgrade/4 %% will fail. %% %% == Callback functions == %% -%% The following functions should be exported from a {@module} +%% The following functions should be exported from a ct_release_test %% callback module. %% %% All callback functions are called on the node where the upgrade is %% executed. %% -%% <dl> -%% <dt>Module:upgrade_init(CtData,State) -> NewState</dt> -%% <dd>Types: +%% Module:upgrade_init(CtData,State) -> NewState +%% Types: %% -%% <b><code>CtData = {@link ct_data()}</code></b><br/> -%% <b><code>State = NewState = cb_state()</code></b> +%% CtData = ct_data() +%% State = NewState = cb_state() %% %% Initialyze system before upgrade test starts. %% %% This function is called before the upgrade is started. All -%% applications given in {@link upgrade/4} are already started by +%% applications given in upgrade/4 are already started by %% the boot script, so this callback is intended for additional %% initialization, if necessary. %% -%% <code>CtData</code> is an opaque data structure which shall be used -%% in any call to <code>ct_release_test</code> inside the callback. +%% CtData is an opaque data structure which shall be used +%% in any call to ct_release_test inside the callback. %% %% Example: %% -%% ``` %% upgrade_init(CtData,State) -> %% {ok,{FromVsn,ToVsn}} = ct_release_test:get_app_vsns(CtData,myapp), -%% open_connection(State).''' -%% </dd> +%% open_connection(State). %% -%% <dt>Module:upgrade_upgraded(CtData,State) -> NewState</dt> -%% <dd>Types: +%% Module:upgrade_upgraded(CtData,State) -> NewState +%% Types: %% -%% <b><code>CtData = {@link ct_data()}</code></b><br/> -%% <b><code>State = NewState = cb_state()</code></b> +%% CtData = ct_data() +%% State = NewState = cb_state() %% %% Check that upgrade was successful. %% @@ -89,21 +86,19 @@ %% been made permanent. It allows application specific checks to %% ensure that the upgrade was successful. %% -%% <code>CtData</code> is an opaque data structure which shall be used -%% in any call to <code>ct_release_test</code> inside the callback. +%% CtData is an opaque data structure which shall be used +%% in any call to ct_release_test inside the callback. %% %% Example: %% -%% ``` %% upgrade_upgraded(CtData,State) -> -%% check_connection_still_open(State).''' -%% </dd> +%% check_connection_still_open(State). %% -%% <dt>Module:upgrade_downgraded(CtData,State) -> NewState</dt> -%% <dd>Types: +%% Module:upgrade_downgraded(CtData,State) -> NewState +%% Types: %% -%% <b><code>CtData = {@link ct_data()}</code></b><br/> -%% <b><code>State = NewState = cb_state()</code></b> +%% CtData = ct_data() +%% State = NewState = cb_state() %% %% Check that downgrade was successful. %% @@ -112,17 +107,13 @@ %% made permanent. It allows application specific checks to ensure %% that the downgrade was successful. %% -%% <code>CtData</code> is an opaque data structure which shall be used -%% in any call to <code>ct_release_test</code> inside the callback. +%% CtData is an opaque data structure which shall be used +%% in any call to ct_release_test inside the callback. %% %% Example: %% -%% ``` %% upgrade_downgraded(CtData,State) -> -%% check_connection_closed(State).''' -%% </dd> -%% </dl> -%% @end +%% check_connection_closed(State). %%----------------------------------------------------------------- -module(ct_release_test). @@ -152,7 +143,7 @@ Config :: config(), Result :: config() | SkipOrFail, SkipOrFail :: {skip,Reason} | {fail,Reason}. -%% @doc Initialize `{@module}'. +%% Initialize ct_release_test. %% %% This function can be called from any of the %% `init_per_*' functions in the test suite. It updates @@ -168,9 +159,8 @@ %% %% Example: %% -%% ``` %% init_per_suite(Config) -> -%% ct_release_test:init(Config).''' +%% ct_release_test:init(Config). %% init(Config) -> try init_upgrade_test() of @@ -194,47 +184,42 @@ init(Config) -> Callback :: {module(),InitState}, InitState :: cb_state(), Config :: config(). -%% @doc Test upgrade of the given application(s). +%% Test upgrade of the given application(s). %% %% This function can be called from a test case. It requires that -%% `Config' has been initialized by calling {@link -%% init/1} prior to this, for example from `init_per_suite/1'. +%% `Config' has been initialized by calling +%% init/1 prior to this, for example from `init_per_suite/1'. %% %% Upgrade tests are performed as follows: %% -%% <ol> -%% <li>Figure out which OTP release to test upgrade +%% Figure out which OTP release to test upgrade %% from. Start a node running that release and find the %% application versions on that node. Terminate the -%% node.</li> -%% <li>Figure out all dependencies for the applications under -%% test.</li> -%% <li>Create a release containing the core +%% node. +%% Figure out all dependencies for the applications under +%% test. +%% Create a release containing the core %% applications `kernel', `stdlib' and `sasl' %% in addition to the application(s) under test and all %% dependencies of these. The versions of the applications %% under test will be the ones found on the OTP release to %% upgrade from. The versions of all other applications will %% be those found on the current node, i.e. the common_test -%% node. This is the "From"-release.</li> -%% <li>Create another release containing the same +%% node. This is the "From"-release. +%% Create another release containing the same %% applications as in the previous step, but with all %% application versions taken from the current node. This is -%% the "To"-release.</li> -%% <li>Install the "From"-release and start a new node -%% running this release.</li> -%% <li>Perform the upgrade test and allow customized +%% the "To"-release. +%% Install the "From"-release and start a new node +%% running this release. +%% Perform the upgrade test and allow customized %% control by using callbacks: -%% <ol> -%% <li>Callback: `upgrade_init/2'</li> -%% <li>Unpack the new release</li> -%% <li>Install the new release</li> -%% <li>Callback: `upgrade_upgraded/2'</li> -%% <li>Install the original release</li> -%% <li>Callback: `upgrade_downgraded/2'</li> -%% </ol> -%% </li> -%% </ol> +%% Callback: `upgrade_init/2' +%% Unpack the new release +%% Install the new release +%% Callback: `upgrade_upgraded/2' +%% Install the original release +%% Callback: `upgrade_downgraded/2' %% %% `App' or `Apps' %% specifies the applications under test, i.e. the applications @@ -244,27 +229,25 @@ init(Config) -> %% %% `Level' specifies which OTP release to %% pick the "From" versions from. -%% <dl> -%% <dt>major</dt> -%% <dd>From verions are picked from the previous major +%% major +%% From verions are picked from the previous major %% release. For example, if the test is run on an OTP-17 -%% node, `{@module}' will pick the application +%% node, ct_release_test will pick the application %% "From" versions from an OTP installation running OTP -%% R16B.</dd> +%% R16B. %% -%% <dt>minor</dt> -%% <dd>From verions are picked from the current major +%% minor +%% From verions are picked from the current major %% release. For example, if the test is run on an OTP-17 -%% node, `{@module}' will pick the application +%% node, ct_release_test will pick the application %% "From" versions from an OTP installation running an -%% earlier patch level of OTP-17.</dd> -%% </dl> +%% earlier patch level of OTP-17. %% %% The application "To" versions are allways picked from the %% current node, i.e. the common_test node. %% %% `Callback' specifies the module (normally the -%% test suite) which implements the {@section Callback functions}, and +%% test suite) which implements the Callback functions, and %% the initial value of the `State' variable used in these %% functions. %% @@ -273,10 +256,8 @@ init(Config) -> %% %% Example: %% -%% ``` %% minor_upgrade(Config) -> %% ct_release_test:upgrade(ssl,minor,{?MODULE,[]},Config). -%% ''' %% upgrade(App,Level,Callback,Config) when is_atom(App) -> upgrade([App],Level,Callback,Config); @@ -318,10 +299,10 @@ upgrade(Apps,Level,Callback,Config) -> -spec cleanup(Config) -> Result when Config :: config(), Result :: config(). -%% @doc Clean up after tests. +%% Clean up after tests. %% %% This function shall be called from the `end_per_*' function -%% complementing the `init_per_*' function where {@link init/1} +%% complementing the `init_per_*' function where init/1 %% is called. %% %% It cleans up after the test, for example kills hanging @@ -329,9 +310,8 @@ upgrade(Apps,Level,Callback,Config) -> %% %% Example: %% -%% ``` %% end_per_suite(Config) -> -%% ct_release_test:cleanup(Config).''' +%% ct_release_test:cleanup(Config). %% cleanup(Config) -> AllNodes = [node_name(?testnode)|nodes()], @@ -352,15 +332,15 @@ cleanup(Config) -> From :: string(), To :: string(), Reason :: {app_not_found,App}. -%% @doc Get versions involved in this upgrade for the given application. +%% Get versions involved in this upgrade for the given application. %% %% This function can be called from inside any of the callback %% functions. It returns the old (From) and new (To) versions involved %% in the upgrade/downgrade test for the given application. %% -%% <code>CtData</code> must be the first argument received in the +%% CtData must be the first argument received in the %% calling callback function - an opaque data structure set by -%% <code>ct_release_tests</code>. +%% ct_release_tests. get_app_vsns(#ct_data{from=FromApps,to=ToApps},App) -> case {lists:keyfind(App,1,FromApps),lists:keyfind(App,1,ToApps)} of {{App,FromVsn,_},{App,ToVsn,_}} -> @@ -380,16 +360,16 @@ get_app_vsns(#ct_data{from=FromApps,to=ToApps},App) -> Down :: [Instr], Instr :: term(), Reason :: {app_not_found,App} | {vsn_not_found,{App,From}}. -%% @doc Get appup instructions for the given application. +%% Get appup instructions for the given application. %% %% This function can be called from inside any of the callback %% functions. It reads the appup file for the given application and %% returns the instructions for upgrade and downgrade for the versions %% in the test. %% -%% <code>CtData</code> must be the first argument received in the +%% CtData must be the first argument received in the %% calling callback function - an opaque data structure set by -%% <code>ct_release_tests</code>. +%% ct_release_tests. %% %% See reference manual for appup files for types definitions for the %% instructions. @@ -817,7 +797,7 @@ get_runtime_deps([App|Apps],StartApps,Acc,Visited) -> RuntimeDeps = lists:flatmap( fun(Str) -> - [RuntimeAppStr,_] = string:tokens(Str,"-"), + [RuntimeAppStr,_] = string:lexemes(Str,"-"), RuntimeApp = list_to_atom(RuntimeAppStr), case {lists:keymember(RuntimeApp,1,Acc), lists:member(RuntimeApp,StartApps)} of diff --git a/lib/common_test/src/ct_repeat.erl b/lib/common_test/src/ct_repeat.erl index 177ef37d1f..8b1c7d47bb 100644 --- a/lib/common_test/src/ct_repeat.erl +++ b/lib/common_test/src/ct_repeat.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2017. All Rights Reserved. +%% Copyright Ericsson AB 2007-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,14 +18,14 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework module that handles repeated test runs +%%% doc Common Test Framework module that handles repeated test runs %%% -%%% <p>This module exports functions for repeating tests. The following +%%% This module exports functions for repeating tests. The following %%% start flags (or equivalent ct:run_test/1 options) are supported: %%% -until <StopTime>, StopTime = YYMoMoDDHHMMSS | HHMMSS %%% -duration <DurTime>, DurTime = HHMMSS %%% -force_stop [skip_rest] -%%% -repeat <N>, N = integer()</p> +%%% -repeat <N>, N = integer() -module(ct_repeat). diff --git a/lib/common_test/src/ct_rpc.erl b/lib/common_test/src/ct_rpc.erl index b4a0bc9d74..cef5ad14e5 100644 --- a/lib/common_test/src/ct_rpc.erl +++ b/lib/common_test/src/ct_rpc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-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,8 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc Common Test specific layer on Erlang/OTP rpc. - -module(ct_rpc). %%% API @@ -29,49 +27,12 @@ %%%========================================================================= %%% API %%%========================================================================= -%%% @spec app_node(App, Candidates) -> NodeName -%%% -%%% App = atom() -%%% Candidates = [NodeName] -%%% NodeName = atom() -%%% -%%% @doc From a set of candidate nodes determines which of them is -%%% running the application App. If none of the candidate nodes -%%% is running the application the function will make the test case -%%% calling this function fail. This function is the same as calling -%%% <code>app_node(App, Candidates, true)</code>. -%%% app_node(App, Candidates) -> app_node(App, Candidates, true, []). -%%% @spec app_node(App, Candidates, FailOnBadRPC) -> NodeName -%%% -%%% App = atom() -%%% Candidates = [NodeName] -%%% NodeName = atom() -%%% FailOnBadRPC = true | false -%%% -%%% @doc Same as <code>app_node/2</code> only the <code>FailOnBadRPC</code> -%%% argument will determine if the search for a candidate node should -%%% stop or not if <code>badrpc</code> is received at some point. -%%% app_node(App, Candidates, FailOnBadRPC) -> app_node(App, Candidates, FailOnBadRPC, []). -%%% @spec app_node(App, Candidates, FailOnBadRPC, Cookie) -> NodeName -%%% -%%% App = atom() -%%% Candidates = [NodeName] -%%% NodeName = atom() -%%% FailOnBadRPC = true | false -%%% Cookie = atom() -%%% -%%% @doc Same as <code>app_node/2</code> only the <code>FailOnBadRPC</code> -%%% argument will determine if the search for a candidate node should -%%% stop or not if <code>badrpc</code> is received at some point. -%%% The cookie on the client node will be set to <code>Cookie</code> -%%% for this rpc operation (use to match the server node cookie). -%%% app_node(App, [], _, _) -> ct:fail({application_not_running, App}); @@ -96,49 +57,12 @@ app_node(App, _Candidates = [CandidateNode | Nodes], FailOnBadRPC, Cookie) -> end end. -%%% @spec call(Node, Module, Function, Args) -> term() | {badrpc, Reason} -%%% -%%% @doc Same as call(Node, Module, Function, Args, infinity) -%%% call(Node, Module, Function, Args) -> call(Node, Module, Function, Args, infinity, []). -%%% @spec call(Node, Module, Function, Args, TimeOut) -> -%%% term() | {badrpc, Reason} -%%% Node = NodeName | {Fun, FunArgs} -%%% Fun = fun() -%%% FunArgs = term() -%%% NodeName = atom() -%%% Module = atom() -%%% Function = atom() -%%% Args = [term()] -%%% Reason = timeout | term() -%%% -%%% @doc Evaluates apply(Module, Function, Args) on the node Node. -%%% Returns whatever Function returns or {badrpc, Reason} if the -%%% remote procedure call fails. If Node is {Fun, FunArgs} applying -%%% Fun to FunArgs should return a node name. call(Node, Module, Function, Args, TimeOut) -> call(Node, Module, Function, Args, TimeOut, []). -%%% @spec call(Node, Module, Function, Args, TimeOut, Cookie) -> -%%% term() | {badrpc, Reason} -%%% Node = NodeName | {Fun, FunArgs} -%%% Fun = fun() -%%% FunArgs = term() -%%% NodeName = atom() -%%% Module = atom() -%%% Function = atom() -%%% Args = [term()] -%%% Reason = timeout | term() -%%% Cookie = atom() -%%% -%%% @doc Evaluates apply(Module, Function, Args) on the node Node. -%%% Returns whatever Function returns or {badrpc, Reason} if the -%%% remote procedure call fails. If Node is {Fun, FunArgs} applying -%%% Fun to FunArgs should return a node name. -%%% The cookie on the client node will be set to <code>Cookie</code> -%%% for this rpc operation (use to match the server node cookie). call({Fun, FunArgs}, Module, Function, Args, TimeOut, Cookie) -> Node = Fun(FunArgs), call(Node, Module, Function, Args, TimeOut, Cookie); @@ -148,42 +72,9 @@ call(Node, Module, Function, Args, TimeOut, Cookie) when is_atom(Node) -> _ = set_the_cookie(Cookie0), Result. -%%% @spec cast(Node, Module, Function, Args) -> ok -%%% Node = NodeName | {Fun, FunArgs} -%%% Fun = fun() -%%% FunArgs = term() -%%% NodeName = atom() -%%% Module = atom() -%%% Function = atom() -%%% Args = [term()] -%%% Reason = timeout | term() -%%% -%%% @doc Evaluates apply(Module, Function, Args) on the node Node. -%%% No response is delivered and the process which makes the call is -%%% not suspended until the evaluation is compleated as in the case of -%%% call/[3,4]. If Node is {Fun, FunArgs} applying -%%% Fun to FunArgs should return a node name. cast(Node, Module, Function, Args) -> cast(Node, Module, Function, Args, []). -%%% @spec cast(Node, Module, Function, Args, Cookie) -> ok -%%% Node = NodeName | {Fun, FunArgs} -%%% Fun = fun() -%%% FunArgs = term() -%%% NodeName = atom() -%%% Module = atom() -%%% Function = atom() -%%% Args = [term()] -%%% Reason = timeout | term() -%%% Cookie = atom() -%%% -%%% @doc Evaluates apply(Module, Function, Args) on the node Node. -%%% No response is delivered and the process which makes the call is -%%% not suspended until the evaluation is compleated as in the case of -%%% call/[3,4]. If Node is {Fun, FunArgs} applying -%%% Fun to FunArgs should return a node name. -%%% The cookie on the client node will be set to <code>Cookie</code> -%%% for this rpc operation (use to match the server node cookie). cast({Fun, FunArgs}, Module, Function, Args, Cookie) -> Node = Fun(FunArgs), cast(Node, Module, Function, Args, Cookie); @@ -196,7 +87,6 @@ cast(Node, Module, Function, Args, Cookie) when is_atom(Node) -> %%%---------- Internal ----------- -%%% @hidden set_the_cookie([]) -> []; set_the_cookie(Cookie) -> diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 05b1e70098..c9d406f1fd 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2017. All Rights Reserved. +%% Copyright Ericsson AB 2004-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,11 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework test execution control module. -%%% -%%% <p>This module exports functions for installing and running tests -%%% withing the Common Test Framework.</p> - -module(ct_run). %% Script interface @@ -84,17 +79,6 @@ tests, starter}). -%%%----------------------------------------------------------------- -%%% @spec script_start() -> term() -%%% -%%% @doc Start tests via the ct_run program or script. -%%% -%%% <p>Example:<br/><code>./ct_run -config config.ctc -dir -%%% $TEST_DIR</code></p> -%%% -%%% <p>Example:<br/><code>./ct_run -config config.ctc -suite -%%% $SUITE_PATH/$SUITE_NAME [-case $CASE_NAME]</code></p> -%%% script_start() -> process_flag(trap_exit, true), Init = init:get_arguments(), @@ -147,7 +131,7 @@ script_start(Args) -> CTVsn = case filename:basename(code:lib_dir(common_test)) of CTBase when is_list(CTBase) -> - case string:tokens(CTBase, "-") of + case string:lexemes(CTBase, "-") of ["common_test",Vsn] -> " v"++Vsn; _ -> "" end @@ -317,7 +301,7 @@ script_start1(Parent, Args) -> {undefined,InclDirs}; CtInclPath -> AllInclDirs = - string:tokens(CtInclPath,[$:,$ ,$,]) ++ InclDirs, + string:lexemes(CtInclPath,[$:,$ ,$,]) ++ InclDirs, application:set_env(common_test, include, AllInclDirs), {undefined,AllInclDirs} end; @@ -442,11 +426,9 @@ script_start2(Opts = #opts{vts = undefined, TestSpecData -> execute_all_specs(TestSpecData, Opts, Args, []) catch - throw:{error,Reason} -> - StackTrace = erlang:get_stacktrace(), + throw:{error,Reason}:StackTrace -> {error,{invalid_testspec,{Reason,StackTrace}}}; - _:Reason -> - StackTrace = erlang:get_stacktrace(), + _:Reason:StackTrace -> {error,{invalid_testspec,{Reason,StackTrace}}} end; [] -> @@ -801,9 +783,6 @@ script_start4(#opts{shell = true, cover = Cover}, _) -> script_start4(Opts = #opts{tests = Tests}, Args) -> do_run(Tests, [], Opts, Args). -%%%----------------------------------------------------------------- -%%% @spec script_usage() -> ok -%%% @doc Print usage information for <code>ct_run</code>. script_usage() -> io:format("\nUsage:\n\n"), io:format("Run tests from command line:\n\n" @@ -887,9 +866,6 @@ script_usage() -> "\n\t [-basic_html]" "\n\t [-no_esc_chars]\n\n"). -%%%----------------------------------------------------------------- -%%% @hidden -%%% @equiv ct:install/1 install(Opts) -> install(Opts, "."). @@ -933,15 +909,6 @@ install(Opts, LogDir) -> variables_file_name(Dir) -> filename:join(Dir, "variables-"++atom_to_list(node())). -%%%----------------------------------------------------------------- -%%% @spec run_test(Opts) -> Result -%%% Opts = [tuple()] -%%% Result = [TestResult] | {error,Reason} -%%% -%%% @doc Start tests from the erlang shell or from an erlang program. -%%% @equiv ct:run_test/1 -%%%----------------------------------------------------------------- - run_test(StartOpt) when is_tuple(StartOpt) -> run_test([StartOpt]); @@ -1101,7 +1068,7 @@ run_test2(StartOpts) -> application:set_env(common_test, include, InclDirs), {undefined,InclDirs}; CtInclPath -> - InclDirs1 = string:tokens(CtInclPath, [$:,$ ,$,]), + InclDirs1 = string:lexemes(CtInclPath, [$:,$ ,$,]), AllInclDirs = InclDirs1++InclDirs, application:set_env(common_test, include, AllInclDirs), {undefined,AllInclDirs} @@ -1211,11 +1178,9 @@ run_spec_file(Relaxed, TestSpecData -> run_all_specs(TestSpecData, Opts, StartOpts, []) catch - throw:{error,CTReason} -> - StackTrace = erlang:get_stacktrace(), + throw:{error,CTReason}:StackTrace -> exit({error,{invalid_testspec,{CTReason,StackTrace}}}); - _:CTReason -> - StackTrace = erlang:get_stacktrace(), + _:CTReason:StackTrace -> exit({error,{invalid_testspec,{CTReason,StackTrace}}}) end. @@ -1431,14 +1396,6 @@ run_dir(Opts = #opts{logdir = LogDir, exit({error,{incorrect_start_options,{Dir,Suite,GsAndCs}}}) end. -%%%----------------------------------------------------------------- -%%% @spec run_testspec(TestSpec) -> Result -%%% TestSpec = [term()] -%%% -%%% @doc Run test specified by <code>TestSpec</code>. The terms are -%%% the same as those used in test specification files. -%%% @equiv ct:run_testspec/1 -%%%----------------------------------------------------------------- run_testspec(TestSpec) -> CTPid = spawn(run_testspec1_fun(TestSpec)), Ref = monitor(process, CTPid), @@ -1490,7 +1447,7 @@ run_testspec2(TestSpec) -> false -> Opts#opts.include; CtInclPath -> - EnvInclude = string:tokens(CtInclPath, [$:,$ ,$,]), + EnvInclude = string:lexemes(CtInclPath, [$:,$ ,$,]), EnvInclude++Opts#opts.include end, application:set_env(common_test, include, AllInclude), @@ -1638,9 +1595,6 @@ delistify([E]) -> E; delistify(E) -> E. -%%%----------------------------------------------------------------- -%%% @hidden -%%% @equiv ct:run/3 run(TestDir, Suite, Cases) -> case install([]) of ok -> @@ -1649,9 +1603,6 @@ run(TestDir, Suite, Cases) -> Error end. -%%%----------------------------------------------------------------- -%%% @hidden -%%% @equiv ct:run/2 run(TestDir, Suite) when is_list(TestDir), is_integer(hd(TestDir)) -> case install([]) of ok -> @@ -1660,9 +1611,6 @@ run(TestDir, Suite) when is_list(TestDir), is_integer(hd(TestDir)) -> Error end. -%%%----------------------------------------------------------------- -%%% @hidden -%%% @equiv ct:run/1 run(TestDirs) -> case install([]) of ok -> @@ -1961,7 +1909,8 @@ auto_compile(TestSuites) -> SuiteMakeErrors = lists:flatmap(fun({TestDir,Suite} = TS) -> case run_make(suites, TestDir, - Suite, UserInclude) of + Suite, UserInclude, + [nowarn_export_all]) of {error,{make_failed,Bad}} -> [{TS,Bad}]; {error,_} -> @@ -1979,7 +1928,7 @@ auto_compile(TestSuites) -> case lists:member(Dir, Done) of false -> Failed1 = - case run_make(helpmods, Dir, Suite, UserInclude) of + case run_make(helpmods, Dir, Suite, UserInclude, []) of {error,{make_failed,BadMods}} -> [{{Dir,all},BadMods}|Failed]; {error,_} -> @@ -2072,16 +2021,9 @@ get_bad_suites([], BadSuites) -> BadSuites. - -%%%----------------------------------------------------------------- -%%% @hidden -%%% @equiv ct:step/3 step(TestDir, Suite, Case) -> step(TestDir, Suite, Case, []). -%%%----------------------------------------------------------------- -%%% @hidden -%%% @equiv ct:step/4 step(TestDir, Suite, Case, Opts) when is_list(TestDir), is_atom(Suite), is_atom(Case), Suite =/= all, Case =/= all -> @@ -2728,12 +2670,12 @@ get_name(Dir) -> run_make(TestDir, Mod, UserInclude) -> - run_make(suites, TestDir, Mod, UserInclude). + run_make(suites, TestDir, Mod, UserInclude, [nowarn_export_all]). -run_make(Targets, TestDir0, Mod, UserInclude) when is_list(Mod) -> - run_make(Targets, TestDir0, list_to_atom(Mod), UserInclude); +run_make(Targets, TestDir0, Mod, UserInclude, COpts) when is_list(Mod) -> + run_make(Targets, TestDir0, list_to_atom(Mod), UserInclude, COpts); -run_make(Targets, TestDir0, Mod, UserInclude) -> +run_make(Targets, TestDir0, Mod, UserInclude, COpts) -> case locate_test_dir(TestDir0, Mod) of {ok,TestDir} -> %% send a start_make notification which may suspend @@ -2748,7 +2690,7 @@ run_make(Targets, TestDir0, Mod, UserInclude) -> XmerlInclude = get_dir(xmerl, "include"), ErlFlags = UserInclude ++ [{i,CtInclude}, {i,XmerlInclude}, - debug_info], + debug_info] ++ COpts, Result = if Mod == all ; Targets == helpmods -> case (catch ct_make:all([noexec|ErlFlags])) of diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl index b39195483b..dde33440be 100644 --- a/lib/common_test/src/ct_slave.erl +++ b/lib/common_test/src/ct_slave.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% Copyright Ericsson AB 2010-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. @@ -17,13 +17,6 @@ %% %% %CopyrightEnd% -%%% @doc Common Test Framework functions for starting and stopping nodes for -%%% Large Scale Testing. -%%% -%%% <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 -%%% <code>{init, node_start}</code> term of the Test Specification.</p> - %%---------------------------------------------------------------------- %% File : ct_slave.erl %% Description : CT module for starting nodes for large-scale testing. @@ -38,44 +31,12 @@ -record(options, {username, password, boot_timeout, init_timeout, startup_timeout, startup_functions, monitor_master, - kill_if_fail, erl_flags, env, ssh_port, ssh_opts}). - -%%%----------------------------------------------------------------- -%%% @spec start(Node) -> Result -%%% Node = atom() -%%% Result = {ok, NodeName} | -%%% {error, Reason, NodeName} -%%% Reason = already_started | -%%% started_not_connected | -%%% boot_timeout | -%%% init_timeout | -%%% startup_timeout | -%%% not_alive -%%% NodeName = atom() -%%% @doc Starts an Erlang node with name <code>Node</code> on the local host. -%%% @see start/3 + kill_if_fail, erl_flags, env, ssh_port, ssh_opts, + stop_timeout}). + start(Node) -> start(gethostname(), Node). -%%%----------------------------------------------------------------- -%%% @spec start(HostOrNode, NodeOrOpts) -> Result -%%% HostOrNode = atom() -%%% NodeOrOpts = atom() | list() -%%% Result = {ok, NodeName} | -%%% {error, Reason, NodeName} -%%% Reason = already_started | -%%% started_not_connected | -%%% boot_timeout | -%%% init_timeout | -%%% startup_timeout | -%%% not_alive -%%% NodeName = atom() -%%% @doc Starts an Erlang node with default options on a specified -%%% host, or on the local host with specified options. That is, -%%% the call is interpreted as <code>start(Host, Node)</code> when the -%%% second argument is atom-valued and <code>start(Node, Opts)</code> -%%% when it's list-valued. -%%% @see start/3 start(_HostOrNode = Node, _NodeOrOpts = Opts) %% match to satiate edoc when is_list(Opts) -> start(gethostname(), Node, Opts); @@ -83,104 +44,6 @@ start(_HostOrNode = Node, _NodeOrOpts = Opts) %% match to satiate edoc start(Host, Node) -> start(Host, Node, []). -%%%----------------------------------------------------------------- -%%% @spec start(Host, Node, Opts) -> Result -%%% Node = atom() -%%% Host = atom() -%%% Opts = [OptTuples] -%%% 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} | -%%% {env, [{EnvVar,Value}]} -%%% Username = string() -%%% Password = string() -%%% BootTimeout = integer() -%%% InitTimeout = integer() -%%% StartupTimeout = integer() -%%% StartupFunctions = [StartupFunctionSpec] -%%% StartupFunctionSpec = {Module, Function, Arguments} -%%% Module = atom() -%%% Function = atom() -%%% Arguments = [term] -%%% Monitor = bool() -%%% KillIfFail = bool() -%%% ErlangFlags = string() -%%% EnvVar = string() -%%% Value = string() -%%% Result = {ok, NodeName} | -%%% {error, Reason, NodeName} -%%% Reason = already_started | -%%% started_not_connected | -%%% boot_timeout | -%%% init_timeout | -%%% startup_timeout | -%%% not_alive -%%% NodeName = atom() -%%% @doc Starts an Erlang node with name <code>Node</code> on host -%%% <code>Host</code> as specified by the combination of options in -%%% <code>Opts</code>. -%%% -%%% <p>Options <code>Username</code> and <code>Password</code> will be used -%%% to log in onto the remote host <code>Host</code>. -%%% Username, if omitted, defaults to the current user name, -%%% and password is empty by default.</p> -%%% -%%% <p>A list of functions specified in the <code>Startup</code> option will be -%%% executed after startup of the node. Note that all used modules should be -%%% present in the code path on the <code>Host</code>.</p> -%%% -%%% <p>The timeouts are applied as follows:</p> -%%% <list> -%%% <item> -%%% <code>BootTimeout</code> - time to start the Erlang node, in seconds. -%%% Defaults to 3 seconds. If node does not become pingable within this time, -%%% the result <code>{error, boot_timeout, NodeName}</code> is returned; -%%% </item> -%%% <item> -%%% <code>InitTimeout</code> - 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 -%%% <code>{error, init_timeout, NodeName}</code> is returned; -%%% </item> -%%% <item> -%%% <code>StartupTimeout</code> - time to wait intil the node finishes to run -%%% the <code>StartupFunctions</code>. Defaults to one second. -%%% If this timeout occurs, the result -%%% <code>{error, startup_timeout, NodeName}</code> is returned. -%%% </item> -%%% </list> -%%% -%%% <p>Option <code>monitor_master</code> specifies, if the slave node should be -%%% stopped in case of master node stop. Defaults to false.</p> -%%% -%%% <p>Option <code>kill_if_fail</code> 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 <code>erlang_flags</code> specifies, which flags will be added -%%% to the parameters of the <code>erl</code> executable.</p> -%%% -%%% <p>Option <code>env</code> specifies a list of environment variables -%%% that will extended the environment.</p> -%%% -%%% <p>Special return values are:</p> -%%% <list> -%%% <item><code>{error, already_started, NodeName}</code> - if the node with -%%% the given name is already started on a given host;</item> -%%% <item><code>{error, started_not_connected, NodeName}</code> - if node is -%%% started, but not connected to the master node.</item> -%%% <item><code>{error, not_alive, NodeName}</code> - if node on which the -%%% <code>ct_slave:start/3</code> is called, is not alive. Note that -%%% <code>NodeName</code> is the name of current node in this case.</item> -%%% </list> -%%% start(Host, Node, Opts) -> ENode = enodename(Host, Node), case erlang:is_alive() of @@ -198,36 +61,22 @@ start(Host, Node, Opts) -> end end. -%%% @spec stop(Node) -> Result -%%% Node = atom() -%%% Result = {ok, NodeName} | -%%% {error, Reason, NodeName} -%%% Reason = not_started | -%%% not_connected | -%%% stop_timeout - -%%% NodeName = atom() -%%% @doc Stops the running Erlang node with name <code>Node</code> on -%%% the localhost. stop(Node) -> stop(gethostname(), Node). -%%% @spec stop(Host, Node) -> Result -%%% Host = atom() -%%% Node = atom() -%%% Result = {ok, NodeName} | -%%% {error, Reason, NodeName} -%%% Reason = not_started | -%%% not_connected | -%%% stop_timeout -%%% NodeName = atom() -%%% @doc Stops the running Erlang node with name <code>Node</code> on -%%% host <code>Host</code>. +stop(_HostOrNode = Node, _NodeOrOpts = Opts) %% match to satiate edoc + when is_list(Opts) -> + stop(gethostname(), Node, Opts); + stop(Host, Node) -> + stop(Host, Node, []). + +stop(Host, Node, Opts) -> ENode = enodename(Host, Node), case is_started(ENode) of {true, connected}-> - do_stop(ENode); + OptionsRec = fetch_options(Opts), + do_stop(ENode, OptionsRec); {true, not_connected}-> {error, not_connected, ENode}; false-> @@ -257,26 +106,25 @@ fetch_options(Options) -> EnvVars = get_option_value(env, Options, []), SSHPort = get_option_value(ssh_port, Options, []), SSHOpts = get_option_value(ssh_opts, Options, []), + StopTimeout = get_option_value(stop_timeout, Options, 5), #options{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=ErlFlags, env=EnvVars, ssh_port=SSHPort, ssh_opts=SSHOpts}. + erl_flags=ErlFlags, env=EnvVars, ssh_port=SSHPort, ssh_opts=SSHOpts, + stop_timeout=StopTimeout}. % send a message when slave node is started -% @hidden slave_started(ENode, MasterPid) -> MasterPid ! {node_started, ENode}, ok. % send a message when slave node has finished startup -% @hidden 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). @@ -462,6 +310,8 @@ wait_for_node_alive(Node, N) -> % call init:stop on a remote node do_stop(ENode) -> + do_stop(ENode, fetch_options([])). +do_stop(ENode, Options) -> {Cover,MainCoverNode} = case test_server:is_cover() of true -> @@ -472,7 +322,8 @@ do_stop(ENode) -> {false,undefined} end, spawn(ENode, init, stop, []), - case wait_for_node_dead(ENode, 5) of + StopTimeout = Options#options.stop_timeout, + case wait_for_node_dead(ENode, StopTimeout) of {ok,ENode} -> if Cover -> %% To avoid that cover is started again if a node diff --git a/lib/common_test/src/ct_snmp.erl b/lib/common_test/src/ct_snmp.erl index 5844909d17..27b74dd04e 100644 --- a/lib/common_test/src/ct_snmp.erl +++ b/lib/common_test/src/ct_snmp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-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,139 +18,8 @@ %% %CopyrightEnd% %% -%%% @doc Common Test user interface module for the OTP snmp application -%%% -%%% <p>The purpose of this module is to make snmp configuration easier for -%%% the test case writer. Many test cases can use default values for common -%%% operations and then no snmp configuration files need to be supplied. When -%%% it is necessary to change particular configuration parameters, a subset -%%% of the relevant snmp configuration files may be passed to <code>ct_snmp</code> -%%% by means of Common Test configuration files. -%%% For more specialized configuration parameters, it is possible to place a -%%% "simple snmp configuration file" in the test suite data directory. -%%% To simplify the test suite, Common Test keeps track -%%% of some of the snmp manager information. This way the test suite doesn't -%%% have to handle as many input parameters as it would if it had to interface the -%%% OTP snmp manager directly.</p> -%%% -%%% <p> The following snmp manager and agent parameters are configurable: </p> -%%% -%%% <pre> -%%% {snmp, -%%% %%% Manager config -%%% [{start_manager, boolean()} % Optional - default is true -%%% {users, [{user_name(), [call_back_module(), user_data()]}]}, %% Optional -%%% {usm_users, [{usm_user_name(), [usm_config()]}]},%% Optional - snmp v3 only -%%% % managed_agents is optional -%%% {managed_agents,[{agent_name(), [user_name(), agent_ip(), agent_port(), [agent_config()]]}]}, -%%% {max_msg_size, integer()}, % Optional - default is 484 -%%% {mgr_port, integer()}, % Optional - default is 5000 -%%% {engine _id, string()}, % Optional - default is "mgrEngine" -%%% -%%% %%% Agent config -%%% {start_agent, boolean()}, % Optional - default is false -%%% {agent_sysname, string()}, % Optional - default is "ct_test" -%%% {agent_manager_ip, manager_ip()}, % Optional - default is localhost -%%% {agent_vsns, list()}, % Optional - default is [v2] -%%% {agent_trap_udp, integer()}, % Optional - default is 5000 -%%% {agent_udp, integer()}, % Optional - default is 4000 -%%% {agent_notify_type, atom()}, % Optional - default is trap -%%% {agent_sec_type, sec_type()}, % Optional - default is none -%%% {agent_passwd, string()}, % Optional - default is "" -%%% {agent_engine_id, string()}, % Optional - default is "agentEngine" -%%% {agent_max_msg_size, string()},% Optional - default is 484 -%%% -%%% %% The following parameters represents the snmp configuration files -%%% %% context.conf, standard.conf, community.conf, vacm.conf, -%%% %% usm.conf, notify.conf, target_addr.conf and target_params.conf. -%%% %% Note all values in agent.conf can be altered by the parametes -%%% %% above. All these configuration files have default values set -%%% %% up by the snmp application. These values can be overridden by -%%% %% suppling a list of valid configuration values or a file located -%%% %% in the test suites data dir that can produce a list -%%% %% of valid configuration values if you apply file:consult/1 to the -%%% %% file. -%%% {agent_contexts, [term()] | {data_dir_file, rel_path()}}, % Optional -%%% {agent_community, [term()] | {data_dir_file, rel_path()}},% Optional -%%% {agent_sysinfo, [term()] | {data_dir_file, rel_path()}}, % Optional -%%% {agent_vacm, [term()] | {data_dir_file, rel_path()}}, % Optional -%%% {agent_usm, [term()] | {data_dir_file, rel_path()}}, % Optional -%%% {agent_notify_def, [term()] | {data_dir_file, rel_path()}},% Optional -%%% {agent_target_address_def, [term()] | {data_dir_file, rel_path()}},% Optional -%%% {agent_target_param_def, [term()] | {data_dir_file, rel_path()}},% Optional -%%% ]}. -%%% </pre> -%%% -%%% <p>The <code>MgrAgentConfName</code> parameter in the functions -%%% should be a name you allocate in your test suite using a -%%% <code>require</code> statement. -%%% Example (where <code>MgrAgentConfName = snmp_mgr_agent</code>):</p> -%%% <pre> suite() -> [{require, snmp_mgr_agent, snmp}].</pre> -%%% <p>or</p> -%%% <pre> ct:require(snmp_mgr_agent, snmp).</pre> -%%% -%%% <p> Note that Usm users are needed for snmp v3 configuration and are -%%% not to be confused with users.</p> -%%% -%%% <p> Snmp traps, inform and report messages are handled by the -%%% user callback module. For more information about this see -%%% the snmp application. </p> -%%% <p> Note: It is recommended to use the .hrl-files created by the -%%% Erlang/OTP mib-compiler to define the oids. -%%% Example for the getting the erlang node name from the erlNodeTable -%%% in the OTP-MIB:</p> -%%% <pre>Oid = ?erlNodeEntry ++ [?erlNodeName, 1] </pre> -%%% -%%% <p>It is also possible to set values for snmp application configuration -%%% parameters, such as <code>config</code>, <code>server</code>, -%%% <code>net_if</code>, etc (see the "Configuring the application" chapter in -%%% the OTP snmp User's Guide for a list of valid parameters and types). This is -%%% done by defining a configuration data variable on the following form:</p> -%%% <pre> -%%% {snmp_app, [{manager, [snmp_app_manager_params()]}, -%%% {agent, [snmp_app_agent_params()]}]}.</pre> -%%% -%%% <p>A name for the data needs to be allocated in the suite using -%%% <code>require</code> (see example above), and this name passed as -%%% the <code>SnmpAppConfName</code> argument to <code>start/3</code>. -%%% <code>ct_snmp</code> specifies default values for some snmp application -%%% configuration parameters (such as <code>{verbosity,trace}</code> for the -%%% <code>config</code> parameter). This set of defaults will be -%%% merged with the parameters specified by the user, and user values -%%% override <code>ct_snmp</code> defaults.</p> - -module(ct_snmp). -%%% Common Types -%%% @type agent_ip() = ip() -%%% @type manager_ip() = ip() -%%% @type agent_name() = atom() -%%% @type ip() = string() | {integer(), integer(), -%%% integer(), integer()} -%%% @type agent_port() = integer() -%%% @type agent_config() = {Item, Value} -%%% @type user_name() = atom() -%%% @type usm_user_name() = string() -%%% @type usm_config() = {Item, Value} -%%% @type call_back_module() = atom() -%%% @type user_data() = term() -%%% @type oids() = [oid()] -%%% @type oid() = [byte()] -%%% @type snmpreply() = {error_status(), error_index(), varbinds()} -%%% @type error_status() = noError | atom() -%%% @type error_index() = integer() -%%% @type varbinds() = [varbind()] -%%% @type varbind() = term() -%%% @type value_type() = o ('OBJECT IDENTIFIER') | i ('INTEGER') | -%%% u ('Unsigned32') | g ('Unsigned32') | s ('OCTET STRING') -%%% @type varsandvals() = [var_and_val()] -%%% @type var_and_val() = {oid(), value_type(), value()} -%%% @type sec_type() = none | minimum | semi -%%% @type rel_path() = string() -%%% @type snmp_app_manager_params() = term() -%%% @type snmp_app_agent_params() = term() - - -include("snmp_types.hrl"). -include("inet.hrl"). -include("ct.hrl"). @@ -181,31 +50,9 @@ %%% API %%%========================================================================= -%%%----------------------------------------------------------------- -%%% @spec start(Config, MgrAgentConfName) -> ok -%%% @equiv start(Config, MgrAgentConfName, undefined) start(Config, MgrAgentConfName) -> start(Config, MgrAgentConfName, undefined). -%%% @spec start(Config, MgrAgentConfName, SnmpAppConfName) -> ok -%%% Config = [{Key, Value}] -%%% Key = atom() -%%% Value = term() -%%% MgrAgentConfName = atom() -%%% SnmpConfName = atom() -%%% -%%% @doc Starts an snmp manager and/or agent. In the manager case, -%%% registrations of users and agents as specified by the configuration -%%% <code>MgrAgentConfName</code> will be performed. When using snmp -%%% v3 also so called usm users will be registered. Note that users, -%%% usm_users and managed agents may also be registered at a later time -%%% using ct_snmp:register_users/2, ct_snmp:register_agents/2, and -%%% ct_snmp:register_usm_users/2. The agent started will be -%%% called <code>snmp_master_agent</code>. Use ct_snmp:load_mibs/1 to load -%%% mibs into the agent. With <code>SnmpAppConfName</code> it's possible -%%% to configure the snmp application with parameters such as <code>config</code>, -%%% <code>mibs</code>, <code>net_if</code>, etc. The values will be merged -%%% with (and possibly override) default values set by <code>ct_snmp</code>. start(Config, MgrAgentConfName, SnmpAppConfName) -> StartManager= ct:get_config({MgrAgentConfName, start_manager}, true), StartAgent = ct:get_config({MgrAgentConfName, start_agent}, false), @@ -233,12 +80,6 @@ start_application(App) -> Else end. -%%% @spec stop(Config) -> ok -%%% Config = [{Key, Value}] -%%% Key = atom() -%%% Value = term() -%%% -%%% @doc Stops the snmp manager and/or agent removes all files created. stop(Config) -> PrivDir = ?config(priv_dir, Config), ok = application:stop(snmp), @@ -251,41 +92,16 @@ stop(Config) -> catch del_dir(DbDir). -%%% @spec get_values(Agent, Oids, MgrAgentConfName) -> SnmpReply -%%% -%%% Agent = agent_name() -%%% Oids = oids() -%%% MgrAgentConfName = atom() -%%% SnmpReply = snmpreply() -%%% -%%% @doc Issues a synchronous snmp get request. get_values(Agent, Oids, MgrAgentConfName) -> [Uid | _] = agent_conf(Agent, MgrAgentConfName), {ok, SnmpReply, _} = snmpm:sync_get2(Uid, target_name(Agent), Oids), SnmpReply. -%%% @spec get_next_values(Agent, Oids, MgrAgentConfName) -> SnmpReply -%%% -%%% Agent = agent_name() -%%% Oids = oids() -%%% MgrAgentConfName = atom() -%%% SnmpReply = snmpreply() -%%% -%%% @doc Issues a synchronous snmp get next request. get_next_values(Agent, Oids, MgrAgentConfName) -> [Uid | _] = agent_conf(Agent, MgrAgentConfName), {ok, SnmpReply, _} = snmpm:sync_get_next2(Uid, target_name(Agent), Oids), SnmpReply. -%%% @spec set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -> SnmpReply -%%% -%%% Agent = agent_name() -%%% Oids = oids() -%%% MgrAgentConfName = atom() -%%% Config = [{Key, Value}] -%%% SnmpReply = snmpreply() -%%% -%%% @doc Issues a synchronous snmp set request. set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -> PrivDir = ?config(priv_dir, Config), [Uid | _] = agent_conf(Agent, MgrAgentConfName), @@ -301,19 +117,6 @@ set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -> end, SnmpSetReply. -%%% @spec set_info(Config) -> [{Agent, OldVarsAndVals, NewVarsAndVals}] -%%% -%%% Config = [{Key, Value}] -%%% Agent = agent_name() -%%% OldVarsAndVals = varsandvals() -%%% NewVarsAndVals = varsandvals() -%%% -%%% @doc Returns a list of all successful set requests performed in -%%% the test case in reverse order. The list contains the involved -%%% user and agent, the value prior to the set and the new value. This -%%% is intended to facilitate the clean up in the end_per_testcase -%%% function i.e. the undoing of the set requests and its possible -%%% side-effects. set_info(Config) -> PrivDir = ?config(priv_dir, Config), SetLogFile = filename:join(PrivDir, ?CT_SNMP_LOG_FILE), @@ -325,18 +128,6 @@ set_info(Config) -> [] end. -%%% @spec register_users(MgrAgentConfName, Users) -> ok | {error, Reason} -%%% -%%% MgrAgentConfName = atom() -%%% Users = [user()] -%%% Reason = term() -%%% -%%% @doc Register the manager entity (=user) responsible for specific agent(s). -%%% Corresponds to making an entry in users.conf. -%%% -%%% <p>This function will try to register the given users, without -%%% checking if any of them already exist. In order to change an -%%% already registered user, the user must first be unregistered.</p> register_users(MgrAgentConfName, Users) -> case setup_users(Users) of ok -> @@ -350,19 +141,6 @@ register_users(MgrAgentConfName, Users) -> Error end. -%%% @spec register_agents(MgrAgentConfName, ManagedAgents) -> ok | {error, Reason} -%%% -%%% MgrAgentConfName = atom() -%%% ManagedAgents = [agent()] -%%% Reason = term() -%%% -%%% @doc Explicitly instruct the manager to handle this agent. -%%% Corresponds to making an entry in agents.conf -%%% -%%% <p>This function will try to register the given managed agents, -%%% without checking if any of them already exist. In order to change -%%% an already registered managed agent, the agent must first be -%%% unregistered.</p> register_agents(MgrAgentConfName, ManagedAgents) -> case setup_managed_agents(MgrAgentConfName,ManagedAgents) of ok -> @@ -377,18 +155,6 @@ register_agents(MgrAgentConfName, ManagedAgents) -> Error end. -%%% @spec register_usm_users(MgrAgentConfName, UsmUsers) -> ok | {error, Reason} -%%% -%%% MgrAgentConfName = atom() -%%% UsmUsers = [usm_user()] -%%% Reason = term() -%%% -%%% @doc Explicitly instruct the manager to handle this USM user. -%%% Corresponds to making an entry in usm.conf -%%% -%%% <p>This function will try to register the given users, without -%%% checking if any of them already exist. In order to change an -%%% already registered user, the user must first be unregistered.</p> register_usm_users(MgrAgentConfName, UsmUsers) -> EngineID = ct:get_config({MgrAgentConfName, engine_id}, ?ENGINE_ID), case setup_usm_users(UsmUsers, EngineID) of @@ -403,23 +169,10 @@ register_usm_users(MgrAgentConfName, UsmUsers) -> Error end. -%%% @spec unregister_users(MgrAgentConfName) -> ok -%%% -%%% MgrAgentConfName = atom() -%%% Reason = term() -%%% -%%% @doc Unregister all users. unregister_users(MgrAgentConfName) -> Users = [Id || {Id,_} <- ct:get_config({MgrAgentConfName, users},[])], unregister_users(MgrAgentConfName,Users). -%%% @spec unregister_users(MgrAgentConfName,Users) -> ok -%%% -%%% MgrAgentConfName = atom() -%%% Users = [user_name()] -%%% Reason = term() -%%% -%%% @doc Unregister the given users. unregister_users(MgrAgentConfName,Users) -> takedown_users(Users), SnmpVals = ct:get_config(MgrAgentConfName), @@ -432,25 +185,12 @@ unregister_users(MgrAgentConfName,Users) -> ct_config:update_config(MgrAgentConfName, NewSnmpVals), ok. -%%% @spec unregister_agents(MgrAgentConfName) -> ok -%%% -%%% MgrAgentConfName = atom() -%%% Reason = term() -%%% -%%% @doc Unregister all managed agents. unregister_agents(MgrAgentConfName) -> ManagedAgents = [AgentName || {AgentName, _} <- ct:get_config({MgrAgentConfName,managed_agents},[])], unregister_agents(MgrAgentConfName,ManagedAgents). -%%% @spec unregister_agents(MgrAgentConfName,ManagedAgents) -> ok -%%% -%%% MgrAgentConfName = atom() -%%% ManagedAgents = [agent_name()] -%%% Reason = term() -%%% -%%% @doc Unregister the given managed agents. unregister_agents(MgrAgentConfName,ManagedAgents) -> takedown_managed_agents(MgrAgentConfName, ManagedAgents), SnmpVals = ct:get_config(MgrAgentConfName), @@ -464,23 +204,10 @@ unregister_agents(MgrAgentConfName,ManagedAgents) -> ct_config:update_config(MgrAgentConfName, NewSnmpVals), ok. -%%% @spec unregister_usm_users(MgrAgentConfName) -> ok -%%% -%%% MgrAgentConfName = atom() -%%% Reason = term() -%%% -%%% @doc Unregister all usm users. unregister_usm_users(MgrAgentConfName) -> UsmUsers = [Id || {Id,_} <- ct:get_config({MgrAgentConfName, usm_users},[])], unregister_usm_users(MgrAgentConfName,UsmUsers). -%%% @spec unregister_usm_users(MgrAgentConfName,UsmUsers) -> ok -%%% -%%% MgrAgentConfName = atom() -%%% UsmUsers = [usm_user_name()] -%%% Reason = term() -%%% -%%% @doc Unregister the given usm users. unregister_usm_users(MgrAgentConfName,UsmUsers) -> EngineID = ct:get_config({MgrAgentConfName, engine_id}, ?ENGINE_ID), takedown_usm_users(UsmUsers,EngineID), @@ -495,23 +222,9 @@ unregister_usm_users(MgrAgentConfName,UsmUsers) -> ct_config:update_config(MgrAgentConfName, NewSnmpVals), ok. -%%% @spec load_mibs(Mibs) -> ok | {error, Reason} -%%% -%%% Mibs = [MibName] -%%% MibName = string() -%%% Reason = term() -%%% -%%% @doc Load the mibs into the agent 'snmp_master_agent'. load_mibs(Mibs) -> snmpa:load_mibs(snmp_master_agent, Mibs). -%%% @spec unload_mibs(Mibs) -> ok | {error, Reason} -%%% -%%% Mibs = [MibName] -%%% MibName = string() -%%% Reason = term() -%%% -%%% @doc Unload the mibs from the agent 'snmp_master_agent'. unload_mibs(Mibs) -> snmpa:unload_mibs(snmp_master_agent, Mibs). diff --git a/lib/common_test/src/ct_ssh.erl b/lib/common_test/src/ct_ssh.erl index ca62357e1c..79ab122452 100644 --- a/lib/common_test/src/ct_ssh.erl +++ b/lib/common_test/src/ct_ssh.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2017. All Rights Reserved. +%% Copyright Ericsson AB 2009-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,44 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc SSH/SFTP client module. -%%% -%%% <p>ct_ssh uses the OTP ssh application and more detailed information -%%% about e.g. functions, types and options can be found in the -%%% documentation for this application.</p> -%%% -%%% <p>The <code>Server</code> argument in the SFTP functions should -%%% only be used for SFTP sessions that have been started on existing -%%% SSH connections (i.e. when the original connection type is -%%% <code>ssh</code>). Whenever the connection type is -%%% <code>sftp</code>, use the SSH connection reference only.</p> -%%% -%%% <p>The following options are valid for specifying an SSH/SFTP -%%% connection (i.e. may be used as config elements):</p> -%%% -%%% <pre> -%%% -%%% [{ConnType, Addr}, -%%% {port, Port}, -%%% {user, UserName} -%%% {password, Pwd} -%%% {user_dir, String} -%%% {public_key_alg, PubKeyAlg} -%%% {connect_timeout, Timeout} -%%% {key_cb, KeyCallbackMod}] -%%% </pre> -%%% -%%% <p><code>ConnType = ssh | sftp</code>.</p> -%%% <p>Please see ssh(3) for other types.</p> -%%% -%%% <p>All timeout parameters in ct_ssh functions are values in -%%% milliseconds.</p> -%%% -%%% @type connection() = handle() | ct:target_name() -%%% @type handle() = ct_gen_conn:handle(). Handle for a specific -%%% SSH/SFTP connection. -%%% @type ssh_sftp_return() = term(). A return value from an ssh_sftp function. - -module(ct_ssh). %% SSH Functions @@ -100,64 +62,15 @@ %%%----------------------------------------------------------------- %%%------------------------ SSH COMMANDS --------------------------- -%%%----------------------------------------------------------------- -%%% @spec connect(KeyOrName) -> {ok,Handle} | {error,Reason} -%%% @equiv connect(KeyOrName,host,[]) connect(KeyOrName) -> connect(KeyOrName, host). -%%%----------------------------------------------------------------- -%%% @spec connect(KeyOrName,ConnType) -> {ok,Handle} | {error,Reason} -%%% @equiv connect(KeyOrName,ConnType,[]) connect(KeyOrName, ConnType) when is_atom(ConnType) -> connect(KeyOrName, ConnType, []); -%%%----------------------------------------------------------------- -%%% @spec connect(KeyOrName,ExtraOpts) -> {ok,Handle} | {error,Reason} -%%% @equiv connect(KeyOrName,host,ExtraOpts) connect(KeyOrName, ExtraOpts) when is_list(ExtraOpts) -> connect(KeyOrName, host, ExtraOpts). -%%%----------------------------------------------------------------- -%%% @spec connect(KeyOrName,ConnType,ExtraOpts) -> -%%% {ok,Handle} | {error,Reason} -%%% KeyOrName = Key | Name -%%% Key = atom() -%%% Name = ct:target_name() -%%% ConnType = ssh | sftp | host -%%% ExtraOpts = ssh_connect_options() -%%% Handle = handle() -%%% Reason = term() -%%% -%%% @doc Open an SSH or SFTP connection using the information -%%% associated with <code>KeyOrName</code>. -%%% -%%% <p>If <code>Name</code> (an alias name for <code>Key</code>), -%%% is used to identify the connection, this name may -%%% be used as connection reference for subsequent calls. -%%% It's only possible to have one open connection at a time -%%% associated with <code>Name</code>. If <code>Key</code> is -%%% used, the returned handle must be used for subsequent calls -%%% (multiple connections may be opened using the config -%%% data specified by <code>Key</code>). See <c>ct:require/2</c> -%%% for how to create a new <c>Name</c></p> -%%% -%%% <p><code>ConnType</code> will always override the type -%%% specified in the address tuple in the configuration data (and -%%% in <code>ExtraOpts</code>). So it is possible to for example -%%% open an sftp connection directly using data originally -%%% specifying an ssh connection. The value <code>host</code> -%%% means the connection type specified by the host option -%%% (either in the configuration data or in <code>ExtraOpts</code>) -%%% will be used.</p> -%%% -%%% <p><code>ExtraOpts</code> (optional) are extra SSH options -%%% to be added to the config data for <code>KeyOrName</code>. -%%% The extra options will override any existing options with the -%%% same key in the config data. For details on valid SSH -%%% options, see the documentation for the OTP ssh application.</p> -%%% -%%% @see ct:require/2 connect(KeyOrName, ConnType, ExtraOpts) -> case ct:get_config(KeyOrName) of undefined -> @@ -232,12 +145,6 @@ connect(KeyOrName, ConnType, ExtraOpts) -> end end. -%%%----------------------------------------------------------------- -%%% @spec disconnect(SSH) -> ok | {error,Reason} -%%% SSH = connection() -%%% Reason = term() -%%% -%%% @doc Close an SSH/SFTP connection. disconnect(SSH) -> case get_handle(SSH) of {ok,Pid} -> @@ -252,242 +159,78 @@ disconnect(SSH) -> Error end. -%%%----------------------------------------------------------------- -%%% @spec session_open(SSH) -> {ok,ChannelId} | {error, Reason} -%%% @equiv session_open(SSH,DefaultTimeout) session_open(SSH) -> call(SSH, {session_open,?DEFAULT_TIMEOUT}). -%%%----------------------------------------------------------------- -%%% @spec session_open(SSH,Timeout) -> {ok,ChannelId} | {error, Reason} -%%% SSH = connection() -%%% Timeout = integer() -%%% ChannelId = integer() -%%% Reason = term() -%%% -%%% @doc Opens a channel for an SSH session. session_open(SSH, Timeout) -> call(SSH, {session_open,Timeout}). -%%%----------------------------------------------------------------- -%%% @spec session_close(SSH,ChannelId) -> ok | {error, Reason} -%%% SSH = connection() -%%% ChannelId = integer() -%%% Reason = term() -%%% -%%% @doc Closes an SSH session channel. session_close(SSH, ChannelId) -> call(SSH, {session_close,ChannelId}). -%%%----------------------------------------------------------------- -%%% @spec exec(SSH,Command) -> {ok,Data} | {error,Reason} -%%% @equiv exec(SSH,Command,DefaultTimeout) exec(SSH, Command) -> exec(SSH, undefined, Command, ?DEFAULT_TIMEOUT). -%%%----------------------------------------------------------------- -%%% @spec exec(SSH,Command,Timeout) -> {ok,Data} | {error,Reason} -%%% SSH = connection() -%%% Command = string() -%%% Timeout = integer() -%%% Data = list() -%%% Reason = term() -%%% -%%% @doc Requests server to perform <code>Command</code>. A session -%%% channel is opened automatically for the request. -%%% <code>Data</code> is received from the server as a result -%%% of the command. exec(SSH, Command, Timeout) when is_list(Command) -> exec(SSH, undefined, Command, Timeout); -%%%----------------------------------------------------------------- -%%% @spec exec(SSH,ChannelId,Command) -> {ok,Data} | {error,Reason} -%%% @equiv exec(SSH,ChannelId,Command,DefaultTimeout) exec(SSH, ChannelId, Command) when is_integer(ChannelId) -> exec(SSH, ChannelId, Command, ?DEFAULT_TIMEOUT). -%%%----------------------------------------------------------------- -%%% @spec exec(SSH,ChannelId,Command,Timeout) -> {ok,Data} | {error,Reason} -%%% SSH = connection() -%%% ChannelId = integer() -%%% Command = string() -%%% Timeout = integer() -%%% Data = list() -%%% Reason = term() -%%% -%%% @doc Requests server to perform <code>Command</code>. A previously -%%% opened session channel is used for the request. -%%% <code>Data</code> is received from the server as a result -%%% of the command. exec(SSH, ChannelId, Command, Timeout) -> call(SSH, {exec,ChannelId,Command,Timeout}). -%%%----------------------------------------------------------------- -%%% @spec receive_response(SSH,ChannelId) -> {ok,Data} | {error,Reason} -%%% @equiv receive_response(SSH,ChannelId,close) receive_response(SSH, ChannelId) -> receive_response(SSH, ChannelId, close, ?DEFAULT_TIMEOUT). -%%%----------------------------------------------------------------- -%%% @spec receive_response(SSH,ChannelId,End) -> {ok,Data} | {error,Reason} -%%% @equiv receive_response(SSH,ChannelId,End,DefaultTimeout) receive_response(SSH, ChannelId, End) when is_function(End) -> receive_response(SSH, ChannelId, End, ?DEFAULT_TIMEOUT); -%%%----------------------------------------------------------------- -%%% @spec receive_response(SSH,ChannelId,Timeout) -> {ok,Data} | {error,Reason} -%%% @equiv receive_response(SSH,ChannelId,close,Timeout) receive_response(SSH, ChannelId, Timeout) when is_integer(Timeout) -> receive_response(SSH, ChannelId, close, Timeout). -%%%----------------------------------------------------------------- -%%% @spec receive_response(SSH,ChannelId,End,Timeout) -> -%%% {ok,Data} | {timeout,Data} | {error,Reason} -%%% SSH = connection() -%%% ChannelId = integer() -%%% End = Fun | close | timeout -%%% Timeout = integer() -%%% Data = list() -%%% Reason = term() -%%% -%%% @doc Receives expected data from server on the specified -%%% session channel. -%%% -%%% <p>If <code>End == close</code>, data is returned -%%% to the caller when the channel is closed by the -%%% server. If a timeout occurs before this happens, -%%% the function returns <code>{timeout,Data}</code> -%%% (where <code>Data</code> is the data received so far). -%%% If <code>End == timeout</code>, a timeout is expected -%%% and <code>{ok,Data}</code> is returned both in the case -%%% of a timeout and when the channel is closed. If -%%% <code>End</code> is a fun, this fun will be -%%% called with one argument - the data value in a received -%%% <code>ssh_cm</code> message (see ssh_connection(3)). The -%%% fun should return <code>true</code> to end the receiving -%%% operation (and have the so far collected data returned), or -%%% <code>false</code> to wait for more data from the server. -%%% (Note that even if a fun is supplied, the function returns -%%% immediately if the server closes the channel).</p> receive_response(SSH, ChannelId, End, Timeout) -> call(SSH, {receive_response,ChannelId,End,Timeout}). -%%%----------------------------------------------------------------- -%%% @spec send(SSH,ChannelId,Data) -> ok | {error,Reason} -%%% @equiv send(SSH,ChannelId,0,Data,DefaultTimeout) send(SSH, ChannelId, Data) -> send(SSH, ChannelId, 0, Data, ?DEFAULT_TIMEOUT). -%%%----------------------------------------------------------------- -%%% @spec send(SSH,ChannelId,Data,Timeout) -> ok | {error,Reason} -%%% @equiv send(SSH,ChannelId,0,Data,Timeout) send(SSH, ChannelId, Data, Timeout) when is_integer(Timeout) -> send(SSH, ChannelId, 0, Data, Timeout); -%%%----------------------------------------------------------------- -%%% @spec send(SSH,ChannelId,Type,Data) -> ok | {error,Reason} -%%% @equiv send(SSH,ChannelId,Type,Data,DefaultTimeout) send(SSH, ChannelId, Type, Data) when is_integer(Type) -> send(SSH, ChannelId, Type, Data, ?DEFAULT_TIMEOUT). -%%%----------------------------------------------------------------- -%%% @spec send(SSH,ChannelId,Type,Data,Timeout) -> ok | {error,Reason} -%%% SSH = connection() -%%% ChannelId = integer() -%%% Type = integer() -%%% Data = list() -%%% Timeout = integer() -%%% Reason = term() -%%% -%%% @doc Send data to server on specified session channel. send(SSH, ChannelId, Type, Data, Timeout) -> call(SSH, {send,ChannelId,Type,Data,Timeout}). -%%%----------------------------------------------------------------- -%%% @spec send_and_receive(SSH,ChannelId,Data) -> -%%% {ok,Data} | {error,Reason} -%%% @equiv send_and_receive(SSH,ChannelId,Data,close) send_and_receive(SSH, ChannelId, Data) -> send_and_receive(SSH, ChannelId, 0, Data, close, ?DEFAULT_TIMEOUT). -%%%----------------------------------------------------------------- -%%% @spec send_and_receive(SSH,ChannelId,Data,End) -> -%%% {ok,Data} | {error,Reason} -%%% @equiv send_and_receive(SSH,ChannelId,0,Data,End,DefaultTimeout) send_and_receive(SSH, ChannelId, Data, End) when is_function(End) -> send_and_receive(SSH, ChannelId, 0, Data, End, ?DEFAULT_TIMEOUT); -%%%----------------------------------------------------------------- -%%% @spec send_and_receive(SSH,ChannelId,Data,Timeout) -> -%%% {ok,Data} | {error,Reason} -%%% @equiv send_and_receive(SSH,ChannelId,0,Data,close,Timeout) send_and_receive(SSH, ChannelId, Data, Timeout) when is_integer(Timeout) -> send_and_receive(SSH, ChannelId, 0, Data, close, Timeout); -%%%----------------------------------------------------------------- -%%% @spec send_and_receive(SSH,ChannelId,Type,Data) -> -%%% {ok,Data} | {error,Reason} -%%% @equiv send_and_receive(SSH,ChannelId,Type,Data,close,DefaultTimeout) send_and_receive(SSH, ChannelId, Type, Data) when is_integer(Type) -> send_and_receive(SSH, ChannelId, Type, Data, close, ?DEFAULT_TIMEOUT). -%%%----------------------------------------------------------------- -%%% @spec send_and_receive(SSH,ChannelId,Data,End,Timeout) -> -%%% {ok,Data} | {error,Reason} -%%% @equiv send_and_receive(SSH,ChannelId,0,Data,End,Timeout) send_and_receive(SSH, ChannelId, Data, End, Timeout) when is_integer(Timeout) -> send_and_receive(SSH, ChannelId, 0, Data, End, Timeout); -%%%----------------------------------------------------------------- -%%% @spec send_and_receive(SSH,ChannelId,Type,Data,Timeout) -> -%%% {ok,Data} | {error,Reason} -%%% @equiv send_and_receive(SSH,ChannelId,Type,Data,close,Timeout) send_and_receive(SSH, ChannelId, Type, Data, Timeout) when is_integer(Type) -> send_and_receive(SSH, ChannelId, Type, Data, close, Timeout); -%%%----------------------------------------------------------------- -%%% @spec send_and_receive(SSH,ChannelId,Type,Data,End) -> -%%% {ok,Data} | {error,Reason} -%%% @equiv send_and_receive(SSH,ChannelId,Type,Data,End,DefaultTimeout) send_and_receive(SSH, ChannelId, Type, Data, End) when is_function(End) -> send_and_receive(SSH, ChannelId, Type, Data, End, ?DEFAULT_TIMEOUT). -%%%----------------------------------------------------------------- -%%% @spec send_and_receive(SSH,ChannelId,Type,Data,End,Timeout) -> -%%% {ok,Data} | {error,Reason} -%%% SSH = connection() -%%% ChannelId = integer() -%%% Type = integer() -%%% Data = list() -%%% End = Fun | close | timeout -%%% Timeout = integer() -%%% Reason = term() -%%% -%%% @doc Send data to server on specified session channel and wait -%%% to receive the server response. -%%% -%%% <p>See <code>receive_response/4</code> for details on the -%%% <code>End</code> argument.</p> send_and_receive(SSH, ChannelId, Type, Data, End, Timeout) -> call(SSH, {send_and_receive,ChannelId,Type,Data,End,Timeout}). -%%%----------------------------------------------------------------- -%%% @spec subsystem(SSH,ChannelId,Subsystem) -> Status | {error,Reason} -%%% @equiv subsystem(SSH,ChannelId,Subsystem,DefaultTimeout) subsystem(SSH, ChannelId, Subsystem) -> subsystem(SSH, ChannelId, Subsystem, ?DEFAULT_TIMEOUT). -%%%----------------------------------------------------------------- -%%% @spec subsystem(SSH,ChannelId,Subsystem,Timeout) -> -%%% Status | {error,Reason} -%%% SSH = connection() -%%% ChannelId = integer() -%%% Subsystem = string() -%%% Timeout = integer() -%%% Status = success | failure -%%% Reason = term() -%%% -%%% @doc Sends a request to execute a predefined subsystem. subsystem(SSH, ChannelId, Subsystem, Timeout) -> call(SSH, {subsystem,ChannelId,Subsystem,Timeout}). @@ -511,439 +254,157 @@ shell(SSH, ChannelId, Timeout) -> %%%----------------------------------------------------------------- %%%------------------------ SFTP COMMANDS -------------------------- -%%%----------------------------------------------------------------- -%%% @spec sftp_connect(SSH) -> {ok,Server} | {error,Reason} -%%% SSH = connection() -%%% Server = pid() -%%% Reason = term() -%%% @doc Starts an SFTP session on an already existing SSH connection. -%%% <code>Server</code> identifies the new session and must be -%%% specified whenever SFTP requests are to be sent. sftp_connect(SSH) -> call(SSH, sftp_connect). -%%%----------------------------------------------------------------- -%%% @spec read_file(SSH, File) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). read_file(SSH, File) -> call(SSH, {read_file,sftp,File}). -%%%----------------------------------------------------------------- -%%% @spec read_file(SSH, Server, File) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + read_file(SSH, Server, File) -> call(SSH, {read_file,Server,File}). -%%%----------------------------------------------------------------- -%%% @spec write_file(SSH, File, Iolist) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). write_file(SSH, File, Iolist) -> call(SSH, {write_file,sftp,File,Iolist}). -%%%----------------------------------------------------------------- -%%% @spec write_file(SSH, Server, File, Iolist) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + write_file(SSH, Server, File, Iolist) -> call(SSH, {write_file,Server,File,Iolist}). -%%%----------------------------------------------------------------- -%%% @spec list_dir(SSH, Path) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). list_dir(SSH, Path) -> call(SSH, {list_dir,sftp,Path}). -%%%----------------------------------------------------------------- -%%% @spec list_dir(SSH, Server, Path) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + list_dir(SSH, Server, Path) -> call(SSH, {list_dir,Server,Path}). -%%%----------------------------------------------------------------- -%%% @spec open(SSH, File, Mode) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). open(SSH, File, Mode) -> call(SSH, {open,sftp,File,Mode}). -%%%----------------------------------------------------------------- -%%% @spec open(SSH, Server, File, Mode) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + open(SSH, Server, File, Mode) -> call(SSH, {open,Server,File,Mode}). -%%%----------------------------------------------------------------- -%%% @spec opendir(SSH, Path) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). opendir(SSH, Path) -> call(SSH, {opendir,sftp,Path}). -%%%----------------------------------------------------------------- -%%% @spec opendir(SSH, Server, Path) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + opendir(SSH, Server, Path) -> call(SSH, {opendir,Server,Path}). -%%%----------------------------------------------------------------- -%%% @spec close(SSH, Handle) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). close(SSH, Handle) -> call(SSH, {close,sftp,Handle}). -%%%----------------------------------------------------------------- -%%% @spec close(SSH, Server, Handle) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + close(SSH, Server, Handle) -> call(SSH, {close,Server,Handle}). -%%%----------------------------------------------------------------- -%%% @spec read(SSH, Handle, Len) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). read(SSH, Handle, Len) -> call(SSH, {read,sftp,Handle,Len}). -%%%----------------------------------------------------------------- -%%% @spec read(SSH, Server, Handle, Len) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + read(SSH, Server, Handle, Len) -> call(SSH, {read,Server,Handle,Len}). -%%%----------------------------------------------------------------- -%%% @spec pread(SSH, Handle, Position, Length) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). pread(SSH, Handle, Position, Length) -> call(SSH, {pread,sftp,Handle,Position,Length}). -%%%----------------------------------------------------------------- -%%% @spec pread(SSH, Server, Handle, Position, Length) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + pread(SSH, Server, Handle, Position, Length) -> call(SSH, {pread,Server,Handle,Position,Length}). -%%%----------------------------------------------------------------- -%%% @spec aread(SSH, Handle, Len) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). aread(SSH, Handle, Len) -> call(SSH, {aread,sftp,Handle,Len}). -%%%----------------------------------------------------------------- -%%% @spec aread(SSH, Server, Handle, Len) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + aread(SSH, Server, Handle, Len) -> call(SSH, {aread,Server,Handle,Len}). -%%%----------------------------------------------------------------- -%%% @spec apread(SSH, Handle, Position, Length) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). apread(SSH, Handle, Position, Length) -> call(SSH, {apread,sftp,Handle,Position,Length}). -%%%----------------------------------------------------------------- -%%% @spec apread(SSH, Server, Handle, Position, Length) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + apread(SSH, Server, Handle, Position, Length) -> call(SSH, {apread,Server,Handle,Position,Length}). -%%%----------------------------------------------------------------- -%%% @spec write(SSH, Handle, Data) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). write(SSH, Handle, Data) -> call(SSH, {write,sftp,Handle,Data}). -%%%----------------------------------------------------------------- -%%% @spec write(SSH, Server, Handle, Data) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + write(SSH, Server, Handle, Data) -> call(SSH, {write,Server,Handle,Data}). -%%%----------------------------------------------------------------- -%%% @spec pwrite(SSH, Handle, Position, Data) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). pwrite(SSH, Handle, Position, Data) -> call(SSH, {pwrite,sftp,Handle,Position,Data}). -%%%----------------------------------------------------------------- -%%% @spec pwrite(SSH, Server, Handle, Position, Data) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + pwrite(SSH, Server, Handle, Position, Data) -> call(SSH, {pwrite,Server,Handle,Position,Data}). -%%%----------------------------------------------------------------- -%%% @spec awrite(SSH, Handle, Data) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). awrite(SSH, Handle, Data) -> call(SSH, {awrite,sftp,Handle, Data}). -%%%----------------------------------------------------------------- -%%% @spec awrite(SSH, Server, Handle, Data) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + awrite(SSH, Server, Handle, Data) -> call(SSH, {awrite,Server,Handle, Data}). -%%%----------------------------------------------------------------- -%%% @spec apwrite(SSH, Handle, Position, Data) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). apwrite(SSH, Handle, Position, Data) -> call(SSH, {apwrite,sftp,Handle,Position,Data}). -%%%----------------------------------------------------------------- -%%% @spec apwrite(SSH, Server, Handle, Position, Data) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + apwrite(SSH, Server, Handle, Position, Data) -> call(SSH, {apwrite,Server,Handle,Position,Data}). -%%%----------------------------------------------------------------- -%%% @spec position(SSH, Handle, Location) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). position(SSH, Handle, Location) -> call(SSH, {position,sftp,Handle,Location}). -%%%----------------------------------------------------------------- -%%% @spec position(SSH, Server, Handle, Location) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + position(SSH, Server, Handle, Location) -> call(SSH, {position,Server,Handle,Location}). -%%%----------------------------------------------------------------- -%%% @spec read_file_info(SSH, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). read_file_info(SSH, Name) -> call(SSH, {read_file_info,sftp,Name}). -%%%----------------------------------------------------------------- -%%% @spec read_file_info(SSH, Server, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + read_file_info(SSH, Server, Name) -> call(SSH, {read_file_info,Server,Name}). -%%%----------------------------------------------------------------- -%%% @spec get_file_info(SSH, Handle) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). get_file_info(SSH, Handle) -> call(SSH, {get_file_info,sftp,Handle}). -%%%----------------------------------------------------------------- -%%% @spec get_file_info(SSH, Server, Handle) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + get_file_info(SSH, Server, Handle) -> call(SSH, {get_file_info,Server,Handle}). -%%%----------------------------------------------------------------- -%%% @spec read_link_info(SSH, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). read_link_info(SSH, Name) -> call(SSH, {read_link_info,sftp,Name}). -%%%----------------------------------------------------------------- -%%% @spec read_link_info(SSH, Server, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + read_link_info(SSH, Server, Name) -> call(SSH, {read_link_info,Server,Name}). -%%%----------------------------------------------------------------- -%%% @spec write_file_info(SSH, Name, Info) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). write_file_info(SSH, Name, Info) -> call(SSH, {write_file_info,sftp,Name,Info}). -%%%----------------------------------------------------------------- -%%% @spec write_file_info(SSH, Server, Name, Info) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + write_file_info(SSH, Server, Name, Info) -> call(SSH, {write_file_info,Server,Name,Info}). -%%%----------------------------------------------------------------- -%%% @spec read_link(SSH, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). read_link(SSH, Name) -> call(SSH, {read_link,sftp,Name}). -%%%----------------------------------------------------------------- -%%% @spec read_link(SSH, Server, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + read_link(SSH, Server, Name) -> call(SSH, {read_link,Server,Name}). -%%%----------------------------------------------------------------- -%%% @spec make_symlink(SSH, Name, Target) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). make_symlink(SSH, Name, Target) -> call(SSH, {make_symlink,sftp,Name,Target}). -%%%----------------------------------------------------------------- -%%% @spec make_symlink(SSH, Server, Name, Target) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + make_symlink(SSH, Server, Name, Target) -> call(SSH, {make_symlink,Server,Name,Target}). -%%%----------------------------------------------------------------- -%%% @spec rename(SSH, OldName, NewName) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). rename(SSH, OldName, NewName) -> call(SSH, {rename,sftp,OldName,NewName}). -%%%----------------------------------------------------------------- -%%% @spec rename(SSH, Server, OldName, NewName) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + rename(SSH, Server, OldName, NewName) -> call(SSH, {rename,Server,OldName,NewName}). -%%%----------------------------------------------------------------- -%%% @spec delete(SSH, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + delete(SSH, Name) -> call(SSH, {delete,sftp,Name}). -%%%----------------------------------------------------------------- -%%% @spec delete(SSH, Server, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + delete(SSH, Server, Name) -> call(SSH, {delete,Server,Name}). -%%%----------------------------------------------------------------- -%%% @spec make_dir(SSH, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). make_dir(SSH, Name) -> call(SSH, {make_dir,sftp,Name}). -%%%----------------------------------------------------------------- -%%% @spec make_dir(SSH, Server, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + make_dir(SSH, Server, Name) -> call(SSH, {make_dir,Server,Name}). -%%%----------------------------------------------------------------- -%%% @spec del_dir(SSH, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). del_dir(SSH, Name) -> call(SSH, {del_dir,sftp,Name}). -%%%----------------------------------------------------------------- -%%% @spec del_dir(SSH, Server, Name) -> Result -%%% SSH = connection() -%%% Result = ssh_sftp_return() | {error,Reason} -%%% Reason = term() -%%% @doc For info and other types, see ssh_sftp(3). + del_dir(SSH, Server, Name) -> call(SSH, {del_dir,Server,Name}). @@ -952,7 +413,6 @@ del_dir(SSH, Server, Name) -> %%% Callback functions %%%================================================================= -%% @hidden init(KeyOrName, {ConnType,Addr,Port}, AllOpts) -> User = proplists:get_value(user, AllOpts), Password = case proplists:get_value(password, AllOpts) of @@ -996,12 +456,12 @@ init(KeyOrName, {ConnType,Addr,Port}, AllOpts) -> try_log(heading(init,KeyOrName), "Opened ~w connection:\n" "Host: ~tp (~p)\nUser: ~tp\nPassword: ~p\n", - [ConnType,Addr,Port,User,lists:duplicate(length(Password),$*)]), + [ConnType,Addr,Port,User, + lists:duplicate(string:length(Password),$*)]), {ok,SSHRef,#state{ssh_ref=SSHRef, conn_type=ConnType, target=KeyOrName}} end. -%% @hidden handle_msg(sftp_connect, State) -> #state{ssh_ref=SSHRef, target=Target} = State, try_log(heading(sftp_connect,Target), "SSH Ref: ~p", [SSHRef]), @@ -1245,15 +705,12 @@ handle_msg({del_dir,Srv,Name}=Cmd, S=#state{ssh_ref=SSHRef}) -> [SSHRef,ref(Srv,SSHRef),mod(Cmd)]), {ssh_sftp:del_dir(ref(Srv,SSHRef), Name),S}. -%% @hidden reconnect(_Addr,_State) -> {error,no_reconnection_of_ssh}. -%% @hidden close(SSHRef) -> disconnect(SSHRef). -%% @hidden terminate(SSHRef, State) -> case State#state.conn_type of ssh -> @@ -1270,8 +727,6 @@ terminate(SSHRef, State) -> %%%================================================================= %%% Internal functions -%%%----------------------------------------------------------------- -%%% do_recv_response(SSH, Chn, Data, End, Timeout) -> receive {ssh_cm, SSH, {open,Chn,RemoteChn,{session}}} -> @@ -1350,8 +805,6 @@ do_recv_response(SSH, Chn, Data, End, Timeout) -> end end. -%%%----------------------------------------------------------------- -%%% get_handle(SSH) when is_pid(SSH) -> {ok,SSH}; get_handle(SSH) -> @@ -1364,8 +817,6 @@ get_handle(SSH) -> Error end. -%%%----------------------------------------------------------------- -%%% call(SSH, Msg) -> call(SSH, Msg, infinity). @@ -1377,29 +828,19 @@ call(SSH, Msg, Timeout) -> Error end. -%%%----------------------------------------------------------------- -%%% ref(sftp, SSHRef) -> SSHRef; ref(Server, _) -> Server. -%%%----------------------------------------------------------------- -%%% mod(Cmd) -> [Op,_Server|Args] = tuple_to_list(Cmd), list_to_tuple([Op|Args]). -%%%----------------------------------------------------------------- -%%% heading(Function, Ref) -> io_lib:format("ct_ssh:~tw ~tp",[Function,Ref]). -%%%----------------------------------------------------------------- -%%% log(Heading, Str, Args) -> ct_gen_conn:log(Heading, Str, Args). -%%%----------------------------------------------------------------- -%%% try_log(Heading, Str, Args) -> try_log(Heading, Str, Args, infinity). @@ -1413,8 +854,6 @@ try_log(Heading, Str, Args, Timeout) -> ok end. -%%%----------------------------------------------------------------- -%%% debug(Str) -> debug(Str, []). diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl index b50cddd492..f9abecfd38 100644 --- a/lib/common_test/src/ct_telnet.erl +++ b/lib/common_test/src/ct_telnet.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,131 +18,6 @@ %% %CopyrightEnd% %% -%% @doc Common Test specific layer on top of telnet client `ct_telnet_client.erl' -%% -%% <p>Use this module to set up telnet connections, send commands and -%% perform string matching on the result. -%% See the `unix_telnet' manual page for information about how to use -%% `ct_telnet', and configure connections, specifically for unix hosts.</p> -%% <p>The following default values are defined in `ct_telnet':</p> -%% <pre> -%% Connection timeout = 10 sec (time to wait for connection) -%% Command timeout = 10 sec (time to wait for a command to return) -%% Max no of reconnection attempts = 3 -%% Reconnection interval = 5 sek (time to wait in between reconnection attempts) -%% Keep alive = true (will send NOP to the server every 8 sec if connection is idle) -%% Polling limit = 0 (max number of times to poll to get a remaining string terminated) -%% Polling interval = 1 sec (sleep time between polls)</pre> -%% <p>These parameters can be altered by the user with the following -%% configuration term:</p> -%% <pre> -%% {telnet_settings, [{connect_timeout,Millisec}, -%% {command_timeout,Millisec}, -%% {reconnection_attempts,N}, -%% {reconnection_interval,Millisec}, -%% {keep_alive,Bool}, -%% {poll_limit,N}, -%% {poll_interval,Millisec}, -%% {tcp_nodelay,Bool}]}.</pre> -%% <p><code>Millisec = integer(), N = integer()</code></p> -%% <p>Enter the <code>telnet_settings</code> term in a configuration -%% file included in the test and ct_telnet will retrieve the information -%% automatically. Note that `keep_alive' may be specified per connection if -%% required. See `unix_telnet' for details.</p> -%% -%% == Logging == -%% -%% The default logging behaviour of `ct_telnet' is to print information -%% to the test case HTML log about performed operations and commands -%% and their corresponding results. What won't be printed to the HTML log -%% are text strings sent from the telnet server that are not explicitly -%% received by means of a `ct_telnet' function such as `expect/3'. -%% `ct_telnet' may however be configured to use a special purpose event handler, -%% implemented in `ct_conn_log_h', for logging <b>all</b> telnet traffic. -%% To use this handler, you need to install a Common Test hook named -%% `cth_conn_log'. Example (using the test suite info function): -%% -%% ``` -%% suite() -> -%% [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}]. -%% ''' -%% -%% `conn_mod()' is the name of the common_test module implementing -%% the connection protocol, i.e. `ct_telnet'. -%% -%% The `cth_conn_log' hook performs unformatted logging of telnet data to -%% a separate text file. All telnet communication is captured and printed, -%% including arbitrary data sent from the server. The link to this text file -%% can be found on the top of the test case HTML log. -%% -%% By default, data for all telnet connections is logged in one common -%% file (named `default'), which might get messy e.g. if multiple telnet -%% sessions are running in parallel. It is therefore possible to create a -%% separate log file for each connection. To configure this, use the hook -%% option `hosts' and list the names of the servers/connections that will be -%% used in the suite. Note that the connections must be named for this to work -%% (see the `open' function below). -%% -%% The hook option named `log_type' may be used to change the `cth_conn_log' -%% behaviour. The default value of this option is `raw', which results in the -%% behaviour described above. If the value is set to `html', all telnet -%% communication is printed to the test case HTML log instead. -%% -%% All `cth_conn_log' hook options described above can also be specified in -%% a configuration file with the configuration variable `ct_conn_log'. Example: -%% -%% ``` -%% {ct_conn_log, [{ct_telnet,[{log_type,raw}, -%% {hosts,[key_or_name()]}]}]} -%% ''' -%% -%% <b>Note</b> that hook options specified in a configuration file -%% will overwrite any hardcoded hook options in the test suite! -%% -%% === Logging example === -%% -%% The following `ct_hooks' statement will cause printing of telnet traffic -%% to separate logs for the connections named `server1' and `server2'. -%% Traffic for any other connections will be logged in the default telnet log. -%% -%% ``` -%% suite() -> -%% [{ct_hooks, -%% [{cth_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}]}]. -%%''' -%% -%% As previously explained, the above specification could also be provided -%% by means of an entry like this in a configuration file: -%% -%% ``` -%% {ct_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}. -%% ''' -%% -%% in which case the `ct_hooks' statement in the test suite may simply look -%% like this: -%% -%% ``` -%% suite() -> -%% [{ct_hooks, [{cth_conn_log, []}]}]. -%% ''' -%% -%% @end - -%% @type connection_type() = telnet | ts1 | ts2 - -%% @type connection() = handle() | -%% {ct:target_name(),connection_type()} | ct:target_name() - -%% @type handle() = ct_gen_conn:handle(). Handle for a -%% specific telnet connection. - -%% @type prompt_regexp() = string(). A regular expression which -%% matches all possible prompts for a specific type of target. The -%% regexp must not have any groups i.e. when matching, re:run/3 shall -%% return a list with one single element. -%% -%% @see unix_telnet - -module(ct_telnet). -export([open/1, open/2, open/3, open/4, close/1]). @@ -186,20 +61,9 @@ reconn_int=?RECONN_TIMEOUT, tcp_nodelay=false}). -%%%----------------------------------------------------------------- -%%% @spec open(Name) -> {ok,Handle} | {error,Reason} -%%% @equiv open(Name,telnet) open(Name) -> open(Name,telnet). -%%%----------------------------------------------------------------- -%%% @spec open(Name,ConnType) -> {ok,Handle} | {error,Reason} -%%% Name = target_name() -%%% ConnType = ct_telnet:connection_type() -%%% Handle = ct_telnet:handle() -%%% Reason = term() -%%% -%%% @doc Open a telnet connection to the specified target host. open(Name,ConnType) -> case ct_util:get_key_from_name(Name) of {ok, unix} -> % unix host @@ -210,44 +74,9 @@ open(Name,ConnType) -> Error end. -%%%----------------------------------------------------------------- -%%% @spec open(KeyOrName,ConnType,TargetMod) -> -%%% {ok,Handle} | {error,Reason} -%%% @equiv open(KeyOrName,ConnType,TargetMod,[]) open(KeyOrName,ConnType,TargetMod) -> open(KeyOrName,ConnType,TargetMod,KeyOrName). -%%%----------------------------------------------------------------- -%%% @spec open(KeyOrName,ConnType,TargetMod,Extra) -> -%%% {ok,Handle} | {error,Reason} -%%% KeyOrName = Key | Name -%%% Key = atom() -%%% Name = ct:target_name() -%%% ConnType = connection_type() -%%% TargetMod = atom() -%%% Extra = term() -%%% Handle = handle() -%%% Reason = term() -%%% -%%% @doc Open a telnet connection to the specified target host. -%%% -%%% <p>The target data must exist in a configuration file. The connection -%%% may be associated with either <code>Name</code> and/or the returned -%%% <code>Handle</code>. To allocate a name for the target, -%%% use <code>ct:require/2</code> in a test case, or use a -%%% <code>require</code> statement in the suite info function -%%% (<code>suite/0</code>), or in a test case info function. -%%% If you want the connection to be associated with <code>Handle</code> only -%%% (in case you need to open multiple connections to a host for example), -%%% simply use <code>Key</code>, the configuration variable name, to -%%% specify the target. Note that a connection that has no associated target -%%% name can only be closed with the handle value.</p> -%%% -%%% <p><code>TargetMod</code> is a module which exports the functions -%%% <code>connect(Ip,Port,KeepAlive,Extra)</code> and <code>get_prompt_regexp()</code> -%%% for the given <code>TargetType</code> (e.g. <code>unix_telnet</code>).</p> -%%% -%%% @see ct:require/2 open(KeyOrName,ConnType,TargetMod,Extra) -> case ct:get_config({KeyOrName,ConnType}) of undefined -> @@ -287,17 +116,6 @@ open(KeyOrName,ConnType,TargetMod,Extra) -> {old,true}]) end. -%%%----------------------------------------------------------------- -%%% @spec close(Connection) -> ok | {error,Reason} -%%% Connection = ct_telnet:connection() -%%% Reason = term() -%%% -%%% @doc Close the telnet connection and stop the process managing it. -%%% -%%% <p>A connection may be associated with a target name and/or a handle. -%%% If <code>Connection</code> has no associated target name, it may only -%%% be closed with the handle value (see the <code>open/4</code> -%%% function).</p> close(Connection) -> case get_handle(Connection) of {ok,Pid} -> @@ -315,30 +133,10 @@ close(Connection) -> %%%================================================================= %%% Test suite interface %%%----------------------------------------------------------------- -%%% @spec cmd(Connection,Cmd) -> {ok,Data} | {error,Reason} -%%% @equiv cmd(Connection,Cmd,[]) + cmd(Connection,Cmd) -> cmd(Connection,Cmd,[]). -%%%----------------------------------------------------------------- -%%% @spec cmd(Connection,Cmd,Opts) -> {ok,Data} | {error,Reason} -%%% Connection = ct_telnet:connection() -%%% Cmd = string() -%%% Opts = [Opt] -%%% Opt = {timeout,timeout()} | {newline,boolean()} -%%% Data = [string()] -%%% Reason = term() -%%% @doc Send a command via telnet and wait for prompt. -%%% -%%% <p>This function will by default add a newline to the end of the -%%% given command. If this is not desired, the option -%%% `{newline,false}' can be used. This is necessary, for example, -%%% when sending telnet command sequences (prefixed with the -%%% Interprete As Command, IAC, character).</p> -%%% -%%% <p>The option `timeout' specifies how long the client shall wait for -%%% prompt. If the time expires, the function returns -%%% `{error,timeout}'. See the module description for information -%%% about the default value for the command timeout.</p> + cmd(Connection,Cmd,Opts) when is_list(Opts) -> case check_cmd_opts(Opts) of ok -> @@ -363,42 +161,13 @@ check_cmd_opts([]) -> check_cmd_opts(Opts) -> check_send_opts(Opts). -%%%----------------------------------------------------------------- -%%% @spec cmdf(Connection,CmdFormat,Args) -> {ok,Data} | {error,Reason} -%%% @equiv cmdf(Connection,CmdFormat,Args,[]) cmdf(Connection,CmdFormat,Args) -> cmdf(Connection,CmdFormat,Args,[]). -%%%----------------------------------------------------------------- -%%% @spec cmdf(Connection,CmdFormat,Args,Opts) -> {ok,Data} | {error,Reason} -%%% Connection = ct_telnet:connection() -%%% CmdFormat = string() -%%% Args = list() -%%% Opts = [Opt] -%%% Opt = {timeout,timeout()} | {newline,boolean()} -%%% Data = [string()] -%%% Reason = term() -%%% @doc Send a telnet command and wait for prompt -%%% (uses a format string and list of arguments to build the command). -%%% -%%% <p>See {@link cmd/3} further description.</p> + cmdf(Connection,CmdFormat,Args,Opts) when is_list(Args) -> Cmd = lists:flatten(io_lib:format(CmdFormat,Args)), cmd(Connection,Cmd,Opts). -%%%----------------------------------------------------------------- -%%% @spec get_data(Connection) -> {ok,Data} | {error,Reason} -%%% Connection = ct_telnet:connection() -%%% Data = [string()] -%%% Reason = term() -%%% @doc Get all data that has been received by the telnet client -%%% since the last command was sent. Note that only newline terminated -%%% strings are returned. If the last string received has not yet -%%% been terminated, the connection may be polled automatically until -%%% the string is complete. The polling feature is controlled -%%% by the `poll_limit' and `poll_interval' config values and is -%%% by default disabled (meaning the function will immediately -%%% return all complete strings received and save a remaining -%%% non-terminated string for a later `get_data' call). get_data(Connection) -> case get_handle(Connection) of {ok,Pid} -> @@ -407,29 +176,9 @@ get_data(Connection) -> Error end. -%%%----------------------------------------------------------------- -%%% @spec send(Connection,Cmd) -> ok | {error,Reason} -%%% @equiv send(Connection,Cmd,[]) send(Connection,Cmd) -> send(Connection,Cmd,[]). -%%%----------------------------------------------------------------- -%%% @spec send(Connection,Cmd,Opts) -> ok | {error,Reason} -%%% Connection = ct_telnet:connection() -%%% Cmd = string() -%%% Opts = [Opt] -%%% Opt = {newline,boolean()} -%%% Reason = term() -%%% @doc Send a telnet command and return immediately. -%%% -%%% This function will by default add a newline to the end of the -%%% given command. If this is not desired, the option -%%% `{newline,false}' can be used. This is necessary, for example, -%%% when sending telnet command sequences (prefixed with the -%%% Interprete As Command, IAC, character). -%%% -%%% <p>The resulting output from the command can be read with -%%% <code>get_data/1</code> or <code>expect/2/3</code>.</p> send(Connection,Cmd,Opts) -> case check_send_opts(Opts) of ok -> @@ -450,142 +199,16 @@ check_send_opts([Invalid|_]) -> check_send_opts([]) -> ok. - -%%%----------------------------------------------------------------- -%%% @spec sendf(Connection,CmdFormat,Args) -> ok | {error,Reason} -%%% @equiv sendf(Connection,CmdFormat,Args,[]) sendf(Connection,CmdFormat,Args) when is_list(Args) -> sendf(Connection,CmdFormat,Args,[]). -%%%----------------------------------------------------------------- -%%% @spec sendf(Connection,CmdFormat,Args,Opts) -> ok | {error,Reason} -%%% Connection = ct_telnet:connection() -%%% CmdFormat = string() -%%% Args = list() -%%% Opts = [Opt] -%%% Opt = {newline,boolean()} -%%% Reason = term() -%%% @doc Send a telnet command and return immediately (uses a format -%%% string and a list of arguments to build the command). sendf(Connection,CmdFormat,Args,Opts) when is_list(Args) -> Cmd = lists:flatten(io_lib:format(CmdFormat,Args)), send(Connection,Cmd,Opts). -%%%----------------------------------------------------------------- -%%% @spec expect(Connection,Patterns) -> term() -%%% @equiv expect(Connections,Patterns,[]) expect(Connection,Patterns) -> expect(Connection,Patterns,[]). -%%%----------------------------------------------------------------- -%%% @spec expect(Connection,Patterns,Opts) -> {ok,Match} | -%%% {ok,MatchList,HaltReason} | -%%% {error,Reason} -%%% Connection = ct_telnet:connection() -%%% Patterns = Pattern | [Pattern] -%%% Pattern = string() | {Tag,string()} | prompt | {prompt,Prompt} -%%% Prompt = string() -%%% Tag = term() -%%% Opts = [Opt] -%%% Opt = {idle_timeout,IdleTimeout} | {total_timeout,TotalTimeout} | -%%% repeat | {repeat,N} | sequence | {halt,HaltPatterns} | -%%% ignore_prompt | no_prompt_check | wait_for_prompt | -%%% {wait_for_prompt,Prompt} -%%% IdleTimeout = infinity | integer() -%%% TotalTimeout = infinity | integer() -%%% N = integer() -%%% HaltPatterns = Patterns -%%% MatchList = [Match] -%%% Match = RxMatch | {Tag,RxMatch} | {prompt,Prompt} -%%% RxMatch = [string()] -%%% HaltReason = done | Match -%%% Reason = timeout | {prompt,Prompt} -%%% -%%% @doc Get data from telnet and wait for the expected pattern. -%%% -%%% <p><code>Pattern</code> can be a POSIX regular expression. The function -%%% returns as soon as a pattern has been successfully matched (at least one, -%%% in the case of multiple patterns).</p> -%%% -%%% <p><code>RxMatch</code> is a list of matched strings. It looks -%%% like this: <code>[FullMatch, SubMatch1, SubMatch2, ...]</code> -%%% where <code>FullMatch</code> is the string matched by the whole -%%% regular expression and <code>SubMatchN</code> is the string that -%%% matched subexpression no <code>N</code>. Subexpressions are -%%% denoted with '(' ')' in the regular expression</p> -%%% -%%% <p>If a <code>Tag</code> is given, the returned <code>Match</code> -%%% will also include the matched <code>Tag</code>. Else, only -%%% <code>RxMatch</code> is returned.</p> -%%% -%%% <p>The <code>idle_timeout</code> option indicates that the function -%%% shall return if the telnet client is idle (i.e. if no data is -%%% received) for more than <code>IdleTimeout</code> milliseconds. Default -%%% timeout is 10 seconds.</p> -%%% -%%% <p>The <code>total_timeout</code> option sets a time limit for -%%% the complete expect operation. After <code>TotalTimeout</code> -%%% milliseconds, <code>{error,timeout}</code> is returned. The default -%%% value is <code>infinity</code> (i.e. no time limit).</p> -%%% -%%% <p>The function will return when a prompt is received, even if no -%%% pattern has yet been matched. In this event, -%%% <code>{error,{prompt,Prompt}}</code> is returned. -%%% However, this behaviour may be modified with the -%%% <code>ignore_prompt</code> or <code>no_prompt_check</code> option, which -%%% tells <code>expect</code> to return only when a match is found or after a -%%% timeout.</p> -%%% -%%% <p>If the <code>ignore_prompt</code> option is used, -%%% <code>ct_telnet</code> will ignore any prompt found. This option -%%% is useful if data sent by the server could include a pattern that -%%% would match the prompt regexp (as returned by -%%% <code>TargedMod:get_prompt_regexp/0</code>), but which should not -%%% cause the function to return.</p> -%%% -%%% <p>If the <code>no_prompt_check</code> option is used, -%%% <code>ct_telnet</code> will not search for a prompt at all. This -%%% is useful if, for instance, the <code>Pattern</code> itself -%%% matches the prompt.</p> -%%% -%%% <p>The <code>wait_for_prompt</code> option forces <code>ct_telnet</code> -%%% to wait until the prompt string has been received before returning -%%% (even if a pattern has already been matched). This is equal to calling: -%%% <code>expect(Conn, Patterns++[{prompt,Prompt}], [sequence|Opts])</code>. -%%% Note that <code>idle_timeout</code> and <code>total_timeout</code> -%%% may abort the operation of waiting for prompt.</p> -%%% -%%% <p>The <code>repeat</code> option indicates that the pattern(s) -%%% shall be matched multiple times. If <code>N</code> is given, the -%%% pattern(s) will be matched <code>N</code> times, and the function -%%% will return with <code>HaltReason = done</code>.</p> -%%% -%%% <p>The <code>sequence</code> option indicates that all patterns -%%% shall be matched in a sequence. A match will not be concluded -%%% untill all patterns are matched.</p> -%%% -%%% <p>Both <code>repeat</code> and <code>sequence</code> can be -%%% interrupted by one or more <code>HaltPatterns</code>. When -%%% <code>sequence</code> or <code>repeat</code> is used, there will -%%% always be a <code>MatchList</code> returned, i.e. a list of -%%% <code>Match</code> instead of only one <code>Match</code>. There -%%% will also be a <code>HaltReason</code> returned.</p> -%%% -%%% <p><underline>Examples:</underline><br/> -%%% <code>expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}],</code> -%%% <code>[sequence,{halt,[{nnn,"NNN"}]}]).</code><br/> will try to match -%%% "ABC" first and then "XYZ", but if "NNN" appears the function will -%%% return <code>{error,{nnn,["NNN"]}}</code>. If both "ABC" and "XYZ" -%%% are matched, the function will return -%%% <code>{ok,[AbcMatch,XyzMatch]}</code>.</p> -%%% -%%% <p><code>expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}],</code> -%%% <code>[{repeat,2},{halt,[{nnn,"NNN"}]}]).</code><br/> will try to match -%%% "ABC" or "XYZ" twice. If "NNN" appears the function will return -%%% with <code>HaltReason = {nnn,["NNN"]}</code>.</p> -%%% -%%% <p>The <code>repeat</code> and <code>sequence</code> options can be -%%% combined in order to match a sequence multiple times.</p> expect(Connection,Patterns,Opts) -> case get_handle(Connection) of {ok,Pid} -> @@ -596,7 +219,7 @@ expect(Connection,Patterns,Opts) -> %%%================================================================= %%% Callback functions -%% @hidden + init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) -> S0 = case ct:get_config(telnet_settings) of undefined -> @@ -677,7 +300,6 @@ set_telnet_defaults([Unknown|Ss],S) -> set_telnet_defaults([],S) -> S. -%% @hidden handle_msg({cmd,Cmd,Opts},State) -> start_gen_log(heading(cmd,State#state.name)), log(State,cmd,"Cmd: ~tp",[Cmd]), @@ -803,7 +425,6 @@ handle_msg({expect,Pattern,Opts},State) -> {Return1,State#state{buffer=NewBuffer,prompt=Prompt}}. -%% @hidden reconnect({Ip,Port,_Type},State) -> reconnect(Ip,Port,State#state.reconns,State). reconnect(Ip,Port,N,State=#state{name=Name, @@ -834,7 +455,6 @@ reconnect(Ip,Port,N,State=#state{name=Name, end. -%% @hidden terminate(TelnPid,State) -> Result = ct_telnet_client:close(TelnPid), log(State,close,"Telnet connection for ~w closed.",[TelnPid]), @@ -902,7 +522,6 @@ force_log(State,Action,String,Args) -> log(State,Action,String,Args,true). %%%----------------------------------------------------------------- -%%% @hidden log(State,Action,String,Args) when is_record(State, state) -> log(State,Action,String,Args,false); log(Name,Action,String,Args) when is_atom(Name) -> @@ -911,7 +530,6 @@ log(TelnPid,Action,String,Args) when is_pid(TelnPid) -> log(#state{teln_pid=TelnPid},Action,String,Args,false). %%%----------------------------------------------------------------- -%%% @hidden log(undefined,String,Args) -> log(#state{},undefined,String,Args,false); log(Name,String,Args) when is_atom(Name) -> @@ -920,7 +538,6 @@ log(TelnPid,String,Args) when is_pid(TelnPid) -> log(#state{teln_pid=TelnPid},undefined,String,Args). %%%----------------------------------------------------------------- -%%% @hidden log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port}, Action,String,Args,ForcePrint) -> Name1 = if Name == undefined -> get({ct_telnet_pid2name,TelnPid}); @@ -971,7 +588,6 @@ log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port}, end. %%%----------------------------------------------------------------- -%%% @hidden start_gen_log(Heading) -> %% check if output is suppressed case ct_util:is_silenced(telnet) of @@ -980,7 +596,6 @@ start_gen_log(Heading) -> end. %%%----------------------------------------------------------------- -%%% @hidden end_gen_log() -> %% check if output is suppressed case ct_util:is_silenced(telnet) of @@ -988,7 +603,6 @@ end_gen_log() -> false -> ct_gen_conn:end_log() end. -%%% @hidden %% Debug printouts. debug_cont_gen_log(Str,Args) -> Old = put(silent,true), @@ -1038,8 +652,7 @@ teln_get_all_data(State=#state{teln_pid=Pid,prx=Prx},Data,Acc,LastLine,Polls) -> found_prompt=false, prompt_check=true}). -%% @hidden -%% @doc Externally the silent_teln_expect function shall only be used +%% Externally the silent_teln_expect function shall only be used %% by the TargetModule, i.e. the target specific module which %% implements connect/2 and get_prompt_regexp/0. silent_teln_expect(Name,Pid,Data,Pattern,Prx,Opts) -> @@ -1057,9 +670,9 @@ silent_teln_expect(Name,Pid,Data,Pattern,Prx,Opts) -> %% 2) Sequence: Several patterns are given, and they are matched in %% the order they appear in the pattern list. %% 3a) Repeat (single): 1) is repeated either N times or until a halt -%% condition is fullfilled. +%% condition is fulfilled. %% 3b) Repeat (sequence): 2) is repeated either N times or until a -%% halt condition is fullfilled. +%% halt condition is fulfilled. teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) -> HaltPatterns = case get_ignore_prompt(Opts) of @@ -1203,7 +816,7 @@ wait_for_prompt2(Prompt, Pattern, Opts) -> {true,Pattern1,Opts1}. %% Repeat either single or sequence. All match results are accumulated -%% and returned when a halt condition is fulllfilled. +%% and returned when a halt condition is fulfilled. repeat_expect(_Name,_Pid,Rest,_Pattern,Acc,#eo{repeat=0}) -> {ok,lists:reverse(Acc),done,Rest}; repeat_expect(Name,Pid,Data,Pattern,Acc,EO) -> @@ -1342,7 +955,7 @@ one_expect1(Name,Pid,Data,Pattern,Rest,EO) -> %% 2) Sequence. %% First the whole data chunk is searched for a prompt (to avoid doing %% a regexp match for the prompt at each line). -%% If we are searching for anyting else, the datachunk is split into +%% If we are searching for anything else, the datachunk is split into %% lines and each line is matched against the first pattern in the list. %% When a match is found, the match result is accumulated, and we keep %% searching for the next pattern in the list. @@ -1530,8 +1143,6 @@ add_tabs([],[$\n|Acc],LastLine) -> add_tabs([],[],LastLine) -> {[],lists:reverse(LastLine)}. - -%%% @hidden teln_receive_until_prompt(Pid,Prx,Timeout) -> Fun = fun() -> teln_receive_until_prompt(Pid,Prx,[],[]) end, ct_gen_conn:do_within_time(Fun, Timeout). diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl index bd3755722f..2c18caf18f 100644 --- a/lib/common_test/src/ct_testspec.erl +++ b/lib/common_test/src/ct_testspec.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2017. All Rights Reserved. +%% Copyright Ericsson AB 2006-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,10 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework functions handling test specifications. -%%% -%%% <p>This module exports functions that are used within CT to -%%% scan and parse test specifikations.</p> -module(ct_testspec). -export([prepare_tests/1, prepare_tests/2, diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl index 468edc4bee..d8fd401a64 100644 --- a/lib/common_test/src/ct_util.erl +++ b/lib/common_test/src/ct_util.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,11 +18,11 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework Utilities. +%%% Common Test Framework Utilities. %%% -%%% <p>This is a support module for the Common Test Framework. It +%%% This is a support module for the Common Test Framework. It %%% implements the process ct_util_server which acts like a data -%%% holder for suite, configuration and connection data.</p> +%%% holder for suite, configuration and connection data. %%% -module(ct_util). @@ -83,20 +83,20 @@ %%%----------------------------------------------------------------- start() -> start(normal, ".", ?default_verbosity). -%%% @spec start(Mode) -> Pid | exit(Error) +%%% -spec start(Mode) -> Pid | exit(Error) %%% Mode = normal | interactive %%% Pid = pid() %%% -%%% @doc Start start the ct_util_server process +%%% Start start the ct_util_server process %%% (tool-internal use only). %%% -%%% <p>This function is called from ct_run.erl. It starts and initiates -%%% the <code>ct_util_server</code></p> +%%% This function is called from ct_run.erl. It starts and initiates +%%% the ct_util_server %%% -%%% <p>Returns the process identity of the -%%% <code>ct_util_server</code>.</p> +%%% Returns the process identity of the +%%% ct_util_server. %%% -%%% @see ct +%%% See ct. start(LogDir) when is_list(LogDir) -> start(normal, LogDir, ?default_verbosity); start(Mode) -> @@ -209,11 +209,10 @@ do_start(Parent, Mode, LogDir, Verbosity) -> self() ! {{stop,{self(),{user_error,CTHReason}}}, {Parent,make_ref()}} catch - _:CTHReason -> + _:CTHReason:StackTrace -> ErrorInfo = if is_atom(CTHReason) -> io_lib:format("{~tp,~tp}", - [CTHReason, - erlang:get_stacktrace()]); + [CTHReason, StackTrace]); true -> CTHReason end, @@ -521,19 +520,19 @@ get_key_from_name(Name)-> ct_config:get_key_from_name(Name). %%%----------------------------------------------------------------- -%%% @spec register_connection(TargetName,Address,Callback,Handle) -> +%%% -spec register_connection(TargetName,Address,Callback,Handle) -> %%% ok | {error,Reason} %%% TargetName = ct:target_name() %%% Address = term() %%% Callback = atom() %%% Handle = term %%% -%%% @doc Register a new connection (tool-internal use only). +%%% Register a new connection (tool-internal use only). %%% -%%% <p>This function can be called when a new connection is +%%% This function can be called when a new connection is %%% established. The connection data is stored in the connection %%% table, and ct_util will close all registered connections when the -%%% test is finished by calling <code>Callback:close/1</code>.</p> +%%% test is finished by calling Callback:close/1. register_connection(TargetName,Address,Callback,Handle) -> %% If TargetName is a registered alias for a config %% variable, use it as reference for the connection, @@ -554,28 +553,28 @@ register_connection(TargetName,Address,Callback,Handle) -> ok. %%%----------------------------------------------------------------- -%%% @spec unregister_connection(Handle) -> ok +%%% -spec unregister_connection(Handle) -> ok %%% Handle = term %%% -%%% @doc Unregister a connection (tool-internal use only). +%%% Unregister a connection (tool-internal use only). %%% -%%% <p>This function should be called when a registered connection is +%%% This function should be called when a registered connection is %%% closed. It removes the connection data from the connection -%%% table.</p> +%%% table. unregister_connection(Handle) -> ets:delete(?conn_table,Handle), ok. %%%----------------------------------------------------------------- -%%% @spec does_connection_exist(TargetName,Address,Callback) -> +%%% -spec does_connection_exist(TargetName,Address,Callback) -> %%% {ok,Handle} | false %%% TargetName = ct:target_name() %%% Address = address %%% Callback = atom() %%% Handle = term() %%% -%%% @doc Check if a connection already exists. +%%% Check if a connection already exists. does_connection_exist(TargetName,Address,Callback) -> case ct_config:get_key_from_name(TargetName) of {ok,_Key} -> @@ -595,7 +594,7 @@ does_connection_exist(TargetName,Address,Callback) -> end. %%%----------------------------------------------------------------- -%%% @spec get_connection(TargetName,Callback) -> +%%% -spec get_connection(TargetName,Callback) -> %%% {ok,Connection} | {error,Reason} %%% TargetName = ct:target_name() %%% Callback = atom() @@ -603,8 +602,8 @@ does_connection_exist(TargetName,Address,Callback) -> %%% Handle = term() %%% Address = term() %%% -%%% @doc Return the connection for <code>Callback</code> on the -%%% given target (<code>TargetName</code>). +%%% Return the connection for Callback on the +%%% given target (TargetName). get_connection(TargetName,Callback) -> %% check that TargetName is a registered alias case ct_config:get_key_from_name(TargetName) of @@ -625,7 +624,7 @@ get_connection(TargetName,Callback) -> end. %%%----------------------------------------------------------------- -%%% @spec get_connections(ConnPid) -> +%%% -spec get_connections(ConnPid) -> %%% {ok,Connections} | {error,Reason} %%% Connections = [Connection] %%% Connection = {TargetName,Handle,Callback,Address} @@ -634,8 +633,8 @@ get_connection(TargetName,Callback) -> %%% Callback = atom() %%% Address = term() %%% -%%% @doc Get data for all connections associated with a particular -%%% connection pid (see Callback:init/3). +%%% Get data for all connections associated with a particular +%%% connection pid (see Callback:init/3). get_connections(ConnPid) -> Conns = ets:tab2list(?conn_table), lists:flatmap(fun(#conn{targetref=TargetName, @@ -655,8 +654,7 @@ get_connections(ConnPid) -> end, Conns). %%%----------------------------------------------------------------- -%%% @hidden -%%% @equiv ct:get_target_name/1 +%%% Equivalent to ct:get_target_name/1 get_target_name(Handle) -> case ets:select(?conn_table,[{#conn{handle=Handle,targetref='$1',_='_'}, [], @@ -668,17 +666,14 @@ get_target_name(Handle) -> end. %%%----------------------------------------------------------------- -%%% @spec close_connections() -> ok +%%% -spec close_connections() -> ok %%% -%%% @doc Close all open connections. +%%% Close all open connections. close_connections() -> close_connections(ets:tab2list(?conn_table)), ok. %%%----------------------------------------------------------------- -%%% @spec -%%% -%%% @doc override_silence_all_connections() -> Protocols = [telnet,ftp,rpc,snmp,ssh], override_silence_connections(Protocols), @@ -739,12 +734,12 @@ reset_silent_connections() -> %%%----------------------------------------------------------------- -%%% @spec stop(Info) -> ok +%%% -spec stop(Info) -> ok %%% -%%% @doc Stop the ct_util_server and close all existing connections +%%% Stop the ct_util_server and close all existing connections %%% (tool-internal use only). %%% -%%% @see ct +%%% See ct. stop(Info) -> case whereis(ct_util_server) of undefined -> @@ -758,26 +753,25 @@ stop(Info) -> end. %%%----------------------------------------------------------------- -%%% @spec update_last_run_index() -> ok +%%% -spec update_last_run_index() -> ok %%% -%%% @doc Update <code>ct_run.<timestamp>/index.html</code> +%%% Update ct_run.<timestamp>/index.html %%% (tool-internal use only). update_last_run_index() -> call(update_last_run_index). %%%----------------------------------------------------------------- -%%% @spec get_mode() -> Mode +%%% -spec get_mode() -> Mode %%% Mode = normal | interactive %%% -%%% @doc Return the current mode of the ct_util_server +%%% Return the current mode of the ct_util_server %%% (tool-internal use only). get_mode() -> call(get_mode). %%%----------------------------------------------------------------- -%%% @hidden -%%% @equiv ct:listenv/1 +%%% Equivalent to ct:listenv/1 listenv(Telnet) -> case ct_telnet:send(Telnet,"listenv") of ok -> @@ -791,33 +785,32 @@ listenv(Telnet) -> end. %%%----------------------------------------------------------------- -%%% @hidden -%%% @equiv ct:parse_table/1 +%%% Equivalent to ct:parse_table/1 parse_table(Data) -> {Heading, Rest} = get_headings(Data), Lines = parse_row(Rest,[],size(Heading)), {Heading,Lines}. get_headings(["|" ++ Headings | Rest]) -> - {remove_space(string:tokens(Headings, "|"),[]), Rest}; + {remove_space(string:lexemes(Headings, "|"),[]), Rest}; get_headings([_ | Rest]) -> get_headings(Rest); get_headings([]) -> {{},[]}. parse_row(["|" ++ _ = Row | T], Rows, NumCols) when NumCols > 1 -> - case string:tokens(Row, "|") of + case string:lexemes(Row, "|") of Values when length(Values) =:= NumCols -> parse_row(T,[remove_space(Values,[])|Rows], NumCols); Values when length(Values) < NumCols -> parse_row([Row ++"\n"++ hd(T) | tl(T)], Rows, NumCols) end; -parse_row(["|" ++ _ = Row | T], Rows, 1 = NumCols) -> - case string:rchr(Row, $|) of - 1 -> +parse_row(["|" ++ X = Row | T], Rows, 1 = NumCols) -> + case string:find(X, [$|]) of + nomatch -> parse_row([Row ++"\n"++hd(T) | tl(T)], Rows, NumCols); _Else -> - parse_row(T, [remove_space(string:tokens(Row,"|"),[])|Rows], + parse_row(T, [remove_space(string:lexemes(Row,"|"),[])|Rows], NumCols) end; parse_row([_Skip | T], Rows, NumCols) -> @@ -826,22 +819,16 @@ parse_row([], Rows, _NumCols) -> lists:reverse(Rows). remove_space([Str|Rest],Acc) -> - remove_space(Rest,[string:strip(string:strip(Str),both,$')|Acc]); + remove_space(Rest,[string:trim(string:trim(Str,both,[$\s]),both,[$'])|Acc]); remove_space([],Acc) -> list_to_tuple(lists:reverse(Acc)). %%%----------------------------------------------------------------- -%%% @spec -%%% -%%% @doc is_test_dir(Dir) -> - lists:last(string:tokens(filename:basename(Dir), "_")) == "test". + lists:last(string:lexemes(filename:basename(Dir), "_")) == "test". %%%----------------------------------------------------------------- -%%% @spec -%%% -%%% @doc get_testdir(Dir, all) -> Abs = abs_name(Dir), case is_test_dir(Abs) of @@ -885,9 +872,6 @@ get_testdir(Dir, _) -> get_testdir(Dir, all). %%%----------------------------------------------------------------- -%%% @spec -%%% -%%% @doc get_attached(TCPid) -> case dbg_iserver:safe_call({get_attpid,TCPid}) of {ok,AttPid} when is_pid(AttPid) -> @@ -897,9 +881,6 @@ get_attached(TCPid) -> end. %%%----------------------------------------------------------------- -%%% @spec -%%% -%%% @doc kill_attached(undefined,_AttPid) -> ok; kill_attached(_TCPid,undefined) -> @@ -914,9 +895,6 @@ kill_attached(TCPid,AttPid) -> %%%----------------------------------------------------------------- -%%% @spec -%%% -%%% @doc warn_duplicates(Suites) -> Warn = fun(Mod) -> @@ -935,9 +913,6 @@ warn_duplicates(Suites) -> ok. %%%----------------------------------------------------------------- -%%% @spec -%%% -%%% @doc mark_process() -> mark_process(system). @@ -999,9 +974,6 @@ remaining_test_procs() -> {TestProcs, SharedGL, OtherGLs}. %%%----------------------------------------------------------------- -%%% @spec -%%% -%%% @doc get_profile_data() -> get_profile_data(all). @@ -1145,7 +1117,7 @@ open_url(iexplore, Args, URL) -> _ = case win32reg:values(R) of {ok, Paths} -> Path = proplists:get_value(default, Paths), - [Cmd | _] = string:tokens(Path, "%"), + [Cmd | _] = string:lexemes(Path, "%"), Cmd1 = Cmd ++ " " ++ Args ++ " " ++ URL, io:format(?def_gl, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd1]), open_port({spawn,Cmd1}, []); diff --git a/lib/common_test/src/ct_webtool.erl b/lib/common_test/src/ct_webtool.erl index 82aa78fc4b..32d4255217 100644 --- a/lib/common_test/src/ct_webtool.erl +++ b/lib/common_test/src/ct_webtool.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2017. All Rights Reserved. +%% Copyright Ericsson AB 2001-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. @@ -771,7 +771,7 @@ fill_out(Nr)-> %Controls whether the user selected a tool to start %---------------------------------------------------------------------- get_tools(Input)-> - case httpd:parse_query(Input) of + case uri_string:dissect_query(Input) of []-> no_tools; Tools-> diff --git a/lib/common_test/src/ct_webtool_sup.erl b/lib/common_test/src/ct_webtool_sup.erl index 6c6dbde0a6..04fbbf8745 100644 --- a/lib/common_test/src/ct_webtool_sup.erl +++ b/lib/common_test/src/ct_webtool_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2016. All Rights Reserved. +%% Copyright Ericsson AB 2001-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. diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl index 77f90c0df6..99c484de48 100644 --- a/lib/common_test/src/cth_log_redirect.erl +++ b/lib/common_test/src/cth_log_redirect.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2017. All Rights Reserved. +%% Copyright Ericsson AB 2011-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. @@ -19,11 +19,9 @@ %% -module(cth_log_redirect). -%%% @doc Common Test Framework functions handling test specifications. +%%% Common Test Framework functions handling test specifications. %%% -%%% <p>This module redirects sasl and error logger info to common test log.</p> -%%% @end - +%%% This module redirects sasl and error logger info to common test log. %% CTH Callbacks -export([id/1, init/2, @@ -33,17 +31,19 @@ pre_init_per_testcase/4, post_init_per_testcase/5, pre_end_per_testcase/4, post_end_per_testcase/5]). -%% Event handler Callbacks --export([init/1, - handle_event/2, handle_call/2, handle_info/2, - terminate/1, terminate/2, code_change/3]). +%% Logger handler and gen_server callbacks +-export([log/2, + init/1, + handle_cast/2, handle_call/3, + terminate/1, terminate/2]). %% Other -export([handle_remote_events/1]). -include("ct.hrl"). +-include("../../kernel/src/logger_internal.hrl"). --behaviour(gen_event). +-behaviour(gen_server). -record(eh_state, {log_func, curr_suite, @@ -57,7 +57,7 @@ id(_Opts) -> init(?MODULE, _Opts) -> ct_util:mark_process(), - error_logger:add_report_handler(?MODULE), + ok = start_log_handler(), tc_log_async. pre_init_per_suite(Suite, Config, State) -> @@ -100,7 +100,7 @@ pre_end_per_testcase(_Suite, _TC, Config, State) -> post_end_per_testcase(_Suite, _TC, _Config, Result, State) -> %% Make sure that the event queue is flushed %% before ending this test case. - gen_event:call(error_logger, ?MODULE, flush, 300000), + gen_server:call(?MODULE, flush, 300000), {Result, State}. pre_end_per_group(_Suite, Group, Config, {tc_log, Group}) -> @@ -114,127 +114,155 @@ post_end_per_group(_Suite, _Group, Config, Return, State) -> set_curr_func({group,undefined}, Config), {Return, State}. -%% Copied and modified from sasl_report_tty_h.erl -init(_Type) -> - {ok, #eh_state{log_func = tc_log_async}}. - -handle_event({_Type,GL,_Msg}, #eh_state{handle_remote_events = false} = State) - when node(GL) /= node() -> - {ok, State}; -handle_event(Event, #eh_state{log_func = LogFunc} = State) -> - case lists:keyfind(sasl, 1, application:which_applications()) of - false -> - sasl_not_started; - _Else -> - {ok, ErrLogType} = application:get_env(sasl, errlog_type), - SReport = sasl_report:format_report(group_leader(), ErrLogType, - tag_event(Event, local)), - if is_list(SReport) -> - SaslHeader = format_header(State), - case LogFunc of - tc_log -> - ct_logs:tc_log(sasl, ?STD_IMPORTANCE, - SaslHeader, SReport, [], []); - tc_log_async -> - ct_logs:tc_log_async(sasl, ?STD_IMPORTANCE, - SaslHeader, SReport, []) - end; - true -> %% Report is an atom if no logging is to be done - ignore - end - end, - %% note that error_logger (unlike sasl) expects UTC time - EReport = error_logger_tty_h:write_event( - tag_event(Event, utc), io_lib), - if is_list(EReport) -> - ErrHeader = format_header(State), - case LogFunc of - tc_log -> - ct_logs:tc_log(error_logger, ?STD_IMPORTANCE, - ErrHeader, EReport, [], []); - tc_log_async -> - ct_logs:tc_log_async(error_logger, ?STD_IMPORTANCE, - ErrHeader, EReport, []) - end; - true -> %% Report is an atom if no logging is to be done - ignore +start_log_handler() -> + case whereis(?MODULE) of + undefined -> + ChildSpec = + #{id=>?MODULE, + start=>{gen_server,start_link,[{local,?MODULE},?MODULE,[],[]]}, + restart=>transient, + shutdown=>2000, + type=>worker, + modules=>[?MODULE]}, + {ok,_} = supervisor:start_child(logger_sup,ChildSpec); + _Pid -> + ok end, - {ok, State}. + ok = logger:add_handler(?MODULE,?MODULE, + #{level=>info, + formatter=>{?DEFAULT_FORMATTER, + ?DEFAULT_FORMAT_CONFIG}}). + +init([]) -> + {ok, #eh_state{log_func = tc_log_async}}. -handle_info({'EXIT',User,killed}, State) -> - case whereis(user) of - %% init:stop/1/2 has been called, let's finish! +log(#{msg:={report,Msg},meta:=#{domain:=[otp,sasl]}}=Log,Config) -> + case whereis(sasl_sup) of undefined -> - remove_handler; - User -> - remove_handler; - _ -> - {ok,State} + ok; % sasl application is not started + _Else -> + Level = + case application:get_env(sasl, errlog_type) of + {ok,error} -> + error; + {ok,_} -> + info; + undefined -> + info + end, + case Level of + error -> + case Msg of + #{label:={_,progress}} -> + ok; + _ -> + do_log(add_log_category(Log,sasl),Config) + end; + _ -> + do_log(add_log_category(Log,sasl),Config) + end end; +log(#{meta:=#{domain:=[otp]}}=Log,Config) -> + do_log(add_log_category(Log,error_logger),Config); +log(#{meta:=#{domain:=_}},_) -> + ok; +log(Log,Config) -> + do_log(add_log_category(Log,error_logger),Config). + +add_log_category(#{meta:=Meta}=Log,Category) -> + Log#{meta=>Meta#{?MODULE=>#{category=>Category}}}. + +do_log(Log,Config) -> + gen_server:call(?MODULE,{log,Log,Config}). -handle_info(_, State) -> - {ok,State}. +handle_cast(_, State) -> + {noreply,State}. -handle_call(flush,State) -> - {ok, ok, State}; +handle_call({log,#{meta:=#{gl:=GL}},_}, _From, + #eh_state{handle_remote_events=false}=State) + when node(GL) /= node() -> + {reply, ok, State}; + +handle_call({log, + #{msg:=Msg0, + meta:=#{?MODULE:=#{category:=Category}}=Meta}=Log, + #{formatter:={Formatter,FConfig}}}, + _From, + #eh_state{log_func=LogFunc}=State) -> + Header = format_header(State), + Msg = + case Msg0 of + {report,R} -> + Fun=maps:get(report_cb,Meta,fun logger:format_report/1), + Fun(R); + _ -> + Msg0 + end, + String = Formatter:format(Log#{msg=>Msg},FConfig), + case LogFunc of + tc_log -> + ct_logs:tc_log(Category, ?STD_IMPORTANCE, + Header, String, [], []); + tc_log_async -> + ct_logs:tc_log_async(sasl, ?STD_IMPORTANCE, + Header, String, []) + end, + {reply,ok,State}; -handle_call({set_curr_func,{group,Group,Conf},Config}, - State) when is_list(Config) -> +handle_call(flush,_From,State) -> + {reply, ok, State}; + +handle_call({set_curr_func,{group,Group,Conf},Config},_From,State) + when is_list(Config) -> Parallel = case proplists:get_value(tc_group_properties, Config) of undefined -> false; Props -> lists:member(parallel, Props) end, - {ok, ok, State#eh_state{curr_group = Group, - curr_func = Conf, - parallel_tcs = Parallel}}; -handle_call({set_curr_func,{group,Group,Conf},_SkipOrFail}, State) -> - {ok, ok, State#eh_state{curr_group = Group, - curr_func = Conf, - parallel_tcs = false}}; -handle_call({set_curr_func,{group,undefined},_Config}, State) -> - {ok, ok, State#eh_state{curr_group = undefined, - curr_func = undefined, - parallel_tcs = false}}; -handle_call({set_curr_func,{Suite,Conf},_Config}, State) -> - {ok, ok, State#eh_state{curr_suite = Suite, - curr_func = Conf, - parallel_tcs = false}}; -handle_call({set_curr_func,undefined,_Config}, State) -> - {ok, ok, State#eh_state{curr_suite = undefined, - curr_func = undefined, - parallel_tcs = false}}; -handle_call({set_curr_func,TC,_Config}, State) -> - {ok, ok, State#eh_state{curr_func = TC}}; - -handle_call({set_logfunc,NewLogFunc}, State) -> - {ok, NewLogFunc, State#eh_state{log_func = NewLogFunc}}; - -handle_call({handle_remote_events,Bool}, State) -> - {ok, ok, State#eh_state{handle_remote_events = Bool}}; - -handle_call(_Query, _State) -> - {error, bad_query}. + {reply, ok, State#eh_state{curr_group = Group, + curr_func = Conf, + parallel_tcs = Parallel}}; +handle_call({set_curr_func,{group,Group,Conf},_SkipOrFail}, _From, State) -> + {reply, ok, State#eh_state{curr_group = Group, + curr_func = Conf, + parallel_tcs = false}}; +handle_call({set_curr_func,{group,undefined},_Config}, _From, State) -> + {reply, ok, State#eh_state{curr_group = undefined, + curr_func = undefined, + parallel_tcs = false}}; +handle_call({set_curr_func,{Suite,Conf},_Config}, _From, State) -> + {reply, ok, State#eh_state{curr_suite = Suite, + curr_func = Conf, + parallel_tcs = false}}; +handle_call({set_curr_func,undefined,_Config}, _From, State) -> + {reply, ok, State#eh_state{curr_suite = undefined, + curr_func = undefined, + parallel_tcs = false}}; +handle_call({set_curr_func,TC,_Config}, _From, State) -> + {reply, ok, State#eh_state{curr_func = TC}}; + +handle_call({set_logfunc,NewLogFunc}, _From, State) -> + {reply, NewLogFunc, State#eh_state{log_func = NewLogFunc}}; + +handle_call({handle_remote_events,Bool}, _From, State) -> + {reply, ok, State#eh_state{handle_remote_events = Bool}}. terminate(_) -> - error_logger:delete_report_handler(?MODULE), - []. + _ = logger:remove_handler(?MODULE), + _ = supervisor:terminate_child(logger_sup,?MODULE), + _ = supervisor:delete_child(logger_sup,?MODULE), + ok. terminate(_Arg, _State) -> ok. -tag_event(Event, utc) -> - {calendar:universal_time(), Event}; -tag_event(Event, _) -> - {calendar:local_time(), Event}. - set_curr_func(CurrFunc, Config) -> - gen_event:call(error_logger, ?MODULE, {set_curr_func, CurrFunc, Config}). + gen_server:call(?MODULE, {set_curr_func, CurrFunc, Config}). set_log_func(Func) -> - gen_event:call(error_logger, ?MODULE, {set_logfunc, Func}). + gen_server:call(?MODULE, {set_logfunc, Func}). handle_remote_events(Bool) -> - gen_event:call(error_logger, ?MODULE, {handle_remote_events, Bool}). + gen_server:call(?MODULE, {handle_remote_events, Bool}). %%%----------------------------------------------------------------- @@ -272,6 +300,3 @@ format_header(#eh_state{curr_suite = Suite, curr_func = TC}) -> io_lib:format("System report during ~w:~tw/1 in ~tw", [Suite,TC,Group]). - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl index da68bd105e..b0742717ae 100644 --- a/lib/common_test/src/cth_surefire.erl +++ b/lib/common_test/src/cth_surefire.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012-2017. All Rights Reserved. +%% Copyright Ericsson AB 2012-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,10 +18,10 @@ %% %CopyrightEnd% %%-------------------------------------------------------------------- -%%% @doc Common Test Framework functions handling test specifications. +%%% Common Test Framework functions handling test specifications. %%% -%%% <p>This module creates a junit report of the test run if plugged in -%%% as a suite_callback.</p> +%%% This module creates a junit report of the test run if plugged in +%%% as a suite_callback. -module(cth_surefire). @@ -184,15 +184,14 @@ end_tc(Name, _Config, _Res, State = #state{ curr_suite = Suite, Log = case Log0 of "" -> - LowerSuiteName = string:to_lower(atom_to_list(Suite)), + LowerSuiteName = string:lowercase(atom_to_list(Suite)), filename:join(CurrLogDir,LowerSuiteName++"."++Name++".html"); _ -> Log0 end, Url = make_url(UrlBase,Log), ClassName = atom_to_list(Suite), - PGroup = string:join([ atom_to_list(Group)|| - Group <- lists:reverse(Groups)],"."), + PGroup = lists:concat(lists:join(".",lists:reverse(Groups))), TimeTakes = io_lib:format("~f",[timer:now_diff(?now,TS) / 1000000]), State#state{ test_cases = [#testcase{ log = Log, url = Url, @@ -317,9 +316,9 @@ make_url(undefined,_) -> make_url(_,[]) -> undefined; make_url(UrlBase0,Log) -> - UrlBase = string:strip(UrlBase0,right,$/), + UrlBase = string:trim(UrlBase0,trailing,[$/]), RelativeLog = get_relative_log_url(Log), - string:join([UrlBase,RelativeLog],"/"). + lists:flatten(lists:join($/,[UrlBase,RelativeLog])). get_test_root(Log) -> LogParts = filename:split(Log), @@ -329,7 +328,7 @@ get_relative_log_url(Log) -> LogParts = filename:split(Log), Start = length(LogParts)-?log_depth, Length = ?log_depth+1, - string:join(lists:sublist(LogParts,Start,Length),"/"). + lists:flatten(lists:join($/,lists:sublist(LogParts,Start,Length))). count_tcs([#testcase{name=ConfCase}|TCs],Ok,F,S) when ConfCase=="init_per_suite"; diff --git a/lib/common_test/src/test_server.erl b/lib/common_test/src/test_server.erl index e56106408f..a896a0551b 100644 --- a/lib/common_test/src/test_server.erl +++ b/lib/common_test/src/test_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. All Rights Reserved. +%% Copyright Ericsson AB 1996-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. @@ -463,11 +463,12 @@ run_test_case_msgloop(#st{ref=Ref,pid=Pid,end_conf_pid=EndConfPid0}=St0) -> %% it as a comment, potentially replacing user data Error = lists:flatten(io_lib:format("Aborted: ~tp", [Reason])), - Error1 = lists:flatten([string:strip(S,left) || - S <- string:tokens(Error, - [$\n])]), - Comment = if length(Error1) > 63 -> - string:substr(Error1,1,60) ++ "..."; + Error1 = lists:flatten([string:trim(S,leading,"\s") || + S <- string:lexemes(Error, + [$\n])]), + ErrorLength = string:length(Error1), + Comment = if ErrorLength > 63 -> + string:slice(Error1,0,60) ++ "..."; true -> Error1 end, @@ -1339,13 +1340,12 @@ do_init_per_testcase(Mod, Args) -> {skip,Reason}; exit:{Skip,Reason} when Skip =:= skip; Skip =:= skipped -> {skip,Reason}; - throw:Other -> - set_loc(erlang:get_stacktrace()), + throw:Other:Stk -> + set_loc(Stk), Line = get_loc(), print_init_conf_result(Line,"thrown",Other), {skip,{failed,{Mod,init_per_testcase,Other}}}; - _:Reason0 -> - Stk = erlang:get_stacktrace(), + _:Reason0:Stk -> Reason = {Reason0,Stk}, set_loc(Stk), Line = get_loc(), @@ -1394,20 +1394,19 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) -> _ -> ok catch - throw:Other -> + throw:Other:Stk -> Comment0 = case read_comment() of "" -> ""; Cmt -> Cmt ++ test_server_ctrl:xhtml("<br>", "<br />") end, - set_loc(erlang:get_stacktrace()), + set_loc(Stk), comment(io_lib:format("~ts<font color=\"red\">" "WARNING: ~w thrown!" "</font>\n",[Comment0,EndFunc])), print_end_tc_warning(EndFunc,Other,"thrown",get_loc()), {failed,{Mod,end_per_testcase,Other}}; - Class:Reason -> - Stk = erlang:get_stacktrace(), + Class:Reason:Stk -> set_loc(Stk), Why = case Class of exit -> {'EXIT',Reason}; @@ -1549,8 +1548,7 @@ ts_tc(M, F, A) -> throw:{skipped, Reason} -> {skip, Reason}; exit:{skip, Reason} -> {skip, Reason}; exit:{skipped, Reason} -> {skip, Reason}; - Type:Reason -> - Stk = erlang:get_stacktrace(), + Type:Reason:Stk -> set_loc(Stk), case Type of throw -> @@ -1739,8 +1737,8 @@ fail(Reason) -> try exit({suite_failed,Reason}) catch - Class:R -> - case erlang:get_stacktrace() of + Class:R:Stacktrace -> + case Stacktrace of [{?MODULE,fail,1,_}|Stk] -> ok; Stk -> ok end, @@ -1762,8 +1760,8 @@ fail() -> try exit(suite_failed) catch - Class:R -> - case erlang:get_stacktrace() of + Class:R:Stacktrace -> + case Stacktrace of [{?MODULE,fail,0,_}|Stk] -> ok; Stk -> ok end, @@ -2042,15 +2040,15 @@ call_user_timetrap(Func, Sup) when is_function(Func) -> try Func() of Result -> Sup ! {self(),Result} - catch _:Error -> - exit({Error,erlang:get_stacktrace()}) + catch _:Error:Stk -> + exit({Error,Stk}) end; call_user_timetrap({M,F,A}, Sup) -> try apply(M,F,A) of Result -> Sup ! {self(),Result} - catch _:Error -> - exit({Error,erlang:get_stacktrace()}) + catch _:Error:Stk -> + exit({Error,Stk}) end. save_user_timetrap(TCPid, UserTTSup, StartTime) -> @@ -2707,9 +2705,9 @@ is_cover() -> is_debug() -> case catch erlang:system_info(debug_compiled) of {'EXIT', _} -> - case string:str(erlang:system_info(system_version), "debug") of - Int when is_integer(Int), Int > 0 -> true; - _ -> false + case string:find(erlang:system_info(system_version), "debug") of + nomatch -> false; + _ -> true end; Res -> Res @@ -2745,9 +2743,9 @@ has_superfluous_schedulers() -> %% We might want to do more tests on a commercial platform, for instance %% ensuring that all applications have documentation). is_commercial() -> - case string:str(erlang:system_info(system_version), "source") of - Int when is_integer(Int), Int > 0 -> false; - _ -> true + case string:find(erlang:system_info(system_version), "source") of + nomatch -> true; + _ -> false end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/common_test/src/test_server_ctrl.erl b/lib/common_test/src/test_server_ctrl.erl index 8ef28b3343..8bd6cd583a 100644 --- a/lib/common_test/src/test_server_ctrl.erl +++ b/lib/common_test/src/test_server_ctrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2017. All Rights Reserved. +%% Copyright Ericsson AB 2002-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. @@ -1472,13 +1472,14 @@ get_suites([], Mods) -> lists:reverse(Mods). add_mod(Mod, Mods) -> - case string:rstr(atom_to_list(Mod), "_SUITE") of - 0 -> false; - _ -> % test suite + case lists:reverse(atom_to_list(Mod)) of + "ETIUS_" ++ _ -> % test suite case lists:member(Mod, Mods) of true -> false; false -> true - end + end; + _ -> + false end. @@ -2300,7 +2301,7 @@ run_test_cases(TestSpec, Config, TimetrapData) -> %% test_server_io:print_buffered/1 to print the data. To help with this, %% two variables in the process dictionary are used: %% 'test_server_common_io_handler' and 'test_server_queued_io'. The values -%% are set to as follwing: +%% are set to as following: %% %% Value Meaning %% ----- ------- @@ -2632,7 +2633,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0, NumStr -> %% Ex: "123 456 789" or "123,456,789" -> {123,456,789} list_to_tuple([list_to_integer(NS) || - NS <- string:tokens(NumStr, [$ ,$:,$,])]) + NS <- string:lexemes(NumStr, [$ ,$:,$,])]) end, {shuffle_cases(Ref, Cs0, UseSeed),{shuffle,UseSeed}} end; @@ -4001,11 +4002,12 @@ progress(skip, CaseNum, Mod, Func, GrName, Loc, Reason, Time, true -> "~w" end, [Time]), ReasonStr = escape_chars(reason_to_string(Reason1)), - ReasonStr1 = lists:flatten([string:strip(S,left) || - S <- string:tokens(ReasonStr,[$\n])]), + ReasonStr1 = lists:flatten([string:trim(S,leading,"\s") || + S <- string:lexemes(ReasonStr,[$\n])]), + ReasonLength = string:length(ReasonStr1), ReasonStr2 = - if length(ReasonStr1) > 80 -> - string:substr(ReasonStr1, 1, 77) ++ "..."; + if ReasonLength > 80 -> + string:slice(ReasonStr1, 0, 77) ++ "..."; true -> ReasonStr1 end, @@ -4089,11 +4091,12 @@ progress(failed, CaseNum, Mod, Func, GrName, unknown, Reason, Time, true -> "~w" end, [Time]), ErrorReason = escape_chars(lists:flatten(io_lib:format("~tp", [Reason]))), - ErrorReason1 = lists:flatten([string:strip(S,left) || - S <- string:tokens(ErrorReason,[$\n])]), + ErrorReason1 = lists:flatten([string:trim(S,leading,"\s") || + S <- string:lexemes(ErrorReason,[$\n])]), + ErrorReasonLength = string:length(ErrorReason1), ErrorReason2 = - if length(ErrorReason1) > 63 -> - string:substr(ErrorReason1, 1, 60) ++ "..."; + if ErrorReasonLength > 63 -> + string:slice(ErrorReason1, 0, 60) ++ "..."; true -> ErrorReason1 end, @@ -4379,7 +4382,7 @@ do_format_exception(Reason={Error,Stack}) -> PF = fun(Term, I) -> io_lib:format("~." ++ integer_to_list(I) ++ "tp", [Term]) end, - case catch lib:format_exception(1, error, Error, Stack, StackFun, PF, utf8) of + case catch erl_error:format_exception(1, error, Error, Stack, StackFun, PF, utf8) of {'EXIT',_R} -> {"~tp",Reason}; Formatted -> @@ -5164,7 +5167,7 @@ display_info([Pid|T], R, M) -> Other end, Reds = fetch(reductions, Info), - LM = length(fetch(messages, Info)), + LM = fetch(message_queue_len, Info), pformat(io_lib:format("~w", [Pid]), io_lib:format("~tw", [Call]), io_lib:format("~tw", [Curr]), Reds, LM), @@ -5736,7 +5739,7 @@ uri_encode_comp([Char|Chars],Encoding) -> Reserved = sets:is_element(Char, reserved()), case (Char>127 andalso Encoding==latin1) orelse Reserved of true -> - [ $% | http_util:integer_to_hexlist(Char)] ++ + [ $% | integer_to_list(Char, 16)] ++ uri_encode_comp(Chars,Encoding); false -> [Char | uri_encode_comp(Chars,Encoding)] diff --git a/lib/common_test/src/test_server_node.erl b/lib/common_test/src/test_server_node.erl index b3b6ae3d92..ea7ad8538e 100644 --- a/lib/common_test/src/test_server_node.erl +++ b/lib/common_test/src/test_server_node.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2017. All Rights Reserved. +%% Copyright Ericsson AB 2002-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. @@ -315,9 +315,11 @@ start_node_peer(SlaveName, OptList, From, TI) -> Prog0 = start_node_get_option_value(erl, OptList, default), Prog = quote_progname(pick_erl_program(Prog0)), Args = - case string:str(SuppliedArgs,"-setcookie") of - 0 -> "-setcookie " ++ TI#target_info.cookie ++ " " ++ SuppliedArgs; - _ -> SuppliedArgs + case string:find(SuppliedArgs,"-setcookie") of + nomatch -> + "-setcookie " ++ TI#target_info.cookie ++ " " ++ SuppliedArgs; + _ -> + SuppliedArgs end, Cmd = lists:concat([Prog, " -detached ", @@ -589,7 +591,7 @@ cast_to_list(X) -> lists:flatten(io_lib:format("~tw", [X])). %%% this %%% pick_erl_program(default) -> - cast_to_list(lib:progname()); + ct:get_progname(); pick_erl_program(L) -> P = random_element(L), case P of @@ -598,7 +600,7 @@ pick_erl_program(L) -> {release, S} -> find_release(S); this -> - cast_to_list(lib:progname()) + ct:get_progname() end. %% This is an attempt to distinguish between spaces in the program @@ -609,10 +611,10 @@ pick_erl_program(L) -> %% ({prog,String}) or if the -program switch to beam is used and %% includes arguments (typically done by cerl in OTP test environment %% in order to ensure that slave/peer nodes are started with the same -%% emulator and flags as the test node. The return from lib:progname() -%% could then typically be '/<full_path_to>/cerl -gcov'). +%% emulator and flags as the test node. The return from ct:get_progname() +%% could then typically be "/<full_path_to>/cerl -gcov"). quote_progname(Progname) -> - do_quote_progname(string:tokens(Progname," ")). + do_quote_progname(string:lexemes(Progname," ")). do_quote_progname([Prog]) -> "\""++Prog++"\""; diff --git a/lib/common_test/src/test_server_sup.erl b/lib/common_test/src/test_server_sup.erl index 6ddbf1ad27..26e7534c6c 100644 --- a/lib/common_test/src/test_server_sup.erl +++ b/lib/common_test/src/test_server_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2017. All Rights Reserved. +%% Copyright Ericsson AB 1998-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. @@ -781,8 +781,8 @@ framework_call(Callback,Func,Args,DefaultReturn) -> catch exit:Why -> EH(Why); - error:Why -> - EH({Why,erlang:get_stacktrace()}); + error:Why:Stacktrace -> + EH({Why,Stacktrace}); throw:Why -> EH(Why) end; diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl index 8ac467014c..7a210237a8 100644 --- a/lib/common_test/src/unix_telnet.erl +++ b/lib/common_test/src/unix_telnet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2017. All Rights Reserved. +%% Copyright Ericsson AB 2004-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,39 +18,6 @@ %% %CopyrightEnd% %% -%%% @doc Callback module for ct_telnet, for connecting to a telnet -%%% server on a unix host. -%%% -%%% <p>It requires the following entry in the config file:</p> -%%% <pre> -%%% {unix,[{telnet,HostNameOrIpAddress}, -%%% {port,PortNum}, % optional -%%% {username,UserName}, -%%% {password,Password}, -%%% {keep_alive,Bool}, % optional -%%% {tcp_nodely,Bool}]} % optional</pre> -%%% -%%% <p>To communicate via telnet to the host specified by -%%% <code>HostNameOrIpAddress</code>, use the interface functions in -%%% <code>ct_telnet</code>, e.g. <code>open(Name), cmd(Name,Cmd), ...</code>.</p> -%%% -%%% <p><code>Name</code> is the name you allocated to the unix host in -%%% your <code>require</code> statement. E.g.</p> -%%% <pre> suite() -> [{require,Name,{unix,[telnet]}}].</pre> -%%% <p>or</p> -%%% <pre> ct:require(Name,{unix,[telnet]}).</pre> -%%% -%%% <p>The "keep alive" activity (i.e. that Common Test sends NOP to the server -%%% every 10 seconds if the connection is idle) may be enabled or disabled for one -%%% particular connection as described here. It may be disabled for all connections -%%% using <c>telnet_settings</c> (see <c>ct_telnet</c>).</p> -%%% -%%% <p>Note that the <code>{port,PortNum}</code> tuple is optional and if -%%% omitted, default telnet port 23 will be used. Also the <c>keep_alive</c> tuple -%%% is optional, and the value defauls to true (enabled).</p> -%%% -%%% @see ct -%%% @see ct_telnet -module(unix_telnet). %% Callbacks for ct_telnet.erl @@ -61,36 +28,9 @@ -define(password,"Password: "). -define(prx,"login: |Password: |\\\$ |> "). -%%%----------------------------------------------------------------- -%%% @spec get_prompt_regexp() -> PromptRegexp -%%% PromptRegexp = ct_telnet:prompt_regexp() -%%% -%%% @doc Callback for ct_telnet.erl. -%%% -%%% <p>Return a suitable regexp string that will match common -%%% prompts for users on unix hosts.</p> get_prompt_regexp() -> ?prx. - -%%%----------------------------------------------------------------- -%%% @spec connect(ConnName,Ip,Port,Timeout,KeepAlive,Extra) -> -%%% {ok,Handle} | {error,Reason} -%%% ConnName = ct:target_name() -%%% Ip = string() | {integer(),integer(),integer(),integer()} -%%% Port = integer() -%%% Timeout = integer() -%%% KeepAlive = bool() -%%% TCPNoDelay = bool() -%%% Extra = ct:target_name() | {Username,Password} -%%% Username = string() -%%% Password = string() -%%% Handle = ct_telnet:handle() -%%% Reason = term() -%%% -%%% @doc Callback for ct_telnet.erl. -%%% -%%% <p>Setup telnet connection to a unix host.</p> connect(ConnName,Ip,Port,Timeout,KeepAlive,TCPNoDelay,Extra) -> case Extra of {Username,Password} -> @@ -121,7 +61,8 @@ connect1(Name,Ip,Port,Timeout,KeepAlive,TCPNoDelay,Username,Password) -> prompt,?prx,[]) of {ok,{prompt,?password},_} -> ok = ct_telnet_client:send_data(Pid,Password), - Stars = lists:duplicate(length(Password),$*), + Stars = + lists:duplicate(string:length(Password),$*), log(Name,send,"Password: ~s",[Stars]), % ok = ct_telnet_client:send_data(Pid,""), case ct_telnet:silent_teln_expect(Name,Pid,[], diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl index 83fcde2f48..38e549d2d6 100644 --- a/lib/common_test/src/vts.erl +++ b/lib/common_test/src/vts.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. @@ -919,7 +919,7 @@ get_input_data(Input,Key)-> end. parse(Input) -> - httpd:parse_query(Input). + uri_string:dissect_query(Input). vts_integer_to_list(X) when is_atom(X) -> atom_to_list(X); |