123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- 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])
|