George Keishing | e7e9171 | 2021-09-03 11:28:44 -0500 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 2 | |
| 3 | r""" |
| 4 | Use robot framework API to extract test data from test suites. |
George Keishing | 8e86548 | 2025-03-14 21:59:52 +0530 | [diff] [blame] | 5 | Refer to https://robot-framework.readthedocs.io/en/latest/autodoc/robot.running.html |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 6 | """ |
| 7 | |
George Keishing | 37c58c8 | 2022-12-08 07:42:54 -0600 | [diff] [blame] | 8 | import os |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 9 | import sys |
| 10 | |
George Keishing | 8e86548 | 2025-03-14 21:59:52 +0530 | [diff] [blame] | 11 | from robot.api import SuiteVisitor, TestSuiteBuilder |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 12 | |
George Keishing | 37c58c8 | 2022-12-08 07:42:54 -0600 | [diff] [blame] | 13 | sys.path.append(os.path.join(os.path.dirname(__file__), "../lib")) |
| 14 | |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 15 | from gen_arg import * # NOQA |
| 16 | from gen_print import * # NOQA |
| 17 | from gen_valid import * # NOQA |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 18 | |
| 19 | # Set exit_on_error for gen_valid functions. |
| 20 | set_exit_on_error(True) |
| 21 | |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 22 | valid_options = ["name", "tags", "doc", "all"] |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 23 | |
| 24 | parser = argparse.ArgumentParser( |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 25 | usage="%(prog)s [OPTIONS]", |
| 26 | description=( |
| 27 | ";%(prog)s will print test suite information to stdout. This " |
| 28 | " information consists of any and/or all of the following: " |
| 29 | " the suite name, test case names, tag names and doc" |
| 30 | " strings. Example for generated test case names " |
| 31 | " tests/test_basic_poweron.robot " |
| 32 | " Verify Front And Rear LED At Standby Power On Test" |
| 33 | " Check For Application Failures " |
| 34 | " Verify Uptime Average Against Threshold Test SSH" |
| 35 | " And IPMI Connections" |
| 36 | ), |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 37 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 38 | prefix_chars="-+", |
| 39 | ) |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 40 | |
| 41 | parser.add_argument( |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 42 | "--source_path", "-s", help="The robot test file or directory path." |
| 43 | ) |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 44 | |
| 45 | parser.add_argument( |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 46 | "--option", |
| 47 | "-o", |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 48 | default="name", |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 49 | help="Test case attribute name. This may be any one of the following:\n" |
| 50 | + sprint_var(valid_options), |
| 51 | ) |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 52 | |
| 53 | # Populate stock_list with options we want. |
| 54 | stock_list = [("test_mode", 0), ("quiet", 0), ("debug", 0)] |
| 55 | |
| 56 | |
George Keishing | 8e86548 | 2025-03-14 21:59:52 +0530 | [diff] [blame] | 57 | class TestPrint(SuiteVisitor): |
| 58 | |
| 59 | def __init__(self, option): |
| 60 | self.option = option |
| 61 | |
| 62 | def visit_test(self, test): |
| 63 | r""" |
| 64 | Print the test data from suite test object from option specified. |
| 65 | """ |
| 66 | if self.option == "name": |
| 67 | print(test.name) |
| 68 | elif self.option == "tags": |
| 69 | print(test.tags) |
| 70 | elif self.option == "doc": |
| 71 | print(test.doc) |
| 72 | elif self.option == "all": |
| 73 | print(test.name) |
| 74 | print(test.tags) |
| 75 | print(test.doc) |
| 76 | |
| 77 | |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 78 | def exit_function(signal_number=0, frame=None): |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 79 | r""" |
| 80 | Execute whenever the program ends normally or with the signals that we |
| 81 | catch (i.e. TERM, INT). |
| 82 | """ |
| 83 | |
| 84 | dprint_executing() |
| 85 | |
| 86 | dprint_var(signal_number) |
| 87 | |
| 88 | qprint_pgm_footer() |
| 89 | |
| 90 | |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 91 | def signal_handler(signal_number, frame): |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 92 | r""" |
| 93 | Handle signals. Without a function to catch a SIGTERM or SIGINT, the |
| 94 | program would terminate immediately with return code 143 and without |
| 95 | calling the exit_function. |
| 96 | """ |
| 97 | |
| 98 | # Our convention is to set up exit_function with atexit.register() so |
| 99 | # there is no need to explicitly call exit_function from here. |
| 100 | |
| 101 | dprint_executing() |
| 102 | |
| 103 | # Calling exit prevents us from returning to the code that was running |
| 104 | # when the signal was received. |
| 105 | exit(0) |
| 106 | |
| 107 | |
| 108 | def validate_parms(): |
| 109 | r""" |
| 110 | Validate program parameters, etc. Return True or False (i.e. pass/fail) |
| 111 | accordingly. |
| 112 | """ |
| 113 | |
| 114 | valid_path(source_path) |
| 115 | |
| 116 | valid_value(option, valid_values=valid_options) |
| 117 | |
| 118 | gen_post_validation(exit_function, signal_handler) |
| 119 | |
| 120 | |
| 121 | def parse_test_suites(source_path, option): |
| 122 | r""" |
| 123 | Parse the robot files and extract test data output. |
| 124 | |
| 125 | Description of argument(s): |
| 126 | source_path The path to a robot file or a directory of robot files. |
| 127 | option Test case attribute instances such as "name", |
| 128 | "tags" or "doc". |
| 129 | """ |
| 130 | if os.path.isfile(source_path): |
| 131 | file_paths = [source_path] |
| 132 | else: |
Patrick Williams | 20f3871 | 2022-12-08 06:18:26 -0600 | [diff] [blame] | 133 | file_paths = [ |
| 134 | os.path.join(path, file) |
| 135 | for (path, dirs, files) in os.walk(source_path) |
| 136 | for file in files |
| 137 | ] |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 138 | |
| 139 | for file_path in file_paths: |
George Keishing | bfa859a | 2020-04-02 00:38:24 -0500 | [diff] [blame] | 140 | print(file_path) |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 141 | if "__init__.robot" in file_path: |
| 142 | continue |
George Keishing | 8e86548 | 2025-03-14 21:59:52 +0530 | [diff] [blame] | 143 | test_suite_obj = TestSuiteBuilder().build(file_path) |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 144 | parse_test_file(test_suite_obj, option) |
| 145 | |
| 146 | |
| 147 | def parse_test_file(test_suite_obj, option): |
| 148 | r""" |
| 149 | Extract test information from test suite object and print it to stdout in |
| 150 | the following format: |
| 151 | |
| 152 | <Test Case name> |
| 153 | <Test Tags name> |
| 154 | <Test Documentation> |
| 155 | |
| 156 | Description of argument(s): |
| 157 | test_suite_obj Test data suite object. |
| 158 | option Test case attribute instances such as "name", |
| 159 | "tags" or "doc". |
| 160 | """ |
| 161 | |
George Keishing | 8e86548 | 2025-03-14 21:59:52 +0530 | [diff] [blame] | 162 | test_suite_obj.visit(TestPrint(option)) |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 163 | |
| 164 | |
| 165 | def main(): |
George Keishing | 13bdbff | 2018-05-31 02:52:22 -0500 | [diff] [blame] | 166 | gen_get_options(parser, stock_list) |
| 167 | |
| 168 | validate_parms() |
| 169 | |
| 170 | qprint_pgm_header() |
| 171 | |
| 172 | parse_test_suites(source_path, option) |
| 173 | |
| 174 | return True |
| 175 | |
| 176 | |
| 177 | # Main |
| 178 | main() |