Stop implicit validation_resources provisioning

The provisioning of validation resources is unreadable and hard to
use. Tests have to call an helper before super's resource_setup is
invoked and they will find resources in a dictionary in a class
attribute.

Changing to a model where the test.py base class provides helpers
that takes care of common tasks:
- pulling the right parameters from configuration
- scheduling cleanup

There are two helpers available, one to be used when validation
resources are provisioned for a server created at class setup time;
the second one shall be used with servers provisioned durint tests
or test setup.

The new helper returns the provisioned resources to the test.
Other helpers are affected by this change since they cannot pull
validation resource from class anymore safely, and they have
been updated to accept validation resources as input.

Change-Id: I1106e40c6d7483f66d645f3bb560c6d74a612d0f
This commit is contained in:
Andrea Frittoli 2017-08-10 15:38:00 +01:00
parent 3be574898c
commit 9f416dd25a
11 changed files with 372 additions and 172 deletions

View File

@ -17,8 +17,10 @@ import testtools
from tempest.api.compute import base from tempest.api.compute import base
from tempest.common.utils.linux import remote_client from tempest.common.utils.linux import remote_client
from tempest.common import waiters
from tempest import config from tempest import config
from tempest.lib.common.utils import data_utils from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators from tempest.lib import decorators
CONF = config.CONF CONF = config.CONF
@ -35,12 +37,6 @@ class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest):
super(ServersWithSpecificFlavorTestJSON, cls).setup_clients() super(ServersWithSpecificFlavorTestJSON, cls).setup_clients()
cls.client = cls.servers_client cls.client = cls.servers_client
@classmethod
def resource_setup(cls):
cls.set_validation_resources()
super(ServersWithSpecificFlavorTestJSON, cls).resource_setup()
@decorators.idempotent_id('b3c7bcfc-bb5b-4e22-b517-c7f686b802ca') @decorators.idempotent_id('b3c7bcfc-bb5b-4e22-b517-c7f686b802ca')
@testtools.skipUnless(CONF.validation.run_validation, @testtools.skipUnless(CONF.validation.run_validation,
'Instance validation tests are disabled.') 'Instance validation tests are disabled.')
@ -67,20 +63,30 @@ class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest):
admin_pass = self.image_ssh_password admin_pass = self.image_ssh_password
validation_resources = self.get_test_validation_resources(
self.os_primary)
server_no_eph_disk = self.create_test_server( server_no_eph_disk = self.create_test_server(
validatable=True, validatable=True,
validation_resources=validation_resources,
wait_until='ACTIVE', wait_until='ACTIVE',
adminPass=admin_pass, adminPass=admin_pass,
flavor=flavor_no_eph_disk_id) flavor=flavor_no_eph_disk_id)
self.addCleanup(waiters.wait_for_server_termination,
self.servers_client, server_no_eph_disk['id'])
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.servers_client.delete_server,
server_no_eph_disk['id'])
# Get partition number of server without ephemeral disk. # Get partition number of server without ephemeral disk.
server_no_eph_disk = self.client.show_server( server_no_eph_disk = self.client.show_server(
server_no_eph_disk['id'])['server'] server_no_eph_disk['id'])['server']
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(server_no_eph_disk), self.get_server_ip(server_no_eph_disk,
validation_resources),
self.ssh_user, self.ssh_user,
admin_pass, admin_pass,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=server_no_eph_disk, server=server_no_eph_disk,
servers_client=self.client) servers_client=self.client)
disks_num = len(linux_client.get_disks().split('\n')) disks_num = len(linux_client.get_disks().split('\n'))
@ -90,17 +96,25 @@ class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest):
server_with_eph_disk = self.create_test_server( server_with_eph_disk = self.create_test_server(
validatable=True, validatable=True,
validation_resources=validation_resources,
wait_until='ACTIVE', wait_until='ACTIVE',
adminPass=admin_pass, adminPass=admin_pass,
flavor=flavor_with_eph_disk_id) flavor=flavor_with_eph_disk_id)
self.addCleanup(waiters.wait_for_server_termination,
self.servers_client, server_with_eph_disk['id'])
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.servers_client.delete_server,
server_with_eph_disk['id'])
server_with_eph_disk = self.client.show_server( server_with_eph_disk = self.client.show_server(
server_with_eph_disk['id'])['server'] server_with_eph_disk['id'])['server']
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(server_with_eph_disk), self.get_server_ip(server_with_eph_disk,
validation_resources),
self.ssh_user, self.ssh_user,
admin_pass, admin_pass,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=server_with_eph_disk, server=server_with_eph_disk,
servers_client=self.client) servers_client=self.client)
disks_num_eph = len(linux_client.get_disks().split('\n')) disks_num_eph = len(linux_client.get_disks().split('\n'))

View File

@ -190,7 +190,7 @@ class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest,
@classmethod @classmethod
def create_test_server(cls, validatable=False, volume_backed=False, def create_test_server(cls, validatable=False, volume_backed=False,
**kwargs): validation_resources=None, **kwargs):
"""Wrapper utility that returns a test server. """Wrapper utility that returns a test server.
This wrapper utility calls the common create test server and This wrapper utility calls the common create test server and
@ -200,6 +200,10 @@ class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest,
:param validatable: Whether the server will be pingable or sshable. :param validatable: Whether the server will be pingable or sshable.
:param volume_backed: Whether the instance is volume backed or not. :param volume_backed: Whether the instance is volume backed or not.
:param validation_resources: Dictionary of validation resources as
returned by `get_class_validation_resources`.
:param kwargs: Extra arguments are passed down to the
`compute.create_test_server` call.
""" """
if 'name' not in kwargs: if 'name' not in kwargs:
kwargs['name'] = data_utils.rand_name(cls.__name__ + "-server") kwargs['name'] = data_utils.rand_name(cls.__name__ + "-server")
@ -216,7 +220,7 @@ class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest,
body, servers = compute.create_test_server( body, servers = compute.create_test_server(
cls.os_primary, cls.os_primary,
validatable, validatable,
validation_resources=cls.validation_resources, validation_resources=validation_resources,
tenant_network=tenant_network, tenant_network=tenant_network,
volume_backed=volume_backed, volume_backed=volume_backed,
**kwargs) **kwargs)
@ -326,13 +330,33 @@ class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest,
@classmethod @classmethod
def rebuild_server(cls, server_id, validatable=False, **kwargs): def rebuild_server(cls, server_id, validatable=False, **kwargs):
# Destroy an existing server and creates a new one """Destroy an existing class level server and creates a new one
Some test classes use a test server that can be used by multiple
tests. This is done to optimise runtime and test load.
If something goes wrong with the test server, it can be rebuilt
using this helper.
This helper can also be used for the initial provisioning if no
server_id is specified.
:param server_id: UUID of the server to be rebuilt. If None is
specified, a new server is provisioned.
:param validatable: whether to the server needs to be
validatable. When True, validation resources are acquired via
the `get_class_validation_resources` helper.
:param kwargs: extra paramaters are passed through to the
`create_test_server` call.
:return: the UUID of the created server.
"""
if server_id: if server_id:
cls.delete_server(server_id) cls.delete_server(server_id)
cls.password = data_utils.rand_password() cls.password = data_utils.rand_password()
server = cls.create_test_server( server = cls.create_test_server(
validatable, validatable,
validation_resources=cls.get_class_validation_resources(
cls.os_primary),
wait_until='ACTIVE', wait_until='ACTIVE',
adminPass=cls.password, adminPass=cls.password,
**kwargs) **kwargs)
@ -363,14 +387,23 @@ class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest,
cls._delete_volume(cls.volumes_client, volume_id) cls._delete_volume(cls.volumes_client, volume_id)
@classmethod @classmethod
def get_server_ip(cls, server): def get_server_ip(cls, server, validation_resources=None):
"""Get the server fixed or floating IP. """Get the server fixed or floating IP.
Based on the configuration we're in, return a correct ip Based on the configuration we're in, return a correct ip
address for validating that a guest is up. address for validating that a guest is up.
:param server: The server dict as returned by the API
:param validation_resources: The dict of validation resources
provisioned for the server.
""" """
if CONF.validation.connect_method == 'floating': if CONF.validation.connect_method == 'floating':
return cls.validation_resources['floating_ip']['ip'] if validation_resources:
return validation_resources['floating_ip']['ip']
else:
msg = ('When validation.connect_method equals floating, '
'validation_resources cannot be None')
raise exceptions.InvalidParam(invalid_param=msg)
elif CONF.validation.connect_method == 'fixed': elif CONF.validation.connect_method == 'fixed':
addresses = server['addresses'][CONF.validation.network_for_ssh] addresses = server['addresses'][CONF.validation.network_for_ssh]
for address in addresses: for address in addresses:

View File

@ -42,8 +42,9 @@ class ServersTestJSON(base.BaseV2ComputeTest):
@classmethod @classmethod
def resource_setup(cls): def resource_setup(cls):
cls.set_validation_resources()
super(ServersTestJSON, cls).resource_setup() super(ServersTestJSON, cls).resource_setup()
validation_resources = cls.get_class_validation_resources(
cls.os_primary)
cls.meta = {'hello': 'world'} cls.meta = {'hello': 'world'}
cls.accessIPv4 = '1.1.1.1' cls.accessIPv4 = '1.1.1.1'
cls.accessIPv6 = '0000:0000:0000:0000:0000:babe:220.12.22.2' cls.accessIPv6 = '0000:0000:0000:0000:0000:babe:220.12.22.2'
@ -52,6 +53,7 @@ class ServersTestJSON(base.BaseV2ComputeTest):
disk_config = cls.disk_config disk_config = cls.disk_config
server_initial = cls.create_test_server( server_initial = cls.create_test_server(
validatable=True, validatable=True,
validation_resources=validation_resources,
wait_until='ACTIVE', wait_until='ACTIVE',
name=cls.name, name=cls.name,
metadata=cls.meta, metadata=cls.meta,
@ -105,11 +107,13 @@ class ServersTestJSON(base.BaseV2ComputeTest):
# Verify that the number of vcpus reported by the instance matches # Verify that the number of vcpus reported by the instance matches
# the amount stated by the flavor # the amount stated by the flavor
flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
validation_resources = self.get_class_validation_resources(
self.os_primary)
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(self.server), self.get_server_ip(self.server, validation_resources),
self.ssh_user, self.ssh_user,
self.password, self.password,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=self.server, server=self.server,
servers_client=self.client) servers_client=self.client)
output = linux_client.exec_command('grep -c ^processor /proc/cpuinfo') output = linux_client.exec_command('grep -c ^processor /proc/cpuinfo')
@ -120,11 +124,13 @@ class ServersTestJSON(base.BaseV2ComputeTest):
'Instance validation tests are disabled.') 'Instance validation tests are disabled.')
def test_host_name_is_same_as_server_name(self): def test_host_name_is_same_as_server_name(self):
# Verify the instance host name is the same as the server name # Verify the instance host name is the same as the server name
validation_resources = self.get_class_validation_resources(
self.os_primary)
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(self.server), self.get_server_ip(self.server, validation_resources),
self.ssh_user, self.ssh_user,
self.password, self.password,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=self.server, server=self.server,
servers_client=self.client) servers_client=self.client)
hostname = linux_client.exec_command("hostname").rstrip() hostname = linux_client.exec_command("hostname").rstrip()

View File

@ -66,11 +66,6 @@ class DeviceTaggingTest(base.BaseV2ComputeTest):
dhcp=True) dhcp=True)
super(DeviceTaggingTest, cls).setup_credentials() super(DeviceTaggingTest, cls).setup_credentials()
@classmethod
def resource_setup(cls):
cls.set_validation_resources()
super(DeviceTaggingTest, cls).resource_setup()
def verify_device_metadata(self, md_json): def verify_device_metadata(self, md_json):
md_dict = json.loads(md_json) md_dict = json.loads(md_json)
for d in md_dict['devices']: for d in md_dict['devices']:
@ -139,9 +134,12 @@ class DeviceTaggingTest(base.BaseV2ComputeTest):
# Create server # Create server
admin_pass = data_utils.rand_password() admin_pass = data_utils.rand_password()
config_drive_enabled = CONF.compute_feature_enabled.config_drive config_drive_enabled = CONF.compute_feature_enabled.config_drive
validation_resources = self.get_test_validation_resources(
self.os_primary)
server = self.create_test_server( server = self.create_test_server(
validatable=True, validatable=True,
validation_resources=validation_resources,
config_drive=config_drive_enabled, config_drive=config_drive_enabled,
adminPass=admin_pass, adminPass=admin_pass,
name=data_utils.rand_name('device-tagging-server'), name=data_utils.rand_name('device-tagging-server'),
@ -208,10 +206,10 @@ class DeviceTaggingTest(base.BaseV2ComputeTest):
self.addCleanup(self.delete_server, server['id']) self.addCleanup(self.delete_server, server['id'])
self.ssh_client = remote_client.RemoteClient( self.ssh_client = remote_client.RemoteClient(
self.get_server_ip(server), self.get_server_ip(server, validation_resources),
CONF.validation.image_ssh_user, CONF.validation.image_ssh_user,
admin_pass, admin_pass,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=server, server=server,
servers_client=self.servers_client) servers_client=self.servers_client)

View File

@ -44,8 +44,13 @@ class ServerActionsTestJSON(base.BaseV2ComputeTest):
self.server_id, 'ACTIVE') self.server_id, 'ACTIVE')
except lib_exc.NotFound: except lib_exc.NotFound:
# The server was deleted by previous test, create a new one # The server was deleted by previous test, create a new one
# Use class level validation resources to avoid them being
# deleted once a test is over
validation_resources = self.get_class_validation_resources(
self.os_primary)
server = self.create_test_server( server = self.create_test_server(
validatable=True, validatable=True,
validation_resources=validation_resources,
wait_until='ACTIVE') wait_until='ACTIVE')
self.__class__.server_id = server['id'] self.__class__.server_id = server['id']
except Exception: except Exception:
@ -69,8 +74,6 @@ class ServerActionsTestJSON(base.BaseV2ComputeTest):
@classmethod @classmethod
def resource_setup(cls): def resource_setup(cls):
cls.set_validation_resources()
super(ServerActionsTestJSON, cls).resource_setup() super(ServerActionsTestJSON, cls).resource_setup()
cls.server_id = cls.rebuild_server(None, validatable=True) cls.server_id = cls.rebuild_server(None, validatable=True)
@ -80,8 +83,11 @@ class ServerActionsTestJSON(base.BaseV2ComputeTest):
def test_change_server_password(self): def test_change_server_password(self):
# Since this test messes with the password and makes the # Since this test messes with the password and makes the
# server unreachable, it should create its own server # server unreachable, it should create its own server
validation_resources = self.get_test_validation_resources(
self.os_primary)
newserver = self.create_test_server( newserver = self.create_test_server(
validatable=True, validatable=True,
validation_resources=validation_resources,
wait_until='ACTIVE') wait_until='ACTIVE')
# The server's password should be set to the provided password # The server's password should be set to the provided password
new_password = 'Newpass1234' new_password = 'Newpass1234'
@ -92,7 +98,7 @@ class ServerActionsTestJSON(base.BaseV2ComputeTest):
# Verify that the user can authenticate with the new password # Verify that the user can authenticate with the new password
server = self.client.show_server(newserver['id'])['server'] server = self.client.show_server(newserver['id'])['server']
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(server), self.get_server_ip(server, validation_resources),
self.ssh_user, self.ssh_user,
new_password, new_password,
server=server, server=server,
@ -101,13 +107,15 @@ class ServerActionsTestJSON(base.BaseV2ComputeTest):
def _test_reboot_server(self, reboot_type): def _test_reboot_server(self, reboot_type):
if CONF.validation.run_validation: if CONF.validation.run_validation:
validation_resources = self.get_class_validation_resources(
self.os_primary)
# Get the time the server was last rebooted, # Get the time the server was last rebooted,
server = self.client.show_server(self.server_id)['server'] server = self.client.show_server(self.server_id)['server']
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(server), self.get_server_ip(server, validation_resources),
self.ssh_user, self.ssh_user,
self.password, self.password,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=server, server=server,
servers_client=self.client) servers_client=self.client)
boot_time = linux_client.get_boot_time() boot_time = linux_client.get_boot_time()
@ -122,10 +130,10 @@ class ServerActionsTestJSON(base.BaseV2ComputeTest):
if CONF.validation.run_validation: if CONF.validation.run_validation:
# Log in and verify the boot time has changed # Log in and verify the boot time has changed
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(server), self.get_server_ip(server, validation_resources),
self.ssh_user, self.ssh_user,
self.password, self.password,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=server, server=server,
servers_client=self.client) servers_client=self.client)
new_boot_time = linux_client.get_boot_time() new_boot_time = linux_client.get_boot_time()
@ -201,6 +209,8 @@ class ServerActionsTestJSON(base.BaseV2ComputeTest):
self.assertEqual(original_addresses, server['addresses']) self.assertEqual(original_addresses, server['addresses'])
if CONF.validation.run_validation: if CONF.validation.run_validation:
validation_resources = self.get_class_validation_resources(
self.os_primary)
# Authentication is attempted in the following order of priority: # Authentication is attempted in the following order of priority:
# 1.The key passed in, if one was passed in. # 1.The key passed in, if one was passed in.
# 2.Any key we can find through an SSH agent (if allowed). # 2.Any key we can find through an SSH agent (if allowed).
@ -208,10 +218,10 @@ class ServerActionsTestJSON(base.BaseV2ComputeTest):
# ~/.ssh/ (if allowed). # ~/.ssh/ (if allowed).
# 4.Plain username/password auth, if a password was given. # 4.Plain username/password auth, if a password was given.
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(rebuilt_server), self.get_server_ip(rebuilt_server, validation_resources),
self.ssh_user, self.ssh_user,
password, password,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=rebuilt_server, server=rebuilt_server,
servers_client=self.client) servers_client=self.client)
linux_client.validate_authentication() linux_client.validate_authentication()

View File

@ -20,6 +20,7 @@ from tempest.common.utils.linux import remote_client
from tempest.common import waiters from tempest.common import waiters
from tempest import config from tempest import config
from tempest.lib.common.utils import data_utils from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc from tempest.lib import exceptions as lib_exc
@ -33,11 +34,6 @@ class ServerPersonalityTestJSON(base.BaseV2ComputeTest):
cls.prepare_instance_network() cls.prepare_instance_network()
super(ServerPersonalityTestJSON, cls).setup_credentials() super(ServerPersonalityTestJSON, cls).setup_credentials()
@classmethod
def resource_setup(cls):
cls.set_validation_resources()
super(ServerPersonalityTestJSON, cls).resource_setup()
@classmethod @classmethod
def skip_checks(cls): def skip_checks(cls):
super(ServerPersonalityTestJSON, cls).skip_checks() super(ServerPersonalityTestJSON, cls).skip_checks()
@ -57,16 +53,23 @@ class ServerPersonalityTestJSON(base.BaseV2ComputeTest):
personality = [{'path': file_path, personality = [{'path': file_path,
'contents': base64.encode_as_text(file_contents)}] 'contents': base64.encode_as_text(file_contents)}]
password = data_utils.rand_password() password = data_utils.rand_password()
created_server = self.create_test_server(personality=personality, validation_resources = self.get_test_validation_resources(
adminPass=password, self.os_primary)
wait_until='ACTIVE', created_server = self.create_test_server(
validatable=True) personality=personality, adminPass=password, wait_until='ACTIVE',
validatable=True,
validation_resources=validation_resources)
self.addCleanup(waiters.wait_for_server_termination,
self.servers_client, created_server['id'])
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.servers_client.delete_server,
created_server['id'])
server = self.client.show_server(created_server['id'])['server'] server = self.client.show_server(created_server['id'])['server']
if CONF.validation.run_validation: if CONF.validation.run_validation:
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(server), self.get_server_ip(server, validation_resources),
self.ssh_user, password, self.ssh_user, password,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=server, server=server,
servers_client=self.client) servers_client=self.client)
self.assertEqual(file_contents, self.assertEqual(file_contents,
@ -75,8 +78,16 @@ class ServerPersonalityTestJSON(base.BaseV2ComputeTest):
@decorators.idempotent_id('128966d8-71fc-443c-8cab-08e24114ecc9') @decorators.idempotent_id('128966d8-71fc-443c-8cab-08e24114ecc9')
def test_rebuild_server_with_personality(self): def test_rebuild_server_with_personality(self):
server = self.create_test_server(wait_until='ACTIVE', validatable=True) validation_resources = self.get_test_validation_resources(
self.os_primary)
server = self.create_test_server(
wait_until='ACTIVE', validatable=True,
validation_resources=validation_resources)
server_id = server['id'] server_id = server['id']
self.addCleanup(waiters.wait_for_server_termination,
self.servers_client, server_id)
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.servers_client.delete_server, server_id)
file_contents = 'Test server rebuild.' file_contents = 'Test server rebuild.'
personality = [{'path': 'rebuild.txt', personality = [{'path': 'rebuild.txt',
'contents': base64.encode_as_text(file_contents)}] 'contents': base64.encode_as_text(file_contents)}]
@ -126,16 +137,22 @@ class ServerPersonalityTestJSON(base.BaseV2ComputeTest):
'contents': base64.encode_as_text(file_contents + str(i)), 'contents': base64.encode_as_text(file_contents + str(i)),
}) })
password = data_utils.rand_password() password = data_utils.rand_password()
created_server = self.create_test_server(personality=person, validation_resources = self.get_test_validation_resources(
adminPass=password, self.os_primary)
wait_until='ACTIVE', created_server = self.create_test_server(
validatable=True) personality=person, adminPass=password, wait_until='ACTIVE',
validatable=True, validation_resources=validation_resources)
self.addCleanup(waiters.wait_for_server_termination,
self.servers_client, created_server['id'])
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.servers_client.delete_server,
created_server['id'])
server = self.client.show_server(created_server['id'])['server'] server = self.client.show_server(created_server['id'])['server']
if CONF.validation.run_validation: if CONF.validation.run_validation:
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(server), self.get_server_ip(server, validation_resources),
self.ssh_user, password, self.ssh_user, password,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=server, server=server,
servers_client=self.client) servers_client=self.client)
for i in person: for i in person:

View File

@ -40,35 +40,37 @@ class AttachVolumeTestJSON(base.BaseV2ComputeTest):
@classmethod @classmethod
def resource_setup(cls): def resource_setup(cls):
cls.set_validation_resources()
super(AttachVolumeTestJSON, cls).resource_setup() super(AttachVolumeTestJSON, cls).resource_setup()
cls.device = CONF.compute.volume_device_name cls.device = CONF.compute.volume_device_name
def _create_server(self): def _create_server(self):
# Start a server and wait for it to become ready # Start a server and wait for it to become ready
validation_resources = self.get_test_validation_resources(
self.os_primary)
server = self.create_test_server( server = self.create_test_server(
validatable=True, validatable=True,
validation_resources=validation_resources,
wait_until='ACTIVE', wait_until='ACTIVE',
adminPass=self.image_ssh_password) adminPass=self.image_ssh_password)
self.addCleanup(self.delete_server, server['id']) self.addCleanup(self.delete_server, server['id'])
# Record addresses so that we can ssh later # Record addresses so that we can ssh later
server['addresses'] = self.servers_client.list_addresses( server['addresses'] = self.servers_client.list_addresses(
server['id'])['addresses'] server['id'])['addresses']
return server return server, validation_resources
@decorators.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff') @decorators.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff')
def test_attach_detach_volume(self): def test_attach_detach_volume(self):
# Stop and Start a server with an attached volume, ensuring that # Stop and Start a server with an attached volume, ensuring that
# the volume remains attached. # the volume remains attached.
server = self._create_server() server, validation_resources = self._create_server()
# NOTE(andreaf) Create one remote client used throughout the test. # NOTE(andreaf) Create one remote client used throughout the test.
if CONF.validation.run_validation: if CONF.validation.run_validation:
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(server), self.get_server_ip(server, validation_resources),
self.image_ssh_user, self.image_ssh_user,
self.image_ssh_password, self.image_ssh_password,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=server, server=server,
servers_client=self.servers_client) servers_client=self.servers_client)
# NOTE(andreaf) We need to ensure the ssh key has been # NOTE(andreaf) We need to ensure the ssh key has been
@ -111,7 +113,7 @@ class AttachVolumeTestJSON(base.BaseV2ComputeTest):
@decorators.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513') @decorators.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513')
def test_list_get_volume_attachments(self): def test_list_get_volume_attachments(self):
# List volume attachment of the server # List volume attachment of the server
server = self._create_server() server, _ = self._create_server()
volume_1st = self.create_volume() volume_1st = self.create_volume()
attachment_1st = self.attach_volume(server, volume_1st, attachment_1st = self.attach_volume(server, volume_1st,
device=('/dev/%s' % self.device)) device=('/dev/%s' % self.device))
@ -163,15 +165,15 @@ class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
if not CONF.compute_feature_enabled.shelve: if not CONF.compute_feature_enabled.shelve:
raise cls.skipException('Shelve is not available.') raise cls.skipException('Shelve is not available.')
def _count_volumes(self, server): def _count_volumes(self, server, validation_resources):
# Count number of volumes on an instance # Count number of volumes on an instance
volumes = 0 volumes = 0
if CONF.validation.run_validation: if CONF.validation.run_validation:
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(server), self.get_server_ip(server, validation_resources),
self.image_ssh_user, self.image_ssh_user,
self.image_ssh_password, self.image_ssh_password,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=server, server=server,
servers_client=self.servers_client) servers_client=self.servers_client)
@ -179,7 +181,7 @@ class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
volumes = int(linux_client.exec_command(command).strip()) volumes = int(linux_client.exec_command(command).strip())
return volumes return volumes
def _shelve_server(self, server): def _shelve_server(self, server, validation_resources):
# NOTE(andreaf) If we are going to shelve a server, we should # NOTE(andreaf) If we are going to shelve a server, we should
# check first whether the server is ssh-able. Otherwise we # check first whether the server is ssh-able. Otherwise we
# won't be able to distinguish failures introduced by shelve # won't be able to distinguish failures introduced by shelve
@ -188,10 +190,10 @@ class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
# avoid breaking the VM # avoid breaking the VM
if CONF.validation.run_validation: if CONF.validation.run_validation:
linux_client = remote_client.RemoteClient( linux_client = remote_client.RemoteClient(
self.get_server_ip(server), self.get_server_ip(server, validation_resources),
self.image_ssh_user, self.image_ssh_user,
self.image_ssh_password, self.image_ssh_password,
self.validation_resources['keypair']['private_key'], validation_resources['keypair']['private_key'],
server=server, server=server,
servers_client=self.servers_client) servers_client=self.servers_client)
linux_client.validate_authentication() linux_client.validate_authentication()
@ -199,30 +201,34 @@ class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
# If validation went ok, or it was skipped, shelve the server # If validation went ok, or it was skipped, shelve the server
compute.shelve_server(self.servers_client, server['id']) compute.shelve_server(self.servers_client, server['id'])
def _unshelve_server_and_check_volumes(self, server, number_of_volumes): def _unshelve_server_and_check_volumes(self, server,
validation_resources,
number_of_volumes):
# Unshelve the instance and check that there are expected volumes # Unshelve the instance and check that there are expected volumes
self.servers_client.unshelve_server(server['id']) self.servers_client.unshelve_server(server['id'])
waiters.wait_for_server_status(self.servers_client, waiters.wait_for_server_status(self.servers_client,
server['id'], server['id'],
'ACTIVE') 'ACTIVE')
if CONF.validation.run_validation: if CONF.validation.run_validation:
counted_volumes = self._count_volumes(server) counted_volumes = self._count_volumes(
server, validation_resources)
self.assertEqual(number_of_volumes, counted_volumes) self.assertEqual(number_of_volumes, counted_volumes)
@decorators.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee') @decorators.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee')
def test_attach_volume_shelved_or_offload_server(self): def test_attach_volume_shelved_or_offload_server(self):
# Create server, count number of volumes on it, shelve # Create server, count number of volumes on it, shelve
# server and attach pre-created volume to shelved server # server and attach pre-created volume to shelved server
server = self._create_server() server, validation_resources = self._create_server()
volume = self.create_volume() volume = self.create_volume()
num_vol = self._count_volumes(server) num_vol = self._count_volumes(server, validation_resources)
self._shelve_server(server) self._shelve_server(server, validation_resources)
attachment = self.attach_volume(server, volume, attachment = self.attach_volume(server, volume,
device=('/dev/%s' % self.device), device=('/dev/%s' % self.device),
check_reserved=True) check_reserved=True)
# Unshelve the instance and check that attached volume exists # Unshelve the instance and check that attached volume exists
self._unshelve_server_and_check_volumes(server, num_vol + 1) self._unshelve_server_and_check_volumes(
server, validation_resources, num_vol + 1)
# Get volume attachment of the server # Get volume attachment of the server
volume_attachment = self.servers_client.show_volume_attachment( volume_attachment = self.servers_client.show_volume_attachment(
@ -238,10 +244,10 @@ class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
def test_detach_volume_shelved_or_offload_server(self): def test_detach_volume_shelved_or_offload_server(self):
# Count number of volumes on instance, shelve # Count number of volumes on instance, shelve
# server and attach pre-created volume to shelved server # server and attach pre-created volume to shelved server
server = self._create_server() server, validation_resources = self._create_server()
volume = self.create_volume() volume = self.create_volume()
num_vol = self._count_volumes(server) num_vol = self._count_volumes(server, validation_resources)
self._shelve_server(server) self._shelve_server(server, validation_resources)
# Attach and then detach the volume # Attach and then detach the volume
self.attach_volume(server, volume, device=('/dev/%s' % self.device), self.attach_volume(server, volume, device=('/dev/%s' % self.device),
@ -252,4 +258,5 @@ class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
# Unshelve the instance and check that we have the expected number of # Unshelve the instance and check that we have the expected number of
# volume(s) # volume(s)
self._unshelve_server_and_check_volumes(server, num_vol) self._unshelve_server_and_check_volumes(
server, validation_resources, num_vol)

View File

@ -128,6 +128,8 @@ def create_test_server(clients, validatable=False, validation_resources=None,
"this stage.") "this stage.")
raise ValueError(msg) raise ValueError(msg)
LOG.debug("Provisioning test server with validation resources %s",
validation_resources)
if 'security_groups' in kwargs: if 'security_groups' in kwargs:
kwargs['security_groups'].append( kwargs['security_groups'].append(
{'name': validation_resources['security_group']['name']}) {'name': validation_resources['security_group']['name']})

View File

@ -181,6 +181,9 @@ def create_validation_resources(clients, keypair=False, floating_ip=False,
floating_ip = resources['floating_ip']['ip'] floating_ip = resources['floating_ip']['ip']
""" """
# Create and Return the validation resources required to validate a VM # Create and Return the validation resources required to validate a VM
msg = ('Requested validation resources keypair %s, floating IP %s, '
'security group %s')
LOG.debug(msg, keypair, floating_ip, security_group)
validation_data = {} validation_data = {}
try: try:
if keypair: if keypair:
@ -429,6 +432,9 @@ class ValidationResourcesFixture(fixtures.Fixture):
self._validation_resources = None self._validation_resources = None
def _setUp(self): def _setUp(self):
msg = ('Requested setup of ValidationResources keypair %s, floating '
'IP %s, security group %s')
LOG.debug(msg, self._keypair, self._floating_ip, self._security_group)
self._validation_resources = create_validation_resources( self._validation_resources = create_validation_resources(
self._clients, keypair=self._keypair, self._clients, keypair=self._keypair,
floating_ip=self._floating_ip, floating_ip=self._floating_ip,
@ -441,9 +447,9 @@ class ValidationResourcesFixture(fixtures.Fixture):
# cleanup here, so we don't need a try-finally around provisioning # cleanup here, so we don't need a try-finally around provisioning
vr = self._validation_resources vr = self._validation_resources
self.addCleanup(clear_validation_resources, self._clients, self.addCleanup(clear_validation_resources, self._clients,
keypair=vr['keypair'], keypair=vr.get('keypair', None),
floating_ip=vr['floating_ip'], floating_ip=vr.get('floating_ip', None),
security_group=vr['security_group'], security_group=vr.get('security_group', None),
use_neutron=self._use_neutron) use_neutron=self._use_neutron)
@property @property

View File

@ -26,7 +26,7 @@ import testtools
from tempest import clients from tempest import clients
from tempest.common import credentials_factory as credentials from tempest.common import credentials_factory as credentials
from tempest.common import utils from tempest.common import utils
import tempest.common.validation_resources as vresources import tempest.common.validation_resources as vr
from tempest import config from tempest import config
from tempest.lib.common import cred_client from tempest.lib.common import cred_client
from tempest.lib.common import fixed_network from tempest.lib.common import fixed_network
@ -105,13 +105,14 @@ class BaseTestCase(testtools.testcase.WithAttributes,
# a list of roles - the first element of the list being a label, and the # a list of roles - the first element of the list being a label, and the
# rest the actual roles # rest the actual roles
credentials = [] credentials = []
# Resources required to validate a server using ssh
validation_resources = {}
network_resources = {} network_resources = {}
# Stack of resource cleanups # Stack of resource cleanups
_class_cleanups = [] _class_cleanups = []
# Resources required to validate a server using ssh
_validation_resources = {}
# NOTE(sdague): log_format is defined inline here instead of using the oslo # NOTE(sdague): log_format is defined inline here instead of using the oslo
# default because going through the config path recouples config to the # default because going through the config path recouples config to the
# stress tests too early, and depending on testr order will fail unit tests # stress tests too early, and depending on testr order will fail unit tests
@ -379,29 +380,13 @@ class BaseTestCase(testtools.testcase.WithAttributes,
servers.delete_server, servers.delete_server,
cls.shared_server2['id']) cls.shared_server2['id'])
""" """
if (CONF.validation.ip_version_for_ssh not in (4, 6) and pass
CONF.service_available.neutron):
msg = "Invalid IP version %s in ip_version_for_ssh. Use 4 or 6"
raise lib_exc.InvalidConfiguration(
msg % CONF.validation.ip_version_for_ssh)
if hasattr(cls, "os_primary"):
vr = cls.validation_resources
cls.validation_resources = vresources.create_validation_resources(
cls.os_primary,
use_neutron=CONF.service_available.neutron,
ethertype='IPv' + str(CONF.validation.ip_version_for_ssh),
floating_network_id=CONF.network.public_network_id,
floating_network_name=CONF.network.floating_network_name,
**vr)
else:
LOG.warning("Client manager not found, validation resources not"
" created")
@classmethod @classmethod
def resource_cleanup(cls): def resource_cleanup(cls):
"""Class level resource cleanup for test cases. """Class level resource cleanup for test cases.
Resource cleanup processes the stack or cleanups produced by Resource cleanup processes the stack of cleanups produced by
`addClassResourceCleanup` and then cleans up validation resources `addClassResourceCleanup` and then cleans up validation resources
if any were provisioned. if any were provisioned.
@ -440,16 +425,6 @@ class BaseTestCase(testtools.testcase.WithAttributes,
fn(*args, **kwargs) fn(*args, **kwargs)
except Exception: except Exception:
cleanup_errors.append(sys.exc_info()) cleanup_errors.append(sys.exc_info())
if cls.validation_resources:
if hasattr(cls, "os_primary"):
vr = cls.validation_resources
vresources.clear_validation_resources(
cls.os_primary,
use_neutron=CONF.service_available.neutron, **vr)
cls.validation_resources = {}
else:
LOG.warning("Client manager not found, validation resources "
"not deleted")
if cleanup_errors: if cleanup_errors:
raise testtools.MultipleExceptions(*cleanup_errors) raise testtools.MultipleExceptions(*cleanup_errors)
@ -610,45 +585,83 @@ class BaseTestCase(testtools.testcase.WithAttributes,
if hasattr(cls, '_creds_provider'): if hasattr(cls, '_creds_provider'):
cls._creds_provider.clear_creds() cls._creds_provider.clear_creds()
@staticmethod
def _validation_resources_params_from_conf():
return dict(
keypair=(CONF.validation.auth_method.lower() == "keypair"),
floating_ip=(CONF.validation.connect_method.lower() == "floating"),
security_group=CONF.validation.security_group,
security_group_rules=CONF.validation.security_group_rules,
use_neutron=CONF.service_available.neutron,
ethertype='IPv' + str(CONF.validation.ip_version_for_ssh),
floating_network_id=CONF.network.public_network_id,
floating_network_name=CONF.network.floating_network_name)
@classmethod @classmethod
def set_validation_resources(cls, keypair=None, floating_ip=None, def get_class_validation_resources(cls, os_clients):
security_group=None, """Provision validation resources according to configuration
security_group_rules=None):
"""Specify which ssh server validation resources should be created.
Each of the argument must be set to either None, True or False, with This is a wrapper around `create_validation_resources` from
None - use default from config (security groups and security group `tempest.common.validation_resources` that passes parameters from
rules get created when set to None) Tempest configuration. Only one instance of class level
False - Do not create the validation resource validation resources is managed by the helper, so If resources
True - create the validation resource were already provisioned before, existing ones will be returned.
@param keypair Resources are returned as a dictionary. They are also scheduled for
@param security_group automatic cleanup during class teardown using
@param security_group_rules `addClassResourcesCleanup`.
@param floating_ip
If `CONF.validation.run_validation` is False no resource will be
provisioned at all.
@param os_clients: Clients to be used to provision the resources.
""" """
if not CONF.validation.run_validation: if not CONF.validation.run_validation:
return return
if keypair is None: if os_clients in cls._validation_resources:
keypair = (CONF.validation.auth_method.lower() == "keypair") return cls._validation_resources[os_clients]
if floating_ip is None: if (CONF.validation.ip_version_for_ssh not in (4, 6) and
floating_ip = (CONF.validation.connect_method.lower() == CONF.service_available.neutron):
"floating") msg = "Invalid IP version %s in ip_version_for_ssh. Use 4 or 6"
raise lib_exc.InvalidConfiguration(
msg % CONF.validation.ip_version_for_ssh)
if security_group is None: resources = vr.create_validation_resources(
security_group = CONF.validation.security_group os_clients,
**cls._validation_resources_params_from_conf())
if security_group_rules is None: cls.addClassResourceCleanup(
security_group_rules = CONF.validation.security_group_rules vr.clear_validation_resources, os_clients,
use_neutron=CONF.service_available.neutron,
**resources)
cls._validation_resources[os_clients] = resources
return resources
if not cls.validation_resources: def get_test_validation_resources(self, os_clients):
cls.validation_resources = { """Returns a dict of validation resources according to configuration
'keypair': keypair,
'security_group': security_group, Initialise a validation resources fixture based on configuration.
'security_group_rules': security_group_rules, Start the fixture and returns the validation resources.
'floating_ip': floating_ip}
If `CONF.validation.run_validation` is False no resource will be
provisioned at all.
@param os_clients: Clients to be used to provision the resources.
"""
params = {}
# Test will try to use the fixture, so for this to be useful
# we must return a fixture. If validation is disabled though
# we don't need to provision anything, which is the default
# behavior for the fixture.
if CONF.validation.run_validation:
params = self._validation_resources_params_from_conf()
validation = self.useFixture(
vr.ValidationResourcesFixture(os_clients, **params))
return validation.resources
@classmethod @classmethod
def set_network_resources(cls, network=False, router=False, subnet=False, def set_network_resources(cls, network=False, router=False, subnet=False,

View File

@ -19,10 +19,15 @@ import mock
from oslo_config import cfg from oslo_config import cfg
import testtools import testtools
from tempest import clients
from tempest.common import validation_resources as vr
from tempest import config from tempest import config
from tempest.lib import exceptions as lib_exc
from tempest import test from tempest import test
from tempest.tests import base from tempest.tests import base
from tempest.tests import fake_config from tempest.tests import fake_config
from tempest.tests.lib import fake_credentials
from tempest.tests.lib.services import registry_fixture
if sys.version_info >= (2, 7): if sys.version_info >= (2, 7):
@ -41,6 +46,121 @@ class LoggingTestResult(testtools.TestResult):
self.log.append((test, err, details)) self.log.append((test, err, details))
class TestValidationResources(base.TestCase):
validation_resources_module = 'tempest.common.validation_resources'
def setUp(self):
super(TestValidationResources, self).setUp()
self.useFixture(fake_config.ConfigFixture())
self.useFixture(registry_fixture.RegistryFixture())
self.patchobject(config, 'TempestConfigPrivate',
fake_config.FakePrivate)
class TestTestClass(test.BaseTestCase):
pass
self.test_test_class = TestTestClass
def test_validation_resources_no_validation(self):
cfg.CONF.set_default('run_validation', False, 'validation')
creds = fake_credentials.FakeKeystoneV3Credentials()
osclients = clients.Manager(creds)
vr = self.test_test_class.get_class_validation_resources(osclients)
self.assertIsNone(vr)
def test_validation_resources_exists(self):
cfg.CONF.set_default('run_validation', True, 'validation')
creds = fake_credentials.FakeKeystoneV3Credentials()
osclients = clients.Manager(creds)
expected_vr = 'expected_validation_resources'
self.test_test_class._validation_resources[osclients] = expected_vr
obtained_vr = self.test_test_class.get_class_validation_resources(
osclients)
self.assertEqual(expected_vr, obtained_vr)
@mock.patch(validation_resources_module + '.create_validation_resources',
autospec=True)
def test_validation_resources_new(self, mock_create_vr):
cfg.CONF.set_default('run_validation', True, 'validation')
cfg.CONF.set_default('neutron', True, 'service_available')
creds = fake_credentials.FakeKeystoneV3Credentials()
osclients = clients.Manager(creds)
expected_vr = {'expected_validation_resources': None}
mock_create_vr.return_value = expected_vr
with mock.patch.object(
self.test_test_class,
'addClassResourceCleanup') as mock_add_class_cleanup:
obtained_vr = self.test_test_class.get_class_validation_resources(
osclients)
self.assertEqual(1, mock_add_class_cleanup.call_count)
self.assertEqual(mock.call(vr.clear_validation_resources,
osclients,
use_neutron=True,
**expected_vr),
mock_add_class_cleanup.call_args)
self.assertEqual(mock_create_vr.call_count, 1)
self.assertIn(osclients, mock_create_vr.call_args_list[0][0])
self.assertEqual(expected_vr, obtained_vr)
self.assertIn(osclients, self.test_test_class._validation_resources)
self.assertEqual(expected_vr,
self.test_test_class._validation_resources[osclients])
def test_validation_resources_invalid_config(self):
invalid_version = 999
cfg.CONF.set_default('run_validation', True, 'validation')
cfg.CONF.set_default('ip_version_for_ssh', invalid_version,
'validation')
cfg.CONF.set_default('neutron', True, 'service_available')
creds = fake_credentials.FakeKeystoneV3Credentials()
osclients = clients.Manager(creds)
with testtools.ExpectedException(
lib_exc.InvalidConfiguration,
value_re='^.*\n.*' + str(invalid_version)):
self.test_test_class.get_class_validation_resources(osclients)
@mock.patch(validation_resources_module + '.create_validation_resources',
autospec=True)
def test_validation_resources_invalid_config_nova_net(self,
mock_create_vr):
invalid_version = 999
cfg.CONF.set_default('run_validation', True, 'validation')
cfg.CONF.set_default('ip_version_for_ssh', invalid_version,
'validation')
cfg.CONF.set_default('neutron', False, 'service_available')
creds = fake_credentials.FakeKeystoneV3Credentials()
osclients = clients.Manager(creds)
expected_vr = {'expected_validation_resources': None}
mock_create_vr.return_value = expected_vr
obtained_vr = self.test_test_class.get_class_validation_resources(
osclients)
self.assertEqual(mock_create_vr.call_count, 1)
self.assertIn(osclients, mock_create_vr.call_args_list[0][0])
self.assertEqual(expected_vr, obtained_vr)
self.assertIn(osclients, self.test_test_class._validation_resources)
self.assertEqual(expected_vr,
self.test_test_class._validation_resources[osclients])
@mock.patch(validation_resources_module + '.create_validation_resources',
autospec=True)
@mock.patch(validation_resources_module + '.clear_validation_resources',
autospec=True)
def test_validation_resources_fixture(self, mock_clean_vr, mock_create_vr):
class TestWithRun(self.test_test_class):
def runTest(self):
pass
cfg.CONF.set_default('run_validation', True, 'validation')
test_case = TestWithRun()
creds = fake_credentials.FakeKeystoneV3Credentials()
osclients = clients.Manager(creds)
test_case.get_test_validation_resources(osclients)
self.assertEqual(1, mock_create_vr.call_count)
self.assertEqual(0, mock_clean_vr.call_count)
class TestTempestBaseTestClass(base.TestCase): class TestTempestBaseTestClass(base.TestCase):
def setUp(self): def setUp(self):
@ -56,26 +176,16 @@ class TestTempestBaseTestClass(base.TestCase):
self.parent_test = ParentTest self.parent_test = ParentTest
@mock.patch( def test_resource_cleanup(self):
'tempest.common.validation_resources.clear_validation_resources',
autospec=True)
def test_resource_cleanup(self, mock_vr):
cfg.CONF.set_default('neutron', False, 'service_available') cfg.CONF.set_default('neutron', False, 'service_available')
exp_args = (1, 2,) exp_args = (1, 2,)
exp_kwargs = {'a': 1, 'b': 2} exp_kwargs = {'a': 1, 'b': 2}
exp_vr = {'keypair': 'kp1', 'floating_ip': 'fip2'}
mock1 = mock.Mock() mock1 = mock.Mock()
mock2 = mock.Mock() mock2 = mock.Mock()
exp_functions = [mock1, mock2] exp_functions = [mock1, mock2]
class TestWithCleanups(self.parent_test): class TestWithCleanups(self.parent_test):
# set fake validation resources
validation_resources = exp_vr
# set fake clients
os_primary = 'os_primary'
@classmethod @classmethod
def resource_setup(cls): def resource_setup(cls):
for fn in exp_functions: for fn in exp_functions:
@ -92,34 +202,22 @@ class TestTempestBaseTestClass(base.TestCase):
# All stacked resource cleanups invoked # All stacked resource cleanups invoked
mock1.assert_called_once_with(*exp_args, **exp_kwargs) mock1.assert_called_once_with(*exp_args, **exp_kwargs)
mock2.assert_called_once_with(*exp_args, **exp_kwargs) mock2.assert_called_once_with(*exp_args, **exp_kwargs)
self.assertEqual(1, mock_vr.call_count)
# Cleanup stack is empty # Cleanup stack is empty
self.assertEqual(0, len(test_cleanups._class_cleanups)) self.assertEqual(0, len(test_cleanups._class_cleanups))
# Assert vrs are cleaned up
self.assertIn(mock.call(TestWithCleanups.os_primary, use_neutron=False,
**exp_vr), mock_vr.call_args_list)
@mock.patch( def test_resource_cleanup_failures(self):
'tempest.common.validation_resources.clear_validation_resources',
autospec=True)
def test_resource_cleanup_failures(self, mock_vr):
cfg.CONF.set_default('neutron', False, 'service_available') cfg.CONF.set_default('neutron', False, 'service_available')
exp_args = (1, 2,) exp_args = (1, 2,)
exp_kwargs = {'a': 1, 'b': 2} exp_kwargs = {'a': 1, 'b': 2}
exp_vr = {'keypair': 'kp1', 'floating_ip': 'fip2'}
mock1 = mock.Mock() mock1 = mock.Mock()
mock1.side_effect = Exception('mock1 resource cleanup failure') mock1.side_effect = Exception('mock1 resource cleanup failure')
mock2 = mock.Mock() mock2 = mock.Mock()
exp_functions = [mock1, mock2] mock3 = mock.Mock()
mock3.side_effect = Exception('mock3 resource cleanup failure')
exp_functions = [mock1, mock2, mock3]
class TestWithFailingCleanups(self.parent_test): class TestWithFailingCleanups(self.parent_test):
# set fake validation resources
validation_resources = exp_vr
# set fake clients
os_primary = 'os_primary'
@classmethod @classmethod
def resource_setup(cls): def resource_setup(cls):
for fn in exp_functions: for fn in exp_functions:
@ -137,19 +235,15 @@ class TestTempestBaseTestClass(base.TestCase):
# Type, Exception, traceback [1] -> MultipleException # Type, Exception, traceback [1] -> MultipleException
found_exc = log[0][1][1] found_exc = log[0][1][1]
self.assertTrue(isinstance(found_exc, testtools.MultipleExceptions)) self.assertTrue(isinstance(found_exc, testtools.MultipleExceptions))
self.assertEqual(1, len(found_exc.args)) self.assertEqual(2, len(found_exc.args))
# Each arg is exc_info - match messages and order # Each arg is exc_info - match messages and order
self.assertIn('mock1 resource', str(found_exc.args[0][1])) self.assertIn('mock3 resource', str(found_exc.args[0][1]))
self.assertIn('mock1 resource', str(found_exc.args[1][1]))
# All stacked resource cleanups invoked # All stacked resource cleanups invoked
mock1.assert_called_once_with(*exp_args, **exp_kwargs) mock1.assert_called_once_with(*exp_args, **exp_kwargs)
mock2.assert_called_once_with(*exp_args, **exp_kwargs) mock2.assert_called_once_with(*exp_args, **exp_kwargs)
self.assertEqual(1, mock_vr.call_count)
# Cleanup stack is empty # Cleanup stack is empty
self.assertEqual(0, len(test_cleanups._class_cleanups)) self.assertEqual(0, len(test_cleanups._class_cleanups))
# Assert fake vr are cleaned up
self.assertIn(mock.call(TestWithFailingCleanups.os_primary,
use_neutron=False, **exp_vr),
mock_vr.call_args_list)
def test_super_resource_cleanup_not_invoked(self): def test_super_resource_cleanup_not_invoked(self):