def _write_log(self, js_result, path, config): try: LogWriter(js_result).write(path, config) except EnvironmentError, err: # Cannot use err.filename due to http://bugs.jython.org/issue1825 # and thus error has wrong file name if writing split log fails. LOGGER.error("Writing log file '%s' failed: %s" % (path, err.strerror))
def _process_tag_stat_link(self, value): tokens = value.split(':') if len(tokens) >= 3: return tokens[0], ':'.join(tokens[1:-1]), tokens[-1] LOGGER.error("Invalid format for option '--tagstatlink'. " "Expected 'tag:link:title' but got '%s'." % value) return None
def _table_is_allowed(self, table): if table is self.testcase_table: LOGGER.error( "Test suite init file in '%s' contains a test case " "table which is not allowed." % self.source ) return False return True
def _import_visitors(self, visitors): importer = Importer('pre-run visitor') for visitor, args in visitors: try: yield importer.import_class_or_module(visitor, args) except DataError as err: LOGGER.error(unicode(err))
def _convert_to_integer(self, name, value): try: return int(value) except ValueError: LOGGER.error("Option '--%s' expected integer value but got '%s'. " "Default value used instead." % (name.lower(), value)) return self._get_default_value(name)
def _process_report_background(self, colors): if colors.count(':') not in [1, 2]: LOGGER.error("Invalid report background colors '%s'." % colors) return self._get_default_value('ReportBackground') colors = colors.split(':') if len(colors) == 2: return colors[0], colors[0], colors[1] return tuple(colors)
def visit_suite(self, suite): for visitor in self._visitors: try: suite.visit(visitor) except: message, details = get_error_details() LOGGER.error("Executing pre-run visitor '%s' failed: %s\n%s" % (type_name(visitor), message, details))
def _resolve_background_colors(self, color_str): if color_str and color_str.count(':') not in [1, 2]: LOGGER.error("Invalid background color '%s'." % color_str) color_str = None if not color_str: color_str = '#99FF66:#FF3333' colors = color_str.split(':', 2) return colors if len(colors) == 3 else [colors[0], colors[0], colors[1]]
def _get_outfile(self, outpath, outtype): if outpath != 'NONE': try: return open(outpath, 'wb') except: LOGGER.error("Opening %s file '%s' for writing failed: %s" % (outtype, outpath, utils.get_error_message())) return None
def _populate_children(self, datadir, children, include_extensions, include_suites): for child in children: try: datadir.add_child(child, include_suites, include_extensions) except NoTestsFound: LOGGER.info("Data source '%s' has no tests or tasks." % child) except DataError as err: LOGGER.error("Parsing '%s' failed: %s" % (child, err.message))
def _process_tag_stat_link(self, value): ret = [] for item in value: tokens = item.split(':') if len(tokens) >= 3: ret.append((tokens[0], ':'.join(tokens[1:-1]), tokens[-1])) else: LOGGER.error("Invalid format for option '--tagstatlink'. " "Expected 'tag:link:title' but got '%s'." % item) return ret
def _process_deprecated_cli_opts(self, opts): for oldname, newname in self._deprecated.items(): if oldname not in opts or opts[oldname] in [None, []]: continue if newname: LOGGER.warn("Option '--%s' is deprecated. Use '--%s' instead." % (oldname, newname)) opts[newname] = opts[oldname] else: LOGGER.error("Option '--%s' has been removed." % oldname)
def populate(self, path, datadir, include_suites): LOGGER.info("Parsing test data directory '%s'" % path) include_sub_suites = self._get_include_suites(path, include_suites) initfile, children = self._get_children(path, include_sub_suites) datadir.initfile = initfile if initfile: try: FromFilePopulator(datadir).populate(initfile) except DataError, err: LOGGER.error(unicode(err))
def _write_file(self): try: with codecs.open(self._path, 'w', encoding='UTF-8') as outfile: writer = HTMLFileWriter(outfile, self._context.data_model) for line in _WebContentFile(self._template): writer.line(line) except EnvironmentError, err: LOGGER.error("Opening '%s' failed: %s" % (err.filename, err.strerror)) return False
def register_listeners(self): if self.has_listener: try: listeners = EXECUTION_CONTEXTS.current.output.library_listeners listeners.register(self.get_listeners(), self) except DataError as err: self.has_listener = False # Error should have information about suite where the # problem occurred but we don't have such info here. LOGGER.error("Registering listeners for library '%s' failed: %s" % (self.name, err))
def _close_listener(self, listener): method = (getattr(listener, 'close', None) or getattr(listener, '_close', None)) try: if method: method() except: message, details = get_error_details() name = getattr(listener, '__name__', None) or type_name(listener) LOGGER.error("Calling method '%s' of listener '%s' failed: %s" % (method.__name__, name, message)) LOGGER.info("Details:\n%s" % details)
def __init__(self, user_keywords, path=None): self.name = self._get_name_for_resource_file(path) self.handlers = utils.NormalizedDict(ignore=["_"]) self.embedded_arg_handlers = [] for kw in user_keywords: try: handler = EmbeddedArgsTemplate(kw, self.name) except DataError, err: LOGGER.error("Creating user keyword '%s' failed: %s" % (kw.name, unicode(err))) continue except TypeError: handler = UserKeywordHandler(kw, self.name)
def _get_children(self, dirpath, incl_extensions, incl_suites): init_file = None children = [] for path, is_init_file in self._list_dir(dirpath, incl_extensions, incl_suites): if is_init_file: if not init_file: init_file = path else: LOGGER.error("Ignoring second test suite init file '%s'." % path) else: children.append(path) return init_file, children
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 _get_children(self, dirpath, incl_suites): init_file = None children = [] for name, path in self._list_dir(dirpath): if self._is_init_file(name, path): if not init_file: init_file = path else: LOGGER.error("Ignoring second test suite init file '%s'." % path) elif self._is_included(name, path, incl_suites): children.append(path) else: LOGGER.info("Ignoring file or directory '%s'." % name) return init_file, children
def __init__(self, user_keywords, path=None): self.name = self._get_name_for_resource_file(path) self.handlers = utils.NormalizedDict(ignore=["_"]) self.embedded_arg_handlers = [] for kw in user_keywords: try: handler = self._create_handler(kw) except DataError, err: LOGGER.error("Creating user keyword '%s' failed: %s" % (kw.name, unicode(err))) continue if handler.name in self.handlers: error = "Keyword '%s' defined multiple times." % handler.name handler = UserErrorHandler(handler.name, error) self.handlers[handler.name] = handler
def _get_possibly_split_node(self, orig): src = orig.get('src') if not src: return orig # Support for split outputs generated with 2.5.x. path = os.path.join(os.path.dirname(orig.get('path')), src) try: node = utils.etreewrapper.get_root(path).find('suite') except: LOGGER.error("Opening split output '%s' failed: %s" % (path, utils.get_error_message())) return orig self._set_attrs_from_parent(node, orig) return node
def _create_handlers(self, libcode): for name in self._get_handler_names(libcode): method = self._try_to_get_handler_method(libcode, name) if method: handler, embedded = self._try_to_create_handler(name, method) if handler: try: self.handlers.add(handler, embedded) except DataError as err: LOGGER.error("Error in test library '%s': " "Creating keyword '%s' failed: %s" % (self.name, handler.name, err.message)) else: LOGGER.debug("Created keyword '%s'" % handler.name)
def __init__(self, user_keywords, path=None): self.name = self._get_name_for_resource_file(path) self.handlers = HandlerStore(self.name) for kw in user_keywords: try: handler, embedded = self._create_handler(kw) except DataError as err: LOGGER.error("Creating user keyword '%s' failed: %s" % (kw.name, unicode(err))) continue if handler.name in self.handlers: error = "Keyword '%s' defined multiple times." % handler.name handler = UserErrorHandler(handler.name, error) self.handlers.add(handler, embedded)
def __init__(self, user_keywords, path=None): basename = os.path.basename(path) if path else None self.name = os.path.splitext(basename)[0] if path else None self.handlers = HandlerStore(basename) for kw in user_keywords: try: handler, embedded = self._create_handler(kw) self._validate_not_duplicate(handler) except DataError as err: LOGGER.error("Creating user keyword '%s' failed: %s" % (kw.name, unicode(err))) handler = UserErrorHandler(kw.name, unicode(err)) embedded = False self.handlers.add(handler, embedded)
def _set_cli_vars(settings): for path, args in settings['VariableFiles']: try: GLOBAL_VARIABLES.set_from_file(path, args) except: msg, details = utils.get_error_details() LOGGER.error(msg) LOGGER.info(details) for varstr in settings['Variables']: try: name, value = varstr.split(':', 1) except ValueError: name, value = varstr, '' GLOBAL_VARIABLES['${%s}' % name] = value
def _set_cli_variables(self, settings): for path, args in settings.variable_files: try: path = find_file(path, file_type='Variable file') self.set_from_file(path, args) except: msg, details = get_error_details() LOGGER.error(msg) LOGGER.info(details) for varstr in settings.variables: try: name, value = varstr.split(':', 1) except ValueError: name, value = varstr, '' self['${%s}' % name] = value
def _get_output_file(self, option): """Returns path of the requested output file and creates needed dirs. `option` can be 'Output', 'Log', 'Report', 'XUnit' or 'DebugFile'. """ name = self._opts[option] if not name: return None if option == 'Log' and self._output_disabled(): self['Log'] = None LOGGER.error('Log file is not created if output.xml is disabled.') return None name = self._process_output_name(option, name) path = utils.abspath(os.path.join(self['OutputDir'], name)) self._create_output_dir(os.path.dirname(path), option) return path
def _create_handlers(self, libcode): try: names = self._get_handler_names(libcode) except: message, details = get_error_details() raise DataError( "Getting keyword names from library '%s' failed: %s" % (self.name, message), details) for name in names: method = self._try_to_get_handler_method(libcode, name) if method: handler, embedded = self._try_to_create_handler(name, method) if handler: try: self.handlers.add(handler, embedded) except DataError as err: LOGGER.error("Error in test library '%s': " "Creating keyword '%s' failed: %s" % (self.name, handler.name, err.message)) else: LOGGER.debug("Created keyword '%s'" % handler.name)
def _build_suite(self, structure): parent_defaults = self._stack[-1][-1] if self._stack else None source = structure.source defaults = TestDefaults(parent_defaults) parser = self._get_parser(structure.extension) try: if structure.is_directory: suite = parser.parse_init_file(structure.init_file or source, defaults) else: suite = parser.parse_suite_file(source, defaults) if not suite.tests: LOGGER.info("Data source '%s' has no tests or tasks." % source) self._validate_execution_mode(suite) except DataError as err: raise DataError("Parsing '%s' failed: %s" % (source, err.message)) if structure.is_directory and suite.tests: LOGGER.error("Test suite initialization file in '%s' cannot " "contain tests or tasks." % source) suite.tests.clear() return suite, defaults
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 visit_Error(self, node): LOGGER.error("Error in file '%s': %s" % (self.source, node.error))
def _populate_init_file(self, datadir, init_file): datadir.initfile = init_file try: FromFilePopulator(datadir).populate(init_file) except DataError, err: LOGGER.error(unicode(err))
def _log_creating_failed(self, handler, error): LOGGER.error( f"Error in file '{self.source}' on line {handler.lineno}: " f"Creating keyword '{handler.name}' failed: {error.message}")
def visit_Error(self, node): LOGGER.error("Error in file '%s' on line %s: %s" % (self.source, node.lineno, node.error))
def _valid_table(self, table): if table is self.testcase_table: LOGGER.error('Test case table not allowed in test suite init file.') return None return table
def _table_is_allowed(self, table): if table is self.testcase_table: LOGGER.error("Test suite initialization file in '%s' cannot " "contain tests or tasks." % self.source) return False return True
def visit_Error(self, node): for token in node.get_tokens(Token.ERROR): LOGGER.error("Error in file '%s' on line %s: %s" % (self.source, token.lineno, token.error))
def _write_report(self, js_result, path, config): try: ReportWriter(js_result).write(path, config) except EnvironmentError, err: LOGGER.error("Writing report file '%s' failed: %s" % (path, err.strerror))
def _write_xunit(self, result, path): try: result.visit(XUnitWriter(path)) except EnvironmentError, err: LOGGER.error("Opening XUnit result file '%s' failed: %s" % (path, err.strerror))
def _write_output(self, result, path): try: result.save(path) except DataError, err: LOGGER.error(unicode(err))
def _table_is_allowed(self, table): if table is self.testcase_table: LOGGER.error("Test suite init file in '%s' contains a test case " "table which is not allowed." % self.source) return False return True
def _report_error(self, token): # TODO: add line number LOGGER.error("Error in file '%s': %s" % (self.source, token.error))
def _log_creating_failed(self, handler, error): LOGGER.error("Error in %s '%s': Creating keyword '%s' failed: %s" % (self.source_type.lower(), self.source, handler.name, error.message))
def _report_ignored(self, item, test=False): from robot.output import LOGGER type = 'suite' if not test else 'test' LOGGER.error("Merged %s '%s' is ignored because it is not found from " "original result." % (type, item.longname))
class ResultWriter(object): """A class to create log, report, output XML and xUnit files. :param sources: Either one :class:`~robot.result.executionresult.Result` object, or one or more paths to existing output XML files. By default writes ``report.html`` and ``log.html``, but no output XML or xUnit files. Custom file names can be given and results disabled or enabled using ``settings`` or ``options`` passed to the :meth:`write_results` method. The latter is typically more convenient:: writer = ResultWriter(result) writer.write_results(report='custom.html', log=None, xunit='xunit.xml') """ def __init__(self, *sources): self._sources = sources def write_results(self, settings=None, **options): """Writes results based on the given ``settings`` or ``options``. :param settings: :class:`~robot.conf.settings.RebotSettings` object to configure result writing. :param options: Used to construct new :class:`~robot.conf.settings.RebotSettings` object if ``settings`` are not given. """ settings = settings or RebotSettings(options) results = Results(settings, *self._sources) if settings.output: self._write_output(results.result, settings.output) if settings.xunit: self._write_xunit(results.result, settings.xunit, settings.xunit_skip_noncritical) 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, skip_noncritical): self._write('XUnit', XUnitWriter(result, skip_noncritical).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 _log_creating_failed(self, handler, error): LOGGER.error("Error in %s '%s': Creating keyword '%s' failed: %s" % (self.source_type.lower(), self.source, handler.name, error.message))
def _write(self, name, writer, path, *args): try: writer(path, *args) except DataError, err: LOGGER.error(unicode(err))
def visit_Error(self, node): fatal = node.get_token(Token.FATAL_ERROR) if fatal: raise DataError(self._format_message(fatal)) for error in node.get_tokens(Token.ERROR): LOGGER.error(self._format_message(error))
def _populate_init_file(self, datadir, init_file): datadir.initfile = init_file try: FromFilePopulator(datadir).populate(init_file) except DataError as err: LOGGER.error(err.message)