Implement RbacUtilsMixin for base RBAC classes
This PS implements a RbacUtilsMixin mixin class in rbac_utils
module. This mixin is useful for doing basic Patrole setup in one
place. The mixin currently handles skipping tests if the flag
`[patrole] enable_rbac` is False and initializing rbac_utils
for each RBAC test.
Following changes have been made:
* Implementation of RbacUtilsMixin
* Associated unit tests
* Refactor base RBAC classes to use the mixin
* Trivial documentation changes
Change-Id: Ieaf19ccc8ce374b12af4c481a2bddcdbe86dedec
diff --git a/patrole_tempest_plugin/rbac_utils.py b/patrole_tempest_plugin/rbac_utils.py
index 4ef0f80..753c915 100644
--- a/patrole_tempest_plugin/rbac_utils.py
+++ b/patrole_tempest_plugin/rbac_utils.py
@@ -114,7 +114,7 @@
* admin if `toggle_rbac_role` is False
* `CONF.patrole.rbac_test_role` if `toggle_rbac_role` is True
- :param test_obj: test object of type tempest.lib.base.BaseTestCase
+ :param test_obj: instance of :py:class:`tempest.test.BaseTestCase`
:param toggle_rbac_role: role to switch `os_primary` Tempest creds to
"""
self._override_role(test_obj, toggle_rbac_role)
@@ -122,7 +122,7 @@
def _override_role(self, test_obj, toggle_rbac_role=False):
"""Private helper for overriding ``os_primary`` Tempest credentials.
- :param test_obj: test object of type tempest.lib.base.BaseTestCase
+ :param test_obj: instance of :py:class:`tempest.test.BaseTestCase`
:param toggle_rbac_role: Boolean value that controls the role that
overrides default role of ``os_primary`` credentials.
* If True: role is set to ``[patrole] rbac_test_role``
@@ -203,6 +203,39 @@
return False
+class RbacUtilsMixin(object):
+ """Mixin class to be used alongside an instance of
+ :py:class:`tempest.test.BaseTestCase`.
+
+ Should be used to perform Patrole class setup for a base RBAC class. Child
+ classes should not use this mixin.
+
+ Example::
+
+ class BaseRbacTest(rbac_utils.RbacUtilsMixin, base.BaseV2ComputeTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(BaseRbacTest, cls).skip_checks()
+ cls.skip_rbac_checks()
+
+ @classmethod
+ def setup_clients(cls):
+ super(BaseRbacTest, cls).setup_clients()
+ cls.setup_rbac_utils()
+ """
+
+ @classmethod
+ def skip_rbac_checks(cls):
+ if not CONF.patrole.enable_rbac:
+ raise cls.skipException(
+ '%s skipped as Patrole testing not enabled.' % cls.__name__)
+
+ @classmethod
+ def setup_rbac_utils(cls):
+ cls.rbac_utils = RbacUtils(cls)
+
+
def is_admin():
"""Verifies whether the current test role equals the admin role.
diff --git a/patrole_tempest_plugin/tests/api/compute/rbac_base.py b/patrole_tempest_plugin/tests/api/compute/rbac_base.py
index 6246446..1bd1cc7 100644
--- a/patrole_tempest_plugin/tests/api/compute/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/compute/rbac_base.py
@@ -21,20 +21,18 @@
CONF = config.CONF
-class BaseV2ComputeRbacTest(compute_base.BaseV2ComputeTest):
+class BaseV2ComputeRbacTest(rbac_utils.RbacUtilsMixin,
+ compute_base.BaseV2ComputeTest):
@classmethod
def skip_checks(cls):
super(BaseV2ComputeRbacTest, cls).skip_checks()
- if not CONF.patrole.enable_rbac:
- raise cls.skipException(
- '%s skipped as RBAC testing not enabled' % cls.__name__)
+ cls.skip_rbac_checks()
@classmethod
def setup_clients(cls):
super(BaseV2ComputeRbacTest, cls).setup_clients()
- cls.rbac_utils = rbac_utils.RbacUtils(cls)
-
+ cls.setup_rbac_utils()
cls.hosts_client = cls.os_primary.hosts_client
cls.tenant_usages_client = cls.os_primary.tenant_usages_client
diff --git a/patrole_tempest_plugin/tests/api/identity/rbac_base.py b/patrole_tempest_plugin/tests/api/identity/rbac_base.py
index a99365d..63f6ff8 100644
--- a/patrole_tempest_plugin/tests/api/identity/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/identity/rbac_base.py
@@ -26,19 +26,18 @@
LOG = logging.getLogger(__name__)
-class BaseIdentityRbacTest(base.BaseIdentityTest):
+class BaseIdentityRbacTest(rbac_utils.RbacUtilsMixin,
+ base.BaseIdentityTest):
@classmethod
def skip_checks(cls):
super(BaseIdentityRbacTest, cls).skip_checks()
- if not CONF.patrole.enable_rbac:
- raise cls.skipException(
- "%s skipped as RBAC testing not enabled" % cls.__name__)
+ cls.skip_rbac_checks()
@classmethod
def setup_clients(cls):
super(BaseIdentityRbacTest, cls).setup_clients()
- cls.rbac_utils = rbac_utils.RbacUtils(cls)
+ cls.setup_rbac_utils()
@classmethod
def setup_test_endpoint(cls, service=None):
diff --git a/patrole_tempest_plugin/tests/api/image/rbac_base.py b/patrole_tempest_plugin/tests/api/image/rbac_base.py
index ed69c3d..954790d 100644
--- a/patrole_tempest_plugin/tests/api/image/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/image/rbac_base.py
@@ -19,16 +19,15 @@
CONF = config.CONF
-class BaseV2ImageRbacTest(image_base.BaseV2ImageTest):
+class BaseV2ImageRbacTest(rbac_utils.RbacUtilsMixin,
+ image_base.BaseV2ImageTest):
@classmethod
def skip_checks(cls):
super(BaseV2ImageRbacTest, cls).skip_checks()
- if not CONF.patrole.enable_rbac:
- raise cls.skipException(
- "%s skipped as RBAC testing not enabled" % cls.__name__)
+ cls.skip_rbac_checks()
@classmethod
def setup_clients(cls):
super(BaseV2ImageRbacTest, cls).setup_clients()
- cls.rbac_utils = rbac_utils.RbacUtils(cls)
+ cls.setup_rbac_utils()
diff --git a/patrole_tempest_plugin/tests/api/network/rbac_base.py b/patrole_tempest_plugin/tests/api/network/rbac_base.py
index b495098..3065c13 100644
--- a/patrole_tempest_plugin/tests/api/network/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/network/rbac_base.py
@@ -21,16 +21,15 @@
CONF = config.CONF
-class BaseNetworkRbacTest(network_base.BaseNetworkTest):
+class BaseNetworkRbacTest(rbac_utils.RbacUtilsMixin,
+ network_base.BaseNetworkTest):
@classmethod
def skip_checks(cls):
super(BaseNetworkRbacTest, cls).skip_checks()
- if not CONF.patrole.enable_rbac:
- raise cls.skipException(
- "%s skipped as RBAC testing not enabled" % cls.__name__)
+ cls.skip_rbac_checks()
@classmethod
def setup_clients(cls):
super(BaseNetworkRbacTest, cls).setup_clients()
- cls.rbac_utils = rbac_utils.RbacUtils(cls)
+ cls.setup_rbac_utils()
diff --git a/patrole_tempest_plugin/tests/api/volume/rbac_base.py b/patrole_tempest_plugin/tests/api/volume/rbac_base.py
index 7e2ebad..798f311 100644
--- a/patrole_tempest_plugin/tests/api/volume/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/volume/rbac_base.py
@@ -21,7 +21,8 @@
CONF = config.CONF
-class BaseVolumeRbacTest(vol_base.BaseVolumeTest):
+class BaseVolumeRbacTest(rbac_utils.RbacUtilsMixin,
+ vol_base.BaseVolumeTest):
# NOTE(felipemonteiro): Patrole currently only tests the v3 Cinder API
# because it is the current API and because policy enforcement does not
# change between API major versions. So, it is not necessary to specify
@@ -32,15 +33,12 @@
@classmethod
def skip_checks(cls):
super(BaseVolumeRbacTest, cls).skip_checks()
- if not CONF.patrole.enable_rbac:
- raise cls.skipException(
- "%s skipped as RBAC testing not enabled" % cls.__name__)
+ cls.skip_rbac_checks()
@classmethod
def setup_clients(cls):
super(BaseVolumeRbacTest, cls).setup_clients()
- cls.rbac_utils = rbac_utils.RbacUtils(cls)
-
+ cls.setup_rbac_utils()
cls.volume_hosts_client = cls.os_primary.volume_hosts_v2_client
cls.volume_types_client = cls.os_primary.volume_types_v2_client
cls.groups_client = cls.os_primary.groups_v3_client
diff --git a/patrole_tempest_plugin/tests/unit/test_rbac_utils.py b/patrole_tempest_plugin/tests/unit/test_rbac_utils.py
index 0d75c3e..55db501 100644
--- a/patrole_tempest_plugin/tests/unit/test_rbac_utils.py
+++ b/patrole_tempest_plugin/tests/unit/test_rbac_utils.py
@@ -17,6 +17,7 @@
import testtools
from tempest.lib import exceptions as lib_exc
+from tempest import test
from tempest.tests import base
from patrole_tempest_plugin import rbac_exceptions
@@ -199,3 +200,60 @@
_do_test()
mock_override_role.assert_called_once_with(_rbac_utils, test_obj,
False)
+
+
+class RBACUtilsMixinTest(base.TestCase):
+
+ def setUp(self):
+ super(RBACUtilsMixinTest, self).setUp()
+
+ class FakeRbacTest(rbac_utils.RbacUtilsMixin, test.BaseTestCase):
+
+ @classmethod
+ def skip_checks(cls):
+ super(FakeRbacTest, cls).skip_checks()
+ cls.skip_rbac_checks()
+
+ @classmethod
+ def setup_clients(cls):
+ super(FakeRbacTest, cls).setup_clients()
+ cls.setup_rbac_utils()
+
+ def runTest(self):
+ pass
+
+ self.parent_class = FakeRbacTest
+
+ def test_setup_rbac_utils(self):
+ """Validate that the child class has the `rbac_utils` attribute after
+ running parent class's `cls.setup_rbac_utils`.
+ """
+ class ChildRbacTest(self.parent_class):
+ pass
+
+ child_test = ChildRbacTest()
+
+ with mock.patch.object(rbac_utils.RbacUtils, '__init__',
+ lambda *args: None):
+ child_test.setUpClass()
+
+ self.assertTrue(hasattr(child_test, 'rbac_utils'))
+ self.assertIsInstance(child_test.rbac_utils, rbac_utils.RbacUtils)
+
+ def test_skip_rbac_checks(self):
+ """Validate that the child class is skipped if `[patrole] enable_rbac`
+ is False and that the child class's name is in the skip message.
+ """
+ self.useFixture(patrole_fixtures.ConfPatcher(enable_rbac=False,
+ group='patrole'))
+
+ class ChildRbacTest(self.parent_class):
+ pass
+
+ child_test = ChildRbacTest()
+
+ with testtools.ExpectedException(
+ testtools.TestCase.skipException,
+ value_re=('%s skipped as Patrole testing not enabled.'
+ % ChildRbacTest.__name__)):
+ child_test.setUpClass()