Merge "Add support of microversion in all compute service clients"
diff --git a/doc/source/library/api_microversion_testing.rst b/doc/source/library/api_microversion_testing.rst
index 0d0b595..b7a4ba8 100644
--- a/doc/source/library/api_microversion_testing.rst
+++ b/doc/source/library/api_microversion_testing.rst
@@ -8,7 +8,7 @@
---------------------------------------------
Many of the OpenStack components have implemented API microversions.
-It is important to tests those microversion in Tempest or external plugins.
+It is important to test those microversions in Tempest or external plugins.
Tempest now provides stable interfaces to support to test the API microversions.
Based on the microversion range coming from the combination of both configuration
and each test case, APIs request will be made with selected microversion.
diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst
index 29653a6..2622c22 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -55,6 +55,37 @@
tempest.test_plugins =
plugin_name = module.path:PluginClass
+Standalone Plugin vs In-repo Plugin
+-----------------------------------
+
+Since all that's required for a plugin to be detected by tempest is a valid
+setuptools entry point in the proper namespace there is no difference from the
+tempest perspective on either creating a separate python package to
+house the plugin or adding the code to an existing python project. However,
+there are tradeoffs to consider when deciding which approach to take when
+creating a new plugin.
+
+If you create a separate python project for your plugin this makes a lot of
+things much easier. Firstly it makes packaging and versioning much simpler, you
+can easily decouple the requirements for the plugin from the requirements for
+the other project. It lets you version the plugin independently and maintain a
+single version of the test code across project release boundaries (see the
+`Branchless Tempest Spec`_ for more details on this). It also greatly
+simplifies the install time story for external users. Instead of having to
+install the right version of a project in the same python namespace as tempest
+they simply need to pip install the plugin in that namespace. It also means
+that users don't have to worry about inadvertently installing a tempest plugin
+when they install another package.
+
+.. _Branchless Tempest Spec: http://specs.openstack.org/openstack/qa-specs/specs/tempest/implemented/branchless-tempest.html
+
+The sole advantage to integrating a plugin into an existing python project is
+that it enables you to land code changes at the same time you land test changes
+in the plugin. This reduces some of the burden on contributors by not having
+to land 2 changes to add a new API feature and then test it and doing it as a
+single combined commit.
+
+
Plugin Class
============
diff --git a/etc/accounts.yaml.sample b/etc/accounts.yaml.sample
index decc659..3dbed79 100644
--- a/etc/accounts.yaml.sample
+++ b/etc/accounts.yaml.sample
@@ -3,7 +3,25 @@
# This is required to provide isolation between test for running in parallel
#
# Valid fields for credentials are defined in the descendants of
-# auth.Credentials - see KeystoneV[2|3]Credentials.CONF_ATTRIBUTES
+# lib.auth.Credentials - see KeystoneV[2|3]Credentials.ATTRIBUTES
+#
+# The fields in KeystoneV3Credentials behave as follows:
+#
+# tenant_[id|name] also sets project_[id|name].
+#
+# project_[id|name] also sets tenant_[id|name].
+#
+# Providing distinct values for both tenant_[id|name] and project_[id|name]
+# will result in an InvalidCredentials exception.
+#
+# The value of project_domain_[id|name] is used for user_domain_[id|name] if
+# the latter is not specified.
+#
+# The value of user_domain_[id|name] is used for project_domain_[id|name] if
+# the latter is not specified.
+#
+# The value of domain_[id|name] is used for project_domain_[id|name] if not
+# specified and user_domain_[id|name] if not specified.
- username: 'user_1'
tenant_name: 'test_tenant_1'
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index f61d2fb..77ed7cd 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -47,8 +47,8 @@
super(BaseV2ComputeTest, cls).skip_checks()
if not CONF.service_available.nova:
raise cls.skipException("Nova is not available")
- cfg_min_version = CONF.compute_feature_enabled.min_microversion
- cfg_max_version = CONF.compute_feature_enabled.max_microversion
+ cfg_min_version = CONF.compute.min_microversion
+ cfg_max_version = CONF.compute.max_microversion
api_version_utils.check_skip_with_microversion(cls.min_microversion,
cls.max_microversion,
cfg_min_version,
@@ -105,7 +105,7 @@
cls.request_microversion = (
api_version_utils.select_request_microversion(
cls.min_microversion,
- CONF.compute_feature_enabled.min_microversion))
+ CONF.compute.min_microversion))
cls.build_interval = CONF.compute.build_interval
cls.build_timeout = CONF.compute.build_timeout
cls.image_ref = CONF.compute.image_ref
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 0b33d66..c1fbb12 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -14,7 +14,6 @@
# under the License.
from tempest.api.compute import base
-from tempest.api import utils
from tempest.common import fixed_network
from tempest.common.utils import data_utils
from tempest.common import waiters
@@ -89,7 +88,7 @@
wait_until='ACTIVE')
@test.idempotent_id('05e8a8e7-9659-459a-989d-92c2f501f4ba')
- @utils.skip_unless_attr('multiple_images', 'Only one image found')
+ @decorators.skip_unless_attr('multiple_images', 'Only one image found')
def test_list_servers_filter_by_image(self):
# Filter the list of servers by image
params = {'image': self.image_ref}
@@ -174,7 +173,7 @@
len([x for x in servers['servers'] if 'id' in x]))
@test.idempotent_id('b3304c3b-97df-46d2-8cd3-e2b6659724e7')
- @utils.skip_unless_attr('multiple_images', 'Only one image found')
+ @decorators.skip_unless_attr('multiple_images', 'Only one image found')
def test_list_servers_detailed_filter_by_image(self):
# Filter the detailed list of servers by image
params = {'image': self.image_ref}
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index b3e138f..e620e03 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -14,10 +14,11 @@
# under the License.
import netaddr
+import testtools
from tempest.api.compute import base
from tempest import config
-from tempest.lib import decorators
+from tempest.lib import exceptions
from tempest import test
CONF = config.CONF
@@ -42,20 +43,26 @@
server = cls.create_test_server(wait_until='ACTIVE')
cls.server_id = server['id']
- @decorators.skip_because(bug="1183436",
- condition=CONF.service_available.neutron)
@test.idempotent_id('96c4e2ef-5e4d-4d7f-87f5-fed6dca18016')
@test.services('network')
def test_list_virtual_interfaces(self):
# Positive test:Should be able to GET the virtual interfaces list
# for a given server_id
- output = self.client.list_virtual_interfaces(self.server_id)
- self.assertIsNotNone(output)
- virt_ifaces = output
- self.assertNotEqual(0, len(virt_ifaces['virtual_interfaces']),
- 'Expected virtual interfaces, got 0 interfaces.')
- for virt_iface in virt_ifaces['virtual_interfaces']:
- mac_address = virt_iface['mac_address']
- self.assertTrue(netaddr.valid_mac(mac_address),
- "Invalid mac address detected. mac address: %s"
- % mac_address)
+
+ if CONF.service_available.neutron:
+ # TODO(mriedem): After a microversion implements the API for
+ # neutron, a 400 should be a failure for nova-network and neutron.
+ with testtools.ExpectedException(exceptions.BadRequest):
+ self.client.list_virtual_interfaces(self.server_id)
+ else:
+ output = self.client.list_virtual_interfaces(self.server_id)
+ self.assertIsNotNone(output)
+ virt_ifaces = output
+ self.assertNotEqual(0, len(virt_ifaces['virtual_interfaces']),
+ 'Expected virtual interfaces, got 0 '
+ 'interfaces.')
+ for virt_iface in virt_ifaces['virtual_interfaces']:
+ mac_address = virt_iface['mac_address']
+ self.assertTrue(netaddr.valid_mac(mac_address),
+ "Invalid mac address detected. mac address: %s"
+ % mac_address)
diff --git a/tempest/api/identity/admin/v2/test_users.py b/tempest/api/identity/admin/v2/test_users.py
index 60c4e97..d860d2f 100644
--- a/tempest/api/identity/admin/v2/test_users.py
+++ b/tempest/api/identity/admin/v2/test_users.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import time
+
from testtools import matchers
from tempest.api.identity import base
@@ -207,9 +209,11 @@
update_user = self.users_client.update_user_password(
self.data.user['id'], password=new_pass)['user']
self.assertEqual(update_user['id'], self.data.user['id'])
-
- # Validate the updated password
- # Get a token
+ # NOTE(morganfainberg): Fernet tokens are not subsecond aware and
+ # Keystone should only be precise to the second. Sleep to ensure
+ # we are passing the second boundary.
+ time.sleep(1)
+ # Validate the updated password through getting a token.
body = self.token_client.auth(self.data.user['name'], new_pass,
self.data.tenant['name'])
self.assertTrue('id' in body['token'])
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index e26624a..371da9c 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -79,20 +79,15 @@
self.users_client.update_user_password(
user['id'], password=new_password,
original_password=original_password)
- # TODO(lbragstad): Sleeping after the response status has been checked
- # and the body loaded as JSON allows requests to fail-fast. The sleep
- # is necessary because keystone will err on the side of security and
- # invalidate tokens within a small margin of error (within the same
- # wall clock second) after a revocation event is issued (such as a
- # password change). Remove this once keystone and Fernet support
- # sub-second precision, see bug 1517697 for more details.
+ # NOTE(morganfainberg): Fernet tokens are not subsecond aware and
+ # Keystone should only be precise to the second. Sleep to ensure
+ # we are passing the second boundary.
time.sleep(1)
resp = self.token.auth(user_id=user['id'],
password=new_password).response
subject_token = resp['x-subject-token']
# Perform GET Token to verify and confirm password is updated
token_details = self.client.show_token(subject_token)['token']
- self.assertEqual(resp['x-subject-token'], subject_token)
self.assertEqual(token_details['user']['id'], user['id'])
self.assertEqual(token_details['user']['name'], u_name)
diff --git a/tempest/api/identity/v2/test_users.py b/tempest/api/identity/v2/test_users.py
index ce4ee69..62ddead 100644
--- a/tempest/api/identity/v2/test_users.py
+++ b/tempest/api/identity/v2/test_users.py
@@ -55,13 +55,9 @@
# user updates own password
self.non_admin_users_client.update_user_own_password(
user_id, password=new_pass, original_password=old_pass)
- # TODO(lbragstad): Sleeping after the response status has been checked
- # and the body loaded as JSON allows requests to fail-fast. The sleep
- # is necessary because keystone will err on the side of security and
- # invalidate tokens within a small margin of error (within the same
- # wall clock second) after a revocation event is issued (such as a
- # password change). Remove this once keystone and Fernet support
- # sub-second precision.
+ # NOTE(morganfainberg): Fernet tokens are not subsecond aware and
+ # Keystone should only be precise to the second. Sleep to ensure
+ # we are passing the second boundary.
time.sleep(1)
# check authorization with new password
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index ab48c07..60fbe12 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -58,13 +58,9 @@
self.non_admin_users_client.update_user_password(
user_id, password=new_pass, original_password=old_pass)
- # TODO(lbragstad): Sleeping after the response status has been checked
- # and the body loaded as JSON allows requests to fail-fast. The sleep
- # is necessary because keystone will err on the side of security and
- # invalidate tokens within a small margin of error (within the same
- # wall clock second) after a revocation event is issued (such as a
- # password change). Remove this once keystone and Fernet support
- # sub-second precision.
+ # NOTE(morganfainberg): Fernet tokens are not subsecond aware and
+ # Keystone should only be precise to the second. Sleep to ensure
+ # we are passing the second boundary.
time.sleep(1)
# check authorization with new password
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index 78d6aea..7a4547a 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -74,14 +74,14 @@
# query and setup steps are only required if the extension is available
# and only if the router's default type is distributed.
if test.is_extension_enabled('dvr', 'network'):
- cls.is_dvr_router = cls.admin_client.show_router(
+ cls.is_dvr_router = cls.admin_routers_client.show_router(
cls.router['id'])['router'].get('distributed', False)
if cls.is_dvr_router:
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
cls.port = cls.create_port(cls.network)
- cls.client.add_router_interface(cls.router['id'],
- port_id=cls.port['id'])
+ cls.routers_client.add_router_interface(
+ cls.router['id'], port_id=cls.port['id'])
# NOTE: Sometimes we have seen this test fail with dvr in,
# multinode tests, since the dhcp port is not created before
# the test gets executed and so the router is not scheduled
@@ -92,15 +92,15 @@
external_gateway_info = {
'network_id': CONF.network.public_network_id,
'enable_snat': True}
- cls.admin_client.update_router_with_snat_gw_info(
+ cls.admin_routers_client.update_router_with_snat_gw_info(
cls.router['id'],
external_gateway_info=external_gateway_info)
@classmethod
def resource_cleanup(cls):
if cls.is_dvr_router:
- cls.client.remove_router_interface(cls.router['id'],
- port_id=cls.port['id'])
+ cls.routers_client.remove_router_interface(cls.router['id'],
+ port_id=cls.port['id'])
super(L3AgentSchedulerTestJSON, cls).resource_cleanup()
@test.idempotent_id('b7ce6e89-e837-4ded-9b78-9ed3c9c6a45a')
@@ -114,7 +114,8 @@
self.agent['id'],
router_id=self.router['id'])
body = (
- self.admin_client.list_l3_agents_hosting_router(self.router['id']))
+ self.admin_routers_client.list_l3_agents_hosting_router(
+ self.router['id']))
for agent in body['agents']:
l3_agent_ids.append(agent['id'])
self.assertIn('agent_type', agent)
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index a1a881d..c1cdbf2 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -60,7 +60,7 @@
n2['network']['id'])
# Try to create a third network while the quota is two
- with self.assertRaisesRegexp(
+ with self.assertRaisesRegex(
lib_exc.Conflict,
"An object with that identifier already exists\\n" +
"Details.*Quota exceeded for resources: \['network'\].*"):
diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py
index 3e787af..36cb15f 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -34,8 +34,8 @@
# has a distributed attribute.
super(RoutersTestDVR, cls).resource_setup()
name = data_utils.rand_name('pretest-check')
- router = cls.admin_client.create_router(name)
- cls.admin_client.delete_router(router['router']['id'])
+ router = cls.admin_routers_client.create_router(name=name)
+ cls.admin_routers_client.delete_router(router['router']['id'])
if 'distributed' not in router['router']:
msg = "'distributed' flag not found. DVR Possibly not enabled"
raise cls.skipException(msg)
@@ -53,8 +53,9 @@
set to True
"""
name = data_utils.rand_name('router')
- router = self.admin_client.create_router(name, distributed=True)
- self.addCleanup(self.admin_client.delete_router,
+ router = self.admin_routers_client.create_router(name=name,
+ distributed=True)
+ self.addCleanup(self.admin_routers_client.delete_router,
router['router']['id'])
self.assertTrue(router['router']['distributed'])
@@ -72,8 +73,9 @@
as opposed to a "Distributed Virtual Router"
"""
name = data_utils.rand_name('router')
- router = self.admin_client.create_router(name, distributed=False)
- self.addCleanup(self.admin_client.delete_router,
+ router = self.admin_routers_client.create_router(name=name,
+ distributed=False)
+ self.addCleanup(self.admin_routers_client.delete_router,
router['router']['id'])
self.assertFalse(router['router']['distributed'])
@@ -93,11 +95,12 @@
"""
name = data_utils.rand_name('router')
# router needs to be in admin state down in order to be upgraded to DVR
- router = self.admin_client.create_router(name, distributed=False,
- admin_state_up=False)
- self.addCleanup(self.admin_client.delete_router,
+ router = self.admin_routers_client.create_router(name=name,
+ distributed=False,
+ admin_state_up=False)
+ self.addCleanup(self.admin_routers_client.delete_router,
router['router']['id'])
self.assertFalse(router['router']['distributed'])
- router = self.admin_client.update_router(router['router']['id'],
- distributed=True)
+ router = self.admin_routers_client.update_router(
+ router['router']['id'], distributed=True)
self.assertTrue(router['router']['distributed'])
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 1e636f1..d78fc04 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -71,6 +71,7 @@
cls.agents_client = cls.os.network_agents_client
cls.network_extensions_client = cls.os.network_extensions_client
cls.networks_client = cls.os.networks_client
+ cls.routers_client = cls.os.routers_client
cls.subnetpools_client = cls.os.subnetpools_client
cls.subnets_client = cls.os.subnets_client
cls.ports_client = cls.os.ports_client
@@ -231,8 +232,8 @@
ext_gw_info['network_id'] = external_network_id
if enable_snat is not None:
ext_gw_info['enable_snat'] = enable_snat
- body = cls.client.create_router(
- router_name, external_gateway_info=ext_gw_info,
+ body = cls.routers_client.create_router(
+ name=router_name, external_gateway_info=ext_gw_info,
admin_state_up=admin_state_up, **kwargs)
router = body['router']
cls.routers.append(router)
@@ -250,8 +251,8 @@
@classmethod
def create_router_interface(cls, router_id, subnet_id):
"""Wrapper utility that returns a router interface."""
- interface = cls.client.add_router_interface(router_id,
- subnet_id=subnet_id)
+ interface = cls.routers_client.add_router_interface(
+ router_id, subnet_id=subnet_id)
return interface
@classmethod
@@ -260,12 +261,12 @@
interfaces = body['ports']
for i in interfaces:
try:
- cls.client.remove_router_interface(
+ cls.routers_client.remove_router_interface(
router['id'],
subnet_id=i['fixed_ips'][0]['subnet_id'])
except lib_exc.NotFound:
pass
- cls.client.delete_router(router['id'])
+ cls.routers_client.delete_router(router['id'])
class BaseAdminNetworkTest(BaseNetworkTest):
@@ -278,6 +279,7 @@
cls.admin_client = cls.os_adm.network_client
cls.admin_agents_client = cls.os_adm.network_agents_client
cls.admin_networks_client = cls.os_adm.networks_client
+ cls.admin_routers_client = cls.os_adm.routers_client
cls.admin_subnets_client = cls.os_adm.subnets_client
cls.admin_ports_client = cls.os_adm.ports_client
cls.admin_quotas_client = cls.os_adm.network_quotas_client
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
index 3495b76f..807257f 100644
--- a/tempest/api/network/base_routers.py
+++ b/tempest/api/network/base_routers.py
@@ -33,31 +33,31 @@
self.addCleanup(self._cleanup_router, router)
return router
- def _delete_router(self, router_id, network_client=None):
- client = network_client or self.client
+ def _delete_router(self, router_id, routers_client=None):
+ client = routers_client or self.routers_client
client.delete_router(router_id)
# Asserting that the router is not found in the list
# after deletion
- list_body = self.client.list_routers()
+ list_body = self.routers_client.list_routers()
routers_list = list()
for router in list_body['routers']:
routers_list.append(router['id'])
self.assertNotIn(router_id, routers_list)
def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
- interface = self.client.add_router_interface(router_id,
- subnet_id=subnet_id)
+ interface = self.routers_client.add_router_interface(
+ router_id, subnet_id=subnet_id)
self.addCleanup(self._remove_router_interface_with_subnet_id,
router_id, subnet_id)
self.assertEqual(subnet_id, interface['subnet_id'])
return interface
def _remove_router_interface_with_subnet_id(self, router_id, subnet_id):
- body = self.client.remove_router_interface(router_id,
- subnet_id=subnet_id)
+ body = self.routers_client.remove_router_interface(router_id,
+ subnet_id=subnet_id)
self.assertEqual(subnet_id, body['subnet_id'])
def _remove_router_interface_with_port_id(self, router_id, port_id):
- body = self.client.remove_router_interface(router_id,
- port_id=port_id)
+ body = self.routers_client.remove_router_interface(router_id,
+ port_id=port_id)
self.assertEqual(port_id, body['port_id'])
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index f59ecff..77008ab 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -68,8 +68,8 @@
for port in ports:
if (port['device_owner'].startswith('network:router_interface') and
port['device_id'] in [r['id'] for r in self.routers]):
- self.client.remove_router_interface(port['device_id'],
- port_id=port['id'])
+ self.routers_client.remove_router_interface(port['device_id'],
+ port_id=port['id'])
else:
if port['id'] in [p['id'] for p in self.ports]:
self.ports_client.delete_port(port['id'])
@@ -80,11 +80,11 @@
if subnet['id'] in [s['id'] for s in self.subnets]:
self.subnets_client.delete_subnet(subnet['id'])
self._remove_from_list_by_index(self.subnets, subnet)
- body = self.client.list_routers()
+ body = self.routers_client.list_routers()
routers = body['routers']
for router in routers:
if router['id'] in [r['id'] for r in self.routers]:
- self.client.delete_router(router['id'])
+ self.routers_client.delete_router(router['id'])
self._remove_from_list_by_index(self.routers, router)
def _get_ips_from_subnet(self, **kwargs):
@@ -338,12 +338,12 @@
fixed_ips=[
{'subnet_id': subnet['id'],
'ip_address': ip}])
- self.assertRaisesRegexp(lib_exc.Conflict,
- "object with that identifier already exists",
- self.create_port,
- self.network,
- fixed_ips=[{'subnet_id': subnet['id'],
- 'ip_address': ip}])
+ self.assertRaisesRegex(lib_exc.Conflict,
+ "object with that identifier already exists",
+ self.create_port,
+ self.network,
+ fixed_ips=[{'subnet_id': subnet['id'],
+ 'ip_address': ip}])
def _create_subnet_router(self, kwargs):
subnet = self.create_subnet(self.network, **kwargs)
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index ce9c4be..2156e64 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -59,7 +59,6 @@
cls.router = cls.create_router(data_utils.rand_name('router-'),
external_network_id=cls.ext_net_id)
cls.create_router_interface(cls.router['id'], cls.subnet['id'])
- cls.port = list()
# Create two ports one each for Creation and Updating of floatingIP
for i in range(2):
cls.create_port(cls.network)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index a31a4f0..fa1ed6a 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -12,10 +12,9 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-import itertools
-
import netaddr
import six
+import testtools
from tempest.api.network import base
from tempest.common import custom_matchers
@@ -376,6 +375,9 @@
@test.attr(type='smoke')
@test.idempotent_id('af774677-42a9-4e4b-bb58-16fe6a5bc1ec')
+ @test.requires_ext(extension='external-net', service='network')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
def test_external_network_visibility(self):
"""Verifies user can see external networks but not subnets."""
body = self.networks_client.list_networks(**{'router:external': True})
@@ -387,17 +389,12 @@
self.assertEmpty(nonexternal, "Found non-external networks"
" in filtered list (%s)." % nonexternal)
self.assertIn(CONF.network.public_network_id, networks)
-
- subnets_iter = (network['subnets']
- for network in body['networks']
- if not network['shared'])
- # subnets_iter is a list (iterator) of lists. This flattens it to a
- # list of UUIDs
- public_subnets_iter = itertools.chain(*subnets_iter)
- body = self.subnets_client.list_subnets()
- subnets = [sub['id'] for sub in body['subnets']
- if sub['id'] in public_subnets_iter]
- self.assertEmpty(subnets, "Public subnets visible")
+ # only check the public network ID because the other networks may
+ # belong to other tests and their state may have changed during this
+ # test
+ body = self.subnets_client.list_subnets(
+ network_id=CONF.network.public_network_id)
+ self.assertEmpty(body['subnets'], "Public subnets visible")
class BulkNetworkOpsTestJSON(base.BaseNetworkTest):
@@ -621,7 +618,7 @@
subnet_ids = [subnet['id'] for subnet in subnets['subnets']]
self.assertNotIn(subnet_slaac['id'], subnet_ids,
"Subnet wasn't deleted")
- self.assertRaisesRegexp(
+ self.assertRaisesRegex(
lib_exc.Conflict,
"There are one or more ports still in use on the network",
self.networks_client.delete_network,
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 0088a4d..5ff23c6 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -197,13 +197,13 @@
subnet = self.create_subnet(network)
self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
router = self.create_router(data_utils.rand_name('router-'))
- self.addCleanup(self.client.delete_router, router['id'])
+ self.addCleanup(self.routers_client.delete_router, router['id'])
port = self.ports_client.create_port(network_id=network['id'])
# Add router interface to port created above
- self.client.add_router_interface(router['id'],
- port_id=port['port']['id'])
- self.addCleanup(self.client.remove_router_interface, router['id'],
- port_id=port['port']['id'])
+ self.routers_client.add_router_interface(router['id'],
+ port_id=port['port']['id'])
+ self.addCleanup(self.routers_client.remove_router_interface,
+ router['id'], port_id=port['port']['id'])
# List ports filtered by router_id
port_list = self.ports_client.list_ports(device_id=router['id'])
ports = port_list['ports']
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 887a58f..11f7fc6 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -52,8 +52,8 @@
# NOTE(salv-orlando): Do not invoke self.create_router
# as we need to check the response code
name = data_utils.rand_name('router-')
- create_body = self.client.create_router(
- name, external_gateway_info={
+ create_body = self.routers_client.create_router(
+ name=name, external_gateway_info={
"network_id": CONF.network.public_network_id},
admin_state_up=False)
self.addCleanup(self._delete_router, create_body['router']['id'])
@@ -63,24 +63,25 @@
CONF.network.public_network_id)
self.assertEqual(create_body['router']['admin_state_up'], False)
# Show details of the created router
- show_body = self.client.show_router(create_body['router']['id'])
+ show_body = self.routers_client.show_router(
+ create_body['router']['id'])
self.assertEqual(show_body['router']['name'], name)
self.assertEqual(
show_body['router']['external_gateway_info']['network_id'],
CONF.network.public_network_id)
self.assertEqual(show_body['router']['admin_state_up'], False)
# List routers and verify if created router is there in response
- list_body = self.client.list_routers()
+ list_body = self.routers_client.list_routers()
routers_list = list()
for router in list_body['routers']:
routers_list.append(router['id'])
self.assertIn(create_body['router']['id'], routers_list)
# Update the name of router and verify if it is updated
updated_name = 'updated ' + name
- update_body = self.client.update_router(create_body['router']['id'],
- name=updated_name)
+ update_body = self.routers_client.update_router(
+ create_body['router']['id'], name=updated_name)
self.assertEqual(update_body['router']['name'], updated_name)
- show_body = self.client.show_router(
+ show_body = self.routers_client.show_router(
create_body['router']['id'])
self.assertEqual(show_body['router']['name'], updated_name)
@@ -95,9 +96,9 @@
self.addCleanup(self.identity_utils.delete_project, project_id)
name = data_utils.rand_name('router-')
- create_body = self.admin_client.create_router(name,
- tenant_id=project_id)
- self.addCleanup(self.admin_client.delete_router,
+ create_body = self.admin_routers_client.create_router(
+ name=name, tenant_id=project_id)
+ self.addCleanup(self.admin_routers_client.delete_router,
create_body['router']['id'])
self.assertEqual(project_id, create_body['router']['tenant_id'])
@@ -122,9 +123,9 @@
external_gateway_info = {
'network_id': CONF.network.public_network_id,
'enable_snat': enable_snat}
- create_body = self.admin_client.create_router(
- name, external_gateway_info=external_gateway_info)
- self.addCleanup(self.admin_client.delete_router,
+ create_body = self.admin_routers_client.create_router(
+ name=name, external_gateway_info=external_gateway_info)
+ self.addCleanup(self.admin_routers_client.delete_router,
create_body['router']['id'])
# Verify snat attributes after router creation
self._verify_router_gateway(create_body['router']['id'],
@@ -137,8 +138,8 @@
subnet = self.create_subnet(network)
router = self._create_router(data_utils.rand_name('router-'))
# Add router interface with subnet id
- interface = self.client.add_router_interface(router['id'],
- subnet_id=subnet['id'])
+ interface = self.routers_client.add_router_interface(
+ router['id'], subnet_id=subnet['id'])
self.addCleanup(self._remove_router_interface_with_subnet_id,
router['id'], subnet['id'])
self.assertIn('subnet_id', interface.keys())
@@ -158,7 +159,7 @@
port_body = self.ports_client.create_port(
network_id=network['id'])
# add router interface to port created above
- interface = self.client.add_router_interface(
+ interface = self.routers_client.add_router_interface(
router['id'],
port_id=port_body['port']['id'])
self.addCleanup(self._remove_router_interface_with_port_id,
@@ -172,7 +173,7 @@
router['id'])
def _verify_router_gateway(self, router_id, exp_ext_gw_info=None):
- show_body = self.admin_client.show_router(router_id)
+ show_body = self.admin_routers_client.show_router(router_id)
actual_ext_gw_info = show_body['router']['external_gateway_info']
if exp_ext_gw_info is None:
self.assertIsNone(actual_ext_gw_info)
@@ -198,7 +199,7 @@
@test.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79')
def test_update_router_set_gateway(self):
router = self._create_router(data_utils.rand_name('router-'))
- self.client.update_router(
+ self.routers_client.update_router(
router['id'],
external_gateway_info={
'network_id': CONF.network.public_network_id})
@@ -212,7 +213,7 @@
@test.requires_ext(extension='ext-gw-mode', service='network')
def test_update_router_set_gateway_with_snat_explicit(self):
router = self._create_router(data_utils.rand_name('router-'))
- self.admin_client.update_router_with_snat_gw_info(
+ self.admin_routers_client.update_router_with_snat_gw_info(
router['id'],
external_gateway_info={
'network_id': CONF.network.public_network_id,
@@ -227,7 +228,7 @@
@test.requires_ext(extension='ext-gw-mode', service='network')
def test_update_router_set_gateway_without_snat(self):
router = self._create_router(data_utils.rand_name('router-'))
- self.admin_client.update_router_with_snat_gw_info(
+ self.admin_routers_client.update_router_with_snat_gw_info(
router['id'],
external_gateway_info={
'network_id': CONF.network.public_network_id,
@@ -243,7 +244,8 @@
router = self._create_router(
data_utils.rand_name('router-'),
external_network_id=CONF.network.public_network_id)
- self.client.update_router(router['id'], external_gateway_info={})
+ self.routers_client.update_router(router['id'],
+ external_gateway_info={})
self._verify_router_gateway(router['id'])
# No gateway port expected
list_body = self.admin_ports_client.list_ports(
@@ -257,7 +259,7 @@
router = self._create_router(
data_utils.rand_name('router-'),
external_network_id=CONF.network.public_network_id)
- self.admin_client.update_router_with_snat_gw_info(
+ self.admin_routers_client.update_router_with_snat_gw_info(
router['id'],
external_gateway_info={
'network_id': CONF.network.public_network_id,
@@ -301,9 +303,9 @@
)
test_routes.sort(key=lambda x: x['destination'])
- extra_route = self.client.update_extra_routes(router['id'],
- routes=test_routes)
- show_body = self.client.show_router(router['id'])
+ extra_route = self.routers_client.update_extra_routes(
+ router['id'], routes=test_routes)
+ show_body = self.routers_client.show_router(router['id'])
# Assert the number of routes
self.assertEqual(routes_num, len(extra_route['router']['routes']))
self.assertEqual(routes_num, len(show_body['router']['routes']))
@@ -323,22 +325,23 @@
routes[i]['destination'])
self.assertEqual(test_routes[i]['nexthop'], routes[i]['nexthop'])
- self.client.delete_extra_routes(router['id'])
- show_body_after_deletion = self.client.show_router(router['id'])
+ self.routers_client.delete_extra_routes(router['id'])
+ show_body_after_deletion = self.routers_client.show_router(
+ router['id'])
self.assertEmpty(show_body_after_deletion['router']['routes'])
def _delete_extra_routes(self, router_id):
- self.client.delete_extra_routes(router_id)
+ self.routers_client.delete_extra_routes(router_id)
@test.idempotent_id('a8902683-c788-4246-95c7-ad9c6d63a4d9')
def test_update_router_admin_state(self):
router = self._create_router(data_utils.rand_name('router-'))
self.assertFalse(router['admin_state_up'])
# Update router admin state
- update_body = self.client.update_router(router['id'],
- admin_state_up=True)
+ update_body = self.routers_client.update_router(router['id'],
+ admin_state_up=True)
self.assertTrue(update_body['router']['admin_state_up'])
- show_body = self.client.show_router(router['id'])
+ show_body = self.routers_client.show_router(router['id'])
self.assertTrue(show_body['router']['admin_state_up'])
@test.attr(type='smoke')
@@ -385,21 +388,21 @@
@test.idempotent_id('141297aa-3424-455d-aa8d-f2d95731e00a')
def test_create_distributed_router(self):
name = data_utils.rand_name('router')
- create_body = self.admin_client.create_router(
- name, distributed=True)
+ create_body = self.admin_routers_client.create_router(
+ name=name, distributed=True)
self.addCleanup(self._delete_router,
create_body['router']['id'],
- self.admin_client)
+ self.admin_routers_client)
self.assertTrue(create_body['router']['distributed'])
@test.idempotent_id('644d7a4a-01a1-4b68-bb8d-0c0042cb1729')
def test_convert_centralized_router(self):
router = self._create_router(data_utils.rand_name('router'))
self.assertNotIn('distributed', router)
- update_body = self.admin_client.update_router(router['id'],
- distributed=True)
+ update_body = self.admin_routers_client.update_router(router['id'],
+ distributed=True)
self.assertTrue(update_body['router']['distributed'])
- show_body = self.admin_client.show_router(router['id'])
+ show_body = self.admin_routers_client.show_router(router['id'])
self.assertTrue(show_body['router']['distributed'])
- show_body = self.client.show_router(router['id'])
+ show_body = self.routers_client.show_router(router['id'])
self.assertNotIn('distributed', show_body['router'])
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index 84dbd8d..36aaf2d 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -47,7 +47,7 @@
@test.idempotent_id('37a94fc0-a834-45b9-bd23-9a81d2fd1e22')
def test_router_add_gateway_invalid_network_returns_404(self):
self.assertRaises(lib_exc.NotFound,
- self.client.update_router,
+ self.routers_client.update_router,
self.router['id'],
external_gateway_info={
'network_id': self.router['id']})
@@ -60,7 +60,7 @@
sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
self.create_subnet(alt_network, cidr=sub_cidr)
self.assertRaises(lib_exc.BadRequest,
- self.client.update_router,
+ self.routers_client.update_router,
self.router['id'],
external_gateway_info={
'network_id': alt_network['id']})
@@ -84,31 +84,31 @@
@test.attr(type=['negative'])
@test.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20')
def test_router_remove_interface_in_use_returns_409(self):
- self.client.add_router_interface(self.router['id'],
- subnet_id=self.subnet['id'])
+ self.routers_client.add_router_interface(self.router['id'],
+ subnet_id=self.subnet['id'])
self.assertRaises(lib_exc.Conflict,
- self.client.delete_router,
+ self.routers_client.delete_router,
self.router['id'])
@test.attr(type=['negative'])
@test.idempotent_id('c2a70d72-8826-43a7-8208-0209e6360c47')
def test_show_non_existent_router_returns_404(self):
router = data_utils.rand_name('non_exist_router')
- self.assertRaises(lib_exc.NotFound, self.client.show_router,
+ self.assertRaises(lib_exc.NotFound, self.routers_client.show_router,
router)
@test.attr(type=['negative'])
@test.idempotent_id('b23d1569-8b0c-4169-8d4b-6abd34fad5c7')
def test_update_non_existent_router_returns_404(self):
router = data_utils.rand_name('non_exist_router')
- self.assertRaises(lib_exc.NotFound, self.client.update_router,
+ self.assertRaises(lib_exc.NotFound, self.routers_client.update_router,
router, name="new_name")
@test.attr(type=['negative'])
@test.idempotent_id('c7edc5ad-d09d-41e6-a344-5c0c31e2e3e4')
def test_delete_non_existent_router_returns_404(self):
router = data_utils.rand_name('non_exist_router')
- self.assertRaises(lib_exc.NotFound, self.client.delete_router,
+ self.assertRaises(lib_exc.NotFound, self.routers_client.delete_router,
router)
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index 5213c18..401fa3b 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -227,7 +227,7 @@
{'ethertype': 'IPv4',
'ip_prefix': CONF.network.tenant_network_v6_cidr})
for pair in pairs:
- self.assertRaisesRegexp(
+ self.assertRaisesRegex(
lib_exc.BadRequest,
"Conflicting value ethertype",
self.security_group_rules_client.create_security_group_rule,
diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py
index d027132..c6cc8e2 100644
--- a/tempest/api/network/test_subnetpools_extensions.py
+++ b/tempest/api/network/test_subnetpools_extensions.py
@@ -30,7 +30,7 @@
Lists subnet pool.
Show subnet pool details.
- v2.0 of the Neutron API is assumed. It is assumed that subnetpools
+ v2.0 of the Neutron API is assumed. It is assumed that subnet_allocation
options mentioned in the [network-feature-enabled] section and
default_network option mentioned in the [network] section of
etc/tempest.conf:
@@ -40,8 +40,8 @@
@classmethod
def skip_checks(cls):
super(SubnetPoolsTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('subnetpools', 'network'):
- msg = "subnet pools extension not enabled."
+ if not test.is_extension_enabled('subnet_allocation', 'network'):
+ msg = "subnet_allocation extension not enabled."
raise cls.skipException(msg)
@test.attr(type='smoke')
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
index ffff580..61c271c 100644
--- a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
+++ b/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
@@ -1,10 +1,15 @@
heat_template_version: 2013-05-23
+parameters:
+ volume_size:
+ type: number
+ default: 1
+
resources:
volume:
type: OS::Cinder::Volume
properties:
- size: 1
+ size: { get_param: volume_size }
description: a descriptive description
name: volume_name
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
index b660c19..0bc6d69 100644
--- a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
+++ b/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
@@ -1,11 +1,16 @@
heat_template_version: 2013-05-23
+parameters:
+ volume_size:
+ type: number
+ default: 1
+
resources:
volume:
deletion_policy: 'Retain'
type: OS::Cinder::Volume
properties:
- size: 1
+ size: { get_param: volume_size }
description: a descriptive description
name: volume_name
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 001bc08..5483361 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -151,7 +151,7 @@
def test_created_router(self):
"""Verifies created router."""
router_id = self.test_resources.get('Router')['physical_resource_id']
- body = self.network_client.show_router(router_id)
+ body = self.routers_client.show_router(router_id)
router = body['router']
self.assertEqual(self.neutron_basic_template['resources'][
'Router']['properties']['name'], router['name'])
diff --git a/tempest/api/orchestration/stacks/test_volumes.py b/tempest/api/orchestration/stacks/test_volumes.py
index 37e68ef..a5aaf6e 100644
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ b/tempest/api/orchestration/stacks/test_volumes.py
@@ -32,8 +32,7 @@
self.assertIsNotNone(volume_id)
volume = self.volumes_client.show_volume(volume_id)['volume']
self.assertEqual('available', volume.get('status'))
- self.assertEqual(template['resources']['volume']['properties'][
- 'size'], volume.get('size'))
+ self.assertEqual(CONF.volume.volume_size, volume.get('size'))
# Some volume properties have been renamed with Cinder v2
if CONF.volume_feature_enabled.api_v2:
@@ -51,8 +50,8 @@
def _outputs_verify(self, stack_identifier, template):
self.assertEqual('available',
self.get_stack_output(stack_identifier, 'status'))
- self.assertEqual(str(template['resources']['volume']['properties'][
- 'size']), self.get_stack_output(stack_identifier, 'size'))
+ self.assertEqual(str(CONF.volume.volume_size),
+ self.get_stack_output(stack_identifier, 'size'))
self.assertEqual(template['resources']['volume']['properties'][
'description'], self.get_stack_output(stack_identifier,
'display_description'))
@@ -65,7 +64,12 @@
"""Create and delete a volume via OS::Cinder::Volume."""
stack_name = data_utils.rand_name('heat')
template = self.read_template('cinder_basic')
- stack_identifier = self.create_stack(stack_name, template)
+ stack_identifier = self.create_stack(
+ stack_name,
+ template,
+ parameters={
+ 'volume_size': CONF.volume.volume_size
+ })
self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
# Verify with cinder that the volume exists, with matching details
@@ -94,7 +98,12 @@
"""Ensure the 'Retain' deletion policy is respected."""
stack_name = data_utils.rand_name('heat')
template = self.read_template('cinder_basic_delete_retain')
- stack_identifier = self.create_stack(stack_name, template)
+ stack_identifier = self.create_stack(
+ stack_name,
+ template,
+ parameters={
+ 'volume_size': CONF.volume.volume_size
+ })
self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
# Verify with cinder that the volume exists, with matching details
diff --git a/tempest/api/utils.py b/tempest/api/utils.py
deleted file mode 100644
index 00c93b7..0000000
--- a/tempest/api/utils.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# 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.
-
-"""Common utilities used in testing."""
-
-from tempest import test
-
-
-class skip_unless_attr(object):
- """Decorator that skips a test if a specified attr exists and is True."""
- def __init__(self, attr, msg=None):
- self.attr = attr
- self.message = msg or ("Test case attribute %s not found "
- "or False") % attr
-
- def __call__(self, func):
- def _skipper(*args, **kw):
- """Wrapped skipper function."""
- testobj = args[0]
- if not getattr(testobj, self.attr, False):
- raise test.BaseTestCase.skipException(self.message)
- func(*args, **kw)
- _skipper.__name__ = func.__name__
- _skipper.__doc__ = func.__doc__
- return _skipper
diff --git a/tempest/clients.py b/tempest/clients.py
index f1b4e55..8931706 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -131,6 +131,7 @@
from tempest.services.image.v1.json.images_client import ImagesClient
from tempest.services.image.v2.json.images_client import ImagesClientV2
from tempest.services.network.json.network_client import NetworkClient
+from tempest.services.network.json.routers_client import RoutersClient
from tempest.services.network.json.security_group_rules_client import \
SecurityGroupRulesClient
from tempest.services.object_storage.account_client import AccountClient
@@ -308,6 +309,14 @@
build_interval=CONF.network.build_interval,
build_timeout=CONF.network.build_timeout,
**self.default_params)
+ self.routers_client = RoutersClient(
+ self.auth_provider,
+ CONF.network.catalog_type,
+ CONF.network.region or CONF.identity.region,
+ endpoint_type=CONF.network.endpoint_type,
+ build_interval=CONF.network.build_interval,
+ build_timeout=CONF.network.build_timeout,
+ **self.default_params)
self.security_group_rules_client = SecurityGroupRulesClient(
self.auth_provider,
CONF.network.catalog_type,
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index b95111a..6124676 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -104,6 +104,7 @@
from tempest.services.identity.v2.json import tenants_client
from tempest.services.identity.v2.json import users_client
from tempest.services.network.json import network_client
+from tempest.services.network.json import routers_client
LOG = None
CONF = config.CONF
@@ -171,6 +172,7 @@
)
network_admin = None
networks_admin = None
+ routers_admin = None
subnets_admin = None
neutron_iso_networks = False
if (CONF.service_available.neutron and
@@ -188,6 +190,12 @@
CONF.network.region or CONF.identity.region,
endpoint_type='adminURL',
**params)
+ routers_admin = routers_client.RoutersClient(
+ _auth,
+ CONF.network.catalog_type,
+ CONF.network.region or CONF.identity.region,
+ endpoint_type='adminURL',
+ **params)
subnets_admin = subnets_client.SubnetsClient(
_auth,
CONF.network.catalog_type,
@@ -195,12 +203,13 @@
endpoint_type='adminURL',
**params)
return (identity_admin, tenants_admin, roles_admin, users_admin,
- neutron_iso_networks, network_admin, networks_admin, subnets_admin)
+ neutron_iso_networks, network_admin, networks_admin, routers_admin,
+ subnets_admin)
def create_resources(opts, resources):
(identity_admin, tenants_admin, roles_admin, users_admin,
- neutron_iso_networks, network_admin, networks_admin,
+ neutron_iso_networks, network_admin, networks_admin, routers_admin,
subnets_admin) = get_admin_clients(opts)
roles = roles_admin.list_roles()['roles']
for u in resources['users']:
@@ -246,8 +255,8 @@
for u in resources['users']:
tenant = identity.get_tenant_by_name(tenants_admin, u['tenant'])
network_name, router_name = create_network_resources(
- network_admin, networks_admin, subnets_admin, tenant['id'],
- u['name'])
+ network_admin, networks_admin, routers_admin, subnets_admin,
+ tenant['id'], u['name'])
u['network'] = network_name
u['router'] = router_name
LOG.info('Networks created')
@@ -274,7 +283,8 @@
def create_network_resources(network_admin_client, networks_admin_client,
- subnets_admin_client, tenant_id, name):
+ routers_admin_client, subnets_admin_client,
+ tenant_id, name):
def _create_network(name):
resp_body = networks_admin_client.create_network(
@@ -305,14 +315,14 @@
def _create_router(router_name):
external_net_id = dict(
network_id=CONF.network.public_network_id)
- resp_body = network_admin_client.create_router(
- router_name,
+ resp_body = routers_admin_client.create_router(
+ name=router_name,
external_gateway_info=external_net_id,
tenant_id=tenant_id)
return resp_body['router']
def _add_router_interface(router_id, subnet_id):
- network_admin_client.add_router_interface(router_id,
+ routers_admin_client.add_router_interface(router_id,
subnet_id=subnet_id)
network_name = name + "-network"
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index 5a52043..3706b54 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -117,7 +117,6 @@
if is_dry_run:
self.dry_run_data["_tenants_to_clean"] = {}
- f = open(DRY_RUN_JSON, 'w+')
admin_mgr = self.admin_mgr
# Always cleanup tempest and alt tempest tenants unless
@@ -146,9 +145,9 @@
svc.run()
if is_dry_run:
- f.write(json.dumps(self.dry_run_data, sort_keys=True,
- indent=2, separators=(',', ': ')))
- f.close()
+ with open(DRY_RUN_JSON, 'w+') as f:
+ f.write(json.dumps(self.dry_run_data, sort_keys=True,
+ indent=2, separators=(',', ': ')))
self._remove_admin_user_roles()
@@ -281,16 +280,15 @@
svc = service(admin_mgr, **kwargs)
svc.run()
- f = open(SAVED_STATE_JSON, 'w+')
- f.write(json.dumps(data,
- sort_keys=True, indent=2, separators=(',', ': ')))
- f.close()
+ with open(SAVED_STATE_JSON, 'w+') as f:
+ f.write(json.dumps(data,
+ sort_keys=True, indent=2, separators=(',', ': ')))
def _load_json(self):
try:
- json_file = open(SAVED_STATE_JSON)
- self.json_data = json.load(json_file)
- json_file.close()
+ with open(SAVED_STATE_JSON) as json_file:
+ self.json_data = json.load(json_file)
+
except IOError as ex:
LOG.exception("Failed loading saved state, please be sure you"
" have first run cleanup with --init-saved-state "
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 0640a4e..a0676b6 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -390,6 +390,7 @@
self.metering_labels_client = manager.metering_labels_client
self.metering_label_rules_client = manager.metering_label_rules_client
self.security_groups_client = manager.security_groups_client
+ self.routers_client = manager.routers_client
def _filter_by_conf_networks(self, item_list):
if not item_list or not all(('network_id' in i for i in item_list)):
@@ -449,7 +450,7 @@
class NetworkRouterService(NetworkService):
def list(self):
- client = self.client
+ client = self.routers_client
routers = client.list_routers(**self.tenant_filter)
routers = routers['routers']
if self.is_preserve:
@@ -460,7 +461,7 @@
return routers
def delete(self):
- client = self.client
+ client = self.routers_client
routers = self.list()
for router in routers:
try:
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 95be89e..057c227 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -134,6 +134,7 @@
from tempest.services.identity.v2.json import users_client
from tempest.services.image.v2.json import images_client
from tempest.services.network.json import network_client
+from tempest.services.network.json import routers_client
from tempest.services.object_storage import container_client
from tempest.services.object_storage import object_client
from tempest.services.telemetry.json import alarming_client
@@ -270,6 +271,14 @@
build_interval=CONF.network.build_interval,
build_timeout=CONF.network.build_timeout,
**default_params)
+ self.routers = routers_client.RoutersClient(
+ _auth,
+ CONF.network.catalog_type,
+ CONF.network.region or CONF.identity.region,
+ endpoint_type=CONF.network.endpoint_type,
+ build_interval=CONF.network.build_interval,
+ build_timeout=CONF.network.build_timeout,
+ **default_params)
self.subnets = subnets_client.SubnetsClient(
_auth,
CONF.network.catalog_type,
@@ -739,7 +748,7 @@
def _get_router_namespace(client, network):
network_id = _get_resource_by_name(client.networks,
'networks', network)['id']
- n_body = client.networks.list_routers()
+ n_body = client.routers.list_routers()
for router in n_body['routers']:
router_id = router['id']
r_body = client.networks.list_router_interfaces(router_id)
@@ -824,12 +833,12 @@
client = client_for_user(router['owner'])
# only create a router if the name isn't here
- body = client.networks.list_routers()
+ body = client.routers.list_routers()
if any(item['name'] == router['name'] for item in body['routers']):
LOG.warning("Duplicated router name: %s" % router['name'])
continue
- client.networks.create_router(router['name'])
+ client.networks.create_router(name=router['name'])
def destroy_routers(routers):
@@ -841,9 +850,9 @@
for subnet in router['subnet']:
subnet_id = _get_resource_by_name(client.networks,
'subnets', subnet)['id']
- client.networks.remove_router_interface(router_id,
- subnet_id=subnet_id)
- client.networks.delete_router(router_id)
+ client.routers.remove_router_interface(router_id,
+ subnet_id=subnet_id)
+ client.routers.delete_router(router_id)
def add_router_interface(routers):
@@ -856,13 +865,13 @@
subnet_id = _get_resource_by_name(client.networks,
'subnets', subnet)['id']
# connect routers to their subnets
- client.networks.add_router_interface(router_id,
- subnet_id=subnet_id)
+ client.routers.add_router_interface(router_id,
+ subnet_id=subnet_id)
# connect routers to external network if set to "gateway"
if router['gateway']:
if CONF.network.public_network_id:
ext_net = CONF.network.public_network_id
- client.networks._update_router(
+ client.routers._update_router(
router_id, set_enable_snat=True,
external_gateway_info={"network_id": ext_net})
else:
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 5e5e127..9049886 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -354,8 +354,6 @@
outfile = sys.stdout
if update:
conf_file = _get_config_file()
- if opts.output:
- outfile = open(opts.output, 'w+')
CONF_PARSER = moves.configparser.SafeConfigParser()
CONF_PARSER.optionxform = str
CONF_PARSER.readfp(conf_file)
@@ -378,8 +376,9 @@
display_results(results, update, replace)
if update:
conf_file.close()
- CONF_PARSER.write(outfile)
- outfile.close()
+ if opts.output:
+ with open(opts.output, 'w+') as outfile:
+ CONF_PARSER.write(outfile)
finally:
icreds.clear_creds()
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 2fbd1b2..2d2909a 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -49,10 +49,6 @@
# TODO(jlanoux) add support of wait_until PINGABLE/SSHABLE
- name = name
- flavor = flavor
- image_id = image_id
-
if name is None:
name = data_utils.rand_name(__name__ + "-instance")
if flavor is None:
@@ -152,14 +148,12 @@
except Exception:
with excutils.save_and_reraise_exception():
- if ('preserve_server_on_error' not in kwargs
- or kwargs['preserve_server_on_error'] is False):
- for server in servers:
- try:
- clients.servers_client.delete_server(
- server['id'])
- except Exception:
- LOG.exception('Deleting server %s failed'
- % server['id'])
+ for server in servers:
+ try:
+ clients.servers_client.delete_server(
+ server['id'])
+ except Exception:
+ LOG.exception('Deleting server %s failed'
+ % server['id'])
return body, servers
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index 0a01bd4..5f6c8b8 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -64,6 +64,7 @@
self.domains_admin_client,
self.network_admin_client,
self.networks_admin_client,
+ self.routers_admin_client,
self.subnets_admin_client,
self.ports_admin_client,
self.security_groups_admin_client) = self._get_admin_clients()
@@ -93,13 +94,14 @@
if self.identity_version == 'v2':
return (os.identity_client, os.tenants_client, os.users_client,
os.roles_client, None, os.network_client,
- os.networks_client, os.subnets_client, os.ports_client,
- os.security_groups_client)
+ os.networks_client, os.routers_client, os.subnets_client,
+ os.ports_client, os.security_groups_client)
else:
return (os.identity_v3_client, os.projects_client,
os.users_v3_client, os.roles_v3_client, os.domains_client,
- os.network_client, os.networks_client, os.subnets_client,
- os.ports_client, os.security_groups_client)
+ os.network_client, os.networks_client, os.routers_client,
+ os.subnets_client, os.ports_client,
+ os.security_groups_client)
def _create_creds(self, suffix="", admin=False, roles=None):
"""Create random credentials under the following schema.
@@ -237,14 +239,14 @@
def _create_router(self, router_name, tenant_id):
external_net_id = dict(
network_id=CONF.network.public_network_id)
- resp_body = self.network_admin_client.create_router(
- router_name,
+ resp_body = self.routers_admin_client.create_router(
+ name=router_name,
external_gateway_info=external_net_id,
tenant_id=tenant_id)
return resp_body['router']
def _add_router_interface(self, router_id, subnet_id):
- self.network_admin_client.add_router_interface(router_id,
+ self.routers_admin_client.add_router_interface(router_id,
subnet_id=subnet_id)
def get_credentials(self, credential_type):
@@ -295,9 +297,9 @@
return self.get_credentials(roles)
def _clear_isolated_router(self, router_id, router_name):
- net_client = self.network_admin_client
+ client = self.routers_admin_client
try:
- net_client.delete_router(router_id)
+ client.delete_router(router_id)
except lib_exc.NotFound:
LOG.warning('router with name: %s not found for delete' %
router_name)
@@ -331,7 +333,7 @@
(secgroup['name'], secgroup['id']))
def _clear_isolated_net_resources(self):
- net_client = self.network_admin_client
+ client = self.routers_admin_client
for cred in self._creds:
creds = self._creds.get(cred)
if (not creds or not any([creds.router, creds.network,
@@ -344,7 +346,7 @@
if (not self.network_resources or
(self.network_resources.get('router') and creds.subnet)):
try:
- net_client.remove_router_interface(
+ client.remove_router_interface(
creds.router['id'],
subnet_id=creds.subnet['id'])
except lib_exc.NotFound:
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index cfd9df6..36e3e3a 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -102,7 +102,12 @@
cmd = "ip addr %s| awk '/ether/ {print $2}'" % show_nic
return self.exec_command(cmd).strip().lower()
- def get_nic_name(self, address):
+ def get_nic_name_by_mac(self, address):
+ cmd = "ip -o link | awk '/%s/ {print $2}'" % address
+ nic = self.exec_command(cmd)
+ return nic.strip().strip(":").lower()
+
+ def get_nic_name_by_ip(self, address):
cmd = "ip -o addr | awk '/%s/ {print $2}'" % address
nic = self.exec_command(cmd)
return nic.strip().strip(":").lower()
@@ -142,7 +147,7 @@
def _renew_lease_udhcpc(self, fixed_ip=None):
"""Renews DHCP lease via udhcpc client. """
file_path = '/var/run/udhcpc.'
- nic_name = self.get_nic_name(fixed_ip)
+ nic_name = self.get_nic_name_by_ip(fixed_ip)
pid = self.exec_command('cat {path}{nic}.pid'.
format(path=file_path, nic=nic_name))
pid = pid.strip()
diff --git a/tempest/config.py b/tempest/config.py
index c3c6eda..4c3b04b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -281,13 +281,7 @@
help=('The minimum number of compute nodes expected. This will '
'be utilized by some multinode specific tests to ensure '
'that requests match the expected size of the cluster '
- 'you are testing with.'))
-]
-
-compute_features_group = cfg.OptGroup(name='compute-feature-enabled',
- title="Enabled Compute Service Features")
-
-ComputeFeaturesGroup = [
+ 'you are testing with.')),
cfg.StrOpt('min_microversion',
default=None,
help="Lower version of the test target microversion range. "
@@ -296,7 +290,8 @@
"min_microversion and max_microversion. "
"If both values are not specified, Tempest avoids tests "
"which require a microversion. Valid values are string "
- "with format 'X.Y' or string 'latest'"),
+ "with format 'X.Y' or string 'latest'",
+ deprecated_group='compute-feature-enabled'),
cfg.StrOpt('max_microversion',
default=None,
help="Upper version of the test target microversion range. "
@@ -305,7 +300,14 @@
"min_microversion and max_microversion. "
"If both values are not specified, Tempest avoids tests "
"which require a microversion. Valid values are string "
- "with format 'X.Y' or string 'latest'"),
+ "with format 'X.Y' or string 'latest'",
+ deprecated_group='compute-feature-enabled'),
+]
+
+compute_features_group = cfg.OptGroup(name='compute-feature-enabled',
+ title="Enabled Compute Service Features")
+
+ComputeFeaturesGroup = [
cfg.BoolOpt('disk_config',
default=True,
help="If false, skip disk config tests"),
@@ -962,7 +964,7 @@
DataProcessingFeaturesGroup = [
cfg.ListOpt('plugins',
- default=["vanilla", "hdp"],
+ default=["vanilla", "cdh"],
deprecated_group="data_processing-feature-enabled",
help="List of enabled data processing plugins")
]
diff --git a/tempest/hacking/ignored_list_T110.txt b/tempest/hacking/ignored_list_T110.txt
index 50a5477..5d3fc93 100644
--- a/tempest/hacking/ignored_list_T110.txt
+++ b/tempest/hacking/ignored_list_T110.txt
@@ -5,3 +5,4 @@
./tempest/services/volume/base/base_backups_client.py
./tempest/services/baremetal/base.py
./tempest/services/network/json/network_client.py
+./tempest/services/network/json/routers_client.py
diff --git a/tempest/lib/auth.py b/tempest/lib/auth.py
index 2d20a0b..71c4f4f 100644
--- a/tempest/lib/auth.py
+++ b/tempest/lib/auth.py
@@ -622,6 +622,9 @@
return None not in (self.username, self.password)
+COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')]
+
+
class KeystoneV3Credentials(Credentials):
"""Credentials suitable for the Keystone Identity V3 API"""
@@ -630,6 +633,16 @@
'project_name', 'tenant_id', 'tenant_name', 'user_domain_id',
'user_domain_name', 'user_id']
+ def _apply_credentials(self, attr):
+ for (key1, key2) in COLLISIONS:
+ val1 = attr.get(key1)
+ val2 = attr.get(key2)
+ if val1 and val2 and val1 != val2:
+ msg = ('Cannot have conflicting values for %s and %s' %
+ (key1, key2))
+ raise exceptions.InvalidCredentials(msg)
+ super(KeystoneV3Credentials, self)._apply_credentials(attr)
+
def __setattr__(self, key, value):
parent = super(KeystoneV3Credentials, self)
# for tenant_* set both project and tenant
@@ -657,8 +670,10 @@
parent.__setattr__('user_domain_name', value)
# support domain_name coming from config
if key == 'domain_name':
- parent.__setattr__('user_domain_name', value)
- parent.__setattr__('project_domain_name', value)
+ if self.user_domain_name is None:
+ parent.__setattr__('user_domain_name', value)
+ if self.project_domain_name is None:
+ parent.__setattr__('project_domain_name', value)
# finally trigger default behaviour for all attributes
parent.__setattr__(key, value)
diff --git a/tempest/lib/cmd/skip_tracker.py b/tempest/lib/cmd/skip_tracker.py
index b5c9b95..b7d6a24 100755
--- a/tempest/lib/cmd/skip_tracker.py
+++ b/tempest/lib/cmd/skip_tracker.py
@@ -81,21 +81,23 @@
DEF_RE = re.compile(r'\s*def (\w+)\(')
bug_found = False
results = []
- lines = open(path, 'rb').readlines()
- for x, line in enumerate(lines):
- if not bug_found:
- res = BUG_RE.match(line)
- if res:
- bug_no = int(res.group(1))
- debug("Found bug skip %s on line %d", bug_no, x + 1)
- bug_found = True
- else:
- res = DEF_RE.match(line)
- if res:
- method = res.group(1)
- debug("Found test method %s skips for bug %d", method, bug_no)
- results.append((method, bug_no))
- bug_found = False
+ with open(path, 'rb') as content:
+ lines = content.readlines()
+ for x, line in enumerate(lines):
+ if not bug_found:
+ res = BUG_RE.match(line)
+ if res:
+ bug_no = int(res.group(1))
+ debug("Found bug skip %s on line %d", bug_no, x + 1)
+ bug_found = True
+ else:
+ res = DEF_RE.match(line)
+ if res:
+ method = res.group(1)
+ debug("Found test method %s skips for bug %d",
+ method, bug_no)
+ results.append((method, bug_no))
+ bug_found = False
return results
diff --git a/tempest/lib/common/api_version_utils.py b/tempest/lib/common/api_version_utils.py
index 73cd280..1371b3c 100644
--- a/tempest/lib/common/api_version_utils.py
+++ b/tempest/lib/common/api_version_utils.py
@@ -82,7 +82,7 @@
def select_request_microversion(test_min_version, cfg_min_version):
- """Select microversion from test and configuration.
+ """Select microversion from test and configuration min version.
Compare requested microversion and return the maximum
microversion out of those.
@@ -101,7 +101,7 @@
def assert_version_header_matches_request(api_microversion_header_name,
api_microversion,
response_header):
- """Checks API microversion in resposne header
+ """Checks API microversion in response header
Verify whether microversion is present in response header
and with specified 'api_microversion' value.
diff --git a/tempest/lib/services/compute/base_compute_client.py b/tempest/lib/services/compute/base_compute_client.py
index bbadc8f..9161abb 100644
--- a/tempest/lib/services/compute/base_compute_client.py
+++ b/tempest/lib/services/compute/base_compute_client.py
@@ -23,15 +23,14 @@
class BaseComputeClient(rest_client.RestClient):
"""Base compute service clients class to support microversion.
- This class adds microversion to API request header if same is set
- and provide interface to select appropriate JSON schema file for
+ This class adds microversion to API request header if that is set
+ and provides interface to select appropriate JSON schema file for
response validation.
- :param auth_provider: an auth provider object used to wrap requests in
+ :param auth_provider: An auth provider object used to wrap requests in
auth
:param str service: The service name to use for the catalog lookup
:param str region: The region to use for the catalog lookup
- request with microversion
:param kwargs: kwargs required by rest_client.RestClient
"""
@@ -79,12 +78,12 @@
for items in schema_versions_info:
min_version = api_version_request.APIVersionRequest(items['min'])
max_version = api_version_request.APIVersionRequest(items['max'])
- # This is case where self.api_microversion is None, which means
+ # This is case where COMPUTE_MICROVERSION is None, which means
# request without microversion So select base v2.1 schema.
if version.is_null() and items['min'] is None:
schema = items['schema']
break
- # else select appropriate schema as per self.api_microversion
+ # else select appropriate schema as per COMPUTE_MICROVERSION
elif version.matches(min_version, max_version):
schema = items['schema']
break
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index eb29176..8ba5f9a 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -66,6 +66,7 @@
cls.network_client = cls.manager.network_client
cls.networks_client = cls.manager.networks_client
cls.ports_client = cls.manager.ports_client
+ cls.routers_client = cls.manager.routers_client
cls.subnets_client = cls.manager.subnets_client
cls.floating_ips_client = cls.manager.floating_ips_client
cls.security_groups_client = cls.manager.security_groups_client
@@ -261,7 +262,7 @@
return server
def create_volume(self, size=None, name=None, snapshot_id=None,
- imageRef=None, volume_type=None, wait_on_delete=True):
+ imageRef=None, volume_type=None):
if name is None:
name = data_utils.rand_name(self.__class__.__name__)
kwargs = {'display_name': name,
@@ -272,17 +273,10 @@
kwargs.update({'size': size})
volume = self.volumes_client.create_volume(**kwargs)['volume']
- if wait_on_delete:
- self.addCleanup(self.volumes_client.wait_for_resource_deletion,
- volume['id'])
- self.addCleanup(self.delete_wrapper,
- self.volumes_client.delete_volume, volume['id'])
- else:
- self.addCleanup_with_wait(
- waiter_callable=self.volumes_client.wait_for_resource_deletion,
- thing_id=volume['id'], thing_id_param='id',
- cleanup_callable=self.delete_wrapper,
- cleanup_args=[self.volumes_client.delete_volume, volume['id']])
+ self.addCleanup(self.volumes_client.wait_for_resource_deletion,
+ volume['id'])
+ self.addCleanup(self.delete_wrapper,
+ self.volumes_client.delete_volume, volume['id'])
# NOTE(e0ne): Cinder API v2 uses name instead of display_name
if 'display_name' in volume:
@@ -393,8 +387,6 @@
if properties is None:
properties = {}
name = data_utils.rand_name('%s-' % name)
- image_file = open(path, 'rb')
- self.addCleanup(image_file.close)
params = {
'name': name,
'container_format': fmt,
@@ -405,7 +397,8 @@
image = self.image_client.create_image(**params)['image']
self.addCleanup(self.image_client.delete_image, image['id'])
self.assertEqual("queued", image['status'])
- self.image_client.update_image(image['id'], data=image_file)
+ with open(path, 'rb') as image_file:
+ self.image_client.update_image(image['id'], data=image_file)
return image['id']
def glance_image_create(self):
@@ -690,17 +683,21 @@
cls.tenant_id = cls.manager.identity_client.tenant_id
def _create_network(self, client=None, networks_client=None,
- tenant_id=None, namestart='network-smoke-'):
+ routers_client=None, tenant_id=None,
+ namestart='network-smoke-'):
if not client:
client = self.network_client
if not networks_client:
networks_client = self.networks_client
+ if not routers_client:
+ routers_client = self.routers_client
if not tenant_id:
tenant_id = client.tenant_id
name = data_utils.rand_name(namestart)
result = networks_client.create_network(name=name, tenant_id=tenant_id)
network = net_resources.DeletableNetwork(
- networks_client=networks_client, **result['network'])
+ networks_client=networks_client, routers_client=routers_client,
+ **result['network'])
self.assertEqual(network.name, name)
self.addCleanup(self.delete_wrapper, network.delete)
return network
@@ -719,7 +716,7 @@
def _list_routers(self, *args, **kwargs):
"""List routers using admin creds """
- routers_list = self.admin_manager.network_client.list_routers(
+ routers_list = self.admin_manager.routers_client.list_routers(
*args, **kwargs)
return routers_list['routers']
@@ -736,7 +733,8 @@
return agents_list['agents']
def _create_subnet(self, network, client=None, subnets_client=None,
- namestart='subnet-smoke', **kwargs):
+ routers_client=None, namestart='subnet-smoke',
+ **kwargs):
"""Create a subnet for the given network
within the cidr block configured for tenant networks.
@@ -745,6 +743,8 @@
client = self.network_client
if not subnets_client:
subnets_client = self.subnets_client
+ if not routers_client:
+ routers_client = self.routers_client
def cidr_in_use(cidr, tenant_id):
"""Check cidr existence
@@ -792,7 +792,7 @@
self.assertIsNotNone(result, 'Unable to allocate tenant network')
subnet = net_resources.DeletableSubnet(
network_client=client, subnets_client=subnets_client,
- **result['subnet'])
+ routers_client=routers_client, **result['subnet'])
self.assertEqual(subnet.cidr, str_cidr)
self.addCleanup(self.delete_wrapper, subnet.delete)
return subnet
@@ -992,7 +992,7 @@
sg_dict['tenant_id'] = tenant_id
result = client.create_security_group(**sg_dict)
secgroup = net_resources.DeletableSecurityGroup(
- client=client,
+ client=client, routers_client=self.routers_client,
**result['security_group']
)
self.assertEqual(secgroup.name, sg_name)
@@ -1128,7 +1128,7 @@
routes traffic to the public network.
"""
if not client:
- client = self.network_client
+ client = self.routers_client
if not tenant_id:
tenant_id = client.tenant_id
router_id = CONF.network.public_router_id
@@ -1147,14 +1147,14 @@
def _create_router(self, client=None, tenant_id=None,
namestart='router-smoke'):
if not client:
- client = self.network_client
+ client = self.routers_client
if not tenant_id:
tenant_id = client.tenant_id
name = data_utils.rand_name(namestart)
result = client.create_router(name=name,
admin_state_up=True,
tenant_id=tenant_id)
- router = net_resources.DeletableRouter(client=client,
+ router = net_resources.DeletableRouter(routers_client=client,
**result['router'])
self.assertEqual(router.name, name)
self.addCleanup(self.delete_wrapper, router.delete)
@@ -1165,8 +1165,8 @@
self.assertEqual(admin_state_up, router.admin_state_up)
def create_networks(self, client=None, networks_client=None,
- subnets_client=None, tenant_id=None,
- dns_nameservers=None):
+ routers_client=None, subnets_client=None,
+ tenant_id=None, dns_nameservers=None):
"""Create a network with a subnet connected to a router.
The baremetal driver is a special case since all nodes are
@@ -1194,10 +1194,12 @@
network = self._create_network(
client=client, networks_client=networks_client,
tenant_id=tenant_id)
- router = self._get_router(client=client, tenant_id=tenant_id)
+ router = self._get_router(client=routers_client,
+ tenant_id=tenant_id)
subnet_kwargs = dict(network=network, client=client,
- subnets_client=subnets_client)
+ subnets_client=subnets_client,
+ routers_client=routers_client)
# use explicit check because empty list is a valid option
if dns_nameservers is not None:
subnet_kwargs['dns_nameservers'] = dns_nameservers
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 4d03ed7..9e2477e 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -680,7 +680,7 @@
# TODO(yfried): refactor this test to be used for other agents (dhcp)
# as well
- list_hosts = (self.admin_manager.network_client.
+ list_hosts = (self.admin_manager.routers_client.
list_l3_agents_hosting_router)
schedule_router = (self.admin_manager.network_agents_client.
create_router_on_l3_agent)
@@ -693,7 +693,7 @@
# NOTE(kevinbenton): we have to use the admin credentials to check
# for the distributed flag because self.router only has a tenant view.
- admin = self.admin_manager.network_client.show_router(self.router.id)
+ admin = self.admin_manager.routers_client.show_router(self.router.id)
if admin['router'].get('distributed', False):
msg = "Rescheduling test does not apply to distributed routers."
raise self.skipException(msg)
@@ -776,7 +776,7 @@
private_key = self._get_server_key(server)
ssh_client = self.get_remote_client(fip.floating_ip_address,
private_key=private_key)
- spoof_nic = ssh_client.get_nic_name(spoof_port["mac_address"])
+ spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"])
dhcp_ports = self._list_ports(device_owner="network:dhcp",
network_id=self.new_net["id"])
new_net_dhcp = dhcp_ports[0]["fixed_ips"][0]["ip_address"]
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index fc33dd9..66c8ade 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -145,7 +145,7 @@
"ports: %s")
% (self.network_v6, ports))
mac6 = ports[0]
- ssh.set_nic_state(ssh.get_nic_name(mac6))
+ ssh.set_nic_state(ssh.get_nic_name_by_mac(mac6))
def _prepare_and_test(self, address6_mode, n_subnets6=1, dualnet=False):
net_list = self.prepare_network(address6_mode=address6_mode,
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index f59354d..058f43b 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -323,6 +323,7 @@
network, subnet, router = self.create_networks(
client=tenant.manager.network_client,
networks_client=tenant.manager.networks_client,
+ routers_client=tenant.manager.routers_client,
subnets_client=tenant.manager.subnets_client)
tenant.set_network(network, subnet, router)
diff --git a/tempest/services/network/json/base.py b/tempest/services/network/json/base.py
deleted file mode 100644
index a6ada04..0000000
--- a/tempest/services/network/json/base.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# 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_serialization import jsonutils as json
-from six.moves.urllib import parse as urllib
-
-from tempest.lib.common import rest_client
-
-
-class BaseNetworkClient(rest_client.RestClient):
-
- """Base class for Tempest REST clients for Neutron.
-
- Child classes use v2 of the Neutron API, since the V1 API has been
- removed from the code base.
- """
-
- version = '2.0'
- uri_prefix = "v2.0"
-
- def list_resources(self, uri, **filters):
- req_uri = self.uri_prefix + uri
- if filters:
- req_uri += '?' + urllib.urlencode(filters, doseq=1)
- resp, body = self.get(req_uri)
- body = json.loads(body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def delete_resource(self, uri):
- req_uri = self.uri_prefix + uri
- resp, body = self.delete(req_uri)
- self.expected_success(204, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def show_resource(self, uri, **fields):
- # fields is a dict which key is 'fields' and value is a
- # list of field's name. An example:
- # {'fields': ['id', 'name']}
- req_uri = self.uri_prefix + uri
- if fields:
- req_uri += '?' + urllib.urlencode(fields, doseq=1)
- resp, body = self.get(req_uri)
- body = json.loads(body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def create_resource(self, uri, post_data):
- req_uri = self.uri_prefix + uri
- req_post_data = json.dumps(post_data)
- resp, body = self.post(req_uri, req_post_data)
- body = json.loads(body)
- self.expected_success(201, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def update_resource(self, uri, post_data):
- req_uri = self.uri_prefix + uri
- req_post_data = json.dumps(post_data)
- resp, body = self.put(req_uri, req_post_data)
- body = json.loads(body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 8b1a388..bcef36b 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -15,7 +15,7 @@
from tempest import exceptions
from tempest.lib.common.utils import misc
from tempest.lib import exceptions as lib_exc
-from tempest.services.network.json import base
+from tempest.lib.services.network import base
class NetworkClient(base.BaseNetworkClient):
@@ -93,110 +93,10 @@
message = '(%s) %s' % (caller, message)
raise exceptions.TimeoutException(message)
- def create_router(self, name, admin_state_up=True, **kwargs):
- post_body = {'router': kwargs}
- post_body['router']['name'] = name
- post_body['router']['admin_state_up'] = admin_state_up
- uri = '/routers'
- return self.create_resource(uri, post_body)
-
- def _update_router(self, router_id, set_enable_snat, **kwargs):
- uri = '/routers/%s' % router_id
- body = self.show_resource(uri)
- update_body = {}
- update_body['name'] = kwargs.get('name', body['router']['name'])
- update_body['admin_state_up'] = kwargs.get(
- 'admin_state_up', body['router']['admin_state_up'])
- cur_gw_info = body['router']['external_gateway_info']
- if cur_gw_info:
- # TODO(kevinbenton): setting the external gateway info is not
- # allowed for a regular tenant. If the ability to update is also
- # merged, a test case for this will need to be added similar to
- # the SNAT case.
- cur_gw_info.pop('external_fixed_ips', None)
- if not set_enable_snat:
- cur_gw_info.pop('enable_snat', None)
- update_body['external_gateway_info'] = kwargs.get(
- 'external_gateway_info', body['router']['external_gateway_info'])
- if 'distributed' in kwargs:
- update_body['distributed'] = kwargs['distributed']
- update_body = dict(router=update_body)
- return self.update_resource(uri, update_body)
-
- def update_router(self, router_id, **kwargs):
- """Update a router leaving enable_snat to its default value."""
- # If external_gateway_info contains enable_snat the request will fail
- # with 404 unless executed with admin client, and therefore we instruct
- # _update_router to not set this attribute
- # NOTE(salv-orlando): The above applies as long as Neutron's default
- # policy is to restrict enable_snat usage to admins only.
- return self._update_router(router_id, set_enable_snat=False, **kwargs)
-
- def show_router(self, router_id, **fields):
- uri = '/routers/%s' % router_id
- return self.show_resource(uri, **fields)
-
- def delete_router(self, router_id):
- uri = '/routers/%s' % router_id
- return self.delete_resource(uri)
-
- def list_routers(self, **filters):
- uri = '/routers'
- return self.list_resources(uri, **filters)
-
- def update_router_with_snat_gw_info(self, router_id, **kwargs):
- """Update a router passing also the enable_snat attribute.
-
- This method must be execute with admin credentials, otherwise the API
- call will return a 404 error.
- """
- return self._update_router(router_id, set_enable_snat=True, **kwargs)
-
- def add_router_interface(self, router_id, **kwargs):
- """Add router interface.
-
- Available params: see http://developer.openstack.org/
- api-ref-networking-v2-ext.html#addRouterInterface
- """
- uri = '/routers/%s/add_router_interface' % router_id
- return self.update_resource(uri, kwargs)
-
- def remove_router_interface(self, router_id, **kwargs):
- """Remove router interface.
-
- Available params: see http://developer.openstack.org/
- api-ref-networking-v2-ext.html#removeRouterInterface
- """
- uri = '/routers/%s/remove_router_interface' % router_id
- return self.update_resource(uri, kwargs)
-
def list_router_interfaces(self, uuid):
uri = '/ports?device_id=%s' % uuid
return self.list_resources(uri)
- def list_l3_agents_hosting_router(self, router_id):
- uri = '/routers/%s/l3-agents' % router_id
- return self.list_resources(uri)
-
def list_dhcp_agent_hosting_network(self, network_id):
uri = '/networks/%s/dhcp-agents' % network_id
return self.list_resources(uri)
-
- def update_extra_routes(self, router_id, **kwargs):
- """Update Extra routes.
-
- Available params: see http://developer.openstack.org/
- api-ref-networking-v2-ext.html#updateExtraRoutes
- """
- uri = '/routers/%s' % router_id
- put_body = {'router': kwargs}
- return self.update_resource(uri, put_body)
-
- def delete_extra_routes(self, router_id):
- uri = '/routers/%s' % router_id
- put_body = {
- 'router': {
- 'routes': None
- }
- }
- return self.update_resource(uri, put_body)
diff --git a/tempest/services/network/json/routers_client.py b/tempest/services/network/json/routers_client.py
new file mode 100644
index 0000000..725dd76
--- /dev/null
+++ b/tempest/services/network/json/routers_client.py
@@ -0,0 +1,119 @@
+# 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.services.network import base
+
+
+class RoutersClient(base.BaseNetworkClient):
+
+ def create_router(self, **kwargs):
+ """Create a router.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#createRouter
+ """
+ post_body = {'router': kwargs}
+ uri = '/routers'
+ return self.create_resource(uri, post_body)
+
+ def _update_router(self, router_id, set_enable_snat, **kwargs):
+ uri = '/routers/%s' % router_id
+ body = self.show_resource(uri)
+ update_body = {}
+ update_body['name'] = kwargs.get('name', body['router']['name'])
+ update_body['admin_state_up'] = kwargs.get(
+ 'admin_state_up', body['router']['admin_state_up'])
+ cur_gw_info = body['router']['external_gateway_info']
+ if cur_gw_info:
+ # TODO(kevinbenton): setting the external gateway info is not
+ # allowed for a regular tenant. If the ability to update is also
+ # merged, a test case for this will need to be added similar to
+ # the SNAT case.
+ cur_gw_info.pop('external_fixed_ips', None)
+ if not set_enable_snat:
+ cur_gw_info.pop('enable_snat', None)
+ update_body['external_gateway_info'] = kwargs.get(
+ 'external_gateway_info', body['router']['external_gateway_info'])
+ if 'distributed' in kwargs:
+ update_body['distributed'] = kwargs['distributed']
+ update_body = dict(router=update_body)
+ return self.update_resource(uri, update_body)
+
+ def update_router(self, router_id, **kwargs):
+ """Update a router leaving enable_snat to its default value."""
+ # If external_gateway_info contains enable_snat the request will fail
+ # with 404 unless executed with admin client, and therefore we instruct
+ # _update_router to not set this attribute
+ # NOTE(salv-orlando): The above applies as long as Neutron's default
+ # policy is to restrict enable_snat usage to admins only.
+ return self._update_router(router_id, set_enable_snat=False, **kwargs)
+
+ def show_router(self, router_id, **fields):
+ uri = '/routers/%s' % router_id
+ return self.show_resource(uri, **fields)
+
+ def delete_router(self, router_id):
+ uri = '/routers/%s' % router_id
+ return self.delete_resource(uri)
+
+ def list_routers(self, **filters):
+ uri = '/routers'
+ return self.list_resources(uri, **filters)
+
+ def update_extra_routes(self, router_id, **kwargs):
+ """Update Extra routes.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#updateExtraRoutes
+ """
+ uri = '/routers/%s' % router_id
+ put_body = {'router': kwargs}
+ return self.update_resource(uri, put_body)
+
+ def delete_extra_routes(self, router_id):
+ uri = '/routers/%s' % router_id
+ put_body = {
+ 'router': {
+ 'routes': None
+ }
+ }
+ return self.update_resource(uri, put_body)
+
+ def update_router_with_snat_gw_info(self, router_id, **kwargs):
+ """Update a router passing also the enable_snat attribute.
+
+ This method must be execute with admin credentials, otherwise the API
+ call will return a 404 error.
+ """
+ return self._update_router(router_id, set_enable_snat=True, **kwargs)
+
+ def add_router_interface(self, router_id, **kwargs):
+ """Add router interface.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#addRouterInterface
+ """
+ uri = '/routers/%s/add_router_interface' % router_id
+ return self.update_resource(uri, kwargs)
+
+ def remove_router_interface(self, router_id, **kwargs):
+ """Remove router interface.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#removeRouterInterface
+ """
+ uri = '/routers/%s/remove_router_interface' % router_id
+ return self.update_resource(uri, kwargs)
+
+ def list_l3_agents_hosting_router(self, router_id):
+ uri = '/routers/%s/l3-agents' % router_id
+ return self.list_resources(uri)
diff --git a/tempest/services/network/json/security_group_rules_client.py b/tempest/services/network/json/security_group_rules_client.py
index b2ba5b2..944eba6 100644
--- a/tempest/services/network/json/security_group_rules_client.py
+++ b/tempest/services/network/json/security_group_rules_client.py
@@ -10,7 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.services.network.json import base
+from tempest.lib.services.network import base
class SecurityGroupRulesClient(base.BaseNetworkClient):
diff --git a/tempest/services/network/resources.py b/tempest/services/network/resources.py
index 0a7da92..5512075 100644
--- a/tempest/services/network/resources.py
+++ b/tempest/services/network/resources.py
@@ -39,6 +39,7 @@
self.client = kwargs.pop('client', None)
self.network_client = kwargs.pop('network_client', None)
self.networks_client = kwargs.pop('networks_client', None)
+ self.routers_client = kwargs.pop('routers_client', None)
self.subnets_client = kwargs.pop('subnets_client', None)
self.ports_client = kwargs.pop('ports_client', None)
super(DeletableResource, self).__init__(*args, **kwargs)
@@ -89,12 +90,12 @@
def add_to_router(self, router_id):
self._router_ids.add(router_id)
- self.network_client.add_router_interface(router_id,
+ self.routers_client.add_router_interface(router_id,
subnet_id=self.id)
def delete(self):
for router_id in self._router_ids.copy():
- self.network_client.remove_router_interface(router_id,
+ self.routers_client.remove_router_interface(router_id,
subnet_id=self.id)
self._router_ids.remove(router_id)
self.subnets_client.delete_subnet(self.id)
@@ -109,14 +110,14 @@
return self.update(external_gateway_info=dict())
def update(self, *args, **kwargs):
- result = self.client.update_router(self.id,
- *args,
- **kwargs)
+ result = self.routers_client.update_router(self.id,
+ *args,
+ **kwargs)
return super(DeletableRouter, self).update(**result['router'])
def delete(self):
self.unset_gateway()
- self.client.delete_router(self.id)
+ self.routers_client.delete_router(self.id)
class DeletableFloatingIp(DeletableResource):
diff --git a/tempest/tests/cmd/test_javelin.py b/tempest/tests/cmd/test_javelin.py
index 3380f84..57cfe97 100644
--- a/tempest/tests/cmd/test_javelin.py
+++ b/tempest/tests/cmd/test_javelin.py
@@ -250,17 +250,17 @@
def test_create_router(self):
- self.fake_client.networks.list_routers.return_value = {'routers': []}
+ self.fake_client.routers.list_routers.return_value = {'routers': []}
self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
return_value=self.fake_client))
javelin.create_routers([self.fake_object])
mocked_function = self.fake_client.networks.create_router
- mocked_function.assert_called_once_with(self.fake_object['name'])
+ mocked_function.assert_called_once_with(name=self.fake_object['name'])
def test_create_router_existing(self):
- self.fake_client.networks.list_routers.return_value = {
+ self.fake_client.routers.list_routers.return_value = {
'routers': [self.fake_object]}
self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
return_value=self.fake_client))
@@ -405,7 +405,7 @@
javelin.destroy_routers([self.fake_object])
- mocked_function = self.fake_client.networks.delete_router
+ mocked_function = self.fake_client.routers.delete_router
mocked_function.assert_called_once_with(
self.fake_object['router_id'])
diff --git a/tempest/tests/cmd/test_tempest_init.py b/tempest/tests/cmd/test_tempest_init.py
index 1048a52..685a0b3 100644
--- a/tempest/tests/cmd/test_tempest_init.py
+++ b/tempest/tests/cmd/test_tempest_init.py
@@ -36,9 +36,8 @@
testr_conf_file = init.TESTR_CONF % (top_level_path, discover_path)
conf_path = conf_dir.join('.testr.conf')
- conf_file = open(conf_path, 'r')
- self.addCleanup(conf_file.close)
- self.assertEqual(conf_file.read(), testr_conf_file)
+ with open(conf_path, 'r') as conf_file:
+ self.assertEqual(conf_file.read(), testr_conf_file)
def test_generate_sample_config(self):
local_dir = self.useFixture(fixtures.TempDir())
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index d625284..be4a6ee 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -31,6 +31,7 @@
from tempest.services.identity.v2.json import users_client as \
json_users_client
from tempest.services.network.json import network_client as json_network_client
+from tempest.services.network.json import routers_client
from tempest.tests import base
from tempest.tests import fake_config
from tempest.tests import fake_http
@@ -154,7 +155,7 @@
def _mock_router_create(self, id, name):
router_fix = self.useFixture(mockpatch.PatchObject(
- json_network_client.NetworkClient,
+ routers_client.RoutersClient,
'create_router',
return_value={'router': {'id': id, 'name': name}}))
return router_fix
@@ -295,7 +296,7 @@
subnet = mock.patch.object(creds.subnets_admin_client,
'delete_subnet')
subnet_mock = subnet.start()
- router = mock.patch.object(creds.network_admin_client,
+ router = mock.patch.object(creds.routers_admin_client,
'delete_router')
router_mock = router.start()
@@ -321,7 +322,7 @@
self._mock_subnet_create(creds, '1234', 'fake_subnet')
self._mock_router_create('1234', 'fake_router')
router_interface_mock = self.patch(
- 'tempest.services.network.json.network_client.NetworkClient.'
+ 'tempest.services.network.json.routers_client.RoutersClient.'
'add_router_interface')
primary_creds = creds.get_primary_creds()
router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -353,7 +354,7 @@
self._mock_subnet_create(creds, '1234', 'fake_subnet')
self._mock_router_create('1234', 'fake_router')
router_interface_mock = self.patch(
- 'tempest.services.network.json.network_client.NetworkClient.'
+ 'tempest.services.network.json.routers_client.RoutersClient.'
'add_router_interface')
creds.get_primary_creds()
router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -386,11 +387,11 @@
subnet = mock.patch.object(creds.subnets_admin_client,
'delete_subnet')
subnet_mock = subnet.start()
- router = mock.patch.object(creds.network_admin_client,
+ router = mock.patch.object(creds.routers_admin_client,
'delete_router')
router_mock = router.start()
remove_router_interface_mock = self.patch(
- 'tempest.services.network.json.network_client.NetworkClient.'
+ 'tempest.services.network.json.routers_client.RoutersClient.'
'remove_router_interface')
return_values = ({'status': 200}, {'ports': []})
port_list_mock = mock.patch.object(creds.ports_admin_client,
@@ -461,7 +462,7 @@
self._mock_subnet_create(creds, '1234', 'fake_alt_subnet')
self._mock_router_create('1234', 'fake_alt_router')
router_interface_mock = self.patch(
- 'tempest.services.network.json.network_client.NetworkClient.'
+ 'tempest.services.network.json.routers_client.RoutersClient.'
'add_router_interface')
alt_creds = creds.get_alt_creds()
router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -485,7 +486,7 @@
self._mock_subnet_create(creds, '1234', 'fake_admin_subnet')
self._mock_router_create('1234', 'fake_admin_router')
router_interface_mock = self.patch(
- 'tempest.services.network.json.network_client.NetworkClient.'
+ 'tempest.services.network.json.routers_client.RoutersClient.'
'add_router_interface')
self._mock_list_roles('123456', 'admin')
admin_creds = creds.get_admin_creds()
@@ -521,7 +522,7 @@
subnet = mock.patch.object(creds.subnets_admin_client,
'delete_subnet')
subnet_mock = subnet.start()
- router = mock.patch.object(creds.network_admin_client,
+ router = mock.patch.object(creds.routers_admin_client,
'delete_router')
router_mock = router.start()
diff --git a/tempest/tests/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py
index 07502d0..493df89 100644
--- a/tempest/tests/lib/common/utils/test_data_utils.py
+++ b/tempest/tests/lib/common/utils/test_data_utils.py
@@ -24,15 +24,15 @@
def test_rand_uuid(self):
actual = data_utils.rand_uuid()
self.assertIsInstance(actual, str)
- self.assertRegexpMatches(actual, "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]"
- "{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
+ self.assertRegex(actual, "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]"
+ "{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
actual2 = data_utils.rand_uuid()
self.assertNotEqual(actual, actual2)
def test_rand_uuid_hex(self):
actual = data_utils.rand_uuid_hex()
self.assertIsInstance(actual, str)
- self.assertRegexpMatches(actual, "^[0-9a-f]{32}$")
+ self.assertRegex(actual, "^[0-9a-f]{32}$")
actual2 = data_utils.rand_uuid_hex()
self.assertNotEqual(actual, actual2)
@@ -52,14 +52,14 @@
def test_rand_name_with_prefix(self):
actual = data_utils.rand_name(prefix='prefix-str')
self.assertIsInstance(actual, str)
- self.assertRegexpMatches(actual, "^prefix-str-")
+ self.assertRegex(actual, "^prefix-str-")
actual2 = data_utils.rand_name(prefix='prefix-str')
self.assertNotEqual(actual, actual2)
def test_rand_password(self):
actual = data_utils.rand_password()
self.assertIsInstance(actual, str)
- self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{15,}")
+ self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{15,}")
actual2 = data_utils.rand_password()
self.assertNotEqual(actual, actual2)
@@ -67,7 +67,7 @@
actual = data_utils.rand_password(8)
self.assertIsInstance(actual, str)
self.assertEqual(len(actual), 8)
- self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{8}")
+ self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{8}")
actual2 = data_utils.rand_password(8)
self.assertNotEqual(actual, actual2)
@@ -75,14 +75,14 @@
actual = data_utils.rand_password(2)
self.assertIsInstance(actual, str)
self.assertEqual(len(actual), 3)
- self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{3}")
+ self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{3}")
actual2 = data_utils.rand_password(2)
self.assertNotEqual(actual, actual2)
def test_rand_url(self):
actual = data_utils.rand_url()
self.assertIsInstance(actual, str)
- self.assertRegexpMatches(actual, "^https://url-[0-9]*\.com$")
+ self.assertRegex(actual, "^https://url-[0-9]*\.com$")
actual2 = data_utils.rand_url()
self.assertNotEqual(actual, actual2)
@@ -96,8 +96,8 @@
def test_rand_mac_address(self):
actual = data_utils.rand_mac_address()
self.assertIsInstance(actual, str)
- self.assertRegexpMatches(actual, "^([0-9a-f][0-9a-f]:){5}"
- "[0-9a-f][0-9a-f]$")
+ self.assertRegex(actual, "^([0-9a-f][0-9a-f]:){5}"
+ "[0-9a-f][0-9a-f]$")
actual2 = data_utils.rand_mac_address()
self.assertNotEqual(actual, actual2)
@@ -117,12 +117,12 @@
def test_random_bytes(self):
actual = data_utils.random_bytes() # default size=1024
self.assertIsInstance(actual, str)
- self.assertRegexpMatches(actual, "^[\x00-\xFF]{1024}")
+ self.assertRegex(actual, "^[\x00-\xFF]{1024}")
actual2 = data_utils.random_bytes()
self.assertNotEqual(actual, actual2)
actual = data_utils.random_bytes(size=2048)
- self.assertRegexpMatches(actual, "^[\x00-\xFF]{2048}")
+ self.assertRegex(actual, "^[\x00-\xFF]{2048}")
def test_get_ipv6_addr_by_EUI64(self):
actual = data_utils.get_ipv6_addr_by_EUI64('2001:db8::',
diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py
index f7bc7e4..6a01490 100644
--- a/tempest/tests/lib/test_auth.py
+++ b/tempest/tests/lib/test_auth.py
@@ -382,6 +382,31 @@
expected = 'http://fake_url/'
self._test_base_url_helper(expected, self.filters)
+ def test_base_url_with_unversioned_endpoint(self):
+ auth_data = {
+ 'serviceCatalog': [
+ {
+ 'type': 'identity',
+ 'endpoints': [
+ {
+ 'region': 'FakeRegion',
+ 'publicURL': 'http://fake_url'
+ }
+ ]
+ }
+ ]
+ }
+
+ filters = {
+ 'service': 'identity',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion',
+ 'api_version': 'v2.0'
+ }
+
+ expected = 'http://fake_url/v2.0'
+ self._test_base_url_helper(expected, filters, ('token', auth_data))
+
def test_token_not_expired(self):
expiry_data = datetime.datetime.utcnow() + datetime.timedelta(days=1)
self._verify_expiry(expiry_data=expiry_data, should_be_expired=False)
@@ -478,3 +503,70 @@
expected = self._get_result_url_from_endpoint(
self._endpoints[0]['endpoints'][2])
self._test_base_url_helper(expected, self.filters)
+
+ # Overwrites v2 test
+ def test_base_url_with_unversioned_endpoint(self):
+ auth_data = {
+ 'catalog': [
+ {
+ 'type': 'identity',
+ 'endpoints': [
+ {
+ 'region': 'FakeRegion',
+ 'url': 'http://fake_url',
+ 'interface': 'public'
+ }
+ ]
+ }
+ ]
+ }
+
+ filters = {
+ 'service': 'identity',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion',
+ 'api_version': 'v3'
+ }
+
+ expected = 'http://fake_url/v3'
+ self._test_base_url_helper(expected, filters, ('token', auth_data))
+
+
+class TestKeystoneV3Credentials(base.TestCase):
+ def testSetAttrUserDomain(self):
+ creds = auth.KeystoneV3Credentials()
+ creds.user_domain_name = 'user_domain'
+ creds.domain_name = 'domain'
+ self.assertEqual('user_domain', creds.user_domain_name)
+ creds = auth.KeystoneV3Credentials()
+ creds.domain_name = 'domain'
+ creds.user_domain_name = 'user_domain'
+ self.assertEqual('user_domain', creds.user_domain_name)
+
+ def testSetAttrProjectDomain(self):
+ creds = auth.KeystoneV3Credentials()
+ creds.project_domain_name = 'project_domain'
+ creds.domain_name = 'domain'
+ self.assertEqual('project_domain', creds.user_domain_name)
+ creds = auth.KeystoneV3Credentials()
+ creds.domain_name = 'domain'
+ creds.project_domain_name = 'project_domain'
+ self.assertEqual('project_domain', creds.project_domain_name)
+
+ def testProjectTenantNoCollision(self):
+ creds = auth.KeystoneV3Credentials(tenant_id='tenant')
+ self.assertEqual('tenant', creds.project_id)
+ creds = auth.KeystoneV3Credentials(project_id='project')
+ self.assertEqual('project', creds.tenant_id)
+ creds = auth.KeystoneV3Credentials(tenant_name='tenant')
+ self.assertEqual('tenant', creds.project_name)
+ creds = auth.KeystoneV3Credentials(project_name='project')
+ self.assertEqual('project', creds.tenant_name)
+
+ def testProjectTenantCollision(self):
+ attrs = {'tenant_id': 'tenant', 'project_id': 'project'}
+ self.assertRaises(
+ exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs)
+ attrs = {'tenant_name': 'tenant', 'project_name': 'project'}
+ self.assertRaises(
+ exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs)
diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py
index 558445d..07b577c 100644
--- a/tempest/tests/lib/test_decorators.py
+++ b/tempest/tests/lib/test_decorators.py
@@ -109,7 +109,7 @@
t = TestFoo('test_foo')
if expected_to_skip:
self.assertRaises(testtools.TestCase.skipException,
- t.test_foo())
+ t.test_foo)
else:
try:
t.test_foo()
diff --git a/tempest/tests/test_microversions.py b/tempest/tests/test_microversions.py
index f19ee49..cef7975 100644
--- a/tempest/tests/test_microversions.py
+++ b/tempest/tests/test_microversions.py
@@ -64,9 +64,9 @@
expected_pass_tests,
expected_skip_tests):
cfg.CONF.set_default('min_microversion',
- cfg_min, group='compute-feature-enabled')
+ cfg_min, group='compute')
cfg.CONF.set_default('max_microversion',
- cfg_max, group='compute-feature-enabled')
+ cfg_max, group='compute')
try:
for test_class in expected_pass_tests:
test_class.skip_checks()
@@ -138,16 +138,16 @@
def test_config_invalid_version(self):
cfg.CONF.set_default('min_microversion',
- '2.5', group='compute-feature-enabled')
+ '2.5', group='compute')
cfg.CONF.set_default('max_microversion',
- '2.1', group='compute-feature-enabled')
+ '2.1', group='compute')
self.assertRaises(exceptions.InvalidAPIVersionRange,
VersionTestNoneTolatest.skip_checks)
def test_config_version_invalid_test_version(self):
cfg.CONF.set_default('min_microversion',
- None, group='compute-feature-enabled')
+ None, group='compute')
cfg.CONF.set_default('max_microversion',
- '2.13', group='compute-feature-enabled')
+ '2.13', group='compute')
self.assertRaises(exceptions.InvalidAPIVersionRange,
InvalidVersionTest.skip_checks)
diff --git a/tools/skip_tracker.py b/tools/skip_tracker.py
index a47e217..b554514 100755
--- a/tools/skip_tracker.py
+++ b/tools/skip_tracker.py
@@ -73,21 +73,23 @@
DEF_RE = re.compile(r'\s*def (\w+)\(')
bug_found = False
results = []
- lines = open(path, 'rb').readlines()
- for x, line in enumerate(lines):
- if not bug_found:
- res = BUG_RE.match(line)
- if res:
- bug_no = int(res.group(1))
- debug("Found bug skip %s on line %d", bug_no, x + 1)
- bug_found = True
- else:
- res = DEF_RE.match(line)
- if res:
- method = res.group(1)
- debug("Found test method %s skips for bug %d", method, bug_no)
- results.append((method, bug_no))
- bug_found = False
+ with open(path, 'rb') as content:
+ lines = content.readlines()
+ for x, line in enumerate(lines):
+ if not bug_found:
+ res = BUG_RE.match(line)
+ if res:
+ bug_no = int(res.group(1))
+ debug("Found bug skip %s on line %d", bug_no, x + 1)
+ bug_found = True
+ else:
+ res = DEF_RE.match(line)
+ if res:
+ method = res.group(1)
+ debug("Found test method %s skips for bug %d",
+ method, bug_no)
+ results.append((method, bug_no))
+ bug_found = False
return results