diff --git a/api-ref/source/parameters.yaml b/api-ref/source/parameters.yaml index bab30ae2..f58f9e49 100644 --- a/api-ref/source/parameters.yaml +++ b/api-ref/source/parameters.yaml @@ -206,6 +206,22 @@ consistency_group_id_5: in: query required: false type: string +export_location_id_query: + description: | + The export location UUID that can be used to filter shares or + share instances. + in: query + required: false + type: string + min_version: 2.35 +export_location_path_query: + description: | + The export location path that can be used to filter shares or + share instances. + in: query + required: false + type: string + min_version: 2.35 extra_specs_1: description: | The extra specifications as a set of one or more diff --git a/api-ref/source/share-instances.inc b/api-ref/source/share-instances.inc index f9fd4a15..7562d23e 100644 --- a/api-ref/source/share-instances.inc +++ b/api-ref/source/share-instances.inc @@ -25,6 +25,8 @@ Request .. rest_parameters:: parameters.yaml - tenant_id: tenant_id_1 + - export_location_id: export_location_id_query + - export_location_path: export_location_path_query Response parameters ------------------- diff --git a/api-ref/source/shares.inc b/api-ref/source/shares.inc index f889723b..c3d23d29 100644 --- a/api-ref/source/shares.inc +++ b/api-ref/source/shares.inc @@ -113,6 +113,8 @@ Request - project_id: project_id_6 - is_public: is_public - consistency_group_id: consistency_group_id_6 + - export_location_id: export_location_id_query + - export_location_path: export_location_path_query Response parameters ------------------- @@ -164,6 +166,8 @@ Request - project_id: project_id_6 - is_public: is_public - consistency_group_id: consistency_group_id_6 + - export_location_id: export_location_id_query + - export_location_path: export_location_path_query Response parameters ------------------- diff --git a/manila/api/openstack/api_version_request.py b/manila/api/openstack/api_version_request.py index e7f1cd03..3a6fba13 100644 --- a/manila/api/openstack/api_version_request.py +++ b/manila/api/openstack/api_version_request.py @@ -102,13 +102,16 @@ REST_API_VERSION_HISTORY = """ access_list API. * 2.34 - Added 'availability_zone_id' and 'consistent_snapshot_support' fields to 'share_group' object. + * 2.35 - Added support to retrieve shares filtered by export_location_id + and export_location_path. + """ # The minimum and maximum versions of the API supported # The default api version request is defined to be the # minimum version of the API supported. _MIN_API_VERSION = "2.0" -_MAX_API_VERSION = "2.34" +_MAX_API_VERSION = "2.35" DEFAULT_API_VERSION = _MIN_API_VERSION diff --git a/manila/api/openstack/rest_api_version_history.rst b/manila/api/openstack/rest_api_version_history.rst index acc62b5a..c0b6ee32 100644 --- a/manila/api/openstack/rest_api_version_history.rst +++ b/manila/api/openstack/rest_api_version_history.rst @@ -200,3 +200,8 @@ user documentation. ---- Added 'availability_zone_id' and 'consistent_snapshot_support' fields to 'share_group' object. + +2.35 +---- + Added support to retrieve shares filtered by export_location_id and + export_location_path. diff --git a/manila/api/v1/shares.py b/manila/api/v1/shares.py index aa49416c..e8fe7f47 100644 --- a/manila/api/v1/shares.py +++ b/manila/api/v1/shares.py @@ -100,10 +100,14 @@ class ShareMixin(object): def index(self, req): """Returns a summary list of shares.""" + req.GET.pop('export_location_id', None) + req.GET.pop('export_location_path', None) return self._get_shares(req, is_detail=False) def detail(self, req): """Returns a detailed list of shares.""" + req.GET.pop('export_location_id', None) + req.GET.pop('export_location_path', None) return self._get_shares(req, is_detail=True) def _get_shares(self, req, is_detail): @@ -159,7 +163,8 @@ class ShareMixin(object): 'display_name', 'status', 'share_server_id', 'volume_type_id', 'share_type_id', 'snapshot_id', 'host', 'share_network_id', 'is_public', 'metadata', 'extra_specs', 'sort_key', 'sort_dir', - 'share_group_id', 'share_group_snapshot_id' + 'share_group_id', 'share_group_snapshot_id', + 'export_location_id', 'export_location_path' ) def update(self, req, id, body): diff --git a/manila/api/v2/share_instances.py b/manila/api/v2/share_instances.py index ed220e8b..e4dd696e 100644 --- a/manila/api/v2/share_instances.py +++ b/manila/api/v2/share_instances.py @@ -15,6 +15,7 @@ from webob import exc +from manila.api import common from manila.api.openstack import wsgi from manila.api.views import share_instance as instance_view from manila import db @@ -61,14 +62,28 @@ class ShareInstancesController(wsgi.Controller, wsgi.AdminActionsMixin): def instance_force_delete(self, req, id, body): return self._force_delete(req, id, body) - @wsgi.Controller.api_version("2.3") + @wsgi.Controller.api_version("2.3", "2.34") # noqa @wsgi.Controller.authorize - def index(self, req): + def index(self, req): # pylint: disable=E0102 context = req.environ['manila.context'] + req.GET.pop('export_location_id', None) + req.GET.pop('export_location_path', None) instances = db.share_instances_get_all(context) return self._view_builder.detail_list(req, instances) + @wsgi.Controller.api_version("2.35") # noqa + @wsgi.Controller.authorize + def index(self, req): # pylint: disable=E0102 + context = req.environ['manila.context'] + filters = {} + filters.update(req.GET) + common.remove_invalid_options( + context, filters, ('export_location_id', 'export_location_path')) + + instances = db.share_instances_get_all(context, filters) + return self._view_builder.detail_list(req, instances) + @wsgi.Controller.api_version("2.3") @wsgi.Controller.authorize def show(self, req, id): diff --git a/manila/api/v2/shares.py b/manila/api/v2/shares.py index aca1b46c..6ae6105c 100644 --- a/manila/api/v2/shares.py +++ b/manila/api/v2/shares.py @@ -415,6 +415,30 @@ class ShareController(shares.ShareMixin, def revert(self, req, id, body=None): return self._revert(req, id, body) + @wsgi.Controller.api_version("2.0", "2.34") # noqa + def index(self, req): # pylint: disable=E0102 + """Returns a summary list of shares.""" + req.GET.pop('export_location_id', None) + req.GET.pop('export_location_path', None) + return self._get_shares(req, is_detail=False) + + @wsgi.Controller.api_version("2.35") # noqa + def index(self, req): # pylint: disable=E0102 + """Returns a summary list of shares.""" + return self._get_shares(req, is_detail=False) + + @wsgi.Controller.api_version("2.0", "2.34") # noqa + def detail(self, req): # pylint: disable=E0102 + """Returns a detailed list of shares.""" + req.GET.pop('export_location_id', None) + req.GET.pop('export_location_path', None) + return self._get_shares(req, is_detail=True) + + @wsgi.Controller.api_version("2.35") # noqa + def detail(self, req): # pylint: disable=E0102 + """Returns a detailed list of shares.""" + return self._get_shares(req, is_detail=True) + def create_resource(): return wsgi.Resource(ShareController()) diff --git a/manila/db/api.py b/manila/db/api.py index 1f58099a..384fa1a2 100644 --- a/manila/db/api.py +++ b/manila/db/api.py @@ -294,9 +294,9 @@ def share_instance_update(context, instance_id, values, with_share_data=False): with_share_data=with_share_data) -def share_instances_get_all(context): +def share_instances_get_all(context, filters=None): """Returns all share instances.""" - return IMPL.share_instances_get_all(context) + return IMPL.share_instances_get_all(context, filters=filters) def share_instances_get_all_by_share_server(context, share_server_id): diff --git a/manila/db/sqlalchemy/api.py b/manila/db/sqlalchemy/api.py index 7fb1f5d6..f35397f3 100644 --- a/manila/db/sqlalchemy/api.py +++ b/manila/db/sqlalchemy/api.py @@ -1202,13 +1202,35 @@ def share_instance_get(context, share_instance_id, session=None, @require_admin_context -def share_instances_get_all(context): +def share_instances_get_all(context, filters=None): session = get_session() - return model_query( + query = model_query( context, models.ShareInstance, session=session, read_deleted="no", ).options( joinedload('export_locations'), - ).all() + ) + + filters = filters or {} + + export_location_id = filters.get('export_location_id') + export_location_path = filters.get('export_location_path') + if export_location_id or export_location_path: + query = query.join( + models.ShareInstanceExportLocations, + models.ShareInstanceExportLocations.share_instance_id == + models.ShareInstance.id) + if export_location_path: + query = query.filter( + models.ShareInstanceExportLocations.path == + export_location_path) + if export_location_id: + query = query.filter( + models.ShareInstanceExportLocations.uuid == + export_location_id) + + # Returns list of share instances that satisfy filters. + query = query.all() + return query @require_context @@ -1594,6 +1616,23 @@ def _share_get_all_with_filters(context, project_id=None, share_server_id=None, # Apply filters if not filters: filters = {} + + export_location_id = filters.get('export_location_id') + export_location_path = filters.get('export_location_path') + if export_location_id or export_location_path: + query = query.join( + models.ShareInstanceExportLocations, + models.ShareInstanceExportLocations.share_instance_id == + models.ShareInstance.id) + if export_location_path: + query = query.filter( + models.ShareInstanceExportLocations.path == + export_location_path) + if export_location_id: + query = query.filter( + models.ShareInstanceExportLocations.uuid == + export_location_id) + if 'metadata' in filters: for k, v in filters['metadata'].items(): query = query.filter( diff --git a/manila/share/api.py b/manila/share/api.py index 4ad8c977..1a7a0e66 100644 --- a/manila/share/api.py +++ b/manila/share/api.py @@ -1490,6 +1490,12 @@ class API(base.Base): # Prepare filters filters = {} + if 'export_location_id' in search_opts: + filters['export_location_id'] = search_opts.pop( + 'export_location_id') + if 'export_location_path' in search_opts: + filters['export_location_path'] = search_opts.pop( + 'export_location_path') if 'metadata' in search_opts: filters['metadata'] = search_opts.pop('metadata') if not isinstance(filters['metadata'], dict): diff --git a/manila/tests/api/v2/test_share_instances.py b/manila/tests/api/v2/test_share_instances.py index 688c0711..91828cad 100644 --- a/manila/tests/api/v2/test_share_instances.py +++ b/manila/tests/api/v2/test_share_instances.py @@ -68,8 +68,13 @@ class ShareInstancesAPITest(test.TestCase): self.assertEqual([i['id'] for i in expected], [i['id'] for i in actual]) - def test_index(self): - req = self._get_request('/share_instances') + @ddt.data("2.3", "2.34", "2.35") + def test_index(self, version): + url = '/share_instances' + if (api_version_request.APIVersionRequest(version) >= + api_version_request.APIVersionRequest('2.35')): + url += "?export_location_path=/admin/export/location" + req = self._get_request(url, version=version) req_context = req.environ['manila.context'] share_instances_count = 3 test_instances = [ @@ -77,8 +82,15 @@ class ShareInstancesAPITest(test.TestCase): for s in range(0, share_instances_count) ] + db.share_export_locations_update( + self.admin_context, test_instances[0]['id'], + '/admin/export/location', False) + actual_result = self.controller.index(req) + if (api_version_request.APIVersionRequest(version) >= + api_version_request.APIVersionRequest('2.35')): + test_instances = test_instances[:1] self._validate_ids_in_share_instances_list( test_instances, actual_result['share_instances']) self.mock_policy_check.assert_called_once_with( diff --git a/manila/tests/api/v2/test_shares.py b/manila/tests/api/v2/test_shares.py index 09e221e6..a2e4d938 100644 --- a/manila/tests/api/v2/test_shares.py +++ b/manila/tests/api/v2/test_shares.py @@ -1497,7 +1497,11 @@ class ShareAPITest(test.TestCase): req, 1) - def _share_list_summary_with_search_opts(self, use_admin_context): + @ddt.data({'use_admin_context': False, 'version': '2.4'}, + {'use_admin_context': True, 'version': '2.4'}, + {'use_admin_context': True, 'version': '2.35'}, + {'use_admin_context': False, 'version': '2.35'}) + def share_list_summary_with_search_opts(self, use_admin_context, version): search_opts = { 'name': 'fake_name', 'status': constants.STATUS_AVAILABLE, @@ -1512,6 +1516,8 @@ class ShareAPITest(test.TestCase): 'limit': '1', 'offset': '1', 'is_public': 'False', + 'export_location_id': 'fake_export_location_id', + 'export_location_path': 'fake_export_location_path', } if use_admin_context: search_opts['host'] = 'fake_host' @@ -1519,7 +1525,8 @@ class ShareAPITest(test.TestCase): url = '/shares?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v - req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context) + req = fakes.HTTPRequest.blank(url, version=version, + use_admin_context=use_admin_context) shares = [ {'id': 'id1', 'display_name': 'n1'}, @@ -1537,12 +1544,18 @@ class ShareAPITest(test.TestCase): 'share_server_id': search_opts['share_server_id'], 'share_type_id': search_opts['share_type_id'], 'snapshot_id': search_opts['snapshot_id'], - 'share_network_id': search_opts['share_network_id'], 'metadata': {'k1': 'v1'}, 'extra_specs': {'k2': 'v2'}, 'is_public': 'False', } + if (api_version.APIVersionRequest(version) >= + api_version.APIVersionRequest('2.35')): + search_opts_expected['export_location_id'] = ( + search_opts['export_location_id']) + search_opts_expected['export_location_path'] = ( + search_opts['export_location_path']) + if use_admin_context: search_opts_expected.update({'fake_key': 'fake_value'}) search_opts_expected['host'] = search_opts['host'] @@ -1557,12 +1570,6 @@ class ShareAPITest(test.TestCase): self.assertEqual( shares[1]['display_name'], result['shares'][0]['name']) - def test_share_list_summary_with_search_opts_by_non_admin(self): - self._share_list_summary_with_search_opts(use_admin_context=False) - - def test_share_list_summary_with_search_opts_by_admin(self): - self._share_list_summary_with_search_opts(use_admin_context=True) - def test_share_list_summary(self): self.mock_object(share_api.API, 'get_all', stubs.stub_share_get_all_by_project) @@ -1588,7 +1595,11 @@ class ShareAPITest(test.TestCase): } self.assertEqual(expected, res_dict) - def _share_list_detail_with_search_opts(self, use_admin_context): + @ddt.data({'use_admin_context': False, 'version': '2.4'}, + {'use_admin_context': True, 'version': '2.4'}, + {'use_admin_context': True, 'version': '2.35'}, + {'use_admin_context': False, 'version': '2.35'}) + def _share_list_detail_with_search_opts(self, use_admin_context, version): search_opts = { 'name': 'fake_name', 'status': constants.STATUS_AVAILABLE, @@ -1603,6 +1614,8 @@ class ShareAPITest(test.TestCase): 'limit': '1', 'offset': '1', 'is_public': 'False', + 'export_location_id': 'fake_export_location_id', + 'export_location_path': 'fake_export_location_path', } if use_admin_context: search_opts['host'] = 'fake_host' @@ -1610,7 +1623,8 @@ class ShareAPITest(test.TestCase): url = '/shares/detail?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v - req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context) + req = fakes.HTTPRequest.blank(url, version=version, + use_admin_context=use_admin_context) shares = [ {'id': 'id1', 'display_name': 'n1'}, @@ -1627,6 +1641,7 @@ class ShareAPITest(test.TestCase): }, {'id': 'id3', 'display_name': 'n3'}, ] + self.mock_object(share_api.API, 'get_all', mock.Mock(return_value=shares)) @@ -1643,6 +1658,13 @@ class ShareAPITest(test.TestCase): 'extra_specs': {'k2': 'v2'}, 'is_public': 'False', } + if (api_version.APIVersionRequest(version) >= + api_version.APIVersionRequest('2.35')): + search_opts_expected['export_location_id'] = ( + search_opts['export_location_id']) + search_opts_expected['export_location_path'] = ( + search_opts['export_location_path']) + if use_admin_context: search_opts_expected.update({'fake_key': 'fake_value'}) search_opts_expected['host'] = search_opts['host'] @@ -1671,12 +1693,10 @@ class ShareAPITest(test.TestCase): self.assertEqual( shares[1]['instance']['share_network_id'], result['shares'][0]['share_network_id']) - - def test_share_list_detail_with_search_opts_by_non_admin(self): - self._share_list_detail_with_search_opts(use_admin_context=False) - - def test_share_list_detail_with_search_opts_by_admin(self): - self._share_list_detail_with_search_opts(use_admin_context=True) + if (api_version.APIVersionRequest(version) >= + api_version.APIVersionRequest('2.35')): + self.assertEqual(shares[1]['export_location'], + result['shares'][0]['export_location']) def _list_detail_common_expected(self, admin=False): share_dict = { diff --git a/manila/tests/db/sqlalchemy/test_api.py b/manila/tests/db/sqlalchemy/test_api.py index ffc12dd1..7b0fcc09 100644 --- a/manila/tests/db/sqlalchemy/test_api.py +++ b/manila/tests/db/sqlalchemy/test_api.py @@ -335,6 +335,29 @@ class ShareDatabaseAPITestCase(test.TestCase): self.assertEqual('share-%s' % instance['id'], instance['name']) + @ddt.data('id', 'path') + def test_share_instance_get_all_by_export_location(self, type): + share = db_utils.create_share() + initial_location = ['fake_export_location'] + db_api.share_export_locations_update(self.ctxt, share.instance['id'], + initial_location, False) + + if type == 'id': + export_location = ( + db_api.share_export_locations_get_by_share_id(self.ctxt, + share['id'])) + value = export_location[0]['uuid'] + else: + value = 'fake_export_location' + + instances = db_api.share_instances_get_all( + self.ctxt, filters={'export_location_' + type: value}) + + self.assertEqual(1, len(instances)) + instance = instances[0] + + self.assertEqual('share-%s' % instance['id'], instance['name']) + @ddt.data('host', 'share_group_id') def test_share_get_all_sort_by_share_instance_fields(self, sort_key): shares = [db_utils.create_share(**{sort_key: n, 'size': 1}) @@ -346,6 +369,36 @@ class ShareDatabaseAPITestCase(test.TestCase): self.assertEqual(2, len(actual_result)) self.assertEqual(shares[0]['id'], actual_result[1]['id']) + @ddt.data('id', 'path') + def test_share_get_all_by_export_location(self, type): + share = db_utils.create_share() + initial_location = ['fake_export_location'] + db_api.share_export_locations_update(self.ctxt, share.instance['id'], + initial_location, False) + if type == 'id': + export_location = db_api.share_export_locations_get_by_share_id( + self.ctxt, share['id']) + value = export_location[0]['uuid'] + else: + value = 'fake_export_location' + + actual_result = db_api.share_get_all( + self.ctxt, filters={'export_location_' + type: value}) + + self.assertEqual(1, len(actual_result)) + self.assertEqual(share['id'], actual_result[0]['id']) + + @ddt.data('id', 'path') + def test_share_get_all_by_export_location_not_exist(self, type): + share = db_utils.create_share() + initial_location = ['fake_export_location'] + db_api.share_export_locations_update(self.ctxt, share.instance['id'], + initial_location, False) + filter = {'export_location_' + type: 'export_location_not_exist'} + actual_result = db_api.share_get_all(self.ctxt, filters=filter) + + self.assertEqual(0, len(actual_result)) + @ddt.data(None, 'writable') def test_share_get_has_replicas_field(self, replication_type): share = db_utils.create_share(replication_type=replication_type) diff --git a/manila/tests/share/test_api.py b/manila/tests/share/test_api.py index bab06575..0139fb98 100644 --- a/manila/tests/share/test_api.py +++ b/manila/tests/share/test_api.py @@ -310,6 +310,22 @@ class ShareAPITestCase(test.TestCase): ) self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1::2], shares) + @ddt.data('id', 'path') + def test_get_all_admin_filter_by_export_location(self, type): + ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=True) + self.mock_object(db_api, 'share_get_all_by_project', + mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[1:])) + shares = self.api.get_all(ctx, {'export_location_' + type: 'test'}) + share_api.policy.check_policy.assert_has_calls([ + mock.call(ctx, 'share', 'get_all'), + ]) + db_api.share_get_all_by_project.assert_called_once_with( + ctx, sort_dir='desc', sort_key='created_at', + project_id='fake_pid_2', + filters={'export_location_' + type: 'test'}, is_public=False + ) + self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1:], shares) + def test_get_all_admin_filter_by_name_and_all_tenants(self): ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=True) self.mock_object(db_api, 'share_get_all', diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py index e54dd483..062bf97f 100644 --- a/manila_tempest_tests/config.py +++ b/manila_tempest_tests/config.py @@ -30,7 +30,7 @@ ShareGroup = [ 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.34", + default="2.35", 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 53c123e4..353c8cc7 100644 --- a/manila_tempest_tests/services/share/v2/json/shares_client.py +++ b/manila_tempest_tests/services/share/v2/json/shares_client.py @@ -294,8 +294,11 @@ class SharesV2Client(shares_client.SharesClient): self.expected_success(200, resp.status) return self._parse_resp(body) - def list_share_instances(self, version=LATEST_MICROVERSION): - resp, body = self.get("share_instances", version=version) + def list_share_instances(self, version=LATEST_MICROVERSION, + params=None): + uri = 'share_instances' + uri += '?%s' % urlparse.urlencode(params) if params else '' + resp, body = self.get(uri, version=version) self.expected_success(200, resp.status) return self._parse_resp(body) 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 1a4b297a..479850cb 100644 --- a/manila_tempest_tests/tests/api/admin/test_share_instances.py +++ b/manila_tempest_tests/tests/api/admin/test_share_instances.py @@ -14,14 +14,11 @@ # under the License. import ddt -from tempest import config from testtools import testcase as tc from manila_tempest_tests.tests.api import base from manila_tempest_tests import utils -CONF = config.CONF - @ddt.ddt class ShareInstancesTest(base.BaseSharesAdminTest): @@ -92,3 +89,26 @@ class ShareInstancesTest(base.BaseSharesAdminTest): 'Share instance %s returned incorrect keys; ' 'expected %s, got %s.' % ( si['id'], expected_keys, actual_keys)) + + @ddt.data('path', 'id') + @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND) + @base.skip_if_microversion_lt("2.35") + def test_list_share_instances_with_export_location_path_and_id( + self, export_location_type): + share_instances_except = ( + self.shares_v2_client.get_instances_of_share( + self.share['id'])) + export_locations = ( + self.shares_v2_client.list_share_instance_export_locations( + share_instances_except[0]['id'])) + + filters = { + 'export_location_' + export_location_type: + export_locations[0][export_location_type], + } + share_instances = self.shares_v2_client.list_share_instances( + params=filters) + + self.assertEqual(1, len(share_instances)) + self.assertEqual(share_instances_except[0]['id'], + share_instances[0]['id']) diff --git a/manila_tempest_tests/tests/api/admin/test_share_instances_negative.py b/manila_tempest_tests/tests/api/admin/test_share_instances_negative.py new file mode 100644 index 00000000..b52a8a1b --- /dev/null +++ b/manila_tempest_tests/tests/api/admin/test_share_instances_negative.py @@ -0,0 +1,54 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import ddt +from testtools import testcase as tc + +from manila_tempest_tests.tests.api import base + + +@ddt.ddt +class ShareInstancesNegativeTest(base.BaseSharesAdminTest): + + @classmethod + def resource_setup(cls): + super(ShareInstancesNegativeTest, cls).resource_setup() + cls.share = cls.create_share() + + @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND) + @base.skip_if_microversion_not_supported("2.34") + @ddt.data('path', 'id') + def test_list_share_instances_with_export_location_and_invalid_version( + self, export_location_type): + # In API versions