Allow decorators.attr to be conditional

There are cases where we want to conditionally apply an
attribute to a test function, for example, if SSH validation
is enabled then a test may run much slower than if it is not.

This adds a 'condition' kwarg to the attr() decorator which
behaves similarly to the 'condition' kwarg on the skip_because()
decorator.

Change-Id: I83233854a217b6961e7614d7d9df1b4fc8d5a640
This commit is contained in:
Matt Riedemann 2019-02-14 14:32:20 -05:00
parent b4763ef57e
commit 2999963ff8
3 changed files with 31 additions and 3 deletions

View File

@ -0,0 +1,6 @@
---
features:
- |
The ``tempest.lib.decorators.attr`` decorator now supports a ``condition``
kwarg which can be used to conditionally apply the attr to the test
function if the condition evaluates to True.

View File

@ -136,9 +136,16 @@ def attr(**kwargs):
This decorator applies the testtools.testcase.attr if it is in the list of This decorator applies the testtools.testcase.attr if it is in the list of
attributes to testtools we want to apply. attributes to testtools we want to apply.
:param condition: Optional condition which if true will apply the attr. If
a condition is specified which is false the attr will not be applied to
the test function. If not specified, the attr is always applied.
""" """
def decorator(f): def decorator(f):
# Check to see if the attr should be conditional applied.
if 'condition' in kwargs and not kwargs.get('condition'):
return f
if 'type' in kwargs and isinstance(kwargs['type'], str): if 'type' in kwargs and isinstance(kwargs['type'], str):
f = testtools.testcase.attr(kwargs['type'])(f) f = testtools.testcase.attr(kwargs['type'])(f)
elif 'type' in kwargs and isinstance(kwargs['type'], list): elif 'type' in kwargs and isinstance(kwargs['type'], list):

View File

@ -32,9 +32,17 @@ class TestAttrDecorator(base.TestCase):
# By our decorators.attr decorator the attribute __testtools_attrs # By our decorators.attr decorator the attribute __testtools_attrs
# will be set only for 'type' argument, so we test it first. # will be set only for 'type' argument, so we test it first.
if 'type' in decorator_args: if 'type' in decorator_args:
# this is what testtools sets if 'condition' in decorator_args:
self.assertEqual(getattr(foo, '__testtools_attrs'), if decorator_args['condition']:
set(expected_attrs)) # The expected attrs should be in the function.
self.assertEqual(set(expected_attrs),
getattr(foo, '__testtools_attrs'))
else:
# The expected attrs should not be in the function.
self.assertNotIn('__testtools_attrs', foo)
else:
self.assertEqual(set(expected_attrs),
getattr(foo, '__testtools_attrs'))
def test_attr_without_type(self): def test_attr_without_type(self):
self._test_attr_helper(expected_attrs='baz', bar='baz') self._test_attr_helper(expected_attrs='baz', bar='baz')
@ -50,6 +58,13 @@ class TestAttrDecorator(base.TestCase):
def test_attr_decorator_with_duplicated_type(self): def test_attr_decorator_with_duplicated_type(self):
self._test_attr_helper(expected_attrs=['foo'], type=['foo', 'foo']) self._test_attr_helper(expected_attrs=['foo'], type=['foo', 'foo'])
def test_attr_decorator_condition_false(self):
self._test_attr_helper(None, type='slow', condition=False)
def test_attr_decorator_condition_true(self):
self._test_attr_helper(expected_attrs=['slow'], type='slow',
condition=True)
class TestSkipBecauseDecorator(base.TestCase): class TestSkipBecauseDecorator(base.TestCase):
def _test_skip_because_helper(self, expected_to_skip=True, def _test_skip_because_helper(self, expected_to_skip=True,