Merge "Update REVIEWING docs with fast-track approval process"
diff --git a/.zuul.yaml b/.zuul.yaml
index c5f7ecc..6b546ec 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -51,6 +51,41 @@
         ENABLE_FILE_INJECTION: true
 
 - job:
+    name: devstack-tempest-ipv6
+    parent: devstack-ipv6
+    nodeset: openstack-single-node
+    description: |
+      Base Tempest IPv6 job.
+    required-projects:
+      - git.openstack.org/openstack/tempest
+    timeout: 7200
+    roles:
+      - zuul: git.openstack.org/openstack-dev/devstack
+    vars:
+      devstack_services:
+        tempest: true
+      devstack_local_conf:
+        test-config:
+          $TEMPEST_CONFIG:
+            compute:
+              min_compute_nodes: "{{ groups['compute'] | default(['controller']) | length }}"
+      test_results_stage_name: test_results
+      zuul_copy_output:
+        '{{ devstack_base_dir }}/tempest/etc/tempest.conf': logs
+        '{{ devstack_base_dir }}/tempest/etc/accounts.yaml': logs
+        '{{ devstack_base_dir }}/tempest/tempest.log': logs
+        '{{ stage_dir }}/{{ test_results_stage_name }}.subunit': logs
+        '{{ stage_dir }}/{{ test_results_stage_name }}.html': logs
+        '{{ stage_dir }}/stackviz': logs
+      extensions_to_txt:
+        conf: true
+        log: true
+        yaml: true
+        yml: true
+    run: playbooks/devstack-tempest.yaml
+    post-run: playbooks/post-tempest.yaml
+
+- job:
     name: tempest-full
     parent: devstack-tempest
     # This currently works from stable/pike on.
@@ -68,6 +103,37 @@
         ENABLE_FILE_INJECTION: true
 
 - job:
+    name: tempest-full-oslo-master
+    parent: tempest-full
+    description: |
+      Integration test using current git of oslo libs.
+      This ensures that when oslo libs get released that they
+      do not break OpenStack server projects.
+
+      Former name for this job was
+      periodic-tempest-dsvm-oslo-latest-full-master.
+    timeout: 10800
+    required-projects:
+      - git.openstack.org/openstack/oslo.cache
+      - git.openstack.org/openstack/oslo.concurrency
+      - git.openstack.org/openstack/oslo.config
+      - git.openstack.org/openstack/oslo.context
+      - git.openstack.org/openstack/oslo.db
+      - git.openstack.org/openstack/oslo.i18n
+      - git.openstack.org/openstack/oslo.log
+      - git.openstack.org/openstack/oslo.messaging
+      - git.openstack.org/openstack/oslo.middleware
+      - git.openstack.org/openstack/oslo.policy
+      - git.openstack.org/openstack/oslo.privsep
+      - git.openstack.org/openstack/oslo.reports
+      - git.openstack.org/openstack/oslo.rootwrap
+      - git.openstack.org/openstack/oslo.serialization
+      - git.openstack.org/openstack/oslo.service
+      - git.openstack.org/openstack/oslo.utils
+      - git.openstack.org/openstack/oslo.versionedobjects
+      - git.openstack.org/openstack/oslo.vmware
+
+- job:
     name: tempest-full-parallel
     parent: tempest-full
     voting: false
@@ -106,6 +172,28 @@
         c-bak: false
 
 - job:
+    name: tempest-full-py3-ipv6
+    parent: devstack-tempest-ipv6
+    # This currently works from stable/pike on.
+    # Before stable/pike, legacy version of tempest-full
+    # 'legacy-tempest-dsvm-neutron-full' run.
+    branches: ^(?!stable/ocata).*$
+    description: |
+      Base integration test with Neutron networking, IPv6 and py3.
+    vars:
+      tox_envlist: full
+      devstack_localrc:
+        USE_PYTHON3: true
+        FORCE_CONFIG_DRIVE: true
+      devstack_services:
+        s-account: false
+        s-container: false
+        s-object: false
+        s-proxy: false
+        # without Swift, c-bak cannot run (in the Gate at least)
+        c-bak: false
+
+- job:
     name: tempest-multinode-full
     parent: devstack-tempest
     nodeset: openstack-two-node
@@ -372,6 +460,12 @@
               - ^playbooks/
               - ^roles/
               - ^.zuul.yaml$
+        - devstack-tempest-ipv6:
+            voting: false
+            files:
+              - ^playbooks/
+              - ^roles/
+              - ^.zuul.yaml$
         - nova-multiattach:
             # Define list of irrelevant files to use everywhere else
             irrelevant-files: &tempest-irrelevant-files
@@ -385,8 +479,13 @@
               - ^tempest/tests/.*$
         - tempest-full-parallel:
             irrelevant-files: *tempest-irrelevant-files
+        - tempest-full-py3:
+            irrelevant-files: *tempest-irrelevant-files
         - tempest-full-py36:
             irrelevant-files: *tempest-irrelevant-files
+        - tempest-full-py3-ipv6:
+            voting: false
+            irrelevant-files: *tempest-irrelevant-files
         - tempest-full-rocky:
             irrelevant-files: *tempest-irrelevant-files
         - tempest-full-rocky-py3:
@@ -459,8 +558,6 @@
             irrelevant-files: *tempest-irrelevant-files
         - tempest-all:
             irrelevant-files: *tempest-irrelevant-files
-        - legacy-tempest-dsvm-multinode-full:
-            irrelevant-files: *tempest-irrelevant-files
         - legacy-tempest-dsvm-neutron-dvr-multinode-full:
             irrelevant-files: *tempest-irrelevant-files
         - neutron-tempest-dvr-ha-multinode-full:
@@ -486,3 +583,4 @@
     periodic:
       jobs:
         - tempest-all
+        - tempest-full-oslo-master
diff --git a/playbooks/devstack-tempest.yaml b/playbooks/devstack-tempest.yaml
index 01155a8..b51e701 100644
--- a/playbooks/devstack-tempest.yaml
+++ b/playbooks/devstack-tempest.yaml
@@ -7,6 +7,11 @@
 
 # We run tests only on one node, regardless how many nodes are in the system
 - hosts: tempest
+  environment:
+    # This enviroment variable is used by the optional tempest-gabbi
+    # job provided by the gabbi-tempest plugin. It can be safely ignored
+    # if that plugin is not being used.
+    GABBI_TEMPEST_PATH: "{{ gabbi_tempest_path }}"
   roles:
     - setup-tempest-run-dir
     - setup-tempest-data-dir
diff --git a/releasenotes/notes/remove-deprecated-find-test-caller-f4525cd043bfd1b6.yaml b/releasenotes/notes/remove-deprecated-find-test-caller-f4525cd043bfd1b6.yaml
new file mode 100644
index 0000000..f22736f
--- /dev/null
+++ b/releasenotes/notes/remove-deprecated-find-test-caller-f4525cd043bfd1b6.yaml
@@ -0,0 +1,7 @@
+---
+upgrade:
+  - |
+    ``tempest.lib.common.utils.misc.find_test_caller`` was deprecated during
+    Kilo release cycle in favor of
+    ``tempest.lib.common.utils.test_utils.find_test_caller``. The deprecated
+    version of ``find_test_caller`` is removed.
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
index f0178aa..dfa801b 100644
--- a/tempest/api/compute/admin/test_security_groups.py
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -73,8 +73,17 @@
         # search filter
         fetched_list = (self.client.list_security_groups(all_tenants='true')
                         ['security_groups'])
-        # Now check if all created Security Groups are present in fetched list
-        for sec_group in fetched_list:
-            self.assertEqual(sec_group['tenant_id'], client_tenant_id,
-                             "Failed to get all security groups for "
-                             "non admin user.")
+        sec_group_id_list = [sg['id'] for sg in fetched_list]
+        # Now check that 'all_tenants='true' filter for non-admin user only
+        # provide the requested non-admin user's created security groups,
+        # not all security groups which include security groups created by
+        # other users.
+        for sec_group in security_group_list:
+            if sec_group['tenant_id'] == client_tenant_id:
+                self.assertIn(sec_group['id'], sec_group_id_list,
+                              "Failed to get all security groups for "
+                              "non admin user.")
+            else:
+                self.assertNotIn(sec_group['id'], sec_group_id_list,
+                                 "Non admin user shouldn't get other user's "
+                                 "security groups.")
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index 6d6baca..13b5161 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -133,6 +133,13 @@
                           'Security compliance not available.')
     @decorators.idempotent_id('a7ad8bbf-2cff-4520-8c1d-96332e151658')
     def test_user_account_lockout(self):
+        if (CONF.identity.user_lockout_failure_attempts <= 0 or
+                CONF.identity.user_lockout_duration <= 0):
+            raise self.skipException(
+                "Both CONF.identity.user_lockout_failure_attempts and "
+                "CONF.identity.user_lockout_duration should be greater than "
+                "zero to test this feature")
+
         password = self.creds.password
 
         # First, we login using the correct credentials
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index e79f8c3..a075b51 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -14,7 +14,9 @@
 #    under the License.
 
 from tempest.api.network import base
+from tempest.common import identity
 from tempest.common import utils
+from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 
@@ -30,7 +32,6 @@
 
         quota_driver = neutron.db.quota_db.DbQuotaDriver
     """
-    force_tenant_isolation = True
 
     @classmethod
     def skip_checks(cls):
@@ -39,27 +40,36 @@
             msg = "quotas extension not enabled."
             raise cls.skipException(msg)
 
+    def setUp(self):
+        super(QuotasNegativeTest, self).setUp()
+        name = data_utils.rand_name('test_project_')
+        description = data_utils.rand_name('desc_')
+        self.project = identity.identity_utils(self.os_admin).create_project(
+            name=name, description=description)
+        self.addCleanup(identity.identity_utils(self.os_admin).delete_project,
+                        self.project['id'])
+
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('644f4e1b-1bf9-4af0-9fd8-eb56ac0f51cf')
     def test_network_quota_exceeding(self):
         # Set the network quota to two
-        self.admin_quotas_client.update_quotas(self.networks_client.tenant_id,
-                                               network=2)
-        self.addCleanup(self.admin_quotas_client.reset_quotas,
-                        self.networks_client.tenant_id)
+        self.admin_quotas_client.update_quotas(self.project['id'], network=2)
 
         # Create two networks
-        n1 = self.networks_client.create_network()
-        self.addCleanup(self.networks_client.delete_network,
+        n1 = self.admin_networks_client.create_network(
+            tenant_id=self.project['id'])
+        self.addCleanup(self.admin_networks_client.delete_network,
                         n1['network']['id'])
-        n2 = self.networks_client.create_network()
-        self.addCleanup(self.networks_client.delete_network,
+        n2 = self.admin_networks_client.create_network(
+            tenant_id=self.project['id'])
+        self.addCleanup(self.admin_networks_client.delete_network,
                         n2['network']['id'])
 
         # Try to create a third network while the quota is two
         with self.assertRaisesRegex(
                 lib_exc.Conflict,
                 r"Quota exceeded for resources: \['network'\].*"):
-            n3 = self.networks_client.create_network()
-            self.addCleanup(self.networks_client.delete_network,
+            n3 = self.admin_networks_client.create_network(
+                tenant_id=self.project['id'])
+            self.addCleanup(self.admin_networks_client.delete_network,
                             n3['network']['id'])
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index 765bc6d..e9ca0b1 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -38,9 +38,9 @@
     def test_read_object_with_rights(self):
         # attempt to read object using authorized user
         # update X-Container-Read metadata ACL
-        tenant_name = self.os_roles_operator_alt.credentials.tenant_name
-        username = self.os_roles_operator_alt.credentials.username
-        cont_headers = {'X-Container-Read': tenant_name + ':' + username}
+        tenant_id = self.os_roles_operator_alt.credentials.tenant_id
+        user_id = self.os_roles_operator_alt.credentials.user_id
+        cont_headers = {'X-Container-Read': tenant_id + ':' + user_id}
         container_client = self.os_roles_operator.container_client
         resp_meta, _ = (
             container_client.create_update_or_delete_container_metadata(
@@ -66,9 +66,9 @@
     def test_write_object_with_rights(self):
         # attempt to write object using authorized user
         # update X-Container-Write metadata ACL
-        tenant_name = self.os_roles_operator_alt.credentials.tenant_name
-        username = self.os_roles_operator_alt.credentials.username
-        cont_headers = {'X-Container-Write': tenant_name + ':' + username}
+        tenant_id = self.os_roles_operator_alt.credentials.tenant_id
+        user_id = self.os_roles_operator_alt.credentials.user_id
+        cont_headers = {'X-Container-Write': tenant_id + ':' + user_id}
         container_client = self.os_roles_operator.container_client
         resp_meta, _ = (
             container_client.create_update_or_delete_container_metadata(
diff --git a/tempest/config.py b/tempest/config.py
index dbce504..c0a2d60 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -178,7 +178,16 @@
     cfg.IntOpt('user_unique_last_password_count',
                default=2,
                help="The number of passwords for a user that must be unique "
-                    "before an old password can be reused."),
+                    "before an old password can be reused. This only takes "
+                    "effect when identity-feature-enabled.security_compliance "
+                    "is set to 'True'."
+                    "This config option corresponds to keystone.conf: "
+                    "security_compliance.unique_last_password_count, whose "
+                    "default value is 0 meaning disabling this feature. "
+                    "NOTE: This config option value must be same as "
+                    "keystone.conf: security_compliance.unique_last_password_"
+                    "count otherwise test might fail"
+               ),
 ]
 
 service_clients_group = cfg.OptGroup(name='service-clients',
diff --git a/tempest/lib/common/utils/misc.py b/tempest/lib/common/utils/misc.py
index f13b4c8..2b0fcd5 100644
--- a/tempest/lib/common/utils/misc.py
+++ b/tempest/lib/common/utils/misc.py
@@ -14,8 +14,6 @@
 #    under the License.
 from oslo_log import log as logging
 
-from tempest.lib.common.utils import test_utils
-
 LOG = logging.getLogger(__name__)
 
 
@@ -28,10 +26,3 @@
             instances[cls] = cls()
         return instances[cls]
     return getinstance
-
-
-def find_test_caller(*args, **kwargs):
-    LOG.warning("tempest.lib.common.utils.misc.find_test_caller is deprecated "
-                "in favor of tempest.lib.common.utils.test_utils."
-                "find_test_caller")
-    test_utils.find_test_caller(*args, **kwargs)
diff --git a/tempest/tests/cmd/test_account_generator.py b/tempest/tests/cmd/test_account_generator.py
index a1d3a40..b349bba 100644
--- a/tempest/tests/cmd/test_account_generator.py
+++ b/tempest/tests/cmd/test_account_generator.py
@@ -106,6 +106,8 @@
         cp = account_generator.get_credential_provider(self.opts)
         admin_creds = cp.default_admin_creds
         self.assertEqual(self.opts.os_tenant_name, admin_creds.tenant_name)
+        self.assertEqual(self.opts.os_username, admin_creds.username)
+        self.assertEqual(self.opts.os_password, admin_creds.password)
 
 
 class TestAccountGeneratorV3(TestAccountGeneratorV2):
@@ -222,6 +224,30 @@
             self.assertIsNotNone(resource[1].router)
             self.assertIsNotNone(resource[1].subnet)
 
+    def test_generate_resources_swift_no_admin(self):
+        cfg.CONF.set_default('swift', True, group='service_available')
+        cfg.CONF.set_default('operator_role', 'fake_operator',
+                             group='object-storage')
+        cfg.CONF.set_default('reseller_admin_role', 'fake_reseller',
+                             group='object-storage')
+        resources = account_generator.generate_resources(
+            self.cred_provider, admin=False)
+        resource_types = [k for k, _ in resources]
+        # No Admin, swift, expect four credentials only
+        self.assertEqual(4, len(resources))
+        # Ensure create_user was invoked 4 times (4 distinct users)
+        self.assertEqual(4, self.user_create_fixture.mock.call_count)
+        self.assertIn('primary', resource_types)
+        self.assertIn('alt', resource_types)
+        self.assertNotIn('admin', resource_types)
+        self.assertIn(['fake_operator'], resource_types)
+        self.assertIn(['fake_reseller'], resource_types)
+        self.assertNotIn(['fake_owner'], resource_types)
+        for resource in resources:
+            self.assertIsNotNone(resource[1].network)
+            self.assertIsNotNone(resource[1].router)
+            self.assertIsNotNone(resource[1].subnet)
+
 
 class TestGenerateResourcesV3(TestGenerateResourcesV2):
 
diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py
index 9a6be4e..e159cdc 100644
--- a/tempest/tests/cmd/test_run.py
+++ b/tempest/tests/cmd/test_run.py
@@ -24,7 +24,9 @@
 import six
 
 from tempest.cmd import run
+from tempest.cmd import workspace
 from tempest import config
+from tempest.lib.common.utils import data_utils
 from tempest.tests import base
 
 DEVNULL = open(os.devnull, 'wb')
@@ -58,6 +60,12 @@
         self.assertEqual(['i_am_a_fun_little_regex'],
                          self.run_cmd._build_regex(args))
 
+    def test__build_regex_smoke_regex(self):
+        args = mock.Mock(spec=argparse.Namespace)
+        setattr(args, "smoke", True)
+        setattr(args, 'regex', 'i_am_a_fun_little_regex')
+        self.assertEqual(['smoke'], self.run_cmd._build_regex(args))
+
 
 class TestRunReturnCode(base.TestCase):
     def setUp(self):
@@ -173,6 +181,27 @@
 
 
 class TestTakeAction(base.TestCase):
+    def setUp(self):
+        super(TestTakeAction, self).setUp()
+        self.name = data_utils.rand_name('workspace')
+        self.path = tempfile.mkdtemp()
+        self.addCleanup(shutil.rmtree, self.path, ignore_errors=True)
+        store_dir = tempfile.mkdtemp()
+        self.addCleanup(shutil.rmtree, store_dir, ignore_errors=True)
+        self.store_file = os.path.join(store_dir, 'workspace.yaml')
+        self.workspace_manager = workspace.WorkspaceManager(
+            path=self.store_file)
+        self.workspace_manager.register_new_workspace(self.name, self.path)
+
+    def _setup_test_dirs(self):
+        self.directory = tempfile.mkdtemp(prefix='tempest-unit')
+        self.addCleanup(shutil.rmtree, self.directory, ignore_errors=True)
+        self.test_dir = os.path.join(self.directory, 'tests')
+        os.mkdir(self.test_dir)
+        # Change directory, run wrapper and check result
+        self.addCleanup(os.chdir, os.path.abspath(os.curdir))
+        os.chdir(self.directory)
+
     def test_workspace_not_registered(self):
         class Exception_(Exception):
             pass
@@ -201,15 +230,7 @@
         self.assertIn(workspace, exit_msg)
 
     def test_config_file_specified(self):
-        # Setup test dirs
-        self.directory = tempfile.mkdtemp(prefix='tempest-unit')
-        self.addCleanup(shutil.rmtree, self.directory)
-        self.test_dir = os.path.join(self.directory, 'tests')
-        os.mkdir(self.test_dir)
-        # Change directory, run wrapper and check result
-        self.addCleanup(os.chdir, os.path.abspath(os.curdir))
-        os.chdir(self.directory)
-
+        self._setup_test_dirs()
         tempest_run = run.TempestRun(app=mock.Mock(), app_args=mock.Mock())
         parsed_args = mock.Mock()
 
@@ -222,3 +243,97 @@
             m.return_value = 0
             self.assertEqual(0, tempest_run.take_action(parsed_args))
             m.assert_called()
+
+    def test_no_config_file_no_workspace_no_state(self):
+        self._setup_test_dirs()
+        tempest_run = run.TempestRun(app=mock.Mock(), app_args=mock.Mock())
+        parsed_args = mock.Mock()
+
+        parsed_args.workspace = None
+        parsed_args.state = None
+        parsed_args.list_tests = False
+        parsed_args.config_file = ''
+
+        with mock.patch('stestr.commands.run_command'):
+            self.assertRaises(SystemExit, tempest_run.take_action, parsed_args)
+
+    def test_config_file_workspace_registered(self):
+        self._setup_test_dirs()
+        tempest_run = run.TempestRun(app=mock.Mock(), app_args=mock.Mock())
+        parsed_args = mock.Mock()
+        parsed_args.workspace = self.name
+        parsed_args.workspace_path = self.store_file
+        parsed_args.state = None
+        parsed_args.list_tests = False
+        parsed_args.config_file = '.stestr.conf'
+
+        with mock.patch('stestr.commands.run_command') as m:
+            m.return_value = 0
+            self.assertEqual(0, tempest_run.take_action(parsed_args))
+            m.assert_called()
+
+    @mock.patch('tempest.cmd.run.TempestRun._init_state')
+    def test_workspace_registered_no_config_no_state(self, mock_init_state):
+        self._setup_test_dirs()
+        tempest_run = run.TempestRun(app=mock.Mock(), app_args=mock.Mock())
+        parsed_args = mock.Mock()
+        parsed_args.workspace = self.name
+        parsed_args.workspace_path = self.store_file
+        parsed_args.state = None
+        parsed_args.list_tests = False
+        parsed_args.config_file = ''
+
+        with mock.patch('stestr.commands.run_command') as m:
+            m.return_value = 0
+            self.assertEqual(0, tempest_run.take_action(parsed_args))
+            m.assert_called()
+        mock_init_state.assert_not_called()
+
+    @mock.patch('tempest.cmd.run.TempestRun._init_state')
+    def test_no_config_file_no_workspace_state_true(self, mock_init_state):
+        self._setup_test_dirs()
+        tempest_run = run.TempestRun(app=mock.Mock(), app_args=mock.Mock())
+        parsed_args = mock.Mock()
+
+        parsed_args.workspace = None
+        parsed_args.state = True
+        parsed_args.list_tests = False
+        parsed_args.config_file = ''
+
+        with mock.patch('stestr.commands.run_command'):
+            self.assertRaises(SystemExit, tempest_run.take_action, parsed_args)
+        mock_init_state.assert_not_called()
+
+    @mock.patch('tempest.cmd.run.TempestRun._init_state')
+    def test_workspace_registered_no_config_state_true(self, mock_init_state):
+        self._setup_test_dirs()
+        tempest_run = run.TempestRun(app=mock.Mock(), app_args=mock.Mock())
+        parsed_args = mock.Mock()
+        parsed_args.workspace = self.name
+        parsed_args.workspace_path = self.store_file
+        parsed_args.state = True
+        parsed_args.list_tests = False
+        parsed_args.config_file = ''
+
+        with mock.patch('stestr.commands.run_command') as m:
+            m.return_value = 0
+            self.assertEqual(0, tempest_run.take_action(parsed_args))
+            m.assert_called()
+        mock_init_state.assert_called()
+
+    @mock.patch('tempest.cmd.run.TempestRun._init_state')
+    def test_no_workspace_config_file_state_true(self, mock_init_state):
+        self._setup_test_dirs()
+        tempest_run = run.TempestRun(app=mock.Mock(), app_args=mock.Mock())
+        parsed_args = mock.Mock()
+        parsed_args.workspace = None
+        parsed_args.workspace_path = self.store_file
+        parsed_args.state = True
+        parsed_args.list_tests = False
+        parsed_args.config_file = '.stestr.conf'
+
+        with mock.patch('stestr.commands.run_command') as m:
+            m.return_value = 0
+            self.assertEqual(0, tempest_run.take_action(parsed_args))
+            m.assert_called()
+        mock_init_state.assert_called()
diff --git a/tempest/tests/lib/services/image/v2/test_resource_types_client.py b/tempest/tests/lib/services/image/v2/test_resource_types_client.py
index 2e3b117..741b4eb 100644
--- a/tempest/tests/lib/services/image/v2/test_resource_types_client.py
+++ b/tempest/tests/lib/services/image/v2/test_resource_types_client.py
@@ -17,7 +17,7 @@
 from tempest.tests.lib.services import base
 
 
-class TestResouceTypesClient(base.BaseServiceTest):
+class TestResourceTypesClient(base.BaseServiceTest):
     FAKE_LIST_RESOURCETYPES = {
         "resource_types": [
             {
@@ -49,21 +49,21 @@
     }
 
     def setUp(self):
-        super(TestResouceTypesClient, self).setUp()
+        super(TestResourceTypesClient, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = resource_types_client.ResourceTypesClient(fake_auth,
                                                                 'image',
                                                                 'regionOne')
 
-    def _test_list_resouce_types(self, bytes_body=False):
+    def _test_list_resource_types(self, bytes_body=False):
         self.check_service_client_function(
             self.client.list_resource_types,
             'tempest.lib.common.rest_client.RestClient.get',
             self.FAKE_LIST_RESOURCETYPES,
             bytes_body)
 
-    def test_list_resouce_types_with_str_body(self):
-        self._test_list_resouce_types()
+    def test_list_resource_types_with_str_body(self):
+        self._test_list_resource_types()
 
-    def test_list_resouce_types_with_bytes_body(self):
-        self._test_list_resouce_types(bytes_body=True)
+    def test_list_resource_types_with_bytes_body(self):
+        self._test_list_resource_types(bytes_body=True)
diff --git a/tox.ini b/tox.ini
index 8208066..4d3c622 100644
--- a/tox.ini
+++ b/tox.ini
@@ -20,7 +20,7 @@
     OS_STDERR_CAPTURE=1
     OS_TEST_TIMEOUT=160
     PYTHONWARNINGS=default::DeprecationWarning,ignore::DeprecationWarning:distutils,ignore::DeprecationWarning:site
-passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY ZUUL_CACHE_DIR REQUIREMENTS_PIP_LOCATION GENERATE_TEMPEST_PLUGIN_LIST
+passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY ZUUL_CACHE_DIR REQUIREMENTS_PIP_LOCATION GENERATE_TEMPEST_PLUGIN_LIST GABBI_TEMPEST_PATH
 usedevelop = True
 install_command = pip install {opts} {packages}
 whitelist_externals = *
@@ -182,6 +182,7 @@
 commands = {posargs}
 
 [testenv:docs]
+basepython = python3
 deps =
   -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
   -r{toxinidir}/requirements.txt
@@ -192,6 +193,7 @@
 whitelist_externals = rm
 
 [testenv:pep8]
+basepython = python3
 commands =
     flake8 {posargs}
     check-uuid
@@ -216,6 +218,7 @@
 import-order-style = pep8
 
 [testenv:releasenotes]
+basepython = python3
 deps =
   -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
   -r{toxinidir}/requirements.txt