Merge "Disable QoS scenario tests differently"
diff --git a/neutron/tests/tempest/README.rst b/neutron/tests/tempest/README.rst
index d61e72c..f27c34e 100644
--- a/neutron/tests/tempest/README.rst
+++ b/neutron/tests/tempest/README.rst
@@ -1,10 +1,9 @@
WARNING
=======
-The files under this path were copied from tempest as part of the move
-of the api tests, and they will be removed as required over time to
-minimize the dependency on the tempest testing framework.
-While it exists, only neutron.tests.tempest.api and neutron.tests.retargetable
-should be importing files from this path. neutron.tests.tempest.config uses
-the global cfg.CONF instance and importing it outside of the api tests
-has the potential to break Neutron's use of cfg.CONF.
+Some files under this path were copied from tempest as part of the move of the
+api tests, and they will be removed as required over time to minimize the
+dependency on the tempest testing framework. While it exists, only
+neutron.tests.tempest.* should be importing files from this path.
+neutron.tests.tempest.config uses the global cfg.CONF instance and importing it
+outside of the api tests has the potential to break Neutron's use of cfg.CONF.
diff --git a/neutron/tests/tempest/api/admin/test_routers_ha.py b/neutron/tests/tempest/api/admin/test_routers_ha.py
new file mode 100644
index 0000000..187eb6d
--- /dev/null
+++ b/neutron/tests/tempest/api/admin/test_routers_ha.py
@@ -0,0 +1,93 @@
+# 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 decorators
+from tempest import test
+
+from neutron.tests.tempest.api import base_routers as base
+
+
+class RoutersTestHA(base.BaseRouterTest):
+
+ @classmethod
+ @test.requires_ext(extension="router", service="network")
+ @test.requires_ext(extension="l3-ha", service="network")
+ def resource_setup(cls):
+ # The check above will pass if api_extensions=all, which does
+ # not mean "l3-ha" extension itself is present.
+ # Instead, we have to check whether "ha" is actually present by using
+ # admin credentials to create router with ha=True attribute
+ # and checking for BadRequest exception and that the resulting router
+ # has a high availability attribute.
+ super(RoutersTestHA, cls).resource_setup()
+ name = data_utils.rand_name('pretest-check')
+ router = cls.admin_client.create_router(name)
+ if 'ha' not in router['router']:
+ cls.admin_client.delete_router(router['router']['id'])
+ msg = "'ha' attribute not found. HA Possibly not enabled"
+ raise cls.skipException(msg)
+
+ @decorators.idempotent_id('8abc177d-14f1-4018-9f01-589b299cbee1')
+ def test_ha_router_creation(self):
+ """
+ Test uses administrative credentials to create a
+ HA (High Availability) router using the ha=True.
+
+ Acceptance
+ The router is created and the "ha" attribute is set to True
+ """
+ name = data_utils.rand_name('router')
+ router = self.admin_client.create_router(name, ha=True)
+ self.addCleanup(self.admin_client.delete_router,
+ router['router']['id'])
+ self.assertTrue(router['router']['ha'])
+
+ @decorators.idempotent_id('97b5f7ef-2192-4fa3-901e-979cd5c1097a')
+ def test_legacy_router_creation(self):
+ """
+ Test uses administrative credentials to create a
+ SF (Single Failure) router using the ha=False.
+
+ Acceptance
+ The router is created and the "ha" attribute is
+ set to False, thus making it a "Single Failure Router"
+ as opposed to a "High Availability Router"
+ """
+ name = data_utils.rand_name('router')
+ router = self.admin_client.create_router(name, ha=False)
+ self.addCleanup(self.admin_client.delete_router,
+ router['router']['id'])
+ self.assertFalse(router['router']['ha'])
+
+ @decorators.idempotent_id('5a6bfe82-5b23-45a4-b027-5160997d4753')
+ def test_legacy_router_update_to_ha(self):
+ """
+ Test uses administrative credentials to create a
+ SF (Single Failure) router using the ha=False.
+ Then it will "update" the router ha attribute to True
+
+ Acceptance
+ The router is created and the "ha" attribute is
+ set to False. Once the router is updated, the ha
+ attribute will be set to True
+ """
+ name = data_utils.rand_name('router')
+ # router needs to be in admin state down in order to be upgraded to HA
+ router = self.admin_client.create_router(name, ha=False,
+ admin_state_up=False)
+ self.addCleanup(self.admin_client.delete_router,
+ router['router']['id'])
+ self.assertFalse(router['router']['ha'])
+ router = self.admin_client.update_router(router['router']['id'],
+ ha=True)
+ self.assertTrue(router['router']['ha'])
diff --git a/neutron/tests/tempest/api/admin/test_shared_network_extension.py b/neutron/tests/tempest/api/admin/test_shared_network_extension.py
index 042a73e..5557c24 100644
--- a/neutron/tests/tempest/api/admin/test_shared_network_extension.py
+++ b/neutron/tests/tempest/api/admin/test_shared_network_extension.py
@@ -50,6 +50,10 @@
self.assertNotEmpty(items)
self.assertTrue(all(n['shared'] == shared for n in items))
+ def _list_subnets_ids(self, client, shared):
+ body = client.list_subnets(shared=shared)
+ return [subnet['id'] for subnet in body['subnets']]
+
@decorators.idempotent_id('6661d219-b96d-4597-ad10-51672353421a')
def test_filtering_shared_subnets(self):
# shared subnets need to be tested because their shared status isn't
@@ -59,7 +63,8 @@
priv = self.create_subnet(reg, client=self.client)
shared = self.create_subnet(self.shared_network,
client=self.admin_client)
- self.assertIn(shared, self.client.list_subnets(shared=True)['subnets'])
+ self.assertIn(shared['id'],
+ self._list_subnets_ids(self.client, shared=True))
self.assertIn(shared,
self.admin_client.list_subnets(shared=True)['subnets'])
self.assertNotIn(priv,
@@ -67,8 +72,8 @@
self.assertNotIn(priv,
self.admin_client.list_subnets(shared=True)['subnets'])
self.assertIn(priv, self.client.list_subnets(shared=False)['subnets'])
- self.assertIn(priv,
- self.admin_client.list_subnets(shared=False)['subnets'])
+ self.assertIn(priv['id'],
+ self._list_subnets_ids(self.admin_client, shared=False))
self.assertNotIn(shared,
self.client.list_subnets(shared=False)['subnets'])
self.assertNotIn(shared,
diff --git a/neutron/tests/tempest/api/test_qos.py b/neutron/tests/tempest/api/test_qos.py
index 7280297..287207e 100644
--- a/neutron/tests/tempest/api/test_qos.py
+++ b/neutron/tests/tempest/api/test_qos.py
@@ -82,7 +82,8 @@
def test_policy_update(self):
policy = self.create_qos_policy(name='test-policy',
description='',
- shared=False)
+ shared=False,
+ tenant_id=self.admin_client.tenant_id)
self.admin_client.update_qos_policy(policy['id'],
description='test policy desc2',
shared=True)
@@ -119,7 +120,8 @@
def test_shared_policy_update(self):
policy = self.create_qos_policy(name='test-policy',
description='',
- shared=True)
+ shared=True,
+ tenant_id=self.admin_client.tenant_id)
self.admin_client.update_qos_policy(policy['id'],
description='test policy desc2')
@@ -606,7 +608,8 @@
def test_policy_sharing_with_wildcard(self):
qos_pol = self.create_qos_policy(
name=data_utils.rand_name('test-policy'),
- description='test-shared-policy', shared=False)
+ description='test-shared-policy', shared=False,
+ tenant_id=self.admin_client.tenant_id)
self.assertNotIn(qos_pol, self.client2.list_qos_policies()['policies'])
# test update shared False -> True
diff --git a/neutron/tests/tempest/api/test_revisions.py b/neutron/tests/tempest/api/test_revisions.py
index 3db39c6..7a6443c 100644
--- a/neutron/tests/tempest/api/test_revisions.py
+++ b/neutron/tests/tempest/api/test_revisions.py
@@ -313,17 +313,21 @@
@decorators.idempotent_id('afb6486c-41b5-483e-a500-3c506f4deb49')
@test.requires_ext(extension="router", service="network")
- @test.requires_ext(extension="dvr", service="network")
+ @test.requires_ext(extension="l3-ha", service="network")
def test_update_router_extra_attributes_bumps_revision(self):
- router = self.create_router(router_name='r1')
+ # updates from CVR to CVR-HA are supported on every release,
+ # but only the admin can forcibly create a non-HA router
+ router_args = {'tenant_id': self.client.tenant_id,
+ 'ha': False}
+ router = self.admin_client.create_router('r1', True,
+ **router_args)['router']
self.addCleanup(self.client.delete_router, router['id'])
self.assertIn('revision_number', router)
rev1 = router['revision_number']
router = self.admin_client.update_router(
router['id'], admin_state_up=False)['router']
self.assertGreater(router['revision_number'], rev1)
- self.admin_client.update_router(router['id'],
- distributed=True)['router']
+ self.admin_client.update_router(router['id'], ha=True)['router']
updated = self.client.show_router(router['id'])['router']
self.assertGreater(updated['revision_number'],
router['revision_number'])
diff --git a/neutron/tests/tempest/api/test_routers.py b/neutron/tests/tempest/api/test_routers.py
index 7a1e458..85bfe82 100644
--- a/neutron/tests/tempest/api/test_routers.py
+++ b/neutron/tests/tempest/api/test_routers.py
@@ -259,6 +259,26 @@
self.assertNotIn('distributed', show_body['router'])
+class HaRoutersTest(base_routers.BaseRouterTest):
+
+ @classmethod
+ @test.requires_ext(extension="l3-ha", service="network")
+ def skip_checks(cls):
+ super(HaRoutersTest, cls).skip_checks()
+
+ @decorators.idempotent_id('77db8eae-3aa3-4e61-bf2a-e739ce042e53')
+ def test_convert_legacy_router(self):
+ router = self._create_router(data_utils.rand_name('router'))
+ self.assertNotIn('ha', router)
+ update_body = self.admin_client.update_router(router['id'],
+ ha=True)
+ self.assertTrue(update_body['router']['ha'])
+ show_body = self.admin_client.show_router(router['id'])
+ self.assertTrue(show_body['router']['ha'])
+ show_body = self.client.show_router(router['id'])
+ self.assertNotIn('ha', show_body['router'])
+
+
class RoutersSearchCriteriaTest(base.BaseSearchCriteriaTest):
resource = 'router'
diff --git a/neutron/tests/tempest/api/test_routers_negative.py b/neutron/tests/tempest/api/test_routers_negative.py
index 049b9c8..b97e30d 100644
--- a/neutron/tests/tempest/api/test_routers_negative.py
+++ b/neutron/tests/tempest/api/test_routers_negative.py
@@ -85,3 +85,18 @@
with testtools.ExpectedException(lib_exc.Forbidden):
self.create_router(
data_utils.rand_name('router'), distributed=True)
+
+
+class HaRoutersNegativeTest(RoutersNegativeTestBase):
+
+ @classmethod
+ @test.requires_ext(extension="l3-ha", service="network")
+ def skip_checks(cls):
+ super(HaRoutersNegativeTest, cls).skip_checks()
+
+ @test.attr(type='negative')
+ @decorators.idempotent_id('821b85b9-9c51-40f3-831f-bf223a7e0084')
+ def test_router_create_tenant_ha_returns_forbidden(self):
+ with testtools.ExpectedException(lib_exc.Forbidden):
+ self.create_router(
+ data_utils.rand_name('router'), ha=True)
diff --git a/neutron/tests/tempest/api/test_tag.py b/neutron/tests/tempest/api/test_tag.py
index 70a2d44..2553dfb 100644
--- a/neutron/tests/tempest/api/test_tag.py
+++ b/neutron/tests/tempest/api/test_tag.py
@@ -44,6 +44,10 @@
self.client.update_tag(self.resource, self.res_id, 'red')
self._get_and_compare_tags(['red', 'blue', 'green'])
+ # add a tag with a dot
+ self.client.update_tag(self.resource, self.res_id, 'black.or.white')
+ self._get_and_compare_tags(['red', 'blue', 'green', 'black.or.white'])
+
# replace tags
tags = ['red', 'yellow', 'purple']
res_body = self.client.update_tags(self.resource, self.res_id, tags)
diff --git a/neutron/tests/tempest/scenario/base.py b/neutron/tests/tempest/scenario/base.py
index 967a45e..1e20c74 100644
--- a/neutron/tests/tempest/scenario/base.py
+++ b/neutron/tests/tempest/scenario/base.py
@@ -36,24 +36,17 @@
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,
+ def create_server(self, flavor_ref, image_ref, key_name, networks,
name=None, security_groups=None):
"""Create a server using tempest lib
All the parameters are the ones used in Compute API
@@ -78,14 +71,20 @@
if not security_groups:
security_groups = [{'name': 'default'}]
- server = cls.manager.servers_client.create_server(
+ server = self.manager.servers_client.create_server(
name=name,
flavorRef=flavor_ref,
imageRef=image_ref,
key_name=key_name,
networks=networks,
security_groups=security_groups)
- cls.servers.append(server['server']['id'])
+
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ waiters.wait_for_server_termination,
+ self.manager.servers_client, server['server']['id'])
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.manager.servers_client.delete_server,
+ server['server']['id'])
return server
@classmethod
@@ -155,50 +154,48 @@
cls.routers.append(router)
return router
- @classmethod
- def create_and_associate_floatingip(cls, port_id):
- fip = cls.manager.network_client.create_floatingip(
+ def create_and_associate_floatingip(self, port_id):
+ fip = self.manager.network_client.create_floatingip(
CONF.network.public_network_id,
port_id=port_id)['floatingip']
- cls.floating_ips.append(fip)
+ self.floating_ips.append(fip)
return fip
- @classmethod
- def setup_network_and_server(cls, router=None, **kwargs):
+ def setup_network_and_server(self, router=None, **kwargs):
"""Create network resources and a server.
Creating a network, subnet, router, keypair, security group
and a server.
"""
- cls.network = cls.create_network()
- LOG.debug("Created network %s", cls.network['name'])
- cls.subnet = cls.create_subnet(cls.network)
- LOG.debug("Created subnet %s", cls.subnet['id'])
+ self.network = self.create_network()
+ LOG.debug("Created network %s", self.network['name'])
+ self.subnet = self.create_subnet(self.network)
+ LOG.debug("Created subnet %s", self.subnet['id'])
- secgroup = cls.manager.network_client.create_security_group(
+ secgroup = self.manager.network_client.create_security_group(
name=data_utils.rand_name('secgroup-'))
LOG.debug("Created security group %s",
secgroup['security_group']['name'])
- cls.security_groups.append(secgroup['security_group'])
+ self.security_groups.append(secgroup['security_group'])
if not router:
- router = cls.create_router_by_client(**kwargs)
- cls.create_router_interface(router['id'], cls.subnet['id'])
- cls.keypair = cls.create_keypair()
- cls.create_loginable_secgroup_rule(
+ router = self.create_router_by_client(**kwargs)
+ self.create_router_interface(router['id'], self.subnet['id'])
+ self.keypair = self.create_keypair()
+ self.create_loginable_secgroup_rule(
secgroup_id=secgroup['security_group']['id'])
- cls.server = cls.create_server(
+ self.server = self.create_server(
flavor_ref=CONF.compute.flavor_ref,
image_ref=CONF.compute.image_ref,
- key_name=cls.keypair['name'],
- networks=[{'uuid': cls.network['id']}],
+ key_name=self.keypair['name'],
+ networks=[{'uuid': self.network['id']}],
security_groups=[{'name': secgroup['security_group']['name']}])
- waiters.wait_for_server_status(cls.manager.servers_client,
- cls.server['server']['id'],
+ waiters.wait_for_server_status(self.manager.servers_client,
+ self.server['server']['id'],
constants.SERVER_STATUS_ACTIVE)
- port = cls.client.list_ports(network_id=cls.network['id'],
- device_id=cls.server[
+ port = self.client.list_ports(network_id=self.network['id'],
+ device_id=self.server[
'server']['id'])['ports'][0]
- cls.fip = cls.create_and_associate_floatingip(port['id'])
+ self.fip = self.create_and_associate_floatingip(port['id'])
def check_connectivity(self, host, ssh_user, ssh_key, servers=None):
ssh_client = ssh.Client(host, ssh_user, pkey=ssh_key)
diff --git a/neutron/tests/tempest/scenario/test_floatingip.py b/neutron/tests/tempest/scenario/test_floatingip.py
index d4ad72a..1ccb6ac 100644
--- a/neutron/tests/tempest/scenario/test_floatingip.py
+++ b/neutron/tests/tempest/scenario/test_floatingip.py
@@ -51,15 +51,10 @@
cls.create_loginable_secgroup_rule(secgroup_id=cls.secgroup['id'])
cls.create_pingable_secgroup_rule(secgroup_id=cls.secgroup['id'])
- cls._src_server = cls._create_server()
if cls.same_network:
cls._dest_network = cls.network
else:
cls._dest_network = cls._create_dest_network()
- cls._dest_server_with_fip = cls._create_server(
- network=cls._dest_network)
- cls._dest_server_without_fip = cls._create_server(
- create_floating_ip=False, network=cls._dest_network)
@classmethod
def _create_dest_network(cls):
@@ -69,28 +64,27 @@
cls.create_router_interface(cls.router['id'], subnet['id'])
return network
- @classmethod
- def _create_server(cls, create_floating_ip=True, network=None):
+ def _create_server(self, create_floating_ip=True, network=None):
if network is None:
- network = cls.network
- port = cls.create_port(network, security_groups=[cls.secgroup['id']])
+ network = self.network
+ port = self.create_port(network, security_groups=[self.secgroup['id']])
if create_floating_ip:
- fip = cls.create_and_associate_floatingip(port['id'])
+ fip = self.create_and_associate_floatingip(port['id'])
else:
fip = None
- server = cls.create_server(
+ server = self.create_server(
flavor_ref=CONF.compute.flavor_ref,
image_ref=CONF.compute.image_ref,
- key_name=cls.keypair['name'],
+ key_name=self.keypair['name'],
networks=[{'port': port['id']}])['server']
- waiters.wait_for_server_status(cls.manager.servers_client,
+ waiters.wait_for_server_status(self.manager.servers_client,
server['id'],
constants.SERVER_STATUS_ACTIVE)
return {'port': port, 'fip': fip, 'server': server}
def _test_east_west(self):
# Source VM
- server1 = self._src_server
+ server1 = self._create_server()
server1_ip = server1['fip']['floating_ip_address']
ssh_client = ssh.Client(server1_ip,
CONF.validation.image_ssh_user,
@@ -98,9 +92,10 @@
# Destination VM
if self.dest_has_fip:
- dest_server = self._dest_server_with_fip
+ dest_server = self._create_server(network=self._dest_network)
else:
- dest_server = self._dest_server_without_fip
+ dest_server = self._create_server(create_floating_ip=False,
+ network=self._dest_network)
# Check connectivity
self.check_remote_connectivity(ssh_client,
diff --git a/neutron/tests/tempest/scenario/test_trunk.py b/neutron/tests/tempest/scenario/test_trunk.py
index 122068c..c857f3f 100644
--- a/neutron/tests/tempest/scenario/test_trunk.py
+++ b/neutron/tests/tempest/scenario/test_trunk.py
@@ -239,7 +239,8 @@
# Configure VLAN interfaces on server
command = CONFIGURE_VLAN_INTERFACE_COMMANDS % {'tag': vlan_tag}
server['ssh_client'].exec_command(command)
- out = server['ssh_client'].exec_command('ip addr list')
+ out = server['ssh_client'].exec_command(
+ 'PATH=$PATH:/usr/sbin;ip addr list')
LOG.debug("Interfaces on server %s: %s", server, out)
# Ping from server1 to server2 via VLAN interface should fail because