diff options
author | iddqd <iddqd@yandex-team.com> | 2024-05-13 17:19:30 +0300 |
---|---|---|
committer | iddqd <iddqd@yandex-team.com> | 2024-05-13 17:28:44 +0300 |
commit | 84d127b9b7e96ba4352e3f5ddc9222aee9a66053 (patch) | |
tree | 2ebb2689abf65e68dfe92a3ca9b161b4b6ae183f /contrib/python/allure-pytest/allure_pytest/plugin.py | |
parent | b7deb7f0b71db7419781d1b0357dfa443ccc3ff1 (diff) | |
download | ydb-84d127b9b7e96ba4352e3f5ddc9222aee9a66053.tar.gz |
Add allure support to ydb github export
d6cba27d09fb5e50a99c36070a6a3545c8393ea1
Diffstat (limited to 'contrib/python/allure-pytest/allure_pytest/plugin.py')
-rw-r--r-- | contrib/python/allure-pytest/allure_pytest/plugin.py | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/contrib/python/allure-pytest/allure_pytest/plugin.py b/contrib/python/allure-pytest/allure_pytest/plugin.py new file mode 100644 index 0000000000..2771722ffc --- /dev/null +++ b/contrib/python/allure-pytest/allure_pytest/plugin.py @@ -0,0 +1,236 @@ +import argparse + +import allure +import allure_commons +import os + +from allure_commons.types import LabelType, Severity +from allure_commons.logger import AllureFileLogger +from allure_commons.utils import get_testplan + +from allure_pytest.utils import allure_label, allure_labels, allure_full_name +from allure_pytest.helper import AllureTestHelper, AllureTitleHelper +from allure_pytest.listener import AllureListener + +from allure_pytest.utils import ALLURE_DESCRIPTION_MARK, ALLURE_DESCRIPTION_HTML_MARK +from allure_pytest.utils import ALLURE_LABEL_MARK, ALLURE_LINK_MARK + + +def pytest_addoption(parser): + parser.getgroup("reporting").addoption('--alluredir', + action="store", + dest="allure_report_dir", + metavar="DIR", + default=None, + help="Generate Allure report in the specified directory (may not exist)") + + parser.getgroup("reporting").addoption('--clean-alluredir', + action="store_true", + dest="clean_alluredir", + help="Clean alluredir folder if it exists") + + parser.getgroup("reporting").addoption('--allure-no-capture', + action="store_false", + dest="attach_capture", + help="Do not attach pytest captured logging/stdout/stderr to report") + + parser.getgroup("reporting").addoption('--inversion', + action="store", + dest="inversion", + default=False, + help="Run tests not in testplan") + + def label_type(type_name, legal_values=set()): + def a_label_type(string): + atoms = set(string.split(',')) + if type_name is LabelType.SEVERITY: + if not atoms <= legal_values: + raise argparse.ArgumentTypeError('Illegal {} values: {}, only [{}] are allowed'.format( + type_name, + ', '.join(atoms - legal_values), + ', '.join(legal_values) + )) + return set((type_name, allure.severity_level(atom)) for atom in atoms) + return set((type_name, atom) for atom in atoms) + return a_label_type + + severities = [x.value for x in list(allure.severity_level)] + formatted_severities = ', '.join(severities) + parser.getgroup("general").addoption('--allure-severities', + action="store", + dest="allure_severities", + metavar="SEVERITIES_SET", + default={}, + type=label_type(LabelType.SEVERITY, legal_values=set(severities)), + help=f"""Comma-separated list of severity names. + Tests only with these severities will be run. + Possible values are: {formatted_severities}.""") + + parser.getgroup("general").addoption('--allure-epics', + action="store", + dest="allure_epics", + metavar="EPICS_SET", + default={}, + type=label_type(LabelType.EPIC), + help="""Comma-separated list of epic names. + Run tests that have at least one of the specified feature labels.""") + + parser.getgroup("general").addoption('--allure-features', + action="store", + dest="allure_features", + metavar="FEATURES_SET", + default={}, + type=label_type(LabelType.FEATURE), + help="""Comma-separated list of feature names. + Run tests that have at least one of the specified feature labels.""") + + parser.getgroup("general").addoption('--allure-stories', + action="store", + dest="allure_stories", + metavar="STORIES_SET", + default={}, + type=label_type(LabelType.STORY), + help="""Comma-separated list of story names. + Run tests that have at least one of the specified story labels.""") + + parser.getgroup("general").addoption('--allure-ids', + action="store", + dest="allure_ids", + metavar="IDS_SET", + default={}, + type=label_type(LabelType.ID), + help="""Comma-separated list of IDs. + Run tests that have at least one of the specified id labels.""") + + def cf_type(string): + type_name, values = string.split("=", 1) + atoms = set(values.split(",")) + return [(type_name, atom) for atom in atoms] + + parser.getgroup("general").addoption('--allure-label', + action="append", + dest="allure_labels", + metavar="LABELS_SET", + default=[], + type=cf_type, + help="""List of labels to run in format label_name=value1,value2. + "Run tests that have at least one of the specified labels.""") + + def link_pattern(string): + pattern = string.split(':', 1) + if not pattern[0]: + raise argparse.ArgumentTypeError('Link type is mandatory.') + + if len(pattern) != 2: + raise argparse.ArgumentTypeError('Link pattern is mandatory') + return pattern + + parser.getgroup("general").addoption('--allure-link-pattern', + action="append", + dest="allure_link_pattern", + metavar="LINK_TYPE:LINK_PATTERN", + default=[], + type=link_pattern, + help="""Url pattern for link type. Allows short links in test, + like 'issue-1'. Text will be formatted to full url with python + str.format().""") + + +def cleanup_factory(plugin): + def clean_up(): + name = allure_commons.plugin_manager.get_name(plugin) + allure_commons.plugin_manager.unregister(name=name) + return clean_up + + +def pytest_addhooks(pluginmanager): + # Need register title hooks before conftest init + title_helper = AllureTitleHelper() + allure_commons.plugin_manager.register(title_helper) + + +def pytest_configure(config): + report_dir = config.option.allure_report_dir + clean = False if config.option.collectonly else config.option.clean_alluredir + + test_helper = AllureTestHelper(config) + allure_commons.plugin_manager.register(test_helper) + config.add_cleanup(cleanup_factory(test_helper)) + + if report_dir: + report_dir = os.path.abspath(report_dir) + test_listener = AllureListener(config) + config.pluginmanager.register(test_listener, 'allure_listener') + allure_commons.plugin_manager.register(test_listener) + config.add_cleanup(cleanup_factory(test_listener)) + + file_logger = AllureFileLogger(report_dir, clean) + allure_commons.plugin_manager.register(file_logger) + config.add_cleanup(cleanup_factory(file_logger)) + + config.addinivalue_line("markers", f"{ALLURE_LABEL_MARK}: allure label marker") + config.addinivalue_line("markers", f"{ALLURE_LINK_MARK}: allure link marker") + config.addinivalue_line("markers", f"{ALLURE_DESCRIPTION_MARK}: allure description") + config.addinivalue_line("markers", f"{ALLURE_DESCRIPTION_HTML_MARK}: allure description html") + + +def select_by_labels(items, config): + arg_labels = set().union( + config.option.allure_epics, + config.option.allure_features, + config.option.allure_stories, + config.option.allure_ids, + config.option.allure_severities, + *config.option.allure_labels + ) + if arg_labels: + selected, deselected = [], [] + for item in items: + test_labels = set(allure_labels(item)) + test_severity = allure_label(item, LabelType.SEVERITY) + if not test_severity: + test_labels.add((LabelType.SEVERITY, Severity.NORMAL)) + if arg_labels & test_labels: + selected.append(item) + else: + deselected.append(item) + return selected, deselected + else: + return items, [] + + +def select_by_testcase(items, config): + planned_tests = get_testplan() + is_inversion = config.option.inversion + + if planned_tests: + + def is_planed(item): + allure_ids = allure_label(item, LabelType.ID) + allure_string_ids = list(map(str, allure_ids)) + for planed_item in planned_tests: + planed_item_string_id = str(planed_item.get("id")) + planed_item_selector = planed_item.get("selector") + if ( + planed_item_string_id in allure_string_ids + or planed_item_selector == allure_full_name(item) + ): + return True if not is_inversion else False + return False if not is_inversion else True + + selected, deselected = [], [] + for item in items: + selected.append(item) if is_planed(item) else deselected.append(item) + return selected, deselected + else: + return items, [] + + +def pytest_collection_modifyitems(items, config): + selected, deselected_by_testcase = select_by_testcase(items, config) + selected, deselected_by_labels = select_by_labels(selected, config) + + items[:] = selected + + if deselected_by_testcase or deselected_by_labels: + config.hook.pytest_deselected(items=[*deselected_by_testcase, *deselected_by_labels]) |