Skip to content

Commit

Permalink
remove duplicate code in decorators
Browse files Browse the repository at this point in the history
  • Loading branch information
mabdinur committed Dec 9, 2024
1 parent 8291a18 commit 2a66d47
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 77 deletions.
2 changes: 1 addition & 1 deletion tests/parametric/test_span_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
107 changes: 31 additions & 76 deletions utils/_decorators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import inspect
import os
import re
from functools import partial

import pytest
import semantic_version as semver
Expand Down Expand Up @@ -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))
Expand All @@ -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:
Expand Down Expand Up @@ -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):
Expand All @@ -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(
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit 2a66d47

Please sign in to comment.