Merge "Support filter attribute with empty string"
This commit is contained in:
commit
d1a580541a
|
@ -75,12 +75,14 @@ def get_filters_from_dict(data, attr_info, skips=None):
|
|||
becomes:
|
||||
{'check': [u'a', u'b'], 'name': [u'Bob']}
|
||||
"""
|
||||
is_empty_string_supported = is_empty_string_filtering_supported()
|
||||
skips = skips or []
|
||||
res = {}
|
||||
for key, values in data.items():
|
||||
if key in skips or hasattr(model_base.BASEV2, key):
|
||||
continue
|
||||
values = [v for v in values if v]
|
||||
values = [v for v in values
|
||||
if v or (v == "" and is_empty_string_supported)]
|
||||
key_attr_info = attr_info.get(key, {})
|
||||
if 'convert_list_to' in key_attr_info:
|
||||
values = key_attr_info['convert_list_to'](values)
|
||||
|
@ -92,6 +94,11 @@ def get_filters_from_dict(data, attr_info, skips=None):
|
|||
return res
|
||||
|
||||
|
||||
def is_empty_string_filtering_supported():
|
||||
return 'empty-string-filtering' in (extensions.PluginAwareExtensionManager.
|
||||
get_instance().extensions)
|
||||
|
||||
|
||||
def get_previous_link(request, items, id_key):
|
||||
params = request.GET.copy()
|
||||
params.pop('marker', None)
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
# 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.
|
||||
|
||||
"""
|
||||
TODO(hongbin): This module should be deleted once neutron-lib containing
|
||||
https://review.openstack.org/#/c/565342/ change is released.
|
||||
"""
|
||||
|
||||
|
||||
ALIAS = 'empty-string-filtering'
|
||||
IS_SHIM_EXTENSION = True
|
||||
IS_STANDARD_ATTR_EXTENSION = False
|
||||
NAME = 'Empty String Filtering Extension'
|
||||
DESCRIPTION = 'Allow filtering by attributes with empty string value'
|
||||
UPDATED_TIMESTAMP = '2018-04-09T10:00:00-00:00'
|
||||
RESOURCE_ATTRIBUTE_MAP = {}
|
||||
SUB_RESOURCE_ATTRIBUTE_MAP = {}
|
||||
ACTION_MAP = {}
|
||||
REQUIRED_EXTENSIONS = []
|
||||
OPTIONAL_EXTENSIONS = []
|
||||
ACTION_STATUS = {}
|
|
@ -0,0 +1,19 @@
|
|||
# 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 neutron_lib.api import extensions
|
||||
|
||||
from neutron.extensions import _empty_string_filtering_lib as apidef
|
||||
|
||||
|
||||
class Empty_string_filtering(extensions.APIExtensionDescriptor):
|
||||
api_definition = apidef
|
|
@ -158,7 +158,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
"default-subnetpools",
|
||||
"subnet-service-types",
|
||||
"ip-substring-filtering",
|
||||
"port-security-groups-filtering"]
|
||||
"port-security-groups-filtering",
|
||||
"empty-string-filtering"]
|
||||
|
||||
@property
|
||||
def supported_extension_aliases(self):
|
||||
|
|
|
@ -10,6 +10,7 @@ NETWORK_API_EXTENSIONS+=",default-subnetpools"
|
|||
NETWORK_API_EXTENSIONS+=",dhcp_agent_scheduler"
|
||||
NETWORK_API_EXTENSIONS+=",dns-integration"
|
||||
NETWORK_API_EXTENSIONS+=",dvr"
|
||||
NETWORK_API_EXTENSIONS+=",empty-string-filtering"
|
||||
NETWORK_API_EXTENSIONS+=",ext-gw-mode"
|
||||
NETWORK_API_EXTENSIONS+=",external-net"
|
||||
NETWORK_API_EXTENSIONS+=",extra_dhcp_opt"
|
||||
|
|
|
@ -86,6 +86,7 @@ class APIv2TestBase(base.BaseTestCase):
|
|||
self._plugin_patcher = mock.patch(plugin, autospec=True)
|
||||
self.plugin = self._plugin_patcher.start()
|
||||
instance = self.plugin.return_value
|
||||
instance.supported_extension_aliases = ['empty-string-filtering']
|
||||
instance._NeutronPluginBaseV2__native_pagination_support = True
|
||||
instance._NeutronPluginBaseV2__native_sorting_support = True
|
||||
tools.make_mock_plugin_json_encodable(instance)
|
||||
|
@ -202,7 +203,7 @@ class APIv2TestCase(APIv2TestBase):
|
|||
instance.get_networks.return_value = []
|
||||
|
||||
self.api.get(_get_path('networks'), {'name': ''})
|
||||
filters = {}
|
||||
filters = {'name': ['']}
|
||||
kwargs = self._get_collection_kwargs(filters=filters)
|
||||
instance.get_networks.assert_called_once_with(mock.ANY, **kwargs)
|
||||
|
||||
|
@ -211,7 +212,7 @@ class APIv2TestCase(APIv2TestBase):
|
|||
instance.get_networks.return_value = []
|
||||
|
||||
self.api.get(_get_path('networks'), {'name': ['', '']})
|
||||
filters = {}
|
||||
filters = {'name': ['', '']}
|
||||
kwargs = self._get_collection_kwargs(filters=filters)
|
||||
instance.get_networks.assert_called_once_with(mock.ANY, **kwargs)
|
||||
|
||||
|
@ -220,7 +221,7 @@ class APIv2TestCase(APIv2TestBase):
|
|||
instance.get_networks.return_value = []
|
||||
|
||||
self.api.get(_get_path('networks'), {'name': ['bar', '']})
|
||||
filters = {'name': ['bar']}
|
||||
filters = {'name': ['bar', '']}
|
||||
kwargs = self._get_collection_kwargs(filters=filters)
|
||||
instance.get_networks.assert_called_once_with(mock.ANY, **kwargs)
|
||||
|
||||
|
@ -1552,11 +1553,21 @@ class FiltersTestCase(base.BaseTestCase):
|
|||
self.assertEqual({}, api_common.get_filters(request, None,
|
||||
["fields"]))
|
||||
|
||||
def test_blank_values(self):
|
||||
@mock.patch('neutron.api.api_common.is_empty_string_filtering_supported',
|
||||
return_value=False)
|
||||
def test_blank_values(self, mock_is_supported):
|
||||
path = '/?foo=&bar=&baz=&qux='
|
||||
request = webob.Request.blank(path)
|
||||
self.assertEqual({}, api_common.get_filters(request, {}))
|
||||
|
||||
@mock.patch('neutron.api.api_common.is_empty_string_filtering_supported',
|
||||
return_value=True)
|
||||
def test_blank_values_with_filtering_supported(self, mock_is_supported):
|
||||
path = '/?foo=&bar=&baz=&qux='
|
||||
request = webob.Request.blank(path)
|
||||
self.assertEqual({'foo': [''], 'bar': [''], 'baz': [''], 'qux': ['']},
|
||||
api_common.get_filters(request, {}))
|
||||
|
||||
def test_no_attr_info(self):
|
||||
path = '/?foo=4&bar=3&baz=2&qux=1'
|
||||
request = webob.Request.blank(path)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Add support for filtering attributes with value as empty string. A shim
|
||||
extension is added to indicate if this feature is supported.
|
Loading…
Reference in New Issue