Merge "tests: added sorting/pagination api tests for subnetpools"
diff --git a/neutron/tests/tempest/api/admin/test_external_network_extension.py b/neutron/tests/tempest/api/admin/test_external_network_extension.py
index ed56144..99e10ee 100644
--- a/neutron/tests/tempest/api/admin/test_external_network_extension.py
+++ b/neutron/tests/tempest/api/admin/test_external_network_extension.py
@@ -53,7 +53,7 @@
external_gateway_info={'network_id': net['id']})['router']
self.addCleanup(self.admin_client.delete_router, r['id'])
- @test.idempotent_id('afd8f1b7-a81e-4629-bca8-a367b3a144bb')
+ @test.idempotent_id('eff9443a-2d04-48ee-840e-d955ac564bcd')
def test_regular_client_blocked_from_creating_external_wild_policies(self):
net = self.create_network()
with testtools.ExpectedException(lib_exc.Forbidden):
diff --git a/neutron/tests/tempest/api/base.py b/neutron/tests/tempest/api/base.py
index 993e356..45e12f0 100644
--- a/neutron/tests/tempest/api/base.py
+++ b/neutron/tests/tempest/api/base.py
@@ -616,6 +616,7 @@
if prev_links:
uri = self.get_bare_url(prev_links['next'])
else:
+ sort_args.update(self.list_kwargs)
uri = self.client.build_uri(
self.plural_name, limit=1, **sort_args)
prev_links, body = self.client.get_uri_with_links(
@@ -674,6 +675,7 @@
if prev_links:
uri = self.get_bare_url(prev_links['previous'])
else:
+ pagination_args.update(self.list_kwargs)
uri = self.client.build_uri(
self.plural_name, page_reverse=True, **pagination_args)
prev_links, body = self.client.get_uri_with_links(
diff --git a/neutron/tests/tempest/api/clients.py b/neutron/tests/tempest/api/clients.py
index d9879b0..8b51c6e 100644
--- a/neutron/tests/tempest/api/clients.py
+++ b/neutron/tests/tempest/api/clients.py
@@ -13,24 +13,21 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib.services.compute import keypairs_client
+from tempest.lib.services.compute import servers_client
from tempest import manager
-from tempest.services.identity.v2.json.tenants_client import \
- TenantsClient
+from tempest.services.identity.v2.json import tenants_client
from neutron.tests.tempest import config
-from neutron.tests.tempest.services.network.json.network_client import \
- NetworkClientJSON
-
+from neutron.tests.tempest.services.network.json import network_client
CONF = config.CONF
class Manager(manager.Manager):
-
"""
Top level manager for OpenStack tempest clients
"""
-
default_params = {
'disable_ssl_certificate_validation':
CONF.identity.disable_ssl_certificate_validation,
@@ -51,7 +48,7 @@
self._set_identity_clients()
- self.network_client = NetworkClientJSON(
+ self.network_client = network_client.NetworkClientJSON(
self.auth_provider,
CONF.network.catalog_type,
CONF.network.region or CONF.identity.region,
@@ -60,6 +57,23 @@
build_timeout=CONF.network.build_timeout,
**self.default_params)
+ params = {
+ 'service': CONF.compute.catalog_type,
+ 'region': CONF.compute.region or CONF.identity.region,
+ 'endpoint_type': CONF.compute.endpoint_type,
+ 'build_interval': CONF.compute.build_interval,
+ 'build_timeout': CONF.compute.build_timeout
+ }
+ params.update(self.default_params)
+
+ self.servers_client = servers_client.ServersClient(
+ self.auth_provider,
+ enable_instance_password=CONF.compute_feature_enabled
+ .enable_instance_password,
+ **params)
+ self.keypairs_client = keypairs_client.KeyPairsClient(
+ self.auth_provider, **params)
+
def _set_identity_clients(self):
params = {
'service': CONF.identity.catalog_type,
@@ -69,5 +83,5 @@
params_v2_admin = params.copy()
params_v2_admin['endpoint_type'] = CONF.identity.v2_admin_endpoint_type
# Client uses admin endpoint type of Keystone API v2
- self.tenants_client = TenantsClient(self.auth_provider,
- **params_v2_admin)
+ self.tenants_client = tenants_client.TenantsClient(self.auth_provider,
+ **params_v2_admin)
diff --git a/neutron/tests/tempest/api/test_extension_driver_port_security.py b/neutron/tests/tempest/api/test_extension_driver_port_security.py
index de25d9f..71cc6c0 100644
--- a/neutron/tests/tempest/api/test_extension_driver_port_security.py
+++ b/neutron/tests/tempest/api/test_extension_driver_port_security.py
@@ -53,7 +53,7 @@
self.assertEqual(network['port_security_enabled'], port_sec_net)
self.assertEqual(port['port_security_enabled'], expected)
- @test.idempotent_id('05642059-1bfc-4581-9bc9-aaa5db08dd60')
+ @test.idempotent_id('fe7c27b9-f320-4daf-b977-b1547c43daf6')
@test.requires_ext(extension='port-security', service='network')
def test_create_port_sec_with_security_group(self):
network = self.create_network(port_security_enabled=True)
@@ -69,7 +69,7 @@
self.assertEmpty(port['security_groups'])
@test.attr(type='negative')
- @test.idempotent_id('05642059-1bfc-4581-9bc9-aaa5db08dd60')
+ @test.idempotent_id('ff11226c-a5ff-4ad4-8480-0840e36e47a9')
@test.requires_ext(extension='port-security', service='network')
def test_port_sec_update_port_failed(self):
network = self.create_network()
diff --git a/neutron/tests/tempest/api/test_flavors_extensions.py b/neutron/tests/tempest/api/test_flavors_extensions.py
index 57ce27d..e0dda0b 100644
--- a/neutron/tests/tempest/api/test_flavors_extensions.py
+++ b/neutron/tests/tempest/api/test_flavors_extensions.py
@@ -63,7 +63,7 @@
labels = self.admin_client.list_service_profiles(id=service_profile_id)
self.assertEqual(len(labels['service_profiles']), 0)
- @test.idempotent_id('ec8e15ff-95d0-433b-b8a6-b466bddb1e50')
+ @test.idempotent_id('b12a9487-b6a2-4cff-a69a-fe2a0b64fae6')
def test_create_update_delete_service_profile(self):
# Creates a service profile
description = "service_profile created by tempest"
@@ -86,7 +86,7 @@
id=service_profile['id']))
self.assertEqual(len(labels['service_profiles']), 1)
- @test.idempotent_id('ec8e15ff-95d0-433b-b8a6-b466bddb1e50')
+ @test.idempotent_id('136bcf09-00af-4da7-9b7f-174735d4aebd')
def test_create_update_delete_flavor(self):
# Creates a flavor
description = "flavor created by tempest"
@@ -118,7 +118,7 @@
service_profile['metainfo'])
self.assertTrue(service_profile['enabled'])
- @test.idempotent_id('30abb445-0eea-472e-bd02-8649f54a5968')
+ @test.idempotent_id('362f9658-164b-44dd-8356-151bc9b7be72')
def test_show_flavor(self):
# Verifies the details of a flavor
body = self.admin_client.show_flavor(self.flavor['id'])
@@ -128,7 +128,7 @@
self.assertEqual(self.flavor['name'], flavor['name'])
self.assertTrue(flavor['enabled'])
- @test.idempotent_id('e2fb2f8c-45bf-429a-9f17-171c70444612')
+ @test.idempotent_id('eb3dd12e-6dfd-45f4-8393-46e0fa19860e')
def test_list_flavors(self):
# Verify flavor lists
body = self.admin_client.list_flavors(id=33)
diff --git a/neutron/tests/tempest/api/test_metering_extensions.py b/neutron/tests/tempest/api/test_metering_extensions.py
index 42b8e48..756cd5a 100644
--- a/neutron/tests/tempest/api/test_metering_extensions.py
+++ b/neutron/tests/tempest/api/test_metering_extensions.py
@@ -58,7 +58,7 @@
id=metering_label_rule_id))
self.assertEqual(len(rules['metering_label_rules']), 0)
- @test.idempotent_id('e2fb2f8c-45bf-429a-9f17-171c70444612')
+ @test.idempotent_id('05d7c750-6d26-44d6-82f3-c9dd1f81f358')
def test_list_metering_labels(self):
# Verify label filtering
body = self.admin_client.list_metering_labels(id=33)
@@ -81,7 +81,7 @@
id=metering_label['id']))
self.assertEqual(len(labels['metering_labels']), 1)
- @test.idempotent_id('30abb445-0eea-472e-bd02-8649f54a5968')
+ @test.idempotent_id('cfc500d9-9de6-4847-8803-62889c097d45')
def test_show_metering_label(self):
# Verifies the details of a label
body = self.admin_client.show_metering_label(self.metering_label['id'])
diff --git a/neutron/tests/tempest/api/test_qos.py b/neutron/tests/tempest/api/test_qos.py
index 24ef38b..ff5799b 100644
--- a/neutron/tests/tempest/api/test_qos.py
+++ b/neutron/tests/tempest/api/test_qos.py
@@ -75,6 +75,24 @@
self.assertTrue(retrieved_policy['shared'])
self.assertEqual([], retrieved_policy['rules'])
+ @test.idempotent_id('ee263db4-009a-4641-83e5-d0e83506ba4c')
+ def test_shared_policy_update(self):
+ policy = self.create_qos_policy(name='test-policy',
+ description='',
+ shared=True)
+
+ self.admin_client.update_qos_policy(policy['id'],
+ description='test policy desc2')
+ retrieved_policy = self.admin_client.show_qos_policy(policy['id'])
+ retrieved_policy = retrieved_policy['policy']
+ self.assertTrue(retrieved_policy['shared'])
+
+ self.admin_client.update_qos_policy(policy['id'],
+ shared=False)
+ retrieved_policy = self.admin_client.show_qos_policy(policy['id'])
+ retrieved_policy = retrieved_policy['policy']
+ self.assertFalse(retrieved_policy['shared'])
+
@test.idempotent_id('1cb42653-54bd-4a9a-b888-c55e18199201')
def test_delete_policy(self):
policy = self.admin_client.create_qos_policy(
@@ -521,7 +539,7 @@
self.admin_client.delete_rbac_policy(wildcard_rbac['id'])
self.client.list_rbac_policies(id=client_rbac['id'])
- @test.idempotent_id('328b1f70-d424-11e5-a57f-54ee756c66df')
+ @test.idempotent_id('1997b00c-0c75-4e43-8ce2-999f9fa555ee')
def test_net_bound_shared_policy_wildcard_and_tenant_id_wild_remains(self):
client_rbac, wildcard_rbac = self._create_net_bound_qos_rbacs()
# remove client_rbac policy the wildcard share should remain
@@ -683,7 +701,7 @@
def resource_setup(cls):
super(QosDscpMarkingRuleTestJSON, cls).resource_setup()
- @test.idempotent_id('8a59b00b-3e9c-4787-92f8-93a5cdf5e378')
+ @test.idempotent_id('f5cbaceb-5829-497c-9c60-ad70969e9a08')
def test_rule_create(self):
policy = self.create_qos_policy(name='test-policy',
description='test policy',
@@ -712,7 +730,7 @@
self.assertEqual(qos_consts.RULE_TYPE_DSCP_MARK,
policy_rules[0]['type'])
- @test.idempotent_id('8a59b00b-ab01-4787-92f8-93a5cdf5e378')
+ @test.idempotent_id('08553ffe-030f-4037-b486-7e0b8fb9385a')
def test_rule_create_fail_for_the_same_type(self):
policy = self.create_qos_policy(name='test-policy',
description='test policy',
@@ -725,7 +743,7 @@
policy_id=policy['id'],
dscp_mark=self.VALID_DSCP_MARK2)
- @test.idempotent_id('149a6988-2568-47d2-931e-2dbc858943b3')
+ @test.idempotent_id('76f632e5-3175-4408-9a32-3625e599c8a2')
def test_rule_update(self):
policy = self.create_qos_policy(name='test-policy',
description='test policy',
@@ -741,7 +759,7 @@
retrieved_policy = retrieved_policy['dscp_marking_rule']
self.assertEqual(self.VALID_DSCP_MARK2, retrieved_policy['dscp_mark'])
- @test.idempotent_id('67ee6efd-7b33-4a68-927d-275b4f8ba958')
+ @test.idempotent_id('74f81904-c35f-48a3-adae-1f5424cb3c18')
def test_rule_delete(self):
policy = self.create_qos_policy(name='test-policy',
description='test policy',
@@ -759,14 +777,14 @@
self.admin_client.show_dscp_marking_rule,
policy['id'], rule['id'])
- @test.idempotent_id('f211222c-5808-46cb-a961-983bbab6b852')
+ @test.idempotent_id('9cb8ef5c-96fc-4978-9ee0-e3b02bab628a')
def test_rule_create_rule_nonexistent_policy(self):
self.assertRaises(
exceptions.NotFound,
self.admin_client.create_dscp_marking_rule,
'policy', self.VALID_DSCP_MARK1)
- @test.idempotent_id('a4a2e7ad-786f-4927-a85a-e545a93bd274')
+ @test.idempotent_id('bf6002ea-29de-486f-b65d-08aea6d4c4e2')
def test_rule_create_forbidden_for_regular_tenants(self):
self.assertRaises(
exceptions.Forbidden,
@@ -783,7 +801,7 @@
self.admin_client.create_dscp_marking_rule,
policy['id'], 58)
- @test.idempotent_id('ce0bd0c2-54d9-4e29-85f1-cfb36ac3ebe2')
+ @test.idempotent_id('c565131d-4c80-4231-b0f3-9ae2be4de129')
def test_get_rules_by_policy(self):
policy1 = self.create_qos_policy(name='test-policy1',
description='test policy1',
diff --git a/neutron/tests/tempest/scenario/base.py b/neutron/tests/tempest/scenario/base.py
new file mode 100644
index 0000000..04b591a
--- /dev/null
+++ b/neutron/tests/tempest/scenario/base.py
@@ -0,0 +1,113 @@
+# Copyright 2016 Red Hat, 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_log import log as logging
+
+from tempest.common import waiters
+from tempest.lib.common import ssh
+from tempest.lib.common.utils import data_utils
+
+from neutron.tests.tempest.api import base as base_api
+from neutron.tests.tempest import config
+from neutron.tests.tempest.scenario import constants
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+class BaseTempestTestCase(base_api.BaseNetworkTest):
+ @classmethod
+ def resource_setup(cls):
+ super(BaseTempestTestCase, cls).resource_setup()
+
+ cls.servers = []
+ cls.keypairs = []
+
+ @classmethod
+ def resource_cleanup(cls):
+ for server in cls.servers:
+ cls.manager.servers_client.delete_server(server)
+ waiters.wait_for_server_termination(cls.manager.servers_client,
+ server)
+
+ for keypair in cls.keypairs:
+ cls.manager.keypairs_client.delete_keypair(
+ keypair_name=keypair['name'])
+
+ super(BaseTempestTestCase, cls).resource_cleanup()
+
+ @classmethod
+ def create_server(cls, flavor_ref, image_ref, key_name, networks,
+ name=None):
+ name = name or data_utils.rand_name('server-test')
+ server = cls.manager.servers_client.create_server(
+ name=name, flavorRef=flavor_ref,
+ imageRef=image_ref,
+ key_name=key_name,
+ networks=networks)
+ cls.servers.append(server['server']['id'])
+ return server
+
+ @classmethod
+ def create_keypair(cls, client=None):
+ client = client or cls.manager.keypairs_client
+ name = data_utils.rand_name('keypair-test')
+ body = client.create_keypair(name=name)
+ cls.keypairs.append(body['keypair'])
+ return body['keypair']
+
+ @classmethod
+ def create_loginable_secgroup_rule(cls, secgroup_id=None):
+ client = cls.manager.network_client
+ if not secgroup_id:
+ sgs = client.list_security_groups()['security_groups']
+ for sg in sgs:
+ if sg['name'] == constants.DEFAULT_SECURITY_GROUP:
+ secgroup_id = sg['id']
+ break
+
+ # This rule is intended to permit inbound ssh
+ # traffic from all sources, so no group_id is provided.
+ # Setting a group_id would only permit traffic from ports
+ # belonging to the same security group.
+ ruleset = {'protocol': 'tcp',
+ 'port_range_min': 22,
+ 'port_range_max': 22,
+ 'remote_ip_prefix': '0.0.0.0/0'}
+ rules = [client.create_security_group_rule(
+ direction='ingress', security_group_id=secgroup_id,
+ **ruleset)['security_group_rule']]
+ return rules
+
+ @classmethod
+ def create_router_and_interface(cls, subnet_id):
+ router = cls.create_router(
+ data_utils.rand_name('router'), admin_state_up=True,
+ external_network_id=CONF.network.public_network_id)
+ cls.create_router_interface(router['id'], subnet_id)
+ cls.routers.append(router)
+ return router
+
+ @classmethod
+ def create_and_associate_floatingip(cls, port_id):
+ fip = cls.manager.network_client.create_floatingip(
+ CONF.network.public_network_id,
+ port_id=port_id)['floatingip']
+ cls.floating_ips.append(fip)
+ return fip
+
+ @classmethod
+ def check_connectivity(cls, host, ssh_user, ssh_key=None):
+ ssh_client = ssh.Client(host, ssh_user, pkey=ssh_key)
+ ssh_client.test_connection_auth()
diff --git a/neutron/tests/tempest/scenario/constants.py b/neutron/tests/tempest/scenario/constants.py
new file mode 100644
index 0000000..bb1cab3
--- /dev/null
+++ b/neutron/tests/tempest/scenario/constants.py
@@ -0,0 +1,16 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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.
+
+SERVER_STATUS_ACTIVE = 'ACTIVE'
+DEFAULT_SECURITY_GROUP = 'default'
diff --git a/neutron/tests/tempest/scenario/test_basic.py b/neutron/tests/tempest/scenario/test_basic.py
new file mode 100644
index 0000000..c05e1c2
--- /dev/null
+++ b/neutron/tests/tempest/scenario/test_basic.py
@@ -0,0 +1,57 @@
+# Copyright 2016 Red Hat, 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_log import log as logging
+from tempest.common import waiters
+from tempest import test
+
+from neutron.tests.tempest import config
+from neutron.tests.tempest.scenario import base
+from neutron.tests.tempest.scenario import constants
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+class NetworkBasicTest(base.BaseTempestTestCase):
+ credentials = ['primary']
+ force_tenant_isolation = False
+
+ # Default to ipv4.
+ _ip_version = 4
+
+
+ @test.idempotent_id('de07fe0a-e955-449e-b48b-8641c14cd52e')
+ def test_basic_instance(self):
+ network = self.create_network()
+ subnet = self.create_subnet(network)
+
+ self.create_router_and_interface(subnet['id'])
+ keypair = self.create_keypair()
+ self.create_loginable_secgroup_rule()
+ server = self.create_server(
+ flavor_ref=CONF.compute.flavor_ref,
+ image_ref=CONF.compute.image_ref,
+ key_name=keypair['name'],
+ networks=[{'uuid': network['id']}])
+ waiters.wait_for_server_status(self.manager.servers_client,
+ server['server']['id'],
+ constants.SERVER_STATUS_ACTIVE)
+ port = self.client.list_ports(network_id=network['id'],
+ device_id=server[
+ 'server']['id'])['ports'][0]
+ fip = self.create_and_associate_floatingip(port['id'])
+ self.check_connectivity(fip['floating_ip_address'],
+ CONF.validation.image_ssh_user,
+ keypair['private_key'])
diff --git a/neutron/tests/tempest/services/network/json/network_client.py b/neutron/tests/tempest/services/network/json/network_client.py
index a08ede6..87a77e5 100644
--- a/neutron/tests/tempest/services/network/json/network_client.py
+++ b/neutron/tests/tempest/services/network/json/network_client.py
@@ -663,3 +663,57 @@
self.expected_success(200, resp.status)
body = jsonutils.loads(body)
return service_client.ResponseBody(resp, body)
+
+ def create_security_group_rule(self, direction, security_group_id,
+ **kwargs):
+ post_body = {'security_group_rule': kwargs}
+ post_body['security_group_rule']['direction'] = direction
+ post_body['security_group_rule'][
+ 'security_group_id'] = security_group_id
+ body = jsonutils.dumps(post_body)
+ uri = '%s/security-group-rules' % self.uri_prefix
+ resp, body = self.post(uri, body)
+ self.expected_success(201, resp.status)
+ body = jsonutils.loads(body)
+ return service_client.ResponseBody(resp, body)
+
+ def list_security_groups(self, **kwargs):
+ post_body = {'security_groups': kwargs}
+ body = jsonutils.dumps(post_body)
+ uri = '%s/security-groups' % self.uri_prefix
+ if kwargs:
+ uri += '?' + urlparse.urlencode(kwargs, doseq=1)
+ resp, body = self.get(uri)
+ self.expected_success(200, resp.status)
+ body = jsonutils.loads(body)
+ return service_client.ResponseBody(resp, body)
+
+ def delete_security_group(self, security_group_id):
+ uri = '%s/security-groups/%s' % (
+ self.uri_prefix, security_group_id)
+ resp, body = self.delete(uri)
+ self.expected_success(204, resp.status)
+ return service_client.ResponseBody(resp, body)
+
+ def list_ports(self, **kwargs):
+ post_body = {'ports': kwargs}
+ body = jsonutils.dumps(post_body)
+ uri = '%s/ports' % self.uri_prefix
+ if kwargs:
+ uri += '?' + urlparse.urlencode(kwargs, doseq=1)
+ resp, body = self.get(uri)
+ self.expected_success(200, resp.status)
+ body = jsonutils.loads(body)
+ return service_client.ResponseBody(resp, body)
+
+ def create_floatingip(self, floating_network_id, **kwargs):
+ post_body = {'floatingip': {
+ 'floating_network_id': floating_network_id}}
+ if kwargs:
+ post_body['floatingip'].update(kwargs)
+ body = jsonutils.dumps(post_body)
+ uri = '%s/floatingips' % self.uri_prefix
+ resp, body = self.post(uri, body)
+ self.expected_success(201, resp.status)
+ body = jsonutils.loads(body)
+ return service_client.ResponseBody(resp, body)