class AllureBehaveListener(object): def __init__(self): self.allure_lifecycle = AllureReporter() def before_scenario(self, _, scenario): uuid = scenario_history_id(scenario) test_case = TestResult(uuid=uuid, start=now()) test_case.name = scenario_name(scenario) test_case.historyId = scenario_history_id(scenario) self.allure_lifecycle.schedule_test(uuid, test_case) def after_scenario(self, _, scenario): uuid = scenario_history_id(scenario) self.allure_lifecycle.close_test(uuid)
class AllureListener(object): def __init__(self, config): self.config = config self.allure_logger = AllureReporter() self._cache = ItemCache() @allure_commons.hookimpl def start_step(self, uuid, title, params): parameters = [ Parameter(name=name, value=value) for name, value in params ] step = TestStepResult(name=title, start=now(), parameters=parameters) self.allure_logger.start_step(None, uuid, step) @allure_commons.hookimpl def stop_step(self, uuid, exc_type, exc_val, exc_tb): status = Status.PASSED if exc_type is not None: if exc_type == pytest.skip.Exception: status = Status.SKIPPED else: status = Status.FAILED self.allure_logger.stop_step(uuid, stop=now(), status=status) @allure_commons.hookimpl def start_fixture(self, parent_uuid, uuid, name): after_fixture = TestAfterResult(name=name, start=now()) self.allure_logger.start_after_fixture(parent_uuid, uuid, after_fixture) @allure_commons.hookimpl def stop_fixture(self, uuid, exc_type, exc_val, exc_tb): self.allure_logger.stop_after_fixture(uuid, stop=now()) @pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_protocol(self, item, nextitem): uuid = self._cache.set(item.nodeid) for fixturedef in _test_fixtures(item): group_uuid = self._cache.get(fixturedef) if not group_uuid: group_uuid = self._cache.set(fixturedef) group = TestResultContainer(uuid=group_uuid) self.allure_logger.start_group(group_uuid, group) self.allure_logger.update_group(group_uuid, children=uuid) test_case = TestResult(name=item.name, uuid=uuid) self.allure_logger.schedule_test(uuid, test_case) yield test_case.labels += [ Label(name, value) for name, value in allure_labels(item) ] test_case.links += [ Link(link_type, url, name) for link_type, url, name in allure_links(item) ] test_case.labels += [ Label(LabelType.TAG, value) for value in pytest_markers(item) ] test_case.fullName = allure_full_name(item.nodeid) test_case.historyId = md5(test_case.fullName) test_case.labels.append(Label('package', allure_package(item.nodeid))) uuid = self._cache.pop(item.nodeid) self.allure_logger.close_test(uuid) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_call(self, item): uuid = self._cache.get(item.nodeid) self.allure_logger.update_test(uuid, start=now()) yield self.allure_logger.update_test(uuid, stop=now()) @pytest.hookimpl(hookwrapper=True) def pytest_fixture_setup(self, fixturedef, request): fixture_name = fixturedef.argname container_uuid = self._cache.get(fixturedef) if not container_uuid: container_uuid = self._cache.set(fixturedef) container = TestResultContainer(uuid=container_uuid) self.allure_logger.start_group(container_uuid, container) self.allure_logger.update_group(container_uuid, start=now()) before_fixture_uuid = uuid4() before_fixture = TestBeforeResult(name=fixture_name, start=now()) self.allure_logger.start_before_fixture(container_uuid, before_fixture_uuid, before_fixture) parameters = allure_parameters(fixturedef, request) if parameters: test_uuid = self._cache.get(request._pyfuncitem.nodeid) parameters = Parameter(**parameters) if parameters else [] self.allure_logger.update_test(test_uuid, parameters=parameters) yield self.allure_logger.stop_before_fixture(before_fixture_uuid, stop=now()) for index, finalizer in enumerate(fixturedef._finalizer or ()): name = u'{fixture}::{finalizer}'.format( fixture=fixturedef.argname, finalizer=finalizer.__name__) fixturedef._finalizer[index] = allure_commons.fixture( finalizer, parent_uuid=container_uuid, name=name) @pytest.hookimpl(hookwrapper=True) def pytest_fixture_post_finalizer(self, fixturedef): yield if hasattr(fixturedef, 'cached_result') and self._cache.get(fixturedef): container_uuid = self._cache.pop(fixturedef) self.allure_logger.stop_group(container_uuid, stop=now()) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(self, item, call): uuid = self._cache.set(item.nodeid) report = (yield).get_result() allure_item = self.allure_logger.get_item(uuid) status = allure_item.status or None status_details = None if call.excinfo and hasattr(call.excinfo.value, 'msg'): status_details = StatusDetails(message=call.excinfo.value.msg) elif hasattr(report, 'wasxfail'): status_details = StatusDetails(message=report.wasxfail) elif report.failed: status_details = StatusDetails(message=call.excinfo.exconly(), trace=report.longreprtext) if report.when == 'setup': if report.passed: status = Status.PASSED if report.failed: status = Status.BROKEN if report.skipped: status = Status.SKIPPED if report.when == 'call': if report.passed and status == Status.PASSED: pass if report.failed: status = Status.FAILED if report.skipped: status = Status.SKIPPED if report.when == 'teardown': if report.failed and status == Status.PASSED: status = Status.BROKEN if status_details: self.allure_logger.update_test(uuid, status=status, statusDetails=status_details) else: self.allure_logger.update_test(uuid, status=status) @allure_commons.hookimpl def attach_data(self, body, name, attachment_type, extension): self.allure_logger.attach_data(uuid4(), body, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def attach_file(self, source, name, attachment_type, extension): self.allure_logger.attach_file(uuid4(), source, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def add_link(self, url, link_type, name): self.allure_logger.update_test(None, links=[Link(link_type, url, name)]) @allure_commons.hookimpl def add_label(self, label_type, labels): for label in labels: self.allure_logger.update_test(None, labels=Label(label_type, label))
class AllureListener(object): def __init__(self, config): self.config = config self.allure_logger = AllureReporter() self._cache = ItemCache() self._host = host_tag() self._thread = thread_tag() @allure_commons.hookimpl def start_step(self, uuid, title, params): parameters = [ Parameter(name=name, value=value) for name, value in params.items() ] step = TestStepResult(name=title, start=now(), parameters=parameters) self.allure_logger.start_step(None, uuid, step) @allure_commons.hookimpl def stop_step(self, uuid, exc_type, exc_val, exc_tb): self.allure_logger.stop_step(uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details( exc_type, exc_val, exc_tb)) @allure_commons.hookimpl def start_fixture(self, parent_uuid, uuid, name): after_fixture = TestAfterResult(name=name, start=now()) self.allure_logger.start_after_fixture(parent_uuid, uuid, after_fixture) @allure_commons.hookimpl def stop_fixture(self, parent_uuid, uuid, name, exc_type, exc_val, exc_tb): self.allure_logger.stop_after_fixture(uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details( exc_type, exc_val, exc_tb)) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_setup(self, item): uuid = self._cache.set(item.nodeid) test_result = TestResult(name=item.name, uuid=uuid) self.allure_logger.schedule_test(uuid, test_result) yield uuid = self._cache.get(item.nodeid) test_result = self.allure_logger.get_test(uuid) for fixturedef in _test_fixtures(item): group_uuid = self._cache.get(fixturedef) if not group_uuid: group_uuid = self._cache.set(fixturedef) group = TestResultContainer(uuid=group_uuid) self.allure_logger.start_group(group_uuid, group) self.allure_logger.update_group(group_uuid, children=uuid) params = item.callspec.params if hasattr(item, 'callspec') else {} test_result.name = allure_name(item, params) test_result.description = allure_description(item) test_result.descriptionHtml = allure_description_html(item) test_result.fullName = allure_full_name(item) test_result.historyId = md5(test_result.fullName) test_result.parameters.extend([ Parameter(name=name, value=represent(value)) for name, value in params.items() ]) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_call(self, item): uuid = self._cache.get(item.nodeid) test_result = self.allure_logger.get_test(uuid) if test_result: test_result.start = now() yield if test_result: test_result.stop = now() @pytest.hookimpl(hookwrapper=True) def pytest_runtest_teardown(self, item): yield uuid = self._cache.get(item.nodeid) test_result = self.allure_logger.get_test(uuid) test_result.labels.extend([ Label(name=name, value=value) for name, value in allure_labels(item) ]) test_result.labels.extend([ Label(name=LabelType.TAG, value=value) for value in pytest_markers(item) ]) test_result.labels.extend([ Label(name=LabelType.TAG, value=value) for value in pytest_markers(item) ]) test_result.labels.extend([ Label(name=name, value=value) for name, value in allure_suite_labels(item) ]) test_result.labels.append(Label(name=LabelType.HOST, value=self._host)) test_result.labels.append( Label(name=LabelType.THREAD, value=self._thread)) test_result.labels.append( Label(name=LabelType.FRAMEWORK, value='pytest')) test_result.labels.append( Label(name=LabelType.LANGUAGE, value=platform_label())) test_result.labels.append( Label(name='package', value=allure_package(item))) test_result.links.extend([ Link(link_type, url, name) for link_type, url, name in allure_links(item) ]) @pytest.hookimpl(hookwrapper=True) def pytest_fixture_setup(self, fixturedef, request): fixture_name = fixturedef.argname container_uuid = self._cache.get(fixturedef) if not container_uuid: container_uuid = self._cache.set(fixturedef) container = TestResultContainer(uuid=container_uuid) self.allure_logger.start_group(container_uuid, container) self.allure_logger.update_group(container_uuid, start=now()) before_fixture_uuid = uuid4() before_fixture = TestBeforeResult(name=fixture_name, start=now()) self.allure_logger.start_before_fixture(container_uuid, before_fixture_uuid, before_fixture) outcome = yield self.allure_logger.stop_before_fixture( before_fixture_uuid, stop=now(), status=get_outcome_status(outcome), statusDetails=get_outcome_status_details(outcome)) finalizers = getattr(fixturedef, '_finalizers', []) for index, finalizer in enumerate(finalizers): name = '{fixture}::{finalizer}'.format(fixture=fixturedef.argname, finalizer=getattr( finalizer, "__name__", index)) finalizers[index] = allure_commons.fixture( finalizer, parent_uuid=container_uuid, name=name) @pytest.hookimpl(hookwrapper=True) def pytest_fixture_post_finalizer(self, fixturedef): yield if hasattr(fixturedef, 'cached_result') and self._cache.get(fixturedef): container_uuid = self._cache.pop(fixturedef) self.allure_logger.stop_group(container_uuid, stop=now()) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(self, item, call): uuid = self._cache.set(item.nodeid) report = (yield).get_result() test_result = self.allure_logger.get_test(uuid) status = get_pytest_report_status(report) status_details = None if call.excinfo: status_details = StatusDetails( message=escape_non_unicode_symbols(call.excinfo.exconly()), trace=escape_non_unicode_symbols(report.longreprtext)) if (status != Status.SKIPPED and not (call.excinfo.errisinstance(AssertionError) or call.excinfo.errisinstance(pytest.fail.Exception))): status = Status.BROKEN if status == Status.PASSED and hasattr(report, 'wasxfail'): reason = report.wasxfail message = 'XPASS {reason}'.format( reason=reason) if reason else 'XPASS' status_details = StatusDetails(message=message) if report.when == 'setup': test_result.status = status test_result.statusDetails = status_details if report.when == 'call': if test_result.status == Status.PASSED: test_result.status = status test_result.statusDetails = status_details if report.when == 'teardown': if status in (Status.FAILED, Status.BROKEN ) and test_result.status == Status.PASSED: test_result.status = status test_result.statusDetails = status_details if self.config.option.attach_capture: # Capture at teardown contains data from whole test (setup, call, teardown) self.attach_data(report.caplog, "log", AttachmentType.TEXT, None) self.attach_data(report.capstdout, "stdout", AttachmentType.TEXT, None) self.attach_data(report.capstderr, "stderr", AttachmentType.TEXT, None) uuid = self._cache.pop(item.nodeid) self.allure_logger.close_test(uuid) @allure_commons.hookimpl def attach_data(self, body, name, attachment_type, extension): self.allure_logger.attach_data(uuid4(), body, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def attach_file(self, source, name, attachment_type, extension): self.allure_logger.attach_file(uuid4(), source, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def add_title(self, test_title): test_result = self.allure_logger.get_test(None) if test_result: test_result.name = test_title @allure_commons.hookimpl def add_description(self, test_description): test_result = self.allure_logger.get_test(None) if test_result: test_result.description = test_description @allure_commons.hookimpl def add_description_html(self, test_description_html): test_result = self.allure_logger.get_test(None) if test_result: test_result.descriptionHtml = test_description_html @allure_commons.hookimpl def add_link(self, url, link_type, name): test_result = self.allure_logger.get_test(None) if test_result: pattern = dict(self.config.option.allure_link_pattern).get( link_type, u'{}') url = pattern.format(url) test_result.links.append(Link(link_type, url, name)) @allure_commons.hookimpl def add_label(self, label_type, labels): test_result = self.allure_logger.get_test(None) for label in labels if test_result else (): test_result.labels.append(Label(label_type, label))
class allure_robotframework(object): ROBOT_LISTENER_API_VERSION = 2 DEFAULT_OUTPUT_PATH = os.path.join('output', 'allure') LOG_MESSAGE_FORMAT = '{full_message}<p><b>[{level}]</b> {message}</p>' FAIL_MESSAGE_FORMAT = '{full_message}<p style="color: red"><b>[{level}]</b> {message}</p>' def __init__(self, logger_path=DEFAULT_OUTPUT_PATH): self.stack = [] self.items_log = {} self.pool_id = None self.links = OrderedDict() self._previous_keyword_failed = False self._traceback_message = None self.reporter = AllureReporter() self.listener = AllureListener(self.reporter) self.logger = AllureFileLogger(logger_path) allure_commons.plugin_manager.register(self.logger) allure_commons.plugin_manager.register(self.listener) def start_suite(self, name, attributes): if not self.pool_id: self.pool_id = BuiltIn().get_variable_value( '${PABOTEXECUTIONPOOLID}') self.pool_id = int(self.pool_id) if self.pool_id else 0 self.start_new_group(name, attributes) def end_suite(self, name, attributes): self.stop_current_group() def start_test(self, name, attributes): self.start_new_group(name, attributes) self.start_new_test(name, attributes) def end_test(self, name, attributes): self.stop_current_test(name, attributes) self.stop_current_group() def start_keyword(self, name, attributes): self.start_new_keyword(name, attributes) def end_keyword(self, name, attributes): self.end_current_keyword(name, attributes) def log_message(self, message): level = message.get('level') if self._previous_keyword_failed: self._traceback_message = message.get('message') self._previous_keyword_failed = False if level == RobotLogLevel.FAIL: self._previous_keyword_failed = True self.reporter.get_item( self.stack[-1]).statusDetails = StatusDetails( message=message.get('message')) self.append_message_to_last_item_log(message, level) def start_new_group(self, name, attributes): uuid = uuid4() self.set_suite_link(attributes.get('metadata'), uuid) if self.stack: parent_suite = self.reporter.get_last_item(TestResultContainer) parent_suite.children.append(uuid) self.stack.append(uuid) suite = TestResultContainer(uuid=uuid, name=name, description=attributes.get('doc'), start=now()) self.reporter.start_group(uuid, suite) def stop_current_group(self): uuid = self.stack.pop() self.remove_suite_link(uuid) self.reporter.stop_group(uuid, stop=now()) def start_new_test(self, name, attributes): uuid = uuid4() self.reporter.get_last_item(TestResultContainer).children.append(uuid) self.stack.append(uuid) test_case = TestResult(uuid=uuid, historyId=md5(attributes.get('longname')), name=name, fullName=attributes.get('longname'), start=now()) self.reporter.schedule_test(uuid, test_case) def stop_current_test(self, name, attributes): uuid = self.stack.pop() test = self.reporter.get_test(uuid) test.status = utils.get_allure_status(attributes.get('status')) test.labels.extend(utils.get_allure_suites(attributes.get('longname'))) test.labels.extend(allure_tags(attributes)) for label_type in (LabelType.EPIC, LabelType.FEATURE, LabelType.STORY): test.labels.extend(allure_labels(attributes, label_type)) for link_type in (LinkType.ISSUE, LinkType.TEST_CASE, LinkType.LINK): test.links.extend(allure_links(attributes, link_type)) test.labels.append(Label(name=LabelType.THREAD, value=self.pool_id)) test.labels.append(Label(name=LabelType.HOST, value=host_tag())) test.labels.append( Label(name=LabelType.FRAMEWORK, value='robotframework')) test.labels.append( Label(name=LabelType.LANGUAGE, value=platform_label())) test.statusDetails = StatusDetails(message=attributes.get('message'), trace=self.get_traceback_message()) test.description = attributes.get('doc') last_link = list(self.links.values())[-1] if self.links else None if attributes.get(Severity.CRITICAL, 'no') == 'yes': test.labels.append( Label(name=LabelType.SEVERITY, value=Severity.CRITICAL)) if last_link: test.links.append(Link(LinkType.LINK, last_link, 'Link')) test.stop = now() self.reporter.close_test(uuid) def start_new_keyword(self, name, attributes): uuid = uuid4() parent_uuid = self.stack[-1] step_name = '{} = {}'.format( attributes.get('assign')[0], name) if attributes.get('assign') else name args = { 'name': step_name, 'description': attributes.get('doc'), 'parameters': utils.get_allure_parameters(attributes.get('args')), 'start': now() } keyword_type = attributes.get('type') last_item = self.reporter.get_last_item() if keyword_type in RobotKeywordType.FIXTURES and not isinstance( last_item, TestStepResult): if isinstance(last_item, TestResult): parent_uuid = self.stack[-2] if keyword_type == RobotKeywordType.SETUP: self.reporter.start_before_fixture(parent_uuid, uuid, TestBeforeResult(**args)) elif keyword_type == RobotKeywordType.TEARDOWN: self.reporter.start_after_fixture(parent_uuid, uuid, TestAfterResult(**args)) self.stack.append(uuid) return self.stack.append(uuid) self.reporter.start_step(parent_uuid=parent_uuid, uuid=uuid, step=TestStepResult(**args)) def end_current_keyword(self, name, attributes): uuid = self.stack.pop() if uuid in self.items_log: self.reporter.attach_data(uuid=uuid4(), body=self.items_log.pop(uuid).replace( '\n', '<br>'), name='Keyword Log', attachment_type=AttachmentType.HTML) args = { 'uuid': uuid, 'status': utils.get_allure_status(attributes.get('status')), 'stop': now() } keyword_type = attributes.get('type') parent_item = self.reporter.get_last_item() if keyword_type in RobotKeywordType.FIXTURES and not isinstance( parent_item, TestStepResult): if keyword_type == RobotKeywordType.SETUP: self.reporter.stop_before_fixture(**args) return elif keyword_type == RobotKeywordType.TEARDOWN: self.reporter.stop_after_fixture(**args) return self.reporter.stop_step(**args) def append_message_to_last_item_log(self, message, level): full_message = self.items_log[ self.stack[-1]] if self.stack[-1] in self.items_log else '' message_format = self.FAIL_MESSAGE_FORMAT if level in RobotLogLevel.CRITICAL_LEVELS else self.LOG_MESSAGE_FORMAT self.items_log[self.stack[-1]] = message_format.format( full_message=full_message, level=message.get('level'), message=message.get('message')) def set_suite_link(self, metadata, uuid): if metadata: link = metadata.get('Link') if link: self.links[uuid] = link def remove_suite_link(self, uuid): if self.links.get(uuid): self.links.pop(uuid) def get_traceback_message(self): if BuiltIn().get_variable_value('${LOG LEVEL}') in ( RobotLogLevel.DEBUG, RobotLogLevel.TRACE): return self._traceback_message return None def close(self): for plugin in [self.logger, self.listener]: name = allure_commons.plugin_manager.get_name(plugin) allure_commons.plugin_manager.unregister(name=name)
class AllureListener(object): def __init__(self, result_dir): self.logger = AllureReporter() file_logger = AllureFileLogger(result_dir) plugin_manager.register(file_logger) plugin_manager.register(self) self.current_group_uuid = None self.current_before_uuid = None self.current_scenario_uuid = None self.current_step_uuid = None def start_group(self): self.current_group_uuid = uuid4() group = TestResultContainer(uuid=self.current_group_uuid, name='Background') self.logger.start_group(self.current_group_uuid, group) def stop_group(self): if self.current_group_uuid: self.logger.stop_group(self.current_group_uuid) self.current_group_uuid = None def update_group(self): if self.current_group_uuid: self.logger.update_group(self.current_group_uuid, children=self.current_scenario_uuid) def start_before(self, _, background): self.current_before_uuid = uuid4() before = TestBeforeResult(name=background.name or 'Background') self.logger.start_before_fixture(self.current_group_uuid, self.current_before_uuid, before) def stop_before(self, scenario, _): status = background_status(scenario) self.logger.stop_before_fixture(uuid=self.current_before_uuid, status=status) self.current_before_uuid = None def start_scenario(self, scenario): self.current_scenario_uuid = uuid4() test_case = TestResult(uuid=self.current_scenario_uuid, start=now()) test_case.name = scenario_name(scenario) test_case.historyId = scenario_history_id(scenario) test_case.description = '\n'.join(scenario.description) labels = [] feature_label = Label(name=LabelType.FEATURE.value, value=scenario.feature.name) severity = (Label(name=LabelType.SEVERITY.value, value=scenario_severity(scenario).value)) labels.append(feature_label) labels.append(severity) labels += [ Label(name=LabelType.TAG.value, value=tag) for tag in scenario_tags(scenario) ] test_case.parameters = scenario_parameters(scenario) test_case.labels = labels self.logger.schedule_test(self.current_scenario_uuid, test_case) self.update_group() def stop_scenario(self, scenario): status = scenario_status(scenario) status_details = scenario_status_details(scenario) self.logger.update_test(self.current_scenario_uuid, stop=now(), status=status, statusDetails=status_details) self.logger.close_test(self.current_scenario_uuid) self.current_scenario_uuid = None self.current_step_uuid = None def start_step(self, step): self.current_step_uuid = uuid4() name = u'{keyword} {title}'.format(keyword=step.keyword, title=step.name) parent_uuid = self.current_before_uuid or self.current_scenario_uuid allure_step = TestStepResult(name=name, start=now()) self.logger.start_step(parent_uuid, self.current_step_uuid, allure_step) if step.text: self.logger.attach_data(uuid4(), step.text, name='.text', attachment_type=AttachmentType.TEXT) if step.table: table = [','.join(step.table.headings)] [table.append(','.join(list(row))) for row in step.table.rows] self.logger.attach_data(uuid4(), '\n'.join(table), name='.table', attachment_type=AttachmentType.CSV) def stop_step(self, result): status = step_status(result) status_details = step_status_details(result) self.logger.stop_step(self.current_step_uuid, stop=now(), status=status, statusDetails=status_details) @hookimpl def attach_data(self, body, name, attachment_type, extension): self.logger.attach_data(uuid4(), body, name=name, attachment_type=attachment_type, extension=extension) @hookimpl def attach_file(self, source, name, attachment_type, extension): self.logger.attach_file(uuid4(), source, name=name, attachment_type=attachment_type, extension=extension)
class AllureListener(object): def __init__(self, behave_config): self.behave_config = behave_config self.logger = AllureReporter() self.current_step_uuid = None self.current_scenario_uuid = None self.execution_context = Context() self.fixture_context = Context() self.steps = deque() def __del__(self): for group in self.fixture_context.exit(): group.children.extend(self.execution_context) self.logger.stop_group(group.uuid) @allure_commons.hookimpl def start_fixture(self, parent_uuid, uuid, name, parameters): parameters = [ Parameter(name=param_name, value=param_value) for param_name, param_value in parameters.items() ] if name in FIXTURES and not self.fixture_context: group = TestResultContainer(uuid=uuid4()) self.logger.start_group(group.uuid, group) self.fixture_context.append(group) if name in BEFORE_FIXTURES: fixture = TestBeforeResult(name=name, start=now(), parameters=parameters) for group in self.fixture_context: self.logger.start_before_fixture(group.uuid, uuid, fixture) elif name in AFTER_FIXTURES: fixture = TestAfterResult(name=name, start=now(), parameters=parameters) for group in self.fixture_context: self.logger.start_after_fixture(group.uuid, uuid, fixture) @allure_commons.hookimpl def stop_fixture(self, parent_uuid, uuid, name, exc_type, exc_val, exc_tb): if name in FIXTURES: self.logger.stop_before_fixture(uuid=uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details( exc_type, exc_val, exc_tb)) def start_feature(self): self.execution_context.enter() self.fixture_context.enter() def stop_feature(self): uuids = self.execution_context.exit() for group in self.fixture_context.exit(): group.children.extend(uuids) self.logger.stop_group(group.uuid) self.execution_context.extend(uuids) @allure_commons.hookimpl def start_test(self, parent_uuid, uuid, name, parameters, context): self.start_scenario(context['scenario']) def start_scenario(self, scenario): self.current_scenario_uuid = uuid4() self.fixture_context.enter() self.execution_context.enter() self.execution_context.append(self.current_scenario_uuid) test_case = TestResult(uuid=self.current_scenario_uuid, start=now()) test_case.name = scenario_name(scenario) test_case.historyId = scenario_history_id(scenario) test_case.description = '\n'.join(scenario.description) test_case.parameters = scenario_parameters(scenario) test_case.links.extend(scenario_links(scenario)) test_case.labels.extend(scenario_labels(scenario)) test_case.labels.append( Label(name=LabelType.FEATURE, value=scenario.feature.name)) test_case.labels.append(Label(name=LabelType.FRAMEWORK, value='behave')) test_case.labels.append( Label(name=LabelType.LANGUAGE, value=platform_label())) self.logger.schedule_test(self.current_scenario_uuid, test_case) @allure_commons.hookimpl def stop_test(self, parent_uuid, uuid, name, context, exc_type, exc_val, exc_tb): self.stop_scenario(context['scenario']) def stop_scenario(self, scenario): if scenario.status == 'skipped' and not self.behave_config.show_skipped: self.logger.drop_test(self.current_scenario_uuid) else: status = scenario_status(scenario) status_details = scenario_status_details(scenario) self.flush_steps() test_result = self.logger.get_test(self.current_scenario_uuid) test_result.stop = now() test_result.status = status test_result.statusDetails = status_details self.logger.close_test(self.current_scenario_uuid) self.current_step_uuid = None for group in self.fixture_context.exit(): group.children.append(self.current_scenario_uuid) self.logger.stop_group(group.uuid) self.execution_context.exit() self.execution_context.append(self.current_scenario_uuid) self.current_scenario_uuid = None def schedule_step(self, step): self.steps.append(step) def match_step(self, match): step = self.steps.popleft() self.start_behave_step(step) def start_behave_step(self, step): self.current_step_uuid = uuid4() name = u'{keyword} {title}'.format(keyword=step.keyword, title=step.name) allure_step = TestStepResult(name=name, start=now()) self.logger.start_step(None, self.current_step_uuid, allure_step) if step.text: self.logger.attach_data(uuid4(), step.text, name='.text', attachment_type=AttachmentType.TEXT) if step.table: self.logger.attach_data(uuid4(), step_table(step), name='.table', attachment_type=AttachmentType.CSV) def stop_behave_step(self, result): status = step_status(result) status_details = step_status_details(result) self.logger.stop_step(self.current_step_uuid, stop=now(), status=status, statusDetails=status_details) def flush_steps(self): while self.steps: step = self.steps.popleft() self.start_behave_step(step) self.stop_behave_step(step) @allure_commons.hookimpl def start_step(self, uuid, title, params): parameters = [ Parameter(name=name, value=value) for name, value in params.items() ] step = TestStepResult(name=title, start=now(), parameters=parameters) self.logger.start_step(None, uuid, step) @allure_commons.hookimpl def stop_step(self, uuid, exc_type, exc_val, exc_tb): self.logger.stop_step(uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details( exc_type, exc_val, exc_tb)) @allure_commons.hookimpl def attach_data(self, body, name, attachment_type, extension): self.logger.attach_data(uuid4(), body, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def attach_file(self, source, name, attachment_type, extension): self.logger.attach_file(uuid4(), source, name=name, attachment_type=attachment_type, extension=extension)
class allure_robotframework(object): ROBOT_LISTENER_API_VERSION = 2 DEFAULT_OUTPUT_PATH = os.path.join('output', 'allure') LOG_MESSAGE_FORMAT = '{full_message}<p><b>[{level}]</b> {message}</p>' FAIL_MESSAGE_FORMAT = '{full_message}<p style="color: red"><b>[{level}]</b> {message}</p>' def __init__(self, logger_path=DEFAULT_OUTPUT_PATH): self.stack = [] self.items_log = {} self.pool_id = None self.links = OrderedDict() self._previous_keyword_failed = False self._traceback_message = None self.reporter = AllureReporter() self.listener = AllureListener(self.reporter) self.logger = AllureFileLogger(logger_path) allure_commons.plugin_manager.register(self.logger) allure_commons.plugin_manager.register(self.listener) def start_suite(self, name, attributes): if not self.pool_id: self.pool_id = BuiltIn().get_variable_value('${PABOTEXECUTIONPOOLID}') self.pool_id = int(self.pool_id) if self.pool_id else 0 self.start_new_group(name, attributes) def end_suite(self, name, attributes): self.stop_current_group() def start_test(self, name, attributes): self.start_new_group(name, attributes) self.start_new_test(name, attributes) def end_test(self, name, attributes): self.stop_current_test(name, attributes) self.stop_current_group() def start_keyword(self, name, attributes): self.start_new_keyword(name, attributes) def end_keyword(self, name, attributes): self.end_current_keyword(name, attributes) def log_message(self, message): level = message.get('level') if self._previous_keyword_failed: self._traceback_message = message.get('message') self._previous_keyword_failed = False if level == RobotLogLevel.FAIL: self._previous_keyword_failed = True self.reporter.get_item(self.stack[-1]).statusDetails = StatusDetails(message=message.get('message')) self.append_message_to_last_item_log(message, level) def start_new_group(self, name, attributes): uuid = uuid4() self.set_suite_link(attributes.get('metadata'), uuid) if self.stack: parent_suite = self.reporter.get_last_item(TestResultContainer) parent_suite.children.append(uuid) self.stack.append(uuid) suite = TestResultContainer(uuid=uuid, name=name, description=attributes.get('doc'), start=now()) self.reporter.start_group(uuid, suite) def stop_current_group(self): uuid = self.stack.pop() self.remove_suite_link(uuid) self.reporter.stop_group(uuid, stop=now()) def start_new_test(self, name, attributes): uuid = uuid4() self.reporter.get_last_item(TestResultContainer).children.append(uuid) self.stack.append(uuid) test_case = TestResult(uuid=uuid, historyId=md5(attributes.get('longname')), name=name, fullName=attributes.get('longname'), start=now()) self.reporter.schedule_test(uuid, test_case) def stop_current_test(self, name, attributes): uuid = self.stack.pop() test = self.reporter.get_test(uuid) test.status = utils.get_allure_status(attributes.get('status')) test.labels.extend(utils.get_allure_suites(attributes.get('longname'))) test.labels.extend(allure_tags(attributes)) for label_type in (LabelType.EPIC, LabelType.FEATURE, LabelType.STORY): test.labels.extend(allure_labels(attributes, label_type)) for link_type in (LinkType.ISSUE, LinkType.TEST_CASE, LinkType.LINK): test.links.extend(allure_links(attributes, link_type)) test.labels.append(Label(name=LabelType.THREAD, value=self.pool_id)) test.labels.append(Label(name=LabelType.HOST, value=host_tag())) test.labels.append(Label(name=LabelType.FRAMEWORK, value='robotframework')) test.labels.append(Label(name=LabelType.LANGUAGE, value=platform_label())) test.statusDetails = StatusDetails(message=attributes.get('message'), trace=self.get_traceback_message()) test.description = attributes.get('doc') last_link = list(self.links.values())[-1] if self.links else None if attributes.get(Severity.CRITICAL, 'no') == 'yes': test.labels.append(Label(name=LabelType.SEVERITY, value=Severity.CRITICAL)) if last_link: test.links.append(Link(LinkType.LINK, last_link, 'Link')) test.stop = now() self.reporter.close_test(uuid) def start_new_keyword(self, name, attributes): uuid = uuid4() parent_uuid = self.stack[-1] step_name = '{} = {}'.format(attributes.get('assign')[0], name) if attributes.get('assign') else name args = { 'name': step_name, 'description': attributes.get('doc'), 'parameters': utils.get_allure_parameters(attributes.get('args')), 'start': now() } keyword_type = attributes.get('type') last_item = self.reporter.get_last_item() if keyword_type in RobotKeywordType.FIXTURES and not isinstance(last_item, TestStepResult): if isinstance(last_item, TestResult): parent_uuid = self.stack[-2] if keyword_type == RobotKeywordType.SETUP: self.reporter.start_before_fixture(parent_uuid, uuid, TestBeforeResult(**args)) elif keyword_type == RobotKeywordType.TEARDOWN: self.reporter.start_after_fixture(parent_uuid, uuid, TestAfterResult(**args)) self.stack.append(uuid) return self.stack.append(uuid) self.reporter.start_step(parent_uuid=parent_uuid, uuid=uuid, step=TestStepResult(**args)) def end_current_keyword(self, name, attributes): uuid = self.stack.pop() if uuid in self.items_log: self.reporter.attach_data(uuid=uuid4(), body=self.items_log.pop(uuid).replace('\n', '<br>'), name='Keyword Log', attachment_type=AttachmentType.HTML) args = { 'uuid': uuid, 'status': utils.get_allure_status(attributes.get('status')), 'stop': now() } keyword_type = attributes.get('type') parent_item = self.reporter.get_last_item() if keyword_type in RobotKeywordType.FIXTURES and not isinstance(parent_item, TestStepResult): if keyword_type == RobotKeywordType.SETUP: self.reporter.stop_before_fixture(**args) return elif keyword_type == RobotKeywordType.TEARDOWN: self.reporter.stop_after_fixture(**args) return self.reporter.stop_step(**args) def append_message_to_last_item_log(self, message, level): full_message = self.items_log[self.stack[-1]] if self.stack[-1] in self.items_log else '' message_format = self.FAIL_MESSAGE_FORMAT if level in RobotLogLevel.CRITICAL_LEVELS else self.LOG_MESSAGE_FORMAT self.items_log[self.stack[-1]] = message_format.format(full_message=full_message, level=message.get('level'), message=message.get('message')) def set_suite_link(self, metadata, uuid): if metadata: link = metadata.get('Link') if link: self.links[uuid] = link def remove_suite_link(self, uuid): if self.links.get(uuid): self.links.pop(uuid) def get_traceback_message(self): if BuiltIn().get_variable_value('${LOG LEVEL}') in (RobotLogLevel.DEBUG, RobotLogLevel.TRACE): return self._traceback_message return None def close(self): for plugin in [self.logger, self.listener]: name = allure_commons.plugin_manager.get_name(plugin) allure_commons.plugin_manager.unregister(name=name)
class AllureTestResult(object): def __init__(self): report_root_path = os.path.join(os.getcwd(), "reportsxxxx") report_dir_path = os.path.join( report_root_path, datetime.now().strftime('%Y-%m-%d-%H-%M-%S')) if not os.path.isdir(report_dir_path): os.makedirs(report_dir_path) for f in os.listdir(report_dir_path): f = os.path.join(report_dir_path, f) if os.path.isfile(f): os.unlink(f) elif os.path.isdir(f): shutil.rmtree(f) self.file_logger = AllureFileLogger(report_dir_path) allure_commons.plugin_manager.register(self.file_logger) self.allure_logger = AllureReporter() self.start_at = time.time() def _clean_up(self): name = allure_commons.plugin_manager.get_name(self.file_logger) allure_commons.plugin_manager.unregister(name=name) @staticmethod def allure_status(status): return { 'failed': Status.FAILED, 'broken': Status.BROKEN, 'passed': Status.PASSED, 'skipped': Status.SKIPPED }.get(status) @staticmethod def _get_err_message(err): exctype, value, tb = err return str(exctype.__name__) def _add_result(self, test, trace=None): uuid = uuid4() test = TestSummaryResult(**test) test_result = allure_TestResult(name=test.test_name, uuid=uuid) # test_result.status = self.allure_status(test.test_status) test_result.status = self.allure_status(test.test_status) test_result.fullName = test_result.name test_result.historyId = md5(test_result.fullName) test_result.statusDetails = StatusDetails(message=test.test_message, trace=trace) self.allure_logger.schedule_test(uuid, test_result) self.allure_logger.attach_data(uuid4(), 'aaa', name="request_result", attachment_type="text/plain", extension="txt") self.allure_logger.attach_data(uuid4(), json.dumps(test.test_dict, cls=ComplexEncoder, indent=4, sort_keys=True, ensure_ascii=False), name="case_dict", attachment_type="application/json", extension="json") self.allure_logger.close_test(uuid) def render_html_report(self): self._clean_up() @property def duration(self): return time.time() - self.start_at
class AllureListener(object): def __init__(self): self.allure_logger = AllureReporter() self._cache = ItemCache() self._host = host_tag() self._thread = thread_tag() @allure_commons.hookimpl def start_step(self, uuid, title, params): parameters = [Parameter(name=name, value=value) for name, value in params] step = TestStepResult(name=title, start=now(), parameters=parameters) self.allure_logger.start_step(None, uuid, step) @allure_commons.hookimpl def stop_step(self, uuid, exc_type, exc_val, exc_tb): self.allure_logger.stop_step(uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details(exc_type, exc_val, exc_tb)) @allure_commons.hookimpl def start_fixture(self, parent_uuid, uuid, name): after_fixture = TestAfterResult(name=name, start=now()) self.allure_logger.start_after_fixture(parent_uuid, uuid, after_fixture) @allure_commons.hookimpl def stop_fixture(self, parent_uuid, uuid, name, exc_type, exc_val, exc_tb): self.allure_logger.stop_after_fixture(uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details(exc_type, exc_val, exc_tb)) @pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_protocol(self, item, nextitem): uuid = self._cache.set(item.nodeid) for fixturedef in _test_fixtures(item): group_uuid = self._cache.get(fixturedef) if not group_uuid: group_uuid = self._cache.set(fixturedef) group = TestResultContainer(uuid=group_uuid) self.allure_logger.start_group(group_uuid, group) self.allure_logger.update_group(group_uuid, children=uuid) test_case = TestResult(name=allure_name(item), uuid=uuid) self.allure_logger.schedule_test(uuid, test_case) if hasattr(item, 'function'): test_case.description = item.function.__doc__ yield for name, value in item.callspec.params.items() if hasattr(item, 'callspec') else (): test_result = self.allure_logger.get_test(uuid) if test_result: test_result.parameters.append(Parameter(name, represent(value))) test_case.labels.extend([Label(name=name, value=value) for name, value in allure_labels(item)]) test_case.labels.extend([Label(name=LabelType.TAG, value=value) for value in pytest_markers(item)]) test_case.labels.append(Label(name=LabelType.HOST, value=self._host)) test_case.labels.append(Label(name=LabelType.THREAD, value=self._thread)) test_case.labels.append(Label(name=LabelType.FRAMEWORK, value='pytest')) test_case.labels.append(Label(name=LabelType.LANGUAGE, value=platform_label())) test_case.links += [Link(link_type, url, name) for link_type, url, name in allure_links(item)] test_case.fullName = allure_full_name(item) test_case.historyId = md5(test_case.fullName) test_case.labels.append(Label('package', allure_package(item))) uuid = self._cache.pop(item.nodeid) self.allure_logger.close_test(uuid) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_call(self, item): uuid = self._cache.get(item.nodeid) test_result = self.allure_logger.get_test(uuid) if test_result: test_result.start = now() yield if test_result: test_result.stop = now() @pytest.hookimpl(hookwrapper=True) def pytest_fixture_setup(self, fixturedef, request): fixture_name = fixturedef.argname container_uuid = self._cache.get(fixturedef) if not container_uuid: container_uuid = self._cache.set(fixturedef) container = TestResultContainer(uuid=container_uuid) self.allure_logger.start_group(container_uuid, container) self.allure_logger.update_group(container_uuid, start=now()) before_fixture_uuid = uuid4() before_fixture = TestBeforeResult(name=fixture_name, start=now()) self.allure_logger.start_before_fixture(container_uuid, before_fixture_uuid, before_fixture) outcome = yield self.allure_logger.stop_before_fixture(before_fixture_uuid, stop=now(), status=get_outcome_status(outcome), statusDetails=get_outcome_status_details(outcome)) for index, finalizer in enumerate(fixturedef._finalizer or ()): name = '{fixture}::{finalizer}'.format(fixture=fixturedef.argname, finalizer=finalizer.__name__) fixturedef._finalizer[index] = allure_commons.fixture(finalizer, parent_uuid=container_uuid, name=name) @pytest.hookimpl(hookwrapper=True) def pytest_fixture_post_finalizer(self, fixturedef): yield if hasattr(fixturedef, 'cached_result') and self._cache.get(fixturedef): container_uuid = self._cache.pop(fixturedef) self.allure_logger.stop_group(container_uuid, stop=now()) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(self, item, call): uuid = self._cache.set(item.nodeid) report = (yield).get_result() allure_item = self.allure_logger.get_item(uuid) status = allure_item.status or None status_details = None if call.excinfo and hasattr(report, 'wasxfail'): status_details = StatusDetails(message=report.wasxfail, trace=report.longreprtext) elif report.failed: status_details = StatusDetails(message=call.excinfo.exconly(), trace=report.longreprtext) if report.when == 'setup': if report.passed: status = Status.PASSED if report.failed: status = Status.BROKEN if report.skipped: status = Status.SKIPPED if report.when == 'call': if report.passed and status == Status.PASSED: pass if report.failed: status = Status.FAILED if report.skipped: status = Status.SKIPPED if report.when == 'teardown': if report.failed and status == Status.PASSED: status = Status.BROKEN test_result = self.allure_logger.get_test(uuid) if test_result: if status_details: test_result.status = status test_result.statusDetails = status_details else: test_result.status = status @allure_commons.hookimpl def attach_data(self, body, name, attachment_type, extension): self.allure_logger.attach_data(uuid4(), body, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def attach_file(self, source, name, attachment_type, extension): self.allure_logger.attach_file(uuid4(), source, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def add_link(self, url, link_type, name): test_result = self.allure_logger.get_test(None) if test_result: test_result.links.append(Link(link_type, url, name)) @allure_commons.hookimpl def add_label(self, label_type, labels): test_result = self.allure_logger.get_test(None) for label in labels if test_result else (): test_result.labels.append(Label(label_type, label))
class AllureListener(object): def __init__(self, behave_config): self.behave_config = behave_config self.logger = AllureReporter() self.current_step_uuid = None self.current_scenario_uuid = None self.execution_context = Context() self.fixture_context = Context() self.steps = deque() def __del__(self): for group in self.fixture_context.exit(): group.children.extend(self.execution_context) self.logger.stop_group(group.uuid) @allure_commons.hookimpl def start_fixture(self, parent_uuid, uuid, name, parameters): parameters = [Parameter(name=param_name, value=param_value) for param_name, param_value in parameters.items()] if name in FIXTURES and not self.fixture_context: group = TestResultContainer(uuid=uuid4()) self.logger.start_group(group.uuid, group) self.fixture_context.append(group) if name in BEFORE_FIXTURES: fixture = TestBeforeResult(name=name, start=now(), parameters=parameters) for group in self.fixture_context: self.logger.start_before_fixture(group.uuid, uuid, fixture) elif name in AFTER_FIXTURES: fixture = TestAfterResult(name=name, start=now(), parameters=parameters) for group in self.fixture_context: self.logger.start_after_fixture(group.uuid, uuid, fixture) @allure_commons.hookimpl def stop_fixture(self, parent_uuid, uuid, name, exc_type, exc_val, exc_tb): if name in FIXTURES: self.logger.stop_before_fixture(uuid=uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details(exc_type, exc_val, exc_tb)) def start_feature(self): self.execution_context.enter() self.fixture_context.enter() def stop_feature(self): uuids = self.execution_context.exit() for group in self.fixture_context.exit(): group.children.extend(uuids) self.logger.stop_group(group.uuid) self.execution_context.extend(uuids) @allure_commons.hookimpl def start_test(self, parent_uuid, uuid, name, parameters, context): self.start_scenario(context['scenario']) def start_scenario(self, scenario): self.current_scenario_uuid = uuid4() self.fixture_context.enter() self.execution_context.enter() self.execution_context.append(self.current_scenario_uuid) test_case = TestResult(uuid=self.current_scenario_uuid, start=now()) test_case.name = scenario_name(scenario) test_case.historyId = scenario_history_id(scenario) test_case.description = '\n'.join(scenario.description) test_case.parameters = scenario_parameters(scenario) test_case.labels.extend([Label(name=LabelType.TAG, value=tag) for tag in scenario_tags(scenario)]) test_case.labels.append(Label(name=LabelType.SEVERITY, value=scenario_severity(scenario).value)) test_case.labels.append(Label(name=LabelType.FEATURE, value=scenario.feature.name)) test_case.labels.append(Label(name=LabelType.FRAMEWORK, value='behave')) test_case.labels.append(Label(name=LabelType.LANGUAGE, value=platform_label())) self.logger.schedule_test(self.current_scenario_uuid, test_case) @allure_commons.hookimpl def stop_test(self, parent_uuid, uuid, name, context, exc_type, exc_val, exc_tb): self.stop_scenario(context['scenario']) def stop_scenario(self, scenario): if scenario.status == 'skipped' and not self.behave_config.show_skipped: self.logger.drop_test(self.current_scenario_uuid) else: status = scenario_status(scenario) status_details = scenario_status_details(scenario) self.flush_steps() test_result = self.logger.get_test(self.current_scenario_uuid) test_result.stop = now() test_result.status = status test_result.statusDetails = status_details self.logger.close_test(self.current_scenario_uuid) self.current_step_uuid = None for group in self.fixture_context.exit(): group.children.append(self.current_scenario_uuid) self.logger.stop_group(group.uuid) self.execution_context.exit() self.execution_context.append(self.current_scenario_uuid) self.current_scenario_uuid = None def schedule_step(self, step): self.steps.append(step) def match_step(self, match): step = self.steps.popleft() self.start_behave_step(step) def start_behave_step(self, step): self.current_step_uuid = uuid4() name = u'{keyword} {title}'.format(keyword=step.keyword, title=step.name) allure_step = TestStepResult(name=name, start=now()) self.logger.start_step(None, self.current_step_uuid, allure_step) if step.text: self.logger.attach_data(uuid4(), step.text, name='.text', attachment_type=AttachmentType.TEXT) if step.table: self.logger.attach_data(uuid4(), step_table(step), name='.table', attachment_type=AttachmentType.CSV) def stop_behave_step(self, result): status = step_status(result) status_details = step_status_details(result) self.logger.stop_step(self.current_step_uuid, stop=now(), status=status, statusDetails=status_details) def flush_steps(self): while self.steps: step = self.steps.popleft() self.start_behave_step(step) self.stop_behave_step(step) @allure_commons.hookimpl def start_step(self, uuid, title, params): parameters = [Parameter(name=name, value=value) for name, value in params.items()] step = TestStepResult(name=title, start=now(), parameters=parameters) self.logger.start_step(None, uuid, step) @allure_commons.hookimpl def stop_step(self, uuid, exc_type, exc_val, exc_tb): self.logger.stop_step(uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details(exc_type, exc_val, exc_tb)) @allure_commons.hookimpl def attach_data(self, body, name, attachment_type, extension): self.logger.attach_data(uuid4(), body, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def attach_file(self, source, name, attachment_type, extension): self.logger.attach_file(uuid4(), source, name=name, attachment_type=attachment_type, extension=extension)
class AllureListener(object): def __init__(self): self.logger = AllureReporter() self.current_step_uuid = None self.execution_context = Context() self.fixture_context = Context() self.steps = deque() def __del__(self): for group in self.fixture_context.exit(): group.children.extend(self.execution_context) self.logger.stop_group(group.uuid) @allure_commons.hookimpl def start_fixture(self, parent_uuid, uuid, name, parameters): parameters = [Parameter(name=param_name, value=param_value) for param_name, param_value in parameters] if name in FIXTURES and not self.fixture_context: group = TestResultContainer(uuid=uuid4()) self.logger.start_group(group.uuid, group) self.fixture_context.append(group) if name in BEFORE_FIXTURES: fixture = TestBeforeResult(name=name, start=now(), parameters=parameters) for group in self.fixture_context: self.logger.start_before_fixture(group.uuid, uuid, fixture) elif name in AFTER_FIXTURES: fixture = TestAfterResult(name=name, start=now(), parameters=parameters) for group in self.fixture_context: self.logger.start_after_fixture(group.uuid, uuid, fixture) @allure_commons.hookimpl def stop_fixture(self, parent_uuid, uuid, name, exc_type, exc_val, exc_tb): if name in FIXTURES: status = fixture_status(exc_val, exc_tb) status_details = fixture_status_details(exc_val, exc_tb) self.logger.stop_before_fixture(uuid=uuid, stop=now(), status=status, statusDetails=status_details) def start_feature(self): self.execution_context.enter() self.fixture_context.enter() def stop_feature(self): uuids = self.execution_context.exit() for group in self.fixture_context.exit(): group.children.extend(uuids) self.logger.stop_group(group.uuid) self.execution_context.extend(uuids) @allure_commons.hookimpl def start_test(self, parent_uuid, uuid, name, parameters, context): scenario = context['scenario'] self.fixture_context.enter() self.execution_context.enter() self.execution_context.append(uuid) test_case = TestResult(uuid=uuid, start=now()) test_case.name = scenario_name(scenario) test_case.historyId = scenario_history_id(scenario) test_case.description = '\n'.join(scenario.description) labels = [] feature_label = Label(name=LabelType.FEATURE.value, value=scenario.feature.name) severity = (Label(name=LabelType.SEVERITY.value, value=scenario_severity(scenario).value)) labels.append(feature_label) labels.append(severity) labels += [Label(name=LabelType.TAG.value, value=tag) for tag in scenario_tags(scenario)] test_case.parameters = scenario_parameters(scenario) test_case.labels = labels self.logger.schedule_test(uuid, test_case) @allure_commons.hookimpl def stop_test(self, parent_uuid, uuid, name, context, exc_type, exc_val, exc_tb): scenario = context['scenario'] self.flush_steps() status = scenario_status(scenario) status_details = scenario_status_details(scenario) self.logger.update_test(uuid, stop=now(), status=status, statusDetails=status_details) self.logger.close_test(uuid) self.current_step_uuid = None for group in self.fixture_context.exit(): group.children.append(uuid) self.logger.stop_group(group.uuid) self.execution_context.exit() self.execution_context.append(uuid) def schedule_step(self, step): self.steps.append(step) def match_step(self, match): step = self.steps.popleft() self.start_step(step) def start_step(self, step): self.current_step_uuid = uuid4() name = u'{keyword} {title}'.format(keyword=step.keyword, title=step.name) allure_step = TestStepResult(name=name, start=now()) self.logger.start_step(None, self.current_step_uuid, allure_step) if step.text: self.logger.attach_data(uuid4(), step.text, name='.text', attachment_type=AttachmentType.TEXT) if step.table: self.logger.attach_data(uuid4(), step_table(step), name='.table', attachment_type=AttachmentType.CSV) def stop_step(self, result): status = step_status(result) status_details = step_status_details(result) self.logger.stop_step(self.current_step_uuid, stop=now(), status=status, statusDetails=status_details) def flush_steps(self): while self.steps: step = self.steps.popleft() self.start_step(step) self.stop_step(step) @allure_commons.hookimpl def attach_data(self, body, name, attachment_type, extension): self.logger.attach_data(uuid4(), body, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def attach_file(self, source, name, attachment_type, extension): self.logger.attach_file(uuid4(), source, name=name, attachment_type=attachment_type, extension=extension)
class AllureListener: """allure plugin implementation""" def __init__(self, default_test_suite_name=None, default_parent_test_suite_name=None, default_sub_suite_name=None): self.allure_logger = AllureReporter() self._cache = ItemCache() self.default_test_suite_name = default_test_suite_name self.default_parent_test_suite_name = default_parent_test_suite_name self.default_sub_suite_name = default_sub_suite_name self.container_uuid=str(uuid4()) self.current_testcase_container_uuid = None self.parent_test_listener = None @allure_commons.hookimpl def attach_data(self, body, name, attachment_type, extension): """attach data to allure report""" self.allure_logger.attach_data( uuid4(), body, name=name, attachment_type=attachment_type, extension=extension, ) @allure_commons.hookimpl def attach_file(self, source, name, attachment_type, extension): """attach file to allure report""" self.allure_logger.attach_file( uuid4(), source, name=name, attachment_type=attachment_type, extension=extension, ) @allure_commons.hookimpl def add_title(self, test_title): """add title to current allure report item""" test_result = self.allure_logger.get_test(None) if test_result: test_result.name = test_title @allure_commons.hookimpl def add_description(self, test_description): """add description to current allure report item""" test_result = self.allure_logger.get_test(None) if test_result: test_result.description = test_description @allure_commons.hookimpl def start_step(self, uuid, title, params): """start step""" step_data = StepData() self._cache.push(step_data, uuid) parameters = [Parameter(name=name, value=value) for name, value in params.items()] step = TestStepResult(name=title, start=now(), parameters=parameters) self.allure_logger.start_step(None, uuid, step) @allure_commons.hookimpl def stop_step(self, uuid, exc_type, exc_val, exc_tb): """stop step""" step_data = self._cache.get(uuid) out = sys.stdout.getvalue() sys.stdout.close() if len(out) != 0: self.attach_data(out, "STDOUT", AttachmentType.TEXT, "txt") sys.stdout = step_data.prev_stdout err = sys.stderr.getvalue() sys.stderr.close() if len(err) != 0: self.attach_data(err, "STDERR", AttachmentType.TEXT, "txt") sys.stderr = step_data.prev_stderr self.allure_logger.stop_step( uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details(exc_type, exc_val, exc_tb), ) @allure_commons.hookimpl def start_test(self, name, uuid, context): """start test""" test_result = TestResult(name=name, uuid=uuid, start=now(), stop=now()) test_result.status = context.status if self.default_test_suite_name: test_result.labels.append(Label(name=LabelType.SUITE, value=self.default_test_suite_name)) if self.default_parent_test_suite_name: test_result.labels.append(Label(name=LabelType.PARENT_SUITE, value=self.default_parent_test_suite_name)) if self.default_sub_suite_name: test_result.labels.append(Label(name=LabelType.SUB_SUITE, value=self.default_sub_suite_name)) test_result.labels.append(Label(name=LabelType.FRAMEWORK, value="ArangoDB Release Test Automation")) self.allure_logger.schedule_test(uuid, test_result) self._cache.push(test_result, uuid) for label in context.labels: test_result.labels.append(label) self.allure_logger.update_group(self.container_uuid, children=uuid) parent = self.parent_test_listener while parent: parent.allure_logger.update_group(parent.container_uuid, children=uuid) parent = parent.parent_test_listener self.current_testcase_container_uuid = str(uuid4()) container = TestResultContainer(uuid=self.current_testcase_container_uuid, name=name) self._cache.push(container, self.current_testcase_container_uuid) self.allure_logger.start_group(self.current_testcase_container_uuid, container) self.allure_logger.update_group(self.current_testcase_container_uuid, start=now()) self.allure_logger.update_group(self.current_testcase_container_uuid, children=uuid) # pylint: disable=too-many-arguments @allure_commons.hookimpl def stop_test(self, uuid, context, exc_type, exc_val, exc_tb): """stop test""" test_result = self._cache.get(uuid) test_result.status = context.status if context.statusDetails: test_result.statusDetails = context.statusDetails test_result.stop = now() if exc_type or exc_val or exc_tb: test_result.status = get_status(exc_val) test_result.statusDetails = get_status_details(exc_type, exc_val, exc_tb) for step in test_result.steps: if step.status == Status.FAILED: test_result.status = Status.FAILED test_result.statusDetails = step.statusDetails for label in context.labels: if label not in test_result.labels: test_result.labels.append(label) self.allure_logger.close_test(uuid) self.allure_logger.stop_group(self.current_testcase_container_uuid) self.current_testcase_container_uuid = None def start_suite_container(self, suite_name): """start a test suite""" container = TestResultContainer(uuid=self.container_uuid, name=suite_name) self._cache.push(container, self.container_uuid) self.allure_logger.start_group(self.container_uuid, container) self.allure_logger.update_group(self.container_uuid, start=now()) def stop_suite_container(self): """stop running test suite""" self.allure_logger.stop_group(self.container_uuid) def start_before_fixture(self, uuid, name): """start a fixture that is ran before a test case or test suite""" container_uuid = self.current_testcase_container_uuid if self.current_testcase_container_uuid else self.container_uuid fixture = TestBeforeResult(name=name, start=now(), parameters={}) self.allure_logger.start_before_fixture(container_uuid, uuid, fixture) def stop_before_fixture(self, uuid, exc_type, exc_val, exc_tb): """stop a fixture that is ran before a test case or test suite""" self.allure_logger.stop_before_fixture(uuid=uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details(exc_type, exc_val, exc_tb)) def start_after_fixture(self, uuid, name): """start a fixture that is ran after a test case or test suite""" container_uuid = self.current_testcase_container_uuid if self.current_testcase_container_uuid else self.container_uuid fixture = TestAfterResult(name=name, start=now(), parameters={}) self.allure_logger.start_after_fixture(container_uuid, uuid, fixture) def stop_after_fixture(self, uuid, exc_type, exc_val, exc_tb): """stop a fixture that is ran after a test case or test suite""" self.allure_logger.stop_after_fixture(uuid=uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details(exc_type, exc_val, exc_tb))
class AllureListener(object): def __init__(self, config): self.config = config self.allure_logger = AllureReporter() self._cache = ItemCache() self._host = host_tag() self._thread = thread_tag() @allure_commons.hookimpl def start_step(self, uuid, title, params): parameters = [Parameter(name=name, value=value) for name, value in params.items()] step = TestStepResult(name=title, start=now(), parameters=parameters) self.allure_logger.start_step(None, uuid, step) @allure_commons.hookimpl def stop_step(self, uuid, exc_type, exc_val, exc_tb): self.allure_logger.stop_step(uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details(exc_type, exc_val, exc_tb)) @allure_commons.hookimpl def start_fixture(self, parent_uuid, uuid, name): after_fixture = TestAfterResult(name=name, start=now()) self.allure_logger.start_after_fixture(parent_uuid, uuid, after_fixture) @allure_commons.hookimpl def stop_fixture(self, parent_uuid, uuid, name, exc_type, exc_val, exc_tb): self.allure_logger.stop_after_fixture(uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details(exc_type, exc_val, exc_tb)) @pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_protocol(self, item, nextitem): uuid = self._cache.push(item.nodeid) test_result = TestResult(name=item.name, uuid=uuid, start=now(), stop=now()) self.allure_logger.schedule_test(uuid, test_result) yield @pytest.hookimpl(hookwrapper=True) def pytest_runtest_setup(self, item): if not self._cache.get(item.nodeid): uuid = self._cache.push(item.nodeid) test_result = TestResult(name=item.name, uuid=uuid, start=now(), stop=now()) self.allure_logger.schedule_test(uuid, test_result) yield uuid = self._cache.get(item.nodeid) test_result = self.allure_logger.get_test(uuid) for fixturedef in _test_fixtures(item): group_uuid = self._cache.get(fixturedef) if not group_uuid: group_uuid = self._cache.push(fixturedef) group = TestResultContainer(uuid=group_uuid) self.allure_logger.start_group(group_uuid, group) self.allure_logger.update_group(group_uuid, children=uuid) params = item.callspec.params if hasattr(item, 'callspec') else {} test_result.name = allure_name(item, params) test_result.description = allure_description(item) test_result.descriptionHtml = allure_description_html(item) test_result.fullName = allure_full_name(item) test_result.historyId = md5(test_result.fullName) test_result.parameters.extend( [Parameter(name=name, value=represent(value)) for name, value in params.items()]) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_call(self, item): uuid = self._cache.get(item.nodeid) test_result = self.allure_logger.get_test(uuid) if test_result: test_result.start = now() yield if test_result: test_result.stop = now() @pytest.hookimpl(hookwrapper=True) def pytest_runtest_teardown(self, item): yield uuid = self._cache.get(item.nodeid) test_result = self.allure_logger.get_test(uuid) test_result.labels.extend([Label(name=name, value=value) for name, value in allure_labels(item)]) test_result.labels.extend([Label(name=LabelType.TAG, value=value) for value in pytest_markers(item)]) test_result.labels.extend([Label(name=name, value=value) for name, value in allure_suite_labels(item)]) test_result.labels.append(Label(name=LabelType.HOST, value=self._host)) test_result.labels.append(Label(name=LabelType.THREAD, value=self._thread)) test_result.labels.append(Label(name=LabelType.FRAMEWORK, value='pytest')) test_result.labels.append(Label(name=LabelType.LANGUAGE, value=platform_label())) test_result.labels.append(Label(name='package', value=allure_package(item))) test_result.links.extend([Link(link_type, url, name) for link_type, url, name in allure_links(item)]) @pytest.hookimpl(hookwrapper=True) def pytest_fixture_setup(self, fixturedef, request): fixture_name = fixturedef.argname container_uuid = self._cache.get(fixturedef) if not container_uuid: container_uuid = self._cache.push(fixturedef) container = TestResultContainer(uuid=container_uuid) self.allure_logger.start_group(container_uuid, container) self.allure_logger.update_group(container_uuid, start=now()) before_fixture_uuid = uuid4() before_fixture = TestBeforeResult(name=fixture_name, start=now()) self.allure_logger.start_before_fixture(container_uuid, before_fixture_uuid, before_fixture) outcome = yield self.allure_logger.stop_before_fixture(before_fixture_uuid, stop=now(), status=get_outcome_status(outcome), statusDetails=get_outcome_status_details(outcome)) finalizers = getattr(fixturedef, '_finalizers', []) for index, finalizer in enumerate(finalizers): name = '{fixture}::{finalizer}'.format(fixture=fixturedef.argname, finalizer=getattr(finalizer, "__name__", index)) finalizers[index] = allure_commons.fixture(finalizer, parent_uuid=container_uuid, name=name) @pytest.hookimpl(hookwrapper=True) def pytest_fixture_post_finalizer(self, fixturedef): yield if hasattr(fixturedef, 'cached_result') and self._cache.get(fixturedef): container_uuid = self._cache.pop(fixturedef) self.allure_logger.stop_group(container_uuid, stop=now()) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(self, item, call): uuid = self._cache.get(item.nodeid) report = (yield).get_result() test_result = self.allure_logger.get_test(uuid) status = get_pytest_report_status(report) status_details = None if call.excinfo: status_details = StatusDetails( message=escape_non_unicode_symbols(call.excinfo.exconly()), trace=escape_non_unicode_symbols(report.longreprtext)) if (status != Status.SKIPPED and not (call.excinfo.errisinstance(AssertionError) or call.excinfo.errisinstance(pytest.fail.Exception))): status = Status.BROKEN if status == Status.PASSED and hasattr(report, 'wasxfail'): reason = report.wasxfail message = 'XPASS {reason}'.format(reason=reason) if reason else 'XPASS' status_details = StatusDetails(message=message) if report.when == 'setup': test_result.status = status test_result.statusDetails = status_details if report.when == 'call': if test_result.status == Status.PASSED: test_result.status = status test_result.statusDetails = status_details if report.when == 'teardown': if status in (Status.FAILED, Status.BROKEN) and test_result.status == Status.PASSED: test_result.status = status test_result.statusDetails = status_details if self.config.option.attach_capture: if report.caplog: self.attach_data(report.caplog, "log", AttachmentType.TEXT, None) if report.capstdout: self.attach_data(report.capstdout, "stdout", AttachmentType.TEXT, None) if report.capstderr: self.attach_data(report.capstderr, "stderr", AttachmentType.TEXT, None) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_logfinish(self, nodeid, location): yield uuid = self._cache.pop(nodeid) if uuid: self.allure_logger.close_test(uuid) @allure_commons.hookimpl def attach_data(self, body, name, attachment_type, extension): self.allure_logger.attach_data(uuid4(), body, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def attach_file(self, source, name, attachment_type, extension): self.allure_logger.attach_file(uuid4(), source, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def add_title(self, test_title): test_result = self.allure_logger.get_test(None) if test_result: test_result.name = test_title @allure_commons.hookimpl def add_description(self, test_description): test_result = self.allure_logger.get_test(None) if test_result: test_result.description = test_description @allure_commons.hookimpl def add_description_html(self, test_description_html): test_result = self.allure_logger.get_test(None) if test_result: test_result.descriptionHtml = test_description_html @allure_commons.hookimpl def add_link(self, url, link_type, name): test_result = self.allure_logger.get_test(None) if test_result: pattern = dict(self.config.option.allure_link_pattern).get(link_type, u'{}') url = pattern.format(url) test_result.links.append(Link(link_type, url, name)) @allure_commons.hookimpl def add_label(self, label_type, labels): test_result = self.allure_logger.get_test(None) for label in labels if test_result else (): test_result.labels.append(Label(label_type, label))
class AllureListener(object): def __init__(self, behave_config): self.behave_config = behave_config self.issue_pattern = behave_config.userdata.get( 'AllureFormatter.issue_pattern', None) self.link_pattern = behave_config.userdata.get( 'AllureFormatter.link_pattern', None) self.hide_excluded = behave_config.userdata.get( 'AllureFormatter.hide_excluded', False) self.logger = AllureReporter() self.current_step_uuid = None self.current_scenario_uuid = None self.group_context = GroupContext(self.logger) self.group_context.enter() self.steps = deque() def start_file(self): self.group_context.enter() @allure_commons.hookimpl def start_fixture(self, parent_uuid, uuid, name, parameters): # parameters = [Parameter(name=param_name, value=param_value) for param_name, param_value in parameters.items()] if name.startswith("before_"): name = get_hook_name(name, parameters) fixture = TestBeforeResult(name=name, start=now(), parameters=None) group = self.group_context.current_group() self.logger.start_before_fixture(group.uuid, uuid, fixture) elif name.startswith("after_"): name = get_hook_name(name, parameters) fixture = TestAfterResult(name=name, start=now(), parameters=None) group = self.group_context.current_group() self.logger.start_after_fixture(group.uuid, uuid, fixture) @allure_commons.hookimpl def stop_fixture(self, parent_uuid, uuid, name, exc_type, exc_val, exc_tb): self.logger.stop_before_fixture(uuid=uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details( exc_type, exc_val, exc_tb)) def stop_feature(self): self.group_context.exit() @allure_commons.hookimpl def start_test(self, parent_uuid, uuid, name, parameters, context): self.start_scenario(context['scenario']) def start_scenario(self, scenario): self.current_scenario_uuid = uuid4() self.group_context.enter() test_case = TestResult(uuid=self.current_scenario_uuid, start=now()) test_case.name = scenario_name(scenario) test_case.fullName = get_fullname(scenario) test_case.historyId = scenario_history_id(scenario) test_case.description = '\n'.join(scenario.description) test_case.parameters = scenario_parameters(scenario) test_case.links.extend( scenario_links(scenario, issue_pattern=self.issue_pattern, link_pattern=self.link_pattern)) test_case.labels.extend(scenario_labels(scenario)) test_case.labels.append( Label(name=LabelType.FEATURE, value=scenario.feature.name)) test_case.labels.append(Label(name=LabelType.FRAMEWORK, value='behave')) test_case.labels.append( Label(name=LabelType.LANGUAGE, value=platform_label())) self.logger.schedule_test(self.current_scenario_uuid, test_case) @allure_commons.hookimpl def stop_test(self, parent_uuid, uuid, name, context, exc_type, exc_val, exc_tb): self.stop_scenario(context['scenario']) def stop_scenario(self, scenario): should_run = (scenario.should_run_with_tags(self.behave_config.tags) and scenario.should_run_with_name_select( self.behave_config)) should_drop_skipped_by_option = scenario.status == 'skipped' and not self.behave_config.show_skipped should_drop_excluded = self.hide_excluded and ( scenario.skip_reason == TEST_PLAN_SKIP_REASON or not should_run) if should_drop_skipped_by_option or should_drop_excluded: self.logger.drop_test(self.current_scenario_uuid) else: status = scenario_status(scenario) status_details = scenario_status_details(scenario) self.flush_steps() test_result = self.logger.get_test(self.current_scenario_uuid) test_result.stop = now() test_result.status = status test_result.statusDetails = status_details self.logger.close_test(self.current_scenario_uuid) self.current_step_uuid = None self.group_context.append_test(self.current_scenario_uuid) self.group_context.exit() self.current_scenario_uuid = None def schedule_step(self, step): self.steps.append(step) def match_step(self, match): step = self.steps.popleft() self.start_behave_step(step) def start_behave_step(self, step): self.current_step_uuid = uuid4() name = u'{keyword} {title}'.format(keyword=step.keyword, title=step.name) allure_step = TestStepResult(name=name, start=now()) self.logger.start_step(None, self.current_step_uuid, allure_step) if step.text: self.logger.attach_data(uuid4(), step.text, name='.text', attachment_type=AttachmentType.TEXT) if step.table: self.logger.attach_data(uuid4(), step_table(step), name='.table', attachment_type=AttachmentType.CSV) def stop_behave_step(self, result): status = step_status(result) status_details = step_status_details(result) self.logger.stop_step(self.current_step_uuid, stop=now(), status=status, statusDetails=status_details) def flush_steps(self): while self.steps: step = self.steps.popleft() self.start_behave_step(step) self.stop_behave_step(step) @allure_commons.hookimpl def start_step(self, uuid, title, params): parameters = [ Parameter(name=name, value=value) for name, value in params.items() ] step = TestStepResult(name=title, start=now(), parameters=parameters) self.logger.start_step(None, uuid, step) @allure_commons.hookimpl def stop_step(self, uuid, exc_type, exc_val, exc_tb): self.logger.stop_step(uuid, stop=now(), status=get_status(exc_val), statusDetails=get_status_details( exc_type, exc_val, exc_tb)) @allure_commons.hookimpl def attach_data(self, body, name, attachment_type, extension): self.logger.attach_data(uuid4(), body, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def attach_file(self, source, name, attachment_type, extension): self.logger.attach_file(uuid4(), source, name=name, attachment_type=attachment_type, extension=extension) @allure_commons.hookimpl def add_description(self, test_description): test_result = self.logger.get_test(None) if test_result: test_result.description = test_description @allure_commons.hookimpl def add_description_html(self, test_description_html): test_result = self.logger.get_test(None) if test_result: test_result.descriptionHtml = test_description_html @allure_commons.hookimpl def add_link(self, url, link_type, name): test_result = self.logger.get_test(None) if test_result: pattern = u'{}' if link_type == LinkType.ISSUE and self.issue_pattern: pattern = self.issue_pattern elif link_type == LinkType.LINK and self.link_pattern: pattern = self.link_pattern link_url = pattern.format(url) new_link = Link(link_type, link_url, link_url if name is None else name) for link in test_result.links: if link.url == new_link.url: return test_result.links.append(new_link) def stop_session(self): self.group_context.exit()