def test_unicode_nfc_and_nfd_decomposition_equality(self): import unicodedata text = u'Hyv\xe4' assert_equals(unic(unicodedata.normalize('NFC', text)), text) # In Mac filesystem umlaut characters are presented in NFD-format. # This is to check that unic normalizes all strings to NFC assert_equals(unic(unicodedata.normalize('NFD', text)), text)
def _get_string_msg(self,str1,str2,msg,values,delim): default="'%s' %s '%s'" % (utils.unic(str1),delim,utils.unic(str2)) if not msg: msg = default elif values is True: msg ='%s:%s' %(msg,default) return msg
def start_keyword(self, kw): attrs = {'name': kw.kwname, 'library': kw.libname, 'type': kw.type} if kw.timeout: attrs['timeout'] = unicode(kw.timeout) self._writer.start('kw', attrs) self._write_list('tags', 'tag', (unic(t) for t in kw.tags)) self._writer.element('doc', kw.doc) self._write_list('arguments', 'arg', (unic(a) for a in kw.args)) self._write_list('assign', 'var', kw.assign)
def start_keyword(self, kw): attrs = {'name': kw.kwname, 'library': kw.libname} if kw.type != 'kw': attrs['type'] = kw.type self._writer.start('kw', attrs) self._write_list('tags', 'tag', [unic(t) for t in kw.tags]) self._writer.element('doc', kw.doc) self._write_list('arguments', 'arg', [unic(a) for a in kw.args]) self._write_list('assign', 'var', kw.assign)
def _list_dir(self, path): # os.listdir returns Unicode entries when path is Unicode names = os.listdir(utils.unic(path)) # http://bugs.jython.org/issue1593 if utils.is_jython: from java.lang import String names = [utils.unic(String(n)) for n in names] for name in sorted(names, key=unicode.lower): yield name, os.path.join(path, name)
def __init__(self, result): if not (is_dict_like(result) and 'status' in result): raise RuntimeError('Invalid remote result dictionary: %s' % result) self.status = result['status'] self.output = unic(self._get(result, 'output')) self.return_ = self._get(result, 'return') self.error = unic(self._get(result, 'error')) self.traceback = unic(self._get(result, 'traceback')) self.fatal = bool(self._get(result, 'fatal', False)) self.continuable = bool(self._get(result, 'continuable', False))
def dictionary_should_contain_item(self, dictionary, key, value, msg=None): """An item of ``key``/``value`` must be found in a `dictionary`. Value is converted to unicode for comparison. See `Lists Should Be Equal` for an explanation of ``msg``. The given dictionary is never altered by this keyword. """ self.dictionary_should_contain_key(dictionary, key, msg) actual, expected = unic(dictionary[key]), unic(value) default = "Value of dictionary key '%s' does not match: %s != %s" % (key, actual, expected) _verify_condition(actual == expected, default, msg)
def dictionary_should_contain_item(self, dictionary, key, value, msg=None): """An item of ``key`` / ``value`` must be found in a ``dictionary``. Value is converted to unicode for comparison. Use the ``msg`` argument to override the default error message. """ self._validate_dictionary(dictionary) self.dictionary_should_contain_key(dictionary, key, msg) actual, expected = unic(dictionary[key]), unic(value) default = "Value of dictionary key '%s' does not match: %s != %s" % (key, actual, expected) _verify_condition(actual == expected, default, msg)
def _keys_should_be_equal(self, dict1, dict2, msg, values): keys1 = self.get_dictionary_keys(dict1) keys2 = self.get_dictionary_keys(dict2) miss1 = [utils.unic(k) for k in keys2 if k not in dict1] miss2 = [utils.unic(k) for k in keys1 if k not in dict2] error = [] if miss1: error += ["Following keys missing from first dictionary: %s" % ", ".join(miss1)] if miss2: error += ["Following keys missing from second dictionary: %s" % ", ".join(miss2)] _verify_condition(error == [], "\n".join(error), msg, values) return keys1
def _list_dir(self, dir_path, incl_extensions, incl_suites): # os.listdir returns Unicode entries when path is Unicode names = os.listdir(unic(dir_path)) for name in sorted(names, key=lambda item: item.lower()): name = unic(name) # needed to handle nfc/nfd normalization on OSX path = os.path.join(dir_path, name) base, ext = os.path.splitext(name) ext = ext[1:].lower() if self._is_init_file(path, base, ext, incl_extensions): yield path, True elif self._is_included(path, base, ext, incl_extensions, incl_suites): yield path, False else: LOGGER.info("Ignoring file or directory '%s'." % name)
def _get_message(self, record): try: return record.getMessage(), None except: message = "Failed to log following message properly: %s" % utils.unic(record.msg) error = "\n".join(utils.get_error_details()) return message, error
def console(msg, newline=True, stream="stdout"): msg = unic(msg) if newline: msg += "\n" stream = sys.__stdout__ if stream.lower() != "stderr" else sys.__stderr__ stream.write(encode_output(msg)) stream.flush()
def replace_string(self, string, splitted=None, ignore_errors=False): """Replaces variables from a string. Result is always a string.""" if self._cannot_have_variables(string): return utils.unescape(string) result = [] if splitted is None: splitted = VariableSplitter(string, self._identifiers) while True: if splitted.identifier is None: result.append(utils.unescape(string)) break result.append(utils.unescape(string[:splitted.start])) try: value = self._get_variable(splitted) except DataError: if not ignore_errors: raise value = string[splitted.start:splitted.end] if not isinstance(value, unicode): value = utils.unic(value) result.append(value) string = string[splitted.end:] splitted = VariableSplitter(string, self._identifiers) result = ''.join(result) return result
def start_keyword(self, kw): attrs = {'name': kw.name, 'type': kw.type} if kw.timeout: attrs['timeout'] = unicode(kw.timeout) self._writer.start('kw', attrs) self._writer.element('doc', kw.doc) self._write_list('arguments', 'arg', (unic(a) for a in kw.args))
def console(msg, newline=True, stream='stdout'): msg = unic(msg) if newline: msg += '\n' stream = sys.__stdout__ if stream.lower() != 'stderr' else sys.__stderr__ stream.write(console_encode(msg, stream=stream)) stream.flush()
def replace_string(self, string, ignore_errors=False): """Replaces variables from a string. Result is always a string.""" if not is_string(string): return unic(string) if self._cannot_have_variables(string): return unescape(string) return self._replace_string(string, ignore_errors=ignore_errors)
def end_test(self, test): self._writer.element('doc', test.doc) self._write_list('tags', 'tag', test.tags) if test.timeout: self._writer.element('timeout', attrs={'value': unic(test.timeout)}) self._write_status(test, {'critical': 'yes' if test.critical else 'no'}) self._writer.end('test')
def _tracelog_args(self, logger, posargs, namedargs={}): if self._logger_not_available_during_library_init(logger): return args = [utils.safe_repr(a) for a in posargs] \ + ['%s=%s' % (utils.unic(a), utils.safe_repr(namedargs[a])) for a in namedargs] logger.trace('Arguments: [ %s ]' % ' | '.join(args))
def main(self, datasources, **options): settings = RobotSettings(options) LOGGER.register_console_logger(**settings.console_output_config) LOGGER.info('Settings:\n%s' % unic(settings)) builder = TestSuiteBuilder(settings['SuiteNames'], extension=settings.extension, rpa=settings.rpa) suite = builder.build(*datasources) settings.rpa = builder.rpa suite.configure(**settings.suite_config) if settings.pre_run_modifiers: suite.visit(ModelModifier(settings.pre_run_modifiers, settings.run_empty_suite, LOGGER)) with pyloggingconf.robot_handler_enabled(settings.log_level): old_max_error_lines = text.MAX_ERROR_LINES text.MAX_ERROR_LINES = settings.max_error_lines try: result = suite.run(settings) finally: text.MAX_ERROR_LINES = old_max_error_lines LOGGER.info("Tests execution ended. Statistics:\n%s" % result.suite.stat_message) if settings.log or settings.report or settings.xunit: writer = ResultWriter(settings.output if settings.log else result) writer.write_results(settings.get_rebot_settings()) return result.return_code
def _validate_variables(self, variables): for name, value in variables: if name.startswith('LIST__') and not is_list_like(value): # TODO: what to do with this error name = '@{%s}' % name[len('LIST__'):] raise DataError("List variable '%s' cannot get a non-list " "value '%s'" % (name, unic(value)))
def _yield_list_diffs(self, list1, list2, names): for index, (item1, item2) in enumerate(zip(list1, list2)): name = ' (%s)' % names[index] if index in names else '' try: assert_equals(item1, item2, msg='Index %d%s' % (index, name)) except AssertionError as err: yield unic(err)
def __init__(self, name, error, libname=None): self.name = name self.libname = libname self.error = unic(error) self.arguments = ArgumentSpec() self.timeout = '' self.tags = Tags()
def set_suite_metadata(self,name,value,append=False,top=False): if not isinstance(name,unicode): name = utils.unic(name) ns = self._get_namespace(top) metadata = ns.suite.metadata metadata[name] = self._get_possibly_appended_value(metadata.get(name,''), value,append) ns.variables.set_suite('${SUITE_METADATA}',metadata.copy()) self.log("Set suite metadata '%s' to value '%s'. " % (name,metadata[name]))
def _get_message(self, record): try: return record.getMessage(), None except: message = 'Failed to log following message properly: %s' \ % unic(record.msg) error = '\n'.join(get_error_details()) return message, error
def _normalize_message(self, msg): if callable(msg): return msg if not isinstance(msg, unicode): msg = utils.unic(msg) if "\r\n" in msg: msg = msg.replace("\r\n", "\n") return msg
def write(msg, level, html=False): # Callable messages allow lazy logging internally, but we don't want to # expose this functionality publicly. See the following issue for details: # http://code.google.com/p/robotframework/issues/detail?id=1505 if callable(msg): msg = unic(msg) if threading.currentThread().getName() in LOGGING_THREADS: LOGGER.log_message(Message(msg, level, html))
def _handle_java_numbers(self,item): if not utils.is_jython: return item if isinstance(item,String): return utils.unic(item) if isinstance(item,Number): return item.doubleValue() return item
def keyword_teardown(self, error): self.variables.set_keyword('${KEYWORD_STATUS}', 'FAIL' if error else 'PASS') self.variables.set_keyword('${KEYWORD_MESSAGE}', unic(error or '')) self.in_keyword_teardown += 1 try: yield finally: self.in_keyword_teardown -= 1
def _normalize_message(self, msg): if callable(msg): return msg if not isinstance(msg, unicode): msg = utils.unic(msg) if '\r\n' in msg: msg = msg.replace('\r\n', '\n') return msg
def _single_result(source, options): ets = ETSource(source) try: return ExecutionResultBuilder(ets, **options).build(Result(source)) except IOError as err: error = err.strerror except: error = get_error_message() raise DataError("Reading XML source '%s' failed: %s" % (unic(ets), error))
def _write(self, name, writer, path, *args): try: writer(path, *args) except DataError as err: LOGGER.error(err.message) except EnvironmentError as err: # `err.filename` can be different than `path` at least if reading # log/report templates or writing split log fails. # `unic` is needed due to http://bugs.jython.org/issue1825. LOGGER.error( "Writing %s file '%s' failed: %s: %s" % (name.lower(), path, err.strerror, unic(err.filename))) else: LOGGER.output_file(name, path)
def test_list_with_objects_containing_unicode_repr(self): objects = [UnicodeRepr(), UnicodeRepr()] result = unic(objects) if JYTHON: # This is actually wrong behavior assert_equal(result, '[Hyv\\xe4, Hyv\\xe4]') elif IRONPYTHON or PY3: # And so is this. assert_equal(result, '[Hyv\xe4, Hyv\xe4]') elif PY3: assert_equal(result, '[Hyv\xe4, Hyv\xe4]') else: expected = UnRepr.format('list', 'UnicodeEncodeError: ')[:-1] assert_true(result.startswith(expected))
def __init__(self, keyword, libname): self.name = keyword.name self.libname = libname self.doc = unic(keyword.doc) self.source = keyword.source self.lineno = keyword.lineno self.tags = keyword.tags self.arguments = UserKeywordArgumentParser().parse( tuple(keyword.args), self.longname) self._kw = keyword self.timeout = keyword.timeout self.body = keyword.body self.return_value = tuple(keyword.return_) self.teardown = keyword.teardown
def _build_suite(self, data, parent_defaults=None): defaults = TestDefaults(data.setting_table, parent_defaults) suite = TestSuite(name=data.name, source=data.source, doc=unic(data.setting_table.doc), metadata=self._get_metadata(data.setting_table)) self._build_setup(suite, data.setting_table.suite_setup) self._build_teardown(suite, data.setting_table.suite_teardown) for test_data in data.testcase_table.tests: self._build_test(suite, test_data, defaults) for child in data.children: suite.suites.append(self._build_suite(child, defaults)) ResourceFileBuilder().build(data, target=suite.resource) return suite
def dictionary_should_contain_sub_dictionary(self, dict1, dict2, msg=None, values=True): """Fails unless all items in ``dict2`` are found from ``dict1``. See `Lists Should Be Equal` for more information about configuring the error message with ``msg`` and ``values`` arguments. The given dictionaries are never altered by this keyword. """ keys = self.get_dictionary_keys(dict2) diffs = [unic(k) for k in keys if k not in dict1] default = "Following keys missing from first dictionary: %s" \ % ', '.join(diffs) _verify_condition(not diffs, default, msg, values) self._key_values_should_be_equal(keys, dict1, dict2, msg, values)
def end_suite(self, suite): self._suite.message = self._suite_status.message self._context.report_suite_status(self._suite.status, self._suite.full_message) with self._context.suite_teardown(): failure = self._run_teardown(suite.keywords.teardown, self._suite_status) if failure: self._suite.suite_teardown_failed(unic(failure)) self._suite_status.failure_occurred() self._suite.endtime = get_timestamp() self._suite.message = self._suite_status.message self._context.end_suite(ModelCombiner(suite, self._suite)) self._suite = self._suite.parent self._suite_status = self._suite_status.parent self._output.library_listeners.discard_suite_scope()
def __init__(self, library, handler_name, dynamic_method, doc='', argspec=None): self._argspec = argspec _RunnableHandler.__init__(self, library, handler_name, dynamic_method.method, utils.unic(doc or '')) self._run_keyword_method_name = dynamic_method.name self._supports_kwargs = dynamic_method.supports_kwargs if argspec and argspec[-1].startswith('**'): if not self._supports_kwargs: raise DataError("Too few '%s' method parameters for **kwargs " "support." % self._run_keyword_method_name)
def _get_variable_value(self, match, ignore_errors): match.resolve_base(self, ignore_errors) # TODO: Do we anymore need to reserve `*{var}` syntax for anything? if match.identifier == '*': logger.warn(r"Syntax '%s' is reserved for future use. Please " r"escape it like '\%s'." % (match, match)) return unic(match) try: value = self._variables[match] if match.items: value = self._get_variable_item(match, value) except DataError: if not ignore_errors: raise value = unescape(match.match) return value
def end_suite(self, suite): self._suite.message = self._suite_status.message self._context.report_suite_status(self._suite.status, self._suite.full_message) with self._context.suite_teardown(): failure = self._run_teardown(suite.keywords.teardown, self._suite_status) if failure: self._suite.suite_teardown_failed(unic(failure)) if self._suite.statistics.critical.failed: self._suite_status.critical_failure_occurred() self._suite.endtime = get_timestamp() self._suite.message = self._suite_status.message self._context.end_suite(self._suite) self._suite = self._suite.parent self._suite_status = self._suite_status.parent
def list_should_contain_sub_list(self, list1, list2, msg=None, values=True): """Fails if not all of the elements in ``list2`` are found in ``list1``. The order of values and the number of values are not taken into account. See `Lists Should Be Equal` for more information about configuring the error message with ``msg`` and ``values`` arguments. """ diffs = ', '.join(unic(item) for item in list2 if item not in list1) default = 'Following values were not found from first list: ' + diffs _verify_condition(not diffs, default, msg, values)
def _set_from_file(self, variables, overwrite, path): list_prefix = 'LIST__' for name, value in variables: if name.startswith(list_prefix): name = '@{%s}' % name[len(list_prefix):] try: if isinstance(value, basestring): raise TypeError value = list(value) except TypeError: raise DataError("List variable '%s' cannot get a non-list " "value '%s'" % (name, utils.unic(value))) else: name = '${%s}' % name if overwrite or not self.contains(name): self.set(name, value)
def dictionary_should_contain_sub_dictionary(self, dict1, dict2, msg=None, values=True): """Fails unless all items in `dict2` are found from `dict1`. See `Lists Should Be Equal` for an explanation of `msg`. The given dictionaries are never altered by this keyword. """ keys = self.get_dictionary_keys(dict2) diffs = [utils.unic(k) for k in keys if k not in dict1] default = "Following keys missing from first dictionary: %s" \ % ', '.join(diffs) _verify_condition(diffs == [], default, msg, values) self._key_values_should_be_equal(keys, dict1, dict2, msg, values)
def list_should_contain_sub_list(self, list1, list2, msg=None, values=True): """Fails if not all of the elements in ``list2`` are found in ``list1``. The order of values and the number of values are not taken into account. See the use of ``msg`` and ``values`` from the `Lists Should Be Equal` keyword. """ diffs = ', '.join(unic(item) for item in list2 if item not in list1) default = 'Following values were not found from first list: ' + diffs _verify_condition(not diffs, default, msg, values)
def convert_path(self, path_in, dir_out, format_in, format_out, root=None): root = root if root is not None else Path.cwd() # Override default docstring format if path_in in self.config.get("override_docstring", {}): self.logger.debug(f"Overriding docstring format for '{path_in}'") format_in = self.config["override_docstring"][path_in] # Override default output format if path_in in self.config.get("override_format", {}): self.logger.debug(f"Overriding output format for '{path_in}'") format_out = self.config["override_format"][path_in] converter = CONVERTERS[format_out] path_rel = path_in.with_suffix(converter.EXTENSION).relative_to(root) if self.config.get("collapse", False): path_rel = Path("_".join(part.lower() for part in path_rel.parts)) path_out = Path(dir_out) / path_rel path_out.parent.mkdir(parents=True, exist_ok=True) self.logger.debug("Converting '%s' to '%s'", path_in, path_out) libdoc = LibraryDocumentation(str(path_in), doc_format=format_in.upper()) # Override name with user-given value if self.config.get("title"): libdoc.name = self.config["title"] # Create module path for library, e.g. RPA.Excel.Files elif path_rel.parent != Path("."): libdoc.name = "{namespace}.{name}".format( namespace=str(path_rel.parent).replace(os.sep, "."), name=libdoc.name, ) # Convert library scope to RPA format if self.config.get("rpa", False): scope = normalize(unic(libdoc.scope), ignore="_") libdoc.scope = { "testcase": "Task", "testsuite": "Suite", "global": "Global", }.get(scope, "") converter().convert(libdoc, path_out)
def __unicode__(self): if self.kind == self.POSITIONAL_ONLY_MARKER: return '/' if self.kind == self.NAMED_ONLY_MARKER: return '*' ret = self.name if self.kind == self.VAR_POSITIONAL: ret = '*' + ret elif self.kind == self.VAR_NAMED: ret = '**' + ret if self.type is not self.NOTSET: ret = '%s: %s' % (ret, self.type_string) default_sep = ' = ' else: default_sep = '=' if self.default is not self.NOTSET: ret = '%s%s%s' % (ret, default_sep, unic(self.default)) return ret
def _build_suite(self, data, parent_defaults=None): if self._rpa_not_given and data.testcase_table.is_started(): self._set_execution_mode(data) self._check_deprecated_extensions(data.source) defaults = TestDefaults(data.setting_table, parent_defaults) suite = TestSuite(name=data.name, source=data.source, doc=unic(data.setting_table.doc), metadata=self._get_metadata(data.setting_table)) self._build_setup(suite, data.setting_table.suite_setup) self._build_teardown(suite, data.setting_table.suite_teardown) for test_data in data.testcase_table.tests: self._build_test(suite, test_data, defaults) for child in data.children: suite.suites.append(self._build_suite(child, defaults)) suite.rpa = self.rpa ResourceFileBuilder().build(data, target=suite.resource) return suite
def main(self, datasources, **options): settings = RobotSettings(options) LOGGER.register_console_logger(**settings.console_output_config) LOGGER.info('Settings:\n%s' % unic(settings)) suite = TestSuiteBuilder(settings['SuiteNames'], settings['WarnOnSkipped']).build(*datasources) suite.configure(**settings.suite_config) if settings.pre_run_modifiers: suite.visit(ModelModifier(settings.pre_run_modifiers, settings.run_empty_suite, LOGGER)) with pyloggingconf.robot_handler_enabled(settings.log_level): result = suite.run(settings) LOGGER.info("Tests execution ended. Statistics:\n%s" % result.suite.stat_message) if settings.log or settings.report or settings.xunit: writer = ResultWriter(settings.output if settings.log else result) writer.write_results(settings.get_rebot_settings()) return result.return_code
class ResultWriter(object): def __init__(self, *data_sources): self._data_sources = data_sources def write_results(self, settings, results=None): results = results or Results(self._data_sources, settings) if settings.output: self._write_output(results.result, settings.output) if settings.xunit: self._write_xunit(results.result, settings.xunit) if settings.log: config = dict(settings.log_config, minLevel=results.js_result.min_level) self._write_log(results.js_result, settings.log, config) if settings.report: results.js_result.remove_data_not_needed_in_report() self._write_report(results.js_result, settings.report, settings.report_config) return results.return_code def _write_output(self, result, path): self._write('Output', result.save, path) def _write_xunit(self, result, path): self._write('XUnit', XUnitWriter(result).write, path) def _write_log(self, js_result, path, config): self._write('Log', LogWriter(js_result).write, path, config) def _write_report(self, js_result, path, config): self._write('Report', ReportWriter(js_result).write, path, config) def _write(self, name, writer, path, *args): try: writer(path, *args) except DataError, err: LOGGER.error(unicode(err)) except EnvironmentError, err: # `err.filename` can be different than `path` at least if reading # log/report templates or writing split log fails. # `unic` is needed due to http://bugs.jython.org/issue1825. LOGGER.error("Writing %s file '%s' failed: %s: %s" % (name.lower(), path, err.strerror, unic(err.filename)))
def main(self, data_sources, **options): settings = RobotSettings(options) LOGGER.register_console_logger(**settings.console_output_config) LOGGER.info("Settings:\n%s" % unic(settings)) suite = TestSuiteBuilder(settings['SuiteNames'], settings['WarnOnSkipped'], settings['Extension']).build(*data_sources) suite.configure(**settings.suite_config) self._support_python_path(options) self._split_tests(suite) # 递归,找到所有的tests, 写入self.long_names self._assert_data_source( data_sources) # 只取第一个DataSource, 写入self.data_source self._assert_test_count() # 如果没有要测试的, 直接退出, 返回码: 1 self.output_dir = settings['OutputDir'] self.clean_output_dir() # 删掉主要输出目录下所有东东, 类似rm -rf self.output_dir self.log_debug_info(options) p_num = (int(options['processes']) if 'processes' in options else 2 * cpu_count()) start_time, end_time = self.parallel_run(options, p_num) self.merge_report(start_time, end_time)
def get_attributes(self, include_label=False, include_elapsed=False, exclude_empty=False, values_as_strings=False, html_escape=False): attrs = {'pass': self.passed, 'fail': self.failed} attrs.update(self._get_custom_attrs()) if include_label: attrs['label'] = self.name if include_elapsed: attrs['elapsed'] = elapsed_time_to_string(self.elapsed, include_millis=False) if exclude_empty: attrs = dict((k, v) for k, v in attrs.items() if v != '') if values_as_strings: attrs = dict((k, unic(v)) for k, v in attrs.items()) if html_escape: attrs = dict((k, self._html_escape(v)) for k, v in attrs.items()) return attrs
def _get_variable_value(self, match, ignore_errors): match.resolve_base(self, ignore_errors) # TODO: Do we anymore need to reserve `*{var}` syntax for anything? if match.identifier == '*': logger.warn(r"Syntax '%s' is reserved for future use. Please " r"escape it like '\%s'." % (match, match)) return unic(match) try: value = self._finder.find(match) if match.items: value = self._get_variable_item(match, value) try: value = self._validate_value(match, value) except VariableError: raise except: raise VariableError("Resolving variable '%s' failed: %s" % (match, get_error_message())) except DataError: if not ignore_errors: raise value = unescape(match.match) return value
def main(self, datasources, **options): for key, value in options.items(): if not value: options.pop(key) settings = RobotSettings(options) LOGGER.register_console_logger(**settings.console_output_config) LOGGER.info('Settings:\n%s' % unic(settings)) suite = TestSuiteBuilder(settings['SuiteNames'], settings['WarnOnSkipped'], settings['Extension']).build(*datasources) suite.configure(**settings.suite_config) data_sources = '"' + '" "'.join(datasources) + '"' logFolder = settings['OutputDir'] if options.has_key('processes'): p_num = int(options['processes']) else: p_num = 2 * cpu_count() #默认两倍cpu核数 longname = [] testnames = self._split_tests(suite, longname) #递归,找到所有的tests extra_options_cmd = self.unresolve_options(options) #运行前先清理环境,主要是把一些Output文件和图片文件清除 self.clear_env(logFolder) #生成并行运行命令并运行 self.parallel_run(testnames, logFolder, data_sources, extra_options_cmd, p_num) #合并报告 rebotCommand = 'rebot --outputdir "' + logFolder + '" --merge "' + logFolder + '/*_Output.xml"' print(rebotCommand) merge_proc = subprocess.Popen(rebotCommand, shell=True) merge_proc.communicate()
def main(self, datasources, **options): settings = RobotSettings(options) LOGGER.register_console_logger(**settings.console_output_config) if settings['Critical'] or settings['NonCritical']: LOGGER.warn( "Command line options --critical and --noncritical have been " "deprecated. Use --skiponfailure instead.") if settings['XUnitSkipNonCritical']: LOGGER.warn("Command line option --xunitskipnoncritical has been " "deprecated and has no effect.") LOGGER.info('Settings:\n%s' % unic(settings)) builder = TestSuiteBuilder(settings['SuiteNames'], included_extensions=settings.extension, rpa=settings.rpa, allow_empty_suite=settings.run_empty_suite) suite = builder.build(*datasources) settings.rpa = suite.rpa if settings.pre_run_modifiers: suite.visit( ModelModifier(settings.pre_run_modifiers, settings.run_empty_suite, LOGGER)) suite.configure(**settings.suite_config) with pyloggingconf.robot_handler_enabled(settings.log_level): old_max_error_lines = text.MAX_ERROR_LINES text.MAX_ERROR_LINES = settings.max_error_lines try: result = suite.run(settings) finally: text.MAX_ERROR_LINES = old_max_error_lines LOGGER.info("Tests execution ended. Statistics:\n%s" % result.suite.stat_message) if settings.log or settings.report or settings.xunit: writer = ResultWriter( settings.output if settings.log else result) writer.write_results(settings.get_rebot_settings()) return result.return_code
def test_skipped(self, reason): self.skipped = True self.failure.test_skipped = unic(reason)
def _skip_on_failure_message(self, failure): return test_or_task( "{Test} failed but its tags matched '--SkipOnFailure' and it was marked " "skipped.\n\nOriginal failure:\n%s" % unic(failure), rpa=self._rpa)
def _yield_dict_diffs(self, keys, dict1, dict2): for key in keys: try: assert_equal(dict1[key], dict2[key], msg='Key %s' % (key, )) except AssertionError as err: yield unic(err)
def _get_extra_attributes(self, kw): args = [a if is_string(a) else unic(a) for a in kw.args] return {'args': args, 'type': self._types[kw.type]}
def _get_attr(self, object, attr, default='', upper=False): value = unic(getattr(object, attr, default)) if upper: value = normalize(value, ignore='_').upper() return value
def _get_template(self, template): return unic(template) if template.is_active() else None
def _to_string(self, item): item = unic(item) if item is not None else '' return self._handle_string(item)