Add generic CONF skip decorators

This commit adds two new decorators to tempest.config, skip_if_config()
and skip_unless_config(). These decorators take in a group and option
name and will either not skip or skip based on either the existence of
the option or the value of the option. This is can sometimes be
necessary in tempest plugins where there is an optional dependency on
another plugin. There isn't a good way to have tests that skip based
on the existence of config flags that might not exist. This adds a
stable interface for those plugins to rely on. This can't live in
tempest.lib because of it's dependence on tempest config, which
doesn't belong in the lib interface. But, since we provide stability
guarantees on tempest.config and tempest.test_discover.plugins to
tempest plugins this interface can be provided via tempest.config.

Change-Id: I7a5d0dfa59d6d36f0202acddebaa0a3dec119540
This commit is contained in:
Matthew Treinish 2016-04-16 15:04:34 -04:00
parent ffad78a29f
commit ca5a9fff5a
2 changed files with 143 additions and 0 deletions

View File

@ -15,6 +15,7 @@
from __future__ import print_function
import functools
import logging as std_logging
import os
import tempfile
@ -22,6 +23,7 @@ import tempfile
from oslo_concurrency import lockutils
from oslo_config import cfg
from oslo_log import log as logging
import testtools
from tempest.test_discover import plugins
@ -1397,3 +1399,72 @@ class TempestConfigProxy(object):
CONF = TempestConfigProxy()
def skip_unless_config(*args):
"""Decorator to raise a skip if a config opt doesn't exist and is False
:param str group: The first arg, the option group to check
:param str name: The second arg, the option name to check
:param str msg: Optional third arg, the skip msg to use if a skip is raised
:raises testtools.TestCaseskipException: If the specified config option
doesn't exist or it exists and evaluates to False
"""
def decorator(f):
group = args[0]
name = args[1]
@functools.wraps(f)
def wrapper(self, *func_args, **func_kwargs):
if not hasattr(CONF, group):
msg = "Config group %s doesn't exist" % group
raise testtools.TestCase.skipException(msg)
else:
conf_group = getattr(CONF, group)
if not hasattr(conf_group, name):
msg = "Config option %s.%s doesn't exist" % (group,
name)
raise testtools.TestCase.skipException(msg)
else:
value = getattr(conf_group, name)
if not value:
if len(args) == 3:
msg = args[2]
else:
msg = "Config option %s.%s is false" % (group,
name)
raise testtools.TestCase.skipException(msg)
return f(self, *func_args, **func_kwargs)
return wrapper
return decorator
def skip_if_config(*args):
"""Raise a skipException if a config exists and is True
:param str group: The first arg, the option group to check
:param str name: The second arg, the option name to check
:param str msg: Optional third arg, the skip msg to use if a skip is raised
:raises testtools.TestCase.skipException: If the specified config option
exists and evaluates to True
"""
def decorator(f):
group = args[0]
name = args[1]
@functools.wraps(f)
def wrapper(self, *func_args, **func_kwargs):
if hasattr(CONF, group):
conf_group = getattr(CONF, group)
if hasattr(conf_group, name):
value = getattr(conf_group, name)
if value:
if len(args) == 3:
msg = args[2]
else:
msg = "Config option %s.%s is false" % (group,
name)
raise testtools.TestCase.skipException(msg)
return f(self, *func_args, **func_kwargs)
return wrapper
return decorator

View File

@ -246,3 +246,75 @@ class TestSimpleNegativeDecorator(BaseDecoratorsTest):
self.assertIn("test_fake_negative", dir(obj))
obj.test_fake_negative()
mock.assert_called_once_with(self.FakeNegativeJSONTest._schema)
class TestConfigDecorators(BaseDecoratorsTest):
def setUp(self):
super(TestConfigDecorators, self).setUp()
cfg.CONF.set_default('nova', True, 'service_available')
cfg.CONF.set_default('glance', False, 'service_available')
def _test_skip_unless_config(self, expected_to_skip=True, *decorator_args):
class TestFoo(test.BaseTestCase):
@config.skip_unless_config(*decorator_args)
def test_bar(self):
return 0
t = TestFoo('test_bar')
if expected_to_skip:
self.assertRaises(testtools.TestCase.skipException, t.test_bar)
else:
try:
self.assertEqual(t.test_bar(), 0)
except testtools.TestCase.skipException:
# We caught a skipException but we didn't expect to skip
# this test so raise a hard test failure instead.
raise testtools.TestCase.failureException(
"Not supposed to skip")
def _test_skip_if_config(self, expected_to_skip=True,
*decorator_args):
class TestFoo(test.BaseTestCase):
@config.skip_if_config(*decorator_args)
def test_bar(self):
return 0
t = TestFoo('test_bar')
if expected_to_skip:
self.assertRaises(testtools.TestCase.skipException, t.test_bar)
else:
try:
self.assertEqual(t.test_bar(), 0)
except testtools.TestCase.skipException:
# We caught a skipException but we didn't expect to skip
# this test so raise a hard test failure instead.
raise testtools.TestCase.failureException(
"Not supposed to skip")
def test_skip_unless_no_group(self):
self._test_skip_unless_config(True, 'fake_group', 'an_option')
def test_skip_unless_no_option(self):
self._test_skip_unless_config(True, 'service_available',
'not_an_option')
def test_skip_unless_false_option(self):
self._test_skip_unless_config(True, 'service_available', 'glance')
def test_skip_unless_true_option(self):
self._test_skip_unless_config(False,
'service_available', 'nova')
def test_skip_if_no_group(self):
self._test_skip_if_config(False, 'fake_group', 'an_option')
def test_skip_if_no_option(self):
self._test_skip_if_config(False, 'service_available', 'not_an_option')
def test_skip_if_false_option(self):
self._test_skip_if_config(False, 'service_available', 'glance')
def test_skip_if_true_option(self):
self._test_skip_if_config(True, 'service_available', 'nova')