Merge "Include timezone in timestamp fields"
diff --git a/neutron/tests/tempest/api/admin/test_quotas_negative.py b/neutron/tests/tempest/api/admin/test_quotas_negative.py
index 12ae0be..3ff49c6 100644
--- a/neutron/tests/tempest/api/admin/test_quotas_negative.py
+++ b/neutron/tests/tempest/api/admin/test_quotas_negative.py
@@ -71,6 +71,7 @@
subnet_args = {'tenant_id': tenant_id,
'network_id': net['id'],
+ 'enable_dhcp': False,
'cidr': '10.0.0.0/24',
'ip_version': '4'}
subnet = self.admin_client.create_subnet(**subnet_args)['subnet']
diff --git a/neutron/tests/tempest/api/admin/test_routers_flavors.py b/neutron/tests/tempest/api/admin/test_routers_flavors.py
new file mode 100644
index 0000000..300c956
--- /dev/null
+++ b/neutron/tests/tempest/api/admin/test_routers_flavors.py
@@ -0,0 +1,97 @@
+#
+# 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_routers as base
+
+
+class RoutersFlavorTestCase(base.BaseRouterTest):
+
+ @classmethod
+ @test.requires_ext(extension="router", service="network")
+ @test.requires_ext(extension="flavors", service="network")
+ def skip_checks(cls):
+ super(RoutersFlavorTestCase, cls).skip_checks()
+
+ @classmethod
+ def resource_setup(cls):
+ super(RoutersFlavorTestCase, cls).resource_setup()
+ cls.service_profiles = []
+ cls.flavor_service_profiles = []
+ # make a flavor based on legacy router for regular tenant to use
+ driver = ('neutron.services.l3_router.service_providers.'
+ 'single_node.SingleNodeDriver')
+ sp = cls.admin_client.create_service_profile(driver=driver)
+ cls.service_profiles.append(sp['service_profile'])
+ cls.flavor = cls.create_flavor(
+ name='special_flavor',
+ description='econonomy class',
+ service_type='L3_ROUTER_NAT')
+ cls.admin_client.create_flavor_service_profile(
+ cls.flavor['id'], sp['service_profile']['id'])
+ cls.flavor_service_profiles.append((cls.flavor['id'],
+ sp['service_profile']['id']))
+ # make another with a different driver
+ driver = ('neutron.services.l3_router.service_providers.'
+ 'dvr.DvrDriver')
+ sp = cls.admin_client.create_service_profile(driver=driver)
+ cls.service_profiles.append(sp['service_profile'])
+ cls.prem_flavor = cls.create_flavor(
+ name='better_special_flavor',
+ description='econonomy comfort',
+ service_type='L3_ROUTER_NAT')
+ cls.admin_client.create_flavor_service_profile(
+ cls.prem_flavor['id'], sp['service_profile']['id'])
+ cls.flavor_service_profiles.append((cls.prem_flavor['id'],
+ sp['service_profile']['id']))
+
+ @classmethod
+ def resource_cleanup(cls):
+ for flavor_id, service_profile_id in cls.flavor_service_profiles:
+ cls.admin_client.delete_flavor_service_profile(flavor_id,
+ service_profile_id)
+ for service_profile in cls.service_profiles:
+ cls.admin_client.delete_service_profile(
+ service_profile['id'])
+ super(RoutersFlavorTestCase, cls).resource_cleanup()
+
+ @test.idempotent_id('a4d01977-e968-4983-b4d9-824ea6c33f4b')
+ def test_create_router_with_flavor(self):
+ # ensure regular client can see flavor
+ flavors = self.client.list_flavors(id=self.flavor['id'])
+ flavor = flavors['flavors'][0]
+ self.assertEqual('special_flavor', flavor['name'])
+ flavors = self.client.list_flavors(id=self.prem_flavor['id'])
+ prem_flavor = flavors['flavors'][0]
+ self.assertEqual('better_special_flavor', prem_flavor['name'])
+
+ # ensure client can create router with both flavors
+ router = self.create_router('name', flavor_id=flavor['id'])
+ self.assertEqual(flavor['id'], router['flavor_id'])
+ router = self.create_router('name', flavor_id=prem_flavor['id'])
+ self.assertEqual(prem_flavor['id'], router['flavor_id'])
+
+ @test.idempotent_id('30e73858-a0fc-409c-a2e0-e9cd2826f6a2')
+ def test_delete_router_flavor_in_use(self):
+ self.create_router('name', flavor_id=self.flavor['id'])
+ with testtools.ExpectedException(lib_exc.Conflict):
+ self.admin_client.delete_flavor(self.flavor['id'])
+
+ @test.idempotent_id('83939cf7-5070-41bc-9a3e-cd9f22df2186')
+ def test_badrequest_on_requesting_flags_and_flavor(self):
+ with testtools.ExpectedException(lib_exc.BadRequest):
+ self.admin_client.create_router(
+ 'name', flavor_id=self.flavor['id'], distributed=True)
diff --git a/neutron/tests/tempest/api/base.py b/neutron/tests/tempest/api/base.py
index 045cca2..ffb2dfb 100644
--- a/neutron/tests/tempest/api/base.py
+++ b/neutron/tests/tempest/api/base.py
@@ -728,3 +728,12 @@
# marker
expected_resources[:-1],
self._extract_resources(body))
+
+ def _test_list_validation_filters(self):
+ validation_args = {
+ 'unknown_filter': 'value',
+ }
+ body = self.list_method(**validation_args)
+ resources = self._extract_resources(body)
+ for resource in resources:
+ self.assertIn(resource['name'], self.resource_names)
diff --git a/neutron/tests/tempest/api/test_extensions.py b/neutron/tests/tempest/api/test_extensions.py
index 28029d8..b1b09e8 100644
--- a/neutron/tests/tempest/api/test_extensions.py
+++ b/neutron/tests/tempest/api/test_extensions.py
@@ -34,3 +34,7 @@
@test.idempotent_id('19db409e-a23f-445d-8bc8-ca3d64c84706')
def test_list_extensions_pagination(self):
self._test_list_extensions_includes('pagination')
+
+ @test.idempotent_id('155b7bc2-e358-4dd8-bf3e-1774c084567f')
+ def test_list_extensions_project_id(self):
+ self._test_list_extensions_includes('project-id')
diff --git a/neutron/tests/tempest/api/test_floating_ips.py b/neutron/tests/tempest/api/test_floating_ips.py
index 8ccdd44..bafa54c 100644
--- a/neutron/tests/tempest/api/test_floating_ips.py
+++ b/neutron/tests/tempest/api/test_floating_ips.py
@@ -71,3 +71,33 @@
self.assertEqual('d2', body['floatingip']['description'])
body = self.client.show_floatingip(body['floatingip']['id'])
self.assertEqual('d2', body['floatingip']['description'])
+ # disassociate
+ body = self.client.update_floatingip(body['floatingip']['id'],
+ port_id=None)
+ self.assertEqual('d2', body['floatingip']['description'])
+
+ @test.idempotent_id('fd7161e1-2167-4686-a6ff-0f3df08001bb')
+ @test.requires_ext(extension="standard-attr-description",
+ service="network")
+ def test_floatingip_update_extra_attributes_port_id_not_changed(self):
+ port_id = self.ports[1]['id']
+ body = self.client.create_floatingip(
+ floating_network_id=self.ext_net_id,
+ port_id=port_id,
+ description='d1'
+ )['floatingip']
+ self.assertEqual('d1', body['description'])
+ body = self.client.show_floatingip(body['id'])['floatingip']
+ self.assertEqual(port_id, body['port_id'])
+ # Update description
+ body = self.client.update_floatingip(body['id'], description='d2')
+ self.assertEqual('d2', body['floatingip']['description'])
+ # Floating IP association is not changed.
+ self.assertEqual(port_id, body['floatingip']['port_id'])
+ body = self.client.show_floatingip(body['floatingip']['id'])
+ self.assertEqual('d2', body['floatingip']['description'])
+ self.assertEqual(port_id, body['floatingip']['port_id'])
+ # disassociate
+ body = self.client.update_floatingip(body['floatingip']['id'],
+ port_id=None)
+ self.assertEqual(None, body['floatingip']['port_id'])
diff --git a/neutron/tests/tempest/api/test_networks.py b/neutron/tests/tempest/api/test_networks.py
index 2c2991a..439d7a9 100644
--- a/neutron/tests/tempest/api/test_networks.py
+++ b/neutron/tests/tempest/api/test_networks.py
@@ -46,6 +46,10 @@
fields.append('mtu')
for key in fields:
self.assertEqual(network[key], self.network[key])
+ project_id = self.client.tenant_id
+ self.assertEqual(project_id, network['tenant_id'])
+ if test.is_extension_enabled('project-id', 'network'):
+ self.assertEqual(project_id, network['project_id'])
@test.idempotent_id('867819bb-c4b6-45f7-acf9-90edcf70aa5e')
def test_show_network_fields(self):
@@ -59,6 +63,27 @@
self.assertEqual(sorted(network.keys()), sorted(fields))
for field_name in fields:
self.assertEqual(network[field_name], self.network[field_name])
+ self.assertNotIn('tenant_id', network)
+ self.assertNotIn('project_id', network)
+
+ @test.idempotent_id('26f2b7a5-2cd1-4f3a-b11f-ad259b099b11')
+ @test.requires_ext(extension="project-id", service="network")
+ def test_show_network_fields_keystone_v3(self):
+
+ def _check_show_network_fields(fields, expect_project_id,
+ expect_tenant_id):
+ params = {}
+ if fields:
+ params['fields'] = fields
+ body = self.client.show_network(self.network['id'], **params)
+ network = body['network']
+ self.assertEqual(expect_project_id, 'project_id' in network)
+ self.assertEqual(expect_tenant_id, 'tenant_id' in network)
+
+ _check_show_network_fields(None, True, True)
+ _check_show_network_fields(['tenant_id'], False, True)
+ _check_show_network_fields(['project_id'], True, False)
+ _check_show_network_fields(['project_id', 'tenant_id'], True, True)
@test.idempotent_id('c72c1c0c-2193-4aca-ccc4-b1442640bbbb')
@test.requires_ext(extension="standard-attr-description",
@@ -75,6 +100,28 @@
body = self.client.list_networks(id=net_id)['networks'][0]
self.assertEqual('d2', body['description'])
+ @test.idempotent_id('0cc0552f-afaf-4231-b7a7-c2a1774616da')
+ @test.requires_ext(extension="project-id", service="network")
+ def test_create_network_keystone_v3(self):
+ project_id = self.client.tenant_id
+
+ name = 'created-with-project_id'
+ body = self.client.create_network_keystone_v3(name, project_id)
+ new_net = body['network']
+ self.assertEqual(name, new_net['name'])
+ self.assertEqual(project_id, new_net['project_id'])
+ self.assertEqual(project_id, new_net['tenant_id'])
+
+ body = self.client.list_networks(id=new_net['id'])['networks'][0]
+ self.assertEqual(name, body['name'])
+
+ new_name = 'create-with-project_id-2'
+ body = self.client.update_network(new_net['id'], name=new_name)
+ new_net = body['network']
+ self.assertEqual(new_name, new_net['name'])
+ self.assertEqual(project_id, new_net['project_id'])
+ self.assertEqual(project_id, new_net['tenant_id'])
+
@test.idempotent_id('6ae6d24f-9194-4869-9c85-c313cb20e080')
def test_list_networks_fields(self):
# Verify specific fields of the networks
@@ -87,6 +134,26 @@
for network in networks:
self.assertEqual(sorted(network.keys()), sorted(fields))
+ @test.idempotent_id('a23186b9-aa6f-4b08-b877-35ca3b9cd54c')
+ @test.requires_ext(extension="project-id", service="network")
+ def test_list_networks_fields_keystone_v3(self):
+ def _check_list_networks_fields(fields, expect_project_id,
+ expect_tenant_id):
+ params = {}
+ if fields:
+ params['fields'] = fields
+ body = self.client.list_networks(**params)
+ networks = body['networks']
+ self.assertNotEmpty(networks, "Network list returned is empty")
+ for network in networks:
+ self.assertEqual(expect_project_id, 'project_id' in network)
+ self.assertEqual(expect_tenant_id, 'tenant_id' in network)
+
+ _check_list_networks_fields(None, True, True)
+ _check_list_networks_fields(['tenant_id'], False, True)
+ _check_list_networks_fields(['project_id'], True, False)
+ _check_list_networks_fields(['project_id', 'tenant_id'], True, True)
+
class NetworksSearchCriteriaTest(base.BaseSearchCriteriaTest):
@@ -135,3 +202,7 @@
@test.idempotent_id('f1867fc5-e1d6-431f-bc9f-8b882e43a7f9')
def test_list_no_pagination_limit_0(self):
self._test_list_no_pagination_limit_0()
+
+ @test.idempotent_id('3574ec9b-a8b8-43e3-9c11-98f5875df6a9')
+ def test_list_validation_filters(self):
+ self._test_list_validation_filters()
diff --git a/neutron/tests/tempest/api/test_ports.py b/neutron/tests/tempest/api/test_ports.py
index 916f549..093de07 100644
--- a/neutron/tests/tempest/api/test_ports.py
+++ b/neutron/tests/tempest/api/test_ports.py
@@ -47,6 +47,18 @@
self.client.update_subnet(s['id'], enable_dhcp=True)
self.create_port(self.network)
+ @test.idempotent_id('1d6d8683-8691-43c6-a7ba-c69723258726')
+ def test_add_ips_to_port(self):
+ s = self.create_subnet(self.network)
+ port = self.create_port(self.network)
+ # request another IP on the same subnet
+ port['fixed_ips'].append({'subnet_id': s['id']})
+ updated = self.client.update_port(port['id'],
+ fixed_ips=port['fixed_ips'])
+ subnets = [ip['subnet_id'] for ip in updated['port']['fixed_ips']]
+ expected = [s['id'], s['id']]
+ self.assertEqual(expected, subnets)
+
class PortsSearchCriteriaTest(base.BaseSearchCriteriaTest):
diff --git a/neutron/tests/tempest/api/test_qos.py b/neutron/tests/tempest/api/test_qos.py
index a2a9941..b9572ca 100644
--- a/neutron/tests/tempest/api/test_qos.py
+++ b/neutron/tests/tempest/api/test_qos.py
@@ -554,6 +554,7 @@
self.client2.show_qos_policy(qos_pol['id'])
rbac_pol = {'target_tenant': '*',
'tenant_id': self.admin_client.tenant_id,
+ 'project_id': self.admin_client.tenant_id,
'object_type': 'qos_policy',
'object_id': qos_pol['id'],
'action': 'access_as_shared'}
diff --git a/neutron/tests/tempest/api/test_revisions.py b/neutron/tests/tempest/api/test_revisions.py
index 0ecb7b8..10438b7 100644
--- a/neutron/tests/tempest/api/test_revisions.py
+++ b/neutron/tests/tempest/api/test_revisions.py
@@ -153,3 +153,5 @@
b2 = self.client.update_floatingip(body['id'], description='d2')
self.assertGreater(b2['floatingip']['revision_number'],
body['revision_number'])
+ # disassociate
+ self.client.update_floatingip(b2['floatingip']['id'], port_id=None)
diff --git a/neutron/tests/tempest/api/test_subnetpools.py b/neutron/tests/tempest/api/test_subnetpools.py
index 5bd222f..e8ec954 100644
--- a/neutron/tests/tempest/api/test_subnetpools.py
+++ b/neutron/tests/tempest/api/test_subnetpools.py
@@ -110,13 +110,15 @@
body = self._create_subnetpool(description='d1')
self.assertEqual('d1', body['description'])
sub_id = body['id']
- body = filter(lambda x: x['id'] == sub_id,
- self.client.list_subnetpools()['subnetpools'])[0]
+ subnet_pools = [x for x in
+ self.client.list_subnetpools()['subnetpools'] if x['id'] == sub_id]
+ body = subnet_pools[0]
self.assertEqual('d1', body['description'])
body = self.client.update_subnetpool(sub_id, description='d2')
self.assertEqual('d2', body['subnetpool']['description'])
- body = filter(lambda x: x['id'] == sub_id,
- self.client.list_subnetpools()['subnetpools'])[0]
+ subnet_pools = [x for x in
+ self.client.list_subnetpools()['subnetpools'] if x['id'] == sub_id]
+ body = subnet_pools[0]
self.assertEqual('d2', body['description'])
@test.idempotent_id('741d08c2-1e3f-42be-99c7-0ea93c5b728c')
@@ -390,3 +392,7 @@
@test.idempotent_id('82a13efc-c18f-4249-b8ec-cec7cf26fbd6')
def test_list_no_pagination_limit_0(self):
self._test_list_no_pagination_limit_0()
+
+ @test.idempotent_id('27feb3f8-40f4-4e50-8cd2-7d0096a98682')
+ def test_list_validation_filters(self):
+ self._test_list_validation_filters()
diff --git a/neutron/tests/tempest/api/test_subnets.py b/neutron/tests/tempest/api/test_subnets.py
index a3a2e00..4e63a3a 100644
--- a/neutron/tests/tempest/api/test_subnets.py
+++ b/neutron/tests/tempest/api/test_subnets.py
@@ -63,3 +63,7 @@
@test.idempotent_id('d851937c-9821-4b46-9d18-43e9077ecac0')
def test_list_no_pagination_limit_0(self):
self._test_list_no_pagination_limit_0()
+
+ @test.idempotent_id('c0f9280b-9d81-4728-a967-6be22659d4c8')
+ def test_list_validation_filters(self):
+ self._test_list_validation_filters()
diff --git a/neutron/tests/tempest/api/test_trunk.py b/neutron/tests/tempest/api/test_trunk.py
index bf15d9a..d5aa7db 100644
--- a/neutron/tests/tempest/api/test_trunk.py
+++ b/neutron/tests/tempest/api/test_trunk.py
@@ -58,33 +58,18 @@
trunks_cleanup(cls.client, cls.trunks)
super(TrunkTestJSONBase, cls).resource_cleanup()
- def _remove_timestamps(self, trunk):
- # Let's make sure these fields exist, but let's not
- # use them in the comparison, in case skews or
- # roundups get in the way.
- created_at = trunk.pop('created_at')
- updated_at = trunk.pop('updated_at')
- self.assertIsNotNone(created_at)
- self.assertIsNotNone(updated_at)
-
def _create_trunk_with_network_and_parent(self, subports, **kwargs):
network = self.create_network()
parent_port = self.create_port(network)
trunk = self.client.create_trunk(parent_port['id'], subports, **kwargs)
self.trunks.append(trunk['trunk'])
- self._remove_timestamps(trunk['trunk'])
return trunk
def _show_trunk(self, trunk_id):
- trunk = self.client.show_trunk(trunk_id)
- self._remove_timestamps(trunk['trunk'])
- return trunk
+ return self.client.show_trunk(trunk_id)
def _list_trunks(self):
- trunks = self.client.list_trunks()
- for t in trunks['trunks']:
- self._remove_timestamps(t)
- return trunks
+ return self.client.list_trunks()
class TrunkTestJSON(TrunkTestJSONBase):
diff --git a/neutron/tests/tempest/services/network/json/network_client.py b/neutron/tests/tempest/services/network/json/network_client.py
index d788687..4828059 100644
--- a/neutron/tests/tempest/services/network/json/network_client.py
+++ b/neutron/tests/tempest/services/network/json/network_client.py
@@ -795,6 +795,29 @@
self.expected_success(204, resp.status)
return service_client.ResponseBody(resp, body)
+ def create_flavor_service_profile(self, flavor_id, service_profile_id):
+ body = jsonutils.dumps({'service_profile': {'id': service_profile_id}})
+ uri = '%s/flavors/%s/service_profiles' % (self.uri_prefix, flavor_id)
+ resp, body = self.post(uri, body)
+ self.expected_success(201, resp.status)
+ body = jsonutils.loads(body)
+ return service_client.ResponseBody(resp, body)
+
+ def list_flavor_service_profiles(self, flavor_id):
+ uri = '%s/flavors/%s/service_profiles' % (self.uri_prefix, flavor_id)
+ resp, body = self.get(uri)
+ self.expected_success(200, resp.status)
+ body = jsonutils.loads(body)
+ return service_client.ResponseBody(resp, body)
+
+ def delete_flavor_service_profile(self, flavor_id, service_profile_id):
+ uri = '%s/flavors/%s/service_profiles/%s' % (self.uri_prefix,
+ flavor_id,
+ service_profile_id)
+ resp, body = self.delete(uri)
+ self.expected_success(204, resp.status)
+ return service_client.ResponseBody(resp, body)
+
def create_security_group_rule(self, direction, security_group_id,
**kwargs):
post_body = {'security_group_rule': kwargs}
@@ -849,6 +872,19 @@
body = jsonutils.loads(body)
return service_client.ResponseBody(resp, body)
+ def create_network_keystone_v3(self, name, project_id):
+ uri = '%s/networks' % self.uri_prefix
+ post_data = {
+ 'network': {
+ 'name': name,
+ 'project_id': project_id
+ }
+ }
+ resp, body = self.post(uri, self.serialize(post_data))
+ body = self.deserialize_single(body)
+ self.expected_success(201, resp.status)
+ return service_client.ResponseBody(resp, body)
+
def list_extensions(self, **filters):
uri = self.get_uri("extensions")
if filters: