Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test Markers as Test Fields #141

Merged
merged 4 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion betelgeuse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ def get_requirement_field_values(config, requirement):

def update_testcase_fields(config, testcase):
"""Apply testcase fields default values and transformations."""
if testcase.docstring and not type(testcase.docstring) == str:
if testcase.docstring and not isinstance(testcase.docstring, str):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason that this is needed? I feel this should not be part of the PR since we are trying to introduce pytest markers support and not change how the docstring is parsed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elyezer Not needed as part of PR, but the checks are not passing without this change due to flake8 rules! Also there is no harm in doing this change :)

testcase.docstring = testcase.docstring.decode('utf8')

# Check if any field needs a default value
Expand Down
31 changes: 31 additions & 0 deletions betelgeuse/collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import os

from betelgeuse.parser import parse_docstring
from betelgeuse.parser import parse_markers
from betelgeuse.source_generator import gen_source


Expand Down Expand Up @@ -88,11 +89,20 @@ def __init__(self, function_def, parent_class=None, testmodule=None):
for decorator in self.parent_class_def.decorator_list
]
self._parse_docstring()
self._parse_markers()
self.junit_id = self._generate_junit_id()

if 'id' not in self.fields:
self.fields['id'] = self.junit_id

def _parse_markers(self):
"""Parse module, class and function markers."""
markers = [self.module_def.marker_list,
self.class_decorators,
self.decorators]
if markers:
self.fields.update({'markers': parse_markers(markers)})

def _parse_docstring(self):
"""Parse package, module, class and function docstrings."""
if self.docstring is None:
Expand Down Expand Up @@ -137,12 +147,33 @@ def is_test_module(filename):
return False


def _module_markers(module_def):
"""Extract markers applied to testcases from the test module level.

The markers list would be collected from the pytestmark global variable.
"""
markers = []
for node in module_def.body:
if isinstance(node, ast.Assign):
for target in node.targets:
if isinstance(target, ast.Name) and target.id == 'pytestmark':
if isinstance(node.value, ast.List):
for item in node.value.elts:
if isinstance(item, ast.Attribute):
markers.append(item.attr)
elif isinstance(node.value, ast.Attribute):
markers.append(node.value.attr)
return markers or None


def _get_tests(path):
"""Collect tests for the test module located at ``path``."""
tests = []
with open(path) as handler:
root = ast.parse(handler.read())
root.path = path # TODO improve how to pass the path to TestFunction
# Updating test module with module level markers
root.__dict__['marker_list'] = _module_markers(root)
for node in ast.iter_child_nodes(root):
if isinstance(node, ast.ClassDef):
[
Expand Down
27 changes: 27 additions & 0 deletions betelgeuse/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,30 @@ def parse_docstring(docstring=None):
field_value = output
fields_dict[field_name] = field_value
return fields_dict


def parse_markers(all_markers=None):
"""Parse the markers."""
jyejare marked this conversation as resolved.
Show resolved Hide resolved
ignore_list = ['parametrize', 'skipif', 'usefixtures', 'skip_if_not_set']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some of these seem to be robottelo-specific.
Also, since you wish to ignore skipif marker, I'd say you'd like to also ignore rhel_ver_match, one etc.

My point here is - perhaps the ignore_list might be implemented as a CLI option rather than a static, hardcoded list?

It would make it much more flexible and easy to add more over time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rplevka Your wish is granted - Now the ignore list is configurable through betelgeuse_config module 7b15cbf

resolved_markers = []

def _process_marker(marker):
# Fetching exact marker name
marker_name = marker.split('mark.')[-1] if 'mark' in marker else marker
jyejare marked this conversation as resolved.
Show resolved Hide resolved

# ignoring the marker if in ignore list
if not any(ignore_word in marker_name for ignore_word in ignore_list):
resolved_markers.append(marker_name)

for sec_marker in all_markers:
# If the marker is none
if not sec_marker:
continue
elif isinstance(sec_marker, list):
for marker in sec_marker:
_process_marker(marker)
else:
_process_marker(sec_marker)

resolved_markers = ', '.join(resolved_markers)
return resolved_markers
jyejare marked this conversation as resolved.
Show resolved Hide resolved
Loading