Merge "Fix params order in assertEqual"
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index ddf11cd..ad64b4b 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.8",
+ default="2.10",
help="The maximum api microversion is configured to be the "
"value of the latest microversion supported by Manila."),
cfg.StrOpt("region",
diff --git a/manila_tempest_tests/services/share/v2/json/shares_client.py b/manila_tempest_tests/services/share/v2/json/shares_client.py
index 806f108..2ccf9b5 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -187,7 +187,8 @@
name=None, snapshot_id=None, description=None,
metadata=None, share_network_id=None,
share_type_id=None, is_public=False,
- consistency_group_id=None, version=LATEST_MICROVERSION):
+ consistency_group_id=None, availability_zone=None,
+ version=LATEST_MICROVERSION):
metadata = metadata or {}
if name is None:
name = data_utils.rand_name("tempest-created-share")
@@ -208,6 +209,8 @@
"is_public": is_public,
}
}
+ if availability_zone:
+ post_body["share"]["availability_zone"] = availability_zone
if share_network_id:
post_body["share"]["share_network_id"] = share_network_id
if share_type_id:
@@ -238,6 +241,23 @@
self.expected_success(200, resp.status)
return self._parse_resp(body)
+ def get_share_export_location(
+ self, share_id, export_location_uuid, version=LATEST_MICROVERSION):
+ resp, body = self.get(
+ "shares/%(share_id)s/export_locations/%(el_uuid)s" % {
+ "share_id": share_id, "el_uuid": export_location_uuid},
+ version=version)
+ self.expected_success(200, resp.status)
+ return self._parse_resp(body)
+
+ def list_share_export_locations(
+ self, share_id, version=LATEST_MICROVERSION):
+ resp, body = self.get(
+ "shares/%(share_id)s/export_locations" % {"share_id": share_id},
+ version=version)
+ self.expected_success(200, resp.status)
+ return self._parse_resp(body)
+
def delete_share(self, share_id, params=None,
version=LATEST_MICROVERSION):
uri = "shares/%s" % share_id
@@ -265,6 +285,24 @@
self.expected_success(200, resp.status)
return self._parse_resp(body)
+ def get_share_instance_export_location(
+ self, instance_id, export_location_uuid,
+ version=LATEST_MICROVERSION):
+ resp, body = self.get(
+ "share_instances/%(instance_id)s/export_locations/%(el_uuid)s" % {
+ "instance_id": instance_id, "el_uuid": export_location_uuid},
+ version=version)
+ self.expected_success(200, resp.status)
+ return self._parse_resp(body)
+
+ def list_share_instance_export_locations(
+ self, instance_id, version=LATEST_MICROVERSION):
+ resp, body = self.get(
+ "share_instances/%s/export_locations" % instance_id,
+ version=version)
+ self.expected_success(200, resp.status)
+ return self._parse_resp(body)
+
def wait_for_share_instance_status(self, instance_id, status,
version=LATEST_MICROVERSION):
"""Waits for a share to reach a given status."""
@@ -288,6 +326,30 @@
(instance_id, status, self.build_timeout))
raise exceptions.TimeoutException(message)
+ def wait_for_share_status(self, share_id, status, status_attr='status',
+ version=LATEST_MICROVERSION):
+ """Waits for a share to reach a given status."""
+ body = self.get_share(share_id, version=version)
+ share_status = body[status_attr]
+ start = int(time.time())
+
+ while share_status != status:
+ time.sleep(self.build_interval)
+ body = self.get_share(share_id, version=version)
+ share_status = body[status_attr]
+ if share_status == status:
+ return
+ elif 'error' in share_status.lower():
+ raise share_exceptions.ShareBuildErrorException(
+ share_id=share_id)
+
+ if int(time.time()) - start >= self.build_timeout:
+ message = ("Share's %(status_attr)s failed to transition to "
+ "%(status)s within the required time %(seconds)s." %
+ {"status_attr": status_attr, "status": status,
+ "seconds": self.build_timeout})
+ raise exceptions.TimeoutException(message)
+
###############
def extend_share(self, share_id, new_size, version=LATEST_MICROVERSION,
@@ -377,16 +439,16 @@
###############
- def _get_access_action_name(self, version):
+ def _get_access_action_name(self, version, action):
if utils.is_microversion_gt(version, "2.6"):
- return 'allow_access'
- return 'os-allow_access'
+ return action.split('os-')[-1]
+ return action
def create_access_rule(self, share_id, access_type="ip",
access_to="0.0.0.0", access_level=None,
version=LATEST_MICROVERSION, action_name=None):
post_body = {
- self._get_access_action_name(version): {
+ self._get_access_action_name(version, 'os-allow_access'): {
"access_type": access_type,
"access_to": access_to,
"access_level": access_level,
@@ -400,7 +462,7 @@
def list_access_rules(self, share_id, version=LATEST_MICROVERSION,
action_name=None):
- body = {self._get_access_action_name(version): None}
+ body = {self._get_access_action_name(version, 'os-access_list'): None}
resp, body = self.post(
"shares/%s/action" % share_id, json.dumps(body), version=version)
self.expected_success(200, resp.status)
@@ -409,7 +471,7 @@
def delete_access_rule(self, share_id, rule_id,
version=LATEST_MICROVERSION, action_name=None):
post_body = {
- self._get_access_action_name(version): {
+ self._get_access_action_name(version, 'os-deny_access'): {
"access_id": rule_id,
}
}
diff --git a/manila_tempest_tests/tests/api/admin/test_export_locations.py b/manila_tempest_tests/tests/api/admin/test_export_locations.py
new file mode 100644
index 0000000..9c759fc
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_export_locations.py
@@ -0,0 +1,143 @@
+# Copyright 2015 Mirantis Inc.
+# 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 oslo_utils import timeutils
+from oslo_utils import uuidutils
+import six
+from tempest import config
+from tempest import test
+
+from manila_tempest_tests import clients_share as clients
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+@base.skip_if_microversion_not_supported("2.9")
+class ExportLocationsTest(base.BaseSharesAdminTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(ExportLocationsTest, cls).resource_setup()
+ cls.admin_client = cls.shares_v2_client
+ cls.member_client = clients.Manager().shares_v2_client
+ cls.share = cls.create_share()
+ cls.share = cls.shares_v2_client.get_share(cls.share['id'])
+ 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'])
+
+ if not isinstance(export_locations, (list, tuple, set)):
+ export_locations = (export_locations, )
+
+ for export_location in export_locations:
+ self.assertEqual(len(expected_keys), len(export_location))
+ for key in expected_keys:
+ self.assertIn(key, export_location)
+ 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)
+
+ @test.attr(type=["gate", ])
+ def test_list_share_export_locations(self):
+ export_locations = self.admin_client.list_share_export_locations(
+ self.share['id'])
+
+ self._verify_export_location_structure(export_locations)
+
+ @test.attr(type=["gate", ])
+ def test_get_share_export_location(self):
+ export_locations = self.admin_client.list_share_export_locations(
+ self.share['id'])
+
+ 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)
+
+ @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')
+
+ @test.attr(type=["gate", ])
+ def test_get_share_export_location_by_member(self):
+ export_locations = self.admin_client.list_share_export_locations(
+ self.share['id'])
+
+ for export_location in export_locations:
+ el = self.member_client.get_share_export_location(
+ self.share['id'], export_location['uuid'])
+ self._verify_export_location_structure(el, 'member')
+
+ @test.attr(type=["gate", ])
+ 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)
+
+ @test.attr(type=["gate", ])
+ def test_get_share_instance_export_location(self):
+ for share_instance in self.share_instances:
+ export_locations = (
+ self.admin_client.list_share_instance_export_locations(
+ 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)
+
+ @test.attr(type=["gate", ])
+ def test_share_contains_all_export_locations_of_all_share_instances(self):
+ share_export_locations = self.admin_client.list_share_export_locations(
+ self.share['id'])
+ share_instances_export_locations = []
+ for share_instance in self.share_instances:
+ share_instance_export_locations = (
+ self.admin_client.list_share_instance_export_locations(
+ share_instance['id']))
+ share_instances_export_locations.extend(
+ share_instance_export_locations)
+
+ self.assertEqual(
+ len(share_export_locations),
+ 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'])
+ )
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
new file mode 100644
index 0000000..9d53373
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_export_locations_negative.py
@@ -0,0 +1,94 @@
+# Copyright 2015 Mirantis Inc.
+# 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 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
+
+CONF = config.CONF
+
+
+@base.skip_if_microversion_not_supported("2.9")
+class ExportLocationsNegativeTest(base.BaseSharesAdminTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(ExportLocationsNegativeTest, cls).resource_setup()
+ cls.admin_client = cls.shares_v2_client
+ cls.member_client = clients.Manager().shares_v2_client
+ cls.share = cls.create_share()
+ cls.share = cls.shares_v2_client.get_share(cls.share['id'])
+ cls.share_instances = cls.shares_v2_client.get_instances_of_share(
+ cls.share['id'])
+
+ @test.attr(type=["gate", "negative"])
+ def test_get_export_locations_by_inexistent_share(self):
+ self.assertRaises(
+ lib_exc.NotFound,
+ self.admin_client.list_share_export_locations,
+ "fake-inexistent-share-id",
+ )
+
+ @test.attr(type=["gate", "negative"])
+ def test_get_inexistent_share_export_location(self):
+ self.assertRaises(
+ lib_exc.NotFound,
+ self.admin_client.get_share_export_location,
+ self.share['id'],
+ "fake-inexistent-share-instance-id",
+ )
+
+ @test.attr(type=["gate", "negative"])
+ def test_get_export_locations_by_inexistent_share_instance(self):
+ self.assertRaises(
+ lib_exc.NotFound,
+ self.admin_client.list_share_instance_export_locations,
+ "fake-inexistent-share-instance-id",
+ )
+
+ @test.attr(type=["gate", "negative"])
+ def test_get_inexistent_share_instance_export_location(self):
+ for share_instance in self.share_instances:
+ self.assertRaises(
+ lib_exc.NotFound,
+ self.admin_client.get_share_instance_export_location,
+ share_instance['id'],
+ "fake-inexistent-share-instance-id",
+ )
+
+ @test.attr(type=["gate", "negative"])
+ def test_list_share_instance_export_locations_by_member(self):
+ for share_instance in self.share_instances:
+ self.assertRaises(
+ lib_exc.Forbidden,
+ self.member_client.list_share_instance_export_locations,
+ "fake-inexistent-share-instance-id",
+ )
+
+ @test.attr(type=["gate", "negative"])
+ def test_get_share_instance_export_location_by_member(self):
+ for share_instance in self.share_instances:
+ export_locations = (
+ self.admin_client.list_share_instance_export_locations(
+ share_instance['id']))
+ for el in export_locations:
+ self.assertRaises(
+ lib_exc.Forbidden,
+ self.member_client.get_share_instance_export_location,
+ share_instance['id'], el['uuid'],
+ )
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 86d8b61..4e69eda 100644
--- a/manila_tempest_tests/tests/api/admin/test_multi_backend.py
+++ b/manila_tempest_tests/tests/api/admin/test_multi_backend.py
@@ -81,26 +81,6 @@
self.assertEqual(self.sts[i]["name"], get["share_type_name"])
@test.attr(type=["gate", ])
- def test_share_export_locations(self):
- # Different backends have different IPs on interfaces
- # and export locations should be different too.
- if CONF.share.backend_names[0] == CONF.share.backend_names[1]:
- raise self.skipException("Share backends "
- "configured with same name. Skipping.")
- ips = []
- for share in self.shares:
- get = self.shares_client.get_share(share['id'])
- if get["share_proto"].lower() == "nfs":
- # %ip%:/%share_path%
- ip = get["export_location"].split(":")[0]
- ips.append(ip)
- elif get["share_proto"].lower() == "cifs":
- # //%ip%/%share_path%
- ip = get["export_location"][2:].split("/")[0]
- ips.append(ip)
- self.assertNotEqual(ips[0], ips[1])
-
- @test.attr(type=["gate", ])
def test_share_backend_name_distinction(self):
# Different share backends should have different host records
if CONF.share.backend_names[0] == CONF.share.backend_names[1]:
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 576e499..973e52e 100644
--- a/manila_tempest_tests/tests/api/admin/test_scheduler_stats.py
+++ b/manila_tempest_tests/tests/api/admin/test_scheduler_stats.py
@@ -140,4 +140,4 @@
self.assertEmpty(pool_list)
def _wrap_regex_for_exact_match(self, regex):
- return '^%s$' % regex
\ No newline at end of file
+ return '^%s$' % regex
diff --git a/manila_tempest_tests/tests/api/admin/test_share_instances.py b/manila_tempest_tests/tests/api/admin/test_share_instances.py
index 1202b9d..248d145 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_instances.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_instances.py
@@ -17,6 +17,7 @@
from tempest import test
from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
CONF = config.CONF
@@ -58,21 +59,38 @@
msg = 'Share instance for share %s was not found.' % self.share['id']
self.assertIn(self.share['id'], share_ids, msg)
- @test.attr(type=["gate", ])
- def test_get_share_instance_v2_3(self):
+ def _get_share_instance(self, version):
"""Test that we get the proper keys back for the instance."""
share_instances = self.shares_v2_client.get_instances_of_share(
- self.share['id'], version='2.3'
+ self.share['id'], version=version,
)
- si = self.shares_v2_client.get_share_instance(share_instances[0]['id'],
- version='2.3')
- expected_keys = ['host', 'share_id', 'id', 'share_network_id',
- 'status', 'availability_zone', 'share_server_id',
- 'export_locations', 'export_location', 'created_at']
- actual_keys = si.keys()
- self.assertEqual(sorted(expected_keys), sorted(actual_keys),
+ si = self.shares_v2_client.get_share_instance(
+ share_instances[0]['id'], version=version)
+
+ expected_keys = [
+ 'host', 'share_id', 'id', 'share_network_id', 'status',
+ 'availability_zone', 'share_server_id', 'created_at',
+ ]
+ if utils.is_microversion_lt(version, '2.9'):
+ expected_keys.extend(["export_location", "export_locations"])
+ if utils.is_microversion_ge(version, '2.10'):
+ expected_keys.append("access_rules_status")
+ expected_keys = sorted(expected_keys)
+ actual_keys = sorted(si.keys())
+ self.assertEqual(expected_keys, actual_keys,
'Share instance %s returned incorrect keys; '
- 'expected %s, got %s.' % (si['id'],
- sorted(expected_keys),
- sorted(actual_keys)))
+ 'expected %s, got %s.' % (
+ si['id'], expected_keys, actual_keys))
+
+ @test.attr(type=["gate", ])
+ def test_get_share_instance_v2_3(self):
+ self._get_share_instance('2.3')
+
+ @test.attr(type=["gate", ])
+ def test_get_share_instance_v2_9(self):
+ self._get_share_instance('2.9')
+
+ @test.attr(type=["gate", ])
+ def test_get_share_instance_v2_10(self):
+ self._get_share_instance('2.10')
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 c7efa01..bbd98bc 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_manage.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_manage.py
@@ -147,6 +147,13 @@
@test.attr(type=["gate", "smoke"])
def test_manage(self):
+ # After 'unmanage' operation, share instance should be deleted.
+ # Assert not related to 'manage' test, but placed here for
+ # resource optimization.
+ share_instance_list = self.shares_v2_client.list_share_instances()
+ share_ids = [si['share_id'] for si in share_instance_list]
+ self.assertNotIn(self.shares[0]['id'], share_ids)
+
self._test_manage(share=self.shares[0])
@test.attr(type=["gate", "smoke"])
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index b9763fb..f9a678d 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -208,8 +208,8 @@
def setUp(self):
super(BaseSharesTest, self).setUp()
- self.addCleanup(self.clear_resources)
self.addCleanup(self.clear_isolated_creds)
+ self.addCleanup(self.clear_resources)
@classmethod
def resource_cleanup(cls):
@@ -338,7 +338,8 @@
def migrate_share(cls, share_id, dest_host, client=None, **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)
+ share = client.wait_for_migration_completed(
+ share_id, dest_host, version=kwargs.get('version'))
return share
@classmethod
diff --git a/manila_tempest_tests/tests/api/test_rules.py b/manila_tempest_tests/tests/api/test_rules.py
index de08b86..0b0bc08 100644
--- a/manila_tempest_tests/tests/api/test_rules.py
+++ b/manila_tempest_tests/tests/api/test_rules.py
@@ -13,34 +13,57 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest import config # noqa
-from tempest import test # noqa
-from tempest_lib import exceptions as lib_exc # noqa
-import testtools # noqa
+import ddt
+from tempest import config
+from tempest import test
+from tempest_lib import exceptions as lib_exc
+import testtools
from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
CONF = config.CONF
+LATEST_MICROVERSION = CONF.share.max_api_microversion
-def _create_delete_ro_access_rule(self):
+def _create_delete_ro_access_rule(self, version):
"""Common test case for usage in test suites with different decorators.
:param self: instance of test class
"""
- rule = self.shares_client.create_access_rule(
- self.share["id"], self.access_type, self.access_to, 'ro')
+
+ if utils.is_microversion_eq(version, '1.0'):
+ rule = self.shares_client.create_access_rule(
+ self.share["id"], self.access_type, self.access_to, 'ro')
+ else:
+ rule = self.shares_v2_client.create_access_rule(
+ self.share["id"], self.access_type, self.access_to, 'ro',
+ version=version)
self.assertEqual('ro', rule['access_level'])
for key in ('deleted', 'deleted_at', 'instance_mappings'):
self.assertNotIn(key, rule.keys())
- self.shares_client.wait_for_access_rule_status(
- self.share["id"], rule["id"], "active")
- self.shares_client.delete_access_rule(self.share["id"], rule["id"])
- self.shares_client.wait_for_resource_deletion(
- rule_id=rule["id"], share_id=self.share['id'])
+
+ if utils.is_microversion_le(version, '2.9'):
+ self.shares_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ else:
+ self.shares_v2_client.wait_for_share_status(
+ self.share["id"], "active", status_attr='access_rules_status',
+ version=version)
+
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.delete_access_rule(self.share["id"], rule["id"])
+ self.shares_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'])
+ else:
+ self.shares_v2_client.delete_access_rule(
+ self.share["id"], rule["id"], version=version)
+ self.shares_v2_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'], version=version)
+@ddt.ddt
class ShareIpRulesForNFSTest(base.BaseSharesTest):
protocol = "nfs"
@@ -56,55 +79,99 @@
cls.access_to = "2.2.2.2"
@test.attr(type=["gate", ])
- def test_create_delete_access_rules_with_one_ip(self):
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_create_delete_access_rules_with_one_ip(self, version):
# test data
access_to = "1.1.1.1"
# create rule
- rule = self.shares_client.create_access_rule(
- self.share["id"], self.access_type, access_to)
+ if utils.is_microversion_eq(version, '1.0'):
+ rule = self.shares_client.create_access_rule(
+ self.share["id"], self.access_type, access_to)
+ else:
+ rule = self.shares_v2_client.create_access_rule(
+ self.share["id"], self.access_type, access_to,
+ version=version)
self.assertEqual('rw', rule['access_level'])
for key in ('deleted', 'deleted_at', 'instance_mappings'):
self.assertNotIn(key, rule.keys())
- self.shares_client.wait_for_access_rule_status(
- self.share["id"], rule["id"], "active")
+
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ elif utils.is_microversion_eq(version, '2.9'):
+ self.shares_v2_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ else:
+ self.shares_v2_client.wait_for_share_status(
+ self.share["id"], "active", status_attr='access_rules_status',
+ version=version)
# delete rule and wait for deletion
- self.shares_client.delete_access_rule(self.share["id"], rule["id"])
- self.shares_client.wait_for_resource_deletion(
- rule_id=rule["id"], share_id=self.share['id'])
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.delete_access_rule(self.share["id"], rule["id"])
+ self.shares_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'])
+ else:
+ self.shares_v2_client.delete_access_rule(
+ self.share["id"], rule["id"], version=version)
+ self.shares_v2_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'], version=version)
@test.attr(type=["gate", ])
- def test_create_delete_access_rule_with_cidr(self):
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_create_delete_access_rule_with_cidr(self, version):
# test data
access_to = "1.2.3.4/32"
# create rule
- rule = self.shares_client.create_access_rule(
- self.share["id"], self.access_type, access_to)
+ if utils.is_microversion_eq(version, '1.0'):
+ rule = self.shares_client.create_access_rule(
+ self.share["id"], self.access_type, access_to)
+ else:
+ rule = self.shares_v2_client.create_access_rule(
+ self.share["id"], self.access_type, access_to,
+ version=version)
for key in ('deleted', 'deleted_at', 'instance_mappings'):
self.assertNotIn(key, rule.keys())
self.assertEqual('rw', rule['access_level'])
- self.shares_client.wait_for_access_rule_status(
- self.share["id"], rule["id"], "active")
+
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ elif utils.is_microversion_eq(version, '2.9'):
+ self.shares_v2_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ else:
+ self.shares_v2_client.wait_for_share_status(
+ self.share["id"], "active", status_attr='access_rules_status',
+ version=version)
# delete rule and wait for deletion
- self.shares_client.delete_access_rule(self.share["id"], rule["id"])
- self.shares_client.wait_for_resource_deletion(
- rule_id=rule["id"], share_id=self.share['id'])
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.delete_access_rule(self.share["id"], rule["id"])
+ self.shares_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'])
+ else:
+ self.shares_v2_client.delete_access_rule(
+ self.share["id"], rule["id"], version=version)
+ self.shares_v2_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'], version=version)
@test.attr(type=["gate", ])
@testtools.skipIf(
"nfs" not in CONF.share.enable_ro_access_level_for_protocols,
"RO access rule tests are disabled for NFS protocol.")
- def test_create_delete_ro_access_rule(self):
- _create_delete_ro_access_rule(self)
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_create_delete_ro_access_rule(self, client_name):
+ _create_delete_ro_access_rule(self, client_name)
+@ddt.ddt
class ShareIpRulesForCIFSTest(ShareIpRulesForNFSTest):
protocol = "cifs"
@@ -112,10 +179,12 @@
@testtools.skipIf(
"cifs" not in CONF.share.enable_ro_access_level_for_protocols,
"RO access rule tests are disabled for CIFS protocol.")
- def test_create_delete_ro_access_rule(self):
- _create_delete_ro_access_rule(self)
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_create_delete_ro_access_rule(self, version):
+ _create_delete_ro_access_rule(self, version)
+@ddt.ddt
class ShareUserRulesForNFSTest(base.BaseSharesTest):
protocol = "nfs"
@@ -132,31 +201,54 @@
cls.access_to = CONF.share.username_for_user_rules
@test.attr(type=["gate", ])
- def test_create_delete_user_rule(self):
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_create_delete_user_rule(self, version):
# create rule
- rule = self.shares_client.create_access_rule(
- self.share["id"], self.access_type, self.access_to)
+ if utils.is_microversion_eq(version, '1.0'):
+ rule = self.shares_client.create_access_rule(
+ self.share["id"], self.access_type, self.access_to)
+ else:
+ rule = self.shares_v2_client.create_access_rule(
+ self.share["id"], self.access_type, self.access_to,
+ version=version)
self.assertEqual('rw', rule['access_level'])
for key in ('deleted', 'deleted_at', 'instance_mappings'):
self.assertNotIn(key, rule.keys())
- self.shares_client.wait_for_access_rule_status(
- self.share["id"], rule["id"], "active")
+
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ elif utils.is_microversion_eq(version, '2.9'):
+ self.shares_v2_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ else:
+ self.shares_v2_client.wait_for_share_status(
+ self.share["id"], "active", status_attr='access_rules_status',
+ version=version)
# delete rule and wait for deletion
- self.shares_client.delete_access_rule(self.share["id"], rule["id"])
- self.shares_client.wait_for_resource_deletion(
- rule_id=rule["id"], share_id=self.share['id'])
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.delete_access_rule(self.share["id"], rule["id"])
+ self.shares_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'])
+ else:
+ self.shares_v2_client.delete_access_rule(
+ self.share["id"], rule["id"], version=version)
+ self.shares_v2_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'], version=version)
@test.attr(type=["gate", ])
@testtools.skipIf(
"nfs" not in CONF.share.enable_ro_access_level_for_protocols,
"RO access rule tests are disabled for NFS protocol.")
- def test_create_delete_ro_access_rule(self):
- _create_delete_ro_access_rule(self)
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_create_delete_ro_access_rule(self, version):
+ _create_delete_ro_access_rule(self, version)
+@ddt.ddt
class ShareUserRulesForCIFSTest(ShareUserRulesForNFSTest):
protocol = "cifs"
@@ -164,10 +256,12 @@
@testtools.skipIf(
"cifs" not in CONF.share.enable_ro_access_level_for_protocols,
"RO access rule tests are disabled for CIFS protocol.")
- def test_create_delete_ro_access_rule(self):
- _create_delete_ro_access_rule(self)
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_create_delete_ro_access_rule(self, version):
+ _create_delete_ro_access_rule(self, version)
+@ddt.ddt
class ShareCertRulesForGLUSTERFSTest(base.BaseSharesTest):
protocol = "glusterfs"
@@ -186,37 +280,85 @@
cls.access_to = "client1.com"
@test.attr(type=["gate", ])
- def test_create_delete_cert_rule(self):
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_create_delete_cert_rule(self, version):
# create rule
- rule = self.shares_client.create_access_rule(
- self.share["id"], self.access_type, self.access_to)
+ if utils.is_microversion_eq(version, '1.0'):
+ rule = self.shares_client.create_access_rule(
+ self.share["id"], self.access_type, self.access_to)
+ else:
+ rule = self.shares_v2_client.create_access_rule(
+ self.share["id"], self.access_type, self.access_to,
+ version=version)
self.assertEqual('rw', rule['access_level'])
for key in ('deleted', 'deleted_at', 'instance_mappings'):
self.assertNotIn(key, rule.keys())
- self.shares_client.wait_for_access_rule_status(
- self.share["id"], rule["id"], "active")
+
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ elif utils.is_microversion_eq(version, '2.9'):
+ self.shares_v2_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ else:
+ self.shares_v2_client.wait_for_share_status(
+ self.share["id"], "active", status_attr='access_rules_status',
+ version=version)
# delete rule
- self.shares_client.delete_access_rule(self.share["id"], rule["id"])
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.delete_access_rule(self.share["id"], rule["id"])
+ self.shares_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'])
+ else:
+ self.shares_v2_client.delete_access_rule(
+ self.share["id"], rule["id"], version=version)
+ self.shares_v2_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'], version=version)
@test.attr(type=["gate", ])
@testtools.skipIf(
"glusterfs" not in CONF.share.enable_ro_access_level_for_protocols,
"RO access rule tests are disabled for GLUSTERFS protocol.")
- def test_create_delete_cert_ro_access_rule(self):
- rule = self.shares_client.create_access_rule(
- self.share["id"], 'cert', 'client2.com', 'ro')
+ @ddt.data('1.0', '2.9', 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(
+ self.share["id"], 'cert', 'client2.com', 'ro')
+ else:
+ rule = self.shares_v2_client.create_access_rule(
+ self.share["id"], 'cert', 'client2.com', 'ro',
+ version=version)
self.assertEqual('ro', rule['access_level'])
for key in ('deleted', 'deleted_at', 'instance_mappings'):
self.assertNotIn(key, rule.keys())
- self.shares_client.wait_for_access_rule_status(
- self.share["id"], rule["id"], "active")
- self.shares_client.delete_access_rule(self.share["id"], rule["id"])
+
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ elif utils.is_microversion_eq(version, '2.9'):
+ self.shares_v2_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ else:
+ self.shares_v2_client.wait_for_share_status(
+ self.share["id"], "active", status_attr='access_rules_status',
+ version=version)
+
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.delete_access_rule(self.share["id"], rule["id"])
+ self.shares_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'])
+ else:
+ self.shares_v2_client.delete_access_rule(
+ self.share["id"], rule["id"], version=version)
+ self.shares_v2_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'], version=version)
+@ddt.ddt
class ShareRulesTest(base.BaseSharesTest):
@classmethod
@@ -230,50 +372,59 @@
for p in cls.protocols)):
cls.message = "Rule tests are disabled"
raise cls.skipException(cls.message)
+ if CONF.share.enable_ip_rules_for_protocols:
+ cls.protocol = CONF.share.enable_ip_rules_for_protocols[0]
+ cls.access_type = "ip"
+ cls.access_to = "8.8.8.8"
+ elif CONF.share.enable_user_rules_for_protocols:
+ cls.protocol = CONF.share.enable_user_rules_for_protocols[0]
+ cls.access_type = "user"
+ cls.access_to = CONF.share.username_for_user_rules
+ elif CONF.share.enable_cert_rules_for_protocols:
+ cls.protocol = CONF.share.enable_cert_rules_for_protocols[0]
+ cls.access_type = "cert"
+ cls.access_to = "client3.com"
+ cls.shares_v2_client.share_protocol = cls.protocol
cls.share = cls.create_share()
- def setUp(self):
- # Here we choose protocol and rule type for
- # testing common rules functionality,
- # that isn't dependent on protocol or rule type.
- super(ShareRulesTest, self).setUp()
- if CONF.share.enable_ip_rules_for_protocols:
- self.access_type = "ip"
- self.access_to = "8.8.8.8"
- protocol = CONF.share.enable_ip_rules_for_protocols[0]
- elif CONF.share.enable_user_rules_for_protocols:
- self.access_type = "user"
- self.access_to = CONF.share.username_for_user_rules
- protocol = CONF.share.enable_user_rules_for_protocols[0]
- elif CONF.share.enable_cert_rules_for_protocols:
- self.access_type = "cert"
- self.access_to = "client3.com"
- protocol = CONF.share.enable_cert_rules_for_protocols[0]
- else:
- raise self.skipException(self.message)
- self.shares_client.protocol = protocol
-
@test.attr(type=["gate", ])
- def test_list_access_rules(self):
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_list_access_rules(self, version):
# create rule
- rule = self.shares_client.create_access_rule(
- self.share["id"], self.access_type, self.access_to)
+ if utils.is_microversion_eq(version, '1.0'):
+ rule = self.shares_client.create_access_rule(
+ self.share["id"], self.access_type, self.access_to)
+ else:
+ rule = self.shares_v2_client.create_access_rule(
+ self.share["id"], self.access_type, self.access_to,
+ version=version)
- self.shares_client.wait_for_access_rule_status(
- self.share["id"], rule["id"], "active")
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ elif utils.is_microversion_eq(version, '2.9'):
+ self.shares_v2_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ else:
+ self.shares_v2_client.wait_for_share_status(
+ self.share["id"], "active", status_attr='access_rules_status',
+ version=version)
# list rules
- rules = self.shares_client.list_access_rules(self.share["id"])
+ if utils.is_microversion_eq(version, '1.0'):
+ rules = self.shares_client.list_access_rules(self.share["id"])
+ else:
+ rules = self.shares_v2_client.list_access_rules(self.share["id"],
+ version=version)
# verify keys
- for key in ("state", "id", "access_type", "access_to", "access_level"):
+ for key in ("id", "access_type", "access_to", "access_level"):
[self.assertIn(key, r.keys()) for r in rules]
for key in ('deleted', 'deleted_at', 'instance_mappings'):
[self.assertNotIn(key, r.keys()) for r in rules]
# verify values
- self.assertEqual("active", rules[0]["state"])
self.assertEqual(self.access_type, rules[0]["access_type"])
self.assertEqual(self.access_to, rules[0]["access_to"])
self.assertEqual('rw', rules[0]["access_level"])
@@ -283,23 +434,58 @@
msg = "expected id lists %s times in rule list" % (len(gen))
self.assertEqual(1, len(gen), msg)
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.delete_access_rule(self.share["id"], rule["id"])
+ self.shares_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'])
+ else:
+ self.shares_v2_client.delete_access_rule(
+ self.share["id"], rule["id"], version=version)
+ self.shares_v2_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share['id'], version=version)
+
@test.attr(type=["gate", ])
- def test_access_rules_deleted_if_share_deleted(self):
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_access_rules_deleted_if_share_deleted(self, version):
# create share
share = self.create_share()
# create rule
- rule = self.shares_client.create_access_rule(
- share["id"], self.access_type, self.access_to)
- self.shares_client.wait_for_access_rule_status(
- share["id"], rule["id"], "active")
+ if utils.is_microversion_eq(version, '1.0'):
+ rule = self.shares_client.create_access_rule(
+ share["id"], self.access_type, self.access_to)
+ else:
+ rule = self.shares_v2_client.create_access_rule(
+ share["id"], self.access_type, self.access_to,
+ version=version)
+
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.wait_for_access_rule_status(
+ share["id"], rule["id"], "active")
+ elif utils.is_microversion_eq(version, '2.9'):
+ self.shares_v2_client.wait_for_access_rule_status(
+ share["id"], rule["id"], "active")
+ else:
+ self.shares_v2_client.wait_for_share_status(
+ share["id"], "active", status_attr='access_rules_status',
+ version=version)
# delete share
- self.shares_client.delete_share(share['id'])
- self.shares_client.wait_for_resource_deletion(share_id=share['id'])
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.delete_share(share['id'])
+ self.shares_client.wait_for_resource_deletion(share_id=share['id'])
+ else:
+ self.shares_v2_client.delete_share(share['id'], version=version)
+ self.shares_v2_client.wait_for_resource_deletion(
+ share_id=share['id'], version=version)
# verify absence of rules for nonexistent share id
- self.assertRaises(lib_exc.NotFound,
- self.shares_client.list_access_rules,
- share['id'])
+ if utils.is_microversion_eq(version, '1.0'):
+ self.assertRaises(lib_exc.NotFound,
+ self.shares_client.list_access_rules,
+ share['id'])
+ else:
+ self.assertRaises(lib_exc.NotFound,
+ self.shares_v2_client.list_access_rules,
+ share['id'], version)
diff --git a/manila_tempest_tests/tests/api/test_rules_negative.py b/manila_tempest_tests/tests/api/test_rules_negative.py
index 6ad36ba..47f5a52 100644
--- a/manila_tempest_tests/tests/api/test_rules_negative.py
+++ b/manila_tempest_tests/tests/api/test_rules_negative.py
@@ -13,16 +13,20 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest import config # noqa
-from tempest import test # noqa
-from tempest_lib import exceptions as lib_exc # noqa
-import testtools # noqa
+import ddt
+from tempest import config
+from tempest import test
+from tempest_lib import exceptions as lib_exc
+import testtools
from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
CONF = config.CONF
+LATEST_MICROVERSION = CONF.share.max_api_microversion
+@ddt.ddt
class ShareIpRulesForNFSNegativeTest(base.BaseSharesTest):
protocol = "nfs"
@@ -40,84 +44,127 @@
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_ip_with_wrong_target_1(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_ip_with_wrong_target_1(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "ip", "1.2.3.256")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_ip_with_wrong_target_2(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_ip_with_wrong_target_2(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "ip", "1.1.1.-")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_ip_with_wrong_target_3(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_ip_with_wrong_target_3(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "ip", "1.2.3.4/33")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_ip_with_wrong_target_4(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_ip_with_wrong_target_4(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "ip", "1.2.3.*")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_ip_with_wrong_target_5(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_ip_with_wrong_target_5(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "ip", "1.2.3.*/23")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_ip_with_wrong_target_6(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_ip_with_wrong_target_6(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "ip", "1.2.3.1|23")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_ip_with_wrong_target_7(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_ip_with_wrong_target_7(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "ip", "1.2.3.1/-1")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_ip_with_wrong_target_8(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_ip_with_wrong_target_8(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "ip", "1.2.3.1/")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_with_wrong_level(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_with_wrong_level(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"],
'ip',
'2.2.2.2',
'su')
@test.attr(type=["negative", "gate", ])
- def test_create_duplicate_of_ip_rule(self):
+ @ddt.data('1.0', '2.9', LATEST_MICROVERSION)
+ def test_create_duplicate_of_ip_rule(self, version):
# test data
access_type = "ip"
access_to = "1.2.3.4"
# create rule
- rule = self.shares_client.create_access_rule(
- self.share["id"], access_type, access_to)
- self.shares_client.wait_for_access_rule_status(
- self.share["id"], rule["id"], "active")
+ if utils.is_microversion_eq(version, '1.0'):
+ rule = self.shares_client.create_access_rule(
+ self.share["id"], access_type, access_to)
+ else:
+ rule = self.shares_v2_client.create_access_rule(
+ self.share["id"], access_type, access_to, version=version)
+
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ elif utils.is_microversion_eq(version, '2.9'):
+ self.shares_v2_client.wait_for_access_rule_status(
+ self.share["id"], rule["id"], "active")
+ else:
+ self.shares_v2_client.wait_for_share_status(
+ self.share["id"], "active", status_attr='access_rules_status',
+ version=version)
# try create duplicate of rule
- self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
- self.share["id"], access_type, access_to)
+ if utils.is_microversion_eq(version, '1.0'):
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_client.create_access_rule,
+ self.share["id"], access_type, access_to)
+ else:
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_v2_client.create_access_rule,
+ self.share["id"], access_type, access_to,
+ version=version)
+
+ # delete rule and wait for deletion
+ if utils.is_microversion_eq(version, '1.0'):
+ self.shares_client.delete_access_rule(self.share["id"],
+ rule["id"])
+ self.shares_client.wait_for_resource_deletion(
+ rule_id=rule["id"], share_id=self.share["id"])
+ else:
+ 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"], version=version)
+@ddt.ddt
class ShareIpRulesForCIFSNegativeTest(ShareIpRulesForNFSNegativeTest):
protocol = "cifs"
+@ddt.ddt
class ShareUserRulesForNFSNegativeTest(base.BaseSharesTest):
protocol = "nfs"
@@ -135,69 +182,79 @@
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_user_with_wrong_input_2(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_user_with_wrong_input_2(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "user",
"try+")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_user_with_empty_key(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_user_with_empty_key(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "user", "")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_user_with_too_little_key(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_user_with_too_little_key(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "user", "abc")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_user_with_too_big_key(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_user_with_too_big_key(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "user", "a" * 33)
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_user_with_wrong_input_1(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_user_with_wrong_input_1(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "user",
"try+")
@test.attr(type=["negative", "gate", ])
+ @ddt.data('shares_client', 'shares_v2_client')
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
- def test_create_access_rule_user_to_snapshot(self):
+ def test_create_access_rule_user_to_snapshot(self, client_name):
self.assertRaises(lib_exc.NotFound,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.snap["id"],
access_type="user",
access_to="fakeuser")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_user_with_wrong_share_id(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_user_with_wrong_share_id(self, client_name):
self.assertRaises(lib_exc.NotFound,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
"wrong_share_id",
access_type="user",
access_to="fakeuser")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_with_wrong_level(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_with_wrong_level(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"],
'user',
CONF.share.username_for_user_rules,
'su')
+@ddt.ddt
class ShareUserRulesForCIFSNegativeTest(ShareUserRulesForNFSNegativeTest):
protocol = "cifs"
+@ddt.ddt
class ShareCertRulesForGLUSTERFSNegativeTest(base.BaseSharesTest):
protocol = "glusterfs"
@@ -215,43 +272,51 @@
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_cert_with_empty_common_name(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_cert_with_empty_common_name(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "cert", "")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_cert_with_whitespace_common_name(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_cert_with_whitespace_common_name(self,
+ client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "cert", " ")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_cert_with_too_big_common_name(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_cert_with_too_big_common_name(self,
+ client_name):
# common name cannot be more than 64 characters long
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "cert", "a" * 65)
@test.attr(type=["negative", "gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
- def test_create_access_rule_cert_to_snapshot(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_cert_to_snapshot(self, client_name):
self.assertRaises(lib_exc.NotFound,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.snap["id"],
access_type="cert",
access_to="fakeclient1.com")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_cert_with_wrong_share_id(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_cert_with_wrong_share_id(self, client_name):
self.assertRaises(lib_exc.NotFound,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
"wrong_share_id",
access_type="cert",
access_to="fakeclient2.com")
+@ddt.ddt
class ShareRulesNegativeTest(base.BaseSharesTest):
# Tests independent from rule type and share protocol
@@ -273,27 +338,31 @@
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
@test.attr(type=["negative", "gate", ])
- def test_delete_access_rule_with_wrong_id(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_delete_access_rule_with_wrong_id(self, client_name):
self.assertRaises(lib_exc.NotFound,
- self.shares_client.delete_access_rule,
+ getattr(self, client_name).delete_access_rule,
self.share["id"], "wrong_rule_id")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_ip_with_wrong_type(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_ip_with_wrong_type(self, client_name):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.share["id"], "wrong_type", "1.2.3.4")
@test.attr(type=["negative", "gate", ])
- def test_create_access_rule_ip_with_wrong_share_id(self):
+ @ddt.data('shares_client', 'shares_v2_client')
+ def test_create_access_rule_ip_with_wrong_share_id(self, client_name):
self.assertRaises(lib_exc.NotFound,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
"wrong_share_id")
@test.attr(type=["negative", "gate", ])
+ @ddt.data('shares_client', 'shares_v2_client')
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
- def test_create_access_rule_ip_to_snapshot(self):
+ def test_create_access_rule_ip_to_snapshot(self, client_name):
self.assertRaises(lib_exc.NotFound,
- self.shares_client.create_access_rule,
+ getattr(self, client_name).create_access_rule,
self.snap["id"])
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 de0064c..834deb5 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
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from oslo_log import log # noqa
+import six # noqa
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
@@ -21,6 +23,7 @@
from manila_tempest_tests.tests.api import base
CONF = config.CONF
+LOG = log.getLogger(__name__)
class SecServicesMappingNegativeTest(base.BaseSharesTest):
@@ -99,8 +102,21 @@
self.shares_client.add_sec_service_to_share_network(
fresh_sn["id"], self.ss["id"])
- self.create_share(
- share_network_id=fresh_sn["id"], cleanup_in_class=False)
+
+ # Security service with fake data is used, so if we use backend driver
+ # that fails on wrong data, we expect error here.
+ # We require any share that uses our share-network.
+ try:
+ self.create_share(
+ share_network_id=fresh_sn["id"], cleanup_in_class=False)
+ except Exception as e:
+ # we do wait for either 'error' or 'available' status because
+ # it is the only available statuses for proper deletion.
+ LOG.warning("Caught exception. It is expected in case backend "
+ "fails having security-service with improper data "
+ "that leads to share-server creation error. "
+ "%s" % six.text_type(e))
+
self.assertRaises(lib_exc.Forbidden,
self.cl.remove_sec_service_from_share_network,
fresh_sn["id"],
diff --git a/manila_tempest_tests/tests/api/test_shares.py b/manila_tempest_tests/tests/api/test_shares.py
index 1cf081e..2527aa9 100644
--- a/manila_tempest_tests/tests/api/test_shares.py
+++ b/manila_tempest_tests/tests/api/test_shares.py
@@ -19,6 +19,7 @@
import testtools # noqa
from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
CONF = config.CONF
@@ -40,7 +41,7 @@
share = self.create_share(self.protocol)
detailed_elements = {'name', 'id', 'availability_zone',
- 'description', 'export_location', 'project_id',
+ 'description', 'project_id',
'host', 'created_at', 'share_proto', 'metadata',
'size', 'snapshot_id', 'share_network_id',
'status', 'share_type', 'volume_type', 'links',
@@ -55,8 +56,13 @@
self.assertTrue(detailed_elements.issubset(share.keys()), msg)
self.assertFalse(share['is_public'])
+ # The 'status' of the share returned by the create API must be
+ # the default value - 'creating'.
+ self.assertEqual('creating', share['status'])
+
# Get share using v 2.1 - we expect key 'snapshot_support' to be absent
share_get = self.shares_v2_client.get_share(share['id'], version='2.1')
+ detailed_elements.add('export_location')
self.assertTrue(detailed_elements.issubset(share_get.keys()), msg)
# Get share using v 2.2 - we expect key 'snapshot_support' to exist
@@ -64,6 +70,14 @@
detailed_elements.add('snapshot_support')
self.assertTrue(detailed_elements.issubset(share_get.keys()), msg)
+ if utils.is_microversion_supported('2.9'):
+ # Get share using v 2.9 - key 'export_location' is expected
+ # to be absent
+ share_get = self.shares_v2_client.get_share(
+ share['id'], version='2.9')
+ detailed_elements.remove('export_location')
+ self.assertTrue(detailed_elements.issubset(share_get.keys()), msg)
+
# Delete share
self.shares_v2_client.delete_share(share['id'])
self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
@@ -107,6 +121,10 @@
s2 = self.create_share(
self.protocol, snapshot_id=snap["id"], cleanup_in_class=False)
+ # The 'status' of the share returned by the create API must be
+ # the default value - 'creating'.
+ self.assertEqual('creating', s2['status'])
+
# verify share, created from snapshot
get = self.shares_client.get_share(s2["id"])
msg = "Expected snapshot_id %s as "\
@@ -133,6 +151,10 @@
child = self.create_share(
self.protocol, snapshot_id=snap["id"], cleanup_in_class=False)
+ # The 'status' of the share returned by the create API must be
+ # the default value - 'creating'.
+ self.assertEqual('creating', child['status'])
+
# verify share, created from snapshot
get = self.shares_client.get_share(child["id"])
keys = {
diff --git a/manila_tempest_tests/tests/api/test_shares_actions.py b/manila_tempest_tests/tests/api/test_shares_actions.py
index 9d7fc7f..f249efb 100644
--- a/manila_tempest_tests/tests/api/test_shares_actions.py
+++ b/manila_tempest_tests/tests/api/test_shares_actions.py
@@ -82,11 +82,12 @@
# verify keys
expected_keys = [
"status", "description", "links", "availability_zone",
- "created_at", "export_location", "project_id",
- "export_locations", "volume_type", "share_proto", "name",
+ "created_at", "project_id", "volume_type", "share_proto", "name",
"snapshot_id", "id", "size", "share_network_id", "metadata",
"host", "snapshot_id", "is_public",
]
+ if utils.is_microversion_lt(version, '2.9'):
+ expected_keys.extend(["export_location", "export_locations"])
if utils.is_microversion_ge(version, '2.2'):
expected_keys.append("snapshot_support")
if utils.is_microversion_ge(version, '2.4'):
@@ -94,6 +95,8 @@
"source_cgsnapshot_member_id"])
if utils.is_microversion_ge(version, '2.5'):
expected_keys.append("share_type_name")
+ if utils.is_microversion_ge(version, '2.10'):
+ expected_keys.append("access_rules_status")
actual_keys = list(share.keys())
[self.assertIn(key, actual_keys) for key in expected_keys]
@@ -131,10 +134,20 @@
self._get_share('2.6')
@test.attr(type=["gate", ])
+ @utils.skip_if_microversion_not_supported('2.9')
+ def test_get_share_export_locations_removed(self):
+ self._get_share('2.9')
+
+ @test.attr(type=["gate", ])
+ @utils.skip_if_microversion_not_supported('2.10')
+ def test_get_share_with_access_rules_status(self):
+ self._get_share('2.10')
+
+ @test.attr(type=["gate", ])
def test_list_shares(self):
# list shares
- shares = self.shares_client.list_shares()
+ shares = self.shares_v2_client.list_shares()
# verify keys
keys = ["name", "id", "links"]
@@ -155,11 +168,12 @@
# verify keys
keys = [
"status", "description", "links", "availability_zone",
- "created_at", "export_location", "project_id",
- "export_locations", "volume_type", "share_proto", "name",
+ "created_at", "project_id", "volume_type", "share_proto", "name",
"snapshot_id", "id", "size", "share_network_id", "metadata",
"host", "snapshot_id", "is_public", "share_type",
]
+ if utils.is_microversion_lt(version, '2.9'):
+ keys.extend(["export_location", "export_locations"])
if utils.is_microversion_ge(version, '2.2'):
keys.append("snapshot_support")
if utils.is_microversion_ge(version, '2.4'):
@@ -167,6 +181,8 @@
"source_cgsnapshot_member_id"])
if utils.is_microversion_ge(version, '2.6'):
keys.append("share_type_name")
+ if utils.is_microversion_ge(version, '2.10'):
+ keys.append("access_rules_status")
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
@@ -195,6 +211,16 @@
self._list_shares_with_detail('2.6')
@test.attr(type=["gate", ])
+ @utils.skip_if_microversion_not_supported('2.9')
+ def test_list_shares_with_detail_export_locations_removed(self):
+ self._list_shares_with_detail('2.9')
+
+ @test.attr(type=["gate", ])
+ @utils.skip_if_microversion_not_supported('2.10')
+ def test_list_shares_with_detail_with_access_rules_status(self):
+ self._list_shares_with_detail('2.10')
+
+ @test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_metadata(self):
filters = {'metadata': self.metadata}
@@ -473,12 +499,19 @@
new_size = 2
# extend share and wait for active status
- self.shares_client.extend_share(share['id'], new_size)
+ self.shares_v2_client.extend_share(share['id'], new_size)
self.shares_client.wait_for_share_status(share['id'], 'available')
# check state and new size
- share = self.shares_client.get_share(share['id'])
- self.assertEqual(new_size, share['size'])
+ share_get = self.shares_v2_client.get_share(share['id'])
+ msg = (
+ "Share could not be extended. "
+ "Expected %(expected)s, got %(actual)s." % {
+ "expected": new_size,
+ "actual": share_get['size'],
+ }
+ )
+ self.assertEqual(new_size, share_get['size'], msg)
@test.attr(type=["gate", ])
@testtools.skipUnless(
@@ -489,12 +522,19 @@
new_size = 1
# shrink share and wait for active status
- self.shares_client.shrink_share(share['id'], new_size)
+ self.shares_v2_client.shrink_share(share['id'], new_size)
self.shares_client.wait_for_share_status(share['id'], 'available')
# check state and new size
- share = self.shares_client.get_share(share['id'])
- self.assertEqual(new_size, share['size'])
+ share_get = self.shares_v2_client.get_share(share['id'])
+ msg = (
+ "Share could not be shrunk. "
+ "Expected %(expected)s, got %(actual)s." % {
+ "expected": new_size,
+ "actual": share_get['size'],
+ }
+ )
+ self.assertEqual(new_size, share_get['size'], msg)
class SharesRenameTest(base.BaseSharesTest):
diff --git a/manila_tempest_tests/tests/api/test_shares_negative.py b/manila_tempest_tests/tests/api/test_shares_negative.py
index ae57a5f..ec8ac3b 100644
--- a/manila_tempest_tests/tests/api/test_shares_negative.py
+++ b/manila_tempest_tests/tests/api/test_shares_negative.py
@@ -114,6 +114,12 @@
self.shares_client.create_share, size=0)
@test.attr(type=["negative", "gate", ])
+ def test_create_share_non_existent_az(self):
+ self.assertRaises(lib_exc.NotFound,
+ self.shares_v2_client.create_share,
+ availability_zone='fake_az')
+
+ @test.attr(type=["negative", "gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_try_delete_share_with_existing_snapshot(self):
diff --git a/manila_tempest_tests/tests/scenario/manager_share.py b/manila_tempest_tests/tests/scenario/manager_share.py
index 51e65ca..f5f0c1f 100644
--- a/manila_tempest_tests/tests/scenario/manager_share.py
+++ b/manila_tempest_tests/tests/scenario/manager_share.py
@@ -38,6 +38,7 @@
# Manila clients
cls.shares_client = clients_share.Manager().shares_client
+ cls.shares_v2_client = clients_share.Manager().shares_v2_client
cls.shares_admin_client = clients_share.AdminManager().shares_client
cls.shares_admin_v2_client = (
clients_share.AdminManager().shares_v2_client)
@@ -132,7 +133,12 @@
"""
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")
+
+ # NOTE(u_glide): Ignore provided client, because we always need v2
+ # client to make this call
+ self.shares_v2_client.wait_for_share_status(
+ share_id, "active", status_attr='access_rules_status')
+
if cleanup:
self.addCleanup(client.delete_access_rule, share_id, access['id'])
return access
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 7de8870..fe66787 100644
--- a/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
+++ b/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
@@ -20,6 +20,7 @@
from tempest_lib import exceptions
from manila_tempest_tests.tests.scenario import manager_share as manager
+from manila_tempest_tests import utils
CONF = config.CONF
@@ -47,7 +48,7 @@
if not hasattr(self, 'flavor_ref'):
self.flavor_ref = CONF.share.client_vm_flavor_ref
if CONF.share.image_with_share_tools:
- images = self.images_client.list_images()["images"]
+ images = self.compute_images_client.list_images()["images"]
for img in images:
if img["name"] == CONF.share.image_with_share_tools:
self.image_ref = img['id']
@@ -68,12 +69,12 @@
create_kwargs = {
'key_name': self.keypair['name'],
'security_groups': security_groups,
+ 'wait_until': 'ACTIVE',
}
if CONF.share.multitenancy_enabled:
create_kwargs['networks'] = [{'uuid': self.net['id']}, ]
- instance = self.create_server(image=self.image_ref,
- create_kwargs=create_kwargs,
- flavor=self.flavor_ref)
+ instance = self.create_server(
+ image_id=self.image_ref, flavor=self.flavor_ref, **create_kwargs)
return instance
def init_ssh(self, instance, do_ping=False):
@@ -190,6 +191,9 @@
instance1 = self.boot_instance()
self.allow_access_ip(self.share['id'], instance=instance1)
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)
self.addCleanup(self.umount_share,
@@ -235,12 +239,13 @@
dest_pool = dest_pool['name']
- old_export_location = share['export_locations'][0]
-
instance1 = self.boot_instance()
self.allow_access_ip(self.share['id'], instance=instance1,
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)
@@ -266,12 +271,19 @@
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'])
+ 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]
self.assertEqual(dest_pool, share['host'])
- self.assertNotEqual(old_export_location, share['export_locations'][0])
+ self.assertNotEqual(first_location, second_location)
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")