diff options
Diffstat (limited to 'lib/common_test')
110 files changed, 2688 insertions, 4423 deletions
diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile index 293ef591cb..b5acdc6f95 100644 --- a/lib/common_test/doc/src/Makefile +++ b/lib/common_test/doc/src/Makefile @@ -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. @@ -140,6 +140,7 @@ debug opt: clean clean_docs: rm -rf $(HTMLDIR)/* + rm -rf $(XMLDIR) rm -f $(MAN1DIR)/* rm -f $(MAN3DIR)/* rm -f $(MAN6DIR)/* diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml index 5fa87901f6..081adeaec7 100644 --- a/lib/common_test/doc/src/common_test_app.xml +++ b/lib/common_test/doc/src/common_test_app.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>common_test_app.sgml</file> </header> - <module>common_test</module> + <module since="">common_test</module> <modulesummary>A framework for automated testing of any target nodes.</modulesummary> <description> @@ -68,7 +68,7 @@ <funcs> <func> - <name>Module:all() -> Tests | {skip,Reason} </name> + <name since="">Module:all() -> Tests | {skip,Reason} </name> <fsummary>Returns the list of all test case groups and test cases in the module.</fsummary> <type> @@ -117,7 +117,7 @@ </func> <func> - <name>Module:groups() -> GroupDefs</name> + <name since="">Module:groups() -> GroupDefs</name> <fsummary>Returns a list of test case group definitions.</fsummary> <type> <v>GroupDefs = [Group]</v> @@ -143,7 +143,7 @@ </func> <func> - <name>Module:suite() -> [Info] </name> + <name since="">Module:suite() -> [Info] </name> <fsummary>Test suite info function (providing default data for the suite).</fsummary> <type> @@ -216,7 +216,7 @@ </func> <func> - <name>Module:init_per_suite(Config) -> NewConfig | {skip,Reason} | + <name since="">Module:init_per_suite(Config) -> NewConfig | {skip,Reason} | {skip_and_save,Reason,SaveConfig}</name> <fsummary>Test suite initializations.</fsummary> <type> @@ -251,7 +251,7 @@ </func> <func> - <name>Module:end_per_suite(Config) -> term() | + <name since="">Module:end_per_suite(Config) -> term() | {save_config,SaveConfig}</name> <fsummary>Test suite finalization.</fsummary> <type> @@ -275,7 +275,7 @@ </func> <func> - <name>Module:group(GroupName) -> [Info] </name> + <name since="OTP R15B">Module:group(GroupName) -> [Info] </name> <fsummary>Test case group information function (providing default data for a test case group, that is, its test cases and subgroups).</fsummary> @@ -355,7 +355,7 @@ </func> <func> - <name>Module:init_per_group(GroupName, Config) -> NewConfig | + <name since="">Module:init_per_group(GroupName, Config) -> NewConfig | {skip,Reason}</name> <fsummary>Test case group initializations.</fsummary> <type> @@ -393,7 +393,7 @@ </func> <func> - <name>Module:end_per_group(GroupName, Config) -> term() | + <name since="">Module:end_per_group(GroupName, Config) -> term() | {return_group_result,Status}</name> <fsummary>Test case group finalization.</fsummary> <type> @@ -427,7 +427,7 @@ </func> <func> - <name>Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason}</name> + <name since="">Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason}</name> <fsummary>Test case initializations.</fsummary> <type> <v> TestCase = atom()</v> @@ -457,7 +457,7 @@ </func> <func> - <name>Module:end_per_testcase(TestCase, Config) -> term() | {fail,Reason} | {save_config,SaveConfig}</name> + <name since="">Module:end_per_testcase(TestCase, Config) -> term() | {fail,Reason} | {save_config,SaveConfig}</name> <fsummary>Test case finalization.</fsummary> <type> <v>TestCase = atom()</v> @@ -489,7 +489,7 @@ </func> <func> - <name>Module:Testcase() -> [Info] </name> + <name since="OTP R14B">Module:Testcase() -> [Info] </name> <fsummary>Test case information function.</fsummary> <type> <v>Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns}</v> @@ -563,7 +563,7 @@ </func> <func> - <name>Module:Testcase(Config) -> term() | {skip,Reason} | {comment,Comment} | {save_config,SaveConfig} | {skip_and_save,Reason,SaveConfig} | exit() </name> + <name since="OTP R14B">Module:Testcase(Config) -> term() | {skip,Reason} | {comment,Comment} | {save_config,SaveConfig} | {skip_and_save,Reason,SaveConfig} | exit() </name> <fsummary>A test case.</fsummary> <type> <v>Config = SaveConfig = [{Key,Value}]</v> diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml index afd8741cd1..83c0ecb309 100644 --- a/lib/common_test/doc/src/ct.xml +++ b/lib/common_test/doc/src/ct.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2010</year><year>2017</year> + <year>2010</year><year>2018</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct.xml</file> </header> - <module>ct</module> + <module since="">ct</module> <modulesummary>Main user interface for the Common Test framework.</modulesummary> <description> @@ -139,7 +139,7 @@ <funcs> <func> - <name>abort_current_testcase(Reason) -> ok | {error, ErrorReason}</name> + <name since="">abort_current_testcase(Reason) -> ok | {error, ErrorReason}</name> <fsummary>Aborts the currently executing test case.</fsummary> <type> <v>Reason = term()</v> @@ -157,7 +157,7 @@ </func> <func> - <name>add_config(Callback, Config) -> ok | {error, Reason}</name> + <name since="OTP R14B">add_config(Callback, Config) -> ok | {error, Reason}</name> <fsummary>Loads configuration variables using the specified callback module and configuration string.</fsummary> <type> @@ -176,7 +176,7 @@ </func> <func> - <name>break(Comment) -> ok | {error, Reason}</name> + <name since="OTP R15B02">break(Comment) -> ok | {error, Reason}</name> <fsummary>Cancels any active timetrap and pause the execution of the current test case until the user calls function continue/0.</fsummary> <type> @@ -206,7 +206,7 @@ </func> <func> - <name>break(TestCase, Comment) -> ok | {error, Reason}</name> + <name since="OTP R15B02">break(TestCase, Comment) -> ok | {error, Reason}</name> <fsummary>Works the same way as break/1, only argument TestCase makes it possible to pause a test case executing in a parallel group.</fsummary> <type> @@ -228,7 +228,7 @@ </func> <func> - <name>capture_get() -> ListOfStrings</name> + <name since="OTP R15B">capture_get() -> ListOfStrings</name> <fsummary>Equivalent to capture_get([default]).</fsummary> <type> <v>ListOfStrings = [string()]</v> @@ -240,7 +240,7 @@ </func> <func> - <name>capture_get(ExclCategories) -> ListOfStrings</name> + <name since="OTP R15B">capture_get(ExclCategories) -> ListOfStrings</name> <fsummary>Returns and purges the list of text strings buffered during the latest session of capturing printouts to stdout.</fsummary> <type> @@ -262,7 +262,7 @@ </func> <func> - <name>capture_start() -> ok</name> + <name since="OTP R15B">capture_start() -> ok</name> <fsummary>Starts capturing all text strings printed to stdout during execution of the test case.</fsummary> <desc><marker id="capture_start-0"/> @@ -276,7 +276,7 @@ </func> <func> - <name>capture_stop() -> ok</name> + <name since="OTP R15B">capture_stop() -> ok</name> <fsummary>Stops capturing text strings (a session started with capture_start/0).</fsummary> <desc><marker id="capture_stop-0"/> @@ -290,7 +290,7 @@ </func> <func> - <name>comment(Comment) -> ok</name> + <name since="">comment(Comment) -> ok</name> <fsummary>Prints the specified Comment in the comment field in the table on the test suite result page.</fsummary> <type> @@ -307,7 +307,7 @@ </func> <func> - <name>comment(Format, Args) -> ok</name> + <name since="OTP R15B">comment(Format, Args) -> ok</name> <fsummary>Prints the formatted string in the comment field in the table on the test suite result page.</fsummary> <type> @@ -326,7 +326,7 @@ </func> <func> - <name>continue() -> ok</name> + <name since="OTP R15B02">continue() -> ok</name> <fsummary>This function must be called to continue after a test case (not executing in a parallel group) has called break/1.</fsummary> <desc><marker id="continue-0"/> @@ -337,7 +337,7 @@ </func> <func> - <name>continue(TestCase) -> ok</name> + <name since="OTP R15B02">continue(TestCase) -> ok</name> <fsummary>This function must be called to continue after a test case has called break/2.</fsummary> <type> @@ -353,7 +353,7 @@ </func> <func> - <name>decrypt_config_file(EncryptFileName, TargetFileName) -> ok | {error, Reason}</name> + <name since="">decrypt_config_file(EncryptFileName, TargetFileName) -> ok | {error, Reason}</name> <fsummary>Decrypts EncryptFileName, previously generated with encrypt_config_file/2,3.</fsummary> <type> @@ -372,7 +372,7 @@ </func> <func> - <name>decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) -> ok | {error, Reason}</name> + <name since="">decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) -> ok | {error, Reason}</name> <fsummary>Decrypts EncryptFileName, previously generated with encrypt_config_file/2,3.</fsummary> <type> @@ -390,7 +390,7 @@ </func> <func> - <name>encrypt_config_file(SrcFileName, EncryptFileName) -> ok | {error, Reason}</name> + <name since="">encrypt_config_file(SrcFileName, EncryptFileName) -> ok | {error, Reason}</name> <fsummary>Encrypts the source configuration file with DES3 and saves the result in file EncryptFileName.</fsummary> <type> @@ -416,7 +416,7 @@ </func> <func> - <name>encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) -> ok | {error, Reason}</name> + <name since="">encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) -> ok | {error, Reason}</name> <fsummary>Encrypts the source configuration file with DES3 and saves the result in the target file EncryptFileName.</fsummary> <type> @@ -442,7 +442,7 @@ </func> <func> - <name>fail(Reason) -> ok</name> + <name since="">fail(Reason) -> ok</name> <fsummary>Terminates a test case with the specified error Reason.</fsummary> <type> @@ -454,7 +454,7 @@ </func> <func> - <name>fail(Format, Args) -> ok</name> + <name since="OTP R15B">fail(Format, Args) -> ok</name> <fsummary>Terminates a test case with an error message specified by a format string and a list of values (used as arguments to io_lib:format/2).</fsummary> @@ -470,7 +470,7 @@ </func> <func> - <name>get_config(Required) -> Value</name> + <name since="">get_config(Required) -> Value</name> <fsummary>Equivalent to get_config(Required, undefined, []).</fsummary> <desc><marker id="get_config-1"/> <p>Equivalent to <seealso marker="#get_config-3"><c>ct:get_config(Required, @@ -479,7 +479,7 @@ </func> <func> - <name>get_config(Required, Default) -> Value</name> + <name since="">get_config(Required, Default) -> Value</name> <fsummary>Equivalent to get_config(Required, Default, []).</fsummary> <desc><marker id="get_config-2"/> <p>Equivalent to <seealso marker="#get_config-3"><c>ct:get_config(Required, @@ -488,7 +488,7 @@ </func> <func> - <name>get_config(Required, Default, Opts) -> ValueOrElement</name> + <name since="">get_config(Required, Default, Opts) -> ValueOrElement</name> <fsummary>Reads configuration data values.</fsummary> <type> <v>Required = KeyOrName | {KeyOrName, SubKey} | {KeyOrName, SubKey, SubKey}</v> @@ -554,7 +554,7 @@ </func> <func> - <name>get_event_mgr_ref() -> EvMgrRef</name> + <name since="OTP 17.5">get_event_mgr_ref() -> EvMgrRef</name> <fsummary>Gets a reference to the <c>Common Test</c> event manager.</fsummary> <type> <v>EvMgrRef = atom()</v> @@ -572,7 +572,17 @@ </func> <func> - <name>get_status() -> TestStatus | {error, Reason} | no_tests_running</name> + <name since="OTP 21.0">get_progname() -> string()</name> + <fsummary>Returns the command used to start this Erlang instance.</fsummary> + <desc><marker id="get_progname-0"/> + <p>Returns the command used to start this Erlang instance. + If this information could not be found, the string + <c>"no_prog_name"</c> is returned.</p> + </desc> + </func> + + <func> + <name since="">get_status() -> TestStatus | {error, Reason} | no_tests_running</name> <fsummary>Returns status of ongoing test.</fsummary> <type> <v>TestStatus = [StatusElem]</v> @@ -598,7 +608,7 @@ </func> <func> - <name>get_target_name(Handle) -> {ok, TargetName} | {error, Reason}</name> + <name since="">get_target_name(Handle) -> {ok, TargetName} | {error, Reason}</name> <fsummary>Returns the name of the target that the specified connection belongs to.</fsummary> <type> @@ -612,7 +622,7 @@ </func> <func> - <name>get_testspec_terms() -> TestSpecTerms | undefined</name> + <name since="OTP 18.0">get_testspec_terms() -> TestSpecTerms | undefined</name> <fsummary>Gets a list of all test specification terms used to configure and run this test.</fsummary> <type> @@ -626,7 +636,7 @@ </func> <func> - <name>get_testspec_terms(Tags) -> TestSpecTerms | undefined</name> + <name since="OTP 18.0">get_testspec_terms(Tags) -> TestSpecTerms | undefined</name> <fsummary>Reads one or more terms from the test specification used to configure and run this test.</fsummary> <type> @@ -653,7 +663,7 @@ </func> <func> - <name>get_timetrap_info() -> {Time, {Scaling,ScaleVal}}</name> + <name since="OTP R15B">get_timetrap_info() -> {Time, {Scaling,ScaleVal}}</name> <fsummary>Reads information about the timetrap set for the current test case.</fsummary> <type> @@ -672,7 +682,7 @@ </func> <func> - <name>get_verbosity(Category) -> Level | undefined</name> + <name since="OTP 19.1">get_verbosity(Category) -> Level | undefined</name> <fsummary>Read the verbosity level for a logging category.</fsummary> <type> <v>Category = default | atom()</v> @@ -687,7 +697,7 @@ </func> <func> - <name>install(Opts) -> ok | {error, Reason}</name> + <name since="">install(Opts) -> ok | {error, Reason}</name> <fsummary>Installs configuration files and event handlers.</fsummary> <type> <v>Opts = [Opt]</v> @@ -714,7 +724,7 @@ </func> <func> - <name>listenv(Telnet) -> [Env]</name> + <name since="">listenv(Telnet) -> [Env]</name> <fsummary>Performs command listenv on the specified Telnet connection and returns the result as a list of key-value pairs.</fsummary> <type> @@ -730,7 +740,7 @@ </func> <func> - <name>log(Format) -> ok</name> + <name since="">log(Format) -> ok</name> <fsummary>Equivalent to log(default, 50, Format, [], []).</fsummary> <desc><marker id="log-1"/> <p>Equivalent to @@ -739,7 +749,7 @@ </func> <func> - <name>log(X1, X2) -> ok</name> + <name since="">log(X1, X2) -> ok</name> <fsummary>Equivalent to log(Category, Importance, Format, FormatArgs, []).</fsummary> <type> @@ -753,7 +763,7 @@ </func> <func> - <name>log(X1, X2, X3) -> ok</name> + <name since="">log(X1, X2, X3) -> ok</name> <fsummary>Equivalent to log(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -768,7 +778,7 @@ </func> <func> - <name>log(X1, X2, X3, X4) -> ok</name> + <name since="OTP R15B02">log(X1, X2, X3, X4) -> ok</name> <fsummary>Equivalent to log(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -784,7 +794,7 @@ </func> <func> - <name>log(Category, Importance, Format, FormatArgs, Opts) -> ok</name> + <name since="OTP 18.3">log(Category, Importance, Format, FormatArgs, Opts) -> ok</name> <fsummary>Prints from a test case to the log file.</fsummary> <type> <v>Category = atom()</v> @@ -815,7 +825,7 @@ </func> <func> - <name>make_priv_dir() -> ok | {error, Reason}</name> + <name since="OTP R15B01">make_priv_dir() -> ok | {error, Reason}</name> <fsummary>If the test has been started with option create_priv_dir 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.</fsummary> @@ -831,7 +841,7 @@ </func> <func> - <name>notify(Name, Data) -> ok</name> + <name since="OTP R15B02">notify(Name, Data) -> ok</name> <fsummary>Sends an asynchronous notification of type Name with Data to the <c>Common Test</c> event manager.</fsummary> <type> @@ -849,7 +859,7 @@ </func> <func> - <name>pal(Format) -> ok</name> + <name since="">pal(Format) -> ok</name> <fsummary>Equivalent to pal(default, 50, Format, [], []).</fsummary> <desc><marker id="pal-1"/> <p>Equivalent to @@ -859,7 +869,7 @@ </func> <func> - <name>pal(X1, X2) -> ok</name> + <name since="">pal(X1, X2) -> ok</name> <fsummary>Equivalent to pal(Category, Importance, Format, FormatArgs, []).</fsummary> <type> @@ -873,7 +883,7 @@ </func> <func> - <name>pal(X1, X2, X3) -> ok</name> + <name since="">pal(X1, X2, X3) -> ok</name> <fsummary>Equivalent to pal(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -888,7 +898,7 @@ </func> <func> - <name>pal(X1, X2, X3, X4) -> ok</name> + <name since="OTP R15B02">pal(X1, X2, X3, X4) -> ok</name> <fsummary>Equivalent to pal(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -904,7 +914,7 @@ </func> <func> - <name>pal(Category, Importance, Format, FormatArgs, Opts) -> ok</name> + <name since="OTP 19.2">pal(Category, Importance, Format, FormatArgs, Opts) -> ok</name> <fsummary>Prints and logs from a test case.</fsummary> <type> <v>Category = atom()</v> @@ -935,7 +945,7 @@ </func> <func> - <name>parse_table(Data) -> {Heading, Table}</name> + <name since="">parse_table(Data) -> {Heading, Table}</name> <fsummary>Parses the printout from an SQL table and returns a list of tuples.</fsummary> <type> @@ -957,7 +967,7 @@ </func> <func> - <name>print(Format) -> ok</name> + <name since="">print(Format) -> ok</name> <fsummary>Equivalent to print(default, 50, Format, [], []).</fsummary> <desc><marker id="print-1"/> <p>Equivalent to <seealso marker="#print-5"><c>ct:print(default, @@ -966,7 +976,7 @@ </func> <func> - <name>print(X1, X2) -> ok</name> + <name since="OTP R15B02">print(X1, X2) -> ok</name> <fsummary>Equivalent to print(Category, Importance, Format, FormatArgs, []).</fsummary> <type> @@ -980,7 +990,7 @@ </func> <func> - <name>print(X1, X2, X3) -> ok</name> + <name since="">print(X1, X2, X3) -> ok</name> <fsummary>Equivalent to print(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -995,7 +1005,7 @@ </func> <func> - <name>print(X1, X2, X3, X4) -> ok</name> + <name since="OTP R15B02">print(X1, X2, X3, X4) -> ok</name> <fsummary>Equivalent to print(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -1011,7 +1021,7 @@ </func> <func> - <name>print(Category, Importance, Format, FormatArgs, Opts) -> ok</name> + <name since="OTP 19.2">print(Category, Importance, Format, FormatArgs, Opts) -> ok</name> <fsummary>Prints from a test case to the console.</fsummary> <type> <v>Category = atom()</v> @@ -1038,7 +1048,7 @@ </func> <func> - <name>reload_config(Required) -> ValueOrElement | {error, Reason}</name> + <name since="OTP R14B">reload_config(Required) -> ValueOrElement | {error, Reason}</name> <fsummary>Reloads configuration file containing specified configuration key.</fsummary> <type> @@ -1061,7 +1071,7 @@ </func> <func> - <name>remaining_test_procs() -> {TestProcs,SharedGL,OtherGLs}</name> + <name since="OTP 20.2">remaining_test_procs() -> {TestProcs,SharedGL,OtherGLs}</name> <fsummary>>This function will return the identity of test- and group leader processes that are still running at the time of this call.</fsummary> <type> @@ -1097,7 +1107,7 @@ </func> <func> - <name>remove_config(Callback, Config) -> ok</name> + <name since="OTP R14B">remove_config(Callback, Config) -> ok</name> <fsummary>Removes configuration variables (together with their aliases) that were loaded with specified callback module and configuration string.</fsummary> @@ -1114,7 +1124,7 @@ </func> <func> - <name>require(Required) -> ok | {error, Reason}</name> + <name since="">require(Required) -> ok | {error, Reason}</name> <fsummary>Checks if the required configuration is available.</fsummary> <type> <v>Required = Key | {Key, SubKeys} | {Key, SubKey, SubKeys}</v> @@ -1168,7 +1178,7 @@ </func> <func> - <name>require(Name, Required) -> ok | {error, Reason}</name> + <name since="">require(Name, Required) -> ok | {error, Reason}</name> <fsummary>Checks if the required configuration is available and gives it a name.</fsummary> <type> @@ -1227,7 +1237,7 @@ </func> <func> - <name>run(TestDirs) -> Result</name> + <name since="">run(TestDirs) -> Result</name> <fsummary>Runs all test cases in all suites in the specified directories.</fsummary> <type> @@ -1241,7 +1251,7 @@ </func> <func> - <name>run(TestDir, Suite) -> Result</name> + <name since="">run(TestDir, Suite) -> Result</name> <fsummary>Runs all test cases in the specified suite.</fsummary> <desc><marker id="run-2"/> <p>Runs all test cases in the specified suite.</p> @@ -1251,7 +1261,7 @@ </func> <func> - <name>run(TestDir, Suite, Cases) -> Result</name> + <name since="">run(TestDir, Suite, Cases) -> Result</name> <fsummary>Runs the specified test cases.</fsummary> <type> <v>TestDir = string()</v> @@ -1273,7 +1283,7 @@ </func> <func> - <name>run_test(Opts) -> Result</name> + <name since="">run_test(Opts) -> Result</name> <fsummary>Runs tests as specified by the combination of options in Opts.</fsummary> <type> @@ -1345,7 +1355,7 @@ </func> <func> - <name>run_testspec(TestSpec) -> Result</name> + <name since="">run_testspec(TestSpec) -> Result</name> <fsummary>Runs a test specified by TestSpec.</fsummary> <type> <v>TestSpec = [term()]</v> @@ -1365,7 +1375,7 @@ </func> <func> - <name>set_verbosity(Category, Level) -> ok</name> + <name since="OTP 19.1">set_verbosity(Category, Level) -> ok</name> <fsummary>Set the verbosity level for a logging category.</fsummary> <type> <v>Category = default | atom()</v> @@ -1380,7 +1390,7 @@ </func> <func> - <name>sleep(Time) -> ok</name> + <name since="OTP R14B">sleep(Time) -> ok</name> <fsummary>This function, similar to timer:sleep/1, suspends the test case for a specified time.</fsummary> <type> @@ -1402,7 +1412,7 @@ </func> <func> - <name>start_interactive() -> ok</name> + <name since="">start_interactive() -> ok</name> <fsummary>Starts <c>Common Test</c> in interactive mode.</fsummary> <desc><marker id="start_interactive-0"/> <p>Starts <c>Common Test</c> in interactive mode.</p> @@ -1430,7 +1440,7 @@ </func> <func> - <name>step(TestDir, Suite, Case) -> Result</name> + <name since="">step(TestDir, Suite, Case) -> Result</name> <fsummary>Steps through a test case with the debugger.</fsummary> <type> <v>Case = atom()</v> @@ -1443,7 +1453,7 @@ </func> <func> - <name>step(TestDir, Suite, Case, Opts) -> Result</name> + <name since="">step(TestDir, Suite, Case, Opts) -> Result</name> <fsummary>Steps through a test case with the debugger.</fsummary> <type> <v>Case = atom()</v> @@ -1460,7 +1470,7 @@ </func> <func> - <name>stop_interactive() -> ok</name> + <name since="">stop_interactive() -> ok</name> <fsummary>Exits the interactive mode.</fsummary> <desc><marker id="stop_interactive-0"/> <p>Exits the interactive mode.</p> @@ -1472,7 +1482,7 @@ </func> <func> - <name>sync_notify(Name, Data) -> ok</name> + <name since="OTP R15B02">sync_notify(Name, Data) -> ok</name> <fsummary>Sends a synchronous notification of type Name with Data to the <c>Common Test</c> event manager.</fsummary> <type> @@ -1491,7 +1501,7 @@ </func> <func> - <name>testcases(TestDir, Suite) -> Testcases | {error, Reason}</name> + <name since="">testcases(TestDir, Suite) -> Testcases | {error, Reason}</name> <fsummary>Returns all test cases in the specified suite.</fsummary> <type> <v>TestDir = string()</v> @@ -1505,14 +1515,14 @@ </func> <func> - <name>timetrap(Time) -> ok</name> + <name since="OTP R14B">timetrap(Time) -> ok</name> <fsummary>Sets a new timetrap for the running test case.</fsummary> <type> <v>Time = {hours, Hours} | {minutes, Mins} | {seconds, Secs} | Millisecs | infinity | Func</v> <v>Hours = integer()</v> <v>Mins = integer()</v> <v>Secs = integer()</v> - <v>Millisecs = integer() | float()</v> + <v>Millisecs = integer()</v> <v>Func = {M, F, A} | function()</v> <v>M = atom()</v> <v>F = atom()</v> @@ -1529,7 +1539,7 @@ </func> <func> - <name>userdata(TestDir, Suite) -> SuiteUserData | {error, Reason}</name> + <name since="">userdata(TestDir, Suite) -> SuiteUserData | {error, Reason}</name> <fsummary>Returns any data specified with tag userdata in the list of tuples returned from Suite:suite/0.</fsummary> <type> @@ -1546,7 +1556,7 @@ </func> <func> - <name>userdata(TestDir, Suite, Case::GroupOrCase) -> TCUserData | {error, Reason}</name> + <name since="">userdata(TestDir, Suite, Case::GroupOrCase) -> TCUserData | {error, Reason}</name> <fsummary>Returns any data specified with tag userdata in the list of tuples returned from Suite:group(GroupName) or Suite:Case().</fsummary> <type> diff --git a/lib/common_test/doc/src/ct_cover.xml b/lib/common_test/doc/src/ct_cover.xml index 89d944acbe..61365d3522 100644 --- a/lib/common_test/doc/src/ct_cover.xml +++ b/lib/common_test/doc/src/ct_cover.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_cover.xml</file> </header> - <module>ct_cover</module> + <module since="">ct_cover</module> <modulesummary>Common Test framework code coverage support module. </modulesummary> @@ -47,7 +47,7 @@ <funcs> <func> - <name>add_nodes(Nodes) -> {ok, StartedNodes} | {error, Reason}</name> + <name since="">add_nodes(Nodes) -> {ok, StartedNodes} | {error, Reason}</name> <fsummary>Adds nodes to current cover test (only works if cover support is active).</fsummary> <type> @@ -67,7 +67,7 @@ </func> <func> - <name>cross_cover_analyse(Level, Tests) -> ok</name> + <name since="OTP R16B">cross_cover_analyse(Level, Tests) -> ok</name> <fsummary>Accumulates cover results over multiple tests.</fsummary> <type> <v>Level = overview | details</v> @@ -83,7 +83,7 @@ </func> <func> - <name>remove_nodes(Nodes) -> ok | {error, Reason}</name> + <name since="">remove_nodes(Nodes) -> ok | {error, Reason}</name> <fsummary>Removes nodes from the current cover test.</fsummary> <type> <v>Nodes = [atom()]</v> diff --git a/lib/common_test/doc/src/ct_ftp.xml b/lib/common_test/doc/src/ct_ftp.xml index e8c6f72db7..7ee6049486 100644 --- a/lib/common_test/doc/src/ct_ftp.xml +++ b/lib/common_test/doc/src/ct_ftp.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2010</year><year>2016</year> + <year>2010</year><year>2018</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,14 +32,12 @@ <rev>A</rev> <file>ct_ftp.xml</file> </header> - <module>ct_ftp</module> - <modulesummary>FTP client module (based on the FTP support of the Inets - application).</modulesummary> + <module since="">ct_ftp</module> + <modulesummary>FTP client module (based on the FTP application).</modulesummary> <description> - <p>FTP client module (based on the FTP support of the <c>Inets</c> - application).</p> + <p>FTP client module (based on the <c>ftp</c> application).</p> </description> @@ -61,7 +59,7 @@ <funcs> <func> - <name>cd(Connection, Dir) -> ok | {error, Reason}</name> + <name since="">cd(Connection, Dir) -> ok | {error, Reason}</name> <fsummary>Changes directory on remote host.</fsummary> <type> <v>Connection = connection()</v> @@ -73,7 +71,7 @@ </func> <func> - <name>close(Connection) -> ok | {error, Reason}</name> + <name since="">close(Connection) -> ok | {error, Reason}</name> <fsummary>Closes the FTP connection.</fsummary> <type> <v>Connection = connection()</v> @@ -84,7 +82,7 @@ </func> <func> - <name>delete(Connection, File) -> ok | {error, Reason}</name> + <name since="">delete(Connection, File) -> ok | {error, Reason}</name> <fsummary>Deletes a file on remote host.</fsummary> <type> <v>Connection = connection()</v> @@ -96,7 +94,7 @@ </func> <func> - <name>get(KeyOrName, RemoteFile, LocalFile) -> ok | {error, Reason}</name> + <name since="">get(KeyOrName, RemoteFile, LocalFile) -> ok | {error, Reason}</name> <fsummary>Opens an FTP connection and fetches a file from the remote host.</fsummary> <type> @@ -124,7 +122,7 @@ </func> <func> - <name>ls(Connection, Dir) -> {ok, Listing} | {error, Reason}</name> + <name since="">ls(Connection, Dir) -> {ok, Listing} | {error, Reason}</name> <fsummary>Lists directory Dir.</fsummary> <type> <v>Connection = connection()</v> @@ -137,7 +135,7 @@ </func> <func> - <name>open(KeyOrName) -> {ok, Handle} | {error, Reason}</name> + <name since="">open(KeyOrName) -> {ok, Handle} | {error, Reason}</name> <fsummary>Opens an FTP connection to the specified node.</fsummary> <type> <v>KeyOrName = Key | Name</v> @@ -166,7 +164,7 @@ </func> <func> - <name>put(KeyOrName, LocalFile, RemoteFile) -> ok | {error, Reason}</name> + <name since="">put(KeyOrName, LocalFile, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Opens an FTP connection and sends a file to the remote host.</fsummary> <type> @@ -205,7 +203,7 @@ </func> <func> - <name>recv(Connection, RemoteFile) -> ok | {error, Reason}</name> + <name since="">recv(Connection, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Fetches a file over FTP.</fsummary> <desc><marker id="recv-2"/> <p>Fetches a file over FTP.</p> @@ -217,7 +215,7 @@ </func> <func> - <name>recv(Connection, RemoteFile, LocalFile) -> ok | {error, Reason}</name> + <name since="">recv(Connection, RemoteFile, LocalFile) -> ok | {error, Reason}</name> <fsummary>Fetches a file over FTP.</fsummary> <type> <v>Connection = connection()</v> @@ -232,7 +230,7 @@ </func> <func> - <name>send(Connection, LocalFile) -> ok | {error, Reason}</name> + <name since="">send(Connection, LocalFile) -> ok | {error, Reason}</name> <fsummary>Sends a file over FTP.</fsummary> <desc><marker id="send-2"/> <p>Sends a file over FTP.</p> @@ -245,7 +243,7 @@ </func> <func> - <name>send(Connection, LocalFile, RemoteFile) -> ok | {error, Reason}</name> + <name since="">send(Connection, LocalFile, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Sends a file over FTP.</fsummary> <type> <v>Connection = connection()</v> @@ -260,7 +258,7 @@ </func> <func> - <name>type(Connection, Type) -> ok | {error, Reason}</name> + <name since="">type(Connection, Type) -> ok | {error, Reason}</name> <fsummary>Changes the file transfer type.</fsummary> <type> <v>Connection = connection()</v> diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml index 03dfceaa1f..b9bc54ff63 100644 --- a/lib/common_test/doc/src/ct_hooks.xml +++ b/lib/common_test/doc/src/ct_hooks.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>ct_hooks.sgml</file> </header> - <module>ct_hooks</module> + <module since="OTP R14B02">ct_hooks</module> <modulesummary>A callback interface on top of Common Test.</modulesummary> <description> @@ -75,7 +75,7 @@ <funcs> <func> - <name>Module:init(Id, Opts) -> {ok, State} | {ok, State, Priority}</name> + <name since="OTP R14B02">Module:init(Id, Opts) -> {ok, State} | {ok, State, Priority}</name> <fsummary>Initiates the Common Test Hook.</fsummary> <type> <v>Id = reference() | term()</v> @@ -109,7 +109,7 @@ </func> <func> - <name>Module:post_groups(SuiteName, GroupDefs) -> NewGroupDefs</name> + <name since="OTP @OTP-14746@">Module:post_groups(SuiteName, GroupDefs) -> NewGroupDefs</name> <fsummary>Called after groups/0.</fsummary> <type> <v>SuiteName = atom()</v> @@ -165,7 +165,7 @@ </func> <func> - <name>Module:post_all(SuiteName, Return, GroupDefs) -> NewReturn</name> + <name since="OTP @OTP-14746@">Module:post_all(SuiteName, Return, GroupDefs) -> NewReturn</name> <fsummary>Called after all/0.</fsummary> <type> <v>SuiteName = atom()</v> @@ -234,7 +234,7 @@ </func> <func> - <name>Module:pre_init_per_suite(SuiteName, InitData, CTHState) -> Result</name> + <name since="OTP R14B02">Module:pre_init_per_suite(SuiteName, InitData, CTHState) -> Result</name> <fsummary>Called before init_per_suite.</fsummary> <type> <v>SuiteName = atom()</v> @@ -286,7 +286,7 @@ </func> <func> - <name>Module:post_init_per_suite(SuiteName, Config, Return, CTHState) -> Result</name> + <name since="OTP R14B02">Module:post_init_per_suite(SuiteName, Config, Return, CTHState) -> Result</name> <fsummary>Called after init_per_suite.</fsummary> <type> <v>SuiteName = atom()</v> @@ -333,7 +333,7 @@ </func> <func> - <name>Module:pre_init_per_group(SuiteName, GroupName, InitData, CTHState) -> Result</name> + <name since="OTP 19.3">Module:pre_init_per_group(SuiteName, GroupName, InitData, CTHState) -> Result</name> <fsummary>Called before init_per_group.</fsummary> <type> <v>SuiteName = atom()</v> @@ -366,7 +366,7 @@ </func> <func> - <name>Module:post_init_per_group(SuiteName, GroupName, Config, Return, CTHState) -> Result</name> + <name since="OTP 19.3">Module:post_init_per_group(SuiteName, GroupName, Config, Return, CTHState) -> Result</name> <fsummary>Called after init_per_group.</fsummary> <type> <v>SuiteName = atom()</v> @@ -399,7 +399,7 @@ </func> <func> - <name>Module:pre_init_per_testcase(SuiteName, TestcaseName, InitData, CTHState) -> Result</name> + <name since="OTP 19.3">Module:pre_init_per_testcase(SuiteName, TestcaseName, InitData, CTHState) -> Result</name> <fsummary>Called before init_per_testcase.</fsummary> <type> <v>SuiteName = atom()</v> @@ -436,7 +436,7 @@ </func> <func> - <name>Module:post_init_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -> Result</name> + <name since="OTP 19.3">Module:post_init_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -> Result</name> <fsummary>Called after init_per_testcase.</fsummary> <type> <v>SuiteName = atom()</v> @@ -469,7 +469,7 @@ </func> <func> - <name>Module:pre_end_per_testcase(SuiteName, TestcaseName, EndData, CTHState) -> Result</name> + <name since="OTP 19.3">Module:pre_end_per_testcase(SuiteName, TestcaseName, EndData, CTHState) -> Result</name> <fsummary>Called before end_per_testcase.</fsummary> <type> <v>SuiteName = atom()</v> @@ -505,7 +505,7 @@ </func> <func> - <name>Module:post_end_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -> Result</name> + <name since="OTP 19.3">Module:post_end_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -> Result</name> <fsummary>Called after end_per_testcase.</fsummary> <type> <v>SuiteName = atom()</v> @@ -538,7 +538,7 @@ </func> <func> - <name>Module:pre_end_per_group(SuiteName, GroupName, EndData, CTHState) -> Result</name> + <name since="OTP 19.3">Module:pre_end_per_group(SuiteName, GroupName, EndData, CTHState) -> Result</name> <fsummary>Called before end_per_group.</fsummary> <type> <v>SuiteName = atom()</v> @@ -571,7 +571,7 @@ </func> <func> - <name>Module:post_end_per_group(SuiteName, GroupName, Config, Return, CTHState) -> Result</name> + <name since="OTP 19.3">Module:post_end_per_group(SuiteName, GroupName, Config, Return, CTHState) -> Result</name> <fsummary>Called after end_per_group.</fsummary> <type> <v>SuiteName = atom()</v> @@ -604,7 +604,7 @@ </func> <func> - <name>Module:pre_end_per_suite(SuiteName, EndData, CTHState) -> Result</name> + <name since="OTP R14B02">Module:pre_end_per_suite(SuiteName, EndData, CTHState) -> Result</name> <fsummary>Called before end_per_suite.</fsummary> <type> <v>SuiteName = atom()</v> @@ -631,7 +631,7 @@ </func> <func> - <name>Module:post_end_per_suite(SuiteName, Config, Return, CTHState) -> Result</name> + <name since="OTP R14B02">Module:post_end_per_suite(SuiteName, Config, Return, CTHState) -> Result</name> <fsummary>Called after end_per_suite.</fsummary> <type> <v>SuiteName = atom()</v> @@ -658,7 +658,7 @@ </func> <func> - <name>Module:on_tc_fail(SuiteName, TestName, Reason, CTHState) -> NewCTHState</name> + <name since="OTP 19.3">Module:on_tc_fail(SuiteName, TestName, Reason, CTHState) -> NewCTHState</name> <fsummary>Called after the CTH scope ends.</fsummary> <type> <v>SuiteName = atom()</v> @@ -702,7 +702,7 @@ </func> <func> - <name>Module:on_tc_skip(SuiteName, TestName, Reason, CTHState) -> NewCTHState</name> + <name since="OTP 19.3">Module:on_tc_skip(SuiteName, TestName, Reason, CTHState) -> NewCTHState</name> <fsummary>Called after the CTH scope ends.</fsummary> <type> <v>SuiteName = atom()</v> @@ -748,7 +748,7 @@ </func> <func> - <name>Module:terminate(CTHState)</name> + <name since="OTP R14B02">Module:terminate(CTHState)</name> <fsummary>Called after the CTH scope ends.</fsummary> <type> <v>CTHState = term()</v> @@ -762,7 +762,7 @@ </func> <func> - <name>Module:id(Opts) -> Id</name> + <name since="OTP R14B02">Module:id(Opts) -> Id</name> <fsummary>Called before the init function of a CTH.</fsummary> <type> <v>Opts = term()</v> diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml index 7ecc2e4298..ea4b67be08 100644 --- a/lib/common_test/doc/src/ct_hooks_chapter.xml +++ b/lib/common_test/doc/src/ct_hooks_chapter.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2011</year><year>2017</year> + <year>2011</year><year>2018</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -379,7 +379,7 @@ (in Kernel): </p> <code> - %%% @doc Common Test Example Common Test Hook module. + %%% Common Test Example Common Test Hook module. -module(example_cth). %% Callbacks @@ -408,51 +408,51 @@ -record(state, { file_handle, total, suite_total, ts, tcs, data }). - %% @doc Return a unique id for this CTH. + %% Return a unique id for this CTH. id(Opts) -> proplists:get_value(filename, Opts, "/tmp/file.log"). - %% @doc Always called before any other callback function. Use this to initiate + %% Always called before any other callback function. Use this to initiate %% any common state. init(Id, Opts) -> {ok,D} = file:open(Id,[write]), {ok, #state{ file_handle = D, total = 0, data = [] }}. - %% @doc Called before init_per_suite is called. + %% Called before init_per_suite is called. pre_init_per_suite(Suite,Config,State) -> {Config, State#state{ suite_total = 0, tcs = [] }}. - %% @doc Called after init_per_suite. + %% Called after init_per_suite. post_init_per_suite(Suite,Config,Return,State) -> {Return, State}. - %% @doc Called before end_per_suite. + %% Called before end_per_suite. pre_end_per_suite(Suite,Config,State) -> {Config, State}. - %% @doc Called after end_per_suite. + %% Called after end_per_suite. post_end_per_suite(Suite,Config,Return,State) -> Data = {suites, Suite, State#state.suite_total, lists:reverse(State#state.tcs)}, {Return, State#state{ data = [Data | State#state.data] , total = State#state.total + State#state.suite_total } }. - %% @doc Called before each init_per_group. + %% Called before each init_per_group. pre_init_per_group(Suite,Group,Config,State) -> {Config, State}. - %% @doc Called after each init_per_group. + %% Called after each init_per_group. post_init_per_group(Suite,Group,Config,Return,State) -> {Return, State}. - %% @doc Called before each end_per_group. + %% Called before each end_per_group. pre_end_per_group(Suite,Group,Config,State) -> {Config, State}. - %% @doc Called after each end_per_group. + %% Called after each end_per_group. post_end_per_group(Suite,Group,Config,Return,State) -> {Return, State}. - %% @doc Called before each init_per_testcase. + %% Called before each init_per_testcase. pre_init_per_testcase(Suite,TC,Config,State) -> {Config, State#state{ ts = now(), total = State#state.suite_total + 1 } }. @@ -460,26 +460,26 @@ post_init_per_testcase(Suite,TC,Config,Return,State) -> {Return, State} -%% @doc Called before each end_per_testcase (immediately after the test case). +%% Called before each end_per_testcase (immediately after the test case). pre_end_per_testcase(Suite,TC,Config,State) -> {Config, State}. - %% @doc Called after each end_per_testcase. + %% Called after each end_per_testcase. post_end_per_testcase(Suite,TC,Config,Return,State) -> TCInfo = {testcase, Suite, TC, Return, timer:now_diff(now(), State#state.ts)}, {Return, State#state{ ts = undefined, tcs = [TCInfo | State#state.tcs] } }. - %% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group, + %% Called after post_init_per_suite, post_end_per_suite, post_init_per_group, %% post_end_per_group and post_end_per_testcase if the suite, group or test case failed. on_tc_fail(Suite, TC, Reason, State) -> State. - %% @doc Called when a test case is skipped by either user action + %% Called when a test case is skipped by either user action %% or due to an init function failing. on_tc_skip(Suite, TC, Reason, State) -> State. - %% @doc Called when the scope of the CTH is done + %% Called when the scope of the CTH is done terminate(State) -> io:format(State#state.file_handle, "~p.~n", [{test_run, State#state.total, State#state.data}]), @@ -501,12 +501,13 @@ <tag><c>cth_log_redirect</c></tag> <item> <p>Built-in</p> - <p>Captures all <c>error_logger</c> and SASL logging - events and prints them to the current test case log. If an event cannot be - associated with a test case, it is printed in the <c>Common Test</c> framework log. + <p>Captures all log events that would normally be printed by the default + logger handler, and prints them to the current test case log. + If an event cannot be associated with a test case, it is printed in + the <c>Common Test</c> framework log. This happens for test cases running in parallel and events occuring in-between test cases. You can configure the level of - <seealso marker="sasl:sasl_app">SASL</seealso> events report + <seealso marker="sasl:sasl_app">SASL</seealso> reports using the normal SASL mechanisms.</p> </item> <tag><c>cth_surefire</c></tag> diff --git a/lib/common_test/doc/src/ct_master.xml b/lib/common_test/doc/src/ct_master.xml index 6bde4644c6..2ab421fe9e 100644 --- a/lib/common_test/doc/src/ct_master.xml +++ b/lib/common_test/doc/src/ct_master.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_master.xml</file> </header> - <module>ct_master</module> + <module since="">ct_master</module> <modulesummary>Distributed test execution control for Common Test.</modulesummary> <description> @@ -46,7 +46,7 @@ <funcs> <func> - <name>abort() -> ok</name> + <name since="">abort() -> ok</name> <fsummary>Stops all running tests.</fsummary> <desc><marker id="abort-0"/> <p>Stops all running tests.</p> @@ -54,7 +54,7 @@ </func> <func> - <name>abort(Nodes) -> ok</name> + <name since="">abort(Nodes) -> ok</name> <fsummary>Stops tests on specified nodes.</fsummary> <type> <v>Nodes = atom() | [atom()]</v> @@ -65,7 +65,7 @@ </func> <func> - <name>basic_html(Bool) -> ok</name> + <name since="OTP R15B01">basic_html(Bool) -> ok</name> <fsummary>If set to true, the ct_master logs are written on a primitive HTML format, not using the <c>Common Test</c> CSS style sheet.</fsummary> <type> @@ -79,7 +79,7 @@ </func> <func> - <name>get_event_mgr_ref() -> MasterEvMgrRef</name> + <name since="OTP 17.5">get_event_mgr_ref() -> MasterEvMgrRef</name> <fsummary>Gets a reference to the <c>Common Test</c> master event manager.</fsummary> <type> @@ -98,7 +98,7 @@ </func> <func> - <name>progress() -> [{Node, Status}]</name> + <name since="">progress() -> [{Node, Status}]</name> <fsummary>Returns test progress.</fsummary> <type> <v>Node = atom()</v> @@ -112,7 +112,7 @@ </func> <func> - <name>run(TestSpecs) -> ok</name> + <name since="">run(TestSpecs) -> ok</name> <fsummary>Equivalent to run(TestSpecs, false, [], []).</fsummary> <type> <v>TestSpecs = string() | [SeparateOrMerged]</v> @@ -124,7 +124,7 @@ </func> <func> - <name>run(TestSpecs, InclNodes, ExclNodes) -> ok</name> + <name since="">run(TestSpecs, InclNodes, ExclNodes) -> ok</name> <fsummary>Equivalent to run(TestSpecs, false, InclNodes, ExclNodes). </fsummary> <type> @@ -140,7 +140,7 @@ </func> <func> - <name>run(TestSpecs, AllowUserTerms, InclNodes, ExclNodes) -> ok</name> + <name since="">run(TestSpecs, AllowUserTerms, InclNodes, ExclNodes) -> ok</name> <fsummary>Tests are spawned on the nodes as specified in TestSpecs. </fsummary> <type> @@ -162,7 +162,7 @@ </func> <func> - <name>run_on_node(TestSpecs, Node) -> ok</name> + <name since="">run_on_node(TestSpecs, Node) -> ok</name> <fsummary>Equivalent to run_on_node(TestSpecs, false, Node).</fsummary> <type> <v>TestSpecs = string() | [SeparateOrMerged]</v> @@ -177,7 +177,7 @@ </func> <func> - <name>run_on_node(TestSpecs, AllowUserTerms, Node) -> ok</name> + <name since="">run_on_node(TestSpecs, AllowUserTerms, Node) -> ok</name> <fsummary>Tests are spawned on Node according to TestSpecs.</fsummary> <type> <v>TestSpecs = string() | [SeparateOrMerged]</v> @@ -191,7 +191,7 @@ </func> <func> - <name>run_test(Node, Opts) -> ok</name> + <name since="">run_test(Node, Opts) -> ok</name> <fsummary>Tests are spawned on Node using ct:run_test/1.</fsummary> <type> <v>Node = atom()</v> diff --git a/lib/common_test/doc/src/ct_netconfc.xml b/lib/common_test/doc/src/ct_netconfc.xml index 7ec8f23073..8fbe5f3df6 100644 --- a/lib/common_test/doc/src/ct_netconfc.xml +++ b/lib/common_test/doc/src/ct_netconfc.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_netconfc.xml</file> </header> - <module>ct_netconfc</module> + <module since="OTP R15B02">ct_netconfc</module> <modulesummary>NETCONF client module.</modulesummary> <description> @@ -312,8 +312,8 @@ <funcs> <func> - <name name="action" arity="2"/> - <name name="action" arity="3"/> + <name name="action" arity="2" since="OTP R15B02"/> + <name name="action" arity="3" since="OTP R15B02"/> <fsummary>Executes an action.</fsummary> <desc> <p>Executes an action. If the return type is void, <c>ok</c> is @@ -322,8 +322,8 @@ </func> <func> - <name name="close_session" arity="1"/> - <name name="close_session" arity="2"/> + <name name="close_session" arity="1" since="OTP R15B02"/> + <name name="close_session" arity="2" since="OTP R15B02"/> <fsummary>Requests graceful termination of the session associated with the client.</fsummary> <desc> @@ -339,7 +339,7 @@ </func> <func> - <name name="connect" arity="1"/> + <name name="connect" arity="1" since="OTP 20.0"/> <fsummary>Opens an SSH connection to a NETCONF server.</fsummary> <desc> <p>Opens an SSH connection to a NETCONF server.</p> @@ -361,7 +361,7 @@ </func> <func> - <name name="connect" arity="2"/> + <name name="connect" arity="2" since="OTP 20.0"/> <fsummary>Opens an SSH connection to a named NETCONF server.</fsummary> <desc> <p>Open an SSH connection to a named NETCONF server.</p> @@ -399,8 +399,8 @@ </func> <func> - <name name="copy_config" arity="3"/> - <name name="copy_config" arity="4"/> + <name name="copy_config" arity="3" since="OTP R15B02"/> + <name name="copy_config" arity="4" since="OTP R15B02"/> <fsummary>Copies configuration data.</fsummary> <desc> <p>Copies configuration data.</p> @@ -412,12 +412,12 @@ </func> <func> - <name>create_subscription(Client) -> Result</name> - <name>create_subscription(Client, Stream) -> Result</name> - <name>create_subscription(Client, Stream, Filter) -> Result</name> - <name>create_subscription(Client, Stream, Filter, Timeout) -> Result</name> - <name name="create_subscription" arity="5" clause_i="2"/> - <name name="create_subscription" arity="6"/> + <name since="OTP R15B02">create_subscription(Client) -> Result</name> + <name since="OTP R15B02">create_subscription(Client, Stream) -> Result</name> + <name since="OTP R15B02">create_subscription(Client, Stream, Filter) -> Result</name> + <name since="OTP R15B02">create_subscription(Client, Stream, Filter, Timeout) -> Result</name> + <name name="create_subscription" arity="5" clause_i="2" since="OTP R15B02"/> + <name name="create_subscription" arity="6" since="OTP R15B02"/> <fsummary>Creates a subscription for event notifications.</fsummary> <desc> <p>Creates a subscription for event notifications.</p> @@ -490,8 +490,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="delete_config" arity="2"/> - <name name="delete_config" arity="3"/> + <name name="delete_config" arity="2" since="OTP R15B02"/> + <name name="delete_config" arity="3" since="OTP R15B02"/> <fsummary>Deletes configuration data.</fsummary> <desc> <p>Deletes configuration data.</p> @@ -502,7 +502,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="disconnect" arity="1"/> + <name name="disconnect" arity="1" since="OTP 20.0"/> <fsummary>Closes the given SSH connection.</fsummary> <desc> <p>Closes the given SSH connection.</p> @@ -514,10 +514,10 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="edit_config" arity="3"/> - <name name="edit_config" arity="4" clause_i="1"/> - <name name="edit_config" arity="4" clause_i="2"/> - <name name="edit_config" arity="5"/> + <name name="edit_config" arity="3" since="OTP R15B02"/> + <name name="edit_config" arity="4" clause_i="1" since="OTP 18.0"/> + <name name="edit_config" arity="4" clause_i="2" since="OTP R15B02"/> + <name name="edit_config" arity="5" since="OTP 18.0"/> <fsummary>Edits configuration data.</fsummary> <desc> <p>Edits configuration data.</p> @@ -542,8 +542,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="get" arity="2"/> - <name name="get" arity="3"/> + <name name="get" arity="2" since="OTP R15B02"/> + <name name="get" arity="3" since="OTP R15B02"/> <fsummary>Gets data.</fsummary> <desc> <p>Gets data.</p> @@ -557,8 +557,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="get_capabilities" arity="1"/> - <name name="get_capabilities" arity="2"/> + <name name="get_capabilities" arity="1" since="OTP R15B02"/> + <name name="get_capabilities" arity="2" since="OTP R15B02"/> <fsummary>Returns the server side capabilities.</fsummary> <desc> <p>Returns the server side capabilities.</p> @@ -582,8 +582,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="get_config" arity="3"/> - <name name="get_config" arity="4"/> + <name name="get_config" arity="3" since="OTP R15B02"/> + <name name="get_config" arity="4" since="OTP R15B02"/> <fsummary>Gets configuration data.</fsummary> <desc> <p>Gets configuration data.</p> @@ -597,10 +597,10 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="get_event_streams" arity="1"/> - <name name="get_event_streams" arity="2" clause_i="1"/> - <name name="get_event_streams" arity="2" clause_i="2"/> - <name name="get_event_streams" arity="3"/> + <name name="get_event_streams" arity="1" since="OTP 20.0"/> + <name name="get_event_streams" arity="2" clause_i="1" since="OTP R15B02"/> + <name name="get_event_streams" arity="2" clause_i="2" since="OTP 20.0"/> + <name name="get_event_streams" arity="3" since="OTP R15B02"/> <fsummary>Sends a request to get the specified event streams.</fsummary> <desc> <p>Sends a request to get the specified event streams.</p> @@ -637,8 +637,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="get_session_id" arity="1"/> - <name name="get_session_id" arity="2"/> + <name name="get_session_id" arity="1" since="OTP R15B02"/> + <name name="get_session_id" arity="2" since="OTP R15B02"/> <fsummary>Returns the session Id associated with the specified client.</fsummary> <desc> @@ -647,9 +647,9 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="hello" arity="1"/> - <name name="hello" arity="2"/> - <name name="hello" arity="3"/> + <name name="hello" arity="1" since="OTP R15B02"/> + <name name="hello" arity="2" since="OTP R15B02"/> + <name name="hello" arity="3" since="OTP 17.5.3"/> <fsummary>Exchanges hello messages with the server.</fsummary> <desc> <p>Exchanges <c>hello</c> messages with the server.</p> @@ -660,8 +660,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="kill_session" arity="2"/> - <name name="kill_session" arity="3"/> + <name name="kill_session" arity="2" since="OTP R15B02"/> + <name name="kill_session" arity="3" since="OTP R15B02"/> <fsummary>Forces termination of the session associated with the supplied session Id.</fsummary> <desc> @@ -682,8 +682,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="lock" arity="2"/> - <name name="lock" arity="3"/> + <name name="lock" arity="2" since="OTP R15B02"/> + <name name="lock" arity="3" since="OTP R15B02"/> <fsummary>Locks the configuration target.</fsummary> <desc> <p>Locks the configuration target.</p> @@ -703,7 +703,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="only_open" arity="1"/> + <name name="only_open" arity="1" since="OTP R15B02"/> <fsummary>Opens a NETCONF session, but does not send hello.</fsummary> <desc> <p>Opens a NETCONF session, but does not send <c>hello</c>.</p> @@ -714,7 +714,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="only_open" arity="2"/> + <name name="only_open" arity="2" since="OTP R15B02"/> <fsummary>Opens a named NETCONF session, but does not send hello.</fsummary> <desc> <p>Opens a named NETCONF session, but does not send <c>hello</c>.</p> @@ -725,7 +725,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="open" arity="1"/> + <name name="open" arity="1" since="OTP R15B02"/> <fsummary>Opens a NETCONF session and exchanges hello messages.</fsummary> <desc> <p>Opens a NETCONF session and exchanges <c>hello</c> messages.</p> @@ -749,7 +749,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="open" arity="2"/> + <name name="open" arity="2" since="OTP R15B02"/> <fsummary>Opens a named NETCONF session and exchanges hello messages.</fsummary> <desc> @@ -791,8 +791,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="send" arity="2"/> - <name name="send" arity="3"/> + <name name="send" arity="2" since="OTP R16B02"/> + <name name="send" arity="3" since="OTP R16B02"/> <fsummary>Sends an XML document to the server.</fsummary> <desc> <p>Sends an XML document to the server.</p> @@ -804,8 +804,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="send_rpc" arity="2"/> - <name name="send_rpc" arity="3"/> + <name name="send_rpc" arity="2" since="OTP R16B02"/> + <name name="send_rpc" arity="3" since="OTP R16B02"/> <fsummary>Sends a NETCONF rpc request to the server.</fsummary> <desc> <p>Sends a NETCONF <c>rpc</c> request to the server.</p> @@ -820,10 +820,10 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="session" arity="1"/> - <name name="session" arity="2" clause_i="1"/> - <name name="session" arity="2" clause_i="2"/> - <name name="session" arity="3"/> + <name name="session" arity="1" since="OTP 20.0"/> + <name name="session" arity="2" clause_i="1" since="OTP 20.0"/> + <name name="session" arity="2" clause_i="2" since="OTP 20.0"/> + <name name="session" arity="3" since="OTP 20.0"/> <fsummary>Opens a NETCONF session as a channel on the given SSH connection, and exchanges hello messages with the server.</fsummary> @@ -848,8 +848,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="unlock" arity="2"/> - <name name="unlock" arity="3"/> + <name name="unlock" arity="2" since="OTP R15B02"/> + <name name="unlock" arity="3" since="OTP R15B02"/> <fsummary>Unlocks the configuration target.</fsummary> <desc> <p>Unlocks the configuration target.</p> diff --git a/lib/common_test/doc/src/ct_property_test.xml b/lib/common_test/doc/src/ct_property_test.xml index 028e5eb69f..1e01d9a5d7 100644 --- a/lib/common_test/doc/src/ct_property_test.xml +++ b/lib/common_test/doc/src/ct_property_test.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_property_test.xml</file> </header> - <module>ct_property_test</module> + <module since="OTP 17.3">ct_property_test</module> <modulesummary>EXPERIMENTAL support in Common Test for calling property-based tests.</modulesummary> @@ -79,7 +79,7 @@ <funcs> <func> - <name>init_per_suite(Config) -> Config | {skip, Reason}</name> + <name since="OTP 17.3">init_per_suite(Config) -> Config | {skip, Reason}</name> <fsummary>Initializes Config for property testing.</fsummary> <desc><marker id="init_per_suite-1"/> <p>Initializes <c>Config</c> for property testing.</p> @@ -98,7 +98,7 @@ </func> <func> - <name>quickcheck(Property, Config) -> true | {fail, Reason}</name> + <name since="OTP 17.3">quickcheck(Property, Config) -> true | {fail, Reason}</name> <fsummary>Calls quickcheck and returns the result in a form suitable for Common Test.</fsummary> <desc><marker id="quickcheck-2"/> diff --git a/lib/common_test/doc/src/ct_rpc.xml b/lib/common_test/doc/src/ct_rpc.xml index 90e6b833f7..00a4dcec08 100644 --- a/lib/common_test/doc/src/ct_rpc.xml +++ b/lib/common_test/doc/src/ct_rpc.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_rpc.xml</file> </header> - <module>ct_rpc</module> + <module since="">ct_rpc</module> <modulesummary>Common Test specific layer on Erlang/OTP rpc.</modulesummary> <description> @@ -43,7 +43,7 @@ <funcs> <func> - <name>app_node(App, Candidates) -> NodeName</name> + <name since="">app_node(App, Candidates) -> NodeName</name> <fsummary>From a set of candidate nodes determines which of them is running the application App.</fsummary> <type> @@ -61,7 +61,7 @@ </func> <func> - <name>app_node(App, Candidates, FailOnBadRPC) -> NodeName</name> + <name since="">app_node(App, Candidates, FailOnBadRPC) -> NodeName</name> <fsummary>Same as app_node/2, except that argument FailOnBadRPC determines if the search for a candidate node is to stop if badrpc is received at some point.</fsummary> @@ -81,7 +81,7 @@ </func> <func> - <name>app_node(App, Candidates, FailOnBadRPC, Cookie) -> NodeName</name> + <name since="">app_node(App, Candidates, FailOnBadRPC, Cookie) -> NodeName</name> <fsummary>Same as app_node/2, except that argument FailOnBadRPC determines if the search for a candidate node is to stop if badrpc is received at some point.</fsummary> @@ -105,7 +105,7 @@ </func> <func> - <name>call(Node, Module, Function, Args) -> term() | {badrpc, Reason}</name> + <name since="">call(Node, Module, Function, Args) -> term() | {badrpc, Reason}</name> <fsummary>Same as call(Node, Module, Function, Args, infinity).</fsummary> <desc><marker id="call-4"/> <p>Same as <c>call(Node, Module, Function, Args, infinity)</c>.</p> @@ -113,7 +113,7 @@ </func> <func> - <name>call(Node, Module, Function, Args, TimeOut) -> term() | {badrpc, Reason}</name> + <name since="">call(Node, Module, Function, Args, TimeOut) -> term() | {badrpc, Reason}</name> <fsummary>Evaluates apply(Module, Function, Args) on the node Node.</fsummary> <type> @@ -136,7 +136,7 @@ </func> <func> - <name>call(Node, Module, Function, Args, TimeOut, Cookie) -> term() | {badrpc, Reason}</name> + <name since="">call(Node, Module, Function, Args, TimeOut, Cookie) -> term() | {badrpc, Reason}</name> <fsummary>Evaluates apply(Module, Function, Args) on the node Node.</fsummary> <type> @@ -163,7 +163,7 @@ </func> <func> - <name>cast(Node, Module, Function, Args) -> ok</name> + <name since="">cast(Node, Module, Function, Args) -> ok</name> <fsummary>Evaluates apply(Module, Function, Args) on the node Node.</fsummary> <type> @@ -187,7 +187,7 @@ </func> <func> - <name>cast(Node, Module, Function, Args, Cookie) -> ok</name> + <name since="">cast(Node, Module, Function, Args, Cookie) -> ok</name> <fsummary>Evaluates apply(Module, Function, Args) on the node Node.</fsummary> <type> diff --git a/lib/common_test/doc/src/ct_slave.xml b/lib/common_test/doc/src/ct_slave.xml index 9d9aa50051..84e619482d 100644 --- a/lib/common_test/doc/src/ct_slave.xml +++ b/lib/common_test/doc/src/ct_slave.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_slave.xml</file> </header> - <module>ct_slave</module> + <module since="OTP R14B">ct_slave</module> <modulesummary>Common Test framework functions for starting and stopping nodes for Large-Scale Testing.</modulesummary> @@ -50,7 +50,7 @@ <funcs> <func> - <name>start(Node) -> Result</name> + <name since="OTP R14B">start(Node) -> Result</name> <fsummary>Starts an Erlang node with name Node on the local host.</fsummary> <type> @@ -68,7 +68,7 @@ </func> <func> - <name>start(HostOrNode, NodeOrOpts) -> Result</name> + <name since="OTP R14B">start(HostOrNode, NodeOrOpts) -> Result</name> <fsummary>Starts an Erlang node with default options on a specified host, or on the local host with specified options.</fsummary> <type> @@ -90,7 +90,7 @@ </func> <func> - <name>start(Host, Node, Opts) -> Result</name> + <name since="OTP R14B">start(Host, Node, Opts) -> Result</name> <fsummary>Starts an Erlang node with name Node on host Host as specified by the combination of options in Opts.</fsummary> <type> @@ -184,7 +184,7 @@ </func> <func> - <name>stop(Node) -> Result</name> + <name since="OTP R14B">stop(Node) -> Result</name> <fsummary>Stops the running Erlang node with name Node on the local host.</fsummary> <type> @@ -199,7 +199,7 @@ </func> <func> - <name>stop(Host, Node) -> Result</name> + <name since="OTP R14B">stop(Host, Node) -> Result</name> <fsummary>Stops the running Erlang node with name Node on host Host.</fsummary> <type> diff --git a/lib/common_test/doc/src/ct_snmp.xml b/lib/common_test/doc/src/ct_snmp.xml index 0a5e52b16c..343781814a 100644 --- a/lib/common_test/doc/src/ct_snmp.xml +++ b/lib/common_test/doc/src/ct_snmp.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_snmp.xml</file> </header> - <module>ct_snmp</module> + <module since="">ct_snmp</module> <modulesummary>Common Test user interface module for the SNMP application.</modulesummary> <description> @@ -240,7 +240,7 @@ <funcs> <func> - <name>get_next_values(Agent, Oids, MgrAgentConfName) -> SnmpReply</name> + <name since="">get_next_values(Agent, Oids, MgrAgentConfName) -> SnmpReply</name> <fsummary>Issues a synchronous SNMP get next request.</fsummary> <type> <v>Agent = agent_name()</v> @@ -254,7 +254,7 @@ </func> <func> - <name>get_values(Agent, Oids, MgrAgentConfName) -> SnmpReply</name> + <name since="">get_values(Agent, Oids, MgrAgentConfName) -> SnmpReply</name> <fsummary>Issues a synchronous SNMP get request.</fsummary> <type> <v>Agent = agent_name()</v> @@ -268,7 +268,7 @@ </func> <func> - <name>load_mibs(Mibs) -> ok | {error, Reason}</name> + <name since="">load_mibs(Mibs) -> ok | {error, Reason}</name> <fsummary>Loads the MIBs into agent snmp_master_agent.</fsummary> <type> <v>Mibs = [MibName]</v> @@ -281,7 +281,7 @@ </func> <func> - <name>register_agents(MgrAgentConfName, ManagedAgents) -> ok | {error, Reason}</name> + <name since="">register_agents(MgrAgentConfName, ManagedAgents) -> ok | {error, Reason}</name> <fsummary>Explicitly instructs the manager to handle this agent.</fsummary> <type> @@ -300,7 +300,7 @@ </func> <func> - <name>register_users(MgrAgentConfName, Users) -> ok | {error, Reason}</name> + <name since="">register_users(MgrAgentConfName, Users) -> ok | {error, Reason}</name> <fsummary>Registers the manager entity (=user) responsible for specific agent(s).</fsummary> <type> @@ -319,7 +319,7 @@ </func> <func> - <name>register_usm_users(MgrAgentConfName, UsmUsers) -> ok | {error, Reason}</name> + <name since="">register_usm_users(MgrAgentConfName, UsmUsers) -> ok | {error, Reason}</name> <fsummary>Explicitly instructs the manager to handle this USM user.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -337,7 +337,7 @@ </func> <func> - <name>set_info(Config) -> [{Agent, OldVarsAndVals, NewVarsAndVals}]</name> + <name since="">set_info(Config) -> [{Agent, OldVarsAndVals, NewVarsAndVals}]</name> <fsummary>Returns a list of all successful set requests performed in the test case in reverse order.</fsummary> <type> @@ -357,7 +357,7 @@ </func> <func> - <name>set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -> SnmpReply</name> + <name since="">set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -> SnmpReply</name> <fsummary>Issues a synchronous SNMP set request.</fsummary> <type> <v>Agent = agent_name()</v> @@ -372,7 +372,7 @@ </func> <func> - <name>start(Config, MgrAgentConfName) -> ok</name> + <name since="">start(Config, MgrAgentConfName) -> ok</name> <fsummary>Equivalent to start(Config, MgrAgentConfName, undefined).</fsummary> <desc><marker id="start-2"/> @@ -383,7 +383,7 @@ </func> <func> - <name>start(Config, MgrAgentConfName, SnmpAppConfName) -> ok</name> + <name since="">start(Config, MgrAgentConfName, SnmpAppConfName) -> ok</name> <fsummary>Starts an SNMP manager and/or agent.</fsummary> <type> <v>Config = [{Key, Value}]</v> @@ -415,7 +415,7 @@ </func> <func> - <name>stop(Config) -> ok</name> + <name since="">stop(Config) -> ok</name> <fsummary>Stops the SNMP manager and/or agent, and removes all files created.</fsummary> <type> @@ -430,7 +430,7 @@ </func> <func> - <name>unload_mibs(Mibs) -> ok | {error, Reason}</name> + <name since="OTP R16B">unload_mibs(Mibs) -> ok | {error, Reason}</name> <fsummary>Unloads the MIBs from agent snmp_master_agent.</fsummary> <type> <v>Mibs = [MibName]</v> @@ -443,7 +443,7 @@ </func> <func> - <name>unregister_agents(MgrAgentConfName) -> ok</name> + <name since="">unregister_agents(MgrAgentConfName) -> ok</name> <fsummary>Unregisters all managed agents.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -455,7 +455,7 @@ </func> <func> - <name>unregister_agents(MgrAgentConfName, ManagedAgents) -> ok</name> + <name since="OTP R16B">unregister_agents(MgrAgentConfName, ManagedAgents) -> ok</name> <fsummary>Unregisters the specified managed agents.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -468,7 +468,7 @@ </func> <func> - <name>unregister_users(MgrAgentConfName) -> ok</name> + <name since="">unregister_users(MgrAgentConfName) -> ok</name> <fsummary>Unregisters all users.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -480,7 +480,7 @@ </func> <func> - <name>unregister_users(MgrAgentConfName, Users) -> ok</name> + <name since="OTP R16B">unregister_users(MgrAgentConfName, Users) -> ok</name> <fsummary>Unregisters the specified users.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -493,7 +493,7 @@ </func> <func> - <name>unregister_usm_users(MgrAgentConfName) -> ok</name> + <name since="OTP R16B">unregister_usm_users(MgrAgentConfName) -> ok</name> <fsummary>Unregisters all USM users.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -505,7 +505,7 @@ </func> <func> - <name>unregister_usm_users(MgrAgentConfName, UsmUsers) -> ok</name> + <name since="OTP R16B">unregister_usm_users(MgrAgentConfName, UsmUsers) -> ok</name> <fsummary>Unregisters the specified USM users.</fsummary> <type> <v>MgrAgentConfName = atom()</v> diff --git a/lib/common_test/doc/src/ct_ssh.xml b/lib/common_test/doc/src/ct_ssh.xml index 0c7efed154..8d9f31aff8 100644 --- a/lib/common_test/doc/src/ct_ssh.xml +++ b/lib/common_test/doc/src/ct_ssh.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_ssh.xml</file> </header> - <module>ct_ssh</module> + <module since="">ct_ssh</module> <modulesummary>SSH/SFTP client module.</modulesummary> <description> @@ -95,7 +95,7 @@ <funcs> <func> - <name>apread(SSH, Handle, Position, Length) -> Result</name> + <name since="">apread(SSH, Handle, Position, Length) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -109,7 +109,7 @@ </func> <func> - <name>apread(SSH, Server, Handle, Position, Length) -> Result</name> + <name since="">apread(SSH, Server, Handle, Position, Length) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -123,7 +123,7 @@ </func> <func> - <name>apwrite(SSH, Handle, Position, Data) -> Result</name> + <name since="">apwrite(SSH, Handle, Position, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -137,7 +137,7 @@ </func> <func> - <name>apwrite(SSH, Server, Handle, Position, Data) -> Result</name> + <name since="">apwrite(SSH, Server, Handle, Position, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -151,7 +151,7 @@ </func> <func> - <name>aread(SSH, Handle, Len) -> Result</name> + <name since="">aread(SSH, Handle, Len) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -165,7 +165,7 @@ </func> <func> - <name>aread(SSH, Server, Handle, Len) -> Result</name> + <name since="">aread(SSH, Server, Handle, Len) -> Result</name> <fsummary>For inforamtion and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -179,7 +179,7 @@ </func> <func> - <name>awrite(SSH, Handle, Data) -> Result</name> + <name since="">awrite(SSH, Handle, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -193,7 +193,7 @@ </func> <func> - <name>awrite(SSH, Server, Handle, Data) -> Result</name> + <name since="">awrite(SSH, Server, Handle, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -207,7 +207,7 @@ </func> <func> - <name>close(SSH, Handle) -> Result</name> + <name since="">close(SSH, Handle) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -221,7 +221,7 @@ </func> <func> - <name>close(SSH, Server, Handle) -> Result</name> + <name since="">close(SSH, Server, Handle) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -235,7 +235,7 @@ </func> <func> - <name>connect(KeyOrName) -> {ok, Handle} | {error, Reason}</name> + <name since="">connect(KeyOrName) -> {ok, Handle} | {error, Reason}</name> <fsummary>Equivalent to connect(KeyOrName, host, []).</fsummary> <desc><marker id="connect-1"/> <p>Equivalent to @@ -245,7 +245,7 @@ </func> <func> - <name>connect(KeyOrName, ConnType) -> {ok, Handle} | {error, Reason}</name> + <name since="">connect(KeyOrName, ConnType) -> {ok, Handle} | {error, Reason}</name> <fsummary>Equivalent to connect(KeyOrName, ConnType, []).</fsummary> <desc><marker id="connect-2"/> <p>Equivalent to @@ -255,7 +255,7 @@ </func> <func> - <name>connect(KeyOrName, ConnType, ExtraOpts) -> {ok, Handle} | {error, Reason}</name> + <name since="">connect(KeyOrName, ConnType, ExtraOpts) -> {ok, Handle} | {error, Reason}</name> <fsummary>Opens an SSH or SFTP connection using the information associated with KeyOrName.</fsummary> <type> @@ -301,7 +301,7 @@ </func> <func> - <name>del_dir(SSH, Name) -> Result</name> + <name since="">del_dir(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -315,7 +315,7 @@ </func> <func> - <name>del_dir(SSH, Server, Name) -> Result</name> + <name since="">del_dir(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -329,7 +329,7 @@ </func> <func> - <name>delete(SSH, Name) -> Result</name> + <name since="">delete(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -343,7 +343,7 @@ </func> <func> - <name>delete(SSH, Server, Name) -> Result</name> + <name since="">delete(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -357,7 +357,7 @@ </func> <func> - <name>disconnect(SSH) -> ok | {error, Reason}</name> + <name since="">disconnect(SSH) -> ok | {error, Reason}</name> <fsummary>Closes an SSH/SFTP connection.</fsummary> <type> <v>SSH = connection()</v> @@ -369,7 +369,7 @@ </func> <func> - <name>exec(SSH, Command) -> {ok, Data} | {error, Reason}</name> + <name since="">exec(SSH, Command) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to exec(SSH, Command, DefaultTimeout).</fsummary> <desc><marker id="exec-2"/> <p>Equivalent to @@ -379,7 +379,7 @@ </func> <func> - <name>exec(SSH, Command, Timeout) -> {ok, Data} | {error, Reason}</name> + <name since="">exec(SSH, Command, Timeout) -> {ok, Data} | {error, Reason}</name> <fsummary>Requests server to perform Command.</fsummary> <type> <v>SSH = connection()</v> @@ -396,7 +396,7 @@ </func> <func> - <name>exec(SSH, ChannelId, Command, Timeout) -> {ok, Data} | {error, Reason}</name> + <name since="">exec(SSH, ChannelId, Command, Timeout) -> {ok, Data} | {error, Reason}</name> <fsummary>Requests server to perform Command.</fsummary> <type> <v>SSH = connection()</v> @@ -414,7 +414,7 @@ </func> <func> - <name>get_file_info(SSH, Handle) -> Result</name> + <name since="">get_file_info(SSH, Handle) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -428,7 +428,7 @@ </func> <func> - <name>get_file_info(SSH, Server, Handle) -> Result</name> + <name since="">get_file_info(SSH, Server, Handle) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -442,7 +442,7 @@ </func> <func> - <name>list_dir(SSH, Path) -> Result</name> + <name since="">list_dir(SSH, Path) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -456,7 +456,7 @@ </func> <func> - <name>list_dir(SSH, Server, Path) -> Result</name> + <name since="">list_dir(SSH, Server, Path) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -470,7 +470,7 @@ </func> <func> - <name>make_dir(SSH, Name) -> Result</name> + <name since="">make_dir(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -484,7 +484,7 @@ </func> <func> - <name>make_dir(SSH, Server, Name) -> Result</name> + <name since="">make_dir(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -498,7 +498,7 @@ </func> <func> - <name>make_symlink(SSH, Name, Target) -> Result</name> + <name since="">make_symlink(SSH, Name, Target) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -512,7 +512,7 @@ </func> <func> - <name>make_symlink(SSH, Server, Name, Target) -> Result</name> + <name since="">make_symlink(SSH, Server, Name, Target) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -526,7 +526,7 @@ </func> <func> - <name>open(SSH, File, Mode) -> Result</name> + <name since="">open(SSH, File, Mode) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -540,7 +540,7 @@ </func> <func> - <name>open(SSH, Server, File, Mode) -> Result</name> + <name since="">open(SSH, Server, File, Mode) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -554,7 +554,7 @@ </func> <func> - <name>opendir(SSH, Path) -> Result</name> + <name since="">opendir(SSH, Path) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -568,7 +568,7 @@ </func> <func> - <name>opendir(SSH, Server, Path) -> Result</name> + <name since="">opendir(SSH, Server, Path) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -582,7 +582,7 @@ </func> <func> - <name>position(SSH, Handle, Location) -> Result</name> + <name since="">position(SSH, Handle, Location) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -596,7 +596,7 @@ </func> <func> - <name>position(SSH, Server, Handle, Location) -> Result</name> + <name since="">position(SSH, Server, Handle, Location) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -610,7 +610,7 @@ </func> <func> - <name>pread(SSH, Handle, Position, Length) -> Result</name> + <name since="">pread(SSH, Handle, Position, Length) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -624,7 +624,7 @@ </func> <func> - <name>pread(SSH, Server, Handle, Position, Length) -> Result</name> + <name since="">pread(SSH, Server, Handle, Position, Length) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -638,7 +638,7 @@ </func> <func> - <name>pwrite(SSH, Handle, Position, Data) -> Result</name> + <name since="">pwrite(SSH, Handle, Position, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -652,7 +652,7 @@ </func> <func> - <name>pwrite(SSH, Server, Handle, Position, Data) -> Result</name> + <name since="">pwrite(SSH, Server, Handle, Position, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -666,7 +666,7 @@ </func> <func> - <name>read(SSH, Handle, Len) -> Result</name> + <name since="">read(SSH, Handle, Len) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -680,7 +680,7 @@ </func> <func> - <name>read(SSH, Server, Handle, Len) -> Result</name> + <name since="">read(SSH, Server, Handle, Len) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -694,7 +694,7 @@ </func> <func> - <name>read_file(SSH, File) -> Result</name> + <name since="">read_file(SSH, File) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -708,7 +708,7 @@ </func> <func> - <name>read_file(SSH, Server, File) -> Result</name> + <name since="">read_file(SSH, Server, File) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -722,7 +722,7 @@ </func> <func> - <name>read_file_info(SSH, Name) -> Result</name> + <name since="">read_file_info(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -736,7 +736,7 @@ </func> <func> - <name>read_file_info(SSH, Server, Name) -> Result</name> + <name since="">read_file_info(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -750,7 +750,7 @@ </func> <func> - <name>read_link(SSH, Name) -> Result</name> + <name since="">read_link(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -764,7 +764,7 @@ </func> <func> - <name>read_link(SSH, Server, Name) -> Result</name> + <name since="">read_link(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -778,7 +778,7 @@ </func> <func> - <name>read_link_info(SSH, Name) -> Result</name> + <name since="">read_link_info(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -792,7 +792,7 @@ </func> <func> - <name>read_link_info(SSH, Server, Name) -> Result</name> + <name since="">read_link_info(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -806,7 +806,7 @@ </func> <func> - <name>receive_response(SSH, ChannelId) -> {ok, Data} | {error, Reason}</name> + <name since="">receive_response(SSH, ChannelId) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to receive_response(SSH, ChannelId, close).</fsummary> <desc><marker id="receive_response-2"/> @@ -817,7 +817,7 @@ ChannelId, close)</c></seealso>.</p> </func> <func> - <name>receive_response(SSH, ChannelId, End) -> {ok, Data} | {error, Reason}</name> + <name since="">receive_response(SSH, ChannelId, End) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to receive_response(SSH, ChannelId, End, DefaultTimeout).</fsummary> <desc><marker id="receive_response-3"/> @@ -828,7 +828,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>receive_response(SSH, ChannelId, End, Timeout) -> {ok, Data} | {timeout, Data} | {error, Reason}</name> + <name since="">receive_response(SSH, ChannelId, End, Timeout) -> {ok, Data} | {timeout, Data} | {error, Reason}</name> <fsummary>Receives expected data from server on the specified session channel.</fsummary> <type> @@ -863,7 +863,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>rename(SSH, OldName, NewName) -> Result</name> + <name since="">rename(SSH, OldName, NewName) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -877,7 +877,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>rename(SSH, Server, OldName, NewName) -> Result</name> + <name since="">rename(SSH, Server, OldName, NewName) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -891,7 +891,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send(SSH, ChannelId, Data) -> ok | {error, Reason}</name> + <name since="">send(SSH, ChannelId, Data) -> ok | {error, Reason}</name> <fsummary>Equivalent to send(SSH, ChannelId, 0, Data, DefaultTimeout).</fsummary> <desc><marker id="send-3"/> @@ -901,7 +901,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send(SSH, ChannelId, Data, Timeout) -> ok | {error, Reason}</name> + <name since="">send(SSH, ChannelId, Data, Timeout) -> ok | {error, Reason}</name> <fsummary>Equivalent to send(SSH, ChannelId, 0, Data, Timeout).</fsummary> <desc><marker id="send-4"/> <p>Equivalent to <seealso marker="#send-5"><c>ct_ssh:send(SSH, @@ -910,7 +910,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send(SSH, ChannelId, Type, Data, Timeout) -> ok | {error, Reason}</name> + <name since="">send(SSH, ChannelId, Type, Data, Timeout) -> ok | {error, Reason}</name> <fsummary>Sends data to server on specified session channel.</fsummary> <type> <v>SSH = connection()</v> @@ -926,7 +926,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send_and_receive(SSH, ChannelId, Data) -> {ok, Data} | {error, Reason}</name> + <name since="">send_and_receive(SSH, ChannelId, Data) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to send_and_receive(SSH, ChannelId, Data, close).</fsummary> <desc><marker id="send_and_receive-3"/> @@ -937,7 +937,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send_and_receive(SSH, ChannelId, Data, End) -> {ok, Data} | {error, Reason}</name> + <name since="">send_and_receive(SSH, ChannelId, Data, End) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to send_and_receive(SSH, ChannelId, 0, Data, End, DefaultTimeout).</fsummary> <desc><marker id="send_and_receive-4"/> @@ -948,7 +948,7 @@ ChannelId, 0, Data, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send_and_receive(SSH, ChannelId, Data, End, Timeout) -> {ok, Data} | {error, Reason}</name> + <name since="">send_and_receive(SSH, ChannelId, Data, End, Timeout) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to send_and_receive(SSH, ChannelId, 0, Data, End, Timeout).</fsummary> <desc><marker id="send_and_receive-5"/> @@ -959,7 +959,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>send_and_receive(SSH, ChannelId, Type, Data, End, Timeout) -> {ok, Data} | {error, Reason}</name> + <name since="">send_and_receive(SSH, ChannelId, Type, Data, End, Timeout) -> {ok, Data} | {error, Reason}</name> <fsummary>Sends data to server on specified session channel and waits to receive the server response.</fsummary> <type> @@ -981,7 +981,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>session_close(SSH, ChannelId) -> ok | {error, Reason}</name> + <name since="">session_close(SSH, ChannelId) -> ok | {error, Reason}</name> <fsummary>Closes an SSH session channel.</fsummary> <type> <v>SSH = connection()</v> @@ -994,7 +994,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>session_open(SSH) -> {ok, ChannelId} | {error, Reason}</name> + <name since="">session_open(SSH) -> {ok, ChannelId} | {error, Reason}</name> <fsummary>Equivalent to session_open(SSH, DefaultTimeout).</fsummary> <desc><marker id="session_open-1"/> <p>Equivalent to @@ -1004,7 +1004,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>session_open(SSH, Timeout) -> {ok, ChannelId} | {error, Reason}</name> + <name since="">session_open(SSH, Timeout) -> {ok, ChannelId} | {error, Reason}</name> <fsummary>Opens a channel for an SSH session.</fsummary> <type> <v>SSH = connection()</v> @@ -1018,7 +1018,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>sftp_connect(SSH) -> {ok, Server} | {error, Reason}</name> + <name since="">sftp_connect(SSH) -> {ok, Server} | {error, Reason}</name> <fsummary>Starts an SFTP session on an already existing SSH connection.</fsummary> <type> @@ -1034,7 +1034,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>shell(SSH, ChannelId) -> ok | {error, Reason}</name> + <name since="OTP 20.0">shell(SSH, ChannelId) -> ok | {error, Reason}</name> <fsummary>Equivalent to shell(SSH, ChannelId, DefaultTimeout).</fsummary> <desc><marker id="shell-2"/> <p>Equivalent to @@ -1044,7 +1044,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>shell(SSH, ChannelId, Timeout) -> ok | {error, Reason}</name> + <name since="OTP 20.0">shell(SSH, ChannelId, Timeout) -> ok | {error, Reason}</name> <fsummary>Requests that the user default shell is executed at the server end.</fsummary> <type> @@ -1061,7 +1061,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>subsystem(SSH, ChannelId, Subsystem) -> Status | {error, Reason}</name> + <name since="">subsystem(SSH, ChannelId, Subsystem) -> Status | {error, Reason}</name> <fsummary>Equivalent to subsystem(SSH, ChannelId, Subsystem, DefaultTimeout).</fsummary> <desc><marker id="subsystem-3"/> @@ -1072,7 +1072,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>subsystem(SSH, ChannelId, Subsystem, Timeout) -> Status | {error, Reason}</name> + <name since="">subsystem(SSH, ChannelId, Subsystem, Timeout) -> Status | {error, Reason}</name> <fsummary>Sends a request to execute a predefined subsystem.</fsummary> <type> <v>SSH = connection()</v> @@ -1088,7 +1088,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write(SSH, Handle, Data) -> Result</name> + <name since="">write(SSH, Handle, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -1102,7 +1102,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write(SSH, Server, Handle, Data) -> Result</name> + <name since="">write(SSH, Server, Handle, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -1116,7 +1116,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write_file(SSH, File, Iolist) -> Result</name> + <name since="">write_file(SSH, File, Iolist) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -1130,7 +1130,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write_file(SSH, Server, File, Iolist) -> Result</name> + <name since="">write_file(SSH, Server, File, Iolist) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -1144,7 +1144,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write_file_info(SSH, Name, Info) -> Result</name> + <name since="">write_file_info(SSH, Name, Info) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -1158,7 +1158,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write_file_info(SSH, Server, Name, Info) -> Result</name> + <name since="">write_file_info(SSH, Server, Name, Info) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> diff --git a/lib/common_test/doc/src/ct_telnet.xml b/lib/common_test/doc/src/ct_telnet.xml index 8e85cccc99..76f5305c46 100644 --- a/lib/common_test/doc/src/ct_telnet.xml +++ b/lib/common_test/doc/src/ct_telnet.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_telnet.xml</file> </header> - <module>ct_telnet</module> + <module since="">ct_telnet</module> <modulesummary>Common Test specific layer on top of Telnet client ct_telnet_client.erl</modulesummary> <description> @@ -205,7 +205,7 @@ <funcs> <func> - <name>close(Connection) -> ok | {error, Reason}</name> + <name since="">close(Connection) -> ok | {error, Reason}</name> <fsummary>Closes the Telnet connection and stops the process managing it.</fsummary> <type> @@ -223,7 +223,7 @@ </func> <func> - <name>cmd(Connection, Cmd) -> {ok, Data} | {error, Reason}</name> + <name since="">cmd(Connection, Cmd) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to cmd(Connection, Cmd, []).</fsummary> <desc><marker id="cmd-2"/> <p>Equivalent to @@ -233,24 +233,27 @@ </func> <func> - <name>cmd(Connection, Cmd, Opts) -> {ok, Data} | {error, Reason}</name> + <name since="">cmd(Connection, Cmd, Opts) -> {ok, Data} | {error, Reason}</name> <fsummary>Sends a command through Telnet and waits for prompt.</fsummary> <type> <v>Connection = connection()</v> <v>Cmd = string()</v> <v>Opts = [Opt]</v> - <v>Opt = {timeout, timeout()} | {newline, boolean()}</v> + <v>Opt = {timeout, timeout()} | {newline, boolean() | string()}</v> <v>Data = [string()]</v> <v>Reason = term()</v> </type> <desc><marker id="cmd-3"/> <p>Sends a command through Telnet and waits for prompt.</p> - <p>By default, this function adds a new line to the end of the + <p>By default, this function adds "\n" to the end of the specified command. If this is not desired, use option <c>{newline,false}</c>. This is necessary, for example, when sending Telnet command sequences prefixed with character - Interprete As Command (IAC).</p> + Interpret As Command (IAC). Option <c>{newline,string()}</c> + can also be used if a different line end than "\n" is + required, for instance <c>{newline,"\r\n"}</c>, to add both + carriage return and newline characters.</p> <p>Option <c>timeout</c> specifies how long the client must wait for prompt. If the time expires, the function returns @@ -262,7 +265,7 @@ </func> <func> - <name>cmdf(Connection, CmdFormat, Args) -> {ok, Data} | {error, Reason}</name> + <name since="">cmdf(Connection, CmdFormat, Args) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to cmdf(Connection, CmdFormat, Args, []).</fsummary> <desc><marker id="cmdf-3"/> <p>Equivalent to @@ -272,7 +275,7 @@ </func> <func> - <name>cmdf(Connection, CmdFormat, Args, Opts) -> {ok, Data} | {error, Reason}</name> + <name since="">cmdf(Connection, CmdFormat, Args, Opts) -> {ok, Data} | {error, Reason}</name> <fsummary>Sends a Telnet command and waits for prompt (uses a format string and a list of arguments to build the command).</fsummary> <type> @@ -280,7 +283,7 @@ <v>CmdFormat = string()</v> <v>Args = list()</v> <v>Opts = [Opt]</v> - <v>Opt = {timeout, timeout()} | {newline, boolean()}</v> + <v>Opt = {timeout, timeout()} | {newline, boolean() | string()}</v> <v>Data = [string()]</v> <v>Reason = term()</v> </type> @@ -294,7 +297,7 @@ </func> <func> - <name>expect(Connection, Patterns) -> term()</name> + <name since="">expect(Connection, Patterns) -> term()</name> <fsummary>Equivalent to expect(Connections, Patterns, []).</fsummary> <desc><marker id="expect-2"/> <p>Equivalent to @@ -304,7 +307,7 @@ </func> <func> - <name>expect(Connection, Patterns, Opts) -> {ok, Match} | {ok, MatchList, HaltReason} | {error, Reason}</name> + <name since="">expect(Connection, Patterns, Opts) -> {ok, Match} | {ok, MatchList, HaltReason} | {error, Reason}</name> <fsummary>Gets data from Telnet and waits for the expected pattern.</fsummary> <type> @@ -339,7 +342,7 @@ subexpression number <c>N</c>. Subexpressions are denoted with <c>'(' ')'</c> in the regular expression.</p> - <p>If a <c>Tag</c> is speciifed, the returned <c>Match</c> also + <p>If a <c>Tag</c> is specified, the returned <c>Match</c> also includes the matched <c>Tag</c>. Otherwise, only <c>RxMatch</c> is returned.</p> @@ -382,7 +385,7 @@ can abort the operation of waiting for prompt.</p></item> <tag><c>repeat | repeat, N</c></tag> <item><p>The pattern(s) must be matched multiple times. If <c>N</c> - is speciified, the pattern(s) are matched <c>N</c> times, and + is specified, the pattern(s) are matched <c>N</c> times, and the function returns <c>HaltReason = done</c>. This option can be interrupted by one or more <c>HaltPatterns</c>. <c>MatchList</c> is always returned, that is, a list of <c>Match</c> instead of @@ -422,7 +425,7 @@ </func> <func> - <name>get_data(Connection) -> {ok, Data} | {error, Reason}</name> + <name since="">get_data(Connection) -> {ok, Data} | {error, Reason}</name> <fsummary>Gets all data received by the Telnet client since the last command was sent.</fsummary> <type> @@ -446,7 +449,7 @@ </func> <func> - <name>open(Name) -> {ok, Handle} | {error, Reason}</name> + <name since="">open(Name) -> {ok, Handle} | {error, Reason}</name> <fsummary>Equivalent to open(Name, telnet).</fsummary> <desc><marker id="open-1"/> <p>Equivalent to @@ -456,7 +459,7 @@ </func> <func> - <name>open(Name, ConnType) -> {ok, Handle} | {error, Reason}</name> + <name since="">open(Name, ConnType) -> {ok, Handle} | {error, Reason}</name> <fsummary>Opens a Telnet connection to the specified target host.</fsummary> <type> @@ -471,7 +474,7 @@ </func> <func> - <name>open(KeyOrName, ConnType, TargetMod) -> {ok, Handle} | {error, Reason}</name> + <name since="">open(KeyOrName, ConnType, TargetMod) -> {ok, Handle} | {error, Reason}</name> <fsummary>Equivalent to open(KeyOrName, ConnType, TargetMod, []).</fsummary> <desc><marker id="open-3"/> <p>Equivalent to @@ -481,7 +484,7 @@ </func> <func> - <name>open(KeyOrName, ConnType, TargetMod, Extra) -> {ok, Handle} | {error, Reason}</name> + <name since="">open(KeyOrName, ConnType, TargetMod, Extra) -> {ok, Handle} | {error, Reason}</name> <fsummary>Opens a Telnet connection to the specified target host.</fsummary> <type> @@ -531,7 +534,7 @@ </func> <func> - <name>send(Connection, Cmd) -> ok | {error, Reason}</name> + <name since="">send(Connection, Cmd) -> ok | {error, Reason}</name> <fsummary>Equivalent to send(Connection, Cmd, []).</fsummary> <desc><marker id="send-2"/> <p>Equivalent to @@ -541,23 +544,26 @@ </func> <func> - <name>send(Connection, Cmd, Opts) -> ok | {error, Reason}</name> + <name since="OTP 17.4">send(Connection, Cmd, Opts) -> ok | {error, Reason}</name> <fsummary>Sends a Telnet command and returns immediately.</fsummary> <type> <v>Connection = connection()</v> <v>Cmd = string()</v> <v>Opts = [Opt]</v> - <v>Opt = {newline, boolean()}</v> + <v>Opt = {newline, boolean() | string()}</v> <v>Reason = term()</v> </type> <desc><marker id="send-3"/> <p>Sends a Telnet command and returns immediately.</p> - <p>By default, this function adds a newline to the end of the + <p>By default, this function adds "\n" to the end of the specified command. If this is not desired, option <c>{newline,false}</c> can be used. This is necessary, for example, when sending Telnet command sequences prefixed with character - Interprete As Command (IAC).</p> + Interpret As Command (IAC). Option <c>{newline,string()}</c> + can also be used if a different line end than "\n" is + required, for instance <c>{newline,"\r\n"}</c>, to add both + carriage return and newline characters.</p> <p>The resulting output from the command can be read with <seealso marker="#get_data-1"><c>ct_telnet:get_data/2</c></seealso> or @@ -566,7 +572,7 @@ </func> <func> - <name>sendf(Connection, CmdFormat, Args) -> ok | {error, Reason}</name> + <name since="">sendf(Connection, CmdFormat, Args) -> ok | {error, Reason}</name> <fsummary>Equivalent to sendf(Connection, CmdFormat, Args, []).</fsummary> <desc><marker id="sendf-3"/> <p>Equivalent to @@ -576,7 +582,7 @@ </func> <func> - <name>sendf(Connection, CmdFormat, Args, Opts) -> ok | {error, Reason}</name> + <name since="OTP 17.4">sendf(Connection, CmdFormat, Args, Opts) -> ok | {error, Reason}</name> <fsummary>Sends a Telnet command and returns immediately (uses a format string and a list of arguments to build the command).</fsummary> <type> @@ -584,12 +590,15 @@ <v>CmdFormat = string()</v> <v>Args = list()</v> <v>Opts = [Opt]</v> - <v>Opt = {newline, boolean()}</v> + <v>Opt = {newline, boolean() | string()}</v> <v>Reason = term()</v> </type> <desc><marker id="sendf-4"/> <p>Sends a Telnet command and returns immediately (uses a format string and a list of arguments to build the command).</p> + + <p>For details, see + <seealso marker="#send-3"><c>ct_telnet:send/3</c></seealso>.</p> </desc> </func> </funcs> diff --git a/lib/common_test/doc/src/ct_testspec.xml b/lib/common_test/doc/src/ct_testspec.xml index 36893f66cf..9cb9a2ae9f 100644 --- a/lib/common_test/doc/src/ct_testspec.xml +++ b/lib/common_test/doc/src/ct_testspec.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_testspec.xml</file> </header> - <module>ct_testspec</module> + <module since="OTP 19.3">ct_testspec</module> <modulesummary>Parsing of test specifications for Common Test. </modulesummary> @@ -46,7 +46,7 @@ <funcs> <func> - <name>get_tests(SpecsIn) -> {ok, [{Specs,Tests}]} | {error, Reason}</name> + <name since="OTP 19.3">get_tests(SpecsIn) -> {ok, [{Specs,Tests}]} | {error, Reason}</name> <fsummary>Parse the given test specification files and return the tests to run and skip.</fsummary> <type> <v>SpecsIn = [string()] | [[string()]]</v> diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml index ef8b70f1a3..018bb910a1 100644 --- a/lib/common_test/doc/src/notes.xml +++ b/lib/common_test/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2017</year> + <year>2004</year><year>2018</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,6 +33,123 @@ <file>notes.xml</file> </header> +<section><title>Common_Test 1.17.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + OTP internal test improvements.</p> + <p> + Own Id: OTP-15716</p> + </item> + </list> + </section> + +</section> + +<section><title>Common_Test 1.17</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A bug caused <c>ct:encrypt_config_file/3</c> and + <c>ct:decrypt_config_file/3</c> to fail with + <c>badmatch</c> if input parameter <c>KeyOrFile</c> was + <c>{key,string()}</c>. This is now corrected.</p> + <p> + Own Id: OTP-15540</p> + </item> + <item> + <p> + The status of a test case which failed with timetrap + timeout in <c>end_per_testcase</c> could not be modified + by returning <c>{fail,Reason}</c> from a + <c>post_end_per_testcase</c> hook function. This is now + corrected.</p> + <p> + Own Id: OTP-15584 Aux Id: ERIERL-282 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + A new variant of the <c>newline</c> option to + <c>ct_telnet:cmd/3</c> and <c>ct_telnet:send/3</c> is + added, which allows to specify a string to append as + newline indicator on a command. By default, the value is + "\n", but in some cases it is required to be "\r\n", + which this option allows.</p> + <p> + A faulty regular expression given as parameter to + <c>ct_telnet:expect/2,3</c> would earlier crash and look + like an internal error in common_test. A better error + indication is now given, but the test case will still + fail.</p> + <p> + Own Id: OTP-15229 Aux Id: ERIERL-203 </p> + </item> + <item> + <p> + Since the yang RFC allows more than one top element of + config data in an <c>edit-config</c> element, + <c>ct_netconfc:edit_config/3,4,5</c> can now take a list + of XML elements.</p> + <p> + Own Id: OTP-15298</p> + </item> + </list> + </section> + +</section> + +<section><title>Common_Test 1.16.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The Logger handler cth_log_redirect earlier called the + report callback (report_cb) before calling the logger + formatter. In some cases this would fail, since + cth_log_redirect could not handle report callbacks with + two arguments. This is now corrected, so only the + formatter will call the report callback.</p> + <p> + Own Id: OTP-15307</p> + </item> + </list> + </section> + +</section> + +<section><title>Common_Test 1.16</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Use the compiler option <c>nowarn_export_all</c> to + disable <c>export_all</c> warnings when automatically + compiling test suites.</p> + <p> + Own Id: OTP-14810</p> + </item> + <item> + <p> + Use uri_string module instead of http_uri.</p> + <p> + Own Id: OTP-14902</p> + </item> + </list> + </section> + +</section> + <section><title>Common_Test 1.15.4.1</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -52,6 +169,25 @@ </section> +<section><title>Common_Test 1.15.4.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The status of a test case which failed with timetrap + timeout in <c>end_per_testcase</c> could not be modified + by returning <c>{fail,Reason}</c> from a + <c>post_end_per_testcase</c> hook function. This is now + corrected.</p> + <p> + Own Id: OTP-15584 Aux Id: ERIERL-282 </p> + </item> + </list> + </section> + +</section> + <section><title>Common_Test 1.15.4</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -4003,8 +4139,3 @@ <section><title>common_test 1.3.0</title> </section> </chapter> - - - - - diff --git a/lib/common_test/doc/src/unix_telnet.xml b/lib/common_test/doc/src/unix_telnet.xml index b2314a53ec..03d91b7dbe 100644 --- a/lib/common_test/doc/src/unix_telnet.xml +++ b/lib/common_test/doc/src/unix_telnet.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>unix_telnet.xml</file> </header> - <module>unix_telnet</module> + <module since="">unix_telnet</module> <modulesummary>Callback module for ct_telnet, for connecting to a Telnet server on a UNIX host.</modulesummary> @@ -80,7 +80,7 @@ <funcs> <func> - <name>connect(ConnName, Ip, Port, Timeout, KeepAlive, TCPNoDelay, Extra) -> {ok, Handle} | {error, Reason}</name> + <name since="OTP 18.3.3">connect(ConnName, Ip, Port, Timeout, KeepAlive, TCPNoDelay, Extra) -> {ok, Handle} | {error, Reason}</name> <fsummary>Callback for ct_telnet.erl.</fsummary> <type> <v>ConnName = target_name()</v> @@ -107,7 +107,7 @@ </func> <func> - <name>get_prompt_regexp() -> PromptRegexp</name> + <name since="">get_prompt_regexp() -> PromptRegexp</name> <fsummary>Callback for ct_telnet.erl.</fsummary> <type> <v>PromptRegexp = prompt_regexp()</v> 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..a07e61199b 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. @@ -592,7 +592,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {file,KeyFile}) -> encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) -> _ = crypto:start(), - {Key,IVec} = make_crypto_key(Key), + {CryptoKey,IVec} = make_crypto_key(Key), case file:read_file(SrcFileName) of {ok,Bin0} -> Bin1 = term_to_binary({SrcFileName,Bin0}), @@ -600,7 +600,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) -> 0 -> Bin1; N -> list_to_binary([Bin1,random_bytes(8-N)]) end, - EncBin = crypto:block_encrypt(des3_cbc, Key, IVec, Bin2), + EncBin = crypto:block_encrypt(des3_cbc, CryptoKey, IVec, Bin2), case file:write_file(EncryptFileName, EncBin) of ok -> io:format("~ts --(encrypt)--> ~ts~n", @@ -631,10 +631,10 @@ decrypt_config_file(EncryptFileName, TargetFileName, {file,KeyFile}) -> decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) -> _ = crypto:start(), - {Key,IVec} = make_crypto_key(Key), + {CryptoKey,IVec} = make_crypto_key(Key), case file:read_file(EncryptFileName) of {ok,Bin} -> - DecBin = crypto:block_decrypt(des3_cbc, Key, IVec, Bin), + DecBin = crypto:block_decrypt(des3_cbc, CryptoKey, IVec, Bin), case catch binary_to_term(DecBin) of {'EXIT',_} -> {error,bad_file}; @@ -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 c8450280ef..86bd94e999 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 @@ -696,9 +696,16 @@ end_tc(Mod,IPTC={init_per_testcase,_Func},_TCPid,Result,Args,Return) -> end end; -end_tc(Mod,Func0,TCPid,Result,Args,Return) -> +end_tc(Mod,Func00,TCPid,Result,Args,Return) -> %% in case Mod == ct_framework, lookup the suite name Suite = get_suite_name(Mod, Args), + {OnlyCleanup,Func0} = + case Func00 of + {cleanup,F0} -> + {true,F0}; + _ -> + {false,Func00} + end, {Func,FuncSpec,HookFunc} = case Func0 of {end_per_testcase_not_run,F} -> @@ -742,6 +749,8 @@ end_tc(Mod,Func0,TCPid,Result,Args,Return) -> case HookFunc of undefined -> {ok,Result}; + _ when OnlyCleanup -> + {ok,Result}; _ -> case ct_hooks:end_tc(Suite,HookFunc,Args,Result,Return) of '$ct_no_change' -> @@ -752,6 +761,8 @@ end_tc(Mod,Func0,TCPid,Result,Args,Return) -> end, FinalResult = case get('$test_server_framework_test') of + _ when OnlyCleanup -> + Result1; undefined -> %% send sync notification so that event handlers may print %% in the log file before it gets closed @@ -903,15 +914,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 +932,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 +1060,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 safe_apply_groups_0(Mod,{ok,[]}) of @@ -1403,7 +1415,7 @@ end_per_group(GroupName, _) -> ok. %%%----------------------------------------------------------------- -%%% @spec report(What,Data) -> ok +%%% -spec report(What,Data) -> ok report(What,Data) -> case What of loginfo -> @@ -1567,14 +1579,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); @@ -1593,7 +1605,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 -> @@ -1603,12 +1615,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). @@ -1616,7 +1628,7 @@ 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 b734455f15..f4b12c41c0 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 903710963c..97c349578f 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 @@ -50,7 +46,6 @@ %% API Functions %% ------------------------------------------------------------------------- -%% @doc Called before any suites are started -spec init(State :: term()) -> ok | {fail, Reason :: term()}. init(Opts) -> @@ -98,7 +93,7 @@ all(Mod, Tests) -> Other end. -%% @doc Called after all suites are done. +%% Called after all suites are done. -spec terminate(Hooks :: term()) -> ok. terminate(Hooks) -> @@ -107,8 +102,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, @@ -149,8 +142,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, @@ -296,8 +287,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, " @@ -490,8 +480,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..a11613bca2 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 @@ -151,7 +149,7 @@ close(Info, StartDir) -> ok; CacheBin -> %% save final version of the log cache to file - _ = file:write_file(?log_cache_name,CacheBin), + write_log_cache(CacheBin), put(ct_log_cache,undefined) end end, @@ -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"] -> @@ -2032,7 +2022,7 @@ update_all_runs_in_cache(AllRunsData) -> %% read from file as long as this logger process is alive put(ct_log_cache,term_to_binary(LogCache)); _ -> - file:write_file(?log_cache_name,term_to_binary(LogCache)) + write_log_cache(term_to_binary(LogCache)) end; SavedLogCache -> update_all_runs_in_cache(AllRunsData,binary_to_term(SavedLogCache)) @@ -2046,7 +2036,7 @@ update_all_runs_in_cache(AllRunsData, LogCache) -> %% read from file as long as this logger process is alive put(ct_log_cache,term_to_binary(LogCache1)); _ -> - file:write_file(?log_cache_name,term_to_binary(LogCache1)) + write_log_cache(term_to_binary(LogCache1)) end. sort_all_runs(Dirs) -> @@ -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}}). @@ -2690,7 +2668,7 @@ update_tests_in_cache(TempData,LogCache=#log_cache{tests=Tests}) -> {_Pid,_Pid} -> put(ct_log_cache,CacheBin); _ -> - file:write_file(?log_cache_name,CacheBin) + write_log_cache(CacheBin) end. %% @@ -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", @@ -3438,3 +3400,9 @@ unexpected_io(Pid, _Category, _Importance, Content, CtLogFd, EscChars) -> Data = io_lib:format("~ts", [lists:foldl(IoFun, [], Content)]), test_server_io:print_unexpected(Data), ok. + +write_log_cache(LogCacheBin) when is_binary(LogCacheBin) -> + TmpFile = ?log_cache_name++".tmp", + _ = file:write_file(TmpFile,LogCacheBin), + _ = file:rename(TmpFile,?log_cache_name), + ok. 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..6a758c4ea3 100644 --- a/lib/common_test/src/ct_netconfc.erl +++ b/lib/common_test/src/ct_netconfc.erl @@ -583,7 +583,7 @@ get_config(Client, Source, Filter, Timeout) -> -spec edit_config(Client, Target, Config) -> Result when Client :: client(), Target :: netconf_db(), - Config :: simple_xml(), + Config :: simple_xml() | [simple_xml()], Result :: ok | {error,error_reason()}. edit_config(Client, Target, Config) -> edit_config(Client, Target, Config, ?DEFAULT_TIMEOUT). @@ -591,7 +591,7 @@ edit_config(Client, Target, Config) -> -spec edit_config(Client, Target, Config, OptParams) -> Result when Client :: client(), Target :: netconf_db(), - Config :: simple_xml(), + Config :: simple_xml() | [simple_xml()], OptParams :: [simple_xml()], Result :: ok | {error,error_reason()}; (Client, Target, Config, Timeout) -> Result when @@ -608,10 +608,12 @@ edit_config(Client, Target, Config, OptParams) when is_list(OptParams) -> -spec edit_config(Client, Target, Config, OptParams, Timeout) -> Result when Client :: client(), Target :: netconf_db(), - Config :: simple_xml(), + Config :: simple_xml() | [simple_xml()], OptParams :: [simple_xml()], Timeout :: timeout(), Result :: ok | {error,error_reason()}. +edit_config(Client, Target, Config, OptParams, Timeout) when not is_list(Config)-> + edit_config(Client, Target, [Config], OptParams, Timeout); edit_config(Client, Target, Config, OptParams, Timeout) -> call(Client, {send_rpc_op, edit_config, [Target,Config,OptParams], Timeout}). @@ -1113,7 +1115,7 @@ encode_rpc_operation(get,[Filter]) -> encode_rpc_operation(get_config,[Source,Filter]) -> {'get-config',[{source,[Source]}] ++ filter(Filter)}; encode_rpc_operation(edit_config,[Target,Config,OptParams]) -> - {'edit-config',[{target,[Target]}] ++ OptParams ++ [{config,[Config]}]}; + {'edit-config',[{target,[Target]}] ++ OptParams ++ [{config,Config}]}; encode_rpc_operation(delete_config,[Target]) -> {'delete-config',[{target,[Target]}]}; encode_rpc_operation(copy_config,[Target,Source]) -> @@ -1467,7 +1469,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..174008c790 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 -> @@ -445,158 +194,47 @@ send(Connection,Cmd,Opts) -> check_send_opts([{newline,Bool}|Opts]) when is_boolean(Bool) -> check_send_opts(Opts); +check_send_opts([{newline,String}|Opts]) when is_list(String) -> + case lists:all(fun(I) when is_integer(I), I>=0, I=<127 -> true; + (_) -> false + end, String) of + true -> + check_send_opts(Opts); + false -> + {error,{invalid_option,{newline,String}}} + end; check_send_opts([Invalid|_]) -> {error,{invalid_option,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} -> - call(Pid,{expect,Patterns,Opts}); - Error -> - Error + {ok,Pid} -> + case call(Pid,{expect,Patterns,Opts}) of + {error,Reason} when element(1,Reason)==bad_pattern -> + %% Faulty user input - should fail the test case + exit({Reason,{?MODULE,?FUNCTION_NAME,3}}); + Other -> + Other + end; + Error -> + Error end. %%%================================================================= %%% Callback functions -%% @hidden + init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) -> S0 = case ct:get_config(telnet_settings) of undefined -> @@ -677,7 +315,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 +440,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 +470,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 +537,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 +545,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 +553,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 +603,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 +611,6 @@ start_gen_log(Heading) -> end. %%%----------------------------------------------------------------- -%%% @hidden end_gen_log() -> %% check if output is suppressed case ct_util:is_silenced(telnet) of @@ -988,7 +618,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 +667,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,64 +685,72 @@ 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 = + HaltPatterns0 = case get_ignore_prompt(Opts) of true -> get_haltpatterns(Opts); false -> [prompt | get_haltpatterns(Opts)] end, - - PromptCheck = get_prompt_check(Opts), - - {WaitForPrompt,Pattern1,Opts1} = wait_for_prompt(Pattern0,Opts), - - Seq = get_seq(Opts1), - Pattern2 = convert_pattern(Pattern1,Seq), - {IdleTimeout,TotalTimeout} = get_timeouts(Opts1), - - EO = #eo{teln_pid=Pid, - prx=Prx, - idle_timeout=IdleTimeout, - total_timeout=TotalTimeout, - seq=Seq, - haltpatterns=HaltPatterns, - prompt_check=PromptCheck}, + case convert_pattern(HaltPatterns0,false) of + {ok,HaltPatterns} -> + {WaitForPrompt,Pattern1,Opts1} = wait_for_prompt(Pattern0,Opts), + Seq = get_seq(Opts1), + case convert_pattern(Pattern1,Seq) of + {ok,Pattern2} -> + {IdleTimeout,TotalTimeout} = get_timeouts(Opts1), + PromptCheck = get_prompt_check(Opts1), + + EO = #eo{teln_pid=Pid, + prx=Prx, + idle_timeout=IdleTimeout, + total_timeout=TotalTimeout, + seq=Seq, + haltpatterns=HaltPatterns, + prompt_check=PromptCheck}, - case get_repeat(Opts1) of - false -> - case teln_expect1(Name,Pid,Data,Pattern2,[],EO) of - {ok,Matched,Rest} when WaitForPrompt -> - case lists:reverse(Matched) of - [{prompt,_},Matched1] -> - {ok,Matched1,Rest}; - [{prompt,_}|Matched1] -> - {ok,lists:reverse(Matched1),Rest} - end; - {ok,Matched,Rest} -> - {ok,Matched,Rest}; - {halt,Why,Rest} -> - {error,Why,Rest}; - {error,Reason} -> - {error,Reason} - end; - N -> - EO1 = EO#eo{repeat=N}, - repeat_expect(Name,Pid,Data,Pattern2,[],EO1) + case get_repeat(Opts1) of + false -> + case teln_expect1(Name,Pid,Data,Pattern2,[],EO) of + {ok,Matched,Rest} when WaitForPrompt -> + case lists:reverse(Matched) of + [{prompt,_},Matched1] -> + {ok,Matched1,Rest}; + [{prompt,_}|Matched1] -> + {ok,lists:reverse(Matched1),Rest} + end; + {ok,Matched,Rest} -> + {ok,Matched,Rest}; + {halt,Why,Rest} -> + {error,Why,Rest}; + {error,Reason} -> + {error,Reason} + end; + N -> + EO1 = EO#eo{repeat=N}, + repeat_expect(Name,Pid,Data,Pattern2,[],EO1) + end; + Error -> + Error + end; + Error -> + Error end. -convert_pattern(Pattern,Seq) - when is_list(Pattern) and not is_integer(hd(Pattern)) -> - case Seq of - true -> Pattern; - false -> rm_dupl(Pattern,[]) - end; +convert_pattern(Pattern0,Seq) + when Pattern0==[] orelse (is_list(Pattern0) and not is_integer(hd(Pattern0))) -> + Pattern = + case Seq of + true -> Pattern0; + false -> rm_dupl(Pattern0,[]) + end, + compile_pattern(Pattern,[]); convert_pattern(Pattern,_Seq) -> - [Pattern]. + compile_pattern([Pattern],[]). rm_dupl([P|Ps],Acc) -> case lists:member(P,Acc) of @@ -1126,6 +762,25 @@ rm_dupl([P|Ps],Acc) -> rm_dupl([],Acc) -> lists:reverse(Acc). +compile_pattern([prompt|Patterns],Acc) -> + compile_pattern(Patterns,[prompt|Acc]); +compile_pattern([{prompt,_}=P|Patterns],Acc) -> + compile_pattern(Patterns,[P|Acc]); +compile_pattern([{Tag,Pattern}|Patterns],Acc) -> + try re:compile(Pattern,[unicode]) of + {ok,MP} -> compile_pattern(Patterns,[{Tag,MP}|Acc]); + {error,Error} -> {error,{bad_pattern,{Tag,Pattern},Error}} + catch error:badarg -> {error,{bad_pattern,{Tag,Pattern}}} + end; +compile_pattern([Pattern|Patterns],Acc) -> + try re:compile(Pattern,[unicode]) of + {ok,MP} -> compile_pattern(Patterns,[MP|Acc]); + {error,Error} -> {error,{bad_pattern,Pattern,Error}} + catch error:badarg -> {error,{bad_pattern,Pattern}} + end; +compile_pattern([],Acc) -> + {ok,lists:reverse(Acc)}. + get_timeouts(Opts) -> {case lists:keysearch(idle_timeout,1,Opts) of {value,{_,T}} -> @@ -1159,7 +814,7 @@ get_seq(Opts) -> get_haltpatterns(Opts) -> case lists:keysearch(halt,1,Opts) of {value,{halt,HaltPatterns}} -> - convert_pattern(HaltPatterns,false); + HaltPatterns; false -> [] end. @@ -1203,7 +858,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 +997,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. @@ -1455,7 +1110,7 @@ match_line(Name,Pid,Line,[{prompt,PromptType}|Patterns],FoundPrompt,Term, when PromptType=/=FoundPrompt -> match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag); match_line(Name,Pid,Line,[{Tag,Pattern}|Patterns],FoundPrompt,Term,EO,RetTag) -> - case re:run(Line,Pattern,[{capture,all,list},unicode]) of + case re:run(Line,Pattern,[{capture,all,list}]) of nomatch -> match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag); {match,Match} -> @@ -1463,7 +1118,7 @@ match_line(Name,Pid,Line,[{Tag,Pattern}|Patterns],FoundPrompt,Term,EO,RetTag) -> {RetTag,{Tag,Match}} end; match_line(Name,Pid,Line,[Pattern|Patterns],FoundPrompt,Term,EO,RetTag) -> - case re:run(Line,Pattern,[{capture,all,list},unicode]) of + case re:run(Line,Pattern,[{capture,all,list}]) of nomatch -> match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag); {match,Match} -> @@ -1530,8 +1185,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_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl index 76e4b9ea70..007477c855 100644 --- a/lib/common_test/src/ct_telnet_client.erl +++ b/lib/common_test/src/ct_telnet_client.erl @@ -101,9 +101,11 @@ close(Pid) -> end. send_data(Pid, Data) -> - send_data(Pid, Data, true). + send_data(Pid, Data, "\n"). send_data(Pid, Data, true) -> - send_data(Pid, Data++"\n", false); + send_data(Pid, Data, "\n"); +send_data(Pid, Data, Newline) when is_list(Newline) -> + send_data(Pid, Data++Newline, false); send_data(Pid, Data, false) -> Pid ! {send_data, Data}, ok. 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..4980d1ee4b 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,146 @@ 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, + #{meta:=#{?MODULE:=#{category:=Category}}}=Log, + #{formatter:={Formatter,FConfig}}}, + _From, + #eh_state{log_func=LogFunc}=State) -> + Header = format_header(State), + String = Formatter:format(Log,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 +291,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 ecb2ee7caf..756cd4d692 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. @@ -384,8 +384,8 @@ run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit,TimetrapData}) -> {Result,DetFail,ProcBef,ProcAft}. -type tc_status() :: 'starting' | 'running' | 'init_per_testcase' | - 'end_per_testcase' | {'framework',atom(),atom()} | - 'tc'. + 'end_per_testcase' | {'framework',{atom(),atom(),list}} | + 'tc'. -record(st, { ref :: reference(), @@ -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, @@ -652,8 +653,8 @@ handle_tc_exit({testcase_aborted,{user_timetrap_error,_}=Msg,_}, St) -> #st{config=Config,mf={Mod,Func},pid=Pid} = St, spawn_fw_call(Mod, Func, Config, Pid, Msg, unknown, self()), St; -handle_tc_exit(Reason, #st{status={framework,FwMod,FwFunc}, - config=Config,pid=Pid}=St) -> +handle_tc_exit(Reason, #st{status={framework,{FwMod,FwFunc,_}=FwMFA}, + config=Config,mf={Mod,Func},pid=Pid}=St) -> R = case Reason of {timetrap_timeout,TVal,_} -> {timetrap,TVal}; @@ -665,7 +666,7 @@ handle_tc_exit(Reason, #st{status={framework,FwMod,FwFunc}, Other end, Error = {framework_error,R}, - spawn_fw_call(FwMod, FwFunc, Config, Pid, Error, unknown, self()), + spawn_fw_call(Mod, Func, Config, Pid, {Error,FwMFA}, unknown, self()), St; handle_tc_exit(Reason, #st{status=tc,config=Config0,mf={Mod,Func},pid=Pid}=St) when is_list(Config0) -> @@ -869,22 +870,48 @@ spawn_fw_call(Mod,EPTC={end_per_testcase,Func},EndConf,Pid, end, spawn_link(FwCall); -spawn_fw_call(FwMod,FwFunc,_,_Pid,{framework_error,FwError},_,SendTo) -> +spawn_fw_call(Mod,Func,Conf,Pid,{{framework_error,FwError}, + {FwMod,FwFunc,[A1,A2|_]}=FwMFA},_,SendTo) -> FwCall = fun() -> ct_util:mark_process(), - test_server_sup:framework_call(report, [framework_error, - {{FwMod,FwFunc}, - FwError}]), + Time = + case FwError of + {timetrap,TVal} -> + TVal/1000; + _ -> + died + end, + {Ret,Loc,WarnOrError} = + cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,FwMFA), Comment = - lists:flatten( - io_lib:format("<font color=\"red\">" - "WARNING! ~w:~tw failed!</font>", - [FwMod,FwFunc])), + case WarnOrError of + warn -> + group_leader() ! + {printout,12, + "WARNING! ~w:~tw(~w,~tw,...) failed!\n" + " Reason: ~tp\n", + [FwMod,FwFunc,A1,A2,FwError]}, + lists:flatten( + io_lib:format("<font color=\"red\">" + "WARNING! ~w:~tw(~w,~tw,...) " + "failed!</font>", + [FwMod,FwFunc,A1,A2])); + error -> + group_leader() ! + {printout,12, + "Error! ~w:~tw(~w,~tw,...) failed!\n" + " Reason: ~tp\n", + [FwMod,FwFunc,A1,A2,FwError]}, + lists:flatten( + io_lib:format("<font color=\"red\">" + "ERROR! ~w:~tw(~w,~tw,...) " + "failed!</font>", + [FwMod,FwFunc,A1,A2])) + end, %% finished, report back SendTo ! {self(),fw_notify_done, - {died,{error,{FwMod,FwFunc,FwError}}, - {FwMod,FwFunc},[],Comment}} + {Time,Ret,Loc,[],Comment}} end, spawn_link(FwCall); @@ -929,6 +956,163 @@ spawn_fw_call(Mod,Func,CurrConf,Pid,Error,Loc,SendTo) -> end, spawn_link(FwCall). +cleanup_after_fw_error(_Mod,_Func,Conf,Pid,FwError, + {FwMod,FwFunc=init_tc, + [Mod,{init_per_testcase,Func}=IPTC|_]}) -> + %% Failed during pre_init_per_testcase, the test must be skipped + Skip = {auto_skip,{failed,{FwMod,FwFunc,FwError}}}, + try begin do_end_tc_call(Mod,IPTC, {Pid,Skip,[Conf]}, FwError), + do_init_tc_call(Mod,{end_per_testcase_not_run,Func}, + [Conf],{ok,[Conf]}), + do_end_tc_call(Mod,{end_per_testcase_not_run,Func}, + {Pid,Skip,[Conf]}, FwError) end of + _ -> ok + catch + _:FwEndTCErr -> + exit({fw_notify_done,end_tc,FwEndTCErr}) + end, + {Skip,{FwMod,FwFunc},error}; +cleanup_after_fw_error(_Mod,_Func,Conf,Pid,FwError, + {FwMod,FwFunc=end_tc,[Mod,{init_per_testcase,Func}|_]}) -> + %% Failed during post_init_per_testcase, the test must be skipped + Skip = {auto_skip,{failed,{FwMod,FwFunc,FwError}}}, + try begin do_init_tc_call(Mod,{end_per_testcase_not_run,Func}, + [Conf],{ok,[Conf]}), + do_end_tc_call(Mod,{end_per_testcase_not_run,Func}, + {Pid,Skip,[Conf]}, FwError) end of + _ -> ok + catch + _:FwEndTCErr -> + exit({fw_notify_done,end_tc,FwEndTCErr}) + end, + {Skip,{FwMod,FwFunc},error}; +cleanup_after_fw_error(_Mod,_Func,Conf,Pid,FwError, + {FwMod,FwFunc=init_tc,[Mod,{end_per_testcase,Func}|_]}) -> + %% Failed during pre_end_per_testcase. Warn about it. + {RetVal,Loc} = + case {proplists:get_value(tc_status, Conf), + proplists:get_value(tc_fail_loc, Conf, unknown)} of + {undefined,_} -> + {{failed,{FwMod,FwFunc,FwError}},{FwMod,FwFunc}}; + {E = {failed,_Reason},unknown} -> + {E,[{Mod,Func}]}; + {Result,FailLoc} -> + {Result,FailLoc} + end, + try begin do_end_tc_call(Mod,{end_per_testcase_not_run,Func}, + {Pid,RetVal,[Conf]}, FwError) end of + _ -> ok + catch + _:FwEndTCErr -> + exit({fw_notify_done,end_tc,FwEndTCErr}) + end, + {RetVal,Loc,warn}; +cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError, + {FwMod,FwFunc=end_tc,[Mod,{end_per_testcase,Func}|_]}) -> + %% Failed during post_end_per_testcase. Warn about it. + {RetVal,Report,Loc} = + case {proplists:get_value(tc_status, Conf), + proplists:get_value(tc_fail_loc, Conf, unknown)} of + {undefined,_} -> + {{failed,{FwMod,FwFunc,FwError}}, + {{FwMod,FwError},FwError}, + {FwMod,FwFunc}}; + {E = {failed,_Reason},unknown} -> + {E,{Mod,Func,E},[{Mod,Func}]}; + {Result,FailLoc} -> + {Result,{Mod,Func,Result},FailLoc} + end, + try begin do_end_tc_call(Mod,{cleanup,{end_per_testcase_not_run,Func}}, + {Pid,RetVal,[Conf]}, FwError) end of + _ -> ok + catch + _:FwEndTCErr -> + exit({fw_notify_done,end_tc,FwEndTCErr}) + end, + test_server_sup:framework_call(report,[framework_error,Report]), + {RetVal,Loc,warn}; +cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,{FwMod,FwFunc=init_tc,_}) + when Func =:= init_per_suite; Func =:=init_per_group -> + %% Failed during pre_init_per_suite or pre_init_per_group + RetVal = {failed,{FwMod,FwFunc,FwError}}, + try do_end_tc_call(Mod,Func,{Pid,RetVal,[Conf]},FwError) of + _ -> ok + catch + _:FwEndTCErr -> + exit({fw_notify_done,end_tc,FwEndTCErr}) + end, + {RetVal,{FwMod,FwFunc},error}; +cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,{FwMod,FwFunc=end_tc,_}) + when Func =:= init_per_suite; Func =:=init_per_group -> + %% Failed during post_init_per_suite or post_init_per_group + RetVal = {failed,{FwMod,FwFunc,FwError}}, + try do_end_tc_call(Mod,{cleanup,Func},{Pid,RetVal,[Conf]},FwError) of + _ -> ok + catch + _:FwEndTCErr -> + exit({fw_notify_done,end_tc,FwEndTCErr}) + end, + ReportFunc = + case Func of + init_per_group -> + case proplists:get_value(tc_group_properties,Conf) of + undefined -> + {Func,unknown,[]}; + GProps -> + Name = proplists:get_value(name,GProps), + {Func,Name,proplists:delete(name,GProps)} + end; + _ -> + Func + end, + test_server_sup:framework_call(report,[framework_error, + {Mod,ReportFunc,RetVal}]), + {RetVal,{FwMod,FwFunc},error}; +cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,{FwMod,FwFunc=init_tc,_}) + when Func =:= end_per_suite; Func =:=end_per_group -> + %% Failed during pre_end_per_suite or pre_end_per_group + RetVal = {failed,{FwMod,FwFunc,FwError}}, + try do_end_tc_call(Mod,Func,{Pid,RetVal,[Conf]},FwError) of + _ -> ok + catch + _:FwEndTCErr -> + exit({fw_notify_done,end_tc,FwEndTCErr}) + end, + {RetVal,{FwMod,FwFunc},error}; +cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,{FwMod,FwFunc=end_tc,_}) + when Func =:= end_per_suite; Func =:=end_per_group -> + %% Failed during post_end_per_suite or post_end_per_group + RetVal = {failed,{FwMod,FwFunc,FwError}}, + try do_end_tc_call(Mod,{cleanup,Func},{Pid,RetVal,[Conf]},FwError) of + _ -> ok + catch + _:FwEndTCErr -> + exit({fw_notify_done,end_tc,FwEndTCErr}) + end, + ReportFunc = + case Func of + end_per_group -> + case proplists:get_value(tc_group_properties,Conf) of + undefined -> + {Func,unknown,[]}; + GProps -> + Name = proplists:get_value(name,GProps), + {Func,Name,proplists:delete(name,GProps)} + end; + _ -> + Func + end, + test_server_sup:framework_call(report,[framework_error, + {Mod,ReportFunc,RetVal}]), + {RetVal,{FwMod,FwFunc},error}; +cleanup_after_fw_error(_Mod,_Func,_Conf,_Pid,FwError,{FwMod,FwFunc,_}) -> + %% This is unexpected + test_server_sup:framework_call(report, + [framework_error, + {{FwMod,FwFunc}, + FwError}]), + {FwError,{FwMod,FwFunc},error}. + %% The job proxy process forwards messages between the test case %% process on a shielded node (and its descendants) and the job process. %% @@ -1104,6 +1288,9 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> EndConf1 = user_callback(TCCallback, Mod, Func, 'end', EndConf), + %% save updated config in controller loop + set_tc_state(tc, EndConf1), + %% We can't handle fails or skips here EndConf2 = case do_init_tc_call(Mod,{end_per_testcase,Func}, @@ -1356,13 +1543,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(), @@ -1411,20 +1597,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}; @@ -1566,8 +1751,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 -> @@ -1756,8 +1940,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, @@ -1779,8 +1963,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, @@ -2059,15 +2243,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) -> @@ -2724,9 +2908,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 @@ -2762,9 +2946,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 c075aad32d..fdcaaab2eb 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. @@ -1474,13 +1474,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. @@ -2310,7 +2311,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 %% ----- ------- @@ -2642,7 +2643,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; @@ -3898,6 +3899,10 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, {died,{timetrap_timeout,TimetrapTimeout}} -> progress(failed, Num, Mod, Func, GrName, Loc, timetrap_timeout, TimetrapTimeout, Comment, Style); + {died,Reason={auto_skip,_Why}} -> + %% died in init_per_testcase or in a hook in this context + progress(skip, Num, Mod, Func, GrName, Loc, Reason, + Time, Comment, Style); {died,{Skip,Reason}} when Skip==skip; Skip==skipped -> %% died in init_per_testcase progress(skip, Num, Mod, Func, GrName, Loc, Reason, @@ -4059,11 +4064,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, @@ -4147,11 +4153,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, @@ -4437,7 +4444,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 -> @@ -5230,7 +5237,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), @@ -5802,7 +5809,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..3ae4a047d8 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++"\""; @@ -654,9 +656,19 @@ find_release({unix,linux}, Rel) -> find_release(_, _) -> none. find_rel_linux(Rel) -> - case suse_release() of - none -> []; - SuseRel -> find_rel_suse(Rel, SuseRel) + try + case ubuntu_release() of + none -> none; + [UbuntuRel |_] -> throw(find_rel_ubuntu(Rel, UbuntuRel)) + end, + case suse_release() of + none -> none; + SuseRel -> throw(find_rel_suse(Rel, SuseRel)) + end, + [] + catch + throw:Result -> + Result end. find_rel_suse(Rel, SuseRel) -> @@ -733,6 +745,93 @@ suse_release(Fd) -> end end. +find_rel_ubuntu(_Rel, UbuntuRel) when is_integer(UbuntuRel), UbuntuRel < 16 -> + []; +find_rel_ubuntu(Rel, UbuntuRel) when is_integer(UbuntuRel) -> + Root = "/usr/local/otp/releases/ubuntu", + lists:foldl(fun (ChkUbuntuRel, Acc) -> + find_rel_ubuntu_aux1(Rel, Root++integer_to_list(ChkUbuntuRel)) + ++ Acc + end, + [], + lists:seq(16, UbuntuRel)). + +find_rel_ubuntu_aux1(Rel, RootWc) -> + case erlang:system_info(wordsize) of + 4 -> + find_rel_ubuntu_aux2(Rel, RootWc++"_32"); + 8 -> + find_rel_ubuntu_aux2(Rel, RootWc++"_64") ++ + find_rel_ubuntu_aux2(Rel, RootWc++"_32") + end. + +find_rel_ubuntu_aux2(Rel, RootWc) -> + RelDir = filename:dirname(RootWc), + Pat = filename:basename(RootWc ++ "_" ++ Rel) ++ ".*", + case file:list_dir(RelDir) of + {ok,Dirs} -> + case lists:filter(fun(Dir) -> + case re:run(Dir, Pat, [unicode]) of + nomatch -> false; + _ -> true + end + end, Dirs) of + [] -> + []; + [R|_] -> + [filename:join([RelDir,R,"bin","erl"])] + end; + _ -> + [] + end. + +ubuntu_release() -> + case file:open("/etc/lsb-release", [read]) of + {ok,Fd} -> + try + ubuntu_release(Fd, undefined, undefined) + after + file:close(Fd) + end; + {error,_} -> none + end. + +ubuntu_release(_Fd, DistrId, Rel) when DistrId /= undefined, + Rel /= undefined -> + Ubuntu = case DistrId of + "Ubuntu" -> true; + "ubuntu" -> true; + _ -> false + end, + case Ubuntu of + false -> none; + true -> Rel + end; +ubuntu_release(Fd, DistroId, Rel) -> + case io:get_line(Fd, '') of + eof -> + none; + Line when is_list(Line) -> + case re:run(Line, "^DISTRIB_ID=(\\w+)$", + [{capture,all_but_first,list}]) of + {match,[NewDistroId]} -> + ubuntu_release(Fd, NewDistroId, Rel); + nomatch -> + case re:run(Line, "^DISTRIB_RELEASE=(\\d+(?:\\.\\d+)*)$", + [{capture,all_but_first,list}]) of + {match,[RelList]} -> + NewRel = lists:map(fun (N) -> + list_to_integer(N) + end, + string:lexemes(RelList, ".")), + ubuntu_release(Fd, DistroId, NewRel); + nomatch -> + ubuntu_release(Fd, DistroId, Rel) + end + end + end. + + unpack(Bin) -> {One,Term} = split_binary(Bin, 1), case binary_to_list(One) of diff --git a/lib/common_test/src/test_server_sup.erl b/lib/common_test/src/test_server_sup.erl index 6ddbf1ad27..ab8066a88d 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. @@ -770,7 +770,7 @@ framework_call(Callback,Func,Args,DefaultReturn) -> end, case SetTcState of true -> - test_server:set_tc_state({framework,Mod,Func}); + test_server:set_tc_state({framework,{Mod,Func,Args}}); false -> ok end, @@ -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); diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile index 31f75e9f6b..e510b74d6a 100644 --- a/lib/common_test/test/Makefile +++ b/lib/common_test/test/Makefile @@ -75,6 +75,7 @@ MODULES= \ ct_keep_logs_SUITE \ ct_unicode_SUITE \ ct_auto_clean_SUITE \ + ct_util_SUITE \ ct_tc_repeat_SUITE ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/common_test/test/ct_auto_clean_SUITE.erl b/lib/common_test/test/ct_auto_clean_SUITE.erl index fd81430d0d..a89c90eb79 100644 --- a/lib/common_test/test/ct_auto_clean_SUITE.erl +++ b/lib/common_test/test/ct_auto_clean_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2016. 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. diff --git a/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl b/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl index dae7c1e22c..e779f70693 100644 --- a/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl +++ b/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2016. 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. diff --git a/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl b/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl index 137c81969d..3f8d3957cc 100644 --- a/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl +++ b/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2016. 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. diff --git a/lib/common_test/test/ct_auto_compile_SUITE.erl b/lib/common_test/test/ct_auto_compile_SUITE.erl index dface99b8f..f88f13c889 100644 --- a/lib/common_test/test/ct_auto_compile_SUITE.erl +++ b/lib/common_test/test/ct_auto_compile_SUITE.erl @@ -169,7 +169,7 @@ test_events(ac_flag) -> {?eh,start_info,{1,1,3}}, {?eh,tc_start,{ct_framework,error_in_suite}}, {?eh,tc_done,{ct_framework,error_in_suite, - {failed,{error,'bad_SUITE can not be compiled or loaded'}}}}, + {failed,{error,'bad_SUITE cannot be compiled or loaded'}}}}, {?eh,tc_start,{dummy_SUITE,init_per_suite}}, {?eh,tc_done,{dummy_SUITE,init_per_suite,ok}}, {?eh,test_stats,{1,1,{1,0}}}, @@ -186,7 +186,7 @@ test_events(ac_spec) -> {?eh,start_info,{1,1,3}}, {?eh,tc_start,{ct_framework,error_in_suite}}, {?eh,tc_done,{ct_framework,error_in_suite, - {failed,{error,'bad_SUITE can not be compiled or loaded'}}}}, + {failed,{error,'bad_SUITE cannot be compiled or loaded'}}}}, {?eh,tc_start,{dummy_SUITE,init_per_suite}}, {?eh,tc_done,{dummy_SUITE,init_per_suite,ok}}, {?eh,test_stats,{1,1,{1,0}}}, diff --git a/lib/common_test/test/ct_config_SUITE.erl b/lib/common_test/test/ct_config_SUITE.erl index 250700741c..5ffc735d6a 100644 --- a/lib/common_test/test/ct_config_SUITE.erl +++ b/lib/common_test/test/ct_config_SUITE.erl @@ -213,8 +213,8 @@ reformat_events(Events, EH) -> skip_dynamic() -> case os:getenv("TS_EXTRA_PLATFORM_LABEL") of TSExtraPlatformLabel when is_list(TSExtraPlatformLabel) -> - case string:str(TSExtraPlatformLabel,"TimeWarpingOS") of - 0 -> false; + case string:find(TSExtraPlatformLabel,"TimeWarpingOS") of + nomatch -> false; _ -> true end; _ -> diff --git a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl index 4e013b8056..e9e8b2a54d 100644 --- a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl +++ b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.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. @@ -23,9 +23,7 @@ %% Description: %% This file contains the test cases for the code coverage support %% -%% @author Support -%% @doc Test of code coverage support in common_test -%% @end +%% Test of code coverage support in common_test %%---------------------------------------------------------------------- %%---------------------------------------------------------------------- -module(cover_SUITE). diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl index 7468ebe9d9..d31bd26273 100644 --- a/lib/common_test/test/ct_error_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE.erl @@ -648,33 +648,35 @@ test_events(cfg_error) -> {?eh,tc_start,{cfg_error_11_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_11_SUITE,end_per_suite,ok}}, {?eh,tc_start,{cfg_error_12_SUITE,tc1}}, - {?eh,tc_done,{ct_framework,init_tc,{framework_error,{timetrap,500}}}}, - {?eh,test_stats,{13,8,{0,19}}}, + {?eh,tc_done,{cfg_error_12_SUITE,tc1, + {auto_skipped, + {failed,{ct_framework,init_tc,{timetrap,500}}}}}}, + {?eh,test_stats,{13,7,{0,20}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc2}}, {?eh,tc_done,{cfg_error_12_SUITE,tc2,{failed, {cfg_error_12_SUITE,end_per_testcase, {timetrap_timeout,500}}}}}, - {?eh,test_stats,{14,8,{0,19}}}, + {?eh,test_stats,{14,7,{0,20}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc3}}, {?eh,tc_done,{cfg_error_12_SUITE,tc3,ok}}, - {?eh,test_stats,{15,8,{0,19}}}, + {?eh,test_stats,{15,7,{0,20}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc4}}, {?eh,tc_done,{cfg_error_12_SUITE,tc4,{failed, {cfg_error_12_SUITE,end_per_testcase, {timetrap_timeout,500}}}}}, - {?eh,test_stats,{16,8,{0,19}}}, + {?eh,test_stats,{16,7,{0,20}}}, {?eh,tc_start,{cfg_error_13_SUITE,init_per_suite}}, {?eh,tc_done,{cfg_error_13_SUITE,init_per_suite,ok}}, {?eh,tc_start,{cfg_error_13_SUITE,tc1}}, {?eh,tc_done,{cfg_error_13_SUITE,tc1,ok}}, - {?eh,test_stats,{17,8,{0,19}}}, + {?eh,test_stats,{17,7,{0,20}}}, {?eh,tc_start,{cfg_error_13_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_13_SUITE,end_per_suite,ok}}, {?eh,tc_start,{cfg_error_14_SUITE,init_per_suite}}, {?eh,tc_done,{cfg_error_14_SUITE,init_per_suite,ok}}, {?eh,tc_start,{cfg_error_14_SUITE,tc1}}, {?eh,tc_done,{cfg_error_14_SUITE,tc1,ok}}, - {?eh,test_stats,{18,8,{0,19}}}, + {?eh,test_stats,{18,7,{0,20}}}, {?eh,tc_start,{cfg_error_14_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_14_SUITE,end_per_suite, {comment, @@ -728,25 +730,30 @@ test_events(lib_error) -> {lib_error_1_SUITE,no_lines_throw,{failed,{error,{thrown,catch_me_if_u_can}}}}}, {?eh,test_stats,{0,8,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,init_tc_error}}, - {?eh,tc_done,{ct_framework,init_tc, - {framework_error,{{badmatch,[1,2]},'_'}}}}, - {?eh,test_stats,{0,9,{0,0}}}, + {?eh,tc_done,{lib_error_1_SUITE,init_tc_error, + {auto_skipped, + {failed, + {ct_framework,init_tc, + {{badmatch,[1,2]},'_'}}}}}}, + {?eh,test_stats,{0,8,{0,1}}}, {?eh,tc_start,{lib_error_1_SUITE,init_tc_exit}}, - {?eh,tc_done,{ct_framework,init_tc,{framework_error,byebye}}}, - {?eh,test_stats,{0,10,{0,0}}}, + {?eh,tc_done,{lib_error_1_SUITE,init_tc_exit, + {auto_skipped,{failed,{ct_framework,init_tc,byebye}}}}}, + {?eh,test_stats,{0,8,{0,2}}}, {?eh,tc_start,{lib_error_1_SUITE,init_tc_throw}}, - {?eh,tc_done,{ct_framework,init_tc,{framework_error,catch_me_if_u_can}}}, - {?eh,test_stats,{0,11,{0,0}}}, + {?eh,tc_done,{lib_error_1_SUITE,init_tc_throw, + {auto_skipped,{failed,{ct_framework,init_tc, + catch_me_if_u_can}}}}}, + {?eh,test_stats,{0,8,{0,3}}}, {?eh,tc_start,{lib_error_1_SUITE,end_tc_error}}, - {?eh,tc_done,{ct_framework,end_tc, - {framework_error,{{badmatch,[1,2]},'_'}}}}, - {?eh,test_stats,{0,12,{0,0}}}, + {?eh,tc_done,{lib_error_1_SUITE,end_tc_error,ok}}, % warning in comment + {?eh,test_stats,{1,8,{0,3}}}, {?eh,tc_start,{lib_error_1_SUITE,end_tc_exit}}, - {?eh,tc_done,{ct_framework,end_tc,{framework_error,byebye}}}, - {?eh,test_stats,{0,13,{0,0}}}, + {?eh,tc_done,{lib_error_1_SUITE,end_tc_exit,ok}}, % warning in comment + {?eh,test_stats,{2,8,{0,3}}}, {?eh,tc_start,{lib_error_1_SUITE,end_tc_throw}}, - {?eh,tc_done,{ct_framework,end_tc,{framework_error,catch_me_if_u_can}}}, - {?eh,test_stats,{0,14,{0,0}}}, + {?eh,tc_done,{lib_error_1_SUITE,end_tc_throw,ok}}, % warning in comment + {?eh,test_stats,{3,8,{0,3}}}, {?eh,tc_start,{lib_error_1_SUITE,end_per_suite}}, {?eh,tc_done,{lib_error_1_SUITE,end_per_suite,ok}}, {?eh,test_done,{'DEF','STOP_TIME'}}, diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl index 530ee09654..ef8c05cb2e 100644 --- a/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.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. @@ -18,9 +18,9 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Example Suite Callback module. +%%% Common Test Example Suite Callback module. %%% -%%% <p>This module gives an example of a common test CTH (Common Test Hook). +%%% This module gives an example of a common test CTH (Common Test Hook). %%% There are many ways to add a CTH to a test run, you can do it either in %%% the command line using -ct_hook, in a test spec using %%% {ct_hook,M} or in the suite it self by returning ct_hook @@ -31,7 +31,7 @@ %%% it will be stopped after end_per_suite and so on. See terminate %%% documentation for a table describing the scoping machanics. %%% -%%% All of callbacks except init/1 in a CTH are optional.</p> +%%% All of callbacks except init/1 in a CTH are optional. -module(verify_config). @@ -69,14 +69,14 @@ -record(state, { id = ?MODULE :: term()}). -%% @doc Always called before any other callback function. Use this to initiate +%% Always called before any other callback function. Use this to initiate %% any common state. It should return an state for this CTH. -spec init(Id :: term(), Opts :: proplists:proplist()) -> {ok, State :: #state{}}. init(Id, Opts) -> {ok,Opts}. -%% @doc The ID is used to uniquly identify an CTH instance, if two CTH's +%% The ID is used to uniquly identify an CTH instance, if two CTH's %% return the same ID the seconds CTH is ignored. This function should NOT %% have any side effects as it might be called multiple times by common test. -spec id(Opts :: proplists:proplist()) -> @@ -84,7 +84,7 @@ init(Id, Opts) -> id(Opts) -> os:timestamp(). -%% @doc Called before init_per_suite is called. Note that this callback is +%% Called before init_per_suite is called. Note that this callback is %% only called if the CTH is added before init_per_suite is run (eg. in a test %% specification, suite/0 function etc). %% You can change the config in the this function. @@ -95,7 +95,7 @@ id(Opts) -> pre_init_per_suite(Suite,Config,State) -> {Config, State}. -%% @doc Called after init_per_suite. +%% Called after init_per_suite. %% you can change the return value in this function. -spec post_init_per_suite(Suite :: atom(), Config :: config(), @@ -105,7 +105,7 @@ pre_init_per_suite(Suite,Config,State) -> post_init_per_suite(Suite,Config,Return,State) -> {Return, State}. -%% @doc Called before end_per_suite. The config/state can be changed here, +%% Called before end_per_suite. The config/state can be changed here, %% though it will only affect the *end_per_suite function. -spec pre_end_per_suite(Suite :: atom(), Config :: config() | skip_or_fail(), @@ -114,7 +114,7 @@ post_init_per_suite(Suite,Config,Return,State) -> pre_end_per_suite(Suite,Config,State) -> {Config, State}. -%% @doc Called after end_per_suite. Note that the config cannot be +%% Called after end_per_suite. Note that the config cannot be %% changed here, only the status of the suite. -spec post_end_per_suite(Suite :: atom(), Config :: config(), @@ -124,7 +124,7 @@ pre_end_per_suite(Suite,Config,State) -> post_end_per_suite(Suite,Config,Return,State) -> {Return, State}. -%% @doc Called before each init_per_group. +%% Called before each init_per_group. %% You can change the config in this function. -spec pre_init_per_group(Group :: atom(), Config :: config(), @@ -133,7 +133,7 @@ post_end_per_suite(Suite,Config,Return,State) -> pre_init_per_group(Group,Config,State) -> {Config, State}. -%% @doc Called after each init_per_group. +%% Called after each init_per_group. %% You can change the return value in this function. -spec post_init_per_group(Group :: atom(), Config :: config(), @@ -143,7 +143,7 @@ pre_init_per_group(Group,Config,State) -> post_init_per_group(Group,Config,Return,State) -> {Return, State}. -%% @doc Called after each end_per_group. The config/state can be changed here, +%% Called after each end_per_group. The config/state can be changed here, %% though it will only affect the *end_per_group functions. -spec pre_end_per_group(Group :: atom(), Config :: config() | skip_or_fail(), @@ -152,7 +152,7 @@ post_init_per_group(Group,Config,Return,State) -> pre_end_per_group(Group,Config,State) -> {Config, State}. -%% @doc Called after each end_per_group. Note that the config cannot be +%% Called after each end_per_group. Note that the config cannot be %% changed here, only the status of the group. -spec post_end_per_group(Group :: atom(), Config :: config(), @@ -162,7 +162,7 @@ pre_end_per_group(Group,Config,State) -> post_end_per_group(Group,Config,Return,State) -> {Return, State}. -%% @doc Called before each test case. +%% Called before each test case. %% You can change the config in this function. -spec pre_init_per_testcase(TC :: atom(), Config :: config(), @@ -171,7 +171,7 @@ post_end_per_group(Group,Config,Return,State) -> pre_init_per_testcase(TC,Config,State) -> {Config, State}. -%% @doc Called after each test case. Note that the config cannot be +%% Called after each test case. Note that the config cannot be %% changed here, only the status of the test case. -spec post_end_per_testcase(TC :: atom(), Config :: config(), @@ -198,7 +198,7 @@ post_end_per_testcase(TC,Config,Return,State) -> end, {Return, State}. -%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group, +%% Called after post_init_per_suite, post_end_per_suite, post_init_per_group, %% post_end_per_group and post_end_per_tc if the suite, group or test case failed. %% This function should be used for extra cleanup which might be needed. %% It is not possible to modify the config or the status of the test run. @@ -209,7 +209,7 @@ post_end_per_testcase(TC,Config,Return,State) -> on_tc_fail(TC, Reason, State) -> State. -%% @doc Called when a test case is skipped by either user action +%% Called when a test case is skipped by either user action %% or due to an init function failing. Test case can be %% end_per_suite, init_per_group, end_per_group and the actual test cases. -spec on_tc_skip(TC :: end_per_suite | @@ -221,7 +221,7 @@ on_tc_fail(TC, Reason, State) -> on_tc_skip(TC, Reason, State) -> State. -%% @doc Called when the scope of the CTH is done, this depends on +%% Called when the scope of the CTH is done, this depends on %% when the CTH was specified. This translation table describes when this %% function is called. %% diff --git a/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl b/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl index 07b21b4178..e4c7be3cac 100644 --- a/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl +++ b/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2016. All Rights Reserved. +%% Copyright Ericsson AB 2008-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 Event handler module +%%% Event handler module %%% -%%% <p>This is an event handler module used for testing that -%%% Common Test generates events as expected.</p> +%%% This is an event handler module used for testing that +%%% Common Test generates events as expected. %%% -module(eh_A). diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl index edcfec4fb5..340b8f3d52 100644 --- a/lib/common_test/test/ct_hooks_SUITE.erl +++ b/lib/common_test/test/ct_hooks_SUITE.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. @@ -270,16 +270,21 @@ cth_log(Config) when is_list(Config) -> lists:foreach( fun(UnexpIoLog) -> {ok,Bin} = file:read_file(UnexpIoLog), - Ts = string:tokens(binary_to_list(Bin),[$\n]), - Matches = lists:foldl(fun([$=,$E,$R,$R,$O,$R|_], N) -> - N+1; - ([$L,$o,$g,$g,$e,$r|_], N) -> - N+1; + Ts = string:lexemes(binary_to_list(Bin),[$\n]), + Matches = lists:foldl(fun([$=,$E,$R,$R,$O,$R|_], {E,I,L}) -> + {E+1,I,L}; + ([$=,$I,$N,$F,$O|_], {E,I,L}) -> + {E,I+1,L}; + ([$L,$o,$g,$g,$e,$r|_], {E,I,L}) -> + {E,I,L+1}; (_, N) -> N - end, 0, Ts), - ct:pal("~p matches in ~tp", [Matches,UnexpIoLog]), - if Matches > 10 -> ok; - true -> exit({no_unexpected_io_found,UnexpIoLog}) + end, {0,0,0}, Ts), + ct:pal("~p ({Error,Info,Log}) matches in ~tp", + [Matches,UnexpIoLog]), + MatchList = tuple_to_list(Matches), + case [N || N <- MatchList, N<3] of + [] -> ok; + _ -> exit({missing_unexpected_io,UnexpIoLog}) end end, UnexpIoLogs), ok. diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl index d400348354..404fb33476 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.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. @@ -29,7 +29,6 @@ %% Test server callback functions
%%--------------------------------------------------------------------
-%% @doc
%% Config - [tuple()]
%% A list of key/value pairs, holding the test case configuration.
%%
@@ -38,27 +37,23 @@ %% Note: This function is free to add any key/value pairs to the Config
%% variable, but should NOT alter/remove any existing entries.
%%
-%% @spec init_per_suite(Config) -> Config
-%% @end
+%% -spec init_per_suite(Config) -> Config
%%--------------------------------------------------------------------
init_per_suite(Config) ->
Config.
%%--------------------------------------------------------------------
-%% @doc
%% Config - [tuple()]
%% A list of key/value pairs, holding the test case configuration.
%%
%% Cleanup after the whole suite
%%
-%% @spec end_per_suite(Config) -> _
-%% @end
+%% -spec end_per_suite(Config) -> _
%%--------------------------------------------------------------------
end_per_suite(_Config) ->
ok.
%%--------------------------------------------------------------------
-%% @doc
%% Case - atom()
%% Name of the test case that is about to be run.
%% Config - [tuple()]
@@ -70,14 +65,12 @@ end_per_suite(_Config) -> %% variable, but should NOT alter/remove any existing entries.
%% Initiation before each test case
%%
-%% @spec init_per_testcase(TestCase, Config) -> Config
-%% @end
+%% -spec init_per_testcase(TestCase, Config) -> Config
%%--------------------------------------------------------------------
init_per_testcase(_TestCase, Config) ->
[{ct_hooks,[empty_cth]}|Config].
%%--------------------------------------------------------------------
-%% @doc
%% Case - atom()
%% Name of the test case that is about to be run.
%% Config - [tuple()]
@@ -85,22 +78,19 @@ init_per_testcase(_TestCase, Config) -> %%
%% Cleanup after each test case
%%
-%% @spec end_per_testcase(TestCase, Config) -> _
-%% @end
+%% -spec end_per_testcase(TestCase, Config) -> _
%%--------------------------------------------------------------------
end_per_testcase(_TestCase, _Config) ->
ok.
%%--------------------------------------------------------------------
-%% @doc
%% TestCases - [Case]
%% Case - atom()
%% Name of a test case.
%%
%% Returns a list of all test cases in this test suite
%%
-%% @spec all() -> TestCases
-%% @end
+%% -spec all() -> TestCases
%%--------------------------------------------------------------------
all() ->
[test_case].
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl index bd1ac54781..eda190b682 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.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. @@ -124,6 +124,6 @@ gen() -> gen_loop(N) -> ct:log("Logger iteration: ~p", [N]), error_logger:error_report(N), - error_logger:info_report(progress, N), + error_logger:info_report(N), ct:sleep(150), gen_loop(N+1). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl index 324f1dc80a..60488e84c6 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.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. @@ -18,9 +18,9 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Example Suite Callback module. +%%% Common Test Example Suite Callback module. %%% -%%% <p>This module gives an example of a common test CTH (Common Test Hook). +%%% This module gives an example of a common test CTH (Common Test Hook). %%% There are many ways to add a CTH to a test run, you can do it either in %%% the command line using -ct_hook, in a test spec using %%% {ct_hook,M} or in the suite it self by returning ct_hook @@ -31,7 +31,7 @@ %%% it will be stopped after end_per_suite and so on. See terminate %%% documentation for a table describing the scoping machanics. %%% -%%% All of callbacks except init/1 in a CTH are optional.</p> +%%% All of callbacks except init/1 in a CTH are optional. -module(empty_cth). @@ -74,8 +74,8 @@ -record(state, { id = ?MODULE :: term()}). -%% @doc Called after groups/0. -%% you can change the return value in this function. +%% Called after groups/0. +%% You can change the return value in this function. -spec post_groups(Suite :: atom(), Groups :: list()) -> list(). post_groups(Suite,Groups) -> gen_event:notify( @@ -85,8 +85,8 @@ post_groups(Suite,Groups) -> ct:log("~w:post_groups(~w) called", [?MODULE,Suite]), Groups. -%% @doc Called after all/0. -%% you can change the return value in this function. +%% Called after all/0. +%% You can change the return value in this function. -spec post_all(Suite :: atom(), Tests :: list(), Groups :: term()) -> @@ -99,7 +99,7 @@ post_all(Suite,Tests,Groups) -> ct:log("~w:post_all(~w) called", [?MODULE,Suite]), Tests. -%% @doc Always called before any other callback function. Use this to initiate +%% Always called before any other callback function. Use this to initiate %% any common state. It should return an state for this CTH. -spec init(Id :: term(), Opts :: proplists:proplist()) -> {ok, State :: #state{}}. @@ -109,7 +109,7 @@ init(Id, Opts) -> ct:log("~w:init called", [?MODULE]), {ok,Opts}. -%% @doc The ID is used to uniquly identify an CTH instance, if two CTH's +%% The ID is used to uniquly identify an CTH instance, if two CTH's %% return the same ID the seconds CTH is ignored. This function should NOT %% have any side effects as it might be called multiple times by common test. -spec id(Opts :: proplists:proplist()) -> @@ -120,7 +120,7 @@ id(Opts) -> ct:log("~w:id called", [?MODULE]), ct_test_support:unique_timestamp(). -%% @doc Called before init_per_suite is called. Note that this callback is +%% Called before init_per_suite is called. Note that this callback is %% only called if the CTH is added before init_per_suite is run (eg. in a test %% specification, suite/0 function etc). %% You can change the config in the this function. @@ -136,7 +136,7 @@ pre_init_per_suite(Suite,Config,State) -> ct:log("~w:pre_init_per_suite(~w) called", [?MODULE,Suite]), {Config, State}. -%% @doc Called after init_per_suite. +%% Called after init_per_suite. %% you can change the return value in this function. -spec post_init_per_suite(Suite :: atom(), Config :: config(), @@ -151,7 +151,7 @@ post_init_per_suite(Suite,Config,Return,State) -> ct:log("~w:post_init_per_suite(~w) called", [?MODULE,Suite]), {Return, State}. -%% @doc Called before end_per_suite. The config/state can be changed here, +%% Called before end_per_suite. The config/state can be changed here, %% though it will only affect the *end_per_suite function. -spec pre_end_per_suite(Suite :: atom(), Config :: config() | skip_or_fail(), @@ -165,7 +165,7 @@ pre_end_per_suite(Suite,Config,State) -> ct:log("~w:pre_end_per_suite(~w) called", [?MODULE,Suite]), {Config, State}. -%% @doc Called after end_per_suite. Note that the config cannot be +%% Called after end_per_suite. Note that the config cannot be %% changed here, only the status of the suite. -spec post_end_per_suite(Suite :: atom(), Config :: config(), @@ -180,7 +180,7 @@ post_end_per_suite(Suite,Config,Return,State) -> ct:log("~w:post_end_per_suite(~w) called", [?MODULE,Suite]), {Return, State}. -%% @doc Called before each init_per_group. +%% Called before each init_per_group. %% You can change the config in this function. -spec pre_init_per_group(Suite :: atom(), Group :: atom(), @@ -195,7 +195,7 @@ pre_init_per_group(Suite,Group,Config,State) -> ct:log("~w:pre_init_per_group(~w,~w) called", [?MODULE,Suite,Group]), {Config, State}. -%% @doc Called after each init_per_group. +%% Called after each init_per_group. %% You can change the return value in this function. -spec post_init_per_group(Suite :: atom(), Group :: atom(), @@ -211,7 +211,7 @@ post_init_per_group(Suite,Group,Config,Return,State) -> ct:log("~w:post_init_per_group(~w,~w) called", [?MODULE,Suite,Group]), {Return, State}. -%% @doc Called after each end_per_group. The config/state can be changed here, +%% Called after each end_per_group. The config/state can be changed here, %% though it will only affect the *end_per_group functions. -spec pre_end_per_group(Suite :: atom(), Group :: atom(), @@ -226,7 +226,7 @@ pre_end_per_group(Suite,Group,Config,State) -> ct:log("~w:pre_end_per_group(~w~w) called", [?MODULE,Suite,Group]), {Config, State}. -%% @doc Called after each end_per_group. Note that the config cannot be +%% Called after each end_per_group. Note that the config cannot be %% changed here, only the status of the group. -spec post_end_per_group(Suite :: atom(), Group :: atom(), @@ -242,7 +242,7 @@ post_end_per_group(Suite,Group,Config,Return,State) -> ct:log("~w:post_end_per_group(~w,~w) called", [?MODULE,Suite,Group]), {Return, State}. -%% @doc Called before init_per_testcase/2 for each test case. +%% Called before init_per_testcase/2 for each test case. %% You can change the config in this function. -spec pre_init_per_testcase(Suite :: atom(), TC :: atom(), @@ -257,7 +257,7 @@ pre_init_per_testcase(Suite,TC,Config,State) -> ct:log("~w:pre_init_per_testcase(~w,~w) called", [?MODULE,Suite,TC]), {Config, State}. -%% @doc Called after init_per_testcase/2, and before the test case. +%% Called after init_per_testcase/2, and before the test case. -spec post_init_per_testcase(Suite :: atom(), TC :: atom(), Config :: config(), @@ -272,7 +272,7 @@ post_init_per_testcase(Suite,TC,Config,Return,State) -> ct:log("~w:post_init_per_testcase(~w,~w) called", [?MODULE,Suite,TC]), {Return, State}. -%% @doc Called before end_per_testacse/2. No skip or fail allowed here, +%% Called before end_per_testacse/2. No skip or fail allowed here, %% only config additions. -spec pre_end_per_testcase(Suite :: atom(), TC :: atom(), @@ -287,7 +287,7 @@ pre_end_per_testcase(Suite,TC,Config,State) -> ct:log("~w:pre_end_per_testcase(~w,~w) called", [?MODULE,Suite,TC]), {Config, State}. -%% @doc Called after end_per_testcase/2 for each test case. Note that +%% Called after end_per_testcase/2 for each test case. Note that %% the config cannot be changed here, only the status of the test case. -spec post_end_per_testcase(Suite :: atom(), TC :: atom(), @@ -303,7 +303,7 @@ post_end_per_testcase(Suite,TC,Config,Return,State) -> ct:log("~w:post_end_per_testcase(~w,~w) called", [?MODULE,Suite,TC]), {Return, State}. -%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group, +%% Called after post_init_per_suite, post_end_per_suite, post_init_per_group, %% post_end_per_group and post_end_per_tc if the suite, group or test case failed. %% This function should be used for extra cleanup which might be needed. %% It is not possible to modify the config or the status of the test run. @@ -320,7 +320,7 @@ on_tc_fail(Suite, TC, Reason, State) -> ct:log("~w:on_tc_fail(~w,~w) called", [?MODULE,Suite,TC]), State. -%% @doc Called when a test case is skipped by either user action +%% Called when a test case is skipped by either user action %% or due to an init function failing. Test case can be %% end_per_suite, init_per_group, end_per_group and the actual test cases. -spec on_tc_skip(Suite :: atom(), @@ -338,7 +338,7 @@ on_tc_skip(Suite, TC, Reason, State) -> ct:log("~w:on_tc_skip(~w,~w) called", [?MODULE,Suite,TC]), State. -%% @doc Called when the scope of the CTH is done, this depends on +%% Called when the scope of the CTH is done, this depends on %% when the CTH was specified. This translation table describes when this %% function is called. %% diff --git a/lib/common_test/test/ct_log_SUITE.erl b/lib/common_test/test/ct_log_SUITE.erl index 93affda398..214eb17e1a 100644 --- a/lib/common_test/test/ct_log_SUITE.erl +++ b/lib/common_test/test/ct_log_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2016. 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. @@ -174,7 +174,7 @@ verify(Config) -> TcLogFile = proplists:get_value(the_logfile, SavedCfg), Pid = proplists:get_value(the_pid, SavedCfg), StrPid = lists:flatten(io_lib:format("~p",[Pid])), - EscPid = "<" ++ string:substr(StrPid, 2, length(StrPid)-2) ++ ">", + EscPid = "<" ++ string:slice(StrPid, 1, length(StrPid)-2) ++ ">", String = proplists:get_value(the_string, SavedCfg), ct:log("Read from prev testcase: ~p & ~p", [TcLogFile,Pid]), {ok,Dev} = file:open(TcLogFile, [read]), diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl index 586589ad40..0d17481e95 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2017. All Rights Reserved. +%% Copyright Ericsson AB 2013-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. @@ -23,9 +23,7 @@ %% Description: %% This file contains the test cases for the ct_netconfc API. %% -%% @author Support -%% @doc Netconf Client Interface. -%% @end +%% Netconf Client Interface. %%---------------------------------------------------------------------- %%---------------------------------------------------------------------- -module(netconfc1_SUITE). @@ -442,6 +440,12 @@ edit_config(Config) -> ?ok = ct_netconfc:edit_config(Client,running, {server,[{xmlns,"myns"}], [{name,["myserver"]}]}), + ?NS:expect_reply('edit-config',ok), + ?ok = ct_netconfc:edit_config(Client,running, + [{server,[{xmlns,"myns"}], + [{name,["server1"]}]}, + {server,[{xmlns,"myns"}], + [{name,["server2"]}]}]), ?NS:expect_do_reply('close-session',close,ok), ?ok = ct_netconfc:close_session(Client), ok. diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl index 63bf9be134..656fdb4a40 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012-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. @@ -231,8 +231,7 @@ data_for_channel(CM, Ch, Data, State) -> {ok, NewState} end catch - Class:Reason -> - Stacktrace = erlang:get_stacktrace(), + Class:Reason:Stacktrace -> error_logger:error_report([{?MODULE, data_for_channel}, {request, Data}, {buffer, State#session.buffer}, diff --git a/lib/common_test/test/ct_pre_post_test_io_SUITE.erl b/lib/common_test/test/ct_pre_post_test_io_SUITE.erl index 7ffe6f045b..bca2d5f3de 100644 --- a/lib/common_test/test/ct_pre_post_test_io_SUITE.erl +++ b/lib/common_test/test/ct_pre_post_test_io_SUITE.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. @@ -164,7 +164,7 @@ pre_post_io(Config) -> fun(PrePostIoFile) -> ct:log("Reading Pre/Post Test IO Log file: ~ts", [PrePostIoFile]), {ok,Bin} = file:read_file(PrePostIoFile), - Ts = string:tokens(binary_to_list(Bin),[$\n]), + Ts = string:lexemes(binary_to_list(Bin),[$\n]), PrePostIOEntries = lists:foldl(fun([$L,$o,$g,$g,$e,$r|_], {pre,PreLogN,PreErrN,0,0}) -> @@ -203,7 +203,7 @@ pre_post_io(Config) -> fun(UnexpIoFile) -> ct:log("Reading Unexpected IO Log file: ~ts", [UnexpIoFile]), {ok,Bin} = file:read_file(UnexpIoFile), - Ts = string:tokens(binary_to_list(Bin),[$\n]), + Ts = string:lexemes(binary_to_list(Bin),[$\n]), UnexpIOEntries = lists:foldl(fun([$L,$o,$g,$g,$e,$r|_], [LogN,ErrN]) -> [LogN+1,ErrN]; @@ -241,7 +241,7 @@ try_loop(_Fun, 0) -> gave_up; try_loop(Fun, N) -> try Fun() of - {error,_} -> + {Error,_} when Error==error; Error==badrpc -> timer:sleep(10), try_loop(Fun, N-1); Result -> @@ -257,7 +257,7 @@ try_loop(M, F, _A, 0) -> gave_up; try_loop(M, F, A, N) -> try apply(M, F, A) of - {error,_} -> + {Error,_Reason} when Error==error; Error==badrpc -> timer:sleep(10), try_loop(M, F, A, N-1); Result -> diff --git a/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl b/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl index 1b171801a3..0e10ec187d 100644 --- a/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl +++ b/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2016. 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. @@ -126,12 +126,12 @@ default(Config) -> auto_per_tc(Config) -> PrivDir = proplists:get_value(priv_dir, Config), - ["log_private",_] = string:tokens(filename:basename(PrivDir), "."), + ["log_private",_] = string:lexemes(filename:basename(PrivDir), "."), {ok,_} = file:list_dir(PrivDir). manual_per_tc(Config) -> PrivDir = proplists:get_value(priv_dir, Config), - ["log_private",_] = string:tokens(filename:basename(PrivDir), "."), + ["log_private",_] = string:lexemes(filename:basename(PrivDir), "."), {error,_} = file:list_dir(PrivDir), ok = ct:make_priv_dir(), {ok,_} = file:list_dir(PrivDir). diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl index 4ce375b4ee..1a305b1516 100644 --- a/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl +++ b/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2016. All Rights Reserved. +%% Copyright Ericsson AB 2013-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,14 +19,6 @@ %% %%---------------------------------------------------------------------- %% File: r1_SUITE.erl -%% -%% Description: -%% -%% -%% @author Support -%% @doc -%% @end -%%---------------------------------------------------------------------- %%---------------------------------------------------------------------- -module(r1_SUITE). -include_lib("common_test/include/ct.hrl"). diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl index 77bb544080..393cbcc780 100644 --- a/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl +++ b/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2016. All Rights Reserved. +%% Copyright Ericsson AB 2013-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,14 +19,6 @@ %% %%---------------------------------------------------------------------- %% File: r2_SUITE.erl -%% -%% Description: -%% -%% -%% @author Support -%% @doc -%% @end -%%---------------------------------------------------------------------- %%---------------------------------------------------------------------- -module(r2_SUITE). -include_lib("common_test/include/ct.hrl"). diff --git a/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl b/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl index a6533641d8..1c81bbe95d 100644 --- a/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl +++ b/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.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. @@ -23,9 +23,7 @@ %% Description: %% This file contains the test cases for the ct_snmp API. %% -%% @author Support -%% @doc Test of SNMP support in common_test -%% @end +%% Test of SNMP support in common_test %%---------------------------------------------------------------------- %%---------------------------------------------------------------------- -module(snmp_SUITE). diff --git a/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl b/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl index ed10356cdd..7a73e45b43 100644 --- a/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl +++ b/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.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. @@ -23,9 +23,7 @@ %% Description: %% This file contains the test cases for cth_surefire. %% -%% @author Support -%% @doc Test of surefire support in common_test -%% @end +%% Test of surefire support in common_test %%---------------------------------------------------------------------- %%---------------------------------------------------------------------- -module(surefire_SUITE). diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl index a0089c9bc9..f71b7c370f 100644 --- a/lib/common_test/test/ct_telnet_SUITE.erl +++ b/lib/common_test/test/ct_telnet_SUITE.erl @@ -50,10 +50,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. groups() -> - [{legacy, [], [unix_telnet,own_server,timetrap]}, - {raw, [], [unix_telnet,own_server,timetrap]}, - {html, [], [unix_telnet,own_server]}, - {silent, [], [unix_telnet,own_server]}]. + [{legacy, [], [unix_telnet,own_server,faulty_regexp,timetrap]}, + {raw, [], [unix_telnet,own_server,faulty_regexp,timetrap]}, + {html, [], [unix_telnet,own_server,faulty_regexp]}, + {silent, [], [unix_telnet,own_server,faulty_regexp]}]. all() -> [ @@ -119,6 +119,12 @@ own_server(Config) -> all_tests_in_suite(own_server,"ct_telnet_own_server_SUITE", CfgFile,Config). +faulty_regexp(Config) -> + CfgFile = "telnet.faulty_regexp." ++ + atom_to_list(groupname(Config)) ++ ".cfg", + all_tests_in_suite(faulty_regexp,"ct_telnet_faulty_regexp_SUITE", + CfgFile,Config). + timetrap(Config) -> CfgFile = "telnet.timetrap." ++ atom_to_list(groupname(Config)) ++ ".cfg", @@ -225,6 +231,31 @@ events_to_check(unix_telnet,Config) -> all_cases(ct_telnet_basic_SUITE,Config); events_to_check(own_server,Config) -> all_cases(ct_telnet_own_server_SUITE,Config); +events_to_check(faulty_regexp,_Config) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,tc_done, + {ct_telnet_faulty_regexp_SUITE,expect_pattern, + {failed, + {error,{{bad_pattern,"invalid(pattern",{"missing )",15}}, + {ct_telnet,expect,3}}}}}}, + {?eh,tc_done, + {ct_telnet_faulty_regexp_SUITE,expect_pattern_no_string, + {failed, + {error,{{bad_pattern,invalid_pattern}, + {ct_telnet,expect,3}}}}}}, + {?eh,tc_done, + {ct_telnet_faulty_regexp_SUITE,expect_tag_pattern, + {failed, + {error,{{bad_pattern,{tag,"invalid(pattern"},{"missing )",15}}, + {ct_telnet,expect,3}}}}}}, + {?eh,tc_done, + {ct_telnet_faulty_regexp_SUITE,expect_tag_pattern_no_string, + {failed, + {error,{{bad_pattern,{tag,invalid_pattern}}, + {ct_telnet,expect,3}}}}}}, + {?eh,tc_done,{ct_telnet_faulty_regexp_SUITE,expect_pattern_unicode,ok}}, + {?eh,tc_done,{ct_telnet_faulty_regexp_SUITE,expect_tag_pattern_unicode,ok}}, + {?eh,stop_logging,[]}]; events_to_check(timetrap,_Config) -> [{?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,tc_done,{ct_telnet_timetrap_SUITE,expect_timetrap, diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_faulty_regexp_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_faulty_regexp_SUITE.erl new file mode 100644 index 0000000000..a5c9451a9c --- /dev/null +++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_faulty_regexp_SUITE.erl @@ -0,0 +1,79 @@ +-module(ct_telnet_faulty_regexp_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(name, telnet_server_conn1). + +%%-------------------------------------------------------------------- +%% TEST SERVER CALLBACK FUNCTIONS +%%-------------------------------------------------------------------- + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +suite() -> [{require,?name,{unix,[telnet]}}, + {require,ct_conn_log}, + {ct_hooks, [{cth_conn_log,[]}]}]. + +all() -> + [expect_pattern, + expect_pattern_no_string, + expect_tag_pattern, + expect_tag_pattern_no_string, + expect_pattern_unicode, + expect_tag_pattern_unicode]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +init_per_testcase(_,Config) -> + ct:log("init_per_testcase: opening telnet connection...",[]), + {ok,_} = ct_telnet:open(?name), + ct:log("...done",[]), + Config. + +end_per_testcase(_,_Config) -> + ct:log("end_per_testcase: closing telnet connection...",[]), + _ = ct_telnet:close(?name), + ct:log("...done",[]), + ok. + +expect_pattern(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + ok = ct_telnet:expect(?name, "invalid(pattern"). + +expect_pattern_no_string(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + ok = ct_telnet:expect(?name, invalid_pattern). + +expect_tag_pattern(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + ok = ct_telnet:expect(?name, {tag,"invalid(pattern"}). + +expect_tag_pattern_no_string(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + ok = ct_telnet:expect(?name, {tag,invalid_pattern}). + +%% Test that a unicode pattern can be given without the testcase +%% failing. Do however notice that there is no real unicode support +%% in ct_telnet yet, that is, the telnet binary mode is not supported. +expect_pattern_unicode(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + {error,{prompt,_}} = ct_telnet:expect(?name, "pattern_with_unicode_αβ"), + ok. + +expect_tag_pattern_unicode(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + {error,{prompt,_}} = ct_telnet:expect(?name, "pattern_with_unicode_αβ"), + ok. diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl index 985fa40ad2..34df57027e 100644 --- a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl +++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl @@ -58,7 +58,8 @@ all() -> server_speaks, server_disconnects, newline_ayt, - newline_break + newline_break, + newline_string ]. groups() -> @@ -393,3 +394,11 @@ newline_break(_) -> "> " = lists:flatten(R), ok = ct_telnet:close(Handle), ok. + +%% Test option {newline,String} to specify an own newline, e.g. "\r\n" +newline_string(_) -> + {ok, Handle} = ct_telnet:open(telnet_server_conn1), + ok = ct_telnet:send(Handle, "echo hello-", [{newline,"own_nl\n"}]), + {ok,["hello-own_nl"]} = ct_telnet:expect(Handle, ["hello-own_nl"]), + ok = ct_telnet:close(Handle), + ok. diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl index 44c27e54c2..388d5d46c6 100644 --- a/lib/common_test/test/ct_test_support.erl +++ b/lib/common_test/test/ct_test_support.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2017. All Rights Reserved. +%% Copyright Ericsson AB 2008-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 Test support functions +%%% Test support functions %%% -%%% <p>This is a support module for testing the Common Test Framework.</p> +%%% This is a support module for testing the Common Test Framework. %%% -module(ct_test_support). @@ -88,7 +88,7 @@ start_slave(Config, Level) -> start_slave(ct, Config, Level). start_slave(NodeName, Config, Level) -> - [_,Host] = string:tokens(atom_to_list(node()), "@"), + [_,Host] = string:lexemes(atom_to_list(node()), "@"), test_server:format(0, "Trying to start ~s~n", [atom_to_list(NodeName)++"@"++Host]), PR = proplists:get_value(printable_range,Config,io:printable_range()), @@ -1088,8 +1088,8 @@ locate({TEH,Name,{'DEF','RUNDIR'}}, Node, [Ev|Evs], Config) -> {TEH,#event{name=Name, node=Node, data=EvData}} -> {_,{_,LogDir}} = lists:keysearch(logdir, 1, get_opts(Config)), D = filename:join(LogDir, "ct_run." ++ atom_to_list(Node)), - case string:str(EvData, D) of - 0 -> exit({badmatch,EvData}); + case string:find(EvData, D) of + nomatch -> exit({badmatch,EvData}); _ -> ok end, {Config,Evs}; @@ -1104,8 +1104,8 @@ locate({TEH,Name,{'DEF',{'START_TIME','LOGDIR'}}}, Node, [Ev|Evs], Config) -> {DT={{_,_,_},{_,_,_}},Dir} when is_list(Dir) -> {_,{_,LogDir}} = lists:keysearch(logdir, 1, get_opts(Config)), D = filename:join(LogDir, "ct_run." ++ atom_to_list(Node)), - case string:str(Dir, D) of - 0 -> exit({badmatch,Dir}); + case string:find(Dir, D) of + nomatch -> exit({badmatch,Dir}); _ -> ok end, {[{start_time,DT}|Config],Evs}; @@ -1373,7 +1373,7 @@ delete_dirs(LogDir) -> Dirs2Del = lists:foldl(fun(Dir, Del) -> [S,Mi,H,D,Mo,Y|_] = - lists:reverse(string:tokens(Dir, [$.,$-,$_])), + lists:reverse(string:lexemes(Dir, [$.,$-,$_])), S2I = fun(Str) -> list_to_integer(Str) end, DT = {{S2I(Y),S2I(Mo),S2I(D)}, {S2I(H),S2I(Mi),S2I(S)}}, Then = calendar:datetime_to_gregorian_seconds(DT), diff --git a/lib/common_test/test/ct_test_support_eh.erl b/lib/common_test/test/ct_test_support_eh.erl index e8db52dcd3..120692dc7c 100644 --- a/lib/common_test/test/ct_test_support_eh.erl +++ b/lib/common_test/test/ct_test_support_eh.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2016. 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,10 +18,10 @@ %% %CopyrightEnd% %% -%%% @doc Event handler module +%%% Event handler module %%% -%%% <p>This is an event handler module used for testing that -%%% Common Test generates events as expected.</p> +%%% This is an event handler module used for testing that +%%% Common Test generates events as expected. %%% -module(ct_test_support_eh). diff --git a/lib/common_test/test/ct_unicode_SUITE.erl b/lib/common_test/test/ct_unicode_SUITE.erl index 355503a5dc..6f6ec97ceb 100644 --- a/lib/common_test/test/ct_unicode_SUITE.erl +++ b/lib/common_test/test/ct_unicode_SUITE.erl @@ -191,7 +191,7 @@ check_logs(Dirs) -> [] -> ok; Match -> - MatchStr = string:join(Match,"\n"), + MatchStr = lists:join("\n",Match), ct:log("ERROR: Escaped unicode characters found in:~n~ts",[MatchStr]), ct:fail(escaped_unicode_characters_found) end. diff --git a/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl b/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl index 993452500e..4f9dd20e3e 100644 --- a/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl +++ b/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.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. @@ -77,7 +77,7 @@ all() -> 'fail_αβ_4'(_Config) -> ct:log("This is test case ~tw",[?FUNCTION_NAME]), - S = try throw(ok) catch throw:ok -> erlang:get_stacktrace() end, + S = try throw(ok) catch throw:ok:Stacktrace -> Stacktrace end, erlang:raise(error,{error,testcase,?FUNCTION_NAME},S), ok. diff --git a/lib/common_test/test/ct_userconfig_callback.erl b/lib/common_test/test/ct_userconfig_callback.erl index c723f4ca1c..e48d338dd5 100644 --- a/lib/common_test/test/ct_userconfig_callback.erl +++ b/lib/common_test/test/ct_userconfig_callback.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. @@ -21,7 +21,7 @@ -export([check_parameter/1, read_config/1]). read_config(Str) -> - KeyVals = string:tokens(Str, " "), + KeyVals = string:lexemes(Str, " "), {ok,read_config1(KeyVals)}. read_config1([Key,Val | KeyVals]) -> diff --git a/lib/common_test/test/ct_util_SUITE.erl b/lib/common_test/test/ct_util_SUITE.erl new file mode 100644 index 0000000000..1d773855da --- /dev/null +++ b/lib/common_test/test/ct_util_SUITE.erl @@ -0,0 +1,490 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009-2017. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(ct_util_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +-define(eh, ct_test_support_eh). + +%%-------------------------------------------------------------------- +%% TEST SERVER CALLBACK FUNCTIONS +%%-------------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% Description: Since Common Test starts another Test Server +%% instance, the tests need to be performed on a separate node (or +%% there will be clashes with logging processes etc). +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + DataDir = ?config(data_dir, Config), + CTHs = filelib:wildcard(filename:join(DataDir,"*_cth.erl")), + io:format("CTHs: ~p",[CTHs]), + [io:format("Compiling ~p: ~p", + [FileName,compile:file(FileName,[{outdir,DataDir},debug_info])]) || + FileName <- CTHs], + ct_test_support:init_per_suite([{path_dirs,[DataDir]} | Config]). + +end_per_suite(Config) -> + ct_test_support:end_per_suite(Config). + +init_per_testcase(TestCase, Config) -> + ct_test_support:init_per_testcase(TestCase, Config). + +end_per_testcase(TestCase, Config) -> + ct_test_support:end_per_testcase(TestCase, Config). + + +suite() -> + [{timetrap,{minutes,1}}]. + +all() -> + all(suite). + +all(suite) -> + [ + pre_init_per_suite, + post_init_per_suite, + pre_end_per_suite, + post_end_per_suite, + pre_init_per_group, + post_init_per_group, + pre_end_per_group, + post_end_per_group, + pre_init_per_testcase, + post_init_per_testcase, + pre_end_per_testcase, + post_end_per_testcase + ]. + + +%%-------------------------------------------------------------------- +%% TEST CASES +%%-------------------------------------------------------------------- + +%%%----------------------------------------------------------------- +%%% +pre_init_per_suite(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{pre_init_per_suite, + {curr_tc_SUITE,kill}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +post_init_per_suite(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{post_init_per_suite, + {curr_tc_SUITE,kill}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +pre_end_per_suite(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{pre_end_per_suite, + {curr_tc_SUITE,kill}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +post_end_per_suite(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{post_end_per_suite, + {curr_tc_SUITE,kill}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + + +pre_init_per_group(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{pre_init_per_group, + {curr_tc_SUITE,g,kill}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +post_init_per_group(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{post_init_per_group, + {curr_tc_SUITE,g,kill}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +pre_end_per_group(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{pre_end_per_group, + {curr_tc_SUITE,g,kill}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +post_end_per_group(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{post_end_per_group, + {curr_tc_SUITE,g,kill}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +pre_init_per_testcase(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{pre_init_per_testcase, + {curr_tc_SUITE,tc1,kill}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +post_init_per_testcase(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{post_init_per_testcase, + {curr_tc_SUITE,tc1,{timeout,5000}}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +pre_end_per_testcase(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{pre_end_per_testcase, + {curr_tc_SUITE,tc1,{timeout,5000}}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +post_end_per_testcase(Config) -> + CfgFile = gen_config(?FUNCTION_NAME, + [{post_end_per_testcase, + {curr_tc_SUITE,tc1,kill}}], + Config), + ok = do_test(?FUNCTION_NAME, + "curr_tc_SUITE.erl", + [{ct_hooks,[ct_util_cth]},{config,CfgFile}], + Config). + +%%%----------------------------------------------------------------- +%%% HELP FUNCTIONS +%%%----------------------------------------------------------------- + +do_test(Tag, Suite, RunTestArgs, Config) -> + do_test(Tag, Suite, RunTestArgs, Config, 2). + +do_test(Tag, Suite0, RunTestArgs, Config, EC) -> + DataDir = ?config(data_dir, Config), + Suite = filename:join([DataDir,Suite0]), + {Opts,ERPid} = setup([{suite,Suite}]++[{label,Tag}|RunTestArgs],Config), + Res = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + %% io:format("~p~n",[Events]), + + ct_test_support:log_events(Tag, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + + TestEvents = events_to_check(Tag, EC), + ok = ct_test_support:verify_events(TestEvents, Events, Config), + Res. + +setup(Test, Config) -> + Opts0 = ct_test_support:get_opts(Config), + Level = ?config(trace_level, Config), + EvHArgs = [{cbm,ct_test_support},{trace_level,Level}], + Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test], + ERPid = ct_test_support:start_event_receiver(Config), + {Opts,ERPid}. + +reformat(Events, EH) -> + ct_test_support:reformat(Events, EH). + +gen_config(Name,KeyVals,Config) -> + PrivDir = ?config(priv_dir,Config), + File = filename:join(PrivDir,atom_to_list(Name)++".cfg"), + ok = file:write_file(File,[io_lib:format("~p.~n",[{Key,Value}]) + || {Key,Value} <- KeyVals]), + File. + +%%%----------------------------------------------------------------- +%%% TEST EVENTS +%%%----------------------------------------------------------------- +events_to_check(Test) -> + %% 2 tests (ct:run_test + script_start) is default + events_to_check(Test, 2). + +events_to_check(_, 0) -> + []; +events_to_check(Test, N) -> + test_events(Test) ++ events_to_check(Test, N-1). + +test_events(IPS) when IPS=:=pre_init_per_suite; IPS=:=post_init_per_suite -> + S = curr_tc_SUITE, + FwFunc = + case IPS of + pre_init_per_suite -> init_tc; + post_init_per_suite -> end_tc + end, + E = {failed,{ct_framework,FwFunc,{test_case_failed,hahahahahah}}}, + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,4}}, + {?eh,tc_start,{S,init_per_suite}}, + {?eh,tc_done,{S,init_per_suite,E}}, + {?eh,tc_auto_skip,{S,tc1,{failed,{S,init_per_suite,E}}}}, + {?eh,tc_auto_skip,{S,tc2,{failed,{S,init_per_suite,E}}}}, + {?eh,tc_auto_skip,{S,{tc1,g},{failed,{S,init_per_suite,E}}}}, + {?eh,tc_auto_skip,{S,{tc2,g},{failed,{S,init_per_suite,E}}}}, + {?eh,test_stats,{0,0,{0,4}}}, + {?eh,tc_auto_skip,{S,end_per_suite,{failed,{S,init_per_suite,E}}}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]; + +test_events(EPS) when EPS=:=pre_end_per_suite; EPS=:=post_end_per_suite -> + S = curr_tc_SUITE, + FwFunc = + case EPS of + pre_end_per_suite -> init_tc; + post_end_per_suite -> end_tc + end, + E = {failed,{ct_framework,FwFunc,{test_case_failed,hahahahahah}}}, + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,4}}, + {?eh,tc_start,{S,init_per_suite}}, + {?eh,tc_done,{S,init_per_suite,ok}}, + {?eh,tc_start,{S,tc1}}, + {?eh,tc_done,{S,tc1,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_start,{S,tc2}}, + {?eh,tc_done,{S,tc2,ok}}, + {?eh,test_stats,{2,0,{0,0}}}, + [{?eh,tc_start,{S,{init_per_group,g,[]}}}, + {?eh,tc_done,{S,{init_per_group,g,[]},ok}}, + {?eh,tc_start,{S,tc1}}, + {?eh,tc_done,{S,tc1,ok}}, + {?eh,test_stats,{3,0,{0,0}}}, + {?eh,tc_start,{S,tc2}}, + {?eh,tc_done,{S,tc2,ok}}, + {?eh,test_stats,{4,0,{0,0}}}, + {?eh,tc_start,{S,{end_per_group,g,[]}}}, + {?eh,tc_done,{S,{end_per_group,g,[]},ok}}], + {?eh,tc_start,{S,end_per_suite}}, + {?eh,tc_done,{S,end_per_suite,E}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]; + +test_events(IPG) when IPG=:=pre_init_per_group; IPG=:=post_init_per_group -> + S = curr_tc_SUITE, + FwFunc = + case IPG of + pre_init_per_group -> init_tc; + post_init_per_group -> end_tc + end, + E = {failed,{ct_framework,FwFunc,{test_case_failed,hahahahahah}}}, + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,4}}, + {?eh,tc_start,{S,init_per_suite}}, + {?eh,tc_done,{S,init_per_suite,ok}}, + {?eh,tc_start,{S,tc1}}, + {?eh,tc_done,{S,tc1,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_start,{S,tc2}}, + {?eh,tc_done,{S,tc2,ok}}, + {?eh,test_stats,{2,0,{0,0}}}, + [{?eh,tc_start,{S,{init_per_group,g,[]}}}, + {?eh,tc_done,{S,{init_per_group,g,[]},E}}, + {?eh,tc_auto_skip,{S,{tc1,g},{failed,{S,init_per_group,E}}}}, + {?eh,tc_auto_skip,{S,{tc2,g},{failed,{S,init_per_group,E}}}}, + {?eh,test_stats,{2,0,{0,2}}}, + {?eh,tc_auto_skip,{S,{end_per_group,g},{failed,{S,init_per_group,E}}}}], + {?eh,tc_start,{S,end_per_suite}}, + {?eh,tc_done,{S,end_per_suite,ok}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]; + +test_events(EPG) when EPG=:=pre_end_per_group; EPG=:=post_end_per_group -> + S = curr_tc_SUITE, + FwFunc = + case EPG of + pre_end_per_group -> init_tc; + post_end_per_group -> end_tc + end, + E = {failed,{ct_framework,FwFunc,{test_case_failed,hahahahahah}}}, + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,4}}, + {?eh,tc_start,{S,init_per_suite}}, + {?eh,tc_done,{S,init_per_suite,ok}}, + {?eh,tc_start,{S,tc1}}, + {?eh,tc_done,{S,tc1,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_start,{S,tc2}}, + {?eh,tc_done,{S,tc2,ok}}, + {?eh,test_stats,{2,0,{0,0}}}, + [{?eh,tc_start,{S,{init_per_group,g,[]}}}, + {?eh,tc_done,{S,{init_per_group,g,[]},ok}}, + {?eh,tc_start,{S,tc1}}, + {?eh,tc_done,{S,tc1,ok}}, + {?eh,test_stats,{3,0,{0,0}}}, + {?eh,tc_start,{S,tc2}}, + {?eh,tc_done,{S,tc2,ok}}, + {?eh,test_stats,{4,0,{0,0}}}, + {?eh,tc_start,{S,{end_per_group,g,[]}}}, + {?eh,tc_done,{S,{end_per_group,g,[]},E}}], + {?eh,tc_start,{S,end_per_suite}}, + {?eh,tc_done,{S,end_per_suite,ok}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]; + +test_events(IPTC) when IPTC=:=pre_init_per_testcase; + IPTC=:=post_init_per_testcase -> + S = curr_tc_SUITE, + E = case IPTC of + pre_init_per_testcase -> + {failed,{ct_framework,init_tc,{test_case_failed,hahahahahah}}}; + post_init_per_testcase -> + {failed,{ct_framework,end_tc,{timetrap,3000}}} + end, + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,4}}, + {?eh,tc_start,{S,init_per_suite}}, + {?eh,tc_done,{S,init_per_suite,ok}}, + {?eh,tc_start,{S,tc1}}, + {?eh,tc_done,{S,tc1,{auto_skipped,E}}}, + {?eh,test_stats,{0,0,{0,1}}}, + {?eh,tc_start,{S,tc2}}, + {?eh,tc_done,{S,tc2,ok}}, + {?eh,test_stats,{1,0,{0,1}}}, + [{?eh,tc_start,{S,{init_per_group,g,[]}}}, + {?eh,tc_done,{S,{init_per_group,g,[]},ok}}, + {?eh,tc_start,{S,tc1}}, + {?eh,tc_done,{S,tc1,{auto_skipped,E}}}, + {?eh,test_stats,{1,0,{0,2}}}, + {?eh,tc_start,{S,tc2}}, + {?eh,tc_done,{S,tc2,ok}}, + {?eh,test_stats,{2,0,{0,2}}}, + {?eh,tc_start,{S,{end_per_group,g,[]}}}, + {?eh,tc_done,{S,{end_per_group,g,[]},ok}}], + {?eh,tc_start,{S,end_per_suite}}, + {?eh,tc_done,{S,end_per_suite,ok}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]; + +test_events(EPTC) when EPTC=:=pre_end_per_testcase; EPTC=:=post_end_per_testcase-> + S = curr_tc_SUITE, + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,4}}, + {?eh,tc_start,{S,tc1}}, + {?eh,tc_done,{S,tc1,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_start,{S,tc2}}, + {?eh,tc_done,{S,tc2,ok}}, + {?eh,test_stats,{2,0,{0,0}}}, + [{?eh,tc_start,{S,{init_per_group,g,[]}}}, + {?eh,tc_done,{S,{init_per_group,g,[]},ok}}, + {?eh,tc_start,{S,tc1}}, + {?eh,tc_done,{S,tc1,ok}}, + {?eh,test_stats,{3,0,{0,0}}}, + {?eh,tc_start,{S,tc2}}, + {?eh,tc_done,{S,tc2,ok}}, + {?eh,test_stats,{4,0,{0,0}}}, + {?eh,tc_start,{S,{end_per_group,g,[]}}}, + {?eh,tc_done,{S,{end_per_group,g,[]},ok}}], + {?eh,tc_start,{S,end_per_suite}}, + {?eh,tc_done,{S,end_per_suite,ok}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]. + +%% test events help functions +contains(List) -> + fun(Proplist) when is_list(Proplist) -> + contains(List,Proplist) + end. + +contains([{not_in_order,List}|T],Rest) -> + contains_parallel(List,Rest), + contains(T,Rest); +contains([{Ele,Pos}|T] = L,[H|T2]) -> + case element(Pos,H) of + Ele -> + contains(T,T2); + _ -> + contains(L,T2) + end; +contains([Ele|T],[{Ele,_}|T2])-> + contains(T,T2); +contains([Ele|T],[Ele|T2])-> + contains(T,T2); +contains(List,[_|T]) -> + contains(List,T); +contains([],_) -> + match. + +contains_parallel([Key | T], Elems) -> + contains([Key],Elems), + contains_parallel(T,Elems); +contains_parallel([],_Elems) -> + match. + +not_contains(List) -> + fun(Proplist) when is_list(Proplist) -> + [] = [Ele || {Ele,_} <- Proplist, + Test <- List, + Test =:= Ele] + end. diff --git a/lib/common_test/test/ct_util_SUITE_data/ct_util_cth.erl b/lib/common_test/test/ct_util_SUITE_data/ct_util_cth.erl new file mode 100644 index 0000000000..34c1568a87 --- /dev/null +++ b/lib/common_test/test/ct_util_SUITE_data/ct_util_cth.erl @@ -0,0 +1,105 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2017. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + + +-module(ct_util_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +%% Send a cth_error event if a callback is called with unexpected arguments + +%% CT Hooks +-compile(export_all). + +id(Opts) -> + erlang:system_time(second). + +init(Id, Opts) -> + {ok,ok}. + +pre_init_per_suite(Suite,Config,State) -> + maybe_sleep(?FUNCTION_NAME,Suite), + {Config, State}. + +post_init_per_suite(Suite,Config,Return,State) -> + maybe_sleep(?FUNCTION_NAME,Suite), + {Return, State}. + +pre_end_per_suite(Suite,Config,State) -> + maybe_sleep(?FUNCTION_NAME,Suite), + {Config, State}. + +post_end_per_suite(Suite,Config,Return,State) -> + maybe_sleep(?FUNCTION_NAME,Suite), + {Return, State}. + +pre_init_per_group(Suite, Group, Config, State) -> + maybe_sleep(?FUNCTION_NAME,Suite,Group), + {Config,State}. + +post_init_per_group(Suite, Group, Config,Return,State) -> + maybe_sleep(?FUNCTION_NAME,Suite,Group), + {Return,State}. + +pre_end_per_group(Suite, Group, Config, State) -> + maybe_sleep(?FUNCTION_NAME,Suite,Group), + {Config,State}. + +post_end_per_group(Suite, Group, Config,Return,State) -> + maybe_sleep(?FUNCTION_NAME,Suite,Group), + {Return,State}. + +pre_init_per_testcase(Suite, TC, Config, State) -> + maybe_sleep(?FUNCTION_NAME,Suite,TC), + {Config,State}. + +post_init_per_testcase(Suite, TC, Config,Return,State) -> + maybe_sleep(?FUNCTION_NAME,Suite,TC), + {Return,State}. + +pre_end_per_testcase(Suite, TC, Config, State) -> + maybe_sleep(?FUNCTION_NAME,Suite,TC), + {Config,State}. + +post_end_per_testcase(Suite, TC, Config,Return,State) -> + maybe_sleep(?FUNCTION_NAME,Suite,TC), + {Return,State}. + +%%%----------------------------------------------------------------- +maybe_sleep(FuncName,Suite) -> + maybe_sleep(FuncName,Suite,undefined). +maybe_sleep(FuncName,Suite,GroupOrTC) -> + case ct:get_config(FuncName) of + {Suite,GroupOrTC,Fail} -> + fail(Fail); + {Suite,Fail} when GroupOrTC=:=undefined -> + fail(Fail); + _ -> + ok + end. + +fail({timeout,T}) -> + timer:sleep(T); +fail(kill) -> + spawn_link(fun() -> ct:fail(hahahahahah) end), + timer:sleep(10000). + diff --git a/lib/common_test/test/ct_util_SUITE_data/curr_tc_SUITE.erl b/lib/common_test/test/ct_util_SUITE_data/curr_tc_SUITE.erl new file mode 100644 index 0000000000..b48ba4d24e --- /dev/null +++ b/lib/common_test/test/ct_util_SUITE_data/curr_tc_SUITE.erl @@ -0,0 +1,59 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2017. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(curr_tc_SUITE). + +-suite_defaults([{timetrap, {seconds, 3}}]). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include("ct.hrl"). + +init_per_suite(Config) -> + [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc), + Config. + +end_per_suite(Config) -> + [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc), + ok. + +init_per_group(_Group,Config) -> + [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc), + Config. + +end_per_group(_Group,Config) -> + [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc), + ok. + +all() -> + [tc1,tc2,{group,g}]. + +groups() -> + [{g,[tc1,tc2]}]. + +%% Test cases starts here. +tc1(_Config) -> + [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc), + ok. + +tc2(_Config) -> + [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc), + ok. diff --git a/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl b/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl index 03a0832e53..d1c293b4af 100644 --- a/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl +++ b/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.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,14 +18,14 @@ %% %CopyrightEnd% %% -%%% @doc Common Test Framework Event Handler +%%% 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(simple_evh). -behaviour(gen_event). diff --git a/lib/common_test/test/erl2html2_SUITE.erl b/lib/common_test/test/erl2html2_SUITE.erl index 53a63578b2..b2336ff0bc 100644 --- a/lib/common_test/test/erl2html2_SUITE.erl +++ b/lib/common_test/test/erl2html2_SUITE.erl @@ -214,10 +214,10 @@ check_line_number(Last,Line,OrigLine) -> [$>|Rest] = lists:dropwhile(fun($>) -> false; (_) -> true end,Line), check_line_number(Last,Rest,OrigLine); _ -> - [N |_] = string:tokens(Line,":"), + [N |_] = string:lexemes(Line,":"), % erlang:display(N), Num = - try list_to_integer(string:strip(N)) + try list_to_integer(string:trim(N,both,"\s")) catch _:_ -> ct:fail({no_line_number_after,Last,OrigLine}) end, if Num == Last+1 -> diff --git a/lib/common_test/test/telnet_server.erl b/lib/common_test/test/telnet_server.erl index 65300b0bdf..cef7784333 100644 --- a/lib/common_test/test/telnet_server.erl +++ b/lib/common_test/test/telnet_server.erl @@ -249,7 +249,7 @@ do_handle_data("echo " ++ Data,State) -> send(Data++"\r\n> ",State), {ok,State}; do_handle_data("echo_sep " ++ Data,State) -> - Msgs = string:tokens(Data," "), + Msgs = string:lexemes(Data," "), lists:foreach(fun(Msg) -> send(Msg,State), timer:sleep(10) @@ -260,28 +260,28 @@ do_handle_data("echo_no_prompt " ++ Data,State) -> send(Data,State), {ok,State}; do_handle_data("echo_ml " ++ Data,State) -> - Lines = string:tokens(Data," "), - ReturnData = string:join(Lines,"\n"), + Lines = string:lexemes(Data," "), + ReturnData = lists:flatten(lists:join("\n",Lines)), send(ReturnData++"\r\n> ",State), {ok,State}; do_handle_data("echo_ml_no_prompt " ++ Data,State) -> - Lines = string:tokens(Data," "), - ReturnData = string:join(Lines,"\n"), + Lines = string:lexemes(Data," "), + ReturnData = lists:flatten(lists:join("\n",Lines)), send(ReturnData,State), {ok,State}; do_handle_data("echo_loop " ++ Data,State) -> - [TStr|Lines] = string:tokens(Data," "), - ReturnData = string:join(Lines,"\n"), + [TStr|Lines] = string:lexemes(Data," "), + ReturnData = lists:flatten(lists:join("\n",Lines)), send_loop(list_to_integer(TStr),ReturnData,State), {ok,State}; do_handle_data("echo_delayed_prompt "++Data,State) -> - [MsStr|EchoData] = string:tokens(Data, " "), - send(string:join(EchoData,"\n"),State), + [MsStr|EchoData] = string:lexemes(Data, " "), + send(lists:flatten(lists:join("\n",EchoData)),State), timer:sleep(list_to_integer(MsStr)), send("\r\n> ",State), {ok,State}; do_handle_data("disconnect_after " ++WaitStr,State) -> - Wait = list_to_integer(string:strip(WaitStr,right,$\n)), + Wait = list_to_integer(string:trim(WaitStr,trailing,"\n")), dbg("Server will close connection in ~w ms...", [Wait]), erlang:send_after(Wait,self(),disconnect), {ok,State}; diff --git a/lib/common_test/test/test_server_SUITE.erl b/lib/common_test/test/test_server_SUITE.erl index 50d8bdd1ac..05737cfac9 100644 --- a/lib/common_test/test/test_server_SUITE.erl +++ b/lib/common_test/test/test_server_SUITE.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. @@ -18,12 +18,7 @@ %% %CopyrightEnd% %% %%%------------------------------------------------------------------- -%%% @author Lukas Larsson <[email protected]> -%%% @copyright (C) 2011, Erlang Solutions Ltd. -%%% @doc -%%% -%%% @end -%%% Created : 15 Feb 2011 by Lukas Larsson <[email protected]> +%%% Author: Lukas Larsson <[email protected]> %%%------------------------------------------------------------------- -module(test_server_SUITE). @@ -71,7 +66,7 @@ init_per_testcase(_TestCase, Config) -> %% @spec end_per_testcase(TestCase, Config0) -> %% void() | {save_config,Config1} | {fail,Reason} end_per_testcase(test_server_unicode, _Config) -> - [_,Host] = string:tokens(atom_to_list(node()), "@"), + [_,Host] = string:lexemes(atom_to_list(node()), "@"), N1 = list_to_atom("test_server_tester_latin1" ++ "@" ++ Host), N2 = list_to_atom("test_server_tester_utf8" ++ "@" ++ Host), test_server:stop_node(N1), @@ -347,7 +342,7 @@ generate_and_run_unicode_test(Config0,Encoding) -> RunDir = get_latest_run_dir(LogDir), true = filelib:is_dir(RunDir), - LowerModStr = string:to_lower(ModStr), + LowerModStr = string:lowercase(ModStr), SuiteHtml = translate_filename(LowerModStr++".src.html",Encoding), true = filelib:is_regular(filename:join(RunDir,SuiteHtml)), @@ -362,7 +357,7 @@ generate_and_run_unicode_test(Config0,Encoding) -> %% remote file system on master - i.e. they will use same file name %% mode as the master. start_node(Config,Name,Args) -> - [_,Host] = string:tokens(atom_to_list(node()), "@"), + [_,Host] = string:lexemes(atom_to_list(node()), "@"), ct:log("Trying to start ~w@~s~n",[Name,Host]), case test_server:start_node(Name, peer, [{args,Args}]) of {error,Reason} -> diff --git a/lib/common_test/test/test_server_test_lib.erl b/lib/common_test/test/test_server_test_lib.erl index c18b89b178..9ee946af0b 100644 --- a/lib/common_test/test/test_server_test_lib.erl +++ b/lib/common_test/test/test_server_test_lib.erl @@ -43,7 +43,7 @@ pre_init_per_testcase(_TC,Config,State) -> {start_slave(Config, 50),State}. start_slave(Config,_Level) -> - [_,Host] = string:tokens(atom_to_list(node()), "@"), + [_,Host] = string:lexemes(atom_to_list(node()), "@"), ct:log("Trying to start ~s~n", ["test_server_tester@"++Host]), @@ -121,7 +121,7 @@ parse_suite(FileName) -> end. fline(Fd) -> - case prim_file:read_line(Fd) of + case file:read_line(Fd) of eof -> eof; {ok, Line} -> Line end. diff --git a/lib/common_test/test_server/configure.in b/lib/common_test/test_server/configure.in index 0511d126b4..e07bd4c2aa 100644 --- a/lib/common_test/test_server/configure.in +++ b/lib/common_test/test_server/configure.in @@ -459,11 +459,11 @@ dnl Freely inspired by AC_TRY_LINK. (Maybe better to create a dnl AC_LANG_JAVA instead...) AC_DEFUN(ERL_TRY_LINK_JAVA, [java_link='$JAVAC conftest.java 1>&AC_FD_CC' -changequote(�, �)dnl +changequote(, )dnl cat > conftest.java <<EOF -�$1� +$1 class conftest { public static void main(String[] args) { - �$2� + $2 ; return; }} EOF changequote([, ])dnl diff --git a/lib/common_test/test_server/ts.erl b/lib/common_test/test_server/ts.erl index 5bfea9f4de..179380a562 100644 --- a/lib/common_test/test_server/ts.erl +++ b/lib/common_test/test_server/ts.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-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. @@ -583,7 +583,7 @@ is_list_of_suites(List) -> S = if is_atom(Suite) -> atom_to_list(Suite); true -> Suite end, - try lists:last(string:tokens(S,"_")) of + try lists:last(string:lexemes(S,"_")) of "SUITE" -> true; "suite" -> true; _ -> false diff --git a/lib/common_test/test_server/ts_autoconf_win32.erl b/lib/common_test/test_server/ts_autoconf_win32.erl index 52e5ac8e69..1179dfe0e5 100644 --- a/lib/common_test/test_server/ts_autoconf_win32.erl +++ b/lib/common_test/test_server/ts_autoconf_win32.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-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. @@ -228,7 +228,7 @@ make(Vars) -> end. find_make(MakeCmd, Vars) -> - [Make|_] = string:tokens(MakeCmd, " \t"), + [Make|_] = string:lexemes(MakeCmd, " \t"), case os:find_executable(Make) of false -> {no, Vars}; @@ -248,9 +248,9 @@ javac(Vars) -> end. is_debug_build() -> - case catch string:str(erlang:system_info(system_version), "debug") of - Int when is_integer(Int), Int > 0 -> - true; - _ -> - false + case catch string:find(erlang:system_info(system_version), "debug") of + nomatch -> + false; + _Else -> + true end. diff --git a/lib/common_test/test_server/ts_erl_config.erl b/lib/common_test/test_server/ts_erl_config.erl index 032593bdda..f3972bea4e 100644 --- a/lib/common_test/test_server/ts_erl_config.erl +++ b/lib/common_test/test_server/ts_erl_config.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-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. @@ -208,7 +208,11 @@ erl_interface(Vars,OsType) -> {filename:join(Dir, "lib"), filename:join([Dir, "src", "eidefs.mk"])}; {srctree, _Root, Target} -> - {filename:join([Dir, "obj", Target]), + Obj = case is_debug_build() of + true -> "obj.debug"; + false -> "obj" + end, + {filename:join([Dir, Obj, Target]), filename:join([Dir, "src", Target, "eidefs.mk"])} end} end, @@ -311,7 +315,7 @@ lib_dir(Vars, Lib) -> end, CLibDir = filename:join(CLibDirList), Cmd = "ls -d " ++ CLibDir ++ "*", - XLibDir = lists:last(string:tokens(os:cmd(Cmd),"\n")), + XLibDir = lists:last(string:lexemes(os:cmd(Cmd),"\n")), case file:list_dir(XLibDir) of {error, enoent} -> []; @@ -358,18 +362,22 @@ link_library(_LibName,_Other) -> %% Returns emulator specific variables. emu_vars(Vars) -> [{is_source_build, is_source_build()}, - {erl_name, atom_to_list(lib:progname())}|Vars]. + {erl_name, get_progname()}|Vars]. + +get_progname() -> + case init:get_argument(progname) of + {ok, [[Prog]]} -> + Prog; + _Other -> + "no_prog_name" + end. is_source_build() -> - string:str(erlang:system_info(system_version), "[source]") > 0. + string:find(erlang:system_info(system_version), "source") =/= nomatch. is_debug_build() -> - case catch string:str(erlang:system_info(system_version), "debug") of - Int when is_integer(Int), Int > 0 -> - true; - _ -> - false - end. + string:find(erlang:system_info(system_version), "debug") =/= nomatch. + %% %% ssl_libdir %% diff --git a/lib/common_test/test_server/ts_install.erl b/lib/common_test/test_server/ts_install.erl index c4e0223ac7..048e5493d2 100644 --- a/lib/common_test/test_server/ts_install.erl +++ b/lib/common_test/test_server/ts_install.erl @@ -115,7 +115,7 @@ get_vars(_, _, _, _) -> config_flags() -> case os:getenv("CONFIG_FLAGS") of false -> []; - CF -> string:tokens(CF, " \t\n") + CF -> string:lexemes(CF, " \t\n") end. unix_autoconf(XConf) -> @@ -127,7 +127,7 @@ unix_autoconf(XConf) -> Threads = [" --enable-shlib-thread-safety" || erlang:system_info(threads) /= false], Debug = [" --enable-debug-mode" || - string:str(erlang:system_info(system_version),"debug") > 0], + string:find(erlang:system_info(system_version),"debug") =/= nomatch], MXX_Build = [Y || Y <- config_flags(), Y == "--enable-m64-build" orelse Y == "--enable-m32-build"], @@ -159,10 +159,8 @@ assign_vars([]) -> assign_vars([{VAR,FlagsStr} | VARs]) -> [{VAR,assign_vars(FlagsStr)} | assign_vars(VARs)]; assign_vars(FlagsStr) -> - Flags = [assign_all_vars(Str,[]) || Str <- string:tokens(FlagsStr, [$ ])], - string:strip(lists:flatten(lists:map(fun(Flag) -> - Flag ++ " " - end, Flags)), right). + Flags = [assign_all_vars(Str,[]) || Str <- string:lexemes(FlagsStr, [$\s])], + lists:flatten(lists:join(" ", Flags)). assign_all_vars([$$ | Rest], FlagSoFar) -> {VarName,Rest1} = get_var_name(Rest, []), @@ -292,7 +290,7 @@ add_vars(Vars0, Opts0) -> get_testcase_callback() -> case os:getenv("TS_TESTCASE_CALLBACK") of ModFunc when is_list(ModFunc), ModFunc /= "" -> - case string:tokens(ModFunc, " ") of + case string:lexemes(ModFunc, " ") of [_Mod,_Func] -> ModFunc; _ -> "" end; @@ -408,17 +406,13 @@ off_heap_msgq() -> end. schedulers() -> - case catch erlang:system_info(smp_support) of - true -> - case {erlang:system_info(schedulers), - erlang:system_info(schedulers_online)} of - {S,S} -> - "/S"++integer_to_list(S); - {S,O} -> - "/S"++integer_to_list(S) ++ ":" ++ - integer_to_list(O) - end; - _ -> "" + case {erlang:system_info(schedulers), + erlang:system_info(schedulers_online)} of + {S,S} -> + "/S"++integer_to_list(S); + {S,O} -> + "/S"++integer_to_list(S) ++ ":" ++ + integer_to_list(O) end. bind_type() -> @@ -434,8 +428,8 @@ bind_type() -> debug() -> - case string:str(erlang:system_info(system_version), "debug") of - 0 -> ""; + case string:find(erlang:system_info(system_version), "debug") of + nomatch -> ""; _ -> "/Debug" end. diff --git a/lib/common_test/test_server/ts_install_cth.erl b/lib/common_test/test_server/ts_install_cth.erl index 5d325b1115..b6503fb864 100644 --- a/lib/common_test/test_server/ts_install_cth.erl +++ b/lib/common_test/test_server/ts_install_cth.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. @@ -18,7 +18,7 @@ %% %CopyrightEnd% %% -%%% @doc TS Installed SCB +%%% TS Installed SCB %%% %%% This module does what the make parts of the ts:run/x command did, %%% but not the Makefile.first parts! So they have to be done by ts or @@ -60,13 +60,13 @@ -record(state, { ts_conf_dir, target_system, install_opts, nodenames, nodes }). -%% @doc The id of this SCB +%% The id of this SCB -spec id(Opts :: term()) -> Id :: term(). id(_Opts) -> ?MODULE. -%% @doc Always called before any other callback function. +%% Always called before any other callback function. -spec init(Id :: term(), Opts :: proplists:proplist()) -> {ok, State :: #state{}}. init(_Id, Opts) -> @@ -81,7 +81,7 @@ init(_Id, Opts) -> target_system = TargetSystem, install_opts = InstallOpts } }. -%% @doc Called before init_per_suite is called. +%% Called before init_per_suite is called. -spec pre_init_per_suite(Suite :: atom(), Config :: config(), State :: #state{}) -> @@ -108,13 +108,12 @@ pre_init_per_suite(_Suite,Config,State) -> {add_node_name(Config, State), State} catch error:{badmatch,{error,enoent}} -> {add_node_name(Config, State), State}; - Error:Reason -> - Stack = erlang:get_stacktrace(), + Error:Reason:Stack -> ct:pal("~p failed! ~p:{~p,~p}",[?MODULE,Error,Reason,Stack]), {{fail,{?MODULE,{Error,Reason, Stack}}},State} end. -%% @doc Called after init_per_suite. +%% Called after init_per_suite. -spec post_init_per_suite(Suite :: atom(), Config :: config(), Return :: config() | skip_or_fail(), @@ -124,7 +123,7 @@ post_init_per_suite(_Suite,_Config,Return,State) -> test_server_ctrl:kill_slavenodes(), {Return, State}. -%% @doc Called before end_per_suite. +%% Called before end_per_suite. -spec pre_end_per_suite(Suite :: atom(), Config :: config() | skip_or_fail(), State :: #state{}) -> @@ -132,7 +131,7 @@ post_init_per_suite(_Suite,_Config,Return,State) -> pre_end_per_suite(_Suite,Config,State) -> {Config, State}. -%% @doc Called after end_per_suite. +%% Called after end_per_suite. -spec post_end_per_suite(Suite :: atom(), Config :: config(), Return :: term(), @@ -141,7 +140,7 @@ pre_end_per_suite(_Suite,Config,State) -> post_end_per_suite(_Suite,_Config,Return,State) -> {Return, State}. -%% @doc Called before each init_per_group. +%% Called before each init_per_group. -spec pre_init_per_group(Group :: atom(), Config :: config(), State :: #state{}) -> @@ -149,7 +148,7 @@ post_end_per_suite(_Suite,_Config,Return,State) -> pre_init_per_group(_Group,Config,State) -> {add_node_name(Config, State), State}. -%% @doc Called after each init_per_group. +%% Called after each init_per_group. -spec post_init_per_group(Group :: atom(), Config :: config(), Return :: config() | skip_or_fail(), @@ -158,7 +157,7 @@ pre_init_per_group(_Group,Config,State) -> post_init_per_group(_Group,_Config,Return,State) -> {Return, State}. -%% @doc Called after each end_per_group. +%% Called after each end_per_group. -spec pre_end_per_group(Group :: atom(), Config :: config() | skip_or_fail(), State :: #state{}) -> @@ -166,7 +165,7 @@ post_init_per_group(_Group,_Config,Return,State) -> pre_end_per_group(_Group,Config,State) -> {Config, State}. -%% @doc Called after each end_per_group. +%% Called after each end_per_group. -spec post_end_per_group(Group :: atom(), Config :: config(), Return :: term(), @@ -175,7 +174,7 @@ pre_end_per_group(_Group,Config,State) -> post_end_per_group(_Group,_Config,Return,State) -> {Return, State}. -%% @doc Called before each test case. +%% Called before each test case. -spec pre_init_per_testcase(TC :: atom(), Config :: config(), State :: #state{}) -> @@ -191,7 +190,7 @@ pre_init_per_testcase(_TC,Config,State) -> post_init_per_testcase(_TC,_Config,Return,State) -> {Return, State}. -%% @doc Called after each test case. +%% Called after each test case. -spec pre_end_per_testcase(TC :: atom(), Config :: config(), State :: #state{}) -> @@ -207,7 +206,7 @@ pre_end_per_testcase(_TC,Config,State) -> post_end_per_testcase(_TC,_Config,Return,State) -> {Return, State}. -%% @doc Called after a test case failed. +%% Called after a test case failed. -spec on_tc_fail(TC :: init_per_suite | end_per_suite | init_per_group | end_per_group | atom(), Reason :: term(), State :: #state{}) -> @@ -215,7 +214,7 @@ post_end_per_testcase(_TC,_Config,Return,State) -> on_tc_fail(_TC, _Reason, State) -> State. -%% @doc Called when a test case is skipped. +%% Called when a test case is skipped. -spec on_tc_skip(TC :: end_per_suite | init_per_group | end_per_group | atom(), {tc_auto_skip, {failed, {Mod :: atom(), Function :: atom(), Reason :: term()}}} | @@ -225,7 +224,7 @@ on_tc_fail(_TC, _Reason, State) -> on_tc_skip(_TC, _Reason, State) -> State. -%% @doc Called when the scope of the SCB is done. +%% Called when the scope of the SCB is done. -spec terminate(State :: #state{}) -> term(). terminate(_State) -> diff --git a/lib/common_test/test_server/ts_lib.erl b/lib/common_test/test_server/ts_lib.erl index ea039a2c2b..7c1c14f467 100644 --- a/lib/common_test/test_server/ts_lib.erl +++ b/lib/common_test/test_server/ts_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-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. @@ -99,7 +99,7 @@ specialized_specs(Dir,PostFix) -> sort_tests([begin DirPart = filename:dirname(Name), AppTest = hd(lists:reverse(filename:split(DirPart))), - list_to_atom(string:substr(AppTest, 1, length(AppTest)-5)) + list_to_atom(string:slice(AppTest, 0, string:length(AppTest)-5)) end || Name <- Specs]). specs(Dir) -> @@ -111,9 +111,9 @@ specs(Dir) -> [Spec,TestDir|_] = lists:reverse(filename:split(FullName)), [_TestSuffix|TDParts] = - lists:reverse(string:tokens(TestDir,[$_,$.])), + lists:reverse(string:lexemes(TestDir,[$_,$.])), [_SpecSuffix|SParts] = - lists:reverse(string:tokens(Spec,[$_,$.])), + lists:reverse(string:lexemes(Spec,[$_,$.])), if TDParts == SParts -> [filename_to_atom(FullName)]; true -> @@ -273,7 +273,7 @@ do_test(Rest, Vars, Test) -> get_arg([$(|Rest], Vars, Stop, _) -> get_arg(Rest, Vars, Stop, []); get_arg([Stop|Rest], Vars, Stop, Acc) -> - Arg = string:strip(lists:reverse(Acc)), + Arg = string:trim(lists:reverse(Acc),both,[$\s]), Subst = subst(Arg, Vars), {Subst,Rest}; get_arg([C|Rest], Vars, Stop, Acc) -> diff --git a/lib/common_test/test_server/ts_run.erl b/lib/common_test/test_server/ts_run.erl index e22fa8d196..7e12b9652c 100644 --- a/lib/common_test/test_server/ts_run.erl +++ b/lib/common_test/test_server/ts_run.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-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. @@ -199,7 +199,7 @@ make_command(Vars, Spec, State) -> TestPath = filename:nativename(TestDir), Erl = case os:getenv("TS_RUN_VALGRIND") of false -> - atom_to_list(lib:progname()); + ct:get_progname(); _ -> case State#state.file of Dir when is_list(Dir) -> @@ -207,11 +207,7 @@ make_command(Vars, Spec, State) -> _ -> ok end, - "cerl -valgrind" ++ - case erlang:system_info(smp_support) of - true -> " -smp"; - false -> "" - end + "cerl -valgrind" end, Naming = case ts_lib:var(longnames, Vars) of @@ -415,9 +411,9 @@ make_common_test_args(Args0, Options0, _Vars) -> end, ConfigFiles = [{config,[filename:join(ConfigPath,File) || File <- get_config_files()]}], - io_lib:format("~100000p",[[{abort_if_missing_suites,true} | - Args0++Trace++Cover++Logdir++ - ConfigFiles++Options++TimeTrap]]). + io_lib:format("~0p",[[{abort_if_missing_suites,true} | + Args0++Trace++Cover++Logdir++ + ConfigFiles++Options++TimeTrap]]). to_list(X) when is_atom(X) -> atom_to_list(X); @@ -468,4 +464,4 @@ split_one(Path) -> filename:split(Path). split_path(Path) -> - string:tokens(Path,";"). + string:lexemes(Path,";"). diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk index c8dfa6beb2..14a3622a00 100644 --- a/lib/common_test/vsn.mk +++ b/lib/common_test/vsn.mk @@ -1 +1 @@ -COMMON_TEST_VSN = 1.15.4.1 +COMMON_TEST_VSN = 1.17.1 |