Merge "Add check_service_availability test"
diff --git a/.zuul.yaml b/.zuul.yaml
index 87e277c..dfa9add 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -676,7 +676,6 @@
             voting: false
             irrelevant-files: *tempest-irrelevant-files
         - devstack-plugin-ceph-tempest-py3:
-            voting: false
             irrelevant-files: *tempest-irrelevant-files
         - neutron-grenade-multinode:
             irrelevant-files: *tempest-irrelevant-files
@@ -718,6 +717,8 @@
             irrelevant-files: *tempest-irrelevant-files
         - tempest-ipv6-only:
             irrelevant-files: *tempest-irrelevant-files-2
+        - devstack-plugin-ceph-tempest-py3:
+            irrelevant-files: *tempest-irrelevant-files
     experimental:
       jobs:
         - tempest-cinder-v2-api:
diff --git a/releasenotes/notes/Set-default-of-operator_role-to-member-f9c3abd2ebde23b7.yaml b/releasenotes/notes/Set-default-of-operator_role-to-member-f9c3abd2ebde23b7.yaml
new file mode 100644
index 0000000..980f4ca
--- /dev/null
+++ b/releasenotes/notes/Set-default-of-operator_role-to-member-f9c3abd2ebde23b7.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+  - |
+    ``Member`` role has been deprecated and replaced by ``member``. Therefore
+    the default value of config option ``[object-storage].operator_role`` is
+    changed to ``member``. (Fixes bug #1330132)
diff --git a/releasenotes/notes/account-generator-accepts-positive-numbers-only-33a366a297494ef7.yaml b/releasenotes/notes/account-generator-accepts-positive-numbers-only-33a366a297494ef7.yaml
new file mode 100644
index 0000000..dfee1db
--- /dev/null
+++ b/releasenotes/notes/account-generator-accepts-positive-numbers-only-33a366a297494ef7.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+  - |
+   Concurrency parameter for account-generator command was accepting
+   negative values and zero. The concurrency parameter now accepts only
+   positive numbers. When a negative value or zero is passed to the
+   program then the program ends and help is displayed.
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index f42f53a..d6b6b7e 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -107,7 +107,10 @@
         """
         def verify_flavor_response_extension(flavor):
             # check some extensions for the flavor create/show/detail response
-            self.assertEqual(flavor['swap'], '')
+            if self.is_requested_microversion_compatible('2.74'):
+                self.assertEqual(flavor['swap'], '')
+            else:
+                self.assertEqual(flavor['swap'], 0)
             self.assertEqual(int(flavor['rxtx_factor']), 1)
             self.assertEqual(flavor['OS-FLV-EXT-DATA:ephemeral'], 0)
             self.assertEqual(flavor['os-flavor-access:is_public'], True)
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index 033caa8..a4d7d3f 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -43,6 +43,9 @@
         Expect all services to be returned when the request contains invalid
         parameters.
         """
+        if not self.is_requested_microversion_compatible('2.74'):
+            raise self.skipException(
+                "From microversion 2.75 invalid parameters are not allowed.")
         services = self.client.list_services()['services']
         services_xxx = (self.client.list_services(xxx='nova-compute')
                         ['services'])
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 5a646f9..1247494 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -122,15 +122,17 @@
     def _create_server_and_rescue_image(self, hw_rescue_device=None,
                                         hw_rescue_bus=None,
                                         block_device_mapping_v2=None):
+
+        server_id = self.create_test_server(
+            wait_until='ACTIVE')['id']
+        image_id = self.create_image_from_server(
+            server_id, wait_until='ACTIVE')['id']
+
         if block_device_mapping_v2:
             server_id = self.create_test_server(
                 wait_until='ACTIVE',
                 block_device_mapping_v2=block_device_mapping_v2)['id']
-        else:
-            server_id = self.create_test_server(wait_until='ACTIVE')['id']
 
-        image_id = self.create_image_from_server(server_id,
-                                                 wait_until='ACTIVE')['id']
         if hw_rescue_bus:
             self.images_client.update_image(
                 image_id, [dict(add='/hw_rescue_bus',
@@ -193,6 +195,7 @@
 
     min_microversion = '2.87'
 
+    @decorators.attr(type='slow')
     @decorators.idempotent_id('48f123cb-922a-4065-8db6-b9a9074a556b')
     def test_stable_device_rescue_bfv_blank_volume(self):
         block_device_mapping_v2 = [{
@@ -205,6 +208,7 @@
             block_device_mapping_v2=block_device_mapping_v2)
         self._test_stable_device_rescue(server_id, rescue_image_id)
 
+    @decorators.attr(type='slow')
     @decorators.idempotent_id('e4636333-c928-40fc-98b7-70a23eef4224')
     def test_stable_device_rescue_bfv_image_volume(self):
         block_device_mapping_v2 = [{
@@ -217,19 +221,3 @@
             hw_rescue_device='disk', hw_rescue_bus='virtio',
             block_device_mapping_v2=block_device_mapping_v2)
         self._test_stable_device_rescue(server_id, rescue_image_id)
-
-    @decorators.idempotent_id('7fcc5d2c-130e-4750-95f5-7343f9d0a2f3')
-    def test_stable_device_rescue_bfv_snapshot_volume(self):
-        volume_id = self.create_volume()['id']
-        self.volumes_client.set_bootable_volume(volume_id, bootable=True)
-        snapshot_id = self.create_volume_snapshot(volume_id)['id']
-        block_device_mapping_v2 = [{
-            "boot_index": "0",
-            "source_type": "snapshot",
-            "volume_size": CONF.volume.volume_size,
-            "uuid": snapshot_id,
-            "destination_type": "volume"}]
-        server_id, rescue_image_id = self._create_server_and_rescue_image(
-            hw_rescue_device='disk', hw_rescue_bus='virtio',
-            block_device_mapping_v2=block_device_mapping_v2)
-        self._test_stable_device_rescue(server_id, rescue_image_id)
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index fa1c47f..cb05f39 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import operator
+
 from oslo_utils import timeutils
 import six
 
@@ -40,6 +42,15 @@
         authenticated_token = self.non_admin_client.show_token(
             subject_token)['token']
         # sanity checking to make sure they are indeed the same token
+        # If there are roles in the token, sort the roles
+        authenticated_token_roles = authenticated_token.get("roles")
+        if authenticated_token_roles:
+            authenticated_token["roles"] = authenticated_token_roles.sort(
+                key=operator.itemgetter('id'))
+        token_body_roles = token_body.get("roles")
+        if token_body_roles:
+            token_body["roles"] = token_body_roles.sort(
+                key=operator.itemgetter('id'))
         self.assertEqual(authenticated_token, token_body)
         # test to see if token has been properly authenticated
         self.assertEqual(authenticated_token['user']['id'], user_id)
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 322579c..bdcb5ae 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -123,7 +123,7 @@
                 self.assertEqual(object_content, obj_name[::-1].encode())
 
     @decorators.attr(type='slow')
-    @decorators.skip_because(bug='1317133')
+    @decorators.unstable_test(bug='1317133')
     @decorators.idempotent_id('be008325-1bba-4925-b7dd-93b58f22ce9b')
     @testtools.skipIf(
         not CONF.object_storage_feature_enabled.container_sync,
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index bcbcf43..7af5927 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -233,12 +233,15 @@
         return group
 
     def delete_group(self, group_id, delete_volumes=True):
-        self.groups_client.delete_group(group_id, delete_volumes)
+        group_vols = []
         if delete_volumes:
             vols = self.volumes_client.list_volumes(detail=True)['volumes']
             for vol in vols:
                 if vol['group_id'] == group_id:
-                    self.volumes_client.wait_for_resource_deletion(vol['id'])
+                    group_vols.append(vol['id'])
+        self.groups_client.delete_group(group_id, delete_volumes)
+        for vol in group_vols:
+            self.volumes_client.wait_for_resource_deletion(vol)
         self.groups_client.wait_for_resource_deletion(group_id)
 
 
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index b230615..ff552a1 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -97,6 +97,7 @@
 [OPTIONS] <accounts_file.yaml> -h``.
 """
 
+import argparse
 import os
 import traceback
 
@@ -199,6 +200,14 @@
     LOG.info('%s generated successfully!', account_file)
 
 
+def positive_int(number):
+    number = int(number)
+    if number <= 0:
+        raise argparse.ArgumentTypeError("Concurrency value should be a "
+                                         "positive number")
+    return number
+
+
 def _parser_add_args(parser):
     parser.add_argument('-c', '--config-file',
                         metavar='/etc/tempest.conf',
@@ -228,7 +237,7 @@
                         help='Resources tag')
     parser.add_argument('-r', '--concurrency',
                         default=1,
-                        type=int,
+                        type=positive_int,
                         required=False,
                         dest='concurrency',
                         help='Concurrency count')
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 8d5bdbd..235d8e3 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -60,16 +60,16 @@
 """
 
 import argparse
+import configparser
 import os
 import re
 import sys
 import traceback
+from urllib import parse as urlparse
 
 from cliff import command
 from oslo_log import log as logging
 from oslo_serialization import jsonutils as json
-from six import moves
-from six.moves.urllib import parse as urlparse
 
 from tempest import clients
 from tempest.common import credentials_factory as credentials
@@ -439,9 +439,9 @@
 
     if update:
         conf_file = _get_config_file()
-        CONF_PARSER = moves.configparser.ConfigParser()
+        CONF_PARSER = configparser.ConfigParser()
         CONF_PARSER.optionxform = str
-        CONF_PARSER.readfp(conf_file)
+        CONF_PARSER.read_file(conf_file)
 
     # Indicate not to create network resources as part of getting credentials
     net_resources = {
diff --git a/tempest/config.py b/tempest/config.py
index 204d977..e4e17f1 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -1021,7 +1021,7 @@
                help="Number of seconds to wait while looping to check the "
                     "status of a container to container synchronization"),
     cfg.StrOpt('operator_role',
-               default='Member',
+               default='member',
                help="Role to add to users created for swift tests to "
                     "enable creating containers"),
     cfg.StrOpt('reseller_admin_role',
diff --git a/tempest/lib/api_schema/response/volume/snapshots.py b/tempest/lib/api_schema/response/volume/snapshots.py
index e9aeb64..9d52801 100644
--- a/tempest/lib/api_schema/response/volume/snapshots.py
+++ b/tempest/lib/api_schema/response/volume/snapshots.py
@@ -28,7 +28,7 @@
         'status': {'type': 'string'},
         'description': {'type': ['string', 'null']},
         'created_at': parameter_types.date_time,
-        'name': {'type': 'string'},
+        'name': {'type': ['string', 'null']},
         'volume_id': {'type': 'string', 'format': 'uuid'},
         'metadata': metadata,
         'id': {'type': 'string', 'format': 'uuid'},
diff --git a/tempest/lib/common/dynamic_creds.py b/tempest/lib/common/dynamic_creds.py
index f27e926..8b82391 100644
--- a/tempest/lib/common/dynamic_creds.py
+++ b/tempest/lib/common/dynamic_creds.py
@@ -207,10 +207,10 @@
         # our newly created user has a role on the newly created project.
         if self.identity_version == 'v3' and not role_assigned:
             try:
-                self.creds_client.create_user_role('Member')
+                self.creds_client.create_user_role('member')
             except lib_exc.Conflict:
-                LOG.warning('Member role already exists, ignoring conflict.')
-            self.creds_client.assign_user_role(user, project, 'Member')
+                LOG.warning('member role already exists, ignoring conflict.')
+            self.creds_client.assign_user_role(user, project, 'member')
 
         creds = self.creds_client.get_credentials(user, project, user_password)
         return cred_provider.TestResources(creds)
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index 3ceecda..6723516 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -206,7 +206,10 @@
     def action(self, server_id, action_name,
                schema=schema.server_actions_common_schema,
                **kwargs):
-        post_body = json.dumps({action_name: kwargs})
+        if 'body' in kwargs:
+            post_body = json.dumps(kwargs['body'])
+        else:
+            post_body = json.dumps({action_name: kwargs})
         resp, body = self.post('servers/%s/action' % server_id,
                                post_body)
         if body:
@@ -608,6 +611,15 @@
         API reference:
         https://docs.openstack.org/api-ref/compute/#unshelve-restore-shelved-server-unshelve-action
         """
+        # NOTE(gmann): pass None as request body if nothing is requested.
+        # Nova started the request body check since 2.77 microversion and only
+        # accept AZ or None as valid req body and reject the empty dict {}.
+        # Before 2.77 microverison anything is valid body as Nova does not
+        # check the request body but as per api-ref None is valid request
+        # body to pass so we do not need to check the requested microversion
+        # here and always default req body to None.
+        if not kwargs:
+            kwargs['body'] = {'unshelve': None}
         return self.action(server_id, 'unshelve', **kwargs)
 
     def shelve_offload_server(self, server_id, **kwargs):
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index efdfe8e..8591771 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -1038,9 +1038,12 @@
         floatingip_id = floating_ip['id']
 
         def refresh():
-            result = (self.floating_ips_client.
-                      show_floatingip(floatingip_id)['floatingip'])
-            return status == result['status']
+            floating_ip = (self.floating_ips_client.
+                           show_floatingip(floatingip_id)['floatingip'])
+            if status == floating_ip['status']:
+                LOG.info("FloatingIP: {fp} is at status: {st}"
+                         .format(fp=floating_ip, st=status))
+            return status == floating_ip['status']
 
         if not test_utils.call_until_true(refresh,
                                           CONF.network.build_timeout,
@@ -1052,8 +1055,6 @@
                                      "failed  to reach status: {st}"
                              .format(fp=floating_ip, cst=floating_ip['status'],
                                      st=status))
-        LOG.info("FloatingIP: {fp} is at status: {st}"
-                 .format(fp=floating_ip, st=status))
 
     def check_tenant_network_connectivity(self, server,
                                           username,
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index d8584ec..f466729 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -297,9 +297,19 @@
         ip_mask = CONF.network.project_network_mask_bits
         # check if the address is not already in use, if not, set it
         if ' ' + ip_address + '/' + str(ip_mask) not in ip_output:
-            ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % (
-                                    ip_address, ip_mask, new_nic))
-            ssh_client.exec_command("sudo ip link set %s up" % new_nic)
+            try:
+                ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % (
+                                        ip_address, ip_mask, new_nic))
+                ssh_client.exec_command("sudo ip link set %s up" % new_nic)
+            except exceptions.SSHExecCommandFailed as exc:
+                if 'RTNETLINK answers: File exists' in str(exc):
+                    LOG.debug(
+                        'IP address %(ip_address)s is already set in device '
+                        '%(device)s\nPrevious "ip a" output: %(ip_output)s',
+                        {'ip_address': ip_address, 'device': new_nic,
+                         'ip_output': ip_output})
+                else:
+                    raise exc
 
     def _get_server_nics(self, ssh_client):
         reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+)[@]?.*:')
diff --git a/tempest/tests/api/compute/test_base.py b/tempest/tests/api/compute/test_base.py
index 1593464..74d2625 100644
--- a/tempest/tests/api/compute/test_base.py
+++ b/tempest/tests/api/compute/test_base.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
 
 from oslo_utils import uuidutils
 import six
diff --git a/tempest/tests/base.py b/tempest/tests/base.py
index 0b53b45..e8b2c98 100644
--- a/tempest/tests/base.py
+++ b/tempest/tests/base.py
@@ -12,7 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
+
 from oslotest import base
 
 
diff --git a/tempest/tests/cmd/test_account_generator.py b/tempest/tests/cmd/test_account_generator.py
index a962e37..7d764be 100644
--- a/tempest/tests/cmd/test_account_generator.py
+++ b/tempest/tests/cmd/test_account_generator.py
@@ -12,8 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from unittest import mock
+
 import fixtures
-import mock
 from oslo_config import cfg
 
 from tempest.cmd import account_generator
@@ -336,3 +337,24 @@
     def setUp(self):
         self.mock_domains()
         super(TestDumpAccountsV3, self).setUp()
+
+
+class TestAccountGeneratorCliCheck(base.TestCase):
+
+    def setUp(self):
+        super(TestAccountGeneratorCliCheck, self).setUp()
+        self.account_generator = account_generator.TempestAccountGenerator(
+            app=mock.Mock(), app_args=mock.Mock())
+        self.parser = self.account_generator.get_parser("generator")
+
+    def test_account_generator_zero_concurrency(self):
+        error = self.assertRaises(
+            SystemExit, lambda: self.parser.parse_args(
+                ['-r', '0', 'accounts_file.yaml']))
+        self.assertTrue(error.code != 0)
+
+    def test_account_generator_negative_concurrency(self):
+        error = self.assertRaises(
+            SystemExit, lambda: self.parser.parse_args(
+                ['-r', '-1', 'accounts_file.yaml']))
+        self.assertTrue(error.code != 0)
diff --git a/tempest/tests/cmd/test_cleanup.py b/tempest/tests/cmd/test_cleanup.py
index 1618df9..69e735b 100644
--- a/tempest/tests/cmd/test_cleanup.py
+++ b/tempest/tests/cmd/test_cleanup.py
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import mock
+from unittest import mock
 
 from tempest.cmd import cleanup
 from tempest.tests import base
diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py
index e9bbcc2..5d9ddfa 100644
--- a/tempest/tests/cmd/test_run.py
+++ b/tempest/tests/cmd/test_run.py
@@ -18,9 +18,9 @@
 import shutil
 import subprocess
 import tempfile
+from unittest import mock
 
 import fixtures
-import mock
 import six
 
 from tempest.cmd import run
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 9c76efb..721fd76 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -13,9 +13,9 @@
 #    under the License.
 
 import os
+from unittest import mock
 
 import fixtures
-import mock
 from oslo_serialization import jsonutils as json
 
 from tempest import clients
diff --git a/tempest/tests/common/test_compute.py b/tempest/tests/common/test_compute.py
index c108be9..45a439c 100644
--- a/tempest/tests/common/test_compute.py
+++ b/tempest/tests/common/test_compute.py
@@ -13,9 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from unittest import mock
+
 from six.moves.urllib import parse as urlparse
 
-import mock
 
 from tempest.common import compute
 from tempest.tests import base
diff --git a/tempest/tests/common/test_credentials_factory.py b/tempest/tests/common/test_credentials_factory.py
index 7cf87f8..0ef3742 100644
--- a/tempest/tests/common/test_credentials_factory.py
+++ b/tempest/tests/common/test_credentials_factory.py
@@ -13,7 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
+
 from oslo_config import cfg
 import testtools
 
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index e3bb836..5f8b990 100755
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -13,8 +13,8 @@
 #    under the License.
 
 import time
+from unittest import mock
 
-import mock
 from oslo_utils.fixture import uuidsentinel as uuids
 
 from tempest.common import waiters
diff --git a/tempest/tests/common/utils/test_net_utils.py b/tempest/tests/common/utils/test_net_utils.py
index 83c6bcc..51d86d1 100644
--- a/tempest/tests/common/utils/test_net_utils.py
+++ b/tempest/tests/common/utils/test_net_utils.py
@@ -10,7 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
 
 from tempest.common.utils import net_utils
 from tempest.lib import exceptions as lib_exc
diff --git a/tempest/tests/lib/cli/test_execute.py b/tempest/tests/lib/cli/test_execute.py
index c069af5..a10e3bb 100644
--- a/tempest/tests/lib/cli/test_execute.py
+++ b/tempest/tests/lib/cli/test_execute.py
@@ -12,8 +12,8 @@
 #    under the License.
 
 import subprocess
+from unittest import mock
 
-import mock
 
 from tempest.lib.cli import base as cli_base
 from tempest.lib import exceptions
diff --git a/tempest/tests/lib/cmd/__init__.py b/tempest/tests/lib/cmd/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/tests/lib/cmd/__init__.py
diff --git a/tempest/tests/lib/cmd/test_check_uuid.py b/tempest/tests/lib/cmd/test_check_uuid.py
new file mode 100644
index 0000000..01c37c6
--- /dev/null
+++ b/tempest/tests/lib/cmd/test_check_uuid.py
@@ -0,0 +1,139 @@
+# 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.
+
+import tempfile
+
+import importlib
+import mock
+
+from tempest.lib.cmd import check_uuid
+from tempest.tests import base
+
+
+class TestSourcePatcher(base.TestCase):
+    def test_add_patch(self):
+        patcher = check_uuid.SourcePatcher()
+        fake_file = tempfile.NamedTemporaryFile("w+t", delete=False)
+        file_contents = 'first_line\nsecond_line'
+        fake_file.write(file_contents)
+        fake_file.close()
+        patcher.add_patch(fake_file.name, 'patch', 2)
+
+        source_file = patcher.source_files[fake_file.name]
+        self.assertEqual(1, len(patcher.patches))
+        (patch_id, patch), = patcher.patches.items()
+        self.assertEqual(patcher._quote('patch\n'), patch)
+        self.assertEqual('first_line\n{%s:s}second_line' % patch_id,
+                         patcher._unquote(source_file))
+
+    def test_apply_patches(self):
+        fake_file = tempfile.NamedTemporaryFile("w+t")
+        patcher = check_uuid.SourcePatcher()
+        patcher.patches = {'fake-uuid': patcher._quote('patch\n')}
+        patcher.source_files = {
+            fake_file.name: patcher._quote('first_line\n') +
+            '{fake-uuid:s}second_line'}
+        with mock.patch('sys.stdout'):
+            patcher.apply_patches()
+
+        lines = fake_file.read().split('\n')
+        fake_file.close()
+        self.assertEqual(['first_line', 'patch', 'second_line'], lines)
+        self.assertFalse(patcher.patches)
+        self.assertFalse(patcher.source_files)
+
+
+class TestTestChecker(base.TestCase):
+    def _test_add_uuid_to_test(self, source_file):
+        class Fake_test_node():
+            lineno = 1
+            col_offset = 4
+        patcher = check_uuid.SourcePatcher()
+        checker = check_uuid.TestChecker(importlib.import_module('tempest'))
+        fake_file = tempfile.NamedTemporaryFile("w+t", delete=False)
+        fake_file.write(source_file)
+        fake_file.close()
+        checker._add_uuid_to_test(patcher, Fake_test_node(), fake_file.name)
+
+        self.assertEqual(1, len(patcher.patches))
+        self.assertEqual(1, len(patcher.source_files))
+        (patch_id, patch), = patcher.patches.items()
+        changed_source_file, = patcher.source_files.values()
+        self.assertEqual('{%s:s}%s' % (patch_id, patcher._quote(source_file)),
+                         changed_source_file)
+        expected_patch_start = patcher._quote(
+            '    ' + check_uuid.DECORATOR_TEMPLATE.split('(')[0])
+        self.assertTrue(patch.startswith(expected_patch_start))
+
+    def test_add_uuid_to_test_def(self):
+        source_file = ("    def test_test():\n"
+                       "        pass")
+        self._test_add_uuid_to_test(source_file)
+
+    def test_add_uuid_to_test_decorator(self):
+        source_file = ("    @decorators.idempotent_id\n"
+                       "    def test_test():\n"
+                       "        pass")
+        self._test_add_uuid_to_test(source_file)
+
+    def test_add_import_for_test_uuid_no_tempest(self):
+        patcher = check_uuid.SourcePatcher()
+        checker = check_uuid.TestChecker(importlib.import_module('tempest'))
+        fake_file = tempfile.NamedTemporaryFile("w+t")
+
+        class Fake_src_parsed():
+            body = ['test_node']
+        checker._import_name = mock.Mock(return_value='fake_module')
+
+        checker._add_import_for_test_uuid(patcher, Fake_src_parsed(),
+                                          fake_file.name)
+        (patch_id, patch), = patcher.patches.items()
+        self.assertEqual(patcher._quote('\n' + check_uuid.IMPORT_LINE + '\n'),
+                         patch)
+        self.assertEqual('{%s:s}' % patch_id,
+                         patcher.source_files[fake_file.name])
+
+    def test_add_import_for_test_uuid_tempest(self):
+        patcher = check_uuid.SourcePatcher()
+        checker = check_uuid.TestChecker(importlib.import_module('tempest'))
+        fake_file = tempfile.NamedTemporaryFile("w+t", delete=False)
+        test1 = ("    def test_test():\n"
+                 "        pass\n")
+        test2 = ("    def test_another_test():\n"
+                 "        pass\n")
+        source_code = test1 + test2
+        fake_file.write(source_code)
+        fake_file.close()
+
+        def fake_import_name(node):
+            return node.name
+        checker._import_name = fake_import_name
+
+        class Fake_node():
+            def __init__(self, lineno, col_offset, name):
+                self.lineno = lineno
+                self.col_offset = col_offset
+                self.name = name
+
+        class Fake_src_parsed():
+            body = [Fake_node(1, 4, 'tempest.a_fake_module'),
+                    Fake_node(3, 4, 'another_fake_module')]
+
+        checker._add_import_for_test_uuid(patcher, Fake_src_parsed(),
+                                          fake_file.name)
+        (patch_id, patch), = patcher.patches.items()
+        self.assertEqual(patcher._quote(check_uuid.IMPORT_LINE + '\n'),
+                         patch)
+        expected_source = patcher._quote(test1) + '{' + patch_id + ':s}' +\
+            patcher._quote(test2)
+        self.assertEqual(expected_source,
+                         patcher.source_files[fake_file.name])
diff --git a/tempest/tests/lib/common/test_cred_client.py b/tempest/tests/lib/common/test_cred_client.py
index 3dff16f..860a465 100644
--- a/tempest/tests/lib/common/test_cred_client.py
+++ b/tempest/tests/lib/common/test_cred_client.py
@@ -11,7 +11,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import mock
+from unittest import mock
 
 from tempest.lib.common import cred_client
 from tempest.tests import base
diff --git a/tempest/tests/lib/common/test_dynamic_creds.py b/tempest/tests/lib/common/test_dynamic_creds.py
index 4723458..e9073cc 100644
--- a/tempest/tests/lib/common/test_dynamic_creds.py
+++ b/tempest/tests/lib/common/test_dynamic_creds.py
@@ -12,8 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from unittest import mock
+
 import fixtures
-import mock
 from oslo_config import cfg
 
 from tempest.common import credentials_factory as credentials
@@ -110,7 +111,7 @@
                           (200,
                            {'roles': [{'id': id, 'name': name},
                                       {'id': '1', 'name': 'FakeRole'},
-                                      {'id': '2', 'name': 'Member'}]}))))
+                                      {'id': '2', 'name': 'member'}]}))))
         return roles_fix
 
     def _mock_list_2_roles(self):
@@ -139,7 +140,7 @@
             return_value=(rest_client.ResponseBody
                           (200, {'roles': [
                               {'id': '1', 'name': 'FakeRole'},
-                              {'id': '2', 'name': 'Member'}]}))))
+                              {'id': '2', 'name': 'member'}]}))))
         return roles_fix
 
     def _mock_list_ec2_credentials(self, user_id, tenant_id):
@@ -664,6 +665,6 @@
         with mock.patch('tempest.lib.common.dynamic_creds.LOG') as log_mock:
             creds._create_creds()
             log_mock.warning.assert_called_once_with(
-                "Member role already exists, ignoring conflict.")
+                "member role already exists, ignoring conflict.")
         creds.creds_client.assign_user_role.assert_called_once_with(
-            mock.ANY, mock.ANY, 'Member')
+            mock.ANY, mock.ANY, 'member')
diff --git a/tempest/tests/lib/common/test_preprov_creds.py b/tempest/tests/lib/common/test_preprov_creds.py
index 25df2a7..579363e 100644
--- a/tempest/tests/lib/common/test_preprov_creds.py
+++ b/tempest/tests/lib/common/test_preprov_creds.py
@@ -15,8 +15,8 @@
 import hashlib
 import os
 import shutil
+from unittest import mock
 
-import mock
 import six
 import testtools
 
diff --git a/tempest/tests/lib/common/test_profiler.py b/tempest/tests/lib/common/test_profiler.py
index 59fa0364..166d831 100644
--- a/tempest/tests/lib/common/test_profiler.py
+++ b/tempest/tests/lib/common/test_profiler.py
@@ -10,7 +10,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
+
 import testtools
 
 from tempest.lib.common import profiler
diff --git a/tempest/tests/lib/common/test_validation_resources.py b/tempest/tests/lib/common/test_validation_resources.py
index d5139f4..d50fd89 100644
--- a/tempest/tests/lib/common/test_validation_resources.py
+++ b/tempest/tests/lib/common/test_validation_resources.py
@@ -11,8 +11,9 @@
 #    See the License for the specific language governing permissions and
 #    limitations under the License.
 
+from unittest import mock
+
 import fixtures
-import mock
 import testtools
 
 from tempest.lib.common import validation_resources as vr
diff --git a/tempest/tests/lib/common/utils/linux/test_remote_client.py b/tempest/tests/lib/common/utils/linux/test_remote_client.py
index 7a21a5f..df23e63 100644
--- a/tempest/tests/lib/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/lib/common/utils/linux/test_remote_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
 
 from tempest.lib.common import ssh
 from tempest.lib.common.utils.linux import remote_client
diff --git a/tempest/tests/lib/common/utils/test_test_utils.py b/tempest/tests/lib/common/utils/test_test_utils.py
index 865767b..bdc0ea4 100644
--- a/tempest/tests/lib/common/utils/test_test_utils.py
+++ b/tempest/tests/lib/common/utils/test_test_utils.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 import time
+from unittest import mock
 
-import mock
 
 from tempest.lib.common import thread
 from tempest.lib.common.utils import test_utils
diff --git a/tempest/tests/lib/services/compute/test_base_compute_client.py b/tempest/tests/lib/services/compute/test_base_compute_client.py
index 69e8542..5841ae4 100644
--- a/tempest/tests/lib/services/compute/test_base_compute_client.py
+++ b/tempest/tests/lib/services/compute/test_base_compute_client.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
 
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions
diff --git a/tempest/tests/lib/services/compute/test_servers_client.py b/tempest/tests/lib/services/compute/test_servers_client.py
index 86f6ad5..a82b255 100644
--- a/tempest/tests/lib/services/compute/test_servers_client.py
+++ b/tempest/tests/lib/services/compute/test_servers_client.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 import copy
+from unittest import mock
 
-import mock
 
 from tempest.lib.services.compute import base_compute_client
 from tempest.lib.services.compute import servers_client
diff --git a/tempest/tests/lib/services/compute/test_services_client.py b/tempest/tests/lib/services/compute/test_services_client.py
index ba432e3..0c513cc 100644
--- a/tempest/tests/lib/services/compute/test_services_client.py
+++ b/tempest/tests/lib/services/compute/test_services_client.py
@@ -13,8 +13,8 @@
 #    under the License.
 
 import copy
+from unittest import mock
 
-import mock
 
 from tempest.lib.services.compute import base_compute_client
 from tempest.lib.services.compute import services_client
diff --git a/tempest/tests/lib/services/identity/v2/test_token_client.py b/tempest/tests/lib/services/identity/v2/test_token_client.py
index 5b4e210..dc14a50 100644
--- a/tempest/tests/lib/services/identity/v2/test_token_client.py
+++ b/tempest/tests/lib/services/identity/v2/test_token_client.py
@@ -12,7 +12,8 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import mock
+from unittest import mock
+
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.common import rest_client
diff --git a/tempest/tests/lib/services/identity/v3/test_token_client.py b/tempest/tests/lib/services/identity/v3/test_token_client.py
index 656e10a..1c2295d 100644
--- a/tempest/tests/lib/services/identity/v3/test_token_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_token_client.py
@@ -12,7 +12,8 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import mock
+from unittest import mock
+
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.common import rest_client
diff --git a/tempest/tests/lib/services/network/test_base_network_client.py b/tempest/tests/lib/services/network/test_base_network_client.py
index e121cec..a426397 100644
--- a/tempest/tests/lib/services/network/test_base_network_client.py
+++ b/tempest/tests/lib/services/network/test_base_network_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
 
 from tempest.lib.services.network import base as base_network_client
 from tempest.tests.lib import fake_auth_provider
diff --git a/tempest/tests/lib/services/network/test_security_group_rules_client.py b/tempest/tests/lib/services/network/test_security_group_rules_client.py
index b9c17a1..2ecc996 100644
--- a/tempest/tests/lib/services/network/test_security_group_rules_client.py
+++ b/tempest/tests/lib/services/network/test_security_group_rules_client.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 import copy
+from unittest import mock
 
-import mock
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.services.network import base as network_base
diff --git a/tempest/tests/lib/services/network/test_security_groups_client.py b/tempest/tests/lib/services/network/test_security_groups_client.py
index f96805f..501883b 100644
--- a/tempest/tests/lib/services/network/test_security_groups_client.py
+++ b/tempest/tests/lib/services/network/test_security_groups_client.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 import copy
+from unittest import mock
 
-import mock
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.services.network import base as network_base
diff --git a/tempest/tests/lib/services/object_storage/test_object_client.py b/tempest/tests/lib/services/object_storage/test_object_client.py
index 1749b03..c646d61 100644
--- a/tempest/tests/lib/services/object_storage/test_object_client.py
+++ b/tempest/tests/lib/services/object_storage/test_object_client.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 
-import mock
+from unittest import mock
 
 from tempest.lib import exceptions
 from tempest.lib.services.object_storage import object_client
diff --git a/tempest/tests/lib/services/test_clients.py b/tempest/tests/lib/services/test_clients.py
index 43fd88f..f83064a 100644
--- a/tempest/tests/lib/services/test_clients.py
+++ b/tempest/tests/lib/services/test_clients.py
@@ -13,9 +13,9 @@
 # the License.
 
 import types
+from unittest import mock
 
 import fixtures
-import mock
 import six
 import testtools
 
diff --git a/tempest/tests/lib/services/volume/v3/test_services_client.py b/tempest/tests/lib/services/volume/v3/test_services_client.py
index f65228f..c807bc2 100644
--- a/tempest/tests/lib/services/volume/v3/test_services_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_services_client.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 import copy
+from unittest import mock
 
-import mock
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.services.volume.v3 import services_client
diff --git a/tempest/tests/lib/services/volume/v3/test_snapshot_manage_client.py b/tempest/tests/lib/services/volume/v3/test_snapshot_manage_client.py
index 1b88020..8309f7a 100644
--- a/tempest/tests/lib/services/volume/v3/test_snapshot_manage_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_snapshot_manage_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
 
 from oslo_serialization import jsonutils as json
 
diff --git a/tempest/tests/lib/services/volume/v3/test_transfers_client.py b/tempest/tests/lib/services/volume/v3/test_transfers_client.py
index d631fe7..1dfe2df 100644
--- a/tempest/tests/lib/services/volume/v3/test_transfers_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_transfers_client.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 import copy
+from unittest import mock
 
-import mock
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.services.volume.v3 import transfers_client
diff --git a/tempest/tests/lib/services/volume/v3/test_volume_manage_client.py b/tempest/tests/lib/services/volume/v3/test_volume_manage_client.py
index 902f027..d4313a2 100644
--- a/tempest/tests/lib/services/volume/v3/test_volume_manage_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_volume_manage_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
 
 from oslo_serialization import jsonutils as json
 
diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py
index 9c6cac7..e3c17e8 100644
--- a/tempest/tests/lib/test_decorators.py
+++ b/tempest/tests/lib/test_decorators.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 import abc
+from unittest import mock
 
-import mock
 import six
 import testtools
 
diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py
index c849231..85048fb 100644
--- a/tempest/tests/lib/test_ssh.py
+++ b/tempest/tests/lib/test_ssh.py
@@ -13,8 +13,8 @@
 #    under the License.
 
 import socket
+from unittest import mock
 
-import mock
 import six
 from six import StringIO
 import testtools
diff --git a/tempest/tests/test_base_test.py b/tempest/tests/test_base_test.py
index 2b5a947..b154cd5 100644
--- a/tempest/tests/test_base_test.py
+++ b/tempest/tests/test_base_test.py
@@ -12,7 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
+from unittest import mock
+
 from oslo_config import cfg
 
 from tempest import clients
diff --git a/tempest/tests/test_imports.py b/tempest/tests/test_imports.py
index 6f1cfca..ad7bebb 100644
--- a/tempest/tests/test_imports.py
+++ b/tempest/tests/test_imports.py
@@ -12,7 +12,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import mock
+from unittest import mock
 
 from tempest.tests import base
 
diff --git a/tempest/tests/test_test.py b/tempest/tests/test_test.py
index 49fd010..72e8b6d 100644
--- a/tempest/tests/test_test.py
+++ b/tempest/tests/test_test.py
@@ -15,8 +15,8 @@
 
 import os
 import sys
+from unittest import mock
 
-import mock
 from oslo_config import cfg
 import testtools
 
diff --git a/test-requirements.txt b/test-requirements.txt
index 17a7d2a..17fa9f1 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -2,7 +2,6 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 hacking>=3.0.1,<3.1.0;python_version>='3.5' # Apache-2.0
-mock>=2.0.0 # BSD
 coverage!=4.4,>=4.0 # Apache-2.0
 oslotest>=3.2.0 # Apache-2.0
 pycodestyle>=2.0.0,<2.6.0 # MIT
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index 5ffef3e..530ce5e 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -52,6 +52,8 @@
     'x/tap-as-a-service',  # To avoid sanity-job failure
     'x/valet',  # https://review.opendev.org/#/c/638339/
     'x/kingbird',  # https://bugs.launchpad.net/kingbird/+bug/1869722
+    # vmware-nsx is blacklisted since https://review.opendev.org/#/c/736952
+    'x/vmware-nsx-tempest-plugin',
 ]
 
 url = 'https://review.opendev.org/projects/'
diff --git a/tools/tempest-integrated-gate-compute-blacklist.txt b/tools/tempest-integrated-gate-compute-blacklist.txt
index 8805262..2290751 100644
--- a/tools/tempest-integrated-gate-compute-blacklist.txt
+++ b/tools/tempest-integrated-gate-compute-blacklist.txt
@@ -11,3 +11,9 @@
 tempest.scenario.test_object_storage_basic_ops.TestObjectStorageBasicOps.test_swift_basic_ops
 tempest.scenario.test_object_storage_basic_ops.TestObjectStorageBasicOps.test_swift_acl_anonymous_download
 tempest.scenario.test_volume_backup_restore.TestVolumeBackupRestore.test_volume_backup_restore
+
+# Skip test scenario when creating second image from instance
+# https://bugs.launchpad.net/tripleo/+bug/1881592
+# The test is most likely wrong and may fail if the fists image is create quickly.
+# FIXME: Either fix the test so it won't race or consider if we should cover the scenario at all.
+tempest.api.compute.images.test_images_oneserver_negative.ImagesOneServerNegativeTestJSON.test_create_second_image_when_first_image_is_being_saved
diff --git a/tools/tempest-plugin-sanity.sh b/tools/tempest-plugin-sanity.sh
index 2ff4aea..c983da9 100644
--- a/tools/tempest-plugin-sanity.sh
+++ b/tools/tempest-plugin-sanity.sh
@@ -66,7 +66,7 @@
 # function to create virtualenv to perform sanity operation
 function prepare_workspace {
     SANITY_DIR=$(pwd)
-    virtualenv -p python3 --clear "$SANITY_DIR"/.venv
+    python3 -m venv "$SANITY_DIR"/.venv
     export TVENV="$SANITY_DIR/tools/with_venv.sh"
     cd "$SANITY_DIR"