Add Share Migration tempest functional tests

This patch adds functional tests for Share Migration,
running on generic driver DHSS = true mode.

Implements: blueprint share-migration
Change-Id: I64b0a3ee77b27278cc294f72702408a27888e0e9
diff --git a/manila_tempest_tests/tests/api/admin/test_migration.py b/manila_tempest_tests/tests/api/admin/test_migration.py
new file mode 100644
index 0000000..4c6bacf
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_migration.py
@@ -0,0 +1,67 @@
+# 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 import test  # noqa
+
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+class MigrationTest(base.BaseSharesAdminTest):
+    """Tests Share Migration.
+
+    Tests migration in multi-backend environment.
+    """
+
+    protocol = "nfs"
+
+    @classmethod
+    def resource_setup(cls):
+        super(MigrationTest, cls).resource_setup()
+        if cls.protocol not in CONF.share.enable_protocols:
+            message = "%s tests are disabled" % cls.protocol
+            raise cls.skipException(message)
+
+    @test.attr(type=["gate", "smoke", ])
+    def test_migration_empty(self):
+
+        if not CONF.share.migration_enabled:
+            raise self.skipException("Migration tests disabled. Skipping.")
+
+        pools = self.shares_client.list_pools()['pools']
+
+        if len(pools) < 2:
+            raise self.skipException("At least two different running "
+                                     "manila-share services are needed to "
+                                     "run migration tests. Skipping.")
+        share = self.create_share(self.protocol)
+        share = self.shares_client.get_share(share['id'])
+
+        dest_pool = next((x for x in pools if x['name'] != share['host']),
+                         None)
+
+        self.assertIsNotNone(dest_pool)
+
+        dest_pool = dest_pool['name']
+
+        old_export_location = share['export_locations'][0]
+
+        share = self.migrate_share(share['id'], dest_pool)
+
+        self.assertEqual(dest_pool, share['host'])
+        self.assertNotEqual(old_export_location, share['export_locations'][0])
+        self.assertEqual('migration_success', share['task_state'])
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index 554ba35..6444ccc 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -304,6 +304,13 @@
         return share
 
     @classmethod
+    def migrate_share(cls, share_id, dest_host, client=None):
+        client = client or cls.shares_client
+        client.migrate_share(share_id, dest_host)
+        share = client.wait_for_migration_completed(share_id, dest_host)
+        return share
+
+    @classmethod
     def create_share(cls, *args, **kwargs):
         """Create one share and wait for available state. Retry if allowed."""
         result = cls.create_shares([{"args": args, "kwargs": kwargs}])
diff --git a/manila_tempest_tests/tests/scenario/manager_share.py b/manila_tempest_tests/tests/scenario/manager_share.py
index a8133f9..00a2209 100644
--- a/manila_tempest_tests/tests/scenario/manager_share.py
+++ b/manila_tempest_tests/tests/scenario/manager_share.py
@@ -116,7 +116,7 @@
         return sn
 
     def _allow_access(self, share_id, client=None,
-                      access_type="ip", access_to="0.0.0.0"):
+                      access_type="ip", access_to="0.0.0.0", cleanup=True):
         """Allow share access
 
         :param share_id: id of the share
@@ -128,8 +128,8 @@
         client = client or self.shares_client
         access = client.create_access_rule(share_id, access_type, access_to)
         client.wait_for_access_rule_status(share_id, access['id'], "active")
-        self.addCleanup(client.delete_access_rule,
-                        share_id, access['id'])
+        if cleanup:
+            self.addCleanup(client.delete_access_rule, share_id, access['id'])
         return access
 
     def _create_router_interface(self, subnet_id, client=None,
@@ -182,3 +182,9 @@
             raise
 
         return linux_client
+
+    def _migrate_share(self, share_id, dest_host, client=None):
+        client = client or self.shares_client
+        client.migrate_share(share_id, dest_host)
+        share = client.wait_for_migration_completed(share_id, dest_host)
+        return share
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 2864b00..be07639 100644
--- a/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
+++ b/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
@@ -116,6 +116,11 @@
         data = ssh_client.exec_command("sudo cat /mnt/t1")
         return data.rstrip()
 
+    def migrate_share(self, share_id, dest_host):
+        share = self._migrate_share(share_id, dest_host,
+                                    self.shares_admin_client)
+        return share
+
     def create_share_network(self):
         self.net = self._create_network(namestart="manila-share")
         self.subnet = self._create_subnet(network=self.net,
@@ -132,7 +137,7 @@
         self.share = self._create_share(share_protocol=self.protocol,
                                         share_network_id=share_net_id)
 
-    def allow_access_ip(self, share_id, ip=None, instance=None):
+    def allow_access_ip(self, share_id, ip=None, instance=None, cleanup=True):
         if instance and not ip:
             try:
                 net_addresses = instance['addresses']
@@ -144,7 +149,8 @@
                               "Falling back to default")
         if not ip:
             ip = '0.0.0.0/0'
-        self._allow_access(share_id, access_type='ip', access_to=ip)
+        self._allow_access(share_id, access_type='ip', access_to=ip,
+                           cleanup=cleanup)
 
     @test.services('compute', 'network')
     def test_mount_share_one_vm(self):
@@ -187,6 +193,84 @@
         data = self.read_data(ssh_client_inst2)
         self.assertEqual(test_data, data)
 
+    @test.services('compute', 'network')
+    def test_migration_files(self):
+
+        if self.protocol == "CIFS":
+            raise self.skipException("Test for CIFS protocol not supported "
+                                     "at this moment. Skipping.")
+
+        if not CONF.share.migration_enabled:
+            raise self.skipException("Migration tests disabled. Skipping.")
+
+        pools = self.shares_admin_client.list_pools()['pools']
+
+        if len(pools) < 2:
+            raise self.skipException("At least two different running "
+                                     "manila-share services are needed to "
+                                     "run migration tests. Skipping.")
+
+        self.security_group = self._create_security_group()
+        self.create_share_network()
+        self.create_share(self.share_net['id'])
+        share = self.shares_client.get_share(self.share['id'])
+
+        dest_pool = next((x for x in pools if x['name'] != share['host']),
+                         None)
+
+        self.assertIsNotNone(dest_pool)
+
+        dest_pool = dest_pool['name']
+
+        old_export_location = share['export_locations'][0]
+
+        instance1 = self.boot_instance(self.net)
+        self.allow_access_ip(self.share['id'], instance=instance1,
+                             cleanup=False)
+        ssh_client = self.init_ssh(instance1)
+        first_location = self.share['export_locations'][0]
+        self.mount_share(first_location, ssh_client)
+
+        ssh_client.exec_command("mkdir -p /mnt/f1")
+        ssh_client.exec_command("mkdir -p /mnt/f2")
+        ssh_client.exec_command("mkdir -p /mnt/f3")
+        ssh_client.exec_command("mkdir -p /mnt/f4")
+        ssh_client.exec_command("mkdir -p /mnt/f1/ff1")
+        ssh_client.exec_command("sleep 1")
+        ssh_client.exec_command("dd if=/dev/zero of=/mnt/f1/1m1.bin bs=1M"
+                                " count=1")
+        ssh_client.exec_command("dd if=/dev/zero of=/mnt/f2/1m2.bin bs=1M"
+                                " count=1")
+        ssh_client.exec_command("dd if=/dev/zero of=/mnt/f3/1m3.bin bs=1M"
+                                " count=1")
+        ssh_client.exec_command("dd if=/dev/zero of=/mnt/f4/1m4.bin bs=1M"
+                                " count=1")
+        ssh_client.exec_command("dd if=/dev/zero of=/mnt/f1/ff1/1m5.bin bs=1M"
+                                " count=1")
+        ssh_client.exec_command("chmod -R 555 /mnt/f3")
+        ssh_client.exec_command("chmod -R 777 /mnt/f4")
+
+        self.umount_share(ssh_client)
+
+        share = self.migrate_share(share['id'], dest_pool)
+
+        self.assertEqual(dest_pool, share['host'])
+        self.assertNotEqual(old_export_location, share['export_locations'][0])
+        self.assertEqual('migration_success', share['task_state'])
+
+        second_location = share['export_locations'][0]
+        self.mount_share(second_location, ssh_client)
+
+        output = ssh_client.exec_command("ls -lRA --ignore=lost+found /mnt")
+
+        self.umount_share(ssh_client)
+
+        self.assertTrue('1m1.bin' in output)
+        self.assertTrue('1m2.bin' in output)
+        self.assertTrue('1m3.bin' in output)
+        self.assertTrue('1m4.bin' in output)
+        self.assertTrue('1m5.bin' in output)
+
 
 class TestShareBasicOpsNFS(ShareBasicOpsBase):
     protocol = "NFS"