def prepare_test_tender_data(procedure_intervals, tender_parameters): # Get actual intervals by mode name mode = tender_parameters['mode'] if mode in procedure_intervals: intervals = procedure_intervals[mode] else: intervals = procedure_intervals['default'] LOGGER.log_message(Message(intervals)) tender_parameters['intervals'] = intervals # Set acceleration value for certain modes assert isinstance(intervals['accelerator'], int), \ "Accelerator should be an 'int', " \ "not '{}'".format(type(intervals['accelerator']).__name__) assert intervals['accelerator'] >= 0, \ "Accelerator should not be less than 0" if mode == 'negotiation': return munchify({'data': test_tender_data_limited(tender_parameters)}) elif mode == 'negotiation.quick': return munchify({'data': test_tender_data_limited(tender_parameters)}) elif mode == 'openeu': return munchify({'data': test_tender_data_openeu(tender_parameters)}) elif mode == 'openua': return munchify({'data': test_tender_data_openua(tender_parameters)}) elif mode == 'open_competitive_dialogue': return munchify({'data': test_tender_data_competitive_dialogue(tender_parameters)}) elif mode == 'reporting': return munchify({'data': test_tender_data_limited(tender_parameters)}) elif mode == 'belowThreshold': return munchify({'data': test_tender_data(tender_parameters)}) raise ValueError("Invalid mode for prepare_test_tender_data")
def _get_multisource_suite(datasources, include_suites): suitedatas = [] for datasource in datasources: try: suitedatas.append(_parse_suite(datasource, include_suites)) except DataError, err: LOGGER.info(err)
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 _get_variable(self, var): """'var' is an instance of a VariableSplitter""" # 1) Handle reserved syntax if var.identifier not in ['$','@','%']: value = '%s{%s}' % (var.identifier, var.base) LOGGER.warn("Syntax '%s' is reserved for future use. Please " "escape it like '\\%s'." % (value, value)) return value # 2) Handle environment variables elif var.identifier == '%': try: name = var.get_replaced_base(self).strip() if name != '': return os.environ[name] else: return '%%{%s}' % var.base except KeyError: raise DataError("Environment variable '%s' does not exist" % name) # 3) Handle ${scalar} variables and @{list} variables without index elif var.index is None: name = '%s{%s}' % (var.identifier, var.get_replaced_base(self)) return self[name] # 4) Handle items from list variables e.g. @{var}[1] else: try: index = int(self.replace_string(var.index)) name = '@{%s}' % var.get_replaced_base(self) return self[name][index] except (ValueError, DataError, IndexError): raise DataError("Non-existing variable '@{%s}[%s]'" % (var.base, var.index))
def _release_and_log(self): stdout, stderr = self._release() if stdout: LOGGER.log_output(stdout) if stderr: LOGGER.log_output(stderr) sys.__stderr__.write(console_encode(stderr, stream=sys.__stderr__))
def _handle_deprecated_exit_for_loop(self, error): if self._get(error, 'EXIT_FOR_LOOP'): from robot.output import LOGGER LOGGER.warn("Support for using 'ROBOT_EXIT_FOR_LOOP' attribute to " "exit for loops is deprecated in Robot Framework 2.8 " "and will be removed in 2.9.") raise ExitForLoop
def _get_variable(self, var): """'var' is an instance of a VariableSplitter""" # 1) Handle reserved syntax if var.identifier not in "$@%": value = "%s{%s}" % (var.identifier, var.base) LOGGER.warn("Syntax '%s' is reserved for future use. Please " "escape it like '\\%s'." % (value, value)) return value # 2) Handle environment variables and Java system properties elif var.identifier == "%": name = var.get_replaced_base(self).strip() if not name: return "%%{%s}" % var.base value = utils.get_env_var(name) if value is not None: return value value = getJavaSystemProperty(name) if value is not None: return value raise DataError("Environment variable '%s' does not exist" % name) # 3) Handle ${scalar} variables and @{list} variables without index elif var.index is None: name = "%s{%s}" % (var.identifier, var.get_replaced_base(self)) return self[name] # 4) Handle items from list variables e.g. @{var}[1] else: try: index = int(self.replace_string(var.index)) name = "@{%s}" % var.get_replaced_base(self) return self[name][index] except (ValueError, DataError, IndexError): raise DataError("Non-existing variable '@{%s}[%s]'" % (var.base, var.index))
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 _deprecate_escaped_cells_before_continuation(self, data): index = data.index(self._row_continuation_marker) if any(cell == '\\' for cell in data[:index]): LOGGER.warn("Error in file '%s': Escaping empty cells with " "'\\' before line continuation marker '...' is " "deprecated. Remove escaping before Robot " "Framework 3.2." % self.source)
def _get_multisource_suite(datasources, include_suites, warn_on_skipped): suitedatas = [] for datasource in datasources: try: suitedatas.append(_parse_suite(datasource, include_suites, warn_on_skipped)) except DataError, err: LOGGER.warn(err)
def log_object_data(data, file_name=None, format="yaml"): """Log object data in pretty format (JSON or YAML) Two output formats are supported: "yaml" and "json". If a file name is specified, the output is written into that file. If you would like to get similar output everywhere, use the following snippet somewhere in your code before actually using Munch. For instance, put it into your __init__.py, or, if you use zc.buildout, specify it in "initialization" setting of zc.recipe.egg. from munch import Munch Munch.__str__ = lambda self: Munch.toYAML(self, allow_unicode=True, default_flow_style=False) Munch.__repr__ = Munch.__str__ """ if not isinstance(data, Munch): data = munchify(data) if format.lower() == "json": data = data.toJSON(indent=2) else: data = data.toYAML(allow_unicode=True, default_flow_style=False) format = "yaml" LOGGER.log_message(Message(data.decode("utf-8"), "INFO")) if file_name: output_dir = BuiltIn().get_variable_value("${OUTPUT_DIR}") with open(os.path.join(output_dir, file_name + "." + format), "w") as file_obj: file_obj.write(data)
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 _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 import_resource(self, path): if path in self._resource_cache: LOGGER.info("Found resource file '%s' from cache" % path) else: resource = ResourceFileBuilder().build(path) self._resource_cache[path] = resource return self._resource_cache[path]
def import_resource(self, path): if self._resources.has_key(path): LOGGER.info("Found resource file '%s' from cache" % path) else: resource = ResourceFile(path) self._resources[path] = resource return self._resources[path]
def _get_multisource_suite(sources, include_suites, warn_on_skipped, process_variables): data = [] for src in sources: try: data.append(_parse_suite(src, include_suites, warn_on_skipped)) except DataError, err: LOGGER.warn(err)
def filter_empty_suites(self): for suite in self.suites[:]: suite.filter_empty_suites() if suite.get_test_count() == 0: self.suites.remove(suite) LOGGER.info("Running test suite '%s' failed: Test suite " "contains no test cases." % suite.source)
def _release_and_log(self): stdout, stderr = self._release() if stdout: LOGGER.log_output(stdout) if stderr: LOGGER.log_output(stderr) sys.__stderr__.write(encode_output(stderr+'\n'))
def import_resource(self, path): if path in self._resource_cache: LOGGER.info("Found resource file '%s' from cache" % path) else: resource = ResourceFile(path).populate() self._resource_cache[path] = resource return self._resource_cache[path]
def setUp(self): self._datafile = TestCaseFile() self._datafile.directory = '/path/to' self._populator = FromFilePopulator(self._datafile) self._logger = _MockLogger() LOGGER.disable_message_cache() LOGGER.register_logger(self._logger)
def prepare_test_tender_data(procedure_intervals, mode): # Get actual intervals by mode name if mode in procedure_intervals: intervals = procedure_intervals[mode] else: intervals = procedure_intervals['default'] LOGGER.log_message(Message(intervals)) # Set acceleration value for certain modes if mode in ['openua', 'openeu']: assert isinstance(intervals['accelerator'], int), \ "Accelerator should be an 'int', " \ "not '{}'".format(type(intervals['accelerator']).__name__) assert intervals['accelerator'] >= 0, \ "Accelerator should not be less than 0" else: assert 'accelerator' not in intervals.keys(), \ "Accelerator is not available for mode '{0}'".format(mode) if mode == 'single': return munchify({'data': test_tender_data(intervals)}) elif mode == 'multi': return munchify({'data': test_tender_data_multiple_items(intervals)}) elif mode == 'reporting': return munchify({'data': test_tender_data_limited(intervals, 'reporting')}) elif mode == 'negotiation': return munchify({'data': test_tender_data_limited(intervals, 'negotiation')}) elif mode == 'negotiation.quick': return munchify({'data': test_tender_data_limited(intervals, 'negotiation.quick')}) elif mode == 'openua': return munchify({'data': test_tender_data_openua(intervals)}) elif mode == 'openeu': return munchify({'data': test_tender_data_openeu(intervals)}) raise ValueError("Invalid mode for prepare_test_tender_data")
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 _deprecate_quoting(self, cell, path, line_number): if len(cell) > 1 and cell[0] == cell[-1] == '"': LOGGER.warn("TSV file '%s' has quotes around cells which is " "deprecated and must be fixed. Remove quotes " "from '%s' on line %d." % (path, cell, line_number)) return cell[1:-1].replace('""', '"').strip() return cell
def main(self, datasources, **options): settings = RebotSettings(options) LOGGER.register_console_logger(**settings.console_logger_config) LOGGER.disable_message_cache() rc = ResultWriter(*datasources).write_results(settings) if rc < 0: raise DataError('No outputs created.') return rc
def __init__(self, library_import=False): if library_import: LOGGER.enable_library_import_logging() self._library_import = library_import self._python_out = _PythonCapturer(stdout=True) self._python_err = _PythonCapturer(stdout=False) self._java_out = _JavaCapturer(stdout=True) self._java_err = _JavaCapturer(stdout=False)
def __init__(self, variables, suite, resource): LOGGER.info("Initializing namespace for test suite '%s'" % suite.longname) self.variables = variables self._imports = resource.imports self._kw_store = KeywordStore(resource) self._imported_variable_files = ImportCache() self._suite_name = suite.longname self._running_test = False
def import_library(self, name, args, alias, variables): lib = TestLibrary(name, args, variables, create_handlers=False) positional, named = lib.positional_args, lib.named_args lib = self._import_library(name, positional, named, lib) if alias and name != alias: lib = self._copy_library(lib, alias) LOGGER.info("Imported library '%s' with name '%s'" % (name, alias)) return lib
def _report_adding_keyword_failed(self, name, message=None, details=None, level=None): if not message: message, details = get_error_details() LOGGER.write( "Adding keyword '%s' to library '%s' failed: %s" % (name, self.name, message), level or self._failure_level ) if details: LOGGER.debug("Details:\n%s" % details)
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: self.handlers.add(handler, embedded) LOGGER.debug("Created keyword '%s'" % handler.name)
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))) else: LOGGER.output_file(name, path) class Results(object): def __init__(self, settings, *sources): self._settings = settings self._sources = sources if len(sources) == 1 and isinstance(sources[0], Result): self._result = sources[0] self._prune = False self.return_code = self._result.return_code else: self._result = None self._prune = True self.return_code = -1 self._js_result = None
def tearDown(self): LOGGER.unregister_logger(self.logger) signal.signal = self._orig_signal
def report_invalid_syntax(self, message, level='ERROR'): LOGGER.write( "Error in file '%s': Setting variable '%s' failed: %s" % (self.source or '<unknown>', self.name, message), level)
def _warn_about_registeration_error(self, signum, err): name, ctrlc = {signal.SIGINT: ('INT', 'or with Ctrl-C '), signal.SIGTERM: ('TERM', '')}[signum] LOGGER.warn('Registering signal %s failed. Stopping execution ' 'gracefully with this signal %sis not possible. ' 'Original error was: %s' % (name, ctrlc, err))
def visit_Error(self, node): LOGGER.error("Error in file '%s' on line %s: %s" % (self.source, node.lineno, node.error))
def _report_status(self): if self.setting_table or self.variable_table or self.keyword_table: LOGGER.info("Imported resource file '%s' (%d keywords)." % (self.source, len(self.keyword_table.keywords))) else: LOGGER.warn("Imported resource file '%s' is empty." % self.source)
def report_invalid_syntax(self, message, level='ERROR'): source = self.source or '<unknown>' line = ' on line %s' % self.lineno if self.lineno is not None else '' LOGGER.write("Error in file '%s'%s: %s" % (source, line, message), level)
def prepare_test_tender_data(procedure_intervals, tender_parameters, submissionMethodDetails, accelerator, funders): # Get actual intervals by mode name mode = tender_parameters['mode'] if mode in procedure_intervals: intervals = procedure_intervals[mode] else: intervals = procedure_intervals['default'] LOGGER.log_message(Message(intervals)) tender_parameters['intervals'] = intervals # Set acceleration value for certain modes assert isinstance(intervals['accelerator'], int), \ "Accelerator should be an 'int', " \ "not '{}'".format(type(intervals['accelerator']).__name__) assert intervals['accelerator'] >= 0, \ "Accelerator should not be less than 0" if mode == 'negotiation': return munchify({'data': test_tender_data_limited(tender_parameters)}) elif mode == 'negotiation.quick': return munchify({'data': test_tender_data_limited(tender_parameters)}) elif mode == 'openeu': return munchify({ 'data': test_tender_data_openeu(tender_parameters, submissionMethodDetails) }) elif mode == 'openua': return munchify({ 'data': test_tender_data_openua(tender_parameters, submissionMethodDetails) }) elif mode == 'openua_defense': return munchify({ 'data': test_tender_data_openua_defense(tender_parameters, submissionMethodDetails) }) elif mode == 'open_competitive_dialogue': return munchify({ 'data': test_tender_data_competitive_dialogue(tender_parameters, submissionMethodDetails) }) elif mode == 'reporting': return munchify({'data': test_tender_data_limited(tender_parameters)}) elif mode == 'open_framework': return munchify({ 'data': test_tender_data_framework_agreement(tender_parameters, submissionMethodDetails) }) elif mode == 'belowThreshold': return munchify({ 'data': test_tender_data(tender_parameters, submissionMethodDetails=submissionMethodDetails, funders=funders, accelerator=accelerator) }) elif mode == 'open_esco': return munchify({ 'data': test_tender_data_esco(tender_parameters, submissionMethodDetails) }) # The previous line needs an explicit keyword argument because, # unlike previous functions, this one has three arguments. raise ValueError("Invalid mode for prepare_test_tender_data")
def setUp(self): self.logger = LoggerStub() LOGGER._message_cache = [] LOGGER.register_logger(self.logger) self._orig_signal = signal.signal
def __enter__(self): if self._library_import: LOGGER.enable_library_import_logging() return self
def __exit__(self, exc_type, exc_value, exc_trace): self._release_and_log() if self._library_import: LOGGER.disable_library_import_logging() return False
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': %s" % (self.source, node.error))
def tearDown(self): LOGGER.unregister_logger(self._logger)
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 _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_invalid_syntax(self, message, level='ERROR'): initfile = getattr(self, 'initfile', None) path = os.path.join(self.source, initfile) if initfile else self.source LOGGER.write("Error in file '%s': %s" % (path, message), level)
def run(self, settings=None, **options): """Executes the suite based based the given ``settings`` or ``options``. :param settings: :class:`~robot.conf.settings.RobotSettings` object to configure test execution. :param options: Used to construct new :class:`~robot.conf.settings.RobotSettings` object if ``settings`` are not given. :return: :class:`~robot.result.executionresult.Result` object with information about executed suites and tests. If ``options`` are used, their names are the same as long command line options except without hyphens. Some options are ignored (see below), but otherwise they have the same semantics as on the command line. Options that can be given on the command line multiple times can be passed as lists like ``variable=['VAR1:value1', 'VAR2:value2']``. If such an option is used only once, it can be given also as a single string like ``variable='VAR:value'``. Additionally listener option allows passing object directly instead of listener name, e.g. ``run('tests.robot', listener=Listener())``. To capture stdout and/or stderr streams, pass open file objects in as special keyword arguments ``stdout`` and ``stderr``, respectively. Only options related to the actual test execution have an effect. For example, options related to selecting or modifying test cases or suites (e.g. ``--include``, ``--name``, ``--prerunmodifier``) or creating logs and reports are silently ignored. The output XML generated as part of the execution can be configured, though. This includes disabling it with ``output=None``. Example:: stdout = StringIO() result = suite.run(variable='EXAMPLE:value', output='example.xml', exitonfailure=True, stdout=stdout) print(result.return_code) To save memory, the returned :class:`~robot.result.executionresult.Result` object does not have any information about the executed keywords. If that information is needed, the created output XML file needs to be read using the :class:`~robot.result.resultbuilder.ExecutionResult` factory method. See the :mod:`package level <robot.running>` documentation for more examples, including how to construct executable test suites and how to create logs and reports based on the execution results. See the :func:`robot.run <robot.run.run>` function for a higher-level API for executing tests in files or directories. """ from .namespace import IMPORTER from .signalhandler import STOP_SIGNAL_MONITOR from .suiterunner import SuiteRunner with LOGGER: if not settings: settings = RobotSettings(options) LOGGER.register_console_logger( **settings.console_output_config) with pyloggingconf.robot_handler_enabled(settings.log_level): with STOP_SIGNAL_MONITOR: IMPORTER.reset() output = Output(settings) runner = SuiteRunner(output, settings) self.visit(runner) output.close(runner.result) return runner.result
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 build(self, path): LOGGER.info("Parsing resource file '%s'." % path) model = get_resource_model(path, data_only=True, process_curdir=self.process_curdir) return build_resource(model, path)
def _write(self, name, writer, path, *args): try: writer(path, *args) except DataError, err: LOGGER.error(unicode(err))
from StringIO import StringIO import os import unittest from robot.reporting.resultwriter import ResultWriter, Results from robot.output import LOGGER from robot.result.executionresult import Result from robot.result.executionerrors import ExecutionErrors from robot.result.testsuite import TestSuite from robot.utils.asserts import assert_true, assert_equals LOGGER.disable_automatic_console_logger() class TestReporting(unittest.TestCase): EXPECTED_SUITE_NAME = 'My Suite Name' EXPECTED_TEST_NAME = 'My Test Name' EXPECTED_KEYWORD_NAME = 'My Keyword Name' EXPECTED_FAILING_TEST = 'My Failing Test' EXPECTED_DEBUG_MESSAGE = '1111DEBUG777' EXPECTED_ERROR_MESSAGE = 'ERROR M355463' def test_no_generation(self): settings = StubSettings() results = StubResults(None, settings) rc = ResultWriter().write_results(settings, results) assert_equals(rc, -1) def test_only_output(self): output = ClosableOutput('output.xml') self._write_results(output=output)
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 run(self, settings=None, **options): """Executes the suite based based the given ``settings`` or ``options``. :param settings: :class:`~robot.conf.settings.RobotSettings` object to configure test execution. :param options: Used to construct new :class:`~robot.conf.settings.RobotSettings` object if ``settings`` are not given. :return: :class:`~robot.result.executionresult.Result` object with information about executed suites and tests. If ``options`` are used, their names are the same as long command line options except without hyphens, and they also have the same semantics. Options that can be given on the command line multiple times can be passed as lists like ``variable=['VAR1:value1', 'VAR2:value2']``. If such an option is used only once, it can be given also as a single string like ``variable='VAR:value'``. To capture stdout and/or stderr streams, pass open file objects in as special keyword arguments `stdout` and `stderr`, respectively. Note that this works only in version 2.8.4 and newer. Only options related to the actual test execution have an effect. For example, options related to selecting test cases or creating logs and reports are silently ignored. The output XML generated as part of the execution can be configured, though. This includes disabling it with ``output=None``. Example:: stdout = StringIO() result = suite.run(variable='EXAMPLE:value', critical='regression', output='example.xml', exitonfailure=True, stdout=stdout) print result.return_code To save memory, the returned :class:`~robot.result.executionresult.Result` object does not have any information about the executed keywords. If that information is needed, the created output XML file needs to be read using the :class:`~robot.result.resultbuilder.ExecutionResult` factory method. See the :mod:`package level <robot.running>` documentation for more examples, including how to construct executable test suites and how to create logs and reports based on the execution results. See the :func:`robot.run <robot.run.run>` function for a higher-level API for executing tests in files or directories. """ if not settings: settings = RobotSettings(options) LOGGER.register_console_logger(**settings.console_logger_config) with STOP_SIGNAL_MONITOR: IMPORTER.reset() pyloggingconf.initialize(settings['LogLevel']) init_global_variables(settings) output = Output(settings) runner = Runner(output, settings) self.visit(runner) output.close(runner.result) return runner.result
from __future__ import print_function import unittest from robot.output.listeners import Listeners from robot.output import LOGGER from robot.utils.asserts import * from robot.utils import JYTHON from robot.running.outputcapture import OutputCapturer LOGGER.unregister_console_logger() class _Mock: def __getattr__(self, name): return '' class SuiteMock(_Mock): def __init__(self): self.name = 'suitemock' self.doc = 'somedoc' self.status = 'PASS' self.tests = self.suites = [] stat_message = 'stat message' full_message = 'full message' class TestMock(_Mock): def __init__(self): self.name = 'testmock' self.doc = 'cod'
def _wrap(self, func, argser, kwargs): if type(func) == MethodType: if func.__name__ == 'import_library': q = [] errors = [] lib_cached = self.get_from_cache(argser[0], argser[1]) if lib_cached: q.append(lib_cached.result) errors = lib_cached.errors else: try: t = threading.Thread(target=self._imp, args=(func, q, errors, argser), kwargs=kwargs) t.setDaemon(True) t.start() t.join(timeout=self.lib_import_timeout) except: errors.append(sys.exc_info()) if len(q) > 0: result = q[0] else: try: result = TestLibrary(argser[0], argser[1], argser[2], create_handlers=False) except: try: result = _BaseTestLibrary(libcode=None, name=argser[0], args=argser[1], source=None, variables=argser[2]) except: try: result = _BaseTestLibrary(libcode=None, name=argser[0], args=[], source=None, variables=argser[3]) except: errors.append(sys.exc_info()) if lib_cached is None: lib = LibItem(argser[0], argser[1]) lib.result = result lib.errors = errors self.cached_lib_items.append(lib) for p in errors: msg = '{LIB_ERROR: ' + argser[ 0] + ', value: VALUE_START(' + str( p) + ')VALUE_END, lib_file_import:' + str( result.source) + '}' LOGGER.message(Message(message=msg, level='FAIL')) else: result = func(*argser, **kwargs) else: result = func(self.obj, *argser, **kwargs) self._handle_keywords(result) return result
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)
def _log_failed_parsing(self, message, warn): if warn: LOGGER.warn(message) else: LOGGER.info(message)
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 _get_reserved_variable(self, splitter): value = splitter.get_replaced_variable(self) LOGGER.warn("Syntax '%s' is reserved for future use. Please " "escape it like '\\%s'." % (value, value)) return value