diff --git a/tests/parametric/test_span_events.py b/tests/parametric/test_span_events.py index 6fc3c3950d..8069b79553 100644 --- a/tests/parametric/test_span_events.py +++ b/tests/parametric/test_span_events.py @@ -9,7 +9,7 @@ @rfc("https://docs.google.com/document/d/1cVod_VI7Yruq8U9dfMRFJd7npDu-uBpste2IB04GyaQ") @scenarios.parametric @features.span_events -@missing_feature(reason="Agent does not advertise native span events serialization support yet") +@missing_feature(True, reason="Agent does not advertise native span events serialization support yet") class Test_Span_Events: def _test_span_with_event(self, _library_env, test_agent, test_library, retrieve_events): """Test adding a span event, with attributes, to an active span. diff --git a/utils/_decorators.py b/utils/_decorators.py index b4616fa7ee..e5e0435caf 100644 --- a/utils/_decorators.py +++ b/utils/_decorators.py @@ -1,6 +1,7 @@ import inspect import os import re +from functools import partial import pytest import semantic_version as semver @@ -49,25 +50,12 @@ def _ensure_jira_ticket_as_reason(item, reason: str): pytest.exit(f"Please set a jira ticket for {nodeid}, instead of reason: {reason}", 1) -def _get_skipped_item(item, skip_reason): +def _get_expected_failure_item(item, skip_reason, noxfail): if inspect.isfunction(item) or inspect.isclass(item): if not hasattr(item, "pytestmark"): setattr(item, "pytestmark", []) - item.pytestmark.append(pytest.mark.skip(reason=skip_reason)) - - else: - raise ValueError(f"Unexpected skipped object: {item}") - - return item - - -def _get_expected_failure_item(item, skip_reason, force_skip: bool = False): - if inspect.isfunction(item) or inspect.isclass(item): - if not hasattr(item, "pytestmark"): - setattr(item, "pytestmark", []) - - if force_skip: + if noxfail: item.pytestmark.append(pytest.mark.skip(reason=skip_reason)) else: item.pytestmark.append(pytest.mark.xfail(reason=skip_reason)) @@ -78,7 +66,7 @@ def _get_expected_failure_item(item, skip_reason, force_skip: bool = False): def _should_skip(condition=None, library=None, weblog_variant=None): - if condition is not None and not condition: + if condition is False: return False if weblog_variant is not None and weblog_variant != context.weblog_variant: @@ -106,43 +94,30 @@ def _should_skip(condition=None, library=None, weblog_variant=None): return True -def missing_feature(condition: bool = None, library=None, weblog_variant=None, reason=None, force_skip: bool = False): - """decorator, allow to mark a test function/class as missing""" - - skip = _should_skip(library=library, weblog_variant=weblog_variant, condition=condition) - - def decorator(function_or_class): +def decorator(skip, noxfail, condition, decorator_type, reason, callback, function_or_class): + if inspect.isclass(function_or_class): + assert condition is not None, _MANIFEST_ERROR_MESSAGE - if inspect.isclass(function_or_class): - assert condition is not None or (library is None and weblog_variant is None), _MANIFEST_ERROR_MESSAGE - - if not skip: - return function_or_class + if decorator_type in ("bug", "flaky"): + _ensure_jira_ticket_as_reason(function_or_class, reason) - full_reason = "missing_feature" if reason is None else f"missing_feature ({reason})" + full_reason = decorator_type if reason is None else f"{decorator_type} ({reason})" + if not skip: + return function_or_class + return callback(function_or_class, full_reason, noxfail) - return _get_expected_failure_item(function_or_class, full_reason, force_skip=force_skip) - return decorator +def missing_feature(condition=None, library=None, weblog_variant=None, reason=None, force_skip: bool = False): + """decorator, allow to mark a test function/class as missing""" + skip = _should_skip(library=library, weblog_variant=weblog_variant, condition=condition) + return partial(decorator, skip, force_skip, condition, "missing_feature", reason, _get_expected_failure_item) def irrelevant(condition=None, library=None, weblog_variant=None, reason=None): """decorator, allow to mark a test function/class as not relevant""" - skip = _should_skip(library=library, weblog_variant=weblog_variant, condition=condition) - - def decorator(function_or_class): - - if inspect.isclass(function_or_class): - assert condition is not None, _MANIFEST_ERROR_MESSAGE - - if not skip: - return function_or_class - - full_reason = "irrelevant" if reason is None else f"irrelevant ({reason})" - return _get_skipped_item(function_or_class, full_reason) - - return decorator + noxfail = True + return partial(decorator, skip, noxfail, condition, "irrelevant", reason, _get_expected_failure_item) def bug(condition=None, library=None, weblog_variant=None, reason=None, force_skip: bool = False): @@ -152,42 +127,22 @@ def bug(condition=None, library=None, weblog_variant=None, reason=None, force_sk """ expected_to_fail = _should_skip(library=library, weblog_variant=weblog_variant, condition=condition) - - def decorator(function_or_class): - - if inspect.isclass(function_or_class): - assert condition is not None, _MANIFEST_ERROR_MESSAGE - - _ensure_jira_ticket_as_reason(function_or_class, reason) - - if not expected_to_fail: - return function_or_class - - full_reason = "bug" if reason is None else f"bug ({reason})" - return _get_expected_failure_item(function_or_class, full_reason, force_skip=force_skip) - - return decorator + return partial(decorator, expected_to_fail, force_skip, condition, "bug", reason, _get_expected_failure_item) def flaky(condition=None, library=None, weblog_variant=None, reason=None): """Decorator, allow to mark a test function/class as a known bug, and skip it""" skip = _should_skip(library=library, weblog_variant=weblog_variant, condition=condition) + noxfail = True + return partial(decorator, skip, noxfail, condition, "flaky", reason, _get_expected_failure_item) - def decorator(function_or_class): - if inspect.isclass(function_or_class): - assert condition is not None, _MANIFEST_ERROR_MESSAGE - - _ensure_jira_ticket_as_reason(function_or_class, reason) - - if not skip: - return function_or_class - - full_reason = "flaky" if reason is None else f"flaky ({reason})" - return _get_skipped_item(function_or_class, full_reason) - - return decorator +def incomplete_test_app(condition=None, library=None, weblog_variant=None, reason=None): + """Decorator, allow to mark a test function/class as not compatible with the tested application""" + skip = _should_skip(library=library, weblog_variant=weblog_variant, condition=condition) + noxfail = False + return partial(decorator, skip, noxfail, condition, "incomplete_test_app", reason, _get_expected_failure_item) def released( @@ -229,7 +184,7 @@ def compute_declaration(only_for_library, component_name, declaration, tested_ve assert declaration != "?" # ensure there is no more ? in version declaration - if declaration.startswith(("missing_feature", "bug", "flaky", "irrelevant")): + if declaration.startswith(("missing_feature", "bug", "flaky", "irrelevant", "incomplete_test_app")): return declaration # declaration must be now a version number @@ -268,16 +223,16 @@ def compute_declaration(only_for_library, component_name, declaration, tested_ve for reason in skip_reasons: if reason.startswith("flaky"): _ensure_jira_ticket_as_reason(test_class, reason[7:-1]) - return _get_skipped_item(test_class, reason) + return _get_expected_failure_item(test_class, reason, noxfail=True) if reason.startswith("irrelevant"): - return _get_skipped_item(test_class, reason) + return _get_expected_failure_item(test_class, reason, noxfail=True) # Otherwise, it's either bug, or missing_feature. Take the first one if reason.startswith("bug"): _ensure_jira_ticket_as_reason(test_class, reason[5:-1]) - return _get_expected_failure_item(test_class, reason) + return _get_expected_failure_item(test_class, reason, noxfail=False) return test_class