Merge "Add support to chose ssh key type"
diff --git a/manila_tempest_tests/common/remote_client.py b/manila_tempest_tests/common/remote_client.py
index 440bee2..a6eee45 100644
--- a/manila_tempest_tests/common/remote_client.py
+++ b/manila_tempest_tests/common/remote_client.py
@@ -13,7 +13,6 @@
 import sys
 
 from oslo_log import log
-import six
 from tempest import config
 from tempest.lib.common import ssh
 from tempest.lib.common.utils import test_utils
@@ -47,7 +46,7 @@
                             msg = 'Could not get console_log for server %s'
                             LOG.debug(msg, self.server['id'])
                 # re-raise the original ssh timeout exception
-                six.reraise(*original_exception)
+                raise original_exception
             finally:
                 # Delete the traceback to avoid circular references
                 _, _, trace = original_exception
diff --git a/manila_tempest_tests/common/waiters.py b/manila_tempest_tests/common/waiters.py
index 5d8d344..24b30de 100644
--- a/manila_tempest_tests/common/waiters.py
+++ b/manila_tempest_tests/common/waiters.py
@@ -15,7 +15,6 @@
 
 import time
 
-import six
 from tempest import config
 from tempest.lib import exceptions
 
@@ -137,7 +136,7 @@
                            'dest': dest_host,
                            'share_id': share['id'],
                            'timeout': client.build_timeout,
-                           'status': six.text_type(statuses),
+                           'status': str(statuses),
                        })
             raise exceptions.TimeoutException(message)
     return share
@@ -180,3 +179,41 @@
                        ' the required time (%s s).' %
                        (resource_id, client.build_timeout))
             raise exceptions.TimeoutException(message)
+
+
+def wait_for_soft_delete(client, share_id, version=LATEST_MICROVERSION):
+    """Wait for a share soft delete to recycle bin."""
+    share = client.get_share(share_id, version=version)['share']
+    start = int(time.time())
+    while not share['is_soft_deleted']:
+        time.sleep(client.build_interval)
+        share = client.get_share(share_id, version=version)['share']
+        if share['is_soft_deleted']:
+            break
+        elif int(time.time()) - start >= client.build_timeout:
+            message = ('Share %(share_id)s failed to be soft deleted to '
+                       'recycle bin within the required time '
+                       '%(timeout)s.' % {
+                           'share_id': share['id'],
+                           'timeout': client.build_timeout,
+                       })
+            raise exceptions.TimeoutException(message)
+
+
+def wait_for_restore(client, share_id, version=LATEST_MICROVERSION):
+    """Wait for a share restore from recycle bin."""
+    share = client.get_share(share_id, version=version)['share']
+    start = int(time.time())
+    while share['is_soft_deleted']:
+        time.sleep(client.build_interval)
+        share = client.get_share(share_id, version=version)['share']
+        if not share['is_soft_deleted']:
+            break
+        elif int(time.time()) - start >= client.build_timeout:
+            message = ('Share %(share_id)s failed to restore from '
+                       'recycle bin within the required time '
+                       '%(timeout)s.' % {
+                           'share_id': share['id'],
+                           'timeout': client.build_timeout,
+                       })
+            raise exceptions.TimeoutException(message)
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index 6f9813c..f5022af 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -21,6 +21,15 @@
                              help="Whether or not manila is expected to be "
                                   "available")
 
+manila_scope_enforcement = cfg.BoolOpt('manila',
+                                       default=False,
+                                       help="Does the Share service API "
+                                            "policies enforce scope? "
+                                            "This configuration value should "
+                                            "be same as manila.conf: "
+                                            "[oslo_policy].enforce_scope "
+                                            "option.")
+
 share_group = cfg.OptGroup(name="share", title="Share Service Options")
 
 ShareGroup = [
@@ -31,7 +40,7 @@
                     "This value is only used to validate the versions "
                     "response from Manila."),
     cfg.StrOpt("max_api_microversion",
-               default="2.65",
+               default="2.69",
                help="The maximum api microversion is configured to be the "
                     "value of the latest microversion supported by Manila."),
     cfg.StrOpt("region",
diff --git a/manila_tempest_tests/plugin.py b/manila_tempest_tests/plugin.py
index 0c32ce1..148a368 100644
--- a/manila_tempest_tests/plugin.py
+++ b/manila_tempest_tests/plugin.py
@@ -33,6 +33,8 @@
     def register_opts(self, conf):
         conf.register_opt(config_share.service_option,
                           group='service_available')
+        conf.register_opt(config_share.manila_scope_enforcement,
+                          group='enforce_scope')
         conf.register_group(config_share.share_group)
         conf.register_opts(config_share.ShareGroup, group='share')
 
@@ -54,7 +56,8 @@
 
     def get_opt_lists(self):
         return [(config_share.share_group.name, config_share.ShareGroup),
-                ('service_available', [config_share.service_option])]
+                ('service_available', [config_share.service_option]),
+                ('enforce_scope', [config_share.manila_scope_enforcement])]
 
     def get_service_clients(self):
         shares_config = config.service_client_config('share')
diff --git a/manila_tempest_tests/services/share/json/shares_client.py b/manila_tempest_tests/services/share/json/shares_client.py
index 770bbb9..3413387 100644
--- a/manila_tempest_tests/services/share/json/shares_client.py
+++ b/manila_tempest_tests/services/share/json/shares_client.py
@@ -15,9 +15,8 @@
 
 import json
 import time
+from urllib import parse as urlparse
 
-import six
-from six.moves.urllib import parse as urlparse
 from tempest import config
 from tempest.lib.common import rest_client
 from tempest.lib.common.utils import data_utils
@@ -322,7 +321,7 @@
                 self.show_share_server, kwargs.get("server_id"))
         else:
             raise share_exceptions.InvalidResource(
-                message=six.text_type(kwargs))
+                message=str(kwargs))
 
     def _is_resource_deleted(self, func, res_id, **kwargs):
         try:
diff --git a/manila_tempest_tests/services/share/v2/json/shares_client.py b/manila_tempest_tests/services/share/v2/json/shares_client.py
index 01028cd..6db5393 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -16,8 +16,8 @@
 import json
 import re
 import time
+from urllib import parse
 
-from six.moves.urllib import parse
 from tempest import config
 from tempest.lib.common import rest_client
 from tempest.lib.common.utils import data_utils
@@ -299,6 +299,20 @@
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
+    def list_shares_in_recycle_bin(self, detailed=False,
+                                   params=None, version=LATEST_MICROVERSION,
+                                   experimental=False):
+        """Get list of shares in recycle bin with w/o filters."""
+        headers = EXPERIMENTAL if experimental else None
+        uri = 'shares/detail' if detailed else 'shares'
+        uri += '?is_soft_deleted=true'
+        uri += '&%s' % parse.urlencode(params) if params else ''
+        resp, body = self.get(uri, headers=headers, extra_headers=experimental,
+                              version=version)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
     def list_shares_with_detail(self, params=None,
                                 version=LATEST_MICROVERSION,
                                 experimental=False):
@@ -342,6 +356,22 @@
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
 
+    def soft_delete_share(self, share_id, version=LATEST_MICROVERSION):
+        post_body = {"soft_delete": None}
+        body = json.dumps(post_body)
+        resp, body = self.post(
+            "shares/%s/action" % share_id, body, version=version)
+        self.expected_success(202, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def restore_share(self, share_id, version=LATEST_MICROVERSION):
+        post_body = {"restore": None}
+        body = json.dumps(post_body)
+        resp, body = self.post(
+            "shares/%s/action" % share_id, body, version=version)
+        self.expected_success(202, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
 ###############
 
     def get_instances_of_share(self, share_id, version=LATEST_MICROVERSION):
@@ -390,17 +420,22 @@
 ###############
 
     def extend_share(self, share_id, new_size, version=LATEST_MICROVERSION,
-                     action_name=None):
+                     action_name=None, force=False):
         if action_name is None:
             if utils.is_microversion_gt(version, "2.6"):
                 action_name = 'extend'
             else:
                 action_name = 'os-extend'
+
         post_body = {
             action_name: {
                 "new_size": new_size,
             }
         }
+
+        if utils.is_microversion_gt(version, "2.63"):
+            post_body[action_name]["force"] = force
+
         body = json.dumps(post_body)
         resp, body = self.post(
             "shares/%s/action" % share_id, body, version=version)
@@ -1523,16 +1558,18 @@
                                version=version)
         return rest_client.ResponseBody(resp, body)
 
-################
-
     def create_share_replica(self, share_id, availability_zone=None,
-                             version=LATEST_MICROVERSION):
+                             version=LATEST_MICROVERSION,
+                             scheduler_hints=None):
         """Add a share replica of an existing share."""
         uri = "share-replicas"
         post_body = {
             'share_id': share_id,
             'availability_zone': availability_zone,
         }
+
+        if scheduler_hints:
+            post_body["scheduler_hints"] = scheduler_hints
         headers, extra_headers = utils.get_extra_headers(
             version, constants.SHARE_REPLICA_GRADUATION_VERSION)
         body = json.dumps({'share_replica': post_body})
diff --git a/manila_tempest_tests/tests/api/admin/test_admin_actions.py b/manila_tempest_tests/tests/api/admin/test_admin_actions.py
index e958ac9..1a5ecc7 100644
--- a/manila_tempest_tests/tests/api/admin/test_admin_actions.py
+++ b/manila_tempest_tests/tests/api/admin/test_admin_actions.py
@@ -181,3 +181,29 @@
             self.assertNotEmpty(share_server)
         else:
             self.assertEmpty(share_server)
+
+    @decorators.idempotent_id('83d94560-e9b4-47c1-b21e-400531528e27')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+    @utils.skip_if_microversion_not_supported("2.64")
+    @testtools.skipUnless(
+        CONF.share.run_extend_tests,
+        "Share extend tests are disabled.")
+    @ddt.data(True, False)
+    def test_extend_share_force(self, force_flag):
+        # Force extend were supported from v2.64
+        # If a admin tries to do force extend, it should be success
+        share = self.create_share(share_type_id=self.share_type_id,
+                                  cleanup_in_class=False)
+        new_size = int(share['size']) + 1
+
+        # force extend share and wait for active status
+        self.admin_shares_v2_client.extend_share(share['id'], new_size,
+                                                 force=force_flag)
+        waiters.wait_for_resource_status(
+            self.shares_client, share['id'], 'available')
+
+        # check new size
+        share_get = self.shares_v2_client.get_share(share['id'])['share']
+        msg = ("Share could not be extended. Expected %s, got %s." % (
+            new_size, share_get['size']))
+        self.assertEqual(new_size, share_get['size'], msg)
diff --git a/manila_tempest_tests/tests/api/admin/test_export_locations.py b/manila_tempest_tests/tests/api/admin/test_export_locations.py
index 7d09f69..db382f2 100644
--- a/manila_tempest_tests/tests/api/admin/test_export_locations.py
+++ b/manila_tempest_tests/tests/api/admin/test_export_locations.py
@@ -16,7 +16,6 @@
 import ddt
 from oslo_utils import timeutils
 from oslo_utils import uuidutils
-import six
 from tempest import config
 from tempest.lib import decorators
 from testtools import testcase as tc
@@ -91,7 +90,7 @@
             # Check the format of ever-present summary keys
             self.assertTrue(uuidutils.is_uuid_like(export_location['id']))
             self.assertIsInstance(export_location['path'],
-                                  six.string_types)
+                                  str)
 
             if utils.is_microversion_ge(version, '2.14'):
                 self.assertIn(export_location['preferred'], (True, False))
diff --git a/manila_tempest_tests/tests/api/admin/test_quotas_negative.py b/manila_tempest_tests/tests/api/admin/test_quotas_negative.py
index 7dd12e1..20e359a 100644
--- a/manila_tempest_tests/tests/api/admin/test_quotas_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_quotas_negative.py
@@ -426,6 +426,25 @@
                           self.create_share,
                           share_type_id=self.share_type_id)
 
+    @decorators.idempotent_id('a2267f4d-63ef-4631-a01d-3723707e5516')
+    @testtools.skipUnless(
+        CONF.share.run_snapshot_tests, 'Snapshot tests are disabled.')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_snapshot_over_quota_limit(self):
+        extra_specs = {'snapshot_support': True}
+        share_type = self.create_share_type(extra_specs=extra_specs)
+        share = self.create_share(share_type_id=share_type['id'])
+
+        # Update snapshot quota
+        self.update_quotas(self.tenant_id, snapshots=1)
+
+        # Create share from updated snapshot, wait for status 'available'
+        self.create_snapshot_wait_for_active(share['id'])
+
+        self.assertRaises(lib_exc.OverLimit,
+                          self.create_snapshot_wait_for_active,
+                          share['id'])
+
 
 @ddt.ddt
 class ReplicaQuotasNegativeTest(rep_neg_test.ReplicationNegativeBase):
diff --git a/manila_tempest_tests/tests/api/admin/test_replication.py b/manila_tempest_tests/tests/api/admin/test_replication.py
index b5b340c..242e786 100644
--- a/manila_tempest_tests/tests/api/admin/test_replication.py
+++ b/manila_tempest_tests/tests/api/admin/test_replication.py
@@ -45,7 +45,6 @@
     def resource_setup(cls):
         super(ReplicationAdminTest, cls).resource_setup()
         cls.admin_client = cls.admin_shares_v2_client
-        cls.member_client = cls.shares_v2_client
         cls.replication_type = CONF.share.backend_replication_type
         cls.multitenancy_enabled = (
             utils.replication_with_multitenancy_support())
@@ -83,6 +82,7 @@
         return [replica['id'] for replica in replica_list
                 if replica['replica_state'] == r_state]
 
+    @decorators.unstable_test(bug='1631314')
     @decorators.idempotent_id('0213cdfd-6a0f-4f24-a154-69796888a64a')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
     @ddt.data(
@@ -137,7 +137,8 @@
                                    version=version)
         # Original replica will need to be cleaned up before the promoted
         # replica can be deleted.
-        self.addCleanup(self.delete_share_replica, original_replica['id'])
+        self.addCleanup(self.delete_share_replica, original_replica['id'],
+                        client=self.admin_client)
 
         # Check if there is still only 1 'active' replica after promotion.
         replica_list = self.admin_client.list_share_replicas(
@@ -211,6 +212,7 @@
             self.admin_client, replica['id'], constants.STATUS_ERROR,
             resource_name='share_replica', status_attr='replica_state')
 
+    @decorators.unstable_test(bug='1631314')
     @decorators.idempotent_id('2969565a-85e8-4c61-9dfb-cc7f7ca9f6dd')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
     @ddt.data(
diff --git a/manila_tempest_tests/tests/api/admin/test_scheduler_hints.py b/manila_tempest_tests/tests/api/admin/test_scheduler_hints.py
new file mode 100644
index 0000000..55c9ca7
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_scheduler_hints.py
@@ -0,0 +1,113 @@
+# Copyright 2022 Cloudification GmbH
+# 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.
+
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests import share_exceptions
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+CONF = config.CONF
+LATEST_MICROVERSION = CONF.share.max_api_microversion
+
+
+class SharesSchedulerHintsAdminTest(base.BaseSharesAdminTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(SharesSchedulerHintsAdminTest, cls).skip_checks()
+        if not CONF.share.multi_backend:
+            raise cls.skipException("Manila multi-backend tests are disabled.")
+        elif len(CONF.share.backend_names) < 2:
+            raise cls.skipException("For running multi-backend tests, two or "
+                                    "more backend names must be configured.")
+        elif any(not name for name in CONF.share.backend_names):
+            raise cls.skipException("Share backend names can not be empty.")
+        utils.check_skip_if_microversion_not_supported('2.67')
+
+    @classmethod
+    def resource_setup(cls):
+        super(SharesSchedulerHintsAdminTest, cls).resource_setup()
+        # Need for requesting pools
+        cls.admin_client = cls.admin_shares_v2_client
+        # create share type
+        share_type = cls.create_share_type()
+        cls.share_type_id = share_type['id']
+
+    @decorators.idempotent_id('54f4dea7-890e-443b-aea5-f6108da893f0')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_only_host_scheduler_hint_in_share_creation(self):
+        share_a = self.create_share(share_type_id=self.share_type_id)
+        share_a = self.admin_shares_v2_client.get_share(share_a['id'])['share']
+        backend_a = share_a['host']
+        scheduler_hint = {"only_host": "%s" % backend_a}
+
+        # create share with hint
+        share_b = self.create_share(share_type_id=self.share_type_id,
+                                    scheduler_hints=scheduler_hint,
+                                    cleanup_in_class=False)
+        share_b = self.admin_shares_v2_client.get_share(share_b['id'])['share']
+        backend_b = share_b['host']
+
+        # verify same backends
+        self.assertEqual(backend_a, backend_b)
+
+    @decorators.idempotent_id('1dec3306-61f4-41b9-ba4a-572a9e6f5f57')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    @tc.skipUnless(CONF.share.run_replication_tests,
+                   'Replication tests are disabled.')
+    def test_only_host_scheduler_hint_in_share_replica_creation(self):
+        replication_type = CONF.share.backend_replication_type
+        if replication_type not in constants.REPLICATION_TYPE_CHOICES:
+            raise share_exceptions.ShareReplicationTypeException(
+                replication_type=replication_type
+            )
+        extra_specs = self.add_extra_specs_to_dict({
+            "replication_type": replication_type
+        })
+        replicated_share_type = self.create_share_type(
+            data_utils.rand_name("replicated-shares"),
+            extra_specs=extra_specs)
+        share = self.create_share(
+            share_type_id=replicated_share_type['id'],
+            cleanup_in_class=False)
+        share = self.admin_shares_v2_client.get_share(share['id'])['share']
+        share_host = share['host']
+        rep_domain, pools = self.get_pools_for_replication_domain(share=share)
+        if len(pools) < 2:
+            msg = ("Can not create valid hint due to insufficient pools.")
+            raise self.skipException(msg)
+
+        for p in pools:
+            if p['name'] != share_host:
+                expected_replica_host = p['name']
+                scheduler_hint = {"only_host": "%s" % expected_replica_host}
+                break
+
+        # create share replica with hint
+        replica = self.create_share_replica(share['id'],
+                                            cleanup_in_class=False,
+                                            version=LATEST_MICROVERSION,
+                                            scheduler_hints=scheduler_hint)
+        replica = self.admin_shares_v2_client.get_share_replica(
+            replica['id'])['share_replica']
+        replica_host = replica['host']
+
+        # verify same backends
+        self.assertEqual(expected_replica_host, replica_host)
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers.py b/manila_tempest_tests/tests/api/admin/test_share_servers.py
index fd553ff..b406a92 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers.py
@@ -16,7 +16,6 @@
 import re
 
 import ddt
-import six
 from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
@@ -120,7 +119,7 @@
         else:
             msg = ("Appropriate server was not found. Its share_network_data"
                    ": '%s'. List of servers: '%s'.") % (self.sn_name_and_id,
-                                                        six.text_type(servers))
+                                                        str(servers))
             raise lib_exc.NotFound(message=msg)
         search_opts = {"host": host}
         servers = self.shares_v2_client.list_share_servers(
@@ -226,8 +225,8 @@
 
         # If details are present they and their values should be only strings
         for k, v in details.items():
-            self.assertIsInstance(k, six.string_types)
-            self.assertIsInstance(v, six.string_types)
+            self.assertIsInstance(k, str)
+            self.assertIsInstance(v, str)
 
     @decorators.idempotent_id('2fdf8d29-3ab8-4424-b684-6253f45b9666')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
diff --git a/manila_tempest_tests/tests/api/admin/test_snapshot_export_locations.py b/manila_tempest_tests/tests/api/admin/test_snapshot_export_locations.py
index fca92c7..1c6a9b7 100644
--- a/manila_tempest_tests/tests/api/admin/test_snapshot_export_locations.py
+++ b/manila_tempest_tests/tests/api/admin/test_snapshot_export_locations.py
@@ -15,7 +15,6 @@
 
 import ddt
 from oslo_utils import uuidutils
-import six
 from tempest import config
 from tempest.lib import decorators
 from testtools import testcase as tc
@@ -94,7 +93,7 @@
             # Check the format of ever-present summary keys
             self.assertTrue(uuidutils.is_uuid_like(export_location['id']))
             self.assertIsInstance(export_location['path'],
-                                  six.string_types)
+                                  str)
 
             if role == 'admin':
                 self.assertIn(export_location['is_admin_only'], (True, False))
diff --git a/manila_tempest_tests/tests/api/admin/test_snapshot_manage_negative.py b/manila_tempest_tests/tests/api/admin/test_snapshot_manage_negative.py
index f2fb48f..36ddf7e 100644
--- a/manila_tempest_tests/tests/api/admin/test_snapshot_manage_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_snapshot_manage_negative.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import six
+
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
@@ -51,7 +51,7 @@
         cls.extra_specs = {
             'storage_protocol': CONF.share.capability_storage_protocol,
             'driver_handles_share_servers': CONF.share.multitenancy_enabled,
-            'snapshot_support': six.text_type(
+            'snapshot_support': str(
                 CONF.share.capability_snapshot_support),
         }
 
diff --git a/manila_tempest_tests/tests/api/admin/test_user_messages_negative.py b/manila_tempest_tests/tests/api/admin/test_user_messages_negative.py
index 197b883..e675387 100644
--- a/manila_tempest_tests/tests/api/admin/test_user_messages_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_user_messages_negative.py
@@ -10,7 +10,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 from oslo_utils import uuidutils
-import six
 from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
@@ -47,7 +46,7 @@
     def test_show_nonexistent_message(self):
         self.assertRaises(lib_exc.NotFound,
                           self.shares_v2_client.get_message,
-                          six.text_type(uuidutils.generate_uuid()))
+                          str(uuidutils.generate_uuid()))
 
     @decorators.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
     @decorators.idempotent_id('2f5be1aa-974b-4f6a-ae3a-084578e64f82')
@@ -61,7 +60,7 @@
     def test_delete_nonexistent_message(self):
         self.assertRaises(lib_exc.NotFound,
                           self.shares_v2_client.delete_message,
-                          six.text_type(uuidutils.generate_uuid()))
+                          str(uuidutils.generate_uuid()))
 
     @decorators.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
     @utils.skip_if_microversion_not_supported(QUERY_BY_TIMESTAMP_MICROVERSION)
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index dd25062..d5cc439 100755
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -18,7 +18,6 @@
 import traceback
 
 from oslo_log import log
-import six
 from tempest import config
 from tempest.lib.common import cred_client
 from tempest.lib.common.utils import data_utils
@@ -636,8 +635,8 @@
         extra_specs = {}
         for k, v in share_type['extra_specs'].items():
             extra_specs[k] = (
-                True if six.text_type(v).lower() == 'true'
-                else False if six.text_type(v).lower() == 'false' else v
+                True if str(v).lower() == 'true'
+                else False if str(v).lower() == 'false' else v
             )
         return [
             pool for pool in pools if all(y in pool['capabilities'].items()
@@ -657,11 +656,15 @@
         azs = cls.get_availability_zones(backends=backends_matching_share_type)
         return azs
 
-    def get_pools_for_replication_domain(self):
+    def get_pools_for_replication_domain(self, share=None):
         # Get the list of pools for the replication domain
         pools = self.admin_client.list_pools(detail=True)['pools']
-        instance_host = self.admin_client.get_share(
-            self.shares[0]['id'])['share']['host']
+        if share:
+            instance_host = self.admin_client.get_share(
+                share['id'])['share']['host']
+        else:
+            instance_host = self.admin_client.get_share(
+                self.shares[0]['id'])['share']['host']
         host_pool = [p for p in pools if p['name'] == instance_host][0]
         rep_domain = host_pool['capabilities']['replication_domain']
         pools_in_rep_domain = [p for p in pools if p['capabilities'][
@@ -672,11 +675,12 @@
     def create_share_replica(cls, share_id, availability_zone=None,
                              client=None, cleanup_in_class=False,
                              cleanup=True,
-                             version=CONF.share.max_api_microversion):
+                             version=CONF.share.max_api_microversion,
+                             scheduler_hints=None):
         client = client or cls.shares_v2_client
         replica = client.create_share_replica(
             share_id, availability_zone=availability_zone,
-            version=version)['share_replica']
+            version=version, scheduler_hints=scheduler_hints)['share_replica']
         resource = {
             "type": "share_replica",
             "id": replica["id"],
@@ -1077,7 +1081,7 @@
     @staticmethod
     def add_extra_specs_to_dict(extra_specs=None):
         """Add any required extra-specs to share type dictionary"""
-        dhss = six.text_type(CONF.share.multitenancy_enabled)
+        dhss = str(CONF.share.multitenancy_enabled)
         extra_specs_dict = {"driver_handles_share_servers": dhss}
         if extra_specs:
             extra_specs_dict.update(extra_specs)
diff --git a/manila_tempest_tests/tests/api/test_metadata.py b/manila_tempest_tests/tests/api/test_metadata.py
index 5ca4e83..c8529a3 100644
--- a/manila_tempest_tests/tests/api/test_metadata.py
+++ b/manila_tempest_tests/tests/api/test_metadata.py
@@ -31,6 +31,19 @@
         # create share
         cls.share = cls.create_share(share_type_id=cls.share_type_id)
 
+    def _verify_share_metadata(self, share, md):
+
+        # get metadata of share
+        metadata = self.shares_client.get_metadata(share["id"])['metadata']
+
+        # verify metadata
+        self.assertEqual(md, metadata)
+
+        # verify metadata items
+        for key in md:
+            get_value = self.shares_client.get_metadata_item(share["id"], key)
+            self.assertEqual(md[key], get_value[key])
+
     @decorators.idempotent_id('9070249f-6e94-4a38-a036-08debee547c3')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     def test_set_metadata_in_share_creation(self):
@@ -42,11 +55,8 @@
                                   metadata=md,
                                   cleanup_in_class=False)
 
-        # get metadata of share
-        metadata = self.shares_client.get_metadata(share["id"])['metadata']
-
         # verify metadata
-        self.assertEqual(md, metadata)
+        self._verify_share_metadata(share, md)
 
     @decorators.idempotent_id('2725ab8e-cc04-4032-9393-74726ba43eb7')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -61,16 +71,8 @@
         # set metadata
         self.shares_client.set_metadata(share["id"], md)
 
-        # read metadata
-        get_md = self.shares_client.get_metadata(share["id"])['metadata']
-
         # verify metadata
-        self.assertEqual(md, get_md)
-
-        # verify metadata items
-        for key in md:
-            get_value = self.shares_client.get_metadata_item(share["id"], key)
-            self.assertEqual(md[key], get_value[key])
+        self._verify_share_metadata(share, md)
 
         # delete metadata
         for key in md.keys():
@@ -78,7 +80,73 @@
 
         # verify deletion of metadata
         get_metadata = self.shares_client.get_metadata(share["id"])['metadata']
-        self.assertEqual({}, get_metadata)
+        self.assertEmpty(get_metadata)
+
+    @decorators.idempotent_id('4e5f8159-62b6-4d5c-f729-d8b1f029d7de')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_metadata_not_delete_pre_metadata(self):
+        md1 = {u"key9": u"value9", u"key10": u"value10", }
+        md2 = {u"key11": u"value11", u"key12": u"value12", }
+
+        # create share
+        share = self.create_share(share_type_id=self.share_type_id,
+                                  cleanup_in_class=False)
+
+        # set metadata
+        self.shares_client.set_metadata(share["id"], md1)
+
+        # verify metadata
+        self._verify_share_metadata(share, md1)
+
+        # set metadata again
+        self.shares_client.set_metadata(share["id"], md2)
+
+        # verify metadata
+        md1.update(md2)
+        md = md1
+
+        # verify metadata
+        self._verify_share_metadata(share, md)
+
+        # delete metadata
+        for key in md.keys():
+            self.shares_client.delete_metadata(share["id"], key)
+
+        # verify deletion of metadata
+        get_metadata = self.shares_client.get_metadata(share["id"])['metadata']
+        self.assertEmpty(get_metadata)
+
+    @decorators.idempotent_id('2ec70ba5-050b-3b17-c862-c149e53543c0')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_metadata_key_already_exist(self):
+        md1 = {u"key9": u"value9", u"key10": u"value10", }
+        md2 = {u"key9": u"value13", u"key11": u"value11", }
+
+        # create share
+        share = self.create_share(share_type_id=self.share_type_id,
+                                  cleanup_in_class=False)
+
+        # set metadata
+        self.shares_client.set_metadata(share["id"], md1)
+
+        # verify metadata
+        self._verify_share_metadata(share, md1)
+
+        # set metadata again
+        self.shares_client.set_metadata(share["id"], md2)
+
+        # verify metadata
+        md = {u"key9": u"value13", u"key10": u"value10",
+              u"key11": u"value11"}
+        self._verify_share_metadata(share, md)
+
+        # delete metadata
+        for key in md.keys():
+            self.shares_client.delete_metadata(share["id"], key)
+
+        # verify deletion of metadata
+        get_metadata = self.shares_client.get_metadata(share["id"])['metadata']
+        self.assertEmpty(get_metadata)
 
     @decorators.idempotent_id('c94851f4-2559-4712-9297-9912db1da7ff')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -97,11 +165,8 @@
         # update metadata
         self.shares_client.update_all_metadata(share["id"], md2)
 
-        # get metadata
-        get_md = self.shares_client.get_metadata(share["id"])['metadata']
-
         # verify metadata
-        self.assertEqual(md2, get_md)
+        self._verify_share_metadata(share, md2)
 
     @decorators.idempotent_id('698ba406-493f-4c69-a093-273676fed438')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
diff --git a/manila_tempest_tests/tests/api/test_metadata_negative.py b/manila_tempest_tests/tests/api/test_metadata_negative.py
index a34d1a6..93a3628 100644
--- a/manila_tempest_tests/tests/api/test_metadata_negative.py
+++ b/manila_tempest_tests/tests/api/test_metadata_negative.py
@@ -113,20 +113,3 @@
         self.assertRaises(lib_exc.NotFound,
                           self.shares_client.delete_metadata,
                           self.share["id"], "wrong_key")
-
-    @decorators.idempotent_id('c6c70d55-7ed0-439f-ae34-f19af55361f6')
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data(("foo.xml", False), ("foo.json", False),
-              ("foo.xml", True), ("foo.json", True))
-    @ddt.unpack
-    def test_try_delete_metadata_with_unsupport_format_key(
-            self, key, is_v2_client):
-        md = {key: u"value.test"}
-
-        client = self.shares_v2_client if is_v2_client else self.shares_client
-        # set metadata
-        client.set_metadata(self.share["id"], md)
-
-        self.assertRaises(lib_exc.NotFound,
-                          client.delete_metadata,
-                          self.share["id"], key)
diff --git a/manila_tempest_tests/tests/api/test_replication_negative.py b/manila_tempest_tests/tests/api/test_replication_negative.py
index 90c52c7..e7d0e7d 100644
--- a/manila_tempest_tests/tests/api/test_replication_negative.py
+++ b/manila_tempest_tests/tests/api/test_replication_negative.py
@@ -137,6 +137,7 @@
                           self.shares_v2_client.delete_share,
                           self.share1["id"])
 
+    @decorators.unstable_test(bug='1631314')
     @decorators.idempotent_id('b9c2e57b-f1ae-475c-9d0b-df75dbe93b61')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_promote_out_of_sync_share_replica(self):
diff --git a/manila_tempest_tests/tests/api/test_security_services.py b/manila_tempest_tests/tests/api/test_security_services.py
index 5bfbc2e..24d8bad 100644
--- a/manila_tempest_tests/tests/api/test_security_services.py
+++ b/manila_tempest_tests/tests/api/test_security_services.py
@@ -15,7 +15,6 @@
 
 import ddt
 from oslo_log import log
-import six
 from tempest import config
 from tempest.lib import decorators
 import testtools
@@ -252,7 +251,7 @@
             LOG.warning("Caught exception. It is expected in case backend "
                         "fails having security-service with improper data "
                         "that leads to share-server creation error. "
-                        "%s", six.text_type(e))
+                        "%s", str(e))
 
         update_data = {
             "name": "name",
diff --git a/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py b/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py
index 9aaf20b..d0bb321 100644
--- a/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py
+++ b/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 from oslo_log import log
-import six
 from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
@@ -136,7 +135,7 @@
             LOG.warning("Caught exception. It is expected in case backend "
                         "fails having security-service with improper data "
                         "that leads to share-server creation error. "
-                        "%s", six.text_type(e))
+                        "%s", str(e))
 
         self.assertRaises(lib_exc.Forbidden,
                           self.cl.remove_sec_service_from_share_network,
diff --git a/manila_tempest_tests/tests/api/test_security_services_negative.py b/manila_tempest_tests/tests/api/test_security_services_negative.py
index 3895fa9..08e3c7b 100644
--- a/manila_tempest_tests/tests/api/test_security_services_negative.py
+++ b/manila_tempest_tests/tests/api/test_security_services_negative.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 from oslo_log import log
-import six
 from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
@@ -120,7 +119,7 @@
             LOG.warning("Caught exception. It is expected in case backend "
                         "fails having security-service with improper data "
                         "that leads to share-server creation error. "
-                        "%s", six.text_type(e))
+                        "%s", str(e))
 
         self.assertRaises(lib_exc.Forbidden,
                           self.shares_client.update_security_service,
diff --git a/manila_tempest_tests/tests/api/test_share_networks.py b/manila_tempest_tests/tests/api/test_share_networks.py
index bd45ed1..e3d5a78 100644
--- a/manila_tempest_tests/tests/api/test_share_networks.py
+++ b/manila_tempest_tests/tests/api/test_share_networks.py
@@ -298,41 +298,14 @@
         sn2 = self.create_share_network(**data)
         self.assertDictContainsSubset(data, sn2)
 
-    @decorators.idempotent_id('50bac743-7ca9-409b-827f-f277da67e32e')
-    @testtools.skipUnless(CONF.share.create_networks_when_multitenancy_enabled,
-                          "Only for setups with network creation.")
-    @testtools.skipUnless(CONF.share.multitenancy_enabled,
-                          "Only for multitenancy.")
-    @testtools.skipUnless(CONF.service_available.neutron, "Only with neutron.")
-    @utils.skip_if_microversion_not_supported("2.18")
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_gateway_with_neutron(self):
-        subnet_client = self.subnets_client
-
-        self.create_share(share_type_id=self.share_type_id,
-                          cleanup_in_class=False)
-        share_net_details = self.shares_v2_client.get_share_network(
-            self.shares_v2_client.share_network_id)['share_network']
-        share_net_info = (
-            utils.share_network_get_default_subnet(share_net_details)
-            if utils.share_network_subnets_are_supported()
-            else share_net_details)
-        subnet_details = subnet_client.show_subnet(
-            share_net_info['neutron_subnet_id'])
-        self.assertEqual(subnet_details['subnet']['gateway_ip'],
-                         share_net_info['gateway'])
-
     @decorators.idempotent_id('2dbf91da-04ae-4f9f-a7b9-0299c6b2e02c')
     @testtools.skipUnless(CONF.share.create_networks_when_multitenancy_enabled,
                           "Only for setups with network creation.")
     @testtools.skipUnless(CONF.share.multitenancy_enabled,
                           "Only for multitenancy.")
     @testtools.skipUnless(CONF.service_available.neutron, "Only with neutron.")
-    @utils.skip_if_microversion_not_supported("2.20")
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_mtu_with_neutron(self):
-        network_client = self.networks_client
-
+    def test_gateway_mtu_neutron_net_id_with_neutron(self):
         self.create_share(share_type_id=self.share_type_id,
                           cleanup_in_class=False)
         share_net_details = self.shares_v2_client.get_share_network(
@@ -341,8 +314,17 @@
             utils.share_network_get_default_subnet(share_net_details)
             if utils.share_network_subnets_are_supported()
             else share_net_details)
-        network_details = network_client.show_network(
-            share_net_info['neutron_net_id'])
 
-        self.assertEqual(network_details['network']['mtu'],
-                         share_net_info['mtu'])
+        if utils.is_microversion_supported('2.18'):
+            subnet_details = self.subnets_client.show_subnet(
+                share_net_info['neutron_subnet_id'])
+            self.assertEqual(subnet_details['subnet']['gateway_ip'],
+                             share_net_info['gateway'])
+
+        if utils.is_microversion_supported('2.20'):
+            network_details = self.networks_client.show_network(
+                share_net_info['neutron_net_id'])
+            self.assertEqual(network_details['network']['mtu'],
+                             share_net_info['mtu'])
+            self.assertEqual(network_details['network']['id'],
+                             share_net_info['neutron_net_id'])
diff --git a/manila_tempest_tests/tests/api/test_shares_actions.py b/manila_tempest_tests/tests/api/test_shares_actions.py
index 4cdc70d..779bfb6 100644
--- a/manila_tempest_tests/tests/api/test_shares_actions.py
+++ b/manila_tempest_tests/tests/api/test_shares_actions.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 import ddt
-import six
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
@@ -93,7 +92,7 @@
 
         # get share
         share = self.shares_v2_client.get_share(
-            self.shares[0]['id'], version=six.text_type(version))['share']
+            self.shares[0]['id'], version=str(version))['share']
 
         # verify keys
         expected_keys = [
@@ -125,13 +124,13 @@
         # verify values
         msg = "Expected name: '%s', actual name: '%s'" % (self.share_name,
                                                           share["name"])
-        self.assertEqual(self.share_name, six.text_type(share["name"]), msg)
+        self.assertEqual(self.share_name, str(share["name"]), msg)
 
         msg = ("Expected description: '%s', "
                "actual description: '%s'" % (self.share_desc,
                                              share["description"]))
         self.assertEqual(
-            self.share_desc, six.text_type(share["description"]), msg)
+            self.share_desc, str(share["description"]), msg)
 
         msg = "Expected size: '%s', actual size: '%s'" % (
             CONF.share.share_size, share["size"])
@@ -211,7 +210,7 @@
 
         # list shares
         shares = self.shares_v2_client.list_shares_with_detail(
-            version=six.text_type(version))['shares']
+            version=str(version))['shares']
 
         # verify keys
         keys = [
@@ -688,6 +687,51 @@
         )
         self.assertEqual(new_size, share_get['size'], msg)
 
+    @utils.skip_if_microversion_not_supported("2.69")
+    @decorators.idempotent_id('7a19fb58-b645-44cc-a6d7-b3508ff8754d')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_soft_delete_and_restore_share(self):
+        share = self.create_share(share_type_id=self.share_type_id)
+
+        # list shares
+        shares = self.shares_v2_client.list_shares()['shares']
+
+        # check the share in share list
+        share_ids = [sh['id'] for sh in shares]
+        self.assertIn(share['id'], share_ids)
+
+        # soft delete the share
+        self.shares_v2_client.soft_delete_share(share['id'])
+        waiters.wait_for_soft_delete(self.shares_v2_client, share['id'])
+
+        # list shares again
+        shares1 = self.shares_v2_client.list_shares()['shares']
+        share_ids1 = [sh['id'] for sh in shares1]
+
+        # list shares in recycle bin
+        shares2 = self.shares_v2_client.list_shares_in_recycle_bin()['shares']
+        share_ids2 = [sh['id'] for sh in shares2]
+
+        # check share has been soft delete to recycle bin
+        self.assertNotIn(share['id'], share_ids1)
+        self.assertIn(share['id'], share_ids2)
+
+        # restore share from recycle bin
+        self.shares_v2_client.restore_share(share['id'])
+        waiters.wait_for_restore(self.shares_v2_client, share['id'])
+
+        # list shares again
+        shares3 = self.shares_v2_client.list_shares()['shares']
+        share_ids3 = [sh['id'] for sh in shares3]
+
+        # list shares in recycle bin again
+        shares4 = self.shares_v2_client.list_shares_in_recycle_bin()['shares']
+        share_ids4 = [sh['id'] for sh in shares4]
+
+        # check share has restored from recycle bin
+        self.assertNotIn(share['id'], share_ids4)
+        self.assertIn(share['id'], share_ids3)
+
 
 class SharesRenameTest(base.BaseSharesMixedTest):
 
diff --git a/manila_tempest_tests/tests/api/test_shares_actions_negative.py b/manila_tempest_tests/tests/api/test_shares_actions_negative.py
index dfd92a8..a600b8e 100644
--- a/manila_tempest_tests/tests/api/test_shares_actions_negative.py
+++ b/manila_tempest_tests/tests/api/test_shares_actions_negative.py
@@ -21,6 +21,7 @@
 import testtools
 from testtools import testcase as tc
 
+from manila_tempest_tests.common import waiters
 from manila_tempest_tests.tests.api import base
 from manila_tempest_tests import utils
 
@@ -121,6 +122,20 @@
                           share['id'],
                           new_size)
 
+    @decorators.idempotent_id('f9d2ba94-4032-d17a-b4ab-a2b67f650a39')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    @utils.skip_if_microversion_not_supported("2.64")
+    @testtools.skipUnless(
+        CONF.share.run_extend_tests,
+        "Share extend tests are disabled.")
+    def test_share_force_extend_non_admin_user(self):
+        # only admin cloud force extend share with micversion >= 2.64
+        # non-admin will get unauthorized error.
+        new_size = int(self.share['size']) + 1
+        self.assertRaises(lib_exc.Forbidden,
+                          self.shares_v2_client.extend_share, self.share['id'],
+                          new_size, force=True)
+
     @decorators.idempotent_id('99d42f94-8da1-4c04-ad5b-9738d6acc139')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     @testtools.skipUnless(
@@ -280,3 +295,68 @@
         self.assertRaises(lib_exc.NotFound,
                           self.alt_shares_v2_client.get_share,
                           self.share['id'])
+
+    @utils.skip_if_microversion_not_supported("2.69")
+    @decorators.idempotent_id('36cbe23b-08d2-49d9-bb42-f9eb2a804cb1')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_soft_delete_share_has_been_soft_deleted(self):
+        share = self.create_share(share_type_id=self.share_type_id,
+                                  cleanup_in_class=False)
+
+        # soft delete the share
+        self.shares_v2_client.soft_delete_share(share['id'])
+
+        # try soft delete the share again
+        self.assertRaises(lib_exc.Forbidden,
+                          self.shares_v2_client.soft_delete_share,
+                          share['id'])
+
+        # restore the share for resource_cleanup
+        self.shares_v2_client.restore_share(share['id'])
+        waiters.wait_for_restore(self.shares_v2_client, share['id'])
+
+    @utils.skip_if_microversion_not_supported("2.69")
+    @decorators.idempotent_id('cf675ac9-0970-49fc-a051-8a94555c73b5')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_soft_delete_share_with_invalid_share_state(self):
+        share = self.create_share(share_type_id=self.share_type_id,
+                                  cleanup_in_class=False)
+
+        # set "error_deleting" state
+        self.admin_client.reset_state(share['id'], status="error_deleting")
+
+        # try soft delete the share
+        self.assertRaises(lib_exc.Forbidden,
+                          self.shares_v2_client.soft_delete_share,
+                          share['id'])
+
+        # rollback to available status
+        self.admin_client.reset_state(share['id'], status="available")
+
+    @utils.skip_if_microversion_not_supported("2.69")
+    @decorators.idempotent_id('f6106ee4-1a01-444f-b623-912a5e751d49')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_soft_delete_share_from_other_project(self):
+        share = self.create_share(share_type_id=self.share_type_id,
+                                  cleanup_in_class=False)
+
+        # try soft delete the share
+        self.assertRaises(lib_exc.Forbidden,
+                          self.alt_shares_v2_client.soft_delete_share,
+                          share['id'])
+
+    @utils.skip_if_microversion_not_supported("2.69")
+    @decorators.idempotent_id('0ccd44dd-2fda-403e-bc23-7ce428550f36')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_soft_delete_share_with_wrong_id(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.soft_delete_share,
+                          "wrong_share_id")
+
+    @utils.skip_if_microversion_not_supported("2.69")
+    @decorators.idempotent_id('87345725-f187-4d7d-86b1-62284e8c75ae')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_restore_share_with_wrong_id(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.restore_share,
+                          "wrong_share_id")
diff --git a/manila_tempest_tests/tests/api/test_snapshot_rules.py b/manila_tempest_tests/tests/api/test_snapshot_rules.py
index 541e861..74d5221 100644
--- a/manila_tempest_tests/tests/api/test_snapshot_rules.py
+++ b/manila_tempest_tests/tests/api/test_snapshot_rules.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 import ddt
-import six
 from tempest import config
 from tempest.lib import decorators
 from testtools import testcase as tc
@@ -54,7 +53,7 @@
             access_to)['snapshot_access']
 
         for key in ('deleted', 'deleted_at', 'instance_mappings'):
-            self.assertNotIn(key, list(six.iterkeys(rule)))
+            self.assertNotIn(key, list(rule.keys()))
 
         waiters.wait_for_resource_status(
             self.shares_v2_client, self.snapshot['id'], 'active',
diff --git a/manila_tempest_tests/tests/scenario/manager.py b/manila_tempest_tests/tests/scenario/manager.py
index 1fa03f4..947d0e6 100644
--- a/manila_tempest_tests/tests/scenario/manager.py
+++ b/manila_tempest_tests/tests/scenario/manager.py
@@ -20,7 +20,6 @@
 from oslo_log import log
 from oslo_utils import netutils
 from oslo_utils import uuidutils
-import six
 from tempest.common import compute
 from tempest.common import image as common_image
 from tempest.common.utils.linux import remote_client
@@ -630,7 +629,7 @@
             try:
                 return subnets_client.create_subnet(**subnet)
             except lib_exc.Conflict as e:
-                if 'overlaps with another subnet' not in six.text_type(e):
+                if 'overlaps with another subnet' not in str(e):
                     raise
 
         result = None
diff --git a/manila_tempest_tests/tests/scenario/manager_share.py b/manila_tempest_tests/tests/scenario/manager_share.py
index d68ab04..657b1f1 100644
--- a/manila_tempest_tests/tests/scenario/manager_share.py
+++ b/manila_tempest_tests/tests/scenario/manager_share.py
@@ -14,10 +14,9 @@
 #    under the License.
 
 from tempfile import mkstemp
+from urllib.request import urlopen
 
 from oslo_log import log
-import six
-from six.moves.urllib.request import urlopen
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import data_utils
@@ -288,7 +287,7 @@
         # original implementation depends on CONF.compute.ssh_auth_method
         # option.
         server_or_ip = kwargs['server_or_ip']
-        if isinstance(server_or_ip, six.string_types):
+        if isinstance(server_or_ip, str):
             ip = server_or_ip
         else:
             addr = server_or_ip['addresses'][
diff --git a/manila_tempest_tests/tests/scenario/test_share_extend.py b/manila_tempest_tests/tests/scenario/test_share_extend.py
index f4dce61..595ddd4 100644
--- a/manila_tempest_tests/tests/scenario/test_share_extend.py
+++ b/manila_tempest_tests/tests/scenario/test_share_extend.py
@@ -13,7 +13,6 @@
 import ddt
 from oslo_log import log as logging
 from oslo_utils import units
-import six
 from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions
@@ -133,7 +132,7 @@
                                                       block_count,
                                                       '/dev/urandom')
         except exceptions.SSHExecCommandFailed as e:
-            if 'stale file handle' in six.text_type(e).lower():
+            if 'stale file handle' in str(e).lower():
                 LOG.warning("Client was disconnected during extend process")
                 self.unmount_share(remote_client)
                 self.mount_share(mount_location, remote_client)
@@ -151,7 +150,12 @@
 
 
 class TestShareExtendCIFS(manager.BaseShareScenarioCIFSTest, ShareExtendBase):
-    pass
+
+    @decorators.idempotent_id('4a9f5cf9-990d-4a35-9ac7-87ef593a09e3')
+    @decorators.unstable_test(bug='1903922')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+    def test_create_extend_and_write(self):
+        super(TestShareExtendCIFS, self).test_create_extend_and_write()
 
 
 class TestBaseShareExtendScenarioCEPHFS(manager.BaseShareScenarioCEPHFSTest,
diff --git a/manila_tempest_tests/tests/scenario/test_share_shrink.py b/manila_tempest_tests/tests/scenario/test_share_shrink.py
index b4bfcd5..a4e59e8 100644
--- a/manila_tempest_tests/tests/scenario/test_share_shrink.py
+++ b/manila_tempest_tests/tests/scenario/test_share_shrink.py
@@ -13,7 +13,6 @@
 import time
 
 from oslo_log import log as logging
-import six
 from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions
@@ -146,7 +145,7 @@
                                                        new_size=new_size)
                 except exceptions.BadRequest as e:
                     if ('New size for shrink must be less than current size'
-                            in six.text_type(e)):
+                            in str(e)):
                         break
 
             time.sleep(check_interval)
diff --git a/manila_tempest_tests/utils.py b/manila_tempest_tests/utils.py
index 7625460..d0860f0 100644
--- a/manila_tempest_tests/utils.py
+++ b/manila_tempest_tests/utils.py
@@ -18,7 +18,6 @@
 import re
 
 from netaddr import ip
-import six
 from tempest import config
 import testtools
 
@@ -110,12 +109,12 @@
     conflicts in real-world testing.
     """
     test_net_3 = '203.0.113.'
-    address = test_net_3 + six.text_type(random.randint(0, 255))
+    address = test_net_3 + str(random.randint(0, 255))
     if network:
-        mask_length = six.text_type(random.randint(24, 32))
+        mask_length = str(random.randint(24, 32))
         address = '/'.join((address, mask_length))
         ip_network = ip.IPNetwork(address)
-        return '/'.join((six.text_type(ip_network.network), mask_length))
+        return '/'.join((str(ip_network.network), mask_length))
     return address
 
 
@@ -124,10 +123,10 @@
     ran_add = ["%x" % random.randrange(0, 16 ** 4) for i in range(6)]
     address = "2001:0DB8:" + ":".join(ran_add)
     if network:
-        mask_length = six.text_type(random.randint(32, 128))
+        mask_length = str(random.randint(32, 128))
         address = '/'.join((address, mask_length))
         ip_network = ip.IPNetwork(address)
-        return '/'.join((six.text_type(ip_network.network), mask_length))
+        return '/'.join((str(ip_network.network), mask_length))
     return address
 
 
@@ -135,8 +134,8 @@
     extra_specs = {}
     # fix extra specs with string values instead of boolean
     for k, v in share_type['extra_specs'].items():
-        extra_specs[k] = (True if six.text_type(v).lower() == 'true'
-                          else False if six.text_type(v).lower() == 'false'
+        extra_specs[k] = (True if str(v).lower() == 'true'
+                          else False if str(v).lower() == 'false'
                           else v)
     selected_pool = next(
         (x for x in pools if (x['name'] != share['host'] and all(
diff --git a/releasenotes/notes/bug-1631314-1509db08c75ff645.yaml b/releasenotes/notes/bug-1631314-1509db08c75ff645.yaml
new file mode 100644
index 0000000..601ff57
--- /dev/null
+++ b/releasenotes/notes/bug-1631314-1509db08c75ff645.yaml
@@ -0,0 +1,5 @@
+---
+fixes:
+  - |
+    `Bug #1631314 <https://bugs.launchpad.net/manila/+bug/1631314>`_:
+    Fixed an issue on unstable replication tests.
diff --git a/zuul.d/manila-tempest-jobs.yaml b/zuul.d/manila-tempest-jobs.yaml
index f31ff11..494b285 100644
--- a/zuul.d/manila-tempest-jobs.yaml
+++ b/zuul.d/manila-tempest-jobs.yaml
@@ -60,6 +60,8 @@
     required-projects: *manila-tempest-required-projects
     vars:
       <<: *manila-tempest-base-vars
+      # NOTE(gouthamr): Disabled until https://launchpad.net/bugs/1940324 is
+      # fixed.
       tempest_exclude_regex: "(^manila_tempest_tests.tests.scenario.*IPv6.*)"
 
 - job:
diff --git a/zuul.d/manila-tempest-stable-jobs.yaml b/zuul.d/manila-tempest-stable-jobs.yaml
index ff74f5d..3d2447e 100644
--- a/zuul.d/manila-tempest-stable-jobs.yaml
+++ b/zuul.d/manila-tempest-stable-jobs.yaml
@@ -1,6 +1,16 @@
 # Stable branch jobs to test the trunk version of manila-tempest-plugin against
 # released stable branches of manila
 - job:
+    name: manila-tempest-plugin-lvm-xena
+    parent: manila-tempest-plugin-lvm
+    override-checkout: stable/xena
+    nodeset: openstack-single-node-focal
+    vars:
+        # NOTE(gouthamr): Disabled until https://launchpad.net/bugs/1940324 is
+        # fixed.
+        tempest_exclude_regex: "(^manila_tempest_tests.tests.scenario.*IPv6.*)"
+
+- job:
     name: manila-tempest-plugin-lvm-wallaby
     parent: manila-tempest-plugin-lvm
     override-checkout: stable/wallaby
@@ -15,11 +25,3 @@
     nodeset: openstack-single-node-focal
     vars:
         tempest_exclude_regex: ''
-
-- job:
-    name: manila-tempest-plugin-lvm-ussuri
-    parent: manila-tempest-plugin-lvm
-    override-checkout: stable/ussuri
-    nodeset: openstack-single-node-bionic
-    vars:
-        tempest_exclude_regex: ''
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index bfeaa7b..ce21547 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -7,9 +7,9 @@
         - manila-tempest-plugin-dummy-no-dhss
         - manila-tempest-plugin-dummy-dhss
         - manila-tempest-plugin-lvm
+        - manila-tempest-plugin-lvm-xena
         - manila-tempest-plugin-lvm-wallaby
         - manila-tempest-plugin-lvm-victoria
-        - manila-tempest-plugin-lvm-ussuri
         - manila-tempest-plugin-zfsonlinux:
             voting: false
         - manila-tempest-plugin-cephfs-native: