Merge "Fix scenario tests"
diff --git a/manila_tempest_tests/common/__init__.py b/manila_tempest_tests/common/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/manila_tempest_tests/common/__init__.py
diff --git a/manila_tempest_tests/common/constants.py b/manila_tempest_tests/common/constants.py
new file mode 100644
index 0000000..bef35a5
--- /dev/null
+++ b/manila_tempest_tests/common/constants.py
@@ -0,0 +1,36 @@
+#    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.
+
+STATUS_ERROR = 'error'
+STATUS_AVAILABLE = 'available'
+STATUS_ERROR_DELETING = 'error_deleting'
+
+TEMPEST_MANILA_PREFIX = 'tempest-manila'
+REPLICATION_STYLE_READABLE = 'readable'
+REPLICATION_STYLE_WRITABLE = 'writable'
+REPLICATION_STYLE_DR = 'dr'
+REPLICATION_TYPE_CHOICES = (
+    REPLICATION_STYLE_READABLE,
+    REPLICATION_STYLE_WRITABLE,
+    REPLICATION_STYLE_DR,
+)
+REPLICATION_PROMOTION_CHOICES = (
+    REPLICATION_STYLE_READABLE,
+    REPLICATION_STYLE_DR,
+)
+REPLICATION_STATE_ACTIVE = 'active'
+REPLICATION_STATE_IN_SYNC = 'in_sync'
+REPLICATION_STATE_OUT_OF_SYNC = 'out_of_sync'
+
+RULE_STATE_ACTIVE = 'active'
+RULE_STATE_OUT_OF_SYNC = 'out_of_sync'
+RULE_STATE_ERROR = 'error'
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index e52ca42..94ffb5f 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -36,7 +36,7 @@
                help="The minimum api microversion is configured to be the "
                     "value of the minimum microversion supported by Manila."),
     cfg.StrOpt("max_api_microversion",
-               default="2.11",
+               default="2.15",
                help="The maximum api microversion is configured to be the "
                     "value of the latest microversion supported by Manila."),
     cfg.StrOpt("region",
@@ -73,6 +73,9 @@
     cfg.ListOpt("enable_cert_rules_for_protocols",
                 default=["glusterfs", ],
                 help="Protocols that should be covered with cert rule tests."),
+    cfg.ListOpt("enable_cephx_rules_for_protocols",
+                default=["cephfs", ],
+                help="Protocols to be covered with cephx rule tests."),
     cfg.StrOpt("username_for_user_rules",
                default="Administrator",
                help="Username, that will be used in user tests."),
@@ -128,13 +131,11 @@
                 help="Whether to suppress errors with clean up operation "
                      "or not. There are cases when we may want to skip "
                      "such errors and catch only test errors."),
-    cfg.BoolOpt("run_manage_unmanage_tests",
-                default=False,
-                help="Defines whether to run manage/unmanage tests or not. "
-                     "These test may leave orphaned resources, so be careful "
-                     "enabling this opt."),
 
     # Switching ON/OFF test suites filtered by features
+    cfg.BoolOpt("run_quota_tests",
+                default=True,
+                help="Defines whether to run quota tests or not."),
     cfg.BoolOpt("run_extend_tests",
                 default=True,
                 help="Defines whether to run share extend tests or not. "
@@ -155,9 +156,24 @@
                 help="Defines whether to run consistency group tests or not. "
                      "Disable this feature if used driver doesn't support "
                      "it."),
+    cfg.BoolOpt("run_replication_tests",
+                default=False,
+                help="Defines whether to run replication tests or not. "
+                     "Enable this feature if the driver is configured "
+                     "for replication."),
     cfg.BoolOpt("run_migration_tests",
                 default=False,
                 help="Enable or disable migration tests."),
+    cfg.BoolOpt("run_manage_unmanage_tests",
+                default=False,
+                help="Defines whether to run manage/unmanage tests or not. "
+                     "These test may leave orphaned resources, so be careful "
+                     "enabling this opt."),
+    cfg.BoolOpt("run_manage_unmanage_snapshot_tests",
+                default=False,
+                help="Defines whether to run manage/unmanage snapshot tests "
+                     "or not. These tests may leave orphaned resources, so be "
+                     "careful enabling this opt."),
 
     cfg.StrOpt("image_with_share_tools",
                default="manila-service-image",
@@ -172,9 +188,13 @@
                default="100",
                help="Flavor used for client vm in scenario tests."),
     cfg.IntOpt("migration_timeout",
-               default=1200,
+               default=1500,
                help="Time to wait for share migration before "
                     "timing out (seconds)."),
     cfg.StrOpt("default_share_type_name",
                help="Default share type name to use in tempest tests."),
+    cfg.StrOpt("backend_replication_type",
+               default='none',
+               choices=['none', 'writable', 'readable', 'dr'],
+               help="Specify the replication type supported by the backend."),
 ]
diff --git a/manila_tempest_tests/services/share/json/shares_client.py b/manila_tempest_tests/services/share/json/shares_client.py
index 040b541..bf8ce2a 100644
--- a/manila_tempest_tests/services/share/json/shares_client.py
+++ b/manila_tempest_tests/services/share/json/shares_client.py
@@ -20,9 +20,9 @@
 from six.moves.urllib import parse as urlparse
 
 from tempest import config  # noqa
-from tempest_lib.common import rest_client
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions
+from tempest.lib.common import rest_client
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
 
 from manila_tempest_tests import share_exceptions
 
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 7a454fa..3b45bf3 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -18,9 +18,10 @@
 
 from six.moves.urllib import parse as urlparse
 from tempest import config
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
 
+from manila_tempest_tests.common import constants
 from manila_tempest_tests.services.share.json import shares_client
 from manila_tempest_tests import share_exceptions
 from manila_tempest_tests import utils
@@ -177,6 +178,9 @@
         elif "cgsnapshot_id" in kwargs:
             return self._is_resource_deleted(
                 self.get_cgsnapshot, kwargs.get("cgsnapshot_id"))
+        elif "replica_id" in kwargs:
+            return self._is_resource_deleted(
+                self.get_share_replica, kwargs.get("replica_id"))
         else:
             return super(SharesV2Client, self).is_resource_deleted(
                 *args, **kwargs)
@@ -439,6 +443,113 @@
 
 ###############
 
+    def create_snapshot(self, share_id, name=None, description=None,
+                        force=False, version=LATEST_MICROVERSION):
+        if name is None:
+            name = data_utils.rand_name("tempest-created-share-snap")
+        if description is None:
+            description = data_utils.rand_name(
+                "tempest-created-share-snap-desc")
+        post_body = {
+            "snapshot": {
+                "name": name,
+                "force": force,
+                "description": description,
+                "share_id": share_id,
+            }
+        }
+        body = json.dumps(post_body)
+        resp, body = self.post("snapshots", body, version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
+
+    def get_snapshot(self, snapshot_id, version=LATEST_MICROVERSION):
+        resp, body = self.get("snapshots/%s" % snapshot_id, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def list_snapshots(self, detailed=False, params=None,
+                       version=LATEST_MICROVERSION):
+        """Get list of share snapshots w/o filters."""
+        uri = 'snapshots/detail' if detailed else 'snapshots'
+        uri += '?%s' % urlparse.urlencode(params) if params else ''
+        resp, body = self.get(uri, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def list_snapshots_with_detail(self, params=None,
+                                   version=LATEST_MICROVERSION):
+        """Get detailed list of share snapshots w/o filters."""
+        return self.list_snapshots(detailed=True, params=params,
+                                   version=version)
+
+    def delete_snapshot(self, snap_id, version=LATEST_MICROVERSION):
+        resp, body = self.delete("snapshots/%s" % snap_id, version=version)
+        self.expected_success(202, resp.status)
+        return body
+
+    def wait_for_snapshot_status(self, snapshot_id, status,
+                                 version=LATEST_MICROVERSION):
+        """Waits for a snapshot to reach a given status."""
+        body = self.get_snapshot(snapshot_id, version=version)
+        snapshot_name = body['name']
+        snapshot_status = body['status']
+        start = int(time.time())
+
+        while snapshot_status != status:
+            time.sleep(self.build_interval)
+            body = self.get_snapshot(snapshot_id, version=version)
+            snapshot_status = body['status']
+            if 'error' in snapshot_status:
+                raise (share_exceptions.
+                       SnapshotBuildErrorException(snapshot_id=snapshot_id))
+
+            if int(time.time()) - start >= self.build_timeout:
+                message = ('Share Snapshot %s failed to reach %s status '
+                           'within the required time (%s s).' %
+                           (snapshot_name, status, self.build_timeout))
+                raise exceptions.TimeoutException(message)
+
+    def manage_snapshot(self, share_id, provider_location,
+                        name=None, description=None,
+                        version=LATEST_MICROVERSION,
+                        driver_options=None):
+        if name is None:
+            name = data_utils.rand_name("tempest-manage-snapshot")
+        if description is None:
+            description = data_utils.rand_name("tempest-manage-snapshot-desc")
+        post_body = {
+            "snapshot": {
+                "share_id": share_id,
+                "provider_location": provider_location,
+                "name": name,
+                "description": description,
+                "driver_options": driver_options if driver_options else {},
+            }
+        }
+        url = 'snapshots/manage'
+        body = json.dumps(post_body)
+        resp, body = self.post(url, body, version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
+
+    def unmanage_snapshot(self, snapshot_id, version=LATEST_MICROVERSION,
+                          body=None):
+        url = 'snapshots'
+        action_name = 'action'
+        if body is None:
+            body = json.dumps({'unmanage': {}})
+        resp, body = self.post(
+            "%(url)s/%(snapshot_id)s/%(action_name)s" % {
+                'url': url, 'snapshot_id': snapshot_id,
+                'action_name': action_name},
+            body,
+            version=version)
+        self.expected_success(202, resp.status)
+        return body
+
+###############
+
     def _get_access_action_name(self, version, action):
         if utils.is_microversion_gt(version, "2.6"):
             return action.split('os-')[-1]
@@ -838,16 +949,19 @@
 
 ###############
 
-    def migrate_share(self, share_id, host, version=LATEST_MICROVERSION,
-                      action_name=None):
+    def migrate_share(self, share_id, host, notify,
+                      version=LATEST_MICROVERSION, action_name=None):
         if action_name is None:
-            if utils.is_microversion_gt(version, "2.6"):
+            if utils.is_microversion_lt(version, "2.7"):
+                action_name = 'os-migrate_share'
+            elif utils.is_microversion_lt(version, "2.15"):
                 action_name = 'migrate_share'
             else:
-                action_name = 'os-migrate_share'
+                action_name = 'migration_start'
         post_body = {
             action_name: {
                 'host': host,
+                'notify': notify,
             }
         }
         body = json.dumps(post_body)
@@ -855,27 +969,242 @@
                          headers=EXPERIMENTAL, extra_headers=True,
                          version=version)
 
-    def wait_for_migration_completed(self, share_id, dest_host,
-                                     version=LATEST_MICROVERSION):
+    def migration_complete(self, share_id, version=LATEST_MICROVERSION,
+                           action_name='migration_complete'):
+        post_body = {
+            action_name: None,
+        }
+        body = json.dumps(post_body)
+        return self.post('shares/%s/action' % share_id, body,
+                         headers=EXPERIMENTAL, extra_headers=True,
+                         version=version)
+
+    def migration_cancel(self, share_id, version=LATEST_MICROVERSION,
+                         action_name='migration_cancel'):
+        post_body = {
+            action_name: None,
+        }
+        body = json.dumps(post_body)
+        return self.post('shares/%s/action' % share_id, body,
+                         headers=EXPERIMENTAL, extra_headers=True,
+                         version=version)
+
+    def migration_get_progress(self, share_id, version=LATEST_MICROVERSION,
+                               action_name='migration_get_progress'):
+        post_body = {
+            action_name: None,
+        }
+        body = json.dumps(post_body)
+        return self.post('shares/%s/action' % share_id, body,
+                         headers=EXPERIMENTAL, extra_headers=True,
+                         version=version)
+
+    def reset_task_state(
+            self, share_id, task_state, version=LATEST_MICROVERSION,
+            action_name='reset_task_state'):
+        post_body = {
+            action_name: {
+                'task_state': task_state,
+            }
+        }
+        body = json.dumps(post_body)
+        return self.post('shares/%s/action' % share_id, body,
+                         headers=EXPERIMENTAL, extra_headers=True,
+                         version=version)
+
+    def wait_for_migration_status(self, share_id, dest_host, status,
+                                  version=LATEST_MICROVERSION):
         """Waits for a share to migrate to a certain host."""
         share = self.get_share(share_id, version=version)
         migration_timeout = CONF.share.migration_timeout
         start = int(time.time())
-        while share['task_state'] != 'migration_success':
+        while share['task_state'] != status:
             time.sleep(self.build_interval)
             share = self.get_share(share_id, version=version)
-            if share['task_state'] == 'migration_success':
+            if share['task_state'] == status:
                 return share
             elif share['task_state'] == 'migration_error':
                 raise share_exceptions.ShareMigrationException(
                     share_id=share['id'], src=share['host'], dest=dest_host)
             elif int(time.time()) - start >= migration_timeout:
-                message = ('Share %(share_id)s failed to migrate from '
-                           'host %(src)s to host %(dest)s within the required '
-                           'time %(timeout)s.' % {
+                message = ('Share %(share_id)s failed to reach status '
+                           '%(status)s when migrating from host %(src)s to '
+                           'host %(dest)s within the required time '
+                           '%(timeout)s.' % {
                                'src': share['host'],
                                'dest': dest_host,
                                'share_id': share['id'],
-                               'timeout': self.build_timeout
+                               'timeout': self.build_timeout,
+                               'status': status,
                            })
                 raise exceptions.TimeoutException(message)
+
+################
+
+    def create_share_replica(self, share_id, availability_zone=None,
+                             version=LATEST_MICROVERSION):
+        """Add a share replica of an existing share."""
+        uri = "share-replicas"
+        post_body = {
+            'share_id': share_id,
+            'availability_zone': availability_zone,
+        }
+
+        body = json.dumps({'share_replica': post_body})
+        resp, body = self.post(uri, body,
+                               headers=EXPERIMENTAL,
+                               extra_headers=True,
+                               version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
+
+    def get_share_replica(self, replica_id, version=LATEST_MICROVERSION):
+        """Get the details of share_replica."""
+        resp, body = self.get("share-replicas/%s" % replica_id,
+                              headers=EXPERIMENTAL,
+                              extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def list_share_replicas(self, share_id=None, version=LATEST_MICROVERSION):
+        """Get list of replicas."""
+        uri = "share-replicas/detail"
+        uri += ("?share_id=%s" % share_id) if share_id is not None else ''
+        resp, body = self.get(uri, headers=EXPERIMENTAL,
+                              extra_headers=True, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def list_share_replicas_summary(self, share_id=None,
+                                    version=LATEST_MICROVERSION):
+        """Get summary list of replicas."""
+        uri = "share-replicas"
+        uri += ("?share_id=%s" % share_id) if share_id is not None else ''
+        resp, body = self.get(uri, headers=EXPERIMENTAL,
+                              extra_headers=True, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def delete_share_replica(self, replica_id, version=LATEST_MICROVERSION):
+        """Delete share_replica."""
+        uri = "share-replicas/%s" % replica_id
+        resp, body = self.delete(uri,
+                                 headers=EXPERIMENTAL,
+                                 extra_headers=True,
+                                 version=version)
+        self.expected_success(202, resp.status)
+        return body
+
+    def promote_share_replica(self, replica_id, expected_status=202,
+                              version=LATEST_MICROVERSION):
+        """Promote a share replica to active state."""
+        uri = "share-replicas/%s/action" % replica_id
+        post_body = {
+            'promote': None,
+        }
+        body = json.dumps(post_body)
+        resp, body = self.post(uri, body,
+                               headers=EXPERIMENTAL,
+                               extra_headers=True,
+                               version=version)
+        self.expected_success(expected_status, resp.status)
+        return self._parse_resp(body)
+
+    def wait_for_share_replica_status(self, replica_id, expected_status,
+                                      status_attr='status'):
+        """Waits for a replica's status_attr to reach a given status."""
+        body = self.get_share_replica(replica_id)
+        replica_status = body[status_attr]
+        start = int(time.time())
+
+        while replica_status != expected_status:
+            time.sleep(self.build_interval)
+            body = self.get_share_replica(replica_id)
+            replica_status = body[status_attr]
+            if replica_status == expected_status:
+                return
+            if ('error' in replica_status
+                    and expected_status != constants.STATUS_ERROR):
+                raise share_exceptions.ShareInstanceBuildErrorException(
+                    id=replica_id)
+
+            if int(time.time()) - start >= self.build_timeout:
+                message = ('The %(status_attr)s of Replica %(id)s failed to '
+                           'reach %(expected_status)s status within the '
+                           'required time (%(time)ss). Current '
+                           '%(status_attr)s: %(current_status)s.' %
+                           {
+                               'status_attr': status_attr,
+                               'expected_status': expected_status,
+                               'time': self.build_timeout,
+                               'id': replica_id,
+                               'current_status': replica_status,
+                           })
+                raise exceptions.TimeoutException(message)
+
+    def reset_share_replica_status(self, replica_id,
+                                   status=constants.STATUS_AVAILABLE,
+                                   version=LATEST_MICROVERSION):
+        """Reset the status."""
+        uri = 'share-replicas/%s/action' % replica_id
+        post_body = {
+            'reset_status': {
+                'status': status
+            }
+        }
+        body = json.dumps(post_body)
+        resp, body = self.post(uri, body,
+                               headers=EXPERIMENTAL,
+                               extra_headers=True,
+                               version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
+
+    def reset_share_replica_state(self, replica_id,
+                                  state=constants.REPLICATION_STATE_ACTIVE,
+                                  version=LATEST_MICROVERSION):
+        """Reset the replication state of a replica."""
+        uri = 'share-replicas/%s/action' % replica_id
+        post_body = {
+            'reset_replica_state': {
+                'replica_state': state
+            }
+        }
+        body = json.dumps(post_body)
+        resp, body = self.post(uri, body,
+                               headers=EXPERIMENTAL,
+                               extra_headers=True,
+                               version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
+
+    def resync_share_replica(self, replica_id, expected_result=202,
+                             version=LATEST_MICROVERSION):
+        """Force an immediate resync of the replica."""
+        uri = 'share-replicas/%s/action' % replica_id
+        post_body = {
+            'resync': None
+        }
+        body = json.dumps(post_body)
+        resp, body = self.post(uri, body,
+                               headers=EXPERIMENTAL,
+                               extra_headers=True,
+                               version=version)
+        self.expected_success(expected_result, resp.status)
+        return self._parse_resp(body)
+
+    def force_delete_share_replica(self, replica_id,
+                                   version=LATEST_MICROVERSION):
+        """Force delete a replica."""
+        uri = 'share-replicas/%s/action' % replica_id
+        post_body = {
+            'force_delete': None
+        }
+        body = json.dumps(post_body)
+        resp, body = self.post(uri, body,
+                               headers=EXPERIMENTAL,
+                               extra_headers=True,
+                               version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
diff --git a/manila_tempest_tests/share_exceptions.py b/manila_tempest_tests/share_exceptions.py
index aa688e4..3a11531 100644
--- a/manila_tempest_tests/share_exceptions.py
+++ b/manila_tempest_tests/share_exceptions.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions
+from tempest.lib import exceptions
 
 
 class ShareBuildErrorException(exceptions.TempestException):
@@ -65,3 +65,8 @@
 
 class ResourceReleaseFailed(exceptions.TempestException):
     message = "Failed to release resource '%(res_type)s' with id '%(res_id)s'."
+
+
+class ShareReplicationTypeException(exceptions.TempestException):
+    message = ("Option backend_replication_type is set to incorrect value: "
+               "%(replication_type)s")
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 9ac085a..108173e 100644
--- a/manila_tempest_tests/tests/api/admin/test_admin_actions.py
+++ b/manila_tempest_tests/tests/api/admin/test_admin_actions.py
@@ -29,6 +29,8 @@
     def resource_setup(cls):
         super(AdminActionsTest, cls).resource_setup()
         cls.states = ["error", "available"]
+        cls.task_states = ["migration_starting", "data_copying_in_progress",
+                           "migration_success"]
         cls.bad_status = "error_deleting"
         cls.sh = cls.create_share()
         cls.sh_instance = (
@@ -116,3 +118,11 @@
         # Snapshot with status 'error_deleting' should be deleted
         self.shares_v2_client.force_delete(sn["id"], s_type="snapshots")
         self.shares_v2_client.wait_for_resource_deletion(snapshot_id=sn["id"])
+
+    @test.attr(type=["gate", ])
+    @base.skip_if_microversion_lt("2.15")
+    def test_reset_share_task_state(self):
+        for task_state in self.task_states:
+            self.shares_v2_client.reset_task_state(self.sh["id"], task_state)
+            self.shares_v2_client.wait_for_share_status(
+                self.sh["id"], task_state, 'task_state')
diff --git a/manila_tempest_tests/tests/api/admin/test_admin_actions_negative.py b/manila_tempest_tests/tests/api/admin/test_admin_actions_negative.py
index a1ff4f7..82fcd5a 100644
--- a/manila_tempest_tests/tests/api/admin/test_admin_actions_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_admin_actions_negative.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 import testtools  # noqa
 
 from manila_tempest_tests import clients_share as clients
@@ -166,3 +166,24 @@
         self.assertRaises(lib_exc.Forbidden,
                           self.member_shares_v2_client.get_instances_of_share,
                           self.sh['id'])
+
+    @test.attr(type=["gate", "negative", ])
+    @base.skip_if_microversion_lt("2.15")
+    def test_reset_task_state_share_not_found(self):
+        self.assertRaises(
+            lib_exc.NotFound, self.shares_v2_client.reset_task_state,
+            'fake_share', 'migration_error')
+
+    @test.attr(type=["gate", "negative", ])
+    @base.skip_if_microversion_lt("2.15")
+    def test_reset_task_state_empty(self):
+        self.assertRaises(
+            lib_exc.BadRequest, self.shares_v2_client.reset_task_state,
+            self.sh['id'], None)
+
+    @test.attr(type=["gate", "negative", ])
+    @base.skip_if_microversion_lt("2.15")
+    def test_reset_task_state_invalid_state(self):
+        self.assertRaises(
+            lib_exc.BadRequest, self.shares_v2_client.reset_task_state,
+            self.sh['id'], 'fake_state')
diff --git a/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py b/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py
index c057c36..085cb1e 100644
--- a/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py
+++ b/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config
+from tempest.lib.common.utils import data_utils
 from tempest import test
-from tempest_lib.common.utils import data_utils
 import testtools
 
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/admin/test_consistency_groups.py b/manila_tempest_tests/tests/api/admin/test_consistency_groups.py
index d562e45..a121c57 100644
--- a/manila_tempest_tests/tests/api/admin/test_consistency_groups.py
+++ b/manila_tempest_tests/tests/api/admin/test_consistency_groups.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config
+from tempest.lib.common.utils import data_utils
 from tempest import test
-from tempest_lib.common.utils import data_utils
 import testtools
 
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py b/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py
index eafb5e8..18cf5db 100644
--- a/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py
@@ -14,9 +14,9 @@
 #    under the License.
 
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
 from tempest import test
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions
 import testtools
 
 from manila_tempest_tests.tests.api import base
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 4791cb0..a7b45a8 100644
--- a/manila_tempest_tests/tests/api/admin/test_export_locations.py
+++ b/manila_tempest_tests/tests/api/admin/test_export_locations.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import ddt
 from oslo_utils import timeutils
 from oslo_utils import uuidutils
 import six
@@ -21,11 +22,14 @@
 
 from manila_tempest_tests import clients_share as clients
 from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
 
 CONF = config.CONF
+LATEST_MICROVERSION = CONF.share.max_api_microversion
 
 
 @base.skip_if_microversion_not_supported("2.9")
+@ddt.ddt
 class ExportLocationsTest(base.BaseSharesAdminTest):
 
     @classmethod
@@ -38,42 +42,82 @@
         cls.share_instances = cls.shares_v2_client.get_instances_of_share(
             cls.share['id'])
 
-    def _verify_export_location_structure(self, export_locations,
-                                          role='admin'):
-        expected_keys = [
-            'created_at', 'updated_at', 'path', 'uuid',
-        ]
-        if role == 'admin':
-            expected_keys.extend(['is_admin_only', 'share_instance_id'])
+    def _verify_export_location_structure(
+            self, export_locations, role='admin', version=LATEST_MICROVERSION,
+            format='summary'):
+
+        # Determine which keys to expect based on role, version and format
+        summary_keys = ['id', 'path']
+        if utils.is_microversion_ge(version, '2.14'):
+            summary_keys += ['preferred']
+
+        admin_summary_keys = summary_keys + [
+            'share_instance_id', 'is_admin_only']
+
+        detail_keys = summary_keys + ['created_at', 'updated_at']
+
+        admin_detail_keys = admin_summary_keys + ['created_at', 'updated_at']
+
+        if format == 'summary':
+            if role == 'admin':
+                expected_keys = admin_summary_keys
+            else:
+                expected_keys = summary_keys
+        else:
+            if role == 'admin':
+                expected_keys = admin_detail_keys
+            else:
+                expected_keys = detail_keys
 
         if not isinstance(export_locations, (list, tuple, set)):
             export_locations = (export_locations, )
 
         for export_location in export_locations:
+
+            # Check that the correct keys are present
             self.assertEqual(len(expected_keys), len(export_location))
             for key in expected_keys:
                 self.assertIn(key, export_location)
+
+            # Check the format of ever-present summary keys
+            self.assertTrue(uuidutils.is_uuid_like(export_location['id']))
+            self.assertTrue(isinstance(export_location['path'],
+                                       six.string_types))
+
+            if utils.is_microversion_ge(version, '2.14'):
+                self.assertIn(export_location['preferred'], (True, False))
+
             if role == 'admin':
                 self.assertIn(export_location['is_admin_only'], (True, False))
-                self.assertTrue(
-                    uuidutils.is_uuid_like(
-                        export_location['share_instance_id']))
-            self.assertTrue(uuidutils.is_uuid_like(export_location['uuid']))
-            self.assertTrue(
-                isinstance(export_location['path'], six.string_types))
-            for time in (export_location['created_at'],
-                         export_location['updated_at']):
-                # If var 'time' has incorrect value then ValueError exception
-                # is expected to be raised. So, just try parse it making
-                # assertion that it has proper date value.
-                timeutils.parse_strtime(time)
+                self.assertTrue(uuidutils.is_uuid_like(
+                    export_location['share_instance_id']))
+
+            # Check the format of the detail keys
+            if format == 'detail':
+                for time in (export_location['created_at'],
+                             export_location['updated_at']):
+                    # If var 'time' has incorrect value then ValueError
+                    # exception is expected to be raised. So, just try parse
+                    # it making assertion that it has proper date value.
+                    timeutils.parse_strtime(time)
 
     @test.attr(type=["gate", ])
+    @utils.skip_if_microversion_not_supported('2.13')
     def test_list_share_export_locations(self):
         export_locations = self.admin_client.list_share_export_locations(
-            self.share['id'])
+            self.share['id'], version='2.13')
 
-        self._verify_export_location_structure(export_locations)
+        self._verify_export_location_structure(export_locations,
+                                               version='2.13')
+
+    @test.attr(type=["gate", ])
+    @utils.skip_if_microversion_not_supported('2.14')
+    def test_list_share_export_locations_with_preferred_flag(self):
+        export_locations = self.admin_client.list_share_export_locations(
+            self.share['id'], version='2.14')
+
+        self._verify_export_location_structure(export_locations,
+                                               version='2.14')
 
     @test.attr(type=["gate", ])
     def test_get_share_export_location(self):
@@ -82,15 +126,15 @@
 
         for export_location in export_locations:
             el = self.admin_client.get_share_export_location(
-                self.share['id'], export_location['uuid'])
-            self._verify_export_location_structure(el)
+                self.share['id'], export_location['id'])
+            self._verify_export_location_structure(el, format='detail')
 
     @test.attr(type=["gate", ])
     def test_list_share_export_locations_by_member(self):
         export_locations = self.member_client.list_share_export_locations(
             self.share['id'])
 
-        self._verify_export_location_structure(export_locations, 'member')
+        self._verify_export_location_structure(export_locations, role='member')
 
     @test.attr(type=["gate", ])
     def test_get_share_export_location_by_member(self):
@@ -101,16 +145,29 @@
             if export_location['is_admin_only']:
                 continue
             el = self.member_client.get_share_export_location(
-                self.share['id'], export_location['uuid'])
-            self._verify_export_location_structure(el, 'member')
+                self.share['id'], export_location['id'])
+            self._verify_export_location_structure(el, role='member',
+                                                   format='detail')
 
     @test.attr(type=["gate", ])
+    @utils.skip_if_microversion_not_supported('2.13')
     def test_list_share_instance_export_locations(self):
         for share_instance in self.share_instances:
             export_locations = (
                 self.admin_client.list_share_instance_export_locations(
-                    share_instance['id']))
-            self._verify_export_location_structure(export_locations)
+                    share_instance['id'], version='2.13'))
+            self._verify_export_location_structure(export_locations,
+                                                   version='2.13')
+
+    @test.attr(type=["gate", ])
+    @utils.skip_if_microversion_not_supported('2.14')
+    def test_list_share_instance_export_locations_with_preferred_flag(self):
+        for share_instance in self.share_instances:
+            export_locations = (
+                self.admin_client.list_share_instance_export_locations(
+                    share_instance['id'], version='2.14'))
+            self._verify_export_location_structure(export_locations,
+                                                   version='2.14')
 
     @test.attr(type=["gate", ])
     def test_get_share_instance_export_location(self):
@@ -120,8 +177,8 @@
                     share_instance['id']))
             for el in export_locations:
                 el = self.admin_client.get_share_instance_export_location(
-                    share_instance['id'], el['uuid'])
-                self._verify_export_location_structure(el)
+                    share_instance['id'], el['id'])
+                self._verify_export_location_structure(el, format='detail')
 
     @test.attr(type=["gate", ])
     def test_share_contains_all_export_locations_of_all_share_instances(self):
@@ -140,6 +197,6 @@
             len(share_instances_export_locations)
         )
         self.assertEqual(
-            sorted(share_export_locations, key=lambda el: el['uuid']),
-            sorted(share_instances_export_locations, key=lambda el: el['uuid'])
+            sorted(share_export_locations, key=lambda el: el['id']),
+            sorted(share_instances_export_locations, key=lambda el: el['id'])
         )
diff --git a/manila_tempest_tests/tests/api/admin/test_export_locations_negative.py b/manila_tempest_tests/tests/api/admin/test_export_locations_negative.py
index 9d53373..93ff5f0 100644
--- a/manila_tempest_tests/tests/api/admin/test_export_locations_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_export_locations_negative.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 
 from manila_tempest_tests import clients_share as clients
 from manila_tempest_tests.tests.api import base
@@ -90,5 +90,5 @@
                 self.assertRaises(
                     lib_exc.Forbidden,
                     self.member_client.get_share_instance_export_location,
-                    share_instance['id'], el['uuid'],
+                    share_instance['id'], el['id'],
                 )
diff --git a/manila_tempest_tests/tests/api/admin/test_migration.py b/manila_tempest_tests/tests/api/admin/test_migration.py
index 517f43d..96f657a 100644
--- a/manila_tempest_tests/tests/api/admin/test_migration.py
+++ b/manila_tempest_tests/tests/api/admin/test_migration.py
@@ -17,6 +17,7 @@
 from tempest import test  # noqa
 
 from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
 
 CONF = config.CONF
 
@@ -39,8 +40,45 @@
             raise cls.skipException("Migration tests disabled. Skipping.")
 
     @test.attr(type=["gate", ])
+    @base.skip_if_microversion_lt("2.5")
     def test_migration_empty_v2_5(self):
 
+        share, dest_pool = self._setup_migration()
+
+        old_exports = share['export_locations']
+
+        share = self.migrate_share(share['id'], dest_pool, version='2.5')
+
+        self._validate_migration_successful(dest_pool, share, old_exports,
+                                            version='2.5')
+
+    @test.attr(type=["gate", ])
+    @base.skip_if_microversion_lt("2.15")
+    def test_migration_completion_empty_v2_15(self):
+
+        share, dest_pool = self._setup_migration()
+
+        old_exports = self.shares_v2_client.list_share_export_locations(
+            share['id'], version='2.15')
+        self.assertNotEmpty(old_exports)
+        old_exports = [x['path'] for x in old_exports
+                       if x['is_admin_only'] is False]
+        self.assertNotEmpty(old_exports)
+
+        share = self.migrate_share(
+            share['id'], dest_pool, version='2.15', notify=False,
+            wait_for_status='data_copying_completed')
+
+        self._validate_migration_successful(dest_pool, share,
+                                            old_exports, '2.15', notify=False)
+
+        share = self.migration_complete(share['id'], dest_pool, version='2.15')
+
+        self._validate_migration_successful(dest_pool, share, old_exports,
+                                            version='2.15')
+
+    def _setup_migration(self):
+
         pools = self.shares_client.list_pools()['pools']
 
         if len(pools) < 2:
@@ -51,6 +89,18 @@
         share = self.create_share(self.protocol)
         share = self.shares_client.get_share(share['id'])
 
+        self.shares_v2_client.create_access_rule(
+            share['id'], access_to="50.50.50.50", access_level="rw")
+
+        self.shares_v2_client.wait_for_share_status(
+            share['id'], 'active', status_attr='access_rules_status')
+
+        self.shares_v2_client.create_access_rule(
+            share['id'], access_to="51.51.51.51", access_level="ro")
+
+        self.shares_v2_client.wait_for_share_status(
+            share['id'], 'active', status_attr='access_rules_status')
+
         dest_pool = next((x for x in pools if x['name'] != share['host']),
                          None)
 
@@ -59,10 +109,30 @@
 
         dest_pool = dest_pool['name']
 
-        old_export_location = share['export_locations'][0]
+        return share, dest_pool
 
-        share = self.migrate_share(share['id'], dest_pool, version='2.5')
+    def _validate_migration_successful(self, dest_pool, share,
+                                       old_exports, version, notify=True):
+        if utils.is_microversion_lt(version, '2.9'):
+            new_exports = share['export_locations']
+            self.assertNotEmpty(new_exports)
+        else:
+            new_exports = self.shares_v2_client.list_share_export_locations(
+                share['id'], version='2.9')
+            self.assertNotEmpty(new_exports)
+            new_exports = [x['path'] for x in new_exports if
+                           x['is_admin_only'] is False]
+            self.assertNotEmpty(new_exports)
 
-        self.assertEqual(dest_pool, share['host'])
-        self.assertNotEqual(old_export_location, share['export_locations'][0])
-        self.assertEqual('migration_success', share['task_state'])
+        # Share migrated
+        if notify:
+            self.assertEqual(dest_pool, share['host'])
+            for export in old_exports:
+                self.assertFalse(export in new_exports)
+            self.assertEqual('migration_success', share['task_state'])
+        # Share not migrated yet
+        else:
+            self.assertNotEqual(dest_pool, share['host'])
+            for export in old_exports:
+                self.assertTrue(export in new_exports)
+            self.assertEqual('data_copying_completed', share['task_state'])
diff --git a/manila_tempest_tests/tests/api/admin/test_migration_negative.py b/manila_tempest_tests/tests/api/admin/test_migration_negative.py
new file mode 100644
index 0000000..b7d75c4
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_migration_negative.py
@@ -0,0 +1,97 @@
+# Copyright 2015 Hitachi Data Systems.
+# 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  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
+from tempest import test  # noqa
+
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+class MigrationNFSTest(base.BaseSharesAdminTest):
+    """Tests Share Migration.
+
+    Tests migration in multi-backend environment.
+    """
+
+    protocol = "nfs"
+
+    @classmethod
+    def resource_setup(cls):
+        super(MigrationNFSTest, cls).resource_setup()
+        if not CONF.share.run_migration_tests:
+            raise cls.skipException("Migration tests disabled. Skipping.")
+
+        cls.share = cls.create_share(cls.protocol)
+        cls.share = cls.shares_client.get_share(cls.share['id'])
+        pools = cls.shares_client.list_pools()['pools']
+
+        if len(pools) < 2:
+            raise cls.skipException("At least two different pool entries "
+                                    "are needed to run migration tests. "
+                                    "Skipping.")
+        cls.dest_pool = next((x for x in pools
+                              if x['name'] != cls.share['host']), None)
+
+    @test.attr(type=["gate", "negative", ])
+    @base.skip_if_microversion_lt("2.15")
+    def test_migration_cancel_invalid(self):
+        self.assertRaises(
+            lib_exc.BadRequest, self.shares_v2_client.migration_cancel,
+            self.share['id'])
+
+    @test.attr(type=["gate", "negative", ])
+    @base.skip_if_microversion_lt("2.15")
+    def test_migration_get_progress_invalid(self):
+        self.assertRaises(
+            lib_exc.BadRequest, self.shares_v2_client.migration_get_progress,
+            self.share['id'])
+
+    @test.attr(type=["gate", "negative", ])
+    @base.skip_if_microversion_lt("2.15")
+    def test_migration_complete_invalid(self):
+        self.assertRaises(
+            lib_exc.BadRequest, self.shares_v2_client.migration_complete,
+            self.share['id'])
+
+    @test.attr(type=["gate", "negative", ])
+    @base.skip_if_microversion_lt("2.5")
+    def test_migrate_share_with_snapshot_v2_5(self):
+        snap = self.create_snapshot_wait_for_active(self.share['id'])
+        self.assertRaises(
+            lib_exc.BadRequest, self.shares_v2_client.migrate_share,
+            self.share['id'], self.dest_pool, True, version='2.5')
+        self.shares_client.delete_snapshot(snap['id'])
+        self.shares_client.wait_for_resource_deletion(snapshot_id=snap["id"])
+
+    @test.attr(type=["gate", "negative", ])
+    @base.skip_if_microversion_lt("2.5")
+    def test_migrate_share_same_host_v2_5(self):
+        self.assertRaises(
+            lib_exc.BadRequest, self.shares_v2_client.migrate_share,
+            self.share['id'], self.share['host'], True, version='2.5')
+
+    @test.attr(type=["gate", "negative", ])
+    @base.skip_if_microversion_lt("2.5")
+    def test_migrate_share_not_available_v2_5(self):
+        self.shares_client.reset_state(self.share['id'], 'error')
+        self.shares_client.wait_for_share_status(self.share['id'], 'error')
+        self.assertRaises(
+            lib_exc.BadRequest, self.shares_v2_client.migrate_share,
+            self.share['id'], self.dest_pool, True, version='2.5')
+        self.shares_client.reset_state(self.share['id'], 'available')
+        self.shares_client.wait_for_share_status(self.share['id'], 'available')
diff --git a/manila_tempest_tests/tests/api/admin/test_multi_backend.py b/manila_tempest_tests/tests/api/admin/test_multi_backend.py
index 4e69eda..59f56c8 100644
--- a/manila_tempest_tests/tests/api/admin/test_multi_backend.py
+++ b/manila_tempest_tests/tests/api/admin/test_multi_backend.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config  # noqa
+from tempest.lib.common.utils import data_utils  # noqa
 from tempest import test  # noqa
-from tempest_lib.common.utils import data_utils  # noqa
 
 from manila_tempest_tests.tests.api import base
 
diff --git a/manila_tempest_tests/tests/api/admin/test_quotas.py b/manila_tempest_tests/tests/api/admin/test_quotas.py
index badedc2..3c99083 100644
--- a/manila_tempest_tests/tests/api/admin/test_quotas.py
+++ b/manila_tempest_tests/tests/api/admin/test_quotas.py
@@ -26,6 +26,9 @@
 
     @classmethod
     def resource_setup(cls):
+        if not CONF.share.run_quota_tests:
+            msg = "Quota tests are disabled."
+            raise cls.skipException(msg)
         cls.os = clients.AdminManager()
         super(SharesAdminQuotasTest, cls).resource_setup()
         cls.user_id = cls.shares_v2_client.user_id
@@ -65,6 +68,14 @@
     force_tenant_isolation = True
     client_version = '2'
 
+    @classmethod
+    def resource_setup(cls):
+        if not CONF.share.run_quota_tests:
+            msg = "Quota tests are disabled."
+            raise cls.skipException(msg)
+        cls.os = clients.AdminManager()
+        super(SharesAdminQuotasUpdateTest, cls).resource_setup()
+
     def setUp(self):
         super(self.__class__, self).setUp()
         self.client = self.get_client_with_isolated_creds(
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 7850a2d..985bef4 100644
--- a/manila_tempest_tests/tests/api/admin/test_quotas_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_quotas_negative.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 import testtools  # noqa
 
 from manila_tempest_tests import clients_share as clients
@@ -30,6 +30,9 @@
 
     @classmethod
     def resource_setup(cls):
+        if not CONF.share.run_quota_tests:
+            msg = "Quota tests are disabled."
+            raise cls.skipException(msg)
         cls.os = clients.AdminManager()
         super(SharesAdminQuotasNegativeTest, cls).resource_setup()
         cls.user_id = cls.shares_client.user_id
diff --git a/manila_tempest_tests/tests/api/admin/test_replication.py b/manila_tempest_tests/tests/api/admin/test_replication.py
new file mode 100644
index 0000000..605656c
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_replication.py
@@ -0,0 +1,173 @@
+# Copyright 2015 Yogesh Kshirsagar
+# 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 import test
+import testtools
+
+from manila_tempest_tests import clients_share as clients
+from manila_tempest_tests.common import constants
+from manila_tempest_tests import share_exceptions
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+_MIN_SUPPORTED_MICROVERSION = '2.11'
+
+
+@testtools.skipUnless(CONF.share.run_replication_tests,
+                      'Replication tests are disabled.')
+@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
+class ReplicationAdminTest(base.BaseSharesAdminTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ReplicationAdminTest, cls).resource_setup()
+        # Create share_type
+        name = data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX)
+        cls.admin_client = clients.AdminManager().shares_v2_client
+        cls.replication_type = CONF.share.backend_replication_type
+
+        if cls.replication_type not in constants.REPLICATION_TYPE_CHOICES:
+            raise share_exceptions.ShareReplicationTypeException(
+                replication_type=cls.replication_type
+            )
+        cls.zones = cls.get_availability_zones(client=cls.admin_client)
+        cls.share_zone = cls.zones[0]
+        cls.replica_zone = cls.zones[-1]
+
+        cls.extra_specs = cls.add_required_extra_specs_to_dict(
+            {"replication_type": cls.replication_type})
+        share_type = cls.create_share_type(
+            name,
+            extra_specs=cls.extra_specs,
+            client=cls.admin_client)
+        cls.share_type = share_type["share_type"]
+        # Create share with above share_type
+        cls.share = cls.create_share(share_type_id=cls.share_type["id"],
+                                     availability_zone=cls.share_zone,)
+        cls.replica = cls.shares_v2_client.list_share_replicas(
+            share_id=cls.share['id'])[0]
+
+    @staticmethod
+    def _filter_share_replica_list(replica_list, r_state):
+        # Iterate through replica list to filter based on replica_state
+        return [replica['id'] for replica in replica_list
+                if replica['replica_state'] == r_state]
+
+    @test.attr(type=["gate", ])
+    def test_promote_out_of_sync_share_replica(self):
+        """Test promote 'out_of_sync' share replica to active state."""
+        if (self.replication_type
+                not in constants.REPLICATION_PROMOTION_CHOICES):
+            msg = "Option backend_replication_type should be one of (%s)!"
+            raise self.skipException(
+                msg % ','.join(constants.REPLICATION_PROMOTION_CHOICES))
+        share = self.create_share(share_type_id=self.share_type['id'])
+        original_replica = self.shares_v2_client.list_share_replicas(
+            share_id=share['id'])[0]
+
+        # NOTE(Yogi1): Cleanup needs to be disabled for replica that is
+        # being promoted since it will become the 'primary'/'active' replica.
+        replica = self.create_share_replica(share["id"], self.replica_zone,
+                                            cleanup=False)
+
+        # List replicas
+        replica_list = self.admin_client.list_share_replicas(
+            share_id=share['id'])
+
+        # Check if there is only 1 'active' replica before promotion.
+        active_replicas = self._filter_share_replica_list(
+            replica_list, constants.REPLICATION_STATE_ACTIVE)
+        self.assertEqual(1, len(active_replicas))
+
+        # Set replica_state to 'out_of_sync'
+        self.admin_client.reset_share_replica_state(
+            replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC)
+        self.shares_v2_client.wait_for_share_replica_status(
+            replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC,
+            status_attr='replica_state')
+
+        # Promote 'out_of_sync' replica to 'active' state.
+        self.promote_share_replica(replica['id'], self.admin_client)
+        # Original replica will need to be cleaned up before the promoted
+        # replica can be deleted.
+        self.addCleanup(self.delete_share_replica, original_replica['id'])
+
+        # Check if there is still only 1 'active' replica after promotion.
+        replica_list = self.shares_v2_client.list_share_replicas(
+            share_id=self.share["id"])
+        new_active_replicas = self._filter_share_replica_list(
+            replica_list, constants.REPLICATION_STATE_ACTIVE)
+        self.assertEqual(1, len(new_active_replicas))
+
+    @test.attr(type=["gate", ])
+    def test_force_delete_share_replica(self):
+        """Test force deleting a replica that is in 'error_deleting' status."""
+        replica = self.create_share_replica(self.share['id'],
+                                            self.replica_zone,
+                                            cleanup_in_class=False)
+        self.admin_client.reset_share_replica_status(
+            replica['id'], constants.STATUS_ERROR_DELETING)
+        self.shares_v2_client.wait_for_share_replica_status(
+            replica['id'], constants.STATUS_ERROR_DELETING)
+        self.admin_client.force_delete_share_replica(replica['id'])
+        self.shares_v2_client.wait_for_resource_deletion(
+            replica_id=replica['id'])
+
+    @test.attr(type=["gate", ])
+    def test_reset_share_replica_status(self):
+        """Test resetting a replica's 'status' attribute."""
+        replica = self.create_share_replica(self.share['id'],
+                                            self.replica_zone,
+                                            cleanup_in_class=False)
+        self.admin_client.reset_share_replica_status(replica['id'],
+                                                     constants.STATUS_ERROR)
+        self.shares_v2_client.wait_for_share_replica_status(
+            replica['id'], constants.STATUS_ERROR)
+
+    @test.attr(type=["gate", ])
+    def test_reset_share_replica_state(self):
+        """Test resetting a replica's 'replica_state' attribute."""
+        replica = self.create_share_replica(self.share['id'],
+                                            self.replica_zone,
+                                            cleanup_in_class=False)
+        self.admin_client.reset_share_replica_state(replica['id'],
+                                                    constants.STATUS_ERROR)
+        self.shares_v2_client.wait_for_share_replica_status(
+            replica['id'], constants.STATUS_ERROR, status_attr='replica_state')
+
+    @test.attr(type=["gate", ])
+    def test_resync_share_replica(self):
+        """Test resyncing a replica."""
+        replica = self.create_share_replica(self.share['id'],
+                                            self.replica_zone,
+                                            cleanup_in_class=False)
+        self.shares_v2_client.wait_for_share_replica_status(
+            replica['id'], constants.REPLICATION_STATE_IN_SYNC,
+            status_attr='replica_state')
+
+        # Set replica_state to 'out_of_sync'.
+        self.admin_client.reset_share_replica_state(
+            replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC)
+        self.shares_v2_client.wait_for_share_replica_status(
+            replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC,
+            status_attr='replica_state')
+
+        # Attempt resync
+        self.admin_client.resync_share_replica(replica['id'])
+        self.shares_v2_client.wait_for_share_replica_status(
+            replica['id'], constants.REPLICATION_STATE_IN_SYNC,
+            status_attr='replica_state')
diff --git a/manila_tempest_tests/tests/api/admin/test_scheduler_stats.py b/manila_tempest_tests/tests/api/admin/test_scheduler_stats.py
index 973e52e..d1ef6ef 100644
--- a/manila_tempest_tests/tests/api/admin/test_scheduler_stats.py
+++ b/manila_tempest_tests/tests/api/admin/test_scheduler_stats.py
@@ -13,8 +13,8 @@
 #    under the License.
 
 from tempest import config  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 
 from manila_tempest_tests.tests.api import base
 
diff --git a/manila_tempest_tests/tests/api/admin/test_services_negative.py b/manila_tempest_tests/tests/api/admin/test_services_negative.py
index a229c45..b32ee5a 100644
--- a/manila_tempest_tests/tests/api/admin/test_services_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_services_negative.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 import ddt
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 
 from manila_tempest_tests import clients_share as clients
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/admin/test_share_manage.py b/manila_tempest_tests/tests/api/admin/test_share_manage.py
index bbd98bc..9908148 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_manage.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_manage.py
@@ -15,9 +15,9 @@
 
 import six
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions as lib_exc
 import testtools
 
 from manila_tempest_tests.tests.api import base
@@ -196,3 +196,7 @@
 
 class ManageHDFSShareTest(ManageNFSShareTest):
     protocol = 'hdfs'
+
+
+class ManageCephFSShareTest(ManageNFSShareTest):
+    protocol = 'cephfs'
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 fb803fc..df13ce9 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers.py
@@ -17,8 +17,8 @@
 
 import six  # noqa
 from tempest import config  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 
 from manila_tempest_tests.tests.api import base
 
@@ -219,7 +219,7 @@
             neutron_subnet_id=self.share_network['neutron_subnet_id'])
 
         # Create server with share
-        share = self.create_share(share_network_id=new_sn['id'])
+        self.create_share(share_network_id=new_sn['id'])
 
         # List share servers, filtered by share_network_id
         search_opts = {"share_network": new_sn["id"]}
@@ -238,7 +238,6 @@
             shares = self.shares_client.list_shares_with_detail(params)
             for s in shares:
                 self.assertEqual(new_sn["id"], s["share_network_id"])
-            self.assertTrue(any(share["id"] == s["id"] for s in shares))
 
             # Delete shares, so we will have share server without shares
             for s in shares:
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers_negative.py b/manila_tempest_tests/tests/api/admin/test_share_servers_negative.py
index a308ccf..e4712aa 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers_negative.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.common.utils import data_utils  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib.common.utils import data_utils  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 
 from manila_tempest_tests import clients_share as clients
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/admin/test_share_types.py b/manila_tempest_tests/tests/api/admin/test_share_types.py
index a521aad..c1a17cd 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_types.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_types.py
@@ -15,9 +15,9 @@
 
 import ddt
 from tempest import config  # noqa
+from tempest.lib.common.utils import data_utils  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib.common.utils import data_utils  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 
 from manila_tempest_tests.tests.api import base
 from manila_tempest_tests import utils
diff --git a/manila_tempest_tests/tests/api/admin/test_share_types_extra_specs.py b/manila_tempest_tests/tests/api/admin/test_share_types_extra_specs.py
index c4be5a8..c387765 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_types_extra_specs.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_types_extra_specs.py
@@ -15,8 +15,8 @@
 
 import copy
 
+from tempest.lib.common.utils import data_utils  # noqa
 from tempest import test  # noqa
-from tempest_lib.common.utils import data_utils  # noqa
 
 from manila_tempest_tests.tests.api import base
 
diff --git a/manila_tempest_tests/tests/api/admin/test_share_types_extra_specs_negative.py b/manila_tempest_tests/tests/api/admin/test_share_types_extra_specs_negative.py
index 600072a..771f240 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_types_extra_specs_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_types_extra_specs_negative.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.common.utils import data_utils  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib.common.utils import data_utils  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 
 from manila_tempest_tests import clients_share as clients
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/admin/test_share_types_negative.py b/manila_tempest_tests/tests/api/admin/test_share_types_negative.py
index 32c9620..2f41e76 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_types_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_types_negative.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.common.utils import data_utils  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib.common.utils import data_utils  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 
 from manila_tempest_tests import clients_share as clients
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/admin/test_shares_actions.py b/manila_tempest_tests/tests/api/admin/test_shares_actions.py
index e630123..696eecb 100644
--- a/manila_tempest_tests/tests/api/admin/test_shares_actions.py
+++ b/manila_tempest_tests/tests/api/admin/test_shares_actions.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config  # noqa
+from tempest.lib.common.utils import data_utils  # noqa
 from tempest import test  # noqa
-from tempest_lib.common.utils import data_utils  # noqa
 import testtools  # noqa
 
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/admin/test_snapshot_manage.py b/manila_tempest_tests/tests/api/admin/test_snapshot_manage.py
new file mode 100644
index 0000000..26ff1af
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_snapshot_manage.py
@@ -0,0 +1,143 @@
+# Copyright 2015 EMC Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import six
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+import testtools
+
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+class ManageNFSSnapshotTest(base.BaseSharesAdminTest):
+    protocol = 'nfs'
+
+    # NOTE(vponomaryov): be careful running these tests using generic driver
+    # because cinder volume snapshots won't be deleted.
+
+    @classmethod
+    @base.skip_if_microversion_lt("2.12")
+    @testtools.skipIf(
+        CONF.share.multitenancy_enabled,
+        "Only for driver_handles_share_servers = False driver mode.")
+    @testtools.skipUnless(
+        CONF.share.run_manage_unmanage_snapshot_tests,
+        "Manage/unmanage snapshot tests are disabled.")
+    def resource_setup(cls):
+        super(ManageNFSSnapshotTest, cls).resource_setup()
+        if cls.protocol not in CONF.share.enable_protocols:
+            message = "%s tests are disabled" % cls.protocol
+            raise cls.skipException(message)
+
+        # Create share type
+        cls.st_name = data_utils.rand_name("tempest-manage-st-name")
+        cls.extra_specs = {
+            'storage_protocol': CONF.share.capability_storage_protocol,
+            'driver_handles_share_servers': False,
+            'snapshot_support': six.text_type(
+                CONF.share.capability_snapshot_support),
+        }
+
+        cls.st = cls.create_share_type(
+            name=cls.st_name,
+            cleanup_in_class=True,
+            extra_specs=cls.extra_specs)
+
+        creation_data = {'kwargs': {
+            'share_type_id': cls.st['share_type']['id'],
+            'share_protocol': cls.protocol,
+        }}
+
+        # Data for creating shares
+        data = [creation_data]
+        shares_created = cls.create_shares(data)
+
+        cls.snapshot = None
+        cls.shares = []
+        # Load all share data (host, etc.)
+        for share in shares_created:
+            cls.shares.append(cls.shares_v2_client.get_share(share['id']))
+            # Create snapshot
+            snap_name = data_utils.rand_name("tempest-snapshot-name")
+            snap_desc = data_utils.rand_name(
+                "tempest-snapshot-description")
+            snap = cls.create_snapshot_wait_for_active(
+                share['id'], snap_name, snap_desc)
+            cls.snapshot = cls.shares_v2_client.get_snapshot(snap['id'])
+            # Unmanage snapshot
+            cls.shares_v2_client.unmanage_snapshot(snap['id'])
+            cls.shares_client.wait_for_resource_deletion(
+                snapshot_id=snap['id'])
+
+    def _test_manage(self, snapshot, version=CONF.share.max_api_microversion):
+        name = ("Name for 'managed' snapshot that had ID %s" %
+                snapshot['id'])
+        description = "Description for 'managed' snapshot"
+
+        # Manage snapshot
+        share_id = snapshot['share_id']
+        snapshot = self.shares_v2_client.manage_snapshot(
+            share_id,
+            snapshot['provider_location'],
+            name=name,
+            description=description,
+            driver_options={}
+        )
+
+        # Add managed snapshot to cleanup queue
+        self.method_resources.insert(
+            0, {'type': 'snapshot', 'id': snapshot['id'],
+                'client': self.shares_v2_client})
+
+        # Wait for success
+        self.shares_v2_client.wait_for_snapshot_status(snapshot['id'],
+                                                       'available')
+
+        # Verify data of managed snapshot
+        get_snapshot = self.shares_v2_client.get_snapshot(snapshot['id'])
+        self.assertEqual(name, get_snapshot['name'])
+        self.assertEqual(description, get_snapshot['description'])
+        self.assertEqual(snapshot['share_id'], get_snapshot['share_id'])
+        self.assertEqual(snapshot['provider_location'],
+                         get_snapshot['provider_location'])
+
+        # Delete snapshot
+        self.shares_v2_client.delete_snapshot(get_snapshot['id'])
+        self.shares_client.wait_for_resource_deletion(
+            snapshot_id=get_snapshot['id'])
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.get_snapshot,
+                          get_snapshot['id'])
+
+    @test.attr(type=["gate", "smoke"])
+    def test_manage(self):
+        # Manage snapshot
+        self._test_manage(snapshot=self.snapshot)
+
+
+class ManageCIFSSnapshotTest(ManageNFSSnapshotTest):
+    protocol = 'cifs'
+
+
+class ManageGLUSTERFSSnapshotTest(ManageNFSSnapshotTest):
+    protocol = 'glusterfs'
+
+
+class ManageHDFSSnapshotTest(ManageNFSSnapshotTest):
+    protocol = 'hdfs'
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
new file mode 100644
index 0000000..2aba07c
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_snapshot_manage_negative.py
@@ -0,0 +1,109 @@
+# Copyright 2015 EMC Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import six
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+import testtools
+
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+class ManageNFSSnapshotNegativeTest(base.BaseSharesAdminTest):
+    protocol = 'nfs'
+
+    @classmethod
+    @base.skip_if_microversion_lt("2.12")
+    @testtools.skipIf(
+        CONF.share.multitenancy_enabled,
+        "Only for driver_handles_share_servers = False driver mode.")
+    @testtools.skipUnless(
+        CONF.share.run_manage_unmanage_snapshot_tests,
+        "Manage/unmanage snapshot tests are disabled.")
+    def resource_setup(cls):
+        super(ManageNFSSnapshotNegativeTest, cls).resource_setup()
+        if cls.protocol not in CONF.share.enable_protocols:
+            message = "%s tests are disabled" % cls.protocol
+            raise cls.skipException(message)
+
+        # Create share type
+        cls.st_name = data_utils.rand_name("tempest-manage-st-name")
+        cls.extra_specs = {
+            'storage_protocol': CONF.share.capability_storage_protocol,
+            'driver_handles_share_servers': False,
+            'snapshot_support': six.text_type(
+                CONF.share.capability_snapshot_support),
+        }
+
+        cls.st = cls.create_share_type(
+            name=cls.st_name,
+            cleanup_in_class=True,
+            extra_specs=cls.extra_specs)
+
+        # Create share
+        cls.share = cls.create_share(
+            share_type_id=cls.st['share_type']['id'],
+            share_protocol=cls.protocol
+        )
+
+    @test.attr(type=["gate", "smoke", "negative", ])
+    def test_manage_not_found(self):
+        # Manage snapshot fails
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.manage_snapshot,
+                          'fake-share-id',
+                          'fake-vol-snap-id',
+                          driver_options={})
+
+    @test.attr(type=["gate", "smoke", "negative", ])
+    def test_manage_already_exists(self):
+        # Manage already existing snapshot fails
+
+        # Create snapshot
+        snap = self.create_snapshot_wait_for_active(self.share['id'])
+        get_snap = self.shares_v2_client.get_snapshot(snap['id'])
+        self.assertEqual(self.share['id'], get_snap['share_id'])
+        self.assertIsNotNone(get_snap['provider_location'])
+
+        # Manage snapshot fails
+        self.assertRaises(lib_exc.Conflict,
+                          self.shares_v2_client.manage_snapshot,
+                          self.share['id'],
+                          get_snap['provider_location'],
+                          driver_options={})
+
+        # Delete snapshot
+        self.shares_v2_client.delete_snapshot(get_snap['id'])
+        self.shares_client.wait_for_resource_deletion(
+            snapshot_id=get_snap['id'])
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.get_snapshot,
+                          get_snap['id'])
+
+
+class ManageCIFSSnapshotNegativeTest(ManageNFSSnapshotNegativeTest):
+    protocol = 'cifs'
+
+
+class ManageGLUSTERFSSnapshotNegativeTest(ManageNFSSnapshotNegativeTest):
+    protocol = 'glusterfs'
+
+
+class ManageHDFSSnapshotNegativeTest(ManageNFSSnapshotNegativeTest):
+    protocol = 'hdfs'
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index f9a678d..0395251 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -23,11 +23,12 @@
 from tempest.common import credentials_factory as common_creds
 from tempest.common import dynamic_creds
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
 from tempest import test
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions
 
 from manila_tempest_tests import clients_share as clients
+from manila_tempest_tests.common import constants
 from manila_tempest_tests import share_exceptions
 from manila_tempest_tests import utils
 
@@ -79,13 +80,14 @@
 
 
 skip_if_microversion_not_supported = utils.skip_if_microversion_not_supported
+skip_if_microversion_lt = utils.skip_if_microversion_lt
 
 
 class BaseSharesTest(test.BaseTestCase):
     """Base test case class for all Manila API tests."""
 
     force_tenant_isolation = False
-    protocols = ["nfs", "cifs", "glusterfs", "hdfs"]
+    protocols = ["nfs", "cifs", "glusterfs", "hdfs", "cephfs"]
 
     # Will be cleaned up in resource_cleanup
     class_resources = []
@@ -104,6 +106,13 @@
             raise self.skipException(
                 "Microversion '%s' is not supported." % microversion)
 
+    def skip_if_microversion_lt(self, microversion):
+        if utils.is_microversion_lt(CONF.share.max_api_microversion,
+                                    microversion):
+            raise self.skipException(
+                "Microversion must be greater than or equal to '%s'." %
+                microversion)
+
     @classmethod
     def get_client_with_isolated_creds(cls,
                                        name=None,
@@ -335,11 +344,22 @@
         return share
 
     @classmethod
-    def migrate_share(cls, share_id, dest_host, client=None, **kwargs):
+    def migrate_share(cls, share_id, dest_host, client=None, notify=True,
+                      wait_for_status='migration_success', **kwargs):
         client = client or cls.shares_v2_client
-        client.migrate_share(share_id, dest_host, **kwargs)
-        share = client.wait_for_migration_completed(
-            share_id, dest_host, version=kwargs.get('version'))
+        client.migrate_share(share_id, dest_host, notify, **kwargs)
+        share = client.wait_for_migration_status(
+            share_id, dest_host, wait_for_status,
+            version=kwargs.get('version'))
+        return share
+
+    @classmethod
+    def migration_complete(cls, share_id, dest_host, client=None, **kwargs):
+        client = client or cls.shares_v2_client
+        client.migration_complete(share_id, **kwargs)
+        share = client.wait_for_migration_status(
+            share_id, dest_host, 'migration_success',
+            version=kwargs.get('version'))
         return share
 
     @classmethod
@@ -489,6 +509,56 @@
         return cgsnapshot
 
     @classmethod
+    def get_availability_zones(cls, client=None):
+        """List the availability zones for "manila-share" services
+
+         that are currently in "up" state.
+         """
+        client = client or cls.shares_v2_client
+        cls.services = client.list_services()
+        zones = [service['zone'] for service in cls.services if
+                 service['binary'] == "manila-share" and
+                 service['state'] == 'up']
+        return zones
+
+    @classmethod
+    def create_share_replica(cls, share_id, availability_zone, client=None,
+                             cleanup_in_class=False, cleanup=True):
+        client = client or cls.shares_v2_client
+        replica = client.create_share_replica(share_id, availability_zone)
+        resource = {
+            "type": "share_replica",
+            "id": replica["id"],
+            "client": client,
+            "share_id": share_id,
+        }
+        # NOTE(Yogi1): Cleanup needs to be disabled during promotion tests.
+        if cleanup:
+            if cleanup_in_class:
+                cls.class_resources.insert(0, resource)
+            else:
+                cls.method_resources.insert(0, resource)
+        client.wait_for_share_replica_status(
+            replica["id"], constants.STATUS_AVAILABLE)
+        return replica
+
+    @classmethod
+    def delete_share_replica(cls, replica_id, client=None):
+        client = client or cls.shares_v2_client
+        client.delete_share_replica(replica_id)
+        client.wait_for_resource_deletion(replica_id=replica_id)
+
+    @classmethod
+    def promote_share_replica(cls, replica_id, client=None):
+        client = client or cls.shares_v2_client
+        replica = client.promote_share_replica(replica_id)
+        client.wait_for_share_replica_status(
+            replica["id"],
+            constants.REPLICATION_STATE_ACTIVE,
+            status_attr="replica_state")
+        return replica
+
+    @classmethod
     def create_share_network(cls, client=None,
                              cleanup_in_class=False, **kwargs):
         if client is None:
@@ -613,6 +683,9 @@
                     elif res["type"] is "cgsnapshot":
                         client.delete_cgsnapshot(res_id)
                         client.wait_for_resource_deletion(cgsnapshot_id=res_id)
+                    elif res["type"] is "share_replica":
+                        client.delete_share_replica(res_id)
+                        client.wait_for_resource_deletion(replica_id=res_id)
                     else:
                         LOG.warning("Provided unsupported resource type for "
                                     "cleanup '%s'. Skipping." % res["type"])
diff --git a/manila_tempest_tests/tests/api/test_availability_zones_negative.py b/manila_tempest_tests/tests/api/test_availability_zones_negative.py
index 0a562c6..ffe4096 100644
--- a/manila_tempest_tests/tests/api/test_availability_zones_negative.py
+++ b/manila_tempest_tests/tests/api/test_availability_zones_negative.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 
 from manila_tempest_tests.tests.api import base
 
diff --git a/manila_tempest_tests/tests/api/test_consistency_group_actions.py b/manila_tempest_tests/tests/api/test_consistency_group_actions.py
index a932fdf..59e07be 100644
--- a/manila_tempest_tests/tests/api/test_consistency_group_actions.py
+++ b/manila_tempest_tests/tests/api/test_consistency_group_actions.py
@@ -15,8 +15,8 @@
 #    under the License.
 
 from tempest import config
+from tempest.lib.common.utils import data_utils
 from tempest import test
-from tempest_lib.common.utils import data_utils
 import testtools
 
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/test_consistency_groups.py b/manila_tempest_tests/tests/api/test_consistency_groups.py
index 33ea334..bebd88f 100644
--- a/manila_tempest_tests/tests/api/test_consistency_groups.py
+++ b/manila_tempest_tests/tests/api/test_consistency_groups.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 import testtools  # noqa
 
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/test_consistency_groups_negative.py b/manila_tempest_tests/tests/api/test_consistency_groups_negative.py
index 34c0a6d..9e9c696 100644
--- a/manila_tempest_tests/tests/api/test_consistency_groups_negative.py
+++ b/manila_tempest_tests/tests/api/test_consistency_groups_negative.py
@@ -14,9 +14,9 @@
 #    under the License.
 
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions as lib_exc
 import testtools
 
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/test_metadata_negative.py b/manila_tempest_tests/tests/api/test_metadata_negative.py
index 7401a41..4da60a6 100644
--- a/manila_tempest_tests/tests/api/test_metadata_negative.py
+++ b/manila_tempest_tests/tests/api/test_metadata_negative.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 
 from manila_tempest_tests.tests.api import base
 
diff --git a/manila_tempest_tests/tests/api/test_quotas.py b/manila_tempest_tests/tests/api/test_quotas.py
index da6dcce..77eae42 100644
--- a/manila_tempest_tests/tests/api/test_quotas.py
+++ b/manila_tempest_tests/tests/api/test_quotas.py
@@ -14,16 +14,22 @@
 #    under the License.
 
 import ddt
-from tempest import test  # noqa
+from tempest import config
+from tempest import test
 
 from manila_tempest_tests.tests.api import base
 
+CONF = config.CONF
+
 
 @ddt.data
 class SharesQuotasTest(base.BaseSharesTest):
 
     @classmethod
     def resource_setup(cls):
+        if not CONF.share.run_quota_tests:
+            msg = "Quota tests are disabled."
+            raise cls.skipException(msg)
         super(SharesQuotasTest, cls).resource_setup()
         cls.user_id = cls.shares_v2_client.user_id
         cls.tenant_id = cls.shares_v2_client.tenant_id
diff --git a/manila_tempest_tests/tests/api/test_quotas_negative.py b/manila_tempest_tests/tests/api/test_quotas_negative.py
index e2d2c37..bf64290 100644
--- a/manila_tempest_tests/tests/api/test_quotas_negative.py
+++ b/manila_tempest_tests/tests/api/test_quotas_negative.py
@@ -14,15 +14,25 @@
 #    under the License.
 
 import ddt
+from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 
 from manila_tempest_tests.tests.api import base
 
+CONF = config.CONF
+
 
 @ddt.ddt
 class SharesQuotasNegativeTest(base.BaseSharesTest):
 
+    @classmethod
+    def resource_setup(cls):
+        if not CONF.share.run_quota_tests:
+            msg = "Quota tests are disabled."
+            raise cls.skipException(msg)
+        super(SharesQuotasNegativeTest, cls).resource_setup()
+
     @test.attr(type=["gate", "smoke", "negative"])
     def test_get_quotas_with_empty_tenant_id(self):
         self.assertRaises(lib_exc.NotFound,
diff --git a/manila_tempest_tests/tests/api/test_replication.py b/manila_tempest_tests/tests/api/test_replication.py
new file mode 100644
index 0000000..4f4268c
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_replication.py
@@ -0,0 +1,406 @@
+# Copyright 2015 Yogesh Kshirsagar
+# 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 import test
+import testtools
+
+from manila_tempest_tests import clients_share as clients
+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
+_MIN_SUPPORTED_MICROVERSION = '2.11'
+SUMMARY_KEYS = ['share_id', 'id', 'replica_state', 'status']
+DETAIL_KEYS = SUMMARY_KEYS + ['availability_zone', 'host', 'updated_at',
+                              'share_network_id', 'created_at']
+
+
+@testtools.skipUnless(CONF.share.run_replication_tests,
+                      'Replication tests are disabled.')
+@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
+class ReplicationTest(base.BaseSharesTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ReplicationTest, cls).resource_setup()
+        # Create share_type
+        name = data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX)
+        cls.admin_client = clients.AdminManager().shares_v2_client
+        cls.replication_type = CONF.share.backend_replication_type
+
+        if cls.replication_type not in constants.REPLICATION_TYPE_CHOICES:
+            raise share_exceptions.ShareReplicationTypeException(
+                replication_type=cls.replication_type
+            )
+        cls.zones = cls.get_availability_zones(client=cls.admin_client)
+        cls.share_zone = cls.zones[0]
+        cls.replica_zone = cls.zones[-1]
+
+        cls.extra_specs = cls.add_required_extra_specs_to_dict(
+            {"replication_type": cls.replication_type})
+        share_type = cls.create_share_type(
+            name,
+            extra_specs=cls.extra_specs,
+            client=cls.admin_client)
+        cls.share_type = share_type["share_type"]
+        # Create share with above share_type
+        cls.creation_data = {'kwargs': {
+            'share_type_id': cls.share_type['id'],
+            'availability_zone': cls.share_zone,
+        }}
+
+        # Data for creating shares in parallel
+        data = [cls.creation_data, cls.creation_data]
+        cls.shares = cls.create_shares(data)
+        cls.shares = [cls.shares_v2_client.get_share(s['id']) for s in
+                      cls.shares]
+        cls.instance_id1 = cls._get_instance(cls.shares[0])
+        cls.instance_id2 = cls._get_instance(cls.shares[1])
+
+        cls.access_type = "ip"
+        cls.access_to = utils.rand_ip()
+
+    @classmethod
+    def _get_instance(cls, share):
+        share_instances = cls.admin_client.get_instances_of_share(share["id"])
+        return share_instances[0]["id"]
+
+    def _verify_create_replica(self):
+        # Create the replica
+        share_replica = self.create_share_replica(self.shares[0]["id"],
+                                                  self.replica_zone,
+                                                  cleanup_in_class=False)
+        share_replicas = self.shares_v2_client.list_share_replicas(
+            share_id=self.shares[0]["id"])
+        # Ensure replica is created successfully.
+        replica_ids = [replica["id"] for replica in share_replicas]
+        self.assertIn(share_replica["id"], replica_ids)
+        return share_replica
+
+    def _verify_active_replica_count(self, share_id):
+        # List replicas
+        replica_list = self.shares_v2_client.list_share_replicas(
+            share_id=share_id)
+
+        # Check if there is only 1 'active' replica before promotion.
+        active_replicas = self._filter_replica_list(
+            replica_list, constants.REPLICATION_STATE_ACTIVE)
+        self.assertEqual(1, len(active_replicas))
+
+    def _filter_replica_list(self, replica_list, r_state):
+        # Iterate through replica list to filter based on replica_state
+        return [replica for replica in replica_list
+                if replica['replica_state'] == r_state]
+
+    def _get_pools_for_replication_domain(self):
+        # Get the list of pools for the replication domain
+        pools = self.admin_client.list_pools(detail=True)['pools']
+        instance_host = self.shares[0]['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'][
+            'replication_domain'] == rep_domain]
+        return rep_domain, pools_in_rep_domain
+
+    def _verify_config_and_set_access_rule_data(self):
+        """Verify the access rule configuration is enabled for NFS.
+
+        Set the data after verification.
+        """
+        protocol = self.shares_v2_client.share_protocol
+
+        # TODO(Yogi1): Add access rules for other protocols.
+        if not ((protocol.lower() == 'nfs') and
+                (protocol in CONF.share.enable_ip_rules_for_protocols) and
+                CONF.share.enable_ip_rules_for_protocols):
+            message = "IP access rules are not supported for this protocol."
+            raise self.skipException(message)
+
+        access_type = "ip"
+        access_to = utils.rand_ip()
+
+        return access_type, access_to
+
+    @test.attr(type=["gate", ])
+    def test_add_delete_share_replica(self):
+        # Create the replica
+        share_replica = self._verify_create_replica()
+
+        # Delete the replica
+        self.delete_share_replica(share_replica["id"])
+
+    @test.attr(type=["gate", ])
+    def test_add_access_rule_create_replica_delete_rule(self):
+        # Add access rule to the share
+        access_type, access_to = self._verify_config_and_set_access_rule_data()
+        rule = self.shares_v2_client.create_access_rule(
+            self.shares[0]["id"], access_type, access_to, 'ro')
+        self.shares_v2_client.wait_for_access_rule_status(
+            self.shares[0]["id"], rule["id"], constants.RULE_STATE_ACTIVE)
+
+        # Create the replica
+        self._verify_create_replica()
+
+        # Verify access rule transitions to 'active' state.
+        self.shares_v2_client.wait_for_access_rule_status(
+            self.shares[0]["id"], rule["id"], constants.RULE_STATE_ACTIVE)
+
+        # Delete rule and wait for deletion
+        self.shares_v2_client.delete_access_rule(self.shares[0]["id"],
+                                                 rule["id"])
+        self.shares_v2_client.wait_for_resource_deletion(
+            rule_id=rule["id"], share_id=self.shares[0]['id'])
+
+    @test.attr(type=["gate", ])
+    def test_create_replica_add_access_rule_delete_replica(self):
+        access_type, access_to = self._verify_config_and_set_access_rule_data()
+        # Create the replica
+        share_replica = self._verify_create_replica()
+
+        # Add access rule
+        rule = self.shares_v2_client.create_access_rule(
+            self.shares[0]["id"], access_type, access_to, 'ro')
+        self.shares_v2_client.wait_for_access_rule_status(
+            self.shares[0]["id"], rule["id"], constants.RULE_STATE_ACTIVE)
+
+        # Delete the replica
+        self.delete_share_replica(share_replica["id"])
+
+    @test.attr(type=["gate", ])
+    def test_add_multiple_share_replicas(self):
+        rep_domain, pools = self._get_pools_for_replication_domain()
+        if len(pools) < 3:
+            msg = ("Replication domain %(domain)s has only %(count)s pools. "
+                   "Need at least 3 pools to run this test." %
+                   {"domain": rep_domain, "count": len(pools)})
+            raise self.skipException(msg)
+        # Add the replicas
+        share_replica1 = self.create_share_replica(self.shares[0]["id"],
+                                                   self.replica_zone,
+                                                   cleanup_in_class=False)
+        share_replica2 = self.create_share_replica(self.shares[0]["id"],
+                                                   self.replica_zone,
+                                                   cleanup_in_class=False)
+        self.shares_v2_client.get_share_replica(share_replica2['id'])
+
+        share_replicas = self.shares_v2_client.list_share_replicas(
+            share_id=self.shares[0]["id"])
+        replica_host_set = {r['host'] for r in share_replicas}
+
+        # Assert that replicas are created on different pools.
+        msg = "More than one replica is created on the same pool."
+        self.assertEqual(3, len(replica_host_set), msg)
+        # Verify replicas are in the replica list
+        replica_ids = [replica["id"] for replica in share_replicas]
+        self.assertIn(share_replica1["id"], replica_ids)
+        self.assertIn(share_replica2["id"], replica_ids)
+
+    @test.attr(type=["gate", ])
+    def test_promote_in_sync_share_replica(self):
+        # Test promote 'in_sync' share_replica to 'active' state
+        if (self.replication_type
+                not in constants.REPLICATION_PROMOTION_CHOICES):
+            msg = "Option backend_replication_type should be one of (%s)!"
+            raise self.skipException(
+                msg % ','.join(constants.REPLICATION_PROMOTION_CHOICES))
+        share = self.create_shares([self.creation_data])[0]
+        original_replica = self.shares_v2_client.list_share_replicas(
+            share["id"])[0]
+        # NOTE(Yogi1): Cleanup needs to be disabled for replica that is
+        # being promoted since it will become the 'primary'/'active' replica.
+        replica = self.create_share_replica(share["id"], self.replica_zone,
+                                            cleanup=False)
+        # Wait for replica state to update after creation
+        self.shares_v2_client.wait_for_share_replica_status(
+            replica['id'], constants.REPLICATION_STATE_IN_SYNC,
+            status_attr='replica_state')
+        # Promote the first in_sync replica to active state
+        promoted_replica = self.promote_share_replica(replica['id'])
+        # Delete the demoted replica so promoted replica can be cleaned
+        # during the cleanup of the share.
+        self.addCleanup(self.delete_share_replica, original_replica['id'])
+        self._verify_active_replica_count(share["id"])
+        # Verify the replica_state for promoted replica
+        promoted_replica = self.shares_v2_client.get_share_replica(
+            promoted_replica["id"])
+        self.assertEqual(constants.REPLICATION_STATE_ACTIVE,
+                         promoted_replica["replica_state"])
+
+    @test.attr(type=["gate", ])
+    def test_promote_and_promote_back(self):
+        # Test promote back and forth between 2 share replicas
+        if (self.replication_type
+                not in constants.REPLICATION_PROMOTION_CHOICES):
+            msg = "Option backend_replication_type should be one of (%s)!"
+            raise self.skipException(
+                msg % ','.join(constants.REPLICATION_PROMOTION_CHOICES))
+
+        # Create a new share
+        share = self.create_shares([self.creation_data])[0]
+
+        # Discover the original replica
+        initial_replicas = self.shares_v2_client.list_share_replicas(
+            share_id=share['id'])
+        self.assertEqual(1, len(initial_replicas),
+                         '%s replicas initially created for share %s' %
+                         (len(initial_replicas), share['id']))
+        original_replica = initial_replicas[0]
+
+        # Create a new replica
+        new_replica = self.create_share_replica(share["id"],
+                                                self.replica_zone,
+                                                cleanup_in_class=False)
+        self.shares_v2_client.wait_for_share_replica_status(
+            new_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
+            status_attr='replica_state')
+
+        # Promote the new replica to active and verify the replica states
+        self.promote_share_replica(new_replica['id'])
+        self._verify_active_replica_count(share["id"])
+        self.shares_v2_client.wait_for_share_replica_status(
+            original_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
+            status_attr='replica_state')
+
+        # Promote the original replica back to active
+        self.promote_share_replica(original_replica['id'])
+        self._verify_active_replica_count(share["id"])
+        self.shares_v2_client.wait_for_share_replica_status(
+            new_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
+            status_attr='replica_state')
+
+    @test.attr(type=["gate", ])
+    def test_active_replication_state(self):
+        # Verify the replica_state of first instance is set to active.
+        replica = self.shares_v2_client.get_share_replica(self.instance_id1)
+        self.assertEqual(
+            constants.REPLICATION_STATE_ACTIVE, replica['replica_state'])
+
+
+@testtools.skipUnless(CONF.share.run_replication_tests,
+                      'Replication tests are disabled.')
+@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
+class ReplicationActionsTest(base.BaseSharesTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ReplicationActionsTest, cls).resource_setup()
+        # Create share_type
+        name = data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX)
+        cls.admin_client = clients.AdminManager().shares_v2_client
+        cls.replication_type = CONF.share.backend_replication_type
+
+        if cls.replication_type not in constants.REPLICATION_TYPE_CHOICES:
+            raise share_exceptions.ShareReplicationTypeException(
+                replication_type=cls.replication_type
+            )
+        cls.zones = cls.get_availability_zones(client=cls.admin_client)
+        cls.share_zone = cls.zones[0]
+        cls.replica_zone = cls.zones[-1]
+
+        cls.extra_specs = cls.add_required_extra_specs_to_dict(
+            {"replication_type": cls.replication_type})
+        share_type = cls.create_share_type(
+            name,
+            extra_specs=cls.extra_specs,
+            client=cls.admin_client)
+        cls.share_type = share_type["share_type"]
+        # Create share with above share_type
+        cls.creation_data = {'kwargs': {
+            'share_type_id': cls.share_type['id'],
+            'availability_zone': cls.share_zone,
+        }}
+
+        # Data for creating shares in parallel
+        data = [cls.creation_data, cls.creation_data]
+        cls.shares = cls.create_shares(data)
+        cls.shares = [cls.shares_v2_client.get_share(s['id']) for s in
+                      cls.shares]
+        cls.instance_id1 = cls._get_instance(cls.shares[0])
+        cls.instance_id2 = cls._get_instance(cls.shares[1])
+
+        # Create replicas to 2 shares
+        cls.replica1 = cls.create_share_replica(cls.shares[0]["id"],
+                                                cls.replica_zone,
+                                                cleanup_in_class=True)
+        cls.replica2 = cls.create_share_replica(cls.shares[1]["id"],
+                                                cls.replica_zone,
+                                                cleanup_in_class=True)
+
+    @classmethod
+    def _get_instance(cls, share):
+        share_instances = cls.admin_client.get_instances_of_share(share["id"])
+        return share_instances[0]["id"]
+
+    def _validate_replica_list(self, replica_list, detail=True):
+        # Verify keys
+        if detail:
+            keys = DETAIL_KEYS
+        else:
+            keys = SUMMARY_KEYS
+        for replica in replica_list:
+            self.assertEqual(sorted(keys), sorted(replica.keys()))
+            # Check for duplicates
+            replica_id_list = [sr["id"] for sr in replica_list
+                               if sr["id"] == replica["id"]]
+            msg = "Replica %s appears %s times in replica list." % (
+                replica['id'], len(replica_id_list))
+            self.assertEqual(1, len(replica_id_list), msg)
+
+    @test.attr(type=["gate", ])
+    def test_show_share_replica(self):
+        replica = self.shares_v2_client.get_share_replica(self.replica1["id"])
+
+        actual_keys = sorted(list(replica.keys()))
+        detail_keys = sorted(DETAIL_KEYS)
+        self.assertEqual(detail_keys, actual_keys,
+                         'Share Replica %s has incorrect keys; '
+                         'expected %s, got %s.' % (replica["id"],
+                                                   detail_keys, actual_keys))
+
+    @test.attr(type=["gate", ])
+    def test_detail_list_share_replicas_for_share(self):
+        # List replicas for share
+        replica_list = self.shares_v2_client.list_share_replicas(
+            share_id=self.shares[0]["id"])
+        replica_ids_list = [rep['id'] for rep in replica_list]
+        self.assertIn(self.replica1['id'], replica_ids_list,
+                      'Replica %s was not returned in the list of replicas: %s'
+                      % (self.replica1['id'], replica_list))
+        # Verify keys
+        self._validate_replica_list(replica_list)
+
+    @test.attr(type=["gate", ])
+    def test_detail_list_share_replicas_for_all_shares(self):
+        # List replicas for all available shares
+        replica_list = self.shares_v2_client.list_share_replicas()
+        replica_ids_list = [rep['id'] for rep in replica_list]
+        for replica in [self.replica1, self.replica2]:
+            self.assertIn(replica['id'], replica_ids_list,
+                          'Replica %s was not returned in the list of '
+                          'replicas: %s' % (replica['id'], replica_list))
+        # Verify keys
+        self._validate_replica_list(replica_list)
+
+    @test.attr(type=["gate", ])
+    def test_summary_list_share_replicas_for_all_shares(self):
+        # List replicas
+        replica_list = self.shares_v2_client.list_share_replicas_summary()
+
+        # Verify keys
+        self._validate_replica_list(replica_list, detail=False)
diff --git a/manila_tempest_tests/tests/api/test_replication_negative.py b/manila_tempest_tests/tests/api/test_replication_negative.py
new file mode 100644
index 0000000..2587dc0
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_replication_negative.py
@@ -0,0 +1,169 @@
+# Copyright 2015 Yogesh Kshirsagar
+# 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 exceptions as lib_exc
+from tempest import test
+import testtools
+
+from manila_tempest_tests import clients_share as clients
+from manila_tempest_tests.common import constants
+from manila_tempest_tests import share_exceptions
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+_MIN_SUPPORTED_MICROVERSION = '2.11'
+
+
+@testtools.skipUnless(CONF.share.run_replication_tests,
+                      'Replication tests are disabled.')
+@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
+class ReplicationNegativeTest(base.BaseSharesTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ReplicationNegativeTest, cls).resource_setup()
+        # Create share_type
+        name = data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX)
+        cls.admin_client = clients.AdminManager().shares_v2_client
+        cls.replication_type = CONF.share.backend_replication_type
+
+        if cls.replication_type not in constants.REPLICATION_TYPE_CHOICES:
+            raise share_exceptions.ShareReplicationTypeException(
+                replication_type=cls.replication_type
+            )
+        cls.zones = cls.get_availability_zones(client=cls.admin_client)
+        cls.share_zone = cls.zones[0]
+        cls.replica_zone = cls.zones[-1]
+
+        cls.extra_specs = cls.add_required_extra_specs_to_dict(
+            {"replication_type": cls.replication_type})
+        share_type = cls.create_share_type(
+            name,
+            extra_specs=cls.extra_specs,
+            client=cls.admin_client)
+        cls.share_type = share_type["share_type"]
+        # Create share with above share_type
+        cls.share1, cls.instance_id1 = cls._create_share_get_instance()
+
+    @classmethod
+    def _create_share_get_instance(cls):
+        share = cls.create_share(share_type_id=cls.share_type["id"],
+                                 availability_zone=cls.share_zone,)
+        share_instances = cls.admin_client.get_instances_of_share(
+            share["id"], version=_MIN_SUPPORTED_MICROVERSION
+        )
+        instance_id = share_instances[0]["id"]
+        return share, instance_id
+
+    def _is_replication_type_promotable(self):
+        if (self.replication_type
+                not in constants.REPLICATION_PROMOTION_CHOICES):
+            msg = "Option backend_replication_type should be one of (%s)!"
+            raise self.skipException(
+                msg % ','.join(constants.REPLICATION_PROMOTION_CHOICES))
+
+    @test.attr(type=["gate", "negative", ])
+    def test_try_add_replica_to_share_with_no_replication_share_type(self):
+        # Create share without replication type
+        share = self.create_share()
+        self.assertRaises(lib_exc.BadRequest,
+                          self.create_share_replica,
+                          share['id'],
+                          self.replica_zone)
+
+    @test.attr(type=["gate", "negative", ])
+    def test_add_replica_to_share_with_error_state(self):
+        # Set "error" state
+        self.admin_client.reset_state(
+            self.share1['id'], constants.STATUS_ERROR)
+        self.addCleanup(self.admin_client.reset_state,
+                        self.share1['id'],
+                        constants.STATUS_AVAILABLE)
+        self.assertRaises(lib_exc.BadRequest,
+                          self.create_share_replica,
+                          self.share1['id'],
+                          self.replica_zone)
+
+    @test.attr(type=["gate", "negative", ])
+    def test_get_replica_by_nonexistent_id(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.get_share_replica,
+                          data_utils.rand_uuid())
+
+    @test.attr(type=["gate", "negative", ])
+    def test_try_delete_replica_by_nonexistent_id(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.delete_share_replica,
+                          data_utils.rand_uuid())
+
+    @test.attr(type=["gate", "negative", ])
+    def test_try_delete_last_active_replica(self):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.delete_share_replica,
+                          self.instance_id1)
+
+    @test.attr(type=["gate", "negative", ])
+    def test_try_delete_share_having_replica(self):
+        self.create_share_replica(self.share1["id"], self.replica_zone,
+                                  cleanup_in_class=False)
+        self.assertRaises(lib_exc.Conflict,
+                          self.shares_v2_client.delete_share,
+                          self.share1["id"])
+
+    @test.attr(type=["negative", "gate", ])
+    def test_promote_out_of_sync_share_replica(self):
+        # Test promoting an out_of_sync share_replica to active state
+        self._is_replication_type_promotable()
+        share, instance_id = self._create_share_get_instance()
+        replica = self.create_share_replica(share["id"], self.replica_zone,
+                                            cleanup_in_class=False)
+        # Set replica state to out of sync
+        self.admin_client.reset_share_replica_state(
+            replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC)
+        self.shares_v2_client.wait_for_share_replica_status(
+            replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC,
+            status_attr='replica_state')
+        # Try promoting the first out_of_sync replica to active state
+        self.assertRaises(lib_exc.Forbidden,
+                          self.shares_v2_client.promote_share_replica,
+                          replica['id'])
+
+    @test.attr(type=["negative", "gate", ])
+    def test_promote_active_share_replica(self):
+        # Test promote active share_replica
+        self._is_replication_type_promotable()
+
+        # Try promoting the active replica
+        self.shares_v2_client.promote_share_replica(self.instance_id1,
+                                                    expected_status=200)
+
+    @test.attr(type=["negative", "gate", ])
+    def test_promote_share_replica_for_writable_share_type(self):
+        # Test promote active share_replica for writable share
+        if self.replication_type != "writable":
+            raise self.skipException("Option backend_replication_type "
+                                     "should be writable!")
+        share, instance_id = self._create_share_get_instance()
+        replica = self.create_share_replica(share["id"], self.replica_zone,
+                                            cleanup_in_class=False)
+        # By default, 'writable' replica is expected to be in active state
+        self.shares_v2_client.wait_for_share_replica_status(
+            replica["id"], constants.REPLICATION_STATE_ACTIVE,
+            status_attr='replica_state')
+
+        # Try promoting the replica
+        self.shares_v2_client.promote_share_replica(replica['id'])
diff --git a/manila_tempest_tests/tests/api/test_rules.py b/manila_tempest_tests/tests/api/test_rules.py
index 0b0bc08..fce3e44 100644
--- a/manila_tempest_tests/tests/api/test_rules.py
+++ b/manila_tempest_tests/tests/api/test_rules.py
@@ -15,8 +15,8 @@
 
 import ddt
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 import testtools
 
 from manila_tempest_tests.tests.api import base
@@ -359,6 +359,41 @@
 
 
 @ddt.ddt
+class ShareCephxRulesForCephFSTest(base.BaseSharesTest):
+    protocol = "cephfs"
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareCephxRulesForCephFSTest, cls).resource_setup()
+        if (cls.protocol not in CONF.share.enable_protocols or
+                cls.protocol not in
+                CONF.share.enable_cephx_rules_for_protocols):
+            msg = ("Cephx rule tests for %s protocol are disabled." %
+                   cls.protocol)
+            raise cls.skipException(msg)
+        cls.share = cls.create_share(cls.protocol)
+        cls.access_type = "cephx"
+        # Provide access to a client identified by a cephx auth id.
+        cls.access_to = "bob"
+
+    @test.attr(type=["gate", ])
+    @ddt.data("alice", "alice_bob", "alice bob")
+    def test_create_delete_cephx_rule(self, access_to):
+        rule = self.shares_v2_client.create_access_rule(
+            self.share["id"], self.access_type, access_to)
+
+        self.assertEqual('rw', rule['access_level'])
+        for key in ('deleted', 'deleted_at', 'instance_mappings'):
+            self.assertNotIn(key, rule.keys())
+        self.shares_v2_client.wait_for_access_rule_status(
+            self.share["id"], rule["id"], "active")
+
+        self.shares_v2_client.delete_access_rule(self.share["id"], rule["id"])
+        self.shares_v2_client.wait_for_resource_deletion(
+            rule_id=rule["id"], share_id=self.share['id'])
+
+
+@ddt.ddt
 class ShareRulesTest(base.BaseSharesTest):
 
     @classmethod
@@ -369,6 +404,8 @@
                 any(p in CONF.share.enable_user_rules_for_protocols
                     for p in cls.protocols) or
                 any(p in CONF.share.enable_cert_rules_for_protocols
+                    for p in cls.protocols) or
+                any(p in CONF.share.enable_cephx_rules_for_protocols
                     for p in cls.protocols)):
             cls.message = "Rule tests are disabled"
             raise cls.skipException(cls.message)
@@ -384,12 +421,21 @@
             cls.protocol = CONF.share.enable_cert_rules_for_protocols[0]
             cls.access_type = "cert"
             cls.access_to = "client3.com"
+        elif CONF.share.enable_cephx_rules_for_protocols:
+            cls.protocol = CONF.share.enable_cephx_rules_for_protocols[0]
+            cls.access_type = "cephx"
+            cls.access_to = "alice"
         cls.shares_v2_client.share_protocol = cls.protocol
         cls.share = cls.create_share()
 
     @test.attr(type=["gate", ])
     @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
     def test_list_access_rules(self, version):
+        if (utils.is_microversion_lt(version, '2.13') and
+                CONF.share.enable_cephx_rules_for_protocols):
+            msg = ("API version %s does not support cephx access type, "
+                   "need version greater than 2.13." % version)
+            raise self.skipException(msg)
 
         # create rule
         if utils.is_microversion_eq(version, '1.0'):
@@ -447,6 +493,11 @@
     @test.attr(type=["gate", ])
     @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
     def test_access_rules_deleted_if_share_deleted(self, version):
+        if (utils.is_microversion_lt(version, '2.13') and
+                CONF.share.enable_cephx_rules_for_protocols):
+            msg = ("API version %s does not support cephx access type, "
+                   "need version greater than 2.13." % version)
+            raise self.skipException(msg)
 
         # create share
         share = self.create_share()
diff --git a/manila_tempest_tests/tests/api/test_rules_negative.py b/manila_tempest_tests/tests/api/test_rules_negative.py
index 47f5a52..a35c18a 100644
--- a/manila_tempest_tests/tests/api/test_rules_negative.py
+++ b/manila_tempest_tests/tests/api/test_rules_negative.py
@@ -15,10 +15,11 @@
 
 import ddt
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 import testtools
 
+from manila_tempest_tests import share_exceptions
 from manila_tempest_tests.tests.api import base
 from manila_tempest_tests import utils
 
@@ -317,6 +318,48 @@
 
 
 @ddt.ddt
+class ShareCephxRulesForCephFSNegativeTest(base.BaseSharesTest):
+    protocol = "cephfs"
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareCephxRulesForCephFSNegativeTest, cls).resource_setup()
+        if not (cls.protocol in CONF.share.enable_protocols and
+                cls.protocol in CONF.share.enable_cephx_rules_for_protocols):
+            msg = ("CEPHX rule tests for %s protocol are disabled" %
+                   cls.protocol)
+            raise cls.skipException(msg)
+        # create share
+        cls.share = cls.create_share(cls.protocol)
+        cls.access_type = "cephx"
+        cls.access_to = "david"
+
+    @test.attr(type=["negative", "gate", ])
+    @ddt.data('jane.doe', u"bj\u00F6rn")
+    def test_create_access_rule_cephx_with_invalid_cephx_id(self, access_to):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.create_access_rule,
+                          self.share["id"], self.access_type, access_to)
+
+    @test.attr(type=["negative", "gate", ])
+    def test_create_access_rule_cephx_with_wrong_level(self):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.create_access_rule,
+                          self.share["id"], self.access_type, self.access_to,
+                          access_level="su")
+
+    @test.attr(type=["negative", "gate", ])
+    def test_create_access_rule_cephx_with_unsupported_access_level_ro(self):
+        rule = self.shares_v2_client.create_access_rule(
+            self.share["id"], self.access_type, self.access_to,
+            access_level="ro")
+        self.assertRaises(
+            share_exceptions.AccessRuleBuildErrorException,
+            self.shares_client.wait_for_access_rule_status,
+            self.share['id'], rule['id'], "active")
+
+
+@ddt.ddt
 class ShareRulesNegativeTest(base.BaseSharesTest):
     # Tests independent from rule type and share protocol
 
@@ -328,6 +371,8 @@
                 any(p in CONF.share.enable_user_rules_for_protocols
                     for p in cls.protocols) or
                 any(p in CONF.share.enable_cert_rules_for_protocols
+                    for p in cls.protocols) or
+                any(p in CONF.share.enable_cephx_rules_for_protocols
                     for p in cls.protocols)):
             cls.message = "Rule tests are disabled"
             raise cls.skipException(cls.message)
@@ -337,9 +382,21 @@
             # create snapshot
             cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
 
+    def skip_if_cephx_access_type_not_supported_by_client(self, client):
+        if client == 'shares_client':
+            version = '1.0'
+        else:
+            version = LATEST_MICROVERSION
+        if (CONF.share.enable_cephx_rules_for_protocols and
+                utils.is_microversion_lt(version, '2.13')):
+            msg = ("API version %s does not support cephx access type, "
+                   "need version greater than 2.13." % version)
+            raise self.skipException(msg)
+
     @test.attr(type=["negative", "gate", ])
     @ddt.data('shares_client', 'shares_v2_client')
     def test_delete_access_rule_with_wrong_id(self, client_name):
+        self.skip_if_cephx_access_type_not_supported_by_client(client_name)
         self.assertRaises(lib_exc.NotFound,
                           getattr(self, client_name).delete_access_rule,
                           self.share["id"], "wrong_rule_id")
@@ -347,6 +404,7 @@
     @test.attr(type=["negative", "gate", ])
     @ddt.data('shares_client', 'shares_v2_client')
     def test_create_access_rule_ip_with_wrong_type(self, client_name):
+        self.skip_if_cephx_access_type_not_supported_by_client(client_name)
         self.assertRaises(lib_exc.BadRequest,
                           getattr(self, client_name).create_access_rule,
                           self.share["id"], "wrong_type", "1.2.3.4")
@@ -354,6 +412,7 @@
     @test.attr(type=["negative", "gate", ])
     @ddt.data('shares_client', 'shares_v2_client')
     def test_create_access_rule_ip_with_wrong_share_id(self, client_name):
+        self.skip_if_cephx_access_type_not_supported_by_client(client_name)
         self.assertRaises(lib_exc.NotFound,
                           getattr(self, client_name).create_access_rule,
                           "wrong_share_id")
@@ -363,6 +422,7 @@
     @testtools.skipUnless(CONF.share.run_snapshot_tests,
                           "Snapshot tests are disabled.")
     def test_create_access_rule_ip_to_snapshot(self, client_name):
+        self.skip_if_cephx_access_type_not_supported_by_client(client_name)
         self.assertRaises(lib_exc.NotFound,
                           getattr(self, client_name).create_access_rule,
                           self.snap["id"])
diff --git a/manila_tempest_tests/tests/api/test_scheduler_stats_negative.py b/manila_tempest_tests/tests/api/test_scheduler_stats_negative.py
index 9be8f64..dd7a498 100644
--- a/manila_tempest_tests/tests/api/test_scheduler_stats_negative.py
+++ b/manila_tempest_tests/tests/api/test_scheduler_stats_negative.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 
 from manila_tempest_tests.tests.api import base
 
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 834deb5..6a5f18f 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
@@ -16,8 +16,8 @@
 from oslo_log import log  # noqa
 import six  # noqa
 from tempest import config  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 import testtools  # noqa
 
 from manila_tempest_tests.tests.api import base
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 5908f81..80139b8 100644
--- a/manila_tempest_tests/tests/api/test_security_services_negative.py
+++ b/manila_tempest_tests/tests/api/test_security_services_negative.py
@@ -16,8 +16,8 @@
 from oslo_log import log  # noqa
 import six  # noqa
 from tempest import config  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 import testtools  # noqa
 
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/test_share_networks_negative.py b/manila_tempest_tests/tests/api/test_share_networks_negative.py
index d0036c3..d337d4a 100644
--- a/manila_tempest_tests/tests/api/test_share_networks_negative.py
+++ b/manila_tempest_tests/tests/api/test_share_networks_negative.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 import testtools  # noqa
 
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/test_share_types_negative.py b/manila_tempest_tests/tests/api/test_share_types_negative.py
index 4d2c189..9be479b 100644
--- a/manila_tempest_tests/tests/api/test_share_types_negative.py
+++ b/manila_tempest_tests/tests/api/test_share_types_negative.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.common.utils import data_utils  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib.common.utils import data_utils  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 
 from manila_tempest_tests import clients_share as clients
 from manila_tempest_tests.tests.api import base
diff --git a/manila_tempest_tests/tests/api/test_shares.py b/manila_tempest_tests/tests/api/test_shares.py
index 46d1558..2057d22 100644
--- a/manila_tempest_tests/tests/api/test_shares.py
+++ b/manila_tempest_tests/tests/api/test_shares.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 import testtools
 
 from manila_tempest_tests.tests.api import base
@@ -187,3 +187,8 @@
 class SharesHDFSTest(SharesNFSTest):
     """Covers share functionality that is related to HDFS share type."""
     protocol = "hdfs"
+
+
+class SharesCephFSTest(SharesNFSTest):
+    """Covers share functionality that is related to CEPHFS share type."""
+    protocol = "cephfs"
diff --git a/manila_tempest_tests/tests/api/test_shares_actions.py b/manila_tempest_tests/tests/api/test_shares_actions.py
index 703dc71..1f37c2a 100644
--- a/manila_tempest_tests/tests/api/test_shares_actions.py
+++ b/manila_tempest_tests/tests/api/test_shares_actions.py
@@ -15,8 +15,8 @@
 
 import six
 from tempest import config
+from tempest.lib.common.utils import data_utils
 from tempest import test
-from tempest_lib.common.utils import data_utils
 import testtools
 
 from manila_tempest_tests.tests.api import base
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 624bf31..5b50a72 100644
--- a/manila_tempest_tests/tests/api/test_shares_actions_negative.py
+++ b/manila_tempest_tests/tests/api/test_shares_actions_negative.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 import testtools  # noqa
 
 from manila_tempest_tests import clients_share as clients
diff --git a/manila_tempest_tests/tests/api/test_shares_negative.py b/manila_tempest_tests/tests/api/test_shares_negative.py
index ec8ac3b..0e91302 100644
--- a/manila_tempest_tests/tests/api/test_shares_negative.py
+++ b/manila_tempest_tests/tests/api/test_shares_negative.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest import config  # noqa
+from tempest.lib import exceptions as lib_exc  # noqa
 from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
 import testtools  # noqa
 
 from manila_tempest_tests import share_exceptions
diff --git a/manila_tempest_tests/tests/scenario/manager_share.py b/manila_tempest_tests/tests/scenario/manager_share.py
index f5f0c1f..37b346e 100644
--- a/manila_tempest_tests/tests/scenario/manager_share.py
+++ b/manila_tempest_tests/tests/scenario/manager_share.py
@@ -18,8 +18,8 @@
 
 from tempest.common.utils.linux import remote_client  # noqa
 from tempest import config  # noqa
+from tempest.lib.common.utils import data_utils
 from tempest.scenario import manager  # noqa
-from tempest_lib.common.utils import data_utils
 
 from manila_tempest_tests import clients_share
 
@@ -157,10 +157,9 @@
             tenant_id = client.tenant_id
         if not router_id:
             router_id = self._get_router()['id']
-        client.add_router_interface_with_subnet_id(router_id,
-                                                   subnet_id)
-        self.addCleanup(client.remove_router_interface_with_subnet_id,
-                        router_id, subnet_id)
+        client.add_router_interface(router_id, subnet_id=subnet_id)
+        self.addCleanup(
+            client.remove_router_interface, router_id, subnet_id=subnet_id)
 
     def get_remote_client(self, *args, **kwargs):
         if not CONF.share.image_with_share_tools:
@@ -196,8 +195,9 @@
 
     def _migrate_share(self, share_id, dest_host, client=None):
         client = client or self.shares_admin_v2_client
-        client.migrate_share(share_id, dest_host)
-        share = client.wait_for_migration_completed(share_id, dest_host)
+        client.migrate_share(share_id, dest_host, True)
+        share = client.wait_for_migration_status(share_id, dest_host,
+                                                 'migration_success')
         return share
 
     def _create_share_type(self, name, is_public=True, **kwargs):
diff --git a/manila_tempest_tests/tests/scenario/test_share_basic_ops.py b/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
index 4b1daf4..7dde3ad 100644
--- a/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
+++ b/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
@@ -15,9 +15,9 @@
 
 from oslo_log import log as logging
 from tempest import config  # noqa
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
 from tempest import test  # noqa
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions
 
 from manila_tempest_tests.tests.scenario import manager_share as manager
 from manila_tempest_tests import utils
@@ -176,7 +176,15 @@
         self.allow_access_ip(self.share['id'], instance=instance,
                              cleanup=False)
         ssh_client = self.init_ssh(instance)
-        for location in self.share['export_locations']:
+
+        if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
+            locations = self.share['export_locations']
+        else:
+            exports = self.shares_v2_client.list_share_export_locations(
+                self.share['id'])
+            locations = [x['path'] for x in exports]
+
+        for location in locations:
             self.mount_share(location, ssh_client)
             self.umount_share(ssh_client)
         self.servers_client.delete_server(instance['id'])
@@ -194,10 +202,14 @@
                              cleanup=False)
         ssh_client_inst1 = self.init_ssh(instance1)
 
-        # TODO(vponomaryov): use separate API for getting export location for
-        # share when "v2" client is used.
-        first_location = self.share['export_locations'][0]
-        self.mount_share(first_location, ssh_client_inst1)
+        if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
+            locations = self.share['export_locations']
+        else:
+            exports = self.shares_v2_client.list_share_export_locations(
+                self.share['id'])
+            locations = [x['path'] for x in exports]
+
+        self.mount_share(locations[0], ssh_client_inst1)
         self.addCleanup(self.umount_share,
                         ssh_client_inst1)
         self.write_data(test_data, ssh_client_inst1)
@@ -206,7 +218,7 @@
         instance2 = self.boot_instance()
         self.allow_access_ip(self.share['id'], instance=instance2)
         ssh_client_inst2 = self.init_ssh(instance2)
-        self.mount_share(first_location, ssh_client_inst2)
+        self.mount_share(locations[0], ssh_client_inst2)
         self.addCleanup(self.umount_share,
                         ssh_client_inst2)
         data = self.read_data(ssh_client_inst2)
@@ -246,10 +258,14 @@
                              cleanup=False)
         ssh_client = self.init_ssh(instance1)
 
-        # TODO(vponomaryov): use separate API for getting export location for
-        # share when "v2" client is used.
-        first_location = self.share['export_locations'][0]
-        self.mount_share(first_location, ssh_client)
+        if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
+            locations = self.share['export_locations']
+        else:
+            exports = self.shares_v2_client.list_share_export_locations(
+                self.share['id'])
+            locations = [x['path'] for x in exports]
+
+        self.mount_share(locations[0], ssh_client)
 
         ssh_client.exec_command("mkdir -p /mnt/f1")
         ssh_client.exec_command("mkdir -p /mnt/f2")
@@ -273,20 +289,20 @@
         self.umount_share(ssh_client)
 
         share = self.migrate_share(share['id'], dest_pool)
-        if utils.is_microversion_supported("2.9"):
-            second_location = (
-                self.shares_v2_client.list_share_export_locations(
-                    share['id'])[0]['path'])
+        if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
+            new_locations = self.share['export_locations']
         else:
-            # NOTE(vponomaryov): following approach is valid for picking up
-            # export location only using microversions lower than '2.9'.
-            second_location = share['export_locations'][0]
+            new_exports = self.shares_v2_client.list_share_export_locations(
+                self.share['id'])
+            new_locations = [x['path'] for x in new_exports]
 
         self.assertEqual(dest_pool, share['host'])
-        self.assertNotEqual(first_location, second_location)
+        locations.sort()
+        new_locations.sort()
+        self.assertNotEqual(locations, new_locations)
         self.assertEqual('migration_success', share['task_state'])
 
-        self.mount_share(second_location, ssh_client)
+        self.mount_share(new_locations[0], ssh_client)
 
         output = ssh_client.exec_command("ls -lRA --ignore=lost+found /mnt")
 
@@ -303,7 +319,7 @@
     protocol = "NFS"
 
     def mount_share(self, location, ssh_client):
-        ssh_client.exec_command("sudo mount \"%s\" /mnt" % location)
+        ssh_client.exec_command("sudo mount -vt nfs \"%s\" /mnt" % location)
 
 
 class TestShareBasicOpsCIFS(ShareBasicOpsBase):
diff --git a/manila_tempest_tests/utils.py b/manila_tempest_tests/utils.py
index 94d8cd3..dea51ab 100644
--- a/manila_tempest_tests/utils.py
+++ b/manila_tempest_tests/utils.py
@@ -81,6 +81,15 @@
     return lambda f: f
 
 
+def skip_if_microversion_lt(microversion):
+    """Decorator for tests that are microversion-specific."""
+    if is_microversion_lt(CONF.share.max_api_microversion, microversion):
+        reason = ("Skipped. Test requires microversion greater than or "
+                  "equal to '%s'." % microversion)
+        return testtools.skip(reason)
+    return lambda f: f
+
+
 def rand_ip():
     """This uses the TEST-NET-3 range of reserved IP addresses.