diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile index cd5f2e2de01e..a5f2f0975e6d 100644 --- a/lib/common_test/doc/src/Makefile +++ b/lib/common_test/doc/src/Makefile @@ -50,7 +50,8 @@ XML_REF3_FILES = ct.xml \ ct_property_test.xml \ ct_netconfc.xml \ ct_hooks.xml \ - ct_testspec.xml + ct_testspec.xml \ + ct_suite.xml XML_REF6_FILES = common_test_app.xml XML_PART_FILES = part.xml @@ -86,7 +87,7 @@ XML_FILES=$(XML_APPLICATION_FILES) $(XML_REF1_FILES) $(XML_REF3_FILES) $(XML_RE TOP_SPECS_FILE = specs.xml -NO_CHUNKS = ct_hooks.xml +NO_CHUNKS = ct_hooks.xml ct_suite.xml # ---------------------------------------------------- diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml index 3fcbda538aa7..07a2a3e2cdc2 100644 --- a/lib/common_test/doc/src/common_test_app.xml +++ b/lib/common_test/doc/src/common_test_app.xml @@ -52,564 +52,7 @@ Step-by-step execution of test cases -

The following section describes the mandatory and optional test suite - functions that Common Test calls during test execution. - For more details, see section - Writing Test Suites - in the User's Guide.

- - - - - - Test Case Callback Functions -

The following functions define the callback interface - for a test suite.

-
- - Module:all() -> Tests | {skip,Reason} - Returns the list of all test case groups and test cases - in the module. - - Tests = [TestCase | {testcase,TestCase,TCRepeatProps} | {group,GroupName} | {group,GroupName,Properties} | {group,GroupName,Properties,SubGroups}] - TestCase = atom() - TCRepeatProps = [{repeat,N} | {repeat_until_ok,N} | {repeat_until_fail,N}] - GroupName = atom() - Properties = [parallel | sequence | Shuffle | {GroupRepeatType,N}] | default - SubGroups = [{GroupName,Properties} | {GroupName,Properties,SubGroups}] - Shuffle = shuffle | {shuffle,Seed} - Seed = {integer(),integer(),integer()} - GroupRepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail - N = integer() | forever - Reason = term() - - - -

MANDATORY

- -

Returns the list of all test cases and test case groups in the - test suite module to be executed. This list also specifies the - order the cases and groups are executed by Common Test. - A test case is represented by an atom, - the name of the test case function, or a testcase tuple - indicating that the test case shall be repeated. A test case group is - represented by a group tuple, where GroupName, - an atom, is the name of the group (defined in - groups/0). - Execution properties for groups can also be specified, both - for a top-level group and for any of its subgroups. - Group execution properties specified here override - properties in the group definition (see - groups/0). - (With value default, the group definition properties - are used).

- -

If {skip,Reason} is returned, all test cases - in the module are skipped and Reason - is printed on the HTML result page.

- -

For details on groups, see section - Test Case - Groups in the User's Guide.

- -
-
- - - Module:groups() -> GroupDefs - Returns a list of test case group definitions. - - GroupDefs = [Group] - Group = {GroupName,Properties,GroupsAndTestCases} - GroupName = atom() - Properties = [parallel | sequence | Shuffle | {GroupRepeatType,N}] - GroupsAndTestCases = [Group | {group,GroupName} | TestCase | {testcase,TestCase,TCRepeatProps}] - TestCase = atom() - TCRepeatProps = [{repeat,N} | {repeat_until_ok,N} | {repeat_until_fail,N}] - Shuffle = shuffle | {shuffle,Seed} - Seed = {integer(),integer(),integer()} - GroupRepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail - N = integer() | forever - - - -

OPTIONAL

- -

Defines test case groups. For details, see section - Test Case - Groups in the User's Guide.

-
-
- - - Module:suite() -> [Info] - Test suite info function (providing default data - for the suite). - - Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns} | {stylesheet,CSSFile} | {ct_hooks, CTHs} - Time = TimeVal | TimeFunc - TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | {hours,integer()} - TimeFunc = {Mod,Func,Args} | Fun - MilliSec = integer() - Mod = atom() - Func = atom() - Args = list() - Fun = fun() - Required = Key | {Key,SubKeys} | {Key,SubKey} | {Key,SubKey,SubKeys} - Key = atom() - SubKeys = SubKey | [SubKey] - SubKey = atom() - Name = atom() - UserData = term() - Conns = [atom()] - CSSFile = string() - CTHs = [CTHModule | -         {CTHModule, CTHInitArgs} | -         {CTHModule, CTHInitArgs, CTHPriority}] - CTHModule = atom() - CTHInitArgs = term() - - - -

OPTIONAL

- -

The test suite information function. Returns a list of tagged - tuples specifying various properties related to the execution of - this test suite (common for all test cases in the suite).

- -

Tag timetrap sets the maximum time that each - test case is allowed to execute (including - init_per_testcase/2 - and - end_per_testcase/2). - If the timetrap time is exceeded, the test case fails with reason - timetrap_timeout. A TimeFunc function can be used to - set a new timetrap by returning a TimeVal. It can also be - used to trigger a timetrap time-out by, at some point, returning a - value other than a TimeVal. For details, see section - Timetrap Time-Outs - in the User's Guide.

- -

Tag require specifies configuration variables - required by test cases (or configuration functions) - in the suite. If the required configuration variables are not found - in any of the configuration files, all test cases are skipped. - For details about the require functionality, see funtion - ct:require/1,2.

- -

With userdata, the user can - specify any test suite-related information, which can be - read by calling - ct:userdata/2.

- -

Tag ct_hooks specifies the - Common Test Hooks - to be run with this suite.

- -

Other tuples than the ones defined are ignored.

- -

For details about the test suite information function, see section - Test - Suite Information Function in the User's Guide.

-
-
- - - Module:init_per_suite(Config) -> NewConfig | {skip,Reason} | - {skip_and_save,Reason,SaveConfig} - Test suite initializations. - - Config = NewConfig = SaveConfig = [{Key,Value}] - Key = atom() - Value = term() - Reason = term() - - - -

OPTIONAL; if this function is defined, then end_per_suite/1 - must also be defined.

- -

This configuration function is called as the first function in the - suite. It typically contains initializations that are common for - all test cases in the suite, and that must only be done - once. Parameter Config is the configuration data - that can be modified. Whatever is returned from this - function is specified as Config to all configuration functions - and test cases in the suite.

- -

If {skip,Reason} - is returned, all test cases in the suite are skipped - and Reason is printed in the overview log for the suite.

- -

For information on save_config and skip_and_save, - see section - Saving - Configuration Data in the User's Guide.

-
-
- - - Module:end_per_suite(Config) -> term() | - {save_config,SaveConfig} - Test suite finalization. - - Config = SaveConfig = [{Key,Value}] - Key = atom() - Value = term() - - - -

OPTIONAL; if this function is defined, then init_per_suite/1 - must also be defined.

- -

This function is called as the last test case in the - suite. It is meant to be used for cleaning up after - init_per_suite/1.

-

For information on save_config, see section - Saving - Configuration Data in the User's Guide.

-
-
- - - Module:group(GroupName) -> [Info] - Test case group information function (providing default data - for a test case group, that is, its test cases and - subgroups). - - Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns} | {stylesheet,CSSFile} | {ct_hooks, CTHs} - Time = TimeVal | TimeFunc - TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | {hours,integer()} - TimeFunc = {Mod,Func,Args} | Fun - MilliSec = integer() - Mod = atom() - Func = atom() - Args = list() - Fun = fun() - Required = Key | {Key,SubKeys} | {Key,Subkey} | {Key,Subkey,SubKeys} - Key = atom() - SubKeys = SubKey | [SubKey] - SubKey = atom() - Name = atom() - UserData = term() - Conns = [atom()] - CSSFile = string() - CTHs = [CTHModule | -         {CTHModule, CTHInitArgs} | -         {CTHModule, CTHInitArgs, CTHPriority}] - CTHModule = atom() - CTHInitArgs = term() - - - -

OPTIONAL

- -

The test case group information function. It is supposed to - return a list of tagged tuples that specify various properties - related to the execution of a test case group (that is, its test - cases and subgroups). Properties set by - group/1 override - properties with the same key that have been set previously by - suite/0.

- -

Tag timetrap sets the maximum time that each - test case is allowed to execute (including - init_per_testcase/2 - and - end_per_testcase/2). - If the timetrap time is - exceeded, the test case fails with reason - timetrap_timeout. A TimeFunc function can be used to - set a new timetrap by returning a TimeVal. It can also be - used to trigger a timetrap time-out by, at some point, returning a - value other than a TimeVal. For details, see section - Timetrap - Time-Outs in the User's Guide.

- -

Tag require specifies configuration variables - required by test cases (or configuration functions) - in the suite. If the required configuration variables are not found - in any of the configuration files, all test cases in this group are - skipped. For details about the require functionality, see - function - ct:require/1,2.

- -

With userdata, the user can - specify any test case group related information that can be - read by calling - ct:userdata/2.

- -

Tag ct_hooks specifies the - Common Test Hooks - to be run with this suite.

- -

Other tuples than the ones defined are ignored.

- -

For details about the test case group information function, - see section Group - Information Function in the User's Guide.

-
-
- - - Module:init_per_group(GroupName, Config) -> NewConfig | - {skip,Reason} - Test case group initializations. - - GroupName = atom() - Config = NewConfig = [{Key,Value}] - Key = atom() - Value = term() - Reason = term() - - - -

OPTIONAL; if this function is defined, then end_per_group/2 - must also be defined.

- -

This configuration function is called before execution of a - test case group. It typically contains initializations that are - common for all test cases and subgroups in the group, and that - must only be performed once. GroupName is the name of the - group, as specified in the group definition (see - groups/0). - Parameter Config is the configuration data that can be - modified. - The return value of this function is given as Config - to all test cases and subgroups in the group.

- -

If {skip,Reason} - is returned, all test cases in the group are skipped and - Reason is printed in the overview log for the group.

- -

For information about test case groups, see section - Test Case - Groups in the User's Guide.

-
-
- - - Module:end_per_group(GroupName, Config) -> term() | - {return_group_result,Status} - Test case group finalization. - - GroupName = atom() - Config = [{Key,Value}] - Key = atom() - Value = term() - Status = ok | skipped | failed - - - -

OPTIONAL; if this function is defined, then init_per_group/2 - must also be defined.

- -

This function is called after the execution of a test case group - is finished. It is meant to be used for cleaning up after - init_per_group/2. - A status value for a nested subgroup can be returned with - {return_group_result,Status}. The status can be retrieved in - end_per_group/2 - for the group on the level above. The status is also used by - Common Test for deciding if execution of a group is to - proceed if property sequence or repeat_until_* - is set.

- -

For details about test case groups, see section - Test Case - Groups in the User's Guide.

-
-
- - - Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason} - Test case initializations. - - TestCase = atom() - Config = NewConfig = [{Key,Value}] - Key = atom() - Value = term() - Reason = term() - - - -

OPTIONAL; if this function is defined, - then - end_per_testcase/2 must also be - defined.

- -

This function is called before each test case. Argument - TestCase is the test case name, and - Config (list of key-value tuples) is the configuration - data that can be modified. The NewConfig list returned - from this function is given as Config to the test case. - If {fail,Reason} is returned, the test case is - marked as failed without being executed.

- -

If {skip,Reason} is returned, the test case is skipped - and Reason is printed in the overview log for the suite.

-
-
- - - Module:end_per_testcase(TestCase, Config) -> term() | {fail,Reason} | {save_config,SaveConfig} - Test case finalization. - - TestCase = atom() - Config = SaveConfig = [{Key,Value}] - Key = atom() - Value = term() - Reason = term() - - - -

OPTIONAL; if this function is defined, - then - init_per_testcase/2 must also be - defined.

- -

This function is called after each test case, and can be used - to clean up after - init_per_testcase/2 - and the test case. Any return value (besides {fail,Reason} - and {save_config,SaveConfig}) is ignored. By returning - {fail,Reason}, TestCase is marked as faulty (even - though it was successful in the sense that it returned - a value instead of terminating).

- -

For information on save_config, see section - Saving - Configuration Data in the User's Guide.

-
-
- - - Module:Testcase() -> [Info] - Test case information function. - - Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns} - Time = TimeVal | TimeFunc - TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | {hours,integer()} - TimeFunc = {Mod,Func,Args} | Fun - MilliSec = integer() - Mod = atom() - Func = atom() - Args = list() - Fun = fun() - Required = Key | {Key,SubKeys} | {Key,Subkey} | {Key,Subkey,SubKeys} - Key = atom() - SubKeys = SubKey | [SubKey] - SubKey = atom() - Name = atom() - UserData = term() - Conns = [atom()] - - - - -

OPTIONAL

- -

The test case information function. It is supposed to - return a list of tagged tuples that specify various properties - related to the execution of this particular test case. - Properties set by - Testcase/0 - override properties set previously for the test case by - group/1 or - suite/0.

- -

Tag timetrap sets the maximum time that the - test case is allowed to execute. If the timetrap time is - exceeded, the test case fails with reason timetrap_timeout. - init_per_testcase/2 - and - end_per_testcase/2 - are included in the timetrap time. - A TimeFunc function can be used to - set a new timetrap by returning a TimeVal. It can also be - used to trigger a timetrap time-out by, at some point, returning a - value other than a TimeVal. For details, see section - Timetrap - Time-Outs in the User's Guide.

- -

Tag require specifies configuration variables - that are required by the test case (or init_per_testcase/2 - or end_per_testcase/2). - If the required configuration variables are not found in any of the - configuration files, the test case is skipped. For details about - the require functionality, see function - ct:require/1,2.

- -

If timetrap or require is not set, the - default values specified by - suite/0 (or - group/1) are used.

- -

With userdata, the user can specify any test case-related - information that can be read by calling - ct:userdata/3.

- -

Other tuples than the ones defined are ignored.

- -

For details about the test case information function, see section - Test - Case Information Function in the User's Guide.

-
-
- - - Module:Testcase(Config) -> term() | {skip,Reason} | {comment,Comment} | {save_config,SaveConfig} | {skip_and_save,Reason,SaveConfig} | exit() - A test case. - - Config = SaveConfig = [{Key,Value}] - Key = atom() - Value = term() - Reason = term() - Comment = string() - - - -

MANDATORY

- -

The implementation of a test case. Call the functions to test and - check the result. If something fails, ensure the - function causes a runtime error or call - ct:fail/1,2 - (which also causes the test case process to terminate).

- -

Elements from the Config list can, for example, be read - with proplists:get_value/2 in STDLIB - (or the macro ?config defined in ct.hrl).

- -

If you decide not to run the test case after all, return - {skip,Reason}. Reason is then - printed in field Comment on the HTML result page.

- -

To print some information in field Comment on the HTML - result page, return {comment,Comment}.

- -

If the function returns anything else, the test case is - considered successful. The return value always gets printed - in the test case log file.

- -

For details about test case implementation, see section - Test Cases - in the User's Guide.

- -

For information on save_config and skip_and_save, - see section - Saving - Configuration Data in the User's Guide.

-
-
- -
- diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml index 0d1c8076971c..c1f638b58054 100644 --- a/lib/common_test/doc/src/ct.xml +++ b/lib/common_test/doc/src/ct.xml @@ -57,9 +57,9 @@

data_dir - Data file directory

priv_dir - Scratch file directory

Whatever added by - init_per_suite/1 + init_per_suite/1 or - init_per_testcase/2 + init_per_testcase/2 in the test suite.

@@ -1524,7 +1524,7 @@

Returns any data specified with tag userdata in the list of tuples returned from - suite/0.

+ suite/0.

diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml index 3c38dcd439be..875efec305a4 100644 --- a/lib/common_test/doc/src/ct_hooks.xml +++ b/lib/common_test/doc/src/ct_hooks.xml @@ -130,12 +130,12 @@

OPTIONAL

This function is called after - groups/0. + groups/0. It is used to modify the test group definitions, for instance to add or remove groups or change group properties.

GroupDefs is what - groups/0 + groups/0 returned, that is, a list of group definitions.

NewGroupDefs is the possibly modified version of this list.

@@ -146,7 +146,7 @@ in the User's Guide.

Notice that for CTHs that are installed by means of the - suite/0 + suite/0 function, post_groups/2 is called before the init/2 hook function. However, for CTHs that are installed by means @@ -191,19 +191,19 @@

OPTIONAL

This function is called after - all/0. + all/0. It is used to modify the set of test cases and test group to be executed, for instance to add or remove test cases and groups, change group properties, or even skip all tests in the suite.

Return is what - all/0 + all/0 returned, that is, a list of test cases and groups to be executed, or a tuple {skip,Reason}.

GroupDefs is what - groups/0 + groups/0 or the post_groups/2 hook returned, that is, a list of group definitions.

@@ -215,7 +215,7 @@ in the User's Guide.

Notice that for CTHs that are installed by means of the - suite/0 + suite/0 function, post_all/2 is called before the init/2 hook function. However, for CTHs that are installed by means @@ -253,7 +253,7 @@

OPTIONAL

This function is called before - init_per_suite + init_per_suite if it exists. It typically contains initialization/logging that must be done before init_per_suite is called. If {skip,Reason} or {fail,Reason} is returned, @@ -270,11 +270,11 @@

Return is the result of the init_per_suite function. If it is {skip,Reason} or {fail,Reason}, - init_per_suite + init_per_suite is never called, instead the initiation is considered to be skipped or failed, respectively. If a NewConfig list is returned, - init_per_suite + init_per_suite is called with that NewConfig list. For more details, see section Pre Hooks in the User's Guide.

@@ -304,21 +304,21 @@

OPTIONAL

This function is called after - init_per_suite + init_per_suite if it exists. It typically contains extra checks to ensure that all the correct dependencies are started correctly.

Return is what - init_per_suite + init_per_suite returned, that is, {fail,Reason}, {skip,Reason}, a Config list, or a term describing how - init_per_suite + init_per_suite failed.

NewReturn is the possibly modified return value of - init_per_suite. + init_per_suite. To recover from a failure in - init_per_suite, + init_per_suite, return ConfigList with the tc_status element removed. For more details, see Post Hooks in @@ -352,11 +352,11 @@

OPTIONAL

This function is called before - init_per_group + init_per_group if it exists. It behaves the same way as pre_init_per_suite, but for function - init_per_group + init_per_group instead.

If Module:pre_init_per_group/4 is not exported, common_test @@ -385,11 +385,11 @@

OPTIONAL

This function is called after - init_per_group + init_per_group if it exists. It behaves the same way as post_init_per_suite, but for function - init_per_group + init_per_group instead.

If Module:post_init_per_group/5 is not exported, common_test @@ -418,11 +418,11 @@

OPTIONAL

This function is called before - init_per_testcase + init_per_testcase if it exists. It behaves the same way as pre_init_per_suite, but for function - init_per_testcase + init_per_testcase instead.

If Module:pre_init_per_testcase/4 is not exported, common_test @@ -455,11 +455,11 @@

OPTIONAL

This function is called after - init_per_testcase + init_per_testcase if it exists. It behaves the same way as post_init_per_suite, but for function - init_per_testcase + init_per_testcase instead.

If Module:post_init_per_testcase/5 is not exported, common_test @@ -487,11 +487,11 @@

OPTIONAL

This function is called before - end_per_testcase + end_per_testcase if it exists. It behaves the same way as pre_end_per_suite, but for function - end_per_testcase + end_per_testcase instead.

This function cannot change the result of the test case by returning skip or fail @@ -524,11 +524,11 @@

OPTIONAL

This function is called after - end_per_testcase + end_per_testcase if it exists. It behaves the same way as post_end_per_suite, but for function - end_per_testcase + end_per_testcase instead.

If Module:post_end_per_testcase/5 is not exported, common_test @@ -557,11 +557,11 @@

OPTIONAL

This function is called before - end_per_group + end_per_group if it exists. It behaves the same way as pre_init_per_suite, but for function - end_per_group + end_per_group instead.

If Module:pre_end_per_group/4 is not exported, common_test @@ -590,11 +590,11 @@

OPTIONAL

This function is called after - end_per_group + end_per_group if it exists. It behaves the same way as post_init_per_suite, but for function - end_per_group + end_per_group instead.

If Module:post_end_per_group/5 is not exported, common_test @@ -622,11 +622,11 @@

OPTIONAL

This function is called before - end_per_suite + end_per_suite if it exists. It behaves the same way as pre_init_per_suite, but for function - end_per_suite + end_per_suite instead.

@@ -649,11 +649,11 @@

OPTIONAL

This function is called after - end_per_suite + end_per_suite if it exists. It behaves the same way as post_init_per_suite, but for function - end_per_suite + end_per_suite instead.

diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml index e23a8b461a58..a4c72c1fa414 100644 --- a/lib/common_test/doc/src/ct_hooks_chapter.xml +++ b/lib/common_test/doc/src/ct_hooks_chapter.xml @@ -84,10 +84,10 @@

CTHs can also be added within a test suite. This is done by returning {ct_hooks,[CTH]} in the configuration list from - suite/0, - + suite/0, + init_per_suite/1, or - + init_per_group/2.

In this case, CTH can either be only the module name of the CTH @@ -157,7 +157,7 @@ the last test suite has been run - suite/0 + suite/0 pre_init_per_suite/3 is called @@ -165,7 +165,7 @@ post_end_per_suite/4 has been called for that test suite - + init_per_suite/1 post_init_per_suite/4 is called @@ -173,7 +173,7 @@ post_end_per_suite/4 has been called for that test suite - + init_per_group/2 post_init_per_group/5 is called @@ -236,12 +236,12 @@ In a CTH, the behavior can be hooked in before the following functions:

- init_per_suite - init_per_group - init_per_testcase - end_per_testcase - end_per_group - end_per_suite + init_per_suite + init_per_group + init_per_testcase + end_per_testcase + end_per_group + end_per_suite

@@ -282,12 +282,12 @@ Post Hooks

In a CTH, behavior can be hooked in after the following functions:

- init_per_suite - init_per_group - init_per_testcase - end_per_testcase - end_per_group - end_per_suite + init_per_suite + init_per_group + init_per_testcase + end_per_testcase + end_per_group + end_per_suite

diff --git a/lib/common_test/doc/src/ct_property_test.xml b/lib/common_test/doc/src/ct_property_test.xml index 891e0b475b7c..4c5eede7584e 100644 --- a/lib/common_test/doc/src/ct_property_test.xml +++ b/lib/common_test/doc/src/ct_property_test.xml @@ -186,7 +186,7 @@ prop_ftp() -> the output from for example proper:run_commands/2 or proper:run_parallel_commands/2 Config = - the Common Test Config in test cases. + the Common Test Config in test cases. Options = [present_option()] present_option() = {print_fun, fun(Format,Args)} diff --git a/lib/common_test/doc/src/ct_suite.xml b/lib/common_test/doc/src/ct_suite.xml new file mode 100644 index 000000000000..0289a569f02b --- /dev/null +++ b/lib/common_test/doc/src/ct_suite.xml @@ -0,0 +1,619 @@ + + + + +

+ + 2020 + Ericsson AB, 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. + + The Initial Developer of the Original Code is Ericsson AB. + + ct_suite + + + + +
+ ct_suite + -behaviour(ct_suite). + + +

The following section describes the mandatory and optional test suite + functions that Common Test calls during test execution. + For more details, see section + Writing Test Suites + in the User's Guide.

+
+ + + + +

The name of the testcase function.

+
+ + +

The name of the test group.

+
+ + +

The configuration data that can be modified.

+
+ + +

The status value for a nested subgroup.

+
+ + ct_group_def() +

The test group definition, as returned by Module:groups/0.

+
+ + ct_test_def() +

The test suite definition, as returned by Module:all/0.

+
+ + ct_info() +

The test suite information, as returned by Module:suite/0, Module:group/1 and Module:Testcase/0.

+
+
+ + + + Callback Functions +

+ The following functions are to be exported from a + ct_suite callback module in order to define + the callback interface for a test suite. +

+
+ + + Module:all() -> [ct_test_def()] | {skip, Reason} + Returns the list of all test case groups and test cases + in the module. + + ct_test_def() = TestCase | {group, GroupName} | {group, GroupName, Properties} | {group, GroupName, Properties, SubGroups} + TestCase = ct_testname() + GroupName = ct_groupname() + Properties = [parallel | sequence | Shuffle | {RepeatType, N}] | default + SubGroups = [{GroupName, Properties} | {GroupName, Properties, SubGroups}] + Shuffle = shuffle | {shuffle, Seed} + Seed = {integer(), integer(), integer()} + RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail + N = integer() | forever + Reason = term() + + + +

MANDATORY

+ +

Returns the list of all test cases and test case groups in the + test suite module to be executed. This list also specifies the + order the cases and groups are executed by Common Test. + A test case is represented by an atom, + the name of the test case function, or a testcase tuple + indicating that the test case shall be repeated. A test case group is + represented by a group tuple, where GroupName, + an atom, is the name of the group (defined in + Module:groups/0). + Execution properties for groups can also be specified, both + for a top-level group and for any of its subgroups. + Group execution properties specified here override + properties in the group definition (see + Module:groups/0). + (With value default, the group definition properties + are used).

+ +

If {skip, Reason} is returned, all test cases + in the module are skipped and Reason + is printed on the HTML result page.

+ +

For details on groups, see section + Test Case + Groups in the User's Guide.

+ +
+
+ + + Module:groups() -> [ct_group_def()] + Returns a list of test case group definitions. + + ct_group_def() = {GroupName, Properties, GroupsAndTestCases} + GroupName = ct_groupname() + Properties = [parallel | sequence | Shuffle | {RepeatType, N}] + GroupsAndTestCases = [Group | {group, GroupName} | TestCase] + TestCase = ct_testname() + Shuffle = shuffle | {shuffle, Seed} + Seed = {integer(), integer(), integer()} + RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail + N = integer() | forever + + + +

OPTIONAL

+ +

Defines test case groups. For details, see section + Test Case + Groups in the User's Guide.

+
+
+ + + Module:suite() -> [ct_info()] + Test suite info function (providing default data + for the suite). + + ct_info() = {timetrap, Time} | {require, Required} | {require, Name, Required} | {userdata, UserData} | {silent_connections, Conns} | {stylesheet, CSSFile} | {ct_hooks, CTHs} + Time = TimeVal | TimeFunc + TimeVal = MilliSec | {seconds, integer()} | {minutes, integer()} | {hours, integer()} + TimeFunc = {Mod, Func, Args} | Fun + MilliSec = integer() + Mod = atom() + Func = atom() + Args = list() + Fun = fun() + Required = Key | {Key, SubKeys} | {Key, SubKey} | {Key, SubKey, SubKeys} + Key = atom() + SubKeys = SubKey | [SubKey] + SubKey = atom() + Name = atom() + UserData = term() + Conns = [atom()] + CSSFile = string() + CTHs = [CTHModule | +         {CTHModule, CTHInitArgs} | +         {CTHModule, CTHInitArgs, CTHPriority}] + CTHModule = atom() + CTHInitArgs = term() + CTHPriority = integer() + + + +

OPTIONAL

+ +

The test suite information function. Returns a list of tagged + tuples specifying various properties related to the execution of + this test suite (common for all test cases in the suite).

+ +

Tag timetrap sets the maximum time that each + test case is allowed to execute (including + Module:init_per_testcase/2 + and + Module:end_per_testcase/2). + If the timetrap time is exceeded, the test case fails with reason + timetrap_timeout. A TimeFunc function can be used to + set a new timetrap by returning a TimeVal. It can also be + used to trigger a timetrap time-out by, at some point, returning a + value other than a TimeVal. For details, see section + Timetrap Time-Outs + in the User's Guide.

+ +

Tag require specifies configuration variables + required by test cases (or configuration functions) + in the suite. If the required configuration variables are not found + in any of the configuration files, all test cases are skipped. + For details about the require functionality, see funtion + ct:require/1,2.

+ +

With userdata, the user can + specify any test suite-related information, which can be + read by calling + ct:userdata/2.

+ +

Tag ct_hooks specifies the + Common Test Hooks + to be run with this suite.

+ +

Other tuples than the ones defined are ignored.

+ +

For details about the test suite information function, see section + Test + Suite Information Function in the User's Guide.

+
+
+ + + Module:init_per_suite(Config) -> NewConfig | {skip, Reason} | + {skip_and_save, Reason, SaveConfig} + Test suite initializations. + + Config = NewConfig = SaveConfig = ct_config() + Reason = term() + + + +

OPTIONAL; if this function is defined, then Module:end_per_suite/1 + must also be defined.

+ +

This configuration function is called as the first function in the + suite. It typically contains initializations that are common for + all test cases in the suite, and that must only be done + once. Parameter Config is the configuration data + that can be modified. Whatever is returned from this + function is specified as Config to all configuration functions + and test cases in the suite.

+ +

If {skip, Reason} + is returned, all test cases in the suite are skipped + and Reason is printed in the overview log for the suite.

+ +

For information on save_config and skip_and_save, + see section + Saving + Configuration Data in the User's Guide.

+
+
+ + + Module:end_per_suite(Config) -> term() | + {save_config, SaveConfig} + Test suite finalization. + + Config = SaveConfig = ct_config() + + + +

OPTIONAL; if this function is defined, then Module:init_per_suite/1 + must also be defined.

+ +

This function is called as the last test case in the + suite. It is meant to be used for cleaning up after + Module:init_per_suite/1.

+

For information on save_config, see section + Saving + Configuration Data in the User's Guide.

+
+
+ + + Module:group(GroupName) -> [ct_info()] + Test case group information function (providing default data + for a test case group, that is, its test cases and + subgroups). + + GroupName = ct_groupname() + ct_info() = {timetrap, Time} | {require, Required} | {require, Name, Required} | {userdata, UserData} | {silent_connections, Conns} | {stylesheet, CSSFile} | {ct_hooks, CTHs} + Time = TimeVal | TimeFunc + TimeVal = MilliSec | {seconds, integer()} | {minutes, integer()} | {hours, integer()} + TimeFunc = {Mod, Func, Args} | Fun + MilliSec = integer() + Mod = atom() + Func = atom() + Args = list() + Fun = fun() + Required = Key | {Key, SubKeys} | {Key, SubKey} | {Key, SubKey, SubKeys} + Key = atom() + SubKeys = SubKey | [SubKey] + SubKey = atom() + Name = atom() + UserData = term() + Conns = [atom()] + CSSFile = string() + CTHs = [CTHModule | +         {CTHModule, CTHInitArgs} | +         {CTHModule, CTHInitArgs, CTHPriority}] + CTHModule = atom() + CTHInitArgs = term() + CTHPriority = integer() + + + +

OPTIONAL

+ +

The test case group information function. It is supposed to + return a list of tagged tuples that specify various properties + related to the execution of a test case group (that is, its test + cases and subgroups). Properties set by + Module:group/1 override + properties with the same key that have been set previously by + Module:suite/0.

+ +

Tag timetrap sets the maximum time that each + test case is allowed to execute (including + Module:init_per_testcase/2 + and + Module:end_per_testcase/2). + If the timetrap time is + exceeded, the test case fails with reason + timetrap_timeout. A TimeFunc function can be used to + set a new timetrap by returning a TimeVal. It can also be + used to trigger a timetrap time-out by, at some point, returning a + value other than a TimeVal. For details, see section + Timetrap + Time-Outs in the User's Guide.

+ +

Tag require specifies configuration variables + required by test cases (or configuration functions) + in the suite. If the required configuration variables are not found + in any of the configuration files, all test cases in this group are + skipped. For details about the require functionality, see + function + ct:require/1,2.

+ +

With userdata, the user can + specify any test case group related information that can be + read by calling + ct:userdata/2.

+ +

Tag ct_hooks specifies the + Common Test Hooks + to be run with this suite.

+ +

Other tuples than the ones defined are ignored.

+ +

For details about the test case group information function, + see section Group + Information Function in the User's Guide.

+
+
+ + + Module:init_per_group(GroupName, Config) -> NewConfig | + {skip, Reason} + Test case group initializations. + + GroupName = ct_groupname() + Config = NewConfig = ct_config() + Reason = term() + + + +

OPTIONAL; if this function is defined, then Module:end_per_group/2 + must also be defined.

+ +

This configuration function is called before execution of a + test case group. It typically contains initializations that are + common for all test cases and subgroups in the group, and that + must only be performed once. GroupName is the name of the + group, as specified in the group definition (see + Module:groups/0). + Parameter Config is the configuration data that can be + modified. + The return value of this function is given as Config + to all test cases and subgroups in the group.

+ +

If {skip, Reason} + is returned, all test cases in the group are skipped and + Reason is printed in the overview log for the group.

+ +

For information about test case groups, see section + Test Case + Groups in the User's Guide.

+
+
+ + + Module:end_per_group(GroupName, Config) -> term() | + {return_group_result, Status} + Test case group finalization. + + GroupName = ct_groupname() + Config = ct_config() + Status = ct_status() + + + +

OPTIONAL; if this function is defined, then Module:init_per_group/2 + must also be defined.

+ +

This function is called after the execution of a test case group + is finished. It is meant to be used for cleaning up after + Module:init_per_group/2. + A status value for a nested subgroup can be returned with + {return_group_result, Status}. The status can be retrieved in + Module:end_per_group/2 + for the group on the level above. The status is also used by + Common Test for deciding if execution of a group is to + proceed if property sequence or repeat_until_* + is set.

+ +

For details about test case groups, see section + Test Case + Groups in the User's Guide.

+
+
+ + + Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail, Reason} | {skip, Reason} + Test case initializations. + + TestCase = ct_testname() + Config = NewConfig = ct_config() + Reason = term() + + + +

OPTIONAL; if this function is defined, + then + Module:end_per_testcase/2 must also be + defined.

+ +

This function is called before each test case. Argument + TestCase is the test case name, and + Config (list of key-value tuples) is the configuration + data that can be modified. The NewConfig list returned + from this function is given as Config to the test case. + If {fail, Reason} is returned, the test case is + marked as failed without being executed.

+ +

If {skip, Reason} is returned, the test case is skipped + and Reason is printed in the overview log for the suite.

+
+
+ + + Module:end_per_testcase(TestCase, Config) -> term() | {fail, Reason} | {save_config, SaveConfig} + Test case finalization. + + TestCase = ct_testname() + Config = SaveConfig = ct_config() + Reason = term() + + + +

OPTIONAL; if this function is defined, + then + Module:init_per_testcase/2 must also be + defined.

+ +

This function is called after each test case, and can be used + to clean up after + Module:init_per_testcase/2 + and the test case. Any return value (besides {fail, Reason} + and {save_config, SaveConfig}) is ignored. By returning + {fail, Reason}, TestCase is marked as faulty (even + though it was successful in the sense that it returned + a value instead of terminating).

+ +

For information on save_config, see section + Saving + Configuration Data in the User's Guide.

+
+
+ + + Module:Testcase() -> [ct_info()] + Test case information function. + + ct_info() = {timetrap, Time} | {require, Required} | {require, Name, Required} | {userdata, UserData} | {silent_connections, Conns} | {stylesheet, CSSFile} | {ct_hooks, CTHs} + Time = TimeVal | TimeFunc + TimeVal = MilliSec | {seconds, integer()} | {minutes, integer()} | {hours, integer()} + TimeFunc = {Mod, Func, Args} | Fun + MilliSec = integer() + Mod = atom() + Func = atom() + Args = list() + Fun = fun() + Required = Key | {Key, SubKeys} | {Key, SubKey} | {Key, SubKey, SubKeys} + Key = atom() + SubKeys = SubKey | [SubKey] + SubKey = atom() + Name = atom() + UserData = term() + Conns = [atom()] + CSSFile = string() + CTHs = [CTHModule | +         {CTHModule, CTHInitArgs} | +         {CTHModule, CTHInitArgs, CTHPriority}] + CTHModule = atom() + CTHInitArgs = term() + CTHPriority = integer() + + + + +

OPTIONAL

+ +

The test case information function. It is supposed to + return a list of tagged tuples that specify various properties + related to the execution of this particular test case. + Properties set by + Module:Testcase/0 + override properties set previously for the test case by + Module:group/1 or + Module:suite/0.

+ +

Tag timetrap sets the maximum time that the + test case is allowed to execute. If the timetrap time is + exceeded, the test case fails with reason timetrap_timeout. + Module:init_per_testcase/2 + and + Module:end_per_testcase/2 + are included in the timetrap time. + A TimeFunc function can be used to + set a new timetrap by returning a TimeVal. It can also be + used to trigger a timetrap time-out by, at some point, returning a + value other than a TimeVal. For details, see section + Timetrap + Time-Outs in the User's Guide.

+ +

Tag require specifies configuration variables + that are required by the test case (or init_per_testcase/2 + or end_per_testcase/2). + If the required configuration variables are not found in any of the + configuration files, the test case is skipped. For details about + the require functionality, see function + ct:require/1,2.

+ +

If timetrap or require is not set, the + default values specified by + Module:suite/0 (or + Module:group/1) are used.

+ +

With userdata, the user can specify any test case-related + information that can be read by calling + ct:userdata/3.

+ +

Other tuples than the ones defined are ignored.

+ +

For details about the test case information function, see section + Test + Case Information Function in the User's Guide.

+
+
+ + + Module:Testcase(Config) -> term() | {skip, Reason} | {comment, Comment} | {save_config, SaveConfig} | {skip_and_save, Reason, SaveConfig} | exit() + A test case. + + Config = SaveConfig = ct_config() + Reason = term() + Comment = string() + + + +

MANDATORY

+ +

The implementation of a test case. Call the functions to test and + check the result. If something fails, ensure the + function causes a runtime error or call + ct:fail/1,2 + (which also causes the test case process to terminate).

+ +

Elements from the Config list can, for example, be read + with proplists:get_value/2 in STDLIB + (or the macro ?config defined in ct.hrl).

+ +

If you decide not to run the test case after all, return + {skip, Reason}. Reason is then + printed in field Comment on the HTML result page.

+ +

To print some information in field Comment on the HTML + result page, return {comment, Comment}.

+ +

If the function returns anything else, the test case is + considered successful. The return value always gets printed + in the test case log file.

+ +

For details about test case implementation, see section + Test Cases + in the User's Guide.

+ +

For information on save_config and skip_and_save, + see section + Saving + Configuration Data in the User's Guide.

+
+
+ +
+ + diff --git a/lib/common_test/doc/src/dependencies_chapter.xml b/lib/common_test/doc/src/dependencies_chapter.xml index 53a767348928..0a0f4c562fc6 100644 --- a/lib/common_test/doc/src/dependencies_chapter.xml +++ b/lib/common_test/doc/src/dependencies_chapter.xml @@ -87,8 +87,8 @@

To avoid this, we can consider starting and stopping the server for every test. We can thus implement the start and stop action as common functions to be called from - init_per_testcase and - end_per_testcase. + init_per_testcase and + end_per_testcase. (Remember to test the start and stop functionality separately.) The configuration can also be implemented as a common function, maybe grouped with the start function. Finally, the testing of connecting and disconnecting a @@ -194,9 +194,9 @@

To pass data from one test suite to another, the same mechanism is used. The data is to be saved by finction - end_per_suite + end_per_suite and read by function - init_per_suite + init_per_suite in the suite that follows. When passing data between suites, Saver carries the name of the test suite.

@@ -306,7 +306,7 @@ any property, that is, they are not required to also be sequences. If you want the status of the subgroup to affect the sequence on the level above, return {return_group_result,Status} from - end_per_group/2, + end_per_group/2, as described in section Repeated Groups in Writing Test Suites. diff --git a/lib/common_test/doc/src/ref_man.xml b/lib/common_test/doc/src/ref_man.xml index e916fc7cec7a..b8184ed7f8ba 100644 --- a/lib/common_test/doc/src/ref_man.xml +++ b/lib/common_test/doc/src/ref_man.xml @@ -48,6 +48,7 @@ + diff --git a/lib/common_test/doc/src/specs.xml b/lib/common_test/doc/src/specs.xml index 7e40e8351d74..def8f761a544 100644 --- a/lib/common_test/doc/src/specs.xml +++ b/lib/common_test/doc/src/specs.xml @@ -2,4 +2,5 @@ + diff --git a/lib/common_test/doc/src/test_structure_chapter.xml b/lib/common_test/doc/src/test_structure_chapter.xml index 42eb3d6e236b..e041376d7f32 100644 --- a/lib/common_test/doc/src/test_structure_chapter.xml +++ b/lib/common_test/doc/src/test_structure_chapter.xml @@ -60,8 +60,8 @@ Returning {skip,Reason} from function - init_per_testcase/2 or - init_per_suite/1. + init_per_testcase/2 or + init_per_suite/1. Returning {skip,Reason} from the execution clause of the test case. The execution clause is called, so the author diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml index 3c3790cfc530..661ba04fe887 100644 --- a/lib/common_test/doc/src/write_test_chapter.xml +++ b/lib/common_test/doc/src/write_test_chapter.xml @@ -67,7 +67,7 @@

Each test suite module must export function - all/0, + all/0, which returns the list of all test case groups and test cases to be executed in that module.

@@ -83,8 +83,8 @@ Init and End per Suite

Each test suite module can contain the optional configuration functions - init_per_suite/1 - and end_per_suite/1. + init_per_suite/1 + and end_per_suite/1. If the init function is defined, so must the end function be.

@@ -138,8 +138,8 @@ Init and End per Test Case

Each test suite module can contain the optional configuration functions - init_per_testcase/2 - and end_per_testcase/2. + init_per_testcase/2 + and end_per_testcase/2. If the init function is defined, so must the end function be.

If init_per_testcase exists, it is called before each @@ -378,7 +378,7 @@

If timetrap or require, or both, is not set specifically for a particular test case, default values specified by function - suite/0 + suite/0 are used.

@@ -404,7 +404,7 @@ Test Suite Information Function -

Function suite/0 +

Function suite/0 can, for example, be used in a test suite module to set a default timetrap value and to require external configuration data. If a test case, or a group information function also specifies any of the information tags, it @@ -445,7 +445,7 @@

A test case group is a set of test cases sharing configuration functions and execution properties. Test case groups are defined by function - groups/0 + groups/0 according to the following syntax:

  groups() -> GroupDefs
@@ -561,12 +561,12 @@
       execution is immediately stopped and the remaining cases are skipped.

Before execution of a group begins, the configuration function - init_per_group(GroupName, Config) + init_per_group(GroupName, Config) is called. The list of tuples returned from this function is passed to the test cases in the usual manner by argument Config. init_per_group/2 is meant to be used for initializations common for the test cases in the group. After execution of the group is finished, function - end_per_group(GroupName, Config) + end_per_group(GroupName, Config) is called. This function is meant to be used for cleaning up after init_per_group/2. If the init function is defined, so must the end function be.

@@ -1163,7 +1163,7 @@ ct:pal(?ERROR, "Error report: ~p", [Error])
environment as possible, so that subsequent test cases do not crash because of their execution order. The function - end_per_testcase + end_per_testcase is suitable for this.

diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile index a20de14e0e3e..7d7b5ed203d7 100644 --- a/lib/common_test/src/Makefile +++ b/lib/common_test/src/Makefile @@ -40,6 +40,9 @@ RELSYSDIR = $(RELEASE_PATH)/lib/common_test-$(VSN) # Target Specs # ---------------------------------------------------- +BEHAVIOUR_MODULES= \ + ct_suite + MODULES= \ ct \ ct_logs \ @@ -88,9 +91,13 @@ MODULES= \ TARGET_MODULES= $(MODULES:%=$(EBIN)/%) -BEAM_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +BEAM_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) \ + $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR)) + +ERL_FILES= \ + $(MODULES:=.erl) \ + $(BEHAVIOUR_MODULES:%=%.erl) -ERL_FILES= $(MODULES:=.erl) HRL_FILES = \ ct_util.hrl \ ct_netconfc.hrl diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src index 07b35b71800c..8aa15efa7e67 100644 --- a/lib/common_test/src/common_test.app.src +++ b/lib/common_test/src/common_test.app.src @@ -63,7 +63,8 @@ test_server_gl, test_server_io, test_server_node, - test_server_sup + test_server_sup, + ct_suite ]}, {registered, [ct_logs, ct_util_server, diff --git a/lib/common_test/src/ct_suite.erl b/lib/common_test/src/ct_suite.erl new file mode 100644 index 000000000000..a2d23e15ef14 --- /dev/null +++ b/lib/common_test/src/ct_suite.erl @@ -0,0 +1,130 @@ +-module(ct_suite). + +%%------------------------------------------------------------------ +%% Test Suite Behaviour +%% ------------------------------------------------------------------ +-export_type([ct_testname/0, + ct_groupname/0, + ct_config/0, + ct_status/0, + ct_group_def/0, + ct_test_def/0, + ct_info/0 + ]). + +-type ct_testname() :: atom(). +-type ct_groupname() :: atom(). +-type ct_config() :: [{Key :: atom(), Value :: term()}]. +-type ct_status() :: ok | + skipped | + failed. +-type ct_group_props() :: [ + parallel | + sequence | + shuffle | + {shuffle, Seed :: {integer(), integer(), integer()}} | + {ct_group_repeat_type(), ct_test_repeat()} + ]. +-type ct_group_props_ref() :: + ct_group_props() | + default. +-type ct_group_repeat_type() :: repeat | + repeat_until_all_ok | + repeat_until_all_fail | + repeat_until_any_ok | + repeat_until_any_fail. +-type ct_test_repeat() :: integer() | + forever. +-type ct_group_def() :: {ct_groupname(), ct_group_props(), [ + ct_testname() | + ct_group_def() | + {group, ct_groupname()} | + ct_testcase_ref() + ]}. +-type ct_subgroups_def() :: {ct_groupname(), ct_group_props_ref()} | + {ct_groupname(), ct_group_props_ref(), ct_subgroups_def()}. +-type ct_group_ref() :: {group, ct_groupname()} | + {group, ct_groupname(), ct_group_props_ref()} | + {group, ct_groupname(), ct_group_props_ref(), ct_subgroups_def()}. +-type ct_testcase_ref() :: {testcase, ct_testname(), ct_testcase_repeat_prop()}. +-type ct_testcase_repeat_prop() :: {repeat, ct_test_repeat()} | + {repeat_until_ok, ct_test_repeat()} | + {repeat_until_fail, ct_test_repeat()}. +-type ct_info() :: {timetrap, ct_info_timetrap()} | + {require, ct_info_required()} | + {require, Name :: atom(), ct_info_required()} | + {userdata, UserData :: term()} | + {silent_connections, Conns :: [atom()]} | + {stylesheet, CSSFile :: string()} | + {ct_hooks, CTHs :: ct_hooks()}. +-type ct_info_timetrap() :: MilliSec :: integer() | + {seconds, integer()} | + {minutes, integer()} | + {hours, integer()} | + {Mod :: atom(), Func :: atom(), Args :: list()} | + ct_info_timetrap_fun(). +-type ct_info_timetrap_fun() :: fun(). +-type ct_info_required() :: Key :: atom() | + {Key :: atom(), SubKeys :: ct_info_required_subkeys()} | + {Key :: atom(), SubKey :: atom()} | + {Key :: atom(), SubKey :: atom(), SubKeys :: ct_info_required_subkeys()}. +-type ct_info_required_subkeys() :: SubKey :: atom() | + [SubKey :: atom()]. +-type ct_hooks() :: [ + CTHModule :: atom() | + {CTHModule :: atom(), CTHInitArgs :: term()} | + {CTHModule :: atom(), CTHInitArgs :: term(), CTHPriority :: integer()} + ]. +-type ct_test_def() :: ct_testname() | ct_group_ref() | ct_testcase_ref(). + +-callback all() -> + [TestDef :: ct_test_def()] | + {skip, Reason :: term()}. + +-callback groups() -> + [GroupDef :: ct_group_def()]. + +-callback suite() -> + [Info :: ct_info()]. + +-callback init_per_suite(Config :: ct_config()) -> + NewConfig :: ct_config() | + {skip, Reason :: term()} | + {skip_and_save, Reason :: term(), SaveConfig :: ct_config()}. + +-callback end_per_suite(Config :: ct_config()) -> + term() | + {save_config, SaveConfig :: ct_config()}. + +-callback group(GroupName :: ct_groupname()) -> + [Info :: ct_info()]. + +-callback init_per_group(GroupName :: ct_groupname(), Config :: ct_config()) -> + NewConfig :: ct_config() | + {skip, Reason :: term()}. + +-callback end_per_group(GroupName :: ct_groupname(), Config :: ct_config()) -> + term() | + {return_group_result, Status :: ct_status()}. + +-callback init_per_testcase(TestCase :: ct_testname(), Config :: ct_config()) -> + NewConfig :: ct_config() | + {fail, Reason :: term()} | + {skip, Reason :: term()}. + +-callback end_per_testcase(TestCase :: ct_testname(), Config :: ct_config()) -> + term() | + {fail, Reason :: term()} | + {save_config, SaveConfig :: ct_config()}. + +%% only all/0 is mandatory +-optional_callbacks([groups/0, + suite/0, + init_per_suite/1, + end_per_suite/1, + group/1, + init_per_group/2, + end_per_group/2, + init_per_testcase/2, + end_per_testcase/2 + ]). diff --git a/lib/ssl/test/ssl_ECC.erl b/lib/ssl/test/ssl_ECC.erl index 56b67361e175..73dafcd1fc93 100644 --- a/lib/ssl/test/ssl_ECC.erl +++ b/lib/ssl/test/ssl_ECC.erl @@ -23,6 +23,8 @@ -module(ssl_ECC). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl index 496cb38fd98d..f834ac410573 100644 --- a/lib/ssl/test/ssl_ECC_SUITE.erl +++ b/lib/ssl/test/ssl_ECC_SUITE.erl @@ -22,6 +22,8 @@ -module(ssl_ECC_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). diff --git a/lib/ssl/test/ssl_alert_SUITE.erl b/lib/ssl/test/ssl_alert_SUITE.erl index ffdc9ea91677..3b32d3ece15e 100644 --- a/lib/ssl/test/ssl_alert_SUITE.erl +++ b/lib/ssl/test/ssl_alert_SUITE.erl @@ -20,6 +20,8 @@ -module(ssl_alert_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). diff --git a/lib/ssl/test/ssl_alpn_SUITE.erl b/lib/ssl/test/ssl_alpn_SUITE.erl index f0be74071658..9cc3303604b7 100644 --- a/lib/ssl/test/ssl_alpn_SUITE.erl +++ b/lib/ssl/test/ssl_alpn_SUITE.erl @@ -21,6 +21,8 @@ %% -module(ssl_alpn_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). %% Callback functions diff --git a/lib/ssl/test/ssl_api_SUITE.erl b/lib/ssl/test/ssl_api_SUITE.erl index d52645cc52fb..95e3c0a058fc 100644 --- a/lib/ssl/test/ssl_api_SUITE.erl +++ b/lib/ssl/test/ssl_api_SUITE.erl @@ -21,6 +21,8 @@ %% -module(ssl_api_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("ssl/src/ssl_api.hrl"). diff --git a/lib/ssl/test/ssl_app_env_SUITE.erl b/lib/ssl/test/ssl_app_env_SUITE.erl index ee9c3ad74552..98e96023b247 100644 --- a/lib/ssl/test/ssl_app_env_SUITE.erl +++ b/lib/ssl/test/ssl_app_env_SUITE.erl @@ -21,6 +21,8 @@ %% -module(ssl_app_env_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("ssl/src/ssl_api.hrl"). diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 0039b0244f51..1426c7ef49b8 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -22,6 +22,8 @@ -module(ssl_basic_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("ssl/src/ssl_api.hrl"). diff --git a/lib/ssl/test/ssl_bench_SUITE.erl b/lib/ssl/test/ssl_bench_SUITE.erl index fe30a83a7e46..f78ac9c9cc80 100644 --- a/lib/ssl/test/ssl_bench_SUITE.erl +++ b/lib/ssl/test/ssl_bench_SUITE.erl @@ -19,6 +19,8 @@ %% -module(ssl_bench_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct_event.hrl"). %% Callback functions diff --git a/lib/ssl/test/ssl_bench_test_lib.erl b/lib/ssl/test/ssl_bench_test_lib.erl index cbb9cfe47abd..74ab142993e1 100644 --- a/lib/ssl/test/ssl_bench_test_lib.erl +++ b/lib/ssl/test/ssl_bench_test_lib.erl @@ -19,6 +19,8 @@ %% -module(ssl_bench_test_lib). +-behaviour(ct_suite). + %% API -export([setup/1]). diff --git a/lib/ssl/test/ssl_cert_SUITE.erl b/lib/ssl/test/ssl_cert_SUITE.erl index bec6057d9123..655d29b6ae76 100644 --- a/lib/ssl/test/ssl_cert_SUITE.erl +++ b/lib/ssl/test/ssl_cert_SUITE.erl @@ -21,6 +21,8 @@ %% -module(ssl_cert_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). diff --git a/lib/ssl/test/ssl_cert_tests.erl b/lib/ssl/test/ssl_cert_tests.erl index 5422ff7fe4fe..d2bf39d88c65 100644 --- a/lib/ssl/test/ssl_cert_tests.erl +++ b/lib/ssl/test/ssl_cert_tests.erl @@ -21,6 +21,8 @@ %% -module(ssl_cert_tests). +-behaviour(ct_suite). + -include_lib("public_key/include/public_key.hrl"). %% Test cases diff --git a/lib/ssl/test/ssl_cipher_SUITE.erl b/lib/ssl/test/ssl_cipher_SUITE.erl index eee8d8078be1..31e60269f8bb 100644 --- a/lib/ssl/test/ssl_cipher_SUITE.erl +++ b/lib/ssl/test/ssl_cipher_SUITE.erl @@ -20,6 +20,8 @@ -module(ssl_cipher_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include("tls_record.hrl"). -include("ssl_cipher.hrl"). diff --git a/lib/ssl/test/ssl_cipher_suite_SUITE.erl b/lib/ssl/test/ssl_cipher_suite_SUITE.erl index 6952472300c6..99911af3706a 100644 --- a/lib/ssl/test/ssl_cipher_suite_SUITE.erl +++ b/lib/ssl/test/ssl_cipher_suite_SUITE.erl @@ -22,6 +22,8 @@ -module(ssl_cipher_suite_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). %% Callback functions -export([all/0, diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl index ad75d29a78f3..f9fac829629e 100644 --- a/lib/ssl/test/ssl_crl_SUITE.erl +++ b/lib/ssl/test/ssl_crl_SUITE.erl @@ -21,6 +21,8 @@ -module(ssl_crl_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl index 20463114f4fb..019e22eaa842 100644 --- a/lib/ssl/test/ssl_dist_SUITE.erl +++ b/lib/ssl/test/ssl_dist_SUITE.erl @@ -20,6 +20,8 @@ -module(ssl_dist_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). -include("ssl_dist_test_lib.hrl"). diff --git a/lib/ssl/test/ssl_dist_bench_SUITE.erl b/lib/ssl/test/ssl_dist_bench_SUITE.erl index 67944c74d27c..2216c6b04b71 100644 --- a/lib/ssl/test/ssl_dist_bench_SUITE.erl +++ b/lib/ssl/test/ssl_dist_bench_SUITE.erl @@ -19,6 +19,8 @@ %% -module(ssl_dist_bench_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct_event.hrl"). -include_lib("public_key/include/public_key.hrl"). diff --git a/lib/ssl/test/ssl_dist_test_lib.erl b/lib/ssl/test/ssl_dist_test_lib.erl index fa1f4217feb1..bf010e6ad4b4 100644 --- a/lib/ssl/test/ssl_dist_test_lib.erl +++ b/lib/ssl/test/ssl_dist_test_lib.erl @@ -20,6 +20,8 @@ -module(ssl_dist_test_lib). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). -include("ssl_dist_test_lib.hrl"). diff --git a/lib/ssl/test/ssl_engine_SUITE.erl b/lib/ssl/test/ssl_engine_SUITE.erl index 4e88c6e46cfe..c0e28120bee7 100644 --- a/lib/ssl/test/ssl_engine_SUITE.erl +++ b/lib/ssl/test/ssl_engine_SUITE.erl @@ -21,6 +21,8 @@ %% -module(ssl_engine_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). diff --git a/lib/ssl/test/ssl_eqc_SUITE.erl b/lib/ssl/test/ssl_eqc_SUITE.erl index 52edb39d9cca..b663597835ed 100644 --- a/lib/ssl/test/ssl_eqc_SUITE.erl +++ b/lib/ssl/test/ssl_eqc_SUITE.erl @@ -20,6 +20,7 @@ -module(ssl_eqc_SUITE). +-behaviour(ct_suite). %% Common test -export([all/0, diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl index f990b9328ae4..6da6da4051f7 100644 --- a/lib/ssl/test/ssl_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_handshake_SUITE.erl @@ -22,6 +22,8 @@ -module(ssl_handshake_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include("ssl_alert.hrl"). -include("ssl_handshake.hrl"). diff --git a/lib/ssl/test/ssl_key_update_SUITE.erl b/lib/ssl/test/ssl_key_update_SUITE.erl index 2816f1a39e22..aba6a02ddc7a 100644 --- a/lib/ssl/test/ssl_key_update_SUITE.erl +++ b/lib/ssl/test/ssl_key_update_SUITE.erl @@ -19,6 +19,8 @@ %% -module(ssl_key_update_SUITE). +-behaviour(ct_suite). + %% Callback functions -export([all/0, groups/0, diff --git a/lib/ssl/test/ssl_mfl_SUITE.erl b/lib/ssl/test/ssl_mfl_SUITE.erl index e8fa0ddf5264..0f9aeb1c674a 100644 --- a/lib/ssl/test/ssl_mfl_SUITE.erl +++ b/lib/ssl/test/ssl_mfl_SUITE.erl @@ -18,6 +18,9 @@ %% %CopyrightEnd% %% -module(ssl_mfl_SUITE). + +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). %% Common test diff --git a/lib/ssl/test/ssl_npn_SUITE.erl b/lib/ssl/test/ssl_npn_SUITE.erl index addf105e592b..81c75ecff04a 100644 --- a/lib/ssl/test/ssl_npn_SUITE.erl +++ b/lib/ssl/test/ssl_npn_SUITE.erl @@ -21,6 +21,8 @@ %% -module(ssl_npn_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). %% Callback functions diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl index ee84383c612d..dae07aae6309 100644 --- a/lib/ssl/test/ssl_npn_hello_SUITE.erl +++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl @@ -22,6 +22,8 @@ -module(ssl_npn_hello_SUITE). +-behaviour(ct_suite). + -include_lib("ssl/src/tls_record.hrl"). -include_lib("ssl/src/tls_handshake.hrl"). -include_lib("ssl/src/ssl_cipher.hrl"). diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index bd390d67bf06..a65173f1723e 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -21,6 +21,8 @@ %% -module(ssl_packet_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). %% Callback functions diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl index df8394ab148a..e594c745b694 100644 --- a/lib/ssl/test/ssl_payload_SUITE.erl +++ b/lib/ssl/test/ssl_payload_SUITE.erl @@ -20,6 +20,8 @@ -module(ssl_payload_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). %% Common test -export([all/0, diff --git a/lib/ssl/test/ssl_pem_cache_SUITE.erl b/lib/ssl/test/ssl_pem_cache_SUITE.erl index 2469b47040ab..50d808905485 100644 --- a/lib/ssl/test/ssl_pem_cache_SUITE.erl +++ b/lib/ssl/test/ssl_pem_cache_SUITE.erl @@ -22,6 +22,8 @@ -module(ssl_pem_cache_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/file.hrl"). diff --git a/lib/ssl/test/ssl_renegotiate_SUITE.erl b/lib/ssl/test/ssl_renegotiate_SUITE.erl index 18ca56b6f976..4b4686341585 100644 --- a/lib/ssl/test/ssl_renegotiate_SUITE.erl +++ b/lib/ssl/test/ssl_renegotiate_SUITE.erl @@ -22,6 +22,8 @@ -module(ssl_renegotiate_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). diff --git a/lib/ssl/test/ssl_rfc_5869_SUITE.erl b/lib/ssl/test/ssl_rfc_5869_SUITE.erl index d350dd099da8..497a05107b4c 100644 --- a/lib/ssl/test/ssl_rfc_5869_SUITE.erl +++ b/lib/ssl/test/ssl_rfc_5869_SUITE.erl @@ -21,6 +21,8 @@ %% -module(ssl_rfc_5869_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). %% Common test diff --git a/lib/ssl/test/ssl_session_SUITE.erl b/lib/ssl/test/ssl_session_SUITE.erl index d123b38d5597..0a614f8b8c76 100644 --- a/lib/ssl/test/ssl_session_SUITE.erl +++ b/lib/ssl/test/ssl_session_SUITE.erl @@ -21,6 +21,8 @@ %% -module(ssl_session_SUITE). +-behaviour(ct_suite). + -include("tls_handshake.hrl"). -include("ssl_record.hrl"). diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index c53161f16868..7c182ee063de 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -22,6 +22,8 @@ -module(ssl_session_cache_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). %% Callback functions diff --git a/lib/ssl/test/ssl_session_ticket_SUITE.erl b/lib/ssl/test/ssl_session_ticket_SUITE.erl index 218c4a156471..16791e2c3691 100644 --- a/lib/ssl/test/ssl_session_ticket_SUITE.erl +++ b/lib/ssl/test/ssl_session_ticket_SUITE.erl @@ -20,6 +20,8 @@ -module(ssl_session_ticket_SUITE). +-behaviour(ct_suite). + %% Callback functions -export([all/0, groups/0, diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl index 74200c7ab00b..9e2f9fddb1e7 100644 --- a/lib/ssl/test/ssl_sni_SUITE.erl +++ b/lib/ssl/test/ssl_sni_SUITE.erl @@ -21,6 +21,8 @@ -module(ssl_sni_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). -include_lib("kernel/include/inet.hrl"). diff --git a/lib/ssl/test/ssl_socket_SUITE.erl b/lib/ssl/test/ssl_socket_SUITE.erl index a6bce2a414ae..e10ec5afafa1 100644 --- a/lib/ssl/test/ssl_socket_SUITE.erl +++ b/lib/ssl/test/ssl_socket_SUITE.erl @@ -20,6 +20,8 @@ -module(ssl_socket_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 03c8c710ba7c..fc5291b326fe 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -21,6 +21,8 @@ %% -module(ssl_test_lib). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). diff --git a/lib/ssl/test/ssl_upgrade_SUITE.erl b/lib/ssl/test/ssl_upgrade_SUITE.erl index b258b9b05709..cc5db6978873 100644 --- a/lib/ssl/test/ssl_upgrade_SUITE.erl +++ b/lib/ssl/test/ssl_upgrade_SUITE.erl @@ -19,6 +19,8 @@ %% -module(ssl_upgrade_SUITE). +-behaviour(ct_suite). + -include_lib("common_test/include/ct.hrl"). %% Common test