|
| 1 | +# Copyright 2008 Nokia Siemens Networks Oyj |
| 2 | +# |
| 3 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +# you may not use this file except in compliance with the License. |
| 5 | +# You may obtain a copy of the License at |
| 6 | +# |
| 7 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +# |
| 9 | +# Unless required by applicable law or agreed to in writing, software |
| 10 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +# See the License for the specific language governing permissions and |
| 13 | +# limitations under the License. |
| 14 | + |
| 15 | + |
| 16 | +import sys |
| 17 | +import os |
| 18 | +import glob |
| 19 | + |
| 20 | +if __name__ == '__main__': |
| 21 | + sys.stderr.write("Use 'runner' or 'rebot' for executing.\n") |
| 22 | + sys.exit(252) # 252 == DATA_ERROR |
| 23 | + |
| 24 | +import pythonpathsetter |
| 25 | +from output import Output, SystemLogger |
| 26 | +from conf import RobotSettings, RebotSettings |
| 27 | +from running import TestSuite |
| 28 | +from serializing import RobotTestOutput, RebotTestOutput, SplitIndexTestOutput |
| 29 | +from errors import DataError, INFO_PRINTED, DATA_ERROR, FRAMEWORK_ERROR |
| 30 | +from variables import init_global_variables |
| 31 | +import utils |
| 32 | + |
| 33 | +__version__ = utils.version |
| 34 | + |
| 35 | + |
| 36 | +def run_from_cli(args, usage): |
| 37 | + options, datasources = _process_arguments(args, usage, 'Robot') |
| 38 | + try: |
| 39 | + suite = run(*datasources, **options) |
| 40 | + except DataError: |
| 41 | + _exit(DATA_ERROR, *utils.get_error_details()) |
| 42 | + except KeyboardInterrupt: |
| 43 | + _exit(FRAMEWORK_ERROR, 'Test execution stopped by user') |
| 44 | + except: |
| 45 | + raise |
| 46 | + _exit(FRAMEWORK_ERROR, 'Unexpected error in test execution', |
| 47 | + '\n'.join(utils.get_error_details())) |
| 48 | + else: |
| 49 | + _exit(suite) |
| 50 | + |
| 51 | + |
| 52 | +def rebot_from_cli(args, usage): |
| 53 | + options, datasources = _process_arguments(args, usage, 'Rebot') |
| 54 | + try: |
| 55 | + suite = rebot(*datasources, **options) |
| 56 | + except DataError: |
| 57 | + _exit(DATA_ERROR, *utils.get_error_details()) |
| 58 | + except KeyboardInterrupt: |
| 59 | + _exit(FRAMEWORK_ERROR, 'Log/report generation stopped by user') |
| 60 | + except: |
| 61 | + _exit(FRAMEWORK_ERROR, 'Unexpected error in log/report generation', |
| 62 | + '\n'.join(utils.get_error_details())) |
| 63 | + else: |
| 64 | + _exit(suite) |
| 65 | + |
| 66 | + |
| 67 | +def run(*datasources, **options): |
| 68 | + """Executes given Robot data sources with given options. |
| 69 | + |
| 70 | + Data sources are paths to files and directories, similarly as when running |
| 71 | + pybot/jybot from command line. Options are given as keywords arguments and |
| 72 | + their names are same as long command line options without hyphens. |
| 73 | + |
| 74 | + Examples: |
| 75 | + run('/path/to/tests.html') |
| 76 | + run('/path/to/tests.html', '/path/to/tests2.html', log='mylog.html') |
| 77 | + |
| 78 | + Equivalent command line usage: |
| 79 | + pybot /path/to/tests.html |
| 80 | + pybot --log mylog.html /path/to/tests.html /path/to/tests2.html |
| 81 | + """ |
| 82 | + settings = RobotSettings(options) |
| 83 | + output = Output(settings) |
| 84 | + settings.report_errors(output.syslog) |
| 85 | + init_global_variables(settings, output.syslog) |
| 86 | + _syslog_start_info('Robot', datasources, settings, output.syslog) |
| 87 | + suite = TestSuite(datasources, settings, output.syslog) |
| 88 | + suite.run(output) |
| 89 | + output.syslog.info("Tests executed successfully. Statistics:\n%s" |
| 90 | + % suite.get_stat_message()) |
| 91 | + testoutput = RobotTestOutput(suite, output.syslog, settings) |
| 92 | + output.close1(suite) |
| 93 | + if settings.is_rebot_needed(): |
| 94 | + datasources, settings = settings.get_rebot_datasources_and_settings() |
| 95 | + if settings['SplitOutputs'] > 0: |
| 96 | + testoutput = SplitIndexTestOutput(suite, datasources[0], settings) |
| 97 | + else: |
| 98 | + testoutput = RebotTestOutput(datasources, settings, output.syslog) |
| 99 | + testoutput.serialize(settings, output.syslog) |
| 100 | + output.close2() |
| 101 | + return suite |
| 102 | + |
| 103 | + |
| 104 | +def rebot(*datasources, **options): |
| 105 | + """Creates reports/logs from given Robot output files with given options. |
| 106 | + |
| 107 | + Given input files are paths to Robot output files similarly as when running |
| 108 | + rebot from command line. Options are given as keywords arguments and |
| 109 | + their names are same as long command line options without hyphens. |
| 110 | + |
| 111 | + Examples: |
| 112 | + rebot('/path/to/output.xml') |
| 113 | + rebot('/path/out1.xml', '/path/out2.xml', report='myrep.html', log='NONE') |
| 114 | + |
| 115 | + Equivalent command line usage: |
| 116 | + rebot /path/to/output.xml |
| 117 | + rebot --report myrep.html --log NONE /path/out1.xml /path/out2.xml |
| 118 | + """ |
| 119 | + settings = RebotSettings(options) |
| 120 | + syslog = SystemLogger(settings) |
| 121 | + settings.report_errors(syslog) |
| 122 | + _syslog_start_info('Rebot', datasources, settings, syslog) |
| 123 | + testoutput = RebotTestOutput(datasources, settings, syslog) |
| 124 | + testoutput.serialize(settings, syslog, 'Rebot') |
| 125 | + syslog.close() |
| 126 | + return testoutput.suite |
| 127 | + |
| 128 | + |
| 129 | +def _syslog_start_info(who, sources, settings, syslog): |
| 130 | + syslog.info(utils.get_full_version(who)) |
| 131 | + syslog.info('Settings:\n%s' % settings) |
| 132 | + syslog.info('Starting processing data source%s %s' |
| 133 | + % (utils.plural_or_not(sources), utils.seq2str(sources))) |
| 134 | + |
| 135 | + |
| 136 | +def _process_arguments(cliargs, usage, who): |
| 137 | + ap = utils.ArgumentParser(usage) |
| 138 | + ppath = who == 'Robot' and 'pythonpath' or None |
| 139 | + try: |
| 140 | + opts, args = ap.parse_args(cliargs, argfile='argumentfile', |
| 141 | + unescape='escape', pythonpath=ppath) |
| 142 | + except DataError, err: |
| 143 | + _exit(DATA_ERROR, str(err)) |
| 144 | + if opts['help']: |
| 145 | + _print_help(usage) |
| 146 | + if opts['version']: |
| 147 | + _print_version(who) |
| 148 | + return opts, _process_datasources(args, who) |
| 149 | + |
| 150 | + |
| 151 | +def _process_datasources(sources, who): |
| 152 | + type_ = who == 'Robot' and 'Robot data source' or 'Robot output file' |
| 153 | + if len(sources) == 0: |
| 154 | + _exit(DATA_ERROR, 'No %ss given.' % type_) |
| 155 | + if utils.is_windows: |
| 156 | + temp = [] |
| 157 | + for path in sources: |
| 158 | + paths = glob.glob(path) |
| 159 | + if len(paths) > 0: |
| 160 | + temp.extend(paths) |
| 161 | + else: |
| 162 | + temp.append(path) |
| 163 | + sources = temp |
| 164 | + for path in sources: |
| 165 | + if not (os.path.exists(path) or utils.is_url(path)): |
| 166 | + _exit(DATA_ERROR, "%s '%s' does not exist." % (type_, path)) |
| 167 | + return sources |
| 168 | + |
| 169 | + |
| 170 | +def _print_help(usage): |
| 171 | + indent = 26 |
| 172 | + escapes = ', '.join(utils.argumentparser.get_escapes()) |
| 173 | + escapes = utils.wrap('Available escapes: '+escapes, 80-indent, indent) |
| 174 | + print usage.replace('\\','') % {'ESCAPES': escapes, 'VERSION': utils.version} |
| 175 | + _exit(INFO_PRINTED) |
| 176 | + |
| 177 | + |
| 178 | +def _print_version(who): |
| 179 | + print utils.get_full_version(who) |
| 180 | + _exit(INFO_PRINTED) |
| 181 | + |
| 182 | + |
| 183 | +def _exit(rc_or_suite, error=None, details=None): |
| 184 | + """Exits with given rc or rc from given output. Syslogs error if given. |
| 185 | + |
| 186 | + Exit code is the number of failed critical tests or error number. |
| 187 | + 0 - Tests executed and all critical tests passed |
| 188 | + 1-250 - Tests executed but returned number of critical tests failed |
| 189 | + (250 means 250 or more failures) |
| 190 | + 251 - Help or version info was printed |
| 191 | + 252 - Invalid test data or command line arguments |
| 192 | + 255 - Internal and unexpected error occurred in the framework itself |
| 193 | + """ |
| 194 | + if utils.is_integer(rc_or_suite): |
| 195 | + rc = rc_or_suite |
| 196 | + if error is not None: |
| 197 | + from robot.output import SYSLOG |
| 198 | + if SYSLOG is None: |
| 199 | + SYSLOG = SystemLogger() |
| 200 | + if rc == DATA_ERROR: |
| 201 | + error += '\n\nTry --help for usage information.' |
| 202 | + SYSLOG.error(error) |
| 203 | + if details is not None: |
| 204 | + SYSLOG.info(details) |
| 205 | + else: |
| 206 | + rc = rc_or_suite.critical_stats.failed |
| 207 | + if rc > 250: |
| 208 | + rc = 250 |
| 209 | + sys.exit(rc) |
0 commit comments