Merge "[ci] Copy ganesha logs in the ceph-nfs job"
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index 610ae51..a24a064 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -262,7 +262,7 @@
                 help="Defines whether to run tests that create share from "
                      "snapshots in another pool or az. Enable this "
                      "option if the used driver supports it."),
-    cfg.BoolOpt("run_share_servers_migration_tests",
+    cfg.BoolOpt("run_share_server_migration_tests",
                 default=False,
                 help="Defines whether to run share servers migration tests. "
                      "Enable this option if the used driver supports it."),
diff --git a/manila_tempest_tests/tests/api/admin/test_replication.py b/manila_tempest_tests/tests/api/admin/test_replication.py
index a7bbad2..c435da1 100644
--- a/manila_tempest_tests/tests/api/admin/test_replication.py
+++ b/manila_tempest_tests/tests/api/admin/test_replication.py
@@ -84,9 +84,9 @@
     @decorators.idempotent_id('0213cdfd-6a0f-4f24-a154-69796888a64a')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_REPLICATION_VERSION,
-              constants.SHARE_REPLICA_GRADUATION_VERSION,
-              LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_REPLICATION_VERSION,
+                            constants.SHARE_REPLICA_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_promote_out_of_sync_share_replica(self, version):
         """Test promote 'out_of_sync' share replica to active state."""
         self.skip_if_microversion_not_supported(version)
@@ -145,9 +145,9 @@
     @decorators.idempotent_id('22a199b7-f4f6-4ede-b09f-8047a9d01cad')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_REPLICATION_VERSION,
-              constants.SHARE_REPLICA_GRADUATION_VERSION,
-              LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_REPLICATION_VERSION,
+                            constants.SHARE_REPLICA_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_force_delete_share_replica(self, version):
         """Test force deleting a replica that is in 'error_deleting' status."""
         self.skip_if_microversion_not_supported(version)
@@ -167,9 +167,9 @@
     @decorators.idempotent_id('16bd90f0-c478-4a99-8633-b18703ff56fa')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_REPLICATION_VERSION,
-              constants.SHARE_REPLICA_GRADUATION_VERSION,
-              LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_REPLICATION_VERSION,
+                            constants.SHARE_REPLICA_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_reset_share_replica_status(self, version):
         """Test resetting a replica's 'status' attribute."""
         self.skip_if_microversion_not_supported(version)
@@ -187,9 +187,9 @@
     @decorators.idempotent_id('258844da-a853-42b6-87db-b16e616018c6')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_REPLICATION_VERSION,
-              constants.SHARE_REPLICA_GRADUATION_VERSION,
-              LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_REPLICATION_VERSION,
+                            constants.SHARE_REPLICA_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_reset_share_replica_state(self, version):
         """Test resetting a replica's 'replica_state' attribute."""
         self.skip_if_microversion_not_supported(version)
@@ -207,9 +207,9 @@
     @decorators.idempotent_id('2969565a-85e8-4c61-9dfb-cc7f7ca9f6dd')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_REPLICATION_VERSION,
-              constants.SHARE_REPLICA_GRADUATION_VERSION,
-              LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_REPLICATION_VERSION,
+                            constants.SHARE_REPLICA_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_resync_share_replica(self, version):
         """Test resyncing a replica."""
         self.skip_if_microversion_not_supported(version)
diff --git a/manila_tempest_tests/tests/api/admin/test_share_group_types.py b/manila_tempest_tests/tests/api/admin/test_share_group_types.py
index 3666079..eb62838 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_group_types.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_group_types.py
@@ -147,8 +147,9 @@
     @decorators.idempotent_id('15b44580-a34d-4e0d-a77b-0e76b45d6199')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_update_single_share_group_type_spec(self, version):
         self.skip_if_microversion_not_supported(version)
         name = data_utils.rand_name("tempest-manila")
@@ -202,8 +203,9 @@
     @decorators.idempotent_id('efddee69-ca23-4681-8247-94ded81c4c3a')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_delete_single_share_group_type_spec_min(self, version):
         self.skip_if_microversion_not_supported(version)
         name = data_utils.rand_name("tempest-manila")
@@ -231,8 +233,9 @@
     @decorators.idempotent_id('c2d34b42-e3ec-404e-8b7a-0fe9b1560507')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_private_share_group_type_access(self, version):
         self.skip_if_microversion_not_supported(version)
         name = data_utils.rand_name("tempest-manila")
@@ -291,7 +294,7 @@
 
     @decorators.idempotent_id('b8b20a96-cecc-4677-8a77-aae3b93e5b96')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
-    @ddt.data(*set(('2.45', '2.46', LATEST_MICROVERSION)))
+    @ddt.data(*utils.deduplicate(('2.45', '2.46', LATEST_MICROVERSION)))
     def test_share_group_type_create_show_list_with_is_default_key(self,
                                                                    version):
         self.skip_if_microversion_not_supported(version)
diff --git a/manila_tempest_tests/tests/api/admin/test_share_groups.py b/manila_tempest_tests/tests/api/admin/test_share_groups.py
index e88d5ce..207db8c 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_groups.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_groups.py
@@ -63,8 +63,9 @@
     @decorators.idempotent_id('79eaa86f-4c8f-49fd-acb2-ec051aa6bf93')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_create_share_group_with_single_share_type_min(self, version):
         self.skip_if_microversion_not_supported(version)
         share_group = self.create_share_group(
@@ -137,8 +138,9 @@
         CONF.share.default_share_type_name, "Only if defaults are defined.")
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_default_share_group_type_applied(self, version):
         self.skip_if_microversion_not_supported(version)
         try:
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 5cda130..09bbdb7 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_manage.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_manage.py
@@ -85,10 +85,14 @@
             share_ids = [si['share_id'] for si in share_instance_list]
             self.assertNotIn(share['id'], share_ids)
 
+        export_path = share['export_locations'][0]
+        if utils.is_microversion_ge(version, "2.8"):
+            export_path = share['export_locations'][0]['path']
+
         # Manage share
         manage_params = {
             'service_host': share['host'],
-            'export_path': share['export_locations'][0],
+            'export_path': export_path,
             'protocol': share['share_proto'],
             'share_type_id': self.st['share_type']['id'],
             'name': name,
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers_migration.py b/manila_tempest_tests/tests/api/admin/test_share_servers_migration.py
index 813cb76..e162b17 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers_migration.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers_migration.py
@@ -36,9 +36,9 @@
             raise cls.skipException('%s tests are disabled.' % cls.protocol)
         if not CONF.share.multitenancy_enabled:
             raise cls.skipException('Multitenancy tests are disabled.')
-        if not CONF.share.run_share_servers_migration_tests:
+        if not CONF.share.run_share_server_migration_tests:
             raise cls.skipException(
-                'Share servers migration tests are disabled.')
+                'Share server migration tests are disabled.')
         utils.check_skip_if_microversion_lt('2.57')
 
     @classmethod
@@ -58,6 +58,10 @@
         # create share type (generic)
         cls.share_type = cls._create_share_type()
 
+        # create two non routable IPs to be used in NFS access rulesi
+        cls.access_rules_ip_rw = utils.rand_ip()
+        cls.access_rules_ip_ro = utils.rand_ip()
+
     def _setup_migration(self, share):
         """Initial share server migration setup."""
 
@@ -66,11 +70,12 @@
 
         # (andrer) Verify if have at least one backend compatible with
         # the specified share server.
-        dest_host, compatible = self._choose_matching_backend_for_share_server(
-            server_id)
+        dest_host, compatible = (
+            self._choose_compatible_backend_for_share_server(server_id))
 
         snapshot = False
-        if compatible['supported_capabilities']['preserve_snapshots']:
+        if (compatible['supported_capabilities']['preserve_snapshots'] and
+                share['snapshot_support']):
             snapshot = self.create_snapshot_wait_for_active(
                 share['id'], cleanup_in_class=False)['id']
 
@@ -85,35 +90,26 @@
         # (andrer) Create the access rules, considering NFS and CIFS
         # protocols.
         access_rules = self._get_access_rule_data_for_protocols()
-        self.shares_v2_client.create_access_rule(
-            share['id'], access_type=access_rules[0].get('access_type'),
-            access_to=access_rules[0].get('access_to'),
-            access_level=access_rules[0].get('access_level'))
-
+        for rule in access_rules:
+            self.shares_v2_client.create_access_rule(
+                share['id'], access_type=rule.get('access_type'),
+                access_to=rule.get('access_to'),
+                access_level=rule.get('access_level')
+            )
         self.shares_v2_client.wait_for_share_status(
             share['id'], constants.RULE_STATE_ACTIVE,
             status_attr='access_rules_status')
 
-        if self.protocol == 'nfs':
-            self.shares_v2_client.create_access_rule(
-                share['id'], access_type=access_rules[1].get('access_type'),
-                access_to=access_rules[1].get('access_to'),
-                access_level=access_rules[1].get('access_level'))
-
-            self.shares_v2_client.wait_for_share_status(
-                share['id'], constants.RULE_STATE_ACTIVE,
-                status_attr='access_rules_status')
-
         share = self.shares_v2_client.get_share(share['id'])
 
         return share, server_id, dest_host, snapshot
 
-    def _validate_instances_states(self, share, instance_status,
-                                   snapshot_id):
+    def _validate_state_of_resources(self, share, expected_status,
+                                     snapshot_id):
         """Validates the share and snapshot status."""
-        statuses = ((instance_status,)
-                    if not isinstance(instance_status, (tuple, list, set))
-                    else instance_status)
+        statuses = ((expected_status,)
+                    if not isinstance(expected_status, (tuple, list, set))
+                    else expected_status)
 
         share = self.shares_v2_client.get_share(share['id'])
         self.assertIn(share['status'], statuses)
@@ -123,9 +119,8 @@
             self.assertIn(snapshot['status'], statuses)
 
     def _validate_share_server_migration_complete(
-        self, share, dest_host, src_server_id, dest_server_id,
-        snapshot_id=None, share_network_id=None,
-        version=CONF.share.max_api_microversion):
+        self, share, dest_host, dest_server_id, snapshot_id=None,
+        share_network_id=None, version=CONF.share.max_api_microversion):
         """Validates the share server migration complete. """
 
         # Check the export locations
@@ -165,12 +160,12 @@
         elif self.protocol == 'nfs':
             expected_rules = [{
                 'state': constants.RULE_STATE_ACTIVE,
-                'access_to': '50.50.50.50',
+                'access_to': self.access_rules_ip_rw,
                 'access_type': 'ip',
                 'access_level': 'rw',
             }, {
                 'state': constants.RULE_STATE_ACTIVE,
-                'access_to': '51.51.51.51',
+                'access_to': self.access_rules_ip_ro,
                 'access_type': 'ip',
                 'access_level': 'ro',
             }]
@@ -186,7 +181,7 @@
         self.assertEqual(len(expected_rules), len(filtered_rules))
 
     @classmethod
-    def _choose_matching_backend_for_share_server(self, server_id):
+    def _choose_compatible_backend_for_share_server(self, server_id):
         """Choose a compatible host for the share server migration."""
         for backend in self.backends:
             # This try is necessary since if you try migrate the share server
@@ -218,10 +213,11 @@
                 return backend, compatibility
 
         raise self.skipException(
-            "Not found incompatible host for the share server migration.")
+            "None of the hosts available are incompatible to perform a"
+            " negative share server migration test.")
 
     def _get_share_server_destination_for_migration(self, src_server_id):
-        """Find the destination share server choosed for the migration."""
+        """Find the destination share server chosen for the migration."""
         params = {'source_share_server_id': src_server_id,
                   'status': constants.STATUS_SERVER_MIGRATING_TO}
         dest_server = self.admin_shares_v2_client.list_share_servers(
@@ -235,11 +231,11 @@
         if self.protocol == 'nfs':
             return [{
                 'access_type': 'ip',
-                'access_to': '50.50.50.50',
+                'access_to': self.access_rules_ip_rw,
                 'access_level': 'rw',
             }, {
                 'access_type': 'ip',
-                'access_to': '51.51.51.51',
+                'access_to': self.access_rules_ip_ro,
                 'access_level': 'ro',
             }]
         elif self.protocol == 'cifs':
@@ -279,9 +275,9 @@
         self.shares_v2_client.share_server_migration_start(
             src_server_id, dest_host, preserve_snapshots=preserve_snapshots)
 
-        task_state = constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE
+        expected_state = constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE
         self.shares_v2_client.wait_for_share_server_status(
-            src_server_id, task_state, status_attr='task_state')
+            src_server_id, expected_state, status_attr='task_state')
         # Get for the destination share server.
         dest_server_id = self._get_share_server_destination_for_migration(
             src_server_id)
@@ -292,19 +288,19 @@
 
         # Validate the share instances status.
         share_status = constants.STATUS_SERVER_MIGRATING
-        self._validate_instances_states(share, share_status, snapshot_id)
+        self._validate_state_of_resources(share, share_status, snapshot_id)
 
         # Cancel the share server migration.
         self.shares_v2_client.share_server_migration_cancel(src_server_id)
 
         # Wait for the migration cancelled status.
-        task_state = constants.TASK_STATE_MIGRATION_CANCELLED
+        expected_state = constants.TASK_STATE_MIGRATION_CANCELLED
         self.shares_v2_client.wait_for_share_server_status(
-            src_server_id, task_state, status_attr='task_state')
+            src_server_id, expected_state, status_attr='task_state')
 
         # After the cancel operation, we need to validate again the resources.
-        share_status = constants.STATUS_AVAILABLE
-        self._validate_instances_states(share, share_status, snapshot_id)
+        expected_status = constants.STATUS_AVAILABLE
+        self._validate_state_of_resources(share, expected_status, snapshot_id)
 
     @decorators.idempotent_id('99e439a8-a716-4205-bf5b-af50128cb908')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@@ -342,9 +338,9 @@
             new_share_network_id=dest_share_network_id,
             preserve_snapshots=preserve_snapshots)
 
-        task_state = constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE
+        expected_state = constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE
         self.shares_v2_client.wait_for_share_server_status(
-            src_server_id, task_state, status_attr='task_state')
+            src_server_id, expected_state, status_attr='task_state')
         # Get for the destination share server.
         dest_server_id = self._get_share_server_destination_for_migration(
             src_server_id)
@@ -354,24 +350,32 @@
         self.assertEqual(dest_share_network_id,
                          dest_server['share_network_id'])
 
-        share_status = constants.STATUS_SERVER_MIGRATING
-        self._validate_instances_states(share, share_status, snapshot_id)
+        expected_status = constants.STATUS_SERVER_MIGRATING
+        self._validate_state_of_resources(share, expected_status, snapshot_id)
 
         # Share server migration complete.
         self.shares_v2_client.share_server_migration_complete(src_server_id)
 
-        # It's necessary wait for the migration success state and
-        # active status.
-        task_state = [constants.TASK_STATE_MIGRATION_SUCCESS,
-                      constants.SERVER_STATE_INACTIVE]
+        # It's necessary wait for the destination server went to active status.
+        expected_status = constants.SERVER_STATE_ACTIVE
         self.shares_v2_client.wait_for_share_server_status(
-            src_server_id, task_state, status_attr='task_state')
+            dest_server_id, expected_status)
+
+        # Check if the source server went to inactive status if it exists.
+        try:
+            src_server = self.shares_v2_client.show_share_server(src_server_id)
+        except exceptions.NotFound:
+            src_server = None
+
+        if src_server:
+            self.assertEqual(
+                src_server['status'], constants.SERVER_STATE_INACTIVE)
 
         # Validate the share server migration complete.
         share = self.shares_v2_client.get_share(share['id'])
         self._validate_share_server_migration_complete(
-            share, dest_host, src_server_id, dest_server_id,
-            snapshot_id=snapshot_id, share_network_id=dest_share_network_id)
+            share, dest_host, dest_server_id, snapshot_id=snapshot_id,
+            share_network_id=dest_share_network_id)
 
     @decorators.idempotent_id('52e154eb-2d39-45af-b5c1-49ea569ab804')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@@ -385,8 +389,9 @@
         # Find a backend compatible or not for the share server
         # check compatibility operation.
         if compatible:
-            dest_host, result = self._choose_matching_backend_for_share_server(
-                server_id=share['share_server_id'])
+            dest_host, result = (
+                self._choose_compatible_backend_for_share_server(
+                    server_id=share['share_server_id']))
             self.assertTrue(result['compatible'])
             self.assertEqual(result['requested_capabilities']['host'],
                              dest_host)
@@ -394,10 +399,6 @@
             dest_host, result = (
                 self._choose_incompatible_backend_for_share_server(
                     server_id=share['share_server_id']))
-            if dest_host is None:
-                raise self.skipException(
-                    "Not found any compatible destination host for the share "
-                    "server %s." % share['share_server_id'])
             self.assertFalse(result['compatible'])
             self.assertEqual(result['requested_capabilities'].get('host'),
                              dest_host)
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers_migration_negative.py b/manila_tempest_tests/tests/api/admin/test_share_servers_migration_negative.py
index 9924f82..3b39a61 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers_migration_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers_migration_negative.py
@@ -29,26 +29,26 @@
 
 class MigrationShareServerNegative(
         test_share_servers_migration.MigrationShareServerBase):
-    protocool = None
+    protocol = None
 
     @classmethod
-    def _setup_migration(self, cleanup_in_class=True):
+    def _setup_migration(cls, cleanup_in_class=True):
         """Setup migration for negative tests."""
         extra_specs = {
             'driver_handles_share_servers': CONF.share.multitenancy_enabled}
         if CONF.share.capability_snapshot_support:
             extra_specs['snapshot_support'] = True
-        share_type = self.create_share_type(
+        share_type = cls.create_share_type(
             name=data_utils.rand_name("tempest-share-type"),
             extra_specs=extra_specs,
             cleanup_in_class=cleanup_in_class)
-        share = self.create_share(share_protocol=self.protocol,
-                                  share_type_id=share_type['share_type']['id'],
-                                  cleanup_in_class=cleanup_in_class)
-        share = self.shares_v2_client.get_share(share['id'])
+        share = cls.create_share(share_protocol=cls.protocol,
+                                 share_type_id=share_type['share_type']['id'],
+                                 cleanup_in_class=cleanup_in_class)
+        share = cls.shares_v2_client.get_share(share['id'])
         share_server_id = share['share_server_id']
-        dest_host, compatible = self._choose_matching_backend_for_share_server(
-            share_server_id)
+        dest_host, compatible = (
+            cls._choose_compatible_backend_for_share_server(share_server_id))
 
         return share, share_server_id, dest_host
 
@@ -60,16 +60,11 @@
     @classmethod
     def resource_setup(cls):
         super(ShareServerMigrationInvalidParametersNFS, cls).resource_setup()
-        cls.share = cls.create_share(
-            share_protocol=cls.protocol,
-            share_type_id=cls.share_type['id'])
-        cls.share = cls.shares_v2_client.get_share(cls.share['id'])
-        cls.share_server_id = cls.share['share_server_id']
         cls.fake_server_id = 'fake_server_id'
         cls.fake_host = 'fake_host@fake_backend'
 
     @decorators.idempotent_id('1be6ec2a-3118-4033-9cdb-ea6d199d97f4')
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
     def test_share_server_invalid_server_migration_check(self):
         """Not found share server in migration check."""
         self.assertRaises(lib_exc.NotFound,
@@ -78,7 +73,7 @@
                           self.fake_host)
 
     @decorators.idempotent_id('2aeffcfa-4e68-40e4-8a75-03b017503501')
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
     def test_share_server_invalid_server_migration_cancel(self):
         """Not found share server in migration cancel."""
         self.assertRaises(lib_exc.NotFound,
@@ -86,7 +81,7 @@
                           self.fake_server_id)
 
     @decorators.idempotent_id('52d23980-80e7-40de-8dba-1bb1382ef995')
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
     def test_share_server_invalid_server_migration_start(self):
         """Not found share server in migration start."""
         self.assertRaises(lib_exc.NotFound,
@@ -95,7 +90,7 @@
                           self.fake_host)
 
     @decorators.idempotent_id('47795631-eb50-424b-9fac-d2ee832cd01c')
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
     def test_share_server_invalid_server_migration_get_progress(self):
         """Not found share server in migration get progress."""
         self.assertRaises(
@@ -104,9 +99,9 @@
             self.fake_server_id)
 
     @decorators.idempotent_id('3b464298-a4e4-417b-92d6-acfbd30ac45b')
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
     def test_share_server_invalid_server_migration_complete(self):
-        """Not found share server in migration """
+        """Not found share server in migration complete."""
         self.assertRaises(
             lib_exc.NotFound,
             self.shares_v2_client.share_server_migration_complete,
@@ -115,21 +110,65 @@
     @decorators.idempotent_id('2d25cf84-0b5c-4a9f-ae20-9bec09bb6914')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_share_server_invalid_host_migration_start(self):
-        """Not found share server in migration start."""
+        """Invalid host in migration start."""
+        share = self.create_share(
+            share_protocol=self.protocol,
+            share_type_id=self.share_type['id'])
+        share = self.shares_v2_client.get_share(share['id'])
+        share_server_id = share['share_server_id']
         self.assertRaises(lib_exc.NotFound,
                           self.shares_v2_client.share_server_migration_start,
-                          self.share_server_id,
+                          share_server_id,
                           self.fake_host)
 
     @decorators.idempotent_id('e7e2c19c-a0ed-41ab-b666-b2beae4a690c')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     def test_share_server_invalid_host_migration_check(self):
-        """Not found share server in migration check."""
+        """Invalid host in migration check."""
+        share = self.create_share(
+            share_protocol=self.protocol,
+            share_type_id=self.share_type['id'])
+        share = self.shares_v2_client.get_share(share['id'])
+        share_server_id = share['share_server_id']
         self.assertRaises(lib_exc.NotFound,
                           self.shares_v2_client.share_server_migration_check,
-                          self.share_server_id,
+                          share_server_id,
                           self.fake_host)
 
+    @decorators.idempotent_id('f0d7a055-3b46-4d2b-9b96-1d719bd323e8')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_share_server_invalid_share_network_migration_start(self):
+        """Invalid host in migration start."""
+        share = self.create_share(
+            share_protocol=self.protocol,
+            share_type_id=self.share_type['id'])
+        share = self.shares_v2_client.get_share(share['id'])
+        share_server_id = share['share_server_id']
+        dest_host, _ = self._choose_compatible_backend_for_share_server(
+            share_server_id)
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.share_server_migration_start,
+                          share_server_id,
+                          dest_host,
+                          new_share_network_id='fake_share_net_id')
+
+    @decorators.idempotent_id('2617e714-7a8e-49a4-8109-beab3ea6527f')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_share_server_invalid_share_network_migration_check(self):
+        """Invalid host in migration check."""
+        share = self.create_share(
+            share_protocol=self.protocol,
+            share_type_id=self.share_type['id'])
+        share = self.shares_v2_client.get_share(share['id'])
+        share_server_id = share['share_server_id']
+        dest_host, _ = self._choose_compatible_backend_for_share_server(
+            share_server_id)
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.share_server_migration_check,
+                          share_server_id,
+                          self.fake_host,
+                          new_share_network_id='fake_share_net_id')
+
 
 class ShareServerErrorStatusOperationNFS(MigrationShareServerNegative):
     protocol = "nfs"
@@ -142,9 +181,10 @@
             share_type_id=cls.share_type['id'])
         cls.share = cls.shares_v2_client.get_share(cls.share['id'])
         cls.share_server_id = cls.share['share_server_id']
+        cls.dest_host, _ = cls._choose_compatible_backend_for_share_server(
+            cls.share_server_id)
         cls.shares_v2_client.share_server_reset_state(
             cls.share_server_id, status=constants.STATUS_ERROR)
-        cls.fake_host = 'fake_host@fake_backend'
 
     @decorators.idempotent_id('1f8d75c1-aa3c-465a-b2dd-9ad33933944f')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@@ -153,7 +193,7 @@
         self.assertRaises(lib_exc.Conflict,
                           self.shares_v2_client.share_server_migration_check,
                           self.share_server_id,
-                          self.fake_host)
+                          self.dest_host)
 
     @decorators.idempotent_id('c256c5f5-b4d1-47b7-a1f4-af21f19ce600')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@@ -162,7 +202,7 @@
         self.assertRaises(lib_exc.Conflict,
                           self.shares_v2_client.share_server_migration_start,
                           self.share_server_id,
-                          self.fake_host)
+                          self.dest_host)
 
     @decorators.idempotent_id('d2830fe4-8d13-40d2-b987-18d414bb6196')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@@ -171,8 +211,7 @@
         self.assertRaises(
             lib_exc.BadRequest,
             self.shares_v2_client.share_server_migration_get_progress,
-            self.share_server_id,
-            self.fake_host)
+            self.share_server_id)
 
     @decorators.idempotent_id('245f39d7-bcbc-4711-afd7-651a5535a880')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@@ -180,8 +219,7 @@
         """Share server migration cancel invalid operation."""
         self.assertRaises(lib_exc.BadRequest,
                           self.shares_v2_client.share_server_migration_cancel,
-                          self.share_server_id,
-                          self.fake_host)
+                          self.share_server_id)
 
     @decorators.idempotent_id('3db45440-2c70-4fa4-b5eb-75e3cb0204f8')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@@ -190,8 +228,7 @@
         self.assertRaises(
             lib_exc.BadRequest,
             self.shares_v2_client.share_server_migration_complete,
-            self.share_server_id,
-            self.fake_host)
+            self.share_server_id)
 
 
 class ShareServerMigrationStartNegativesNFS(MigrationShareServerNegative):
@@ -258,14 +295,34 @@
         """Try server migration start with invalid network."""
         share, share_server_id, dest_host = self._setup_migration(
             cleanup_in_class=False)
-        share_network = self.create_share_network(cleanup_in_class=False)
+        azs = self.get_availability_zones()
+        if len(azs) < 2:
+            raise self.skipException(
+                "Could not find the necessary azs. At least two azs are "
+                "needed to run this test.")
 
+        # In this test we'll attempt to start a migration to a share
+        # network that isn't available in the destination back ends's
+        # availability zone.
+        dest_host_az = self.get_availability_zones(backends=[dest_host])
+
+        if dest_host_az[0] != share['availability_zone']:
+            share_network_az = share['availability_zone']
+        else:
+            for az in azs:
+                if az != dest_host_az:
+                    share_network_az = az
+                    break
+
+        share_network = self.create_share_network(
+            client=self.shares_v2_client, cleanup_in_class=False,
+            availability_zone=share_network_az)
         self.assertRaises(
-            lib_exc.ServerFault,
+            lib_exc.Conflict,
             self.shares_v2_client.share_server_migration_start,
             share_server_id,
             dest_host,
-            new_share_network_id=share_network)
+            new_share_network_id=share_network['id'])
 
     @decorators.idempotent_id('11374277-efcf-4992-ad94-c8f4a393d41b')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@@ -273,7 +330,7 @@
         """Try server migration start with invalid share state."""
         share, share_server_id, dest_host = self._setup_migration(
             cleanup_in_class=False)
-        self.shares_v2_client.reset_state(share['id'])
+        self.shares_v2_client.reset_state(share['id'], status='error')
 
         self.assertRaises(
             lib_exc.Conflict,
@@ -303,7 +360,7 @@
                                   cleanup_in_class=False)
         share = self.shares_v2_client.get_share(share['id'])
         share_server_id = share['share_server_id']
-        dest_host, _ = self._choose_matching_backend_for_share_server(
+        dest_host, _ = self._choose_compatible_backend_for_share_server(
             share_server_id)
         self.create_share_replica(
             share['id'],
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 370e014..cb97bc5 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_types.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_types.py
@@ -296,7 +296,7 @@
 
     @decorators.idempotent_id('90dca5c5-f28e-4f16-90ed-78f5d725664e')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
-    @ddt.data(*set(('2.45', '2.46', LATEST_MICROVERSION)))
+    @ddt.data(*utils.deduplicate(('2.45', '2.46', LATEST_MICROVERSION)))
     def test_share_type_create_show_list_with_is_default_key(self, version):
         self.skip_if_microversion_not_supported(version)
         name = data_utils.rand_name("tempest-manila")
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 1855713..ec65ab9 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
@@ -22,6 +22,7 @@
 from testtools import testcase as tc
 
 from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
 
 
 CONF = config.CONF
@@ -125,7 +126,7 @@
 
     @decorators.idempotent_id('1b9f501d-8f34-46d0-b318-83bdfed571ec')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
-    @ddt.data(*set(['2.24', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['2.24', LATEST_MICROVERSION]))
     def test_delete_snapshot_support_extra_spec(self, version):
         self.skip_if_microversion_not_supported(version)
         # Delete one extra spec for share type
diff --git a/manila_tempest_tests/tests/api/test_replication_export_locations.py b/manila_tempest_tests/tests/api/test_replication_export_locations.py
index 55ea475..c9857e6 100644
--- a/manila_tempest_tests/tests/api/test_replication_export_locations.py
+++ b/manila_tempest_tests/tests/api/test_replication_export_locations.py
@@ -121,7 +121,7 @@
 
     @decorators.idempotent_id('da22cfb8-7dd8-4bf1-87fc-a1f7b51ebf8e')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data(*set(['2.46', '2.47', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['2.46', '2.47', LATEST_MICROVERSION]))
     def test_replicated_share_export_locations(self, version):
         """Test behavior changes in the share export locations API at 2.47"""
         self.skip_if_microversion_not_supported(version)
@@ -139,7 +139,7 @@
 
     @decorators.idempotent_id('58430f57-c6eb-44e2-9583-eecb1dd10594')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data(*set(['2.46', '2.47', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['2.46', '2.47', LATEST_MICROVERSION]))
     @testtools.skipUnless(
         CONF.share.backend_replication_type in
         (constants.REPLICATION_STYLE_READABLE, constants.REPLICATION_STYLE_DR),
diff --git a/manila_tempest_tests/tests/api/test_rules.py b/manila_tempest_tests/tests/api/test_rules.py
index 71bdd06..2a2420a 100644
--- a/manila_tempest_tests/tests/api/test_rules.py
+++ b/manila_tempest_tests/tests/api/test_rules.py
@@ -216,7 +216,8 @@
     @testtools.skipIf(
         "nfs" not in CONF.share.enable_ro_access_level_for_protocols,
         "RO access rule tests are disabled for NFS protocol.")
-    @ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
+                                 LATEST_MICROVERSION]))
     def test_create_delete_ro_access_rule(self, client_name):
         _create_delete_ro_access_rule(self, client_name)
 
@@ -230,7 +231,8 @@
     @testtools.skipIf(
         "cifs" not in CONF.share.enable_ro_access_level_for_protocols,
         "RO access rule tests are disabled for CIFS protocol.")
-    @ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
+                                 LATEST_MICROVERSION]))
     def test_create_delete_ro_access_rule(self, version):
         _create_delete_ro_access_rule(self, version)
 
@@ -265,7 +267,8 @@
 
     @decorators.idempotent_id('1f87565f-c3d9-448d-b89a-387d6c2fdae6')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
-    @ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
+                                 LATEST_MICROVERSION]))
     def test_create_delete_user_rule(self, version):
 
         # create rule
@@ -314,7 +317,8 @@
     @testtools.skipIf(
         "nfs" not in CONF.share.enable_ro_access_level_for_protocols,
         "RO access rule tests are disabled for NFS protocol.")
-    @ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
+                                 LATEST_MICROVERSION]))
     def test_create_delete_ro_access_rule(self, version):
         _create_delete_ro_access_rule(self, version)
 
@@ -328,7 +332,8 @@
     @testtools.skipIf(
         "cifs" not in CONF.share.enable_ro_access_level_for_protocols,
         "RO access rule tests are disabled for CIFS protocol.")
-    @ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
+                                 LATEST_MICROVERSION]))
     def test_create_delete_ro_access_rule(self, version):
         _create_delete_ro_access_rule(self, version)
 
@@ -364,7 +369,8 @@
 
     @decorators.idempotent_id('775ebc55-4a4d-4012-a030-2eeb7b6d2ce8')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
-    @ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
+                                 LATEST_MICROVERSION]))
     def test_create_delete_cert_rule(self, version):
 
         # create rule
@@ -413,7 +419,8 @@
     @testtools.skipIf(
         "glusterfs" not in CONF.share.enable_ro_access_level_for_protocols,
         "RO access rule tests are disabled for GLUSTERFS protocol.")
-    @ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
+                                 LATEST_MICROVERSION]))
     def test_create_delete_cert_ro_access_rule(self, version):
         if utils.is_microversion_eq(version, '1.0'):
             rule = self.shares_client.create_access_rule(
@@ -570,7 +577,7 @@
 
     @decorators.idempotent_id('c52e95cc-d6ea-4d02-9b52-cd7c1913dfff')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data(*set(
+    @ddt.data(*utils.deduplicate(
         ['1.0', '2.9', '2.27', '2.28', '2.45', LATEST_MICROVERSION]))
     def test_list_access_rules(self, version):
         self.skip_if_microversion_not_supported(version)
@@ -664,7 +671,8 @@
 
     @decorators.idempotent_id('b77bcbda-9754-48f0-9be6-79341ad1af64')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
+                                 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):
diff --git a/manila_tempest_tests/tests/api/test_security_services.py b/manila_tempest_tests/tests/api/test_security_services.py
index b300973..81645b5 100644
--- a/manila_tempest_tests/tests/api/test_security_services.py
+++ b/manila_tempest_tests/tests/api/test_security_services.py
@@ -46,7 +46,7 @@
 
     @decorators.idempotent_id('22b22937-7436-458c-ac22-8ff19feab253')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
-    @ddt.data(*set(['1.0', '2.42', '2.44', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['1.0', '2.42', '2.44', LATEST_MICROVERSION]))
     def test_list_security_services_with_detail(self, version):
         self.skip_if_microversion_not_supported(version)
         with_ou = True if utils.is_microversion_ge(version, '2.44') else False
@@ -169,7 +169,7 @@
 
     @decorators.idempotent_id('bb052be4-0176-4613-b7d5-e12bef391ddb')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
-    @ddt.data(*set(['1.0', '2.43', '2.44', LATEST_MICROVERSION]))
+    @ddt.data(*utils.deduplicate(['1.0', '2.43', '2.44', LATEST_MICROVERSION]))
     def test_get_security_service(self, version):
         self.skip_if_microversion_not_supported(version)
         with_ou = True if utils.is_microversion_ge(version, '2.44') else False
diff --git a/manila_tempest_tests/tests/api/test_share_group_actions.py b/manila_tempest_tests/tests/api/test_share_group_actions.py
index 3b2325a..b52d7f6 100644
--- a/manila_tempest_tests/tests/api/test_share_group_actions.py
+++ b/manila_tempest_tests/tests/api/test_share_group_actions.py
@@ -107,8 +107,9 @@
     @decorators.idempotent_id('1e359389-09a7-4235-84c9-7b5c83632fff')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_get_share_group(self, version):
         self.skip_if_microversion_not_supported(version)
 
@@ -161,8 +162,9 @@
     @decorators.idempotent_id('04fcd695-c5f8-4de7-ab09-131424e6bdfb')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_list_share_groups(self, version):
         self.skip_if_microversion_not_supported(version)
 
@@ -192,8 +194,9 @@
     @decorators.idempotent_id('16986c21-ecbc-429e-ab3d-8d1596a3eac4')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION, '2.36',
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION, '2.36',
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_list_share_groups_with_detail_min(self, version):
         self.skip_if_microversion_not_supported(version)
         params = None
@@ -252,8 +255,9 @@
     @decorators.idempotent_id('5d2ca4f5-04da-4528-af47-ec980b95e884')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_get_share_group_snapshot(self, version):
         self.skip_if_microversion_not_supported(version)
 
@@ -308,8 +312,9 @@
     @decorators.idempotent_id('650c5fa7-11f2-48bd-b012-fc2e32b6f446')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_create_share_group_from_populated_share_group_snapshot(self,
                                                                     version):
         self.skip_if_microversion_not_supported(version)
@@ -413,8 +418,9 @@
     @decorators.idempotent_id('7f0a07ce-afdd-4c51-a29c-d8fe6cb5f6a5')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_update_share_group(self, version):
         self.skip_if_microversion_not_supported(version)
 
@@ -453,8 +459,9 @@
     @decorators.idempotent_id('611b1555-df09-499b-8aef-e8261e3f6863')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data(
-        *set([constants.MIN_SHARE_GROUP_MICROVERSION,
-              constants.SHARE_GROUPS_GRADUATION_VERSION, LATEST_MICROVERSION]))
+        *utils.deduplicate([constants.MIN_SHARE_GROUP_MICROVERSION,
+                            constants.SHARE_GROUPS_GRADUATION_VERSION,
+                            LATEST_MICROVERSION]))
     def test_create_update_read_share_group_with_unicode(self, version):
         self.skip_if_microversion_not_supported(version)
 
diff --git a/manila_tempest_tests/utils.py b/manila_tempest_tests/utils.py
index f30c0fc..650614d 100644
--- a/manila_tempest_tests/utils.py
+++ b/manila_tempest_tests/utils.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from collections import OrderedDict
 import random
 import re
 
@@ -27,6 +28,15 @@
 EXPERIMENTAL = {'X-OpenStack-Manila-API-Experimental': 'True'}
 
 
+def deduplicate(items):
+    """De-duplicate a list of items while preserving the order.
+
+    It is useful when passing a list of items to ddt.data, in order
+    to remove duplicated elements which may be specified as constants.
+    """
+    return list(OrderedDict.fromkeys(items))
+
+
 def get_microversion_as_tuple(microversion_str):
     """Transforms string-like microversion to two-value tuple of integers.
 
diff --git a/setup.cfg b/setup.cfg
index 9da84c3..ebb8f8c 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -17,6 +17,7 @@
     Programming Language :: Python :: 3.5
     Programming Language :: Python :: 3.6
     Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3.8
 
 [files]
 packages =
diff --git a/zuul.d/manila-tempest-jobs.yaml b/zuul.d/manila-tempest-jobs.yaml
index bfbe407..05d2984 100644
--- a/zuul.d/manila-tempest-jobs.yaml
+++ b/zuul.d/manila-tempest-jobs.yaml
@@ -255,7 +255,7 @@
               multitenancy_enabled: true
               backend_names: LONDON,PARIS
               multi_backend: true
-              run_share_servers_migration_tests: true
+              run_share_server_migration_tests: true
 
 - job:
     name: manila-tempest-plugin-generic
@@ -512,7 +512,7 @@
               run_mount_snapshot_tests: true
               run_replication_tests: true
               run_revert_to_snapshot_tests: true
-              run_share_servers_migration_tests: true
+              run_share_server_migration_tests: true
 
 - job:
     name: manila-tempest-plugin-glusterfs-native