Merge "Remove a SGs API test following sync to Tempest"
diff --git a/neutron/tests/tempest/api/admin/test_quotas.py b/neutron/tests/tempest/api/admin/test_quotas.py
index 4e00da2..3bf52c5 100644
--- a/neutron/tests/tempest/api/admin/test_quotas.py
+++ b/neutron/tests/tempest/api/admin/test_quotas.py
@@ -21,9 +21,44 @@
from neutron.tests.tempest.api import base
-class QuotasTest(base.BaseAdminNetworkTest):
+class QuotasTestBase(base.BaseAdminNetworkTest):
- """
+ @classmethod
+ @test.requires_ext(extension="quotas", service="network")
+ def resource_setup(cls):
+ super(QuotasTestBase, cls).resource_setup()
+
+ def _create_tenant(self):
+ # Add a tenant to conduct the test
+ test_tenant = data_utils.rand_name('test_tenant_')
+ test_description = data_utils.rand_name('desc_')
+ tenant = self.identity_admin_client.create_tenant(
+ name=test_tenant,
+ description=test_description)['tenant']
+ self.addCleanup(
+ self.identity_admin_client.create_tenant, tenant['id'])
+ return tenant
+
+ def _setup_quotas(self, project_id, **new_quotas):
+ # Change quotas for tenant
+ quota_set = self.admin_client.update_quotas(project_id,
+ **new_quotas)
+ self.addCleanup(self._cleanup_quotas, project_id)
+ return quota_set
+
+ def _cleanup_quotas(self, project_id):
+ # Try to clean up the resources. If it fails, then
+ # assume that everything was already deleted, so
+ # it is OK to continue.
+ try:
+ self.admin_client.reset_quotas(project_id)
+ except lib_exc.NotFound:
+ pass
+
+
+class QuotasTest(QuotasTestBase):
+ """Test the Neutron API of Quotas.
+
Tests the following operations in the Neutron API using the REST client for
Neutron:
@@ -39,29 +74,14 @@
quota_driver = neutron.db.driver.DbQuotaDriver
"""
- @classmethod
- @test.requires_ext(extension="quotas", service="network")
- def resource_setup(cls):
- super(QuotasTest, cls).resource_setup()
-
@test.attr(type='gate')
@test.idempotent_id('2390f766-836d-40ef-9aeb-e810d78207fb')
def test_quotas(self):
- # Add a tenant to conduct the test
- test_tenant = data_utils.rand_name('test_tenant_')
- test_description = data_utils.rand_name('desc_')
- tenant = self.identity_admin_client.create_tenant(
- name=test_tenant,
- description=test_description)['tenant']
- tenant_id = tenant['id']
- self.addCleanup(self.identity_admin_client.delete_tenant, tenant_id)
-
+ tenant_id = self._create_tenant()['id']
new_quotas = {'network': 0, 'security_group': 0}
# Change quotas for tenant
- quota_set = self.admin_client.update_quotas(tenant_id,
- **new_quotas)
- self.addCleanup(self._cleanup_quotas, tenant_id)
+ quota_set = self._setup_quotas(tenant_id, **new_quotas)
for key, value in six.iteritems(new_quotas):
self.assertEqual(value, quota_set[key])
@@ -84,12 +104,3 @@
non_default_quotas = self.admin_client.list_quotas()
for q in non_default_quotas['quotas']:
self.assertNotEqual(tenant_id, q['tenant_id'])
-
- def _cleanup_quotas(self, project_id):
- # Try to clean up the resources. If it fails, then
- # assume that everything was already deleted, so
- # it is OK to continue.
- try:
- self.admin_client.reset_quotas(project_id)
- except lib_exc.NotFound:
- pass
diff --git a/neutron/tests/tempest/api/admin/test_quotas_negative.py b/neutron/tests/tempest/api/admin/test_quotas_negative.py
new file mode 100644
index 0000000..12ae0be
--- /dev/null
+++ b/neutron/tests/tempest/api/admin/test_quotas_negative.py
@@ -0,0 +1,173 @@
+# 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.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+
+from neutron.tests.tempest.api.admin import test_quotas
+from neutron.tests.tempest import config
+
+CONF = config.CONF
+
+
+class QuotasAdminNegativeTestJSON(test_quotas.QuotasTestBase):
+
+ @test.attr(type='negative')
+ @test.idempotent_id('952f9b24-9156-4bdc-90f3-682a3d4302f0')
+ def test_create_network_when_quotas_is_full(self):
+ tenant_id = self._create_tenant()['id']
+ new_quotas = {'network': 1}
+ self._setup_quotas(tenant_id, **new_quotas)
+
+ net_args = {'tenant_id': tenant_id}
+ net = self.admin_client.create_network(**net_args)['network']
+ self.addCleanup(self.admin_client.delete_network, net['id'])
+
+ self.assertRaises(lib_exc.Conflict,
+ self.admin_client.create_network, **net_args)
+
+ @test.attr(type='negative')
+ @test.idempotent_id('0b7f99e3-9f77-45ce-9a89-b39a184de618')
+ def test_create_subnet_when_quotas_is_full(self):
+ tenant_id = self._create_tenant()['id']
+ new_quotas = {'subnet': 1}
+ self._setup_quotas(tenant_id, **new_quotas)
+
+ net_args = {'tenant_id': tenant_id}
+ net = self.admin_client.create_network(**net_args)['network']
+ self.addCleanup(self.admin_client.delete_network, net['id'])
+
+ subnet_args = {'tenant_id': tenant_id,
+ 'network_id': net['id'],
+ 'cidr': '10.0.0.0/24',
+ 'ip_version': '4'}
+ subnet = self.admin_client.create_subnet(**subnet_args)['subnet']
+ self.addCleanup(self.admin_client.delete_subnet, subnet['id'])
+
+ subnet_args['cidr'] = '10.1.0.0/24'
+ self.assertRaises(lib_exc.Conflict,
+ self.admin_client.create_subnet, **subnet_args)
+
+ @test.attr(type='negative')
+ @test.idempotent_id('fe20d9f9-346c-4a20-bbfa-d9ca390f4dc6')
+ def test_create_port_when_quotas_is_full(self):
+ tenant_id = self._create_tenant()['id']
+ new_quotas = {'port': 1}
+ self._setup_quotas(tenant_id, **new_quotas)
+
+ net_args = {'tenant_id': tenant_id}
+ net = self.admin_client.create_network(**net_args)['network']
+ self.addCleanup(self.admin_client.delete_network, net['id'])
+
+ subnet_args = {'tenant_id': tenant_id,
+ 'network_id': net['id'],
+ 'cidr': '10.0.0.0/24',
+ 'ip_version': '4'}
+ subnet = self.admin_client.create_subnet(**subnet_args)['subnet']
+ self.addCleanup(self.admin_client.delete_subnet, subnet['id'])
+
+ port_args = {'tenant_id': tenant_id,
+ 'network_id': net['id']}
+ port = self.admin_client.create_port(**port_args)['port']
+ self.addCleanup(self.admin_client.delete_port, port['id'])
+
+ self.assertRaises(lib_exc.Conflict,
+ self.admin_client.create_port, **port_args)
+
+ @test.attr(type='negative')
+ @test.idempotent_id('bb1e9c3c-7e6f-41f1-b579-63dbc655ecb7')
+ @test.requires_ext(extension="router", service="network")
+ def test_create_router_when_quotas_is_full(self):
+ tenant_id = self._create_tenant()['id']
+ new_quotas = {'router': 1}
+ self._setup_quotas(tenant_id, **new_quotas)
+
+ name = data_utils.rand_name('test_router_')
+ router_args = {'tenant_id': tenant_id}
+ router = self.admin_client.create_router(
+ name, True, **router_args)['router']
+ self.addCleanup(self.admin_client.delete_router, router['id'])
+
+ self.assertRaises(lib_exc.Conflict,
+ self.admin_client.create_router,
+ name, True, **router_args)
+
+ @test.attr(type='negative')
+ @test.idempotent_id('5c924ff7-b7a9-474f-92a3-dbe0f976ec13')
+ @test.requires_ext(extension="security-group", service="network")
+ def test_create_security_group_when_quotas_is_full(self):
+ tenant_id = self._create_tenant()['id']
+ sg_args = {'tenant_id': tenant_id}
+ # avoid a number that is made by default
+ sg_list = self.admin_client.list_security_groups(
+ tenant_id=tenant_id)['security_groups']
+ num = len(sg_list) + 1
+
+ new_quotas = {'security_group': num}
+ self._setup_quotas(tenant_id, **new_quotas)
+
+ sg = self.admin_client.create_security_group(
+ **sg_args)['security_group']
+ self.addCleanup(self.admin_client.delete_security_group, sg['id'])
+
+ self.assertRaises(lib_exc.Conflict,
+ self.admin_client.create_security_group, **sg_args)
+
+ @test.attr(type='negative')
+ @test.idempotent_id('b7143480-6118-4ed4-be38-1b6f15f30d05')
+ @test.requires_ext(extension="security-group", service="network")
+ def test_create_security_group_rule_when_quotas_is_full(self):
+ tenant_id = self._create_tenant()['id']
+ sg_args = {'tenant_id': tenant_id}
+
+ sg = self.admin_client.create_security_group(
+ **sg_args)['security_group']
+ self.addCleanup(self.admin_client.delete_security_group, sg['id'])
+
+ # avoid a number that is made by default
+ sg_rule_list = self.admin_client.list_security_group_rules(
+ tenant_id=tenant_id)['security_group_rules']
+ num = len(sg_rule_list) + 1
+
+ new_quotas = {'security_group_rule': num}
+ self._setup_quotas(tenant_id, **new_quotas)
+
+ sg_rule_args = {'tenant_id': tenant_id,
+ 'security_group_id': sg['id'],
+ 'direction': 'ingress'}
+ sg_rule = self.admin_client.create_security_group_rule(
+ **sg_rule_args)['security_group_rule']
+ self.addCleanup(
+ self.admin_client.delete_security_group_rule, sg_rule['id'])
+
+ sg_rule_args['direction'] = 'egress'
+ self.assertRaises(lib_exc.Conflict,
+ self.admin_client.create_security_group_rule,
+ **sg_rule_args)
+
+ @test.attr(type='negative')
+ @test.idempotent_id('d00fe5bb-9db8-4e1a-9c31-490f52897e6f')
+ @test.requires_ext(extension="router", service="network")
+ def test_create_floatingip_when_quotas_is_full(self):
+ tenant_id = self._create_tenant()['id']
+ new_quotas = {'floatingip': 1}
+ self._setup_quotas(tenant_id, **new_quotas)
+
+ ext_net_id = CONF.network.public_network_id
+ fip_args = {'tenant_id': tenant_id,
+ 'floating_network_id': ext_net_id}
+ fip = self.admin_client.create_floatingip(**fip_args)['floatingip']
+ self.addCleanup(self.admin_client.delete_floatingip, fip['id'])
+
+ self.assertRaises(lib_exc.Conflict,
+ self.admin_client.create_floatingip, **fip_args)
diff --git a/neutron/tests/tempest/api/base.py b/neutron/tests/tempest/api/base.py
index c1bd622..31d6c3a 100644
--- a/neutron/tests/tempest/api/base.py
+++ b/neutron/tests/tempest/api/base.py
@@ -13,11 +13,14 @@
# License for the specific language governing permissions and limitations
# under the License.
+import functools
+
import netaddr
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
from tempest import test
+from neutron.common import constants
from neutron.tests.tempest.api import clients
from neutron.tests.tempest import config
from neutron.tests.tempest import exceptions
@@ -460,3 +463,119 @@
message = (
"net(%s) has no usable IP address in allocation pools" % net_id)
raise exceptions.InvalidConfiguration(message)
+
+
+def _require_sorting(f):
+ @functools.wraps(f)
+ def inner(self, *args, **kwargs):
+ if not CONF.neutron_plugin_options.validate_sorting:
+ self.skipTest('Sorting feature is required')
+ return f(self, *args, **kwargs)
+ return inner
+
+
+def _require_pagination(f):
+ @functools.wraps(f)
+ def inner(self, *args, **kwargs):
+ if not CONF.neutron_plugin_options.validate_pagination:
+ self.skipTest('Pagination feature is required')
+ return f(self, *args, **kwargs)
+ return inner
+
+
+class BaseSearchCriteriaTest(BaseNetworkTest):
+
+ # This should be defined by subclasses to reflect resource name to test
+ resource = None
+
+ # NOTE(ihrachys): some names, like those starting with an underscore (_)
+ # are sorted differently depending on whether the plugin implements native
+ # sorting support, or not. So we avoid any such cases here, sticking to
+ # alphanumeric. Also test a case when there are multiple resources with the
+ # same name
+ resource_names = ('test1', 'abc1', 'test10', '123test') + ('test1',)
+
+ force_tenant_isolation = True
+
+ list_kwargs = {}
+
+ def list_method(self, *args, **kwargs):
+ method = getattr(self.client, 'list_%ss' % self.resource)
+ kwargs.update(self.list_kwargs)
+ return method(*args, **kwargs)
+
+ @classmethod
+ def _extract_resources(cls, body):
+ return body['%ss' % cls.resource]
+
+ def _test_list_sorts(self, direction):
+ sort_args = {
+ 'sort_dir': direction,
+ 'sort_key': 'name'
+ }
+ body = self.list_method(**sort_args)
+ resources = self._extract_resources(body)
+ self.assertNotEmpty(
+ resources, "%s list returned is empty" % self.resource)
+ retrieved_names = [res['name'] for res in resources]
+ expected = sorted(retrieved_names)
+ if direction == constants.SORT_DIRECTION_DESC:
+ expected = list(reversed(expected))
+ self.assertEqual(expected, retrieved_names)
+
+ @_require_sorting
+ def _test_list_sorts_asc(self):
+ self._test_list_sorts(constants.SORT_DIRECTION_ASC)
+
+ @_require_sorting
+ def _test_list_sorts_desc(self):
+ self._test_list_sorts(constants.SORT_DIRECTION_DESC)
+
+ @_require_pagination
+ def _test_list_pagination(self):
+ for limit in range(1, len(self.resource_names) + 1):
+ pagination_args = {
+ 'limit': limit,
+ }
+ body = self.list_method(**pagination_args)
+ resources = self._extract_resources(body)
+ self.assertEqual(limit, len(resources))
+
+ @_require_pagination
+ def _test_list_no_pagination_limit_0(self):
+ pagination_args = {
+ 'limit': 0,
+ }
+ body = self.list_method(**pagination_args)
+ resources = self._extract_resources(body)
+ self.assertTrue(len(resources) >= len(self.resource_names))
+
+ @_require_pagination
+ @_require_sorting
+ def _test_list_pagination_with_marker(self):
+ # first, collect all resources for later comparison
+ sort_args = {
+ 'sort_dir': constants.SORT_DIRECTION_ASC,
+ 'sort_key': 'name'
+ }
+ body = self.list_method(**sort_args)
+ expected_resources = self._extract_resources(body)
+ self.assertNotEmpty(expected_resources)
+
+ # paginate resources one by one, using last fetched resource as a
+ # marker
+ resources = []
+ for i in range(len(expected_resources)):
+ pagination_args = sort_args.copy()
+ pagination_args['limit'] = 1
+ if resources:
+ pagination_args['marker'] = resources[-1]['id']
+ body = self.list_method(**pagination_args)
+ resources_ = self._extract_resources(body)
+ self.assertEqual(1, len(resources_))
+ resources.extend(resources_)
+
+ # finally, compare that the list retrieved in one go is identical to
+ # the one containing pagination results
+ for expected, res in zip(expected_resources, resources):
+ self.assertEqual(expected['name'], res['name'])
diff --git a/neutron/tests/tempest/api/test_networks.py b/neutron/tests/tempest/api/test_networks.py
index b96a5bd..7b133b1 100644
--- a/neutron/tests/tempest/api/test_networks.py
+++ b/neutron/tests/tempest/api/test_networks.py
@@ -89,3 +89,41 @@
self.assertNotEmpty(networks, "Network list returned is empty")
for network in networks:
self.assertEqual(sorted(network.keys()), sorted(fields))
+
+
+class NetworksSearchCriteriaTest(base.BaseSearchCriteriaTest):
+
+ resource = 'network'
+
+ list_kwargs = {'shared': False}
+
+ @classmethod
+ def resource_setup(cls):
+ super(NetworksSearchCriteriaTest, cls).resource_setup()
+ for name in cls.resource_names:
+ cls.create_network(network_name=name)
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('de27d34a-bd9d-4516-83d6-81ef723f7d0d')
+ def test_list_sorts_asc(self):
+ self._test_list_sorts_asc()
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('e767a160-59f9-4c4b-8dc1-72124a68640a')
+ def test_list_sorts_desc(self):
+ self._test_list_sorts_desc()
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('71389852-f57b-49f2-b109-77b705e9e8af')
+ def test_list_pagination(self):
+ self._test_list_pagination()
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('71389852-f57b-49f2-b109-77b705e9e8af')
+ def test_list_pagination_with_marker(self):
+ self._test_list_pagination_with_marker()
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('f1867fc5-e1d6-431f-bc9f-8b882e43a7f9')
+ def test_list_no_pagination_limit_0(self):
+ self._test_list_no_pagination_limit_0()
diff --git a/neutron/tests/tempest/api/test_networks_negative.py b/neutron/tests/tempest/api/test_networks_negative.py
new file mode 100644
index 0000000..87da1b8
--- /dev/null
+++ b/neutron/tests/tempest/api/test_networks_negative.py
@@ -0,0 +1,36 @@
+# 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.lib import exceptions as lib_exc
+from tempest import test
+import testtools
+
+from neutron.tests.tempest.api import base
+
+
+class NetworksNegativeTest(base.BaseNetworkTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(NetworksNegativeTest, cls).resource_setup()
+ cls.network = cls.create_network()
+ cls.subnet = cls.create_subnet(cls.network)
+
+ @test.attr(type='negative')
+ @test.idempotent_id('9f80f25b-5d1b-4f26-9f6b-774b9b270819')
+ def test_delete_network_in_use(self):
+ port = self.client.create_port(network_id=self.network['id'])
+ self.addCleanup(self.client.delete_port, port['port']['id'])
+ with testtools.ExpectedException(lib_exc.Conflict):
+ self.client.delete_subnet(self.subnet['id'])
+ with testtools.ExpectedException(lib_exc.Conflict):
+ self.client.delete_network(self.network['id'])
diff --git a/neutron/tests/tempest/api/test_ports.py b/neutron/tests/tempest/api/test_ports.py
index dd929da..a8e8c4d 100644
--- a/neutron/tests/tempest/api/test_ports.py
+++ b/neutron/tests/tempest/api/test_ports.py
@@ -39,3 +39,47 @@
self.assertEqual('d2', body['port']['description'])
body = self.client.list_ports(id=body['port']['id'])['ports'][0]
self.assertEqual('d2', body['description'])
+
+ @test.idempotent_id('c72c1c0c-2193-4aca-bbb4-b1442640c123')
+ def test_change_dhcp_flag_then_create_port(self):
+ s = self.create_subnet(self.network, enable_dhcp=False)
+ self.create_port(self.network)
+ self.client.update_subnet(s['id'], enable_dhcp=True)
+ self.create_port(self.network)
+
+
+class PortsSearchCriteriaTest(base.BaseSearchCriteriaTest):
+
+ resource = 'port'
+
+ @classmethod
+ def resource_setup(cls):
+ super(PortsSearchCriteriaTest, cls).resource_setup()
+ net = cls.create_network(network_name='port-search-test-net')
+ for name in cls.resource_names:
+ cls.create_port(net, name=name)
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('9ab73df4-960a-4ae3-87d3-60992b8d3e2d')
+ def test_list_sorts_asc(self):
+ self._test_list_sorts_asc()
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('b426671d-7270-430f-82ff-8f33eec93010')
+ def test_list_sorts_desc(self):
+ self._test_list_sorts_desc()
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('a202fdc8-6616-45df-b6a0-463932de6f94')
+ def test_list_pagination(self):
+ self._test_list_pagination()
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('f4723b8e-8186-4b9a-bf9e-57519967e048')
+ def test_list_pagination_with_marker(self):
+ self._test_list_pagination_with_marker()
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('3afe7024-77ab-4cfe-824b-0b2bf4217727')
+ def test_list_no_pagination_limit_0(self):
+ self._test_list_no_pagination_limit_0()
diff --git a/neutron/tests/tempest/api/test_routers_negative.py b/neutron/tests/tempest/api/test_routers_negative.py
index 2ccb34a..6a028db 100644
--- a/neutron/tests/tempest/api/test_routers_negative.py
+++ b/neutron/tests/tempest/api/test_routers_negative.py
@@ -21,20 +21,41 @@
from neutron.tests.tempest.api import base_routers as base
-class DvrRoutersNegativeTest(base.BaseRouterTest):
+class RoutersNegativeTestBase(base.BaseRouterTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(RoutersNegativeTestBase, cls).resource_setup()
+ cls.router = cls.create_router(data_utils.rand_name('router'))
+ cls.network = cls.create_network()
+ cls.subnet = cls.create_subnet(cls.network)
+
+
+class RoutersNegativeTest(RoutersNegativeTestBase):
+
+ @classmethod
+ @test.requires_ext(extension="router", service="network")
+ def skip_checks(cls):
+ super(RoutersNegativeTest, cls).skip_checks()
+
+ @test.attr(type='negative')
+ @test.idempotent_id('e3e751af-15a2-49cc-b214-a7154579e94f')
+ def test_delete_router_in_use(self):
+ # This port is deleted after a test by remove_router_interface.
+ port = self.client.create_port(network_id=self.network['id'])
+ self.client.add_router_interface_with_port_id(
+ self.router['id'], port['port']['id'])
+ with testtools.ExpectedException(lib_exc.Conflict):
+ self.client.delete_router(self.router['id'])
+
+
+class DvrRoutersNegativeTest(RoutersNegativeTestBase):
@classmethod
@test.requires_ext(extension="dvr", service="network")
def skip_checks(cls):
super(DvrRoutersNegativeTest, cls).skip_checks()
- @classmethod
- def resource_setup(cls):
- super(DvrRoutersNegativeTest, cls).resource_setup()
- cls.router = cls.create_router(data_utils.rand_name('router'))
- cls.network = cls.create_network()
- cls.subnet = cls.create_subnet(cls.network)
-
@test.attr(type='negative')
@test.idempotent_id('4990b055-8fc7-48ab-bba7-aa28beaad0b9')
def test_router_create_tenant_distributed_returns_forbidden(self):
diff --git a/neutron/tests/tempest/config.py b/neutron/tests/tempest/config.py
index f50fa39..bad1000 100644
--- a/neutron/tests/tempest/config.py
+++ b/neutron/tests/tempest/config.py
@@ -12,6 +12,7 @@
from oslo_config import cfg
+from neutron import api
from tempest import config
@@ -22,7 +23,13 @@
cfg.BoolOpt('specify_floating_ip_address_available',
default=True,
help='Allow passing an IP Address of the floating ip when '
- 'creating the floating ip')]
+ 'creating the floating ip'),
+ cfg.BoolOpt('validate_pagination',
+ default=api.DEFAULT_ALLOW_PAGINATION,
+ help='Validate pagination'),
+ cfg.BoolOpt('validate_sorting',
+ default=api.DEFAULT_ALLOW_SORTING,
+ help='Validate sorting')]
# TODO(amuller): Redo configuration options registration as part of the planned
# transition to the Tempest plugin architecture