Merge "Remove dsvm prefix from in-repo zuul jobs"
diff --git a/.gitignore b/.gitignore
index 6d47339..b77e7f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -59,4 +59,4 @@
 releasenotes/build
 
 # Misc
-.stestr/
+.stestr
diff --git a/.stestr.conf b/.stestr.conf
new file mode 100644
index 0000000..76a6ac5
--- /dev/null
+++ b/.stestr.conf
@@ -0,0 +1,3 @@
+[DEFAULT]
+test_path=./patrole_tempest_plugin/tests/unit
+group_regex=([^\.]*\.)*
diff --git a/.testr.conf b/.testr.conf
deleted file mode 100644
index 87d049d..0000000
--- a/.testr.conf
+++ /dev/null
@@ -1,7 +0,0 @@
-[DEFAULT]
-test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
-             OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
-             OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
-             ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./patrole_tempest_plugin/tests/unit} $LISTOPT $IDOPTION
-test_id_option=--load-list $IDFILE
-test_list_option=--list
diff --git a/devstack/plugin.sh b/devstack/plugin.sh
index 1f666f2..10d13f6 100644
--- a/devstack/plugin.sh
+++ b/devstack/plugin.sh
@@ -18,8 +18,8 @@
             RBAC_TEST_ROLE="Member"
         fi
 
-        iniset $TEMPEST_CONFIG rbac enable_rbac True
-        iniset $TEMPEST_CONFIG rbac rbac_test_role $RBAC_TEST_ROLE
+        iniset $TEMPEST_CONFIG patrole enable_rbac True
+        iniset $TEMPEST_CONFIG patrole rbac_test_role $RBAC_TEST_ROLE
     fi
 }
 
diff --git a/doc/source/framework/overview.rst b/doc/source/framework/overview.rst
new file mode 100644
index 0000000..1c9bf3b
--- /dev/null
+++ b/doc/source/framework/overview.rst
@@ -0,0 +1,67 @@
+RBAC Testing Validation
+=======================
+
+--------
+Overview
+--------
+
+RBAC testing validation is broken up into 3 stages:
+
+  #. "Expected" stage. Determine whether the test should be able to succeed
+     or fail based on the test role defined by ``[patrole] rbac_test_role``)
+     and the policy action that the test enforces.
+  #. "Actual" stage. Run the test by calling the API endpoint that enforces
+     the expected policy action using the test role.
+  #. Comparing the outputs from both stages for consistency. A "consistent"
+     result is treated as a pass and an "inconsistent" result is treated
+     as a failure. "Consistent" (or successful) cases include:
+
+      * Expected result is ``True`` and the test passes.
+      * Expected result is ``False`` and the test fails.
+
+     For example, a 200 from the API call and a ``True`` result from
+     ``oslo.policy`` or a 403 from the API call and a ``False`` result from
+     ``oslo.policy`` are successful results.
+
+     "Inconsistent" (or failing) cases include:
+
+      * Expected result is ``False`` and the test passes. This results in an
+        ``RbacOverPermission`` exception getting thrown.
+      * Expected result is ``True`` and the test fails. This results in a
+        ``Forbidden`` exception getting thrown.
+
+     For example, a 200 from the API call and a ``False`` result from
+     ``oslo.policy`` or a 403 from the API call and a ``True`` result from
+     ``oslo.policy`` are failing results.
+
+-------------------------------
+The RBAC Rule Validation Module
+-------------------------------
+
+High-level module that provides the decorator that wraps around Tempest tests
+and serves as the entry point for RBAC testing validation. The workflow
+described above is ultimately carried out by the decorator.
+
+For more information about this module, please see :ref:`rbac-validation`.
+
+---------------------------
+The Policy Authority Module
+---------------------------
+
+Module called by :ref:`rbac-validation` to verify whether the test
+role is allowed to execute a policy action by querying ``oslo.policy`` with
+required test data. The result is used by :ref:`rbac-validation` as the
+"Expected" result.
+
+For more information about this module, please see :ref:`policy-authority`.
+
+---------------------
+The RBAC Utils Module
+---------------------
+
+This module is responsible for handling role switching, the mechanism by which
+Patrole is able to set up, tear down and execute APIs using the same set
+of credentials. Every RBAC test must perform a role switch even if the role
+that is being switched to is admin.
+
+For more information about this module, please see :ref:`rbac-utils`.
diff --git a/doc/source/framework/policy_authority.rst b/doc/source/framework/policy_authority.rst
new file mode 100644
index 0000000..7cd4421
--- /dev/null
+++ b/doc/source/framework/policy_authority.rst
@@ -0,0 +1,30 @@
+.. _policy-authority:
+
+Policy Authority Module
+=======================
+
+Overview
+--------
+
+This module is only called for calculating the "Expected" result if
+``[patrole] test_custom_requirements`` is ``False``.
+
+Using the Policy Authority Module, policy verification is performed by:
+
+#. Pooling together the default `in-code` policy rules.
+#. Overriding the defaults with custom policy rules located in a policy.json,
+   if the policy file exists and the custom policy definition is explicitly
+   defined therein.
+#. Confirming that the policy action -- for example, "list_users" -- exists.
+   (``oslo.policy`` otherwise claims that role "foo" is allowed to
+   perform policy action "bar", for example, because it defers to the
+   "default" policy rule and oftentimes the default can be "anyone allowed").
+#. Performing a call with all necessary data to ``oslo.policy`` and returning
+   the expected result back to ``rbac_rule_validation`` decorator.
+
+Implementation
+--------------
+
+.. automodule:: patrole_tempest_plugin.policy_authority
+   :members:
+   :special-members:
diff --git a/doc/source/framework/rbac_utils.rst b/doc/source/framework/rbac_utils.rst
new file mode 100644
index 0000000..0f000ff
--- /dev/null
+++ b/doc/source/framework/rbac_utils.rst
@@ -0,0 +1,103 @@
+.. _rbac-utils:
+
+The RBAC Utils Module
+=====================
+
+Overview
+--------
+
+Patrole manipulates the ``os_primary`` `Tempest credentials`_, which are the
+primary set of Tempest credentials. It is necessary to use the same credentials
+across the entire test setup/test execution/test teardown workflow
+because otherwise 400-level errors will be thrown by OpenStack services.
+
+This is because many services check the request context's project scope -- and
+in very rare cases, user scope. However, each set of Tempest credentials (via
+`dynamic credentials`_) is allocated its own distinct project. For example, the
+``os_admin`` and ``os_primary`` credentials each have a distinct project,
+meaning that it is not always possible for the ``os_primary`` credentials to
+access resources created by the ``os_admin`` credentials.
+
+The only foolproof solution is to manipulate the role for the same set of
+credentials, rather than using distinct credentials for setup/teardown
+and test execution, respectively. This is especially true when considering
+custom policy rule definitions, which can be arbitrarily complex.
+
+Patrole, therefore, implicitly splits up each test into 3 stages: set up,
+test execution, and teardown.
+
+The role workflow is as follows:
+
+#. Setup: Admin role is used automatically. The primary credentials are
+   overridden with the admin role.
+#. Test execution: ``[patrole] rbac_test_role`` is used manually via a call
+   to ``rbac_utils.switch_role(self, toggle_rbac_role=True)``. Everything that
+   is executed after this call, until the end of the test, uses the primary
+   credentials overridden with the ``rbac_test_role``.
+#. Teardown: Admin role is used automatically. The primary credentials have
+   been overridden with the admin role.
+
+.. _Tempest credentials: https://docs.openstack.org/tempest/latest/library/credential_providers.html
+.. _dynamic credentials: https://docs.openstack.org/tempest/latest/configuration.html#dynamic-credentials
+
+Test Setup
+----------
+
+Automatic role switch in background.
+
+Resources can be set up inside the ``resource_setup`` class method that Tempest
+provides. These resources are typically reserved for "expensive" resources
+in terms of memory or storage requirements, like volumes and VMs. These
+resources are **always** created via the admin role; Patrole automatically
+handles this.
+
+Like Tempest, however, Patrole must also create resources inside tests
+themselves. At the beginning of each test, the primary credentials have already
+been overridden with the admin role. One can create whatever test-level
+resources one needs, without having to worry about permissions.
+
+Test Execution
+--------------
+
+Manual role switch required.
+
+"Test execution" here means calling the API endpoint that enforces the policy
+action expected by the ``rbac_rule_validation`` decorator. Test execution
+should be performed *only after* calling
+``rbac_utils.switch_role(self, toggle_rbac_role=True)``.
+
+Immediately after that call, the API endpoint that enforces the policy should
+be called.
+
+Example::
+
+    # Always apply the RBAC decorator to the test.
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-aggregates:show")
+    def test_show_aggregate_rbac(self):
+        # Do test setup before the switch_role call.
+        aggregate_id = self._create_aggregate()
+        # Call the switch_role method so that the primary credentials have
+        # the test role needed for test execution.
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        # Call the endpoint that enforces the expected policy action, described
+        # by the "rule" kwarg in the decorator above.
+        self.aggregates_client.show_aggregate(aggregate_id)
+
+Test Cleanup
+------------
+
+Automatic role switch in background.
+
+After the test -- no matter whether it ended successfully or in failure --
+the credentials are overridden with the admin role by the Patrole framework,
+*before* ``tearDown`` or ``tearDownClass`` are called. This means that
+resources are always cleaned up using the admin role.
+
+Implementation
+--------------
+
+.. automodule:: patrole_tempest_plugin.rbac_utils
+   :members:
+   :private-members:
diff --git a/doc/source/framework/rbac_validation.rst b/doc/source/framework/rbac_validation.rst
new file mode 100644
index 0000000..186dfe2
--- /dev/null
+++ b/doc/source/framework/rbac_validation.rst
@@ -0,0 +1,19 @@
+.. _rbac-validation:
+
+RBAC Rule Validation Module
+===========================
+
+Overview
+--------
+
+Module that implements the decorator which serves as the entry point for
+RBAC validation testing. The decorator should be applied to every RBAC test
+with the appropriate ``service`` (OpenStack service) and ``rule`` (OpenStack
+policy name defined by the ``service``).
+
+Implementation
+--------------
+
+.. automodule:: patrole_tempest_plugin.rbac_rule_validation
+   :members:
+   :private-members:
diff --git a/doc/source/index.rst b/doc/source/index.rst
index e2cc0bd..308c12c 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -30,7 +30,10 @@
 .. toctree::
    :maxdepth: 2
 
-   rbac_validation
+   framework/overview
+   framework/rbac_validation
+   framework/policy_authority
+   framework/rbac_utils
 
 Indices and tables
 ==================
diff --git a/doc/source/rbac_validation.rst b/doc/source/rbac_validation.rst
deleted file mode 100644
index a3cd7e6..0000000
--- a/doc/source/rbac_validation.rst
+++ /dev/null
@@ -1,73 +0,0 @@
-.. _rbac-validation:
-
-RBAC Testing Validation
-=======================
-
---------
-Overview
---------
-
-RBAC testing validation is broken up into 3 stages:
-
-  1. "Expected" stage. Determine whether the test should be able to succeed
-     or fail based on the test role defined by ``[patrole] rbac_test_role``)
-     and the policy action that the test enforces.
-  2. "Actual" stage. Run the test by calling the API endpoint that enforces
-     the expected policy action using the test role.
-  3. Comparing the outputs from both stages for consistency. A "consistent"
-     result is treated as a pass and an "inconsistent" result is treated
-     as a failure. "Consistent" (or successful) cases include:
-
-      * Expected result is ``True`` and the test passes.
-      * Expected result is ``False`` and the test fails.
-
-     "Inconsistent" (or failing) cases include:
-
-      * Expected result is ``False`` and the test passes. This results in an
-        ``RbacOverPermission`` exception getting thrown.
-      * Expected result is ``True`` and the test fails. This results in a
-        ``Forbidden`` exception getting thrown.
-
-     For example, a 200 from the API call and a ``True`` result from
-     ``oslo.policy`` or a 403 from the API call and a ``False`` result from
-     ``oslo.policy`` are successful results.
-
--------------------------------
-The RBAC Rule Validation Module
--------------------------------
-
-High-level module that implements decorator inside which the "Expected" stage
-is initiated.
-
-.. automodule:: patrole_tempest_plugin.rbac_rule_validation
-   :members:
-   :private-members:
-
----------------------------
-The Policy Authority Module
----------------------------
-
-Module called by the "RBAC Rule Validation Module" to verify whether the test
-role is allowed to execute a policy action by querying ``oslo.policy`` with
-required test data. The result is used by the "RBAC Rule Validation Module" as
-the `expected` result.
-
-This module is only called for calculating the `expected` result if
-``[patrole] test_custom_requirements`` is ``False``.
-
-Using the Policy Authority Module, policy verification is performed by:
-
-1. Pooling together the default `in-code` policy rules.
-2. Overriding the defaults with custom policy rules located in a policy.json,
-   if the policy file exists and the custom policy definition is explicitly
-   defined therein.
-3. Confirming that the policy action -- for example, "list_users" -- exists.
-   (``oslo.policy`` otherwise claims that role "foo" is allowed to
-   perform policy action "bar", for example, because it defers to the
-   "default" policy rule and oftentimes the default can be "anyone allowed").
-4. Performing a call with all necessary data to ``oslo.policy`` and returning
-   the expected result back to ``rbac_rule_validation`` decorator.
-
-.. automodule:: patrole_tempest_plugin.policy_authority
-   :members:
-   :special-members:
diff --git a/doc/source/usage.rst b/doc/source/usage.rst
index dff43f2..14c2cc7 100644
--- a/doc/source/usage.rst
+++ b/doc/source/usage.rst
@@ -4,8 +4,8 @@
 Usage
 ========
 
-RBAC (API) Tests
-================
+Patrole (API) Tests
+===================
 
 If Patrole is installed correctly, then the RBAC tests can be executed
 from inside the tempest root directory as follows::
@@ -28,7 +28,7 @@
 ..
 
 To change the role that the patrole tests are being run as, edit
-``rbac_test_role`` in the ``rbac`` section of tempest.conf: ::
+``rbac_test_role`` in the ``patrole`` section of tempest.conf: ::
 
     [patrole]
     rbac_test_role = Member
diff --git a/etc/patrole.conf.sample b/etc/patrole.conf.sample
index 370ca8d..cafdf8a 100644
--- a/etc/patrole.conf.sample
+++ b/etc/patrole.conf.sample
@@ -14,11 +14,17 @@
 # Enables RBAC tests. (boolean value)
 #enable_rbac = true
 
-# If true, throws RbacParsingException for policies which
+# DEPRECATED: If true, throws RbacParsingException for policies which
 # don't exist or are not included in the service's policy file. If
 # false, throws
 # skipException. (boolean value)
-#strict_policy_check = false
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: This option allows for the possibility
+# of false positives. As a testing framework, Patrole should fail any
+# test that
+# passes in an invalid policy.
+#strict_policy_check = true
 
 # List of the paths to search for policy files. Each
 # policy path assumes that the service name is included in the path
@@ -32,46 +38,6 @@
 #  (list value)
 #custom_policy_files = /etc/%s/policy.json
 
-# DEPRECATED: Location of the Cinder policy file. Assumed to be on
-# the same host as Patrole. (string value)
-# This option is deprecated for removal.
-# Its value may be silently ignored in the future.
-# Reason: It is better to use `custom_policy_files` which supports any
-# OpenStack service.
-#cinder_policy_file = /etc/cinder/policy.json
-
-# DEPRECATED: Location of the Glance policy file. Assumed to be on
-# the same host as Patrole. (string value)
-# This option is deprecated for removal.
-# Its value may be silently ignored in the future.
-# Reason: It is better to use `custom_policy_files` which supports any
-# OpenStack service.
-#glance_policy_file = /etc/glance/policy.json
-
-# DEPRECATED: Location of the custom Keystone policy file. Assumed to
-# be on the same host as Patrole. (string value)
-# This option is deprecated for removal.
-# Its value may be silently ignored in the future.
-# Reason: It is better to use `custom_policy_files` which supports any
-# OpenStack service.
-#keystone_policy_file = /etc/keystone/policy.json
-
-# DEPRECATED: Location of the Neutron policy file. Assumed to be on
-# the same host as Patrole. (string value)
-# This option is deprecated for removal.
-# Its value may be silently ignored in the future.
-# Reason: It is better to use `custom_policy_files` which supports any
-# OpenStack service.
-#neutron_policy_file = /etc/neutron/policy.json
-
-# DEPRECATED: Location of the custom Nova policy file. Assumed to be
-# on the same host as Patrole. (string value)
-# This option is deprecated for removal.
-# Its value may be silently ignored in the future.
-# Reason: It is better to use `custom_policy_files` which supports any
-# OpenStack service.
-#nova_policy_file = /etc/nova/policy.json
-
 #
 # This option determines whether Patrole should run against a
 # `custom_requirements_file` which defines RBAC requirements. The
@@ -146,131 +112,3 @@
 # is logged. This is combined withreport_log_name to generate the full
 # path. (string value)
 #report_log_path = .
-
-
-[rbac]
-# This group is deprecated and will be removed in the next release.
-# Use the [patrole] group instead.
-
-#
-# From patrole.config
-#
-
-# The current RBAC role against which to run Patrole
-# tests. (string value)
-#rbac_test_role = admin
-
-# Enables RBAC tests. (boolean value)
-#enable_rbac = true
-
-# If true, throws RbacParsingException for policies which
-# don't exist or are not included in the service's policy file. If
-# false, throws
-# skipException. (boolean value)
-#strict_policy_check = false
-
-# List of the paths to search for policy files. Each
-# policy path assumes that the service name is included in the path
-# once. Also
-# assumes Patrole is on the same host as the policy files. The paths
-# should be
-# ordered by precedence, with high-priority paths before low-priority
-# paths. The
-# first path that is found to contain the service's policy file will
-# be used.
-#  (list value)
-#custom_policy_files = /etc/%s/policy.json
-
-# DEPRECATED: Location of the Cinder policy file. Assumed to be on
-# the same host as Patrole. (string value)
-# This option is deprecated for removal.
-# Its value may be silently ignored in the future.
-# Reason: It is better to use `custom_policy_files` which supports any
-# OpenStack service.
-#cinder_policy_file = /etc/cinder/policy.json
-
-# DEPRECATED: Location of the Glance policy file. Assumed to be on
-# the same host as Patrole. (string value)
-# This option is deprecated for removal.
-# Its value may be silently ignored in the future.
-# Reason: It is better to use `custom_policy_files` which supports any
-# OpenStack service.
-#glance_policy_file = /etc/glance/policy.json
-
-# DEPRECATED: Location of the custom Keystone policy file. Assumed to
-# be on the same host as Patrole. (string value)
-# This option is deprecated for removal.
-# Its value may be silently ignored in the future.
-# Reason: It is better to use `custom_policy_files` which supports any
-# OpenStack service.
-#keystone_policy_file = /etc/keystone/policy.json
-
-# DEPRECATED: Location of the Neutron policy file. Assumed to be on
-# the same host as Patrole. (string value)
-# This option is deprecated for removal.
-# Its value may be silently ignored in the future.
-# Reason: It is better to use `custom_policy_files` which supports any
-# OpenStack service.
-#neutron_policy_file = /etc/neutron/policy.json
-
-# DEPRECATED: Location of the custom Nova policy file. Assumed to be
-# on the same host as Patrole. (string value)
-# This option is deprecated for removal.
-# Its value may be silently ignored in the future.
-# Reason: It is better to use `custom_policy_files` which supports any
-# OpenStack service.
-#nova_policy_file = /etc/nova/policy.json
-
-#
-# This option determines whether Patrole should run against a
-# `custom_requirements_file` which defines RBAC requirements. The
-# purpose of setting this flag to True is to verify that RBAC policy
-# is in accordance to requirements. The idea is that the
-# `custom_requirements_file` perfectly defines what the RBAC
-# requirements are.
-#
-# Here are the possible outcomes when running the Patrole tests
-# against
-# a `custom_requirements_file`:
-#
-# YAML definition: allowed
-# test run: allowed
-# test result: pass
-#
-# YAML definition: allowed
-# test run: not allowed
-# test result: fail (under-permission)
-#
-# YAML definition: not allowed
-# test run: allowed
-# test result: fail (over-permission)
-#  (boolean value)
-#test_custom_requirements = false
-
-#
-# File path of the yaml file that defines your RBAC requirements. This
-# file must be located on the same host that Patrole runs on. The yaml
-# file should be written as follows:
-#
-# ```
-# <service>:
-#   <api_action>:
-#     - <allowed_role>
-#     - <allowed_role>
-#     - <allowed_role>
-#   <api_action>:
-#     - <allowed_role>
-#     - <allowed_role>
-# <service>
-#   <api_action>:
-#     - <allowed_role>
-# ```
-# Where:
-# service = the service that is being tested (cinder, nova, etc)
-# api_action = the policy action that is being tested. Examples:
-#              - volume:create
-#              - os_compute_api:servers:start
-#              - add_image
-# allowed_role = the Keystone role that is allowed to perform the API
-#  (string value)
-#custom_requirements_file = <None>
diff --git a/patrole_tempest_plugin/config.py b/patrole_tempest_plugin/config.py
index 7966247..8ac2a20 100644
--- a/patrole_tempest_plugin/config.py
+++ b/patrole_tempest_plugin/config.py
@@ -22,16 +22,13 @@
 PatroleGroup = [
     cfg.StrOpt('rbac_test_role',
                default='admin',
-               deprecated_group='rbac',
                help="""The current RBAC role against which to run Patrole
 tests."""),
     cfg.BoolOpt('enable_rbac',
                 default=True,
-                deprecated_group='rbac',
                 help="Enables RBAC tests."),
     cfg.BoolOpt('strict_policy_check',
                 default=True,
-                deprecated_group='rbac',
                 deprecated_for_removal=True,
                 deprecated_reason="""This option allows for the possibility
 of false positives. As a testing framework, Patrole should fail any test that
@@ -43,7 +40,6 @@
     # other hosts. It may be possible to leverage the v3 identity policy API.
     cfg.ListOpt('custom_policy_files',
                 default=['/etc/%s/policy.json'],
-                deprecated_group='rbac',
                 help="""List of the paths to search for policy files. Each
 policy path assumes that the service name is included in the path once. Also
 assumes Patrole is on the same host as the policy files. The paths should be
@@ -52,7 +48,6 @@
 """),
     cfg.BoolOpt('test_custom_requirements',
                 default=False,
-                deprecated_group='rbac',
                 help="""
 This option determines whether Patrole should run against a
 `custom_requirements_file` which defines RBAC requirements. The
@@ -76,7 +71,6 @@
 test result: fail (over-permission)
 """),
     cfg.StrOpt('custom_requirements_file',
-               deprecated_group='rbac',
                help="""
 File path of the yaml file that defines your RBAC requirements. This
 file must be located on the same host that Patrole runs on. The yaml
@@ -106,12 +100,6 @@
 ]
 
 
-rbac_group = cfg.OptGroup(name='rbac',
-                          title='RBAC testing options',
-                          help="This group is deprecated and will be removed "
-                               "in the next release. Use the [patrole] group "
-                               "instead.")
-
 patrole_log_group = cfg.OptGroup(
     name='patrole_log', title='Patrole Logging Options')
 
@@ -141,8 +129,7 @@
     """
     opt_list = [
         (patrole_group, PatroleGroup),
-        (patrole_log_group, PatroleLogGroup),
-        (rbac_group, PatroleGroup)
+        (patrole_log_group, PatroleLogGroup)
     ]
 
     return opt_list
diff --git a/patrole_tempest_plugin/plugin.py b/patrole_tempest_plugin/plugin.py
index b7717ea..a214892 100644
--- a/patrole_tempest_plugin/plugin.py
+++ b/patrole_tempest_plugin/plugin.py
@@ -62,12 +62,6 @@
         RBACLOG.addHandler(rbac_report_handler)
 
     def register_opts(self, conf):
-        # TODO(fmontei): Remove ``rbac_group`` in a future release as it is
-        # currently deprecated.
-        config.register_opt_group(
-            conf,
-            project_config.rbac_group,
-            project_config.PatroleGroup)
         config.register_opt_group(
             conf,
             project_config.patrole_group,
diff --git a/patrole_tempest_plugin/rbac_utils.py b/patrole_tempest_plugin/rbac_utils.py
index 9fa3740..2bb9eed 100644
--- a/patrole_tempest_plugin/rbac_utils.py
+++ b/patrole_tempest_plugin/rbac_utils.py
@@ -107,7 +107,7 @@
             # passing the second boundary before attempting to authenticate.
             # Only sleep if a token revocation occurred as a result of role
             # switching. This will optimize test runtime in the case where
-            # ``[identity] admin_role`` == ``[rbac] rbac_test_role``.
+            # ``[identity] admin_role`` == ``[patrole] rbac_test_role``.
             if not role_already_present:
                 time.sleep(1)
             test_obj.os_primary.auth_provider.set_auth()
diff --git a/patrole_tempest_plugin/tests/api/volume/test_groups_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_groups_rbac.py
index 236e927..e1c0910 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_groups_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_groups_rbac.py
@@ -27,6 +27,14 @@
     min_microversion = '3.14'
     max_microversion = 'latest'
 
+    credentials = ['primary', 'admin']
+
+    @classmethod
+    def setup_clients(cls):
+        super(GroupsV3RbacTest, cls).setup_clients()
+        cls.admin_groups_client = cls.os_admin.groups_v3_client
+        cls.admin_volumes_client = cls.os_admin.volumes_v3_client
+
     def setUp(self):
         super(GroupsV3RbacTest, self).setUp()
         self.volume_type_id = self.create_volume_type()['id']
@@ -37,20 +45,25 @@
             self.__class__.__name__ + '-Group')
         group = self.groups_client.create_group(name=group_name, **kwargs)[
             'group']
-        waiters.wait_for_volume_resource_status(
-            self.groups_client, group['id'], 'available')
-
         if ignore_notfound:
             self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                             self._delete_group, group['id'])
         else:
             self.addCleanup(self._delete_group, group['id'])
-
+        waiters.wait_for_volume_resource_status(
+            self.admin_groups_client, group['id'], 'available')
         return group
 
-    def _delete_group(self, group_id, delete_volumes=True):
-        self.groups_client.delete_group(group_id, delete_volumes)
-        self.groups_client.wait_for_resource_deletion(group_id)
+    def _delete_group(self, group_id):
+        self.groups_client.delete_group(group_id, delete_volumes=True)
+        self.admin_groups_client.wait_for_resource_deletion(group_id)
+
+        vols = self.admin_volumes_client.list_volumes(
+            detail=True, params={'all_tenants': True})['volumes']
+        for vol in vols:
+            if vol['group_id'] == group_id:
+                self.admin_volumes_client.wait_for_resource_deletion(
+                    vol['id'])
 
     @decorators.idempotent_id('43235328-66ae-424f-bc7f-f709c0ca268c')
     @rbac_rule_validation.action(
@@ -111,7 +124,7 @@
                                    volume_types=[self.volume_type_id])
 
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-        self.groups_client.delete_group(group['id'])
+        self._delete_group(group['id'])
 
 
 class GroupTypesV3RbacTest(rbac_base.BaseVolumeRbacTest):
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_metadata_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_metadata_rbac.py
index 671ac19..5866934 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_metadata_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_metadata_rbac.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
@@ -66,17 +67,6 @@
         self.volumes_client.delete_volume_metadata_item(self.volume['id'],
                                                         "key1")
 
-    @decorators.idempotent_id('a41c8eed-2051-4a25-b401-df036faacbdc')
-    @rbac_rule_validation.action(
-        service="cinder",
-        rule="volume:delete_volume_metadata")
-    def test_delete_volume_image_metadata(self):
-        self.volumes_client.update_volume_image_metadata(
-            self.volume['id'], image_id=self.image_id)
-        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-        self.volumes_client.delete_volume_image_metadata(self.volume['id'],
-                                                         'image_id')
-
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:update_volume_metadata")
     @decorators.idempotent_id('8ce2ff80-99ba-49ae-9bb1-7e96729ee5af')
@@ -98,8 +88,25 @@
     @decorators.idempotent_id('a9d9e825-5ea3-42e6-96f3-7ac4e97b2ed0')
     @rbac_rule_validation.action(
         service="cinder",
-        rule="volume:update_volume_metadata")
+        rule="volume_extension:volume_image_metadata")
     def test_update_volume_image_metadata(self):
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.volumes_client.update_volume_image_metadata(
             self.volume['id'], image_id=self.image_id)
+        self.addCleanup(self.volumes_client.delete_volume_image_metadata,
+                        self.volume['id'], 'image_id')
+
+    @decorators.idempotent_id('a41c8eed-2051-4a25-b401-df036faacbdc')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_image_metadata")
+    def test_delete_volume_image_metadata(self):
+        self.volumes_client.update_volume_image_metadata(
+            self.volume['id'], image_id=self.image_id)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.volumes_client.delete_volume_image_metadata,
+                        self.volume['id'], 'image_id')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.delete_volume_image_metadata(self.volume['id'],
+                                                         'image_id')
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_quotas_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_quotas_rbac.py
index 01f8203..6a79345 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_quotas_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_quotas_rbac.py
@@ -18,6 +18,9 @@
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
 
+QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes', 'backups',
+              'backup_gigabytes', 'per_volume_gigabytes']
+
 
 class VolumeQuotasV3RbacTest(rbac_base.BaseVolumeRbacTest):
 
@@ -31,23 +34,56 @@
         super(VolumeQuotasV3RbacTest, cls).setup_clients()
         cls.quotas_client = cls.os_primary.volume_quotas_v2_client
 
+    def _restore_default_quota_set(self):
+        default_quota_set = self.quotas_client.show_default_quota_set(
+            self.demo_tenant_id)['quota_set']
+        cleanup_quota_set = dict(
+            (k, v) for k, v in default_quota_set.items()
+            if k in QUOTA_KEYS)
+        self.addCleanup(self.quotas_client.update_quota_set,
+                        self.demo_tenant_id, **cleanup_quota_set)
+
+    @decorators.idempotent_id('427c9f0c-982e-403d-ae45-c05f4d6322ff')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:quotas:show")
+    def test_list_quotas(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quotas_client.show_quota_set(self.demo_tenant_id)
+
+    @decorators.idempotent_id('e47cf444-2753-4983-be6d-fc0d6523720f')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:quotas:show")
+    def test_list_quotas_usage_true(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quotas_client.show_quota_set(self.demo_tenant_id,
+                                          params={'usage': True})
+
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume_extension:quotas:show")
     @decorators.idempotent_id('b3c7177e-b6b1-4d0f-810a-fc95606964dd')
     def test_list_default_quotas(self):
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.quotas_client.show_default_quota_set(
-            self.demo_tenant_id)['quota_set']
+            self.demo_tenant_id)
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume_extension:quotas:update")
     @decorators.idempotent_id('60f8f421-1630-4953-b449-b22af32265c7')
-    def test_update_all_quota_resources_for_tenant(self):
+    def test_update_quota_set(self):
+        self._restore_default_quota_set()
         new_quota_set = {'gigabytes': 1009,
                          'volumes': 11,
                          'snapshots': 11}
-        # Update limits for all quota resources
+        # Update limits for all quota resources.
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.quotas_client.update_quota_set(
-            self.demo_tenant_id,
-            **new_quota_set)['quota_set']
+            self.demo_tenant_id, **new_quota_set)
+
+    @decorators.idempotent_id('329bdb88-5132-4810-b1fc-350d181577e3')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:quotas:delete")
+    def test_delete_quota_set(self):
+        self._restore_default_quota_set()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quotas_client.delete_quota_set(self.demo_tenant_id)
diff --git a/patrole_tempest_plugin/tests/unit/test_patrole.py b/patrole_tempest_plugin/tests/unit/test_patrole.py
deleted file mode 100644
index 9b8e88c..0000000
--- a/patrole_tempest_plugin/tests/unit/test_patrole.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-Tests for `patrole` module.
-"""
-
-from tempest import config
-
-from patrole_tempest_plugin.tests.unit import base
-
-CONF = config.CONF
-
-
-class TestPatrole(base.TestCase):
-
-    def test_rbac_group_backwards_compatability(self):
-        """Validate that the deprecated group [rbac] is available and has the
-        same options and option values as [patrole] group, which is current.
-        """
-        self.assertTrue(hasattr(CONF, 'patrole'))
-        self.assertTrue(hasattr(CONF, 'rbac'))
-        # Validate that both groups are identical.
-        self.assertEqual(CONF.patrole.items(), CONF.rbac.items())
diff --git a/releasenotes/notes/remove-rbac-config-group-097c200f3db99fad.yaml b/releasenotes/notes/remove-rbac-config-group-097c200f3db99fad.yaml
new file mode 100644
index 0000000..fba7dd3
--- /dev/null
+++ b/releasenotes/notes/remove-rbac-config-group-097c200f3db99fad.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+  - |
+    The ``[rbac]`` config group has been removed. Use the ``[patrole]`` group
+    instead which contains the exact same options.
diff --git a/tox.ini b/tox.ini
index e95cadf..d7801db 100644
--- a/tox.ini
+++ b/tox.ini
@@ -12,13 +12,13 @@
    LANGUAGE=en_US
    LC_ALL=en_US.utf-8
    PYTHONWARNINGS=default::DeprecationWarning
-passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
+passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
 whitelist_externals = find
 deps = -r{toxinidir}/requirements.txt
        -r{toxinidir}/test-requirements.txt
 commands =
     find . -type f -name "*.pyc" -delete
-    ostestr {posargs}
+    stestr --test-path ./patrole_tempest_plugin/tests/unit run {posargs}
 
 [testenv:pep8]
 commands = flake8 {posargs}