Simplify whitebox/manager

* Allow the generic resource deletion (thing.delete) to
operate on resources allocated in the setUpClass-es too.

* test_images_whitebox.py is using the python
  client libraries as the scenario tests.

* Remove the not used part of the tempest/manager.py

Change-Id: I980a70d22dc7a3a65a26a8197c7888b125eb3b05
This commit is contained in:
Attila Fazekas 2013-07-02 16:15:01 +02:00
parent 7f9a3125bb
commit d6d8629107
4 changed files with 40 additions and 201 deletions

View File

@ -15,41 +15,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from tempest.common import log as logging
import tempest.config import tempest.config
from tempest import exceptions from tempest import exceptions
# Tempest REST Fuzz testing client libs
from tempest.services.compute.json import extensions_client
from tempest.services.compute.json import flavors_client
from tempest.services.compute.json import floating_ips_client
from tempest.services.compute.json import hypervisor_client
from tempest.services.compute.json import images_client
from tempest.services.compute.json import keypairs_client
from tempest.services.compute.json import limits_client
from tempest.services.compute.json import quotas_client
from tempest.services.compute.json import security_groups_client
from tempest.services.compute.json import servers_client
from tempest.services.compute.json import volumes_extensions_client
from tempest.services.network.json import network_client
from tempest.services.volume.json import snapshots_client
from tempest.services.volume.json import volumes_client
NetworkClient = network_client.NetworkClient
ImagesClient = images_client.ImagesClientJSON
FlavorsClient = flavors_client.FlavorsClientJSON
ServersClient = servers_client.ServersClientJSON
LimitsClient = limits_client.LimitsClientJSON
ExtensionsClient = extensions_client.ExtensionsClientJSON
FloatingIPsClient = floating_ips_client.FloatingIPsClientJSON
SecurityGroupsClient = security_groups_client.SecurityGroupsClientJSON
KeyPairsClient = keypairs_client.KeyPairsClientJSON
VolumesExtensionsClient = volumes_extensions_client.VolumesExtensionsClientJSON
VolumesClient = volumes_client.VolumesClientJSON
SnapshotsClient = snapshots_client.SnapshotsClientJSON
QuotasClient = quotas_client.QuotasClientJSON
HypervisorClient = hypervisor_client.HypervisorClientJSON
LOG = logging.getLogger(__name__)
class Manager(object): class Manager(object):
@ -73,97 +40,3 @@ class Manager(object):
"tenant_name: %(t)s" % "tenant_name: %(t)s" %
{'u': username, 'p': password, 't': tenant_name}) {'u': username, 'p': password, 't': tenant_name})
raise exceptions.InvalidConfiguration(msg) raise exceptions.InvalidConfiguration(msg)
class FuzzClientManager(Manager):
"""
Manager class that indicates the client provided by the manager
is a fuzz-testing client that Tempest contains. These fuzz-testing
clients are used to be able to throw random or invalid data at
an endpoint and check for appropriate error messages returned
from the endpoint.
"""
pass
class ComputeFuzzClientManager(FuzzClientManager):
"""
Manager that uses the Tempest REST client that can send
random or invalid data at the OpenStack Compute API
"""
def __init__(self, username=None, password=None, tenant_name=None):
"""
We allow overriding of the credentials used within the various
client classes managed by the Manager object. Left as None, the
standard username/password/tenant_name is used.
:param username: Override of the username
:param password: Override of the password
:param tenant_name: Override of the tenant name
"""
super(ComputeFuzzClientManager, self).__init__()
# If no creds are provided, we fall back on the defaults
# in the config file for the Compute API.
username = username or self.config.identity.username
password = password or self.config.identity.password
tenant_name = tenant_name or self.config.identity.tenant_name
self._validate_credentials(username, password, tenant_name)
auth_url = self.config.identity.uri
# Ensure /tokens is in the URL for Keystone...
if 'tokens' not in auth_url:
auth_url = auth_url.rstrip('/') + '/tokens'
client_args = (self.config, username, password, auth_url,
tenant_name)
self.servers_client = ServersClient(*client_args)
self.flavors_client = FlavorsClient(*client_args)
self.images_client = ImagesClient(*client_args)
self.limits_client = LimitsClient(*client_args)
self.extensions_client = ExtensionsClient(*client_args)
self.keypairs_client = KeyPairsClient(*client_args)
self.security_groups_client = SecurityGroupsClient(*client_args)
self.floating_ips_client = FloatingIPsClient(*client_args)
self.volumes_extensions_client = VolumesExtensionsClient(*client_args)
self.volumes_client = VolumesClient(*client_args)
self.snapshots_client = SnapshotsClient(*client_args)
self.quotas_client = QuotasClient(*client_args)
self.network_client = NetworkClient(*client_args)
self.hypervisor_client = HypervisorClient(*client_args)
class ComputeFuzzClientAltManager(Manager):
"""
Manager object that uses the alt_XXX credentials for its
managed client objects
"""
def __init__(self):
conf = tempest.config.TempestConfig()
super(ComputeFuzzClientAltManager, self).__init__(
conf.identity.alt_username,
conf.identity.alt_password,
conf.identity.alt_tenant_name)
class ComputeFuzzClientAdminManager(Manager):
"""
Manager object that uses the alt_XXX credentials for its
managed client objects
"""
def __init__(self):
conf = tempest.config.TempestConfig()
super(ComputeFuzzClientAdminManager, self).__init__(
conf.compute_admin.username,
conf.compute_admin.password,
conf.compute_admin.tenant_name)

View File

@ -27,7 +27,6 @@ from tempest.common import log as logging
from tempest.common.utils.data_utils import rand_name from tempest.common.utils.data_utils import rand_name
from tempest import config from tempest import config
from tempest import exceptions from tempest import exceptions
from tempest import manager
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -247,19 +246,22 @@ class TestCase(BaseTestCase):
cls.resource_keys = {} cls.resource_keys = {}
cls.os_resources = [] cls.os_resources = []
def set_resource(self, key, thing): @classmethod
def set_resource(cls, key, thing):
LOG.debug("Adding %r to shared resources of %s" % LOG.debug("Adding %r to shared resources of %s" %
(thing, self.__class__.__name__)) (thing, cls.__name__))
self.resource_keys[key] = thing cls.resource_keys[key] = thing
self.os_resources.append(thing) cls.os_resources.append(thing)
def get_resource(self, key): @classmethod
return self.resource_keys[key] def get_resource(cls, key):
return cls.resource_keys[key]
def remove_resource(self, key): @classmethod
thing = self.resource_keys[key] def remove_resource(cls, key):
self.os_resources.remove(thing) thing = cls.resource_keys[key]
del self.resource_keys[key] cls.os_resources.remove(thing)
del cls.resource_keys[key]
def status_timeout(self, things, thing_id, expected_status): def status_timeout(self, things, thing_id, expected_status):
""" """
@ -289,13 +291,3 @@ class TestCase(BaseTestCase):
conf.compute.build_interval): conf.compute.build_interval):
self.fail("Timed out waiting for thing %s to become %s" self.fail("Timed out waiting for thing %s to become %s"
% (thing_id, expected_status)) % (thing_id, expected_status))
class ComputeFuzzClientTest(TestCase):
"""
Base test case class for OpenStack Compute API (Nova)
that uses the Tempest REST fuzz client libs for calling the API.
"""
manager_class = manager.ComputeFuzzClientManager

View File

@ -21,12 +21,11 @@ import subprocess
import sys import sys
from sqlalchemy import create_engine, MetaData from sqlalchemy import create_engine, MetaData
from tempest.common import log as logging from tempest.common import log as logging
from tempest.common.ssh import Client from tempest.common.ssh import Client
from tempest.common.utils.data_utils import rand_name from tempest.common.utils.data_utils import rand_name
from tempest import exceptions from tempest import exceptions
from tempest import test from tempest.scenario import manager
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -47,7 +46,7 @@ class WhiteboxTest(object):
pass pass
class ComputeWhiteboxTest(test.ComputeFuzzClientTest, WhiteboxTest): class ComputeWhiteboxTest(manager.OfficialClientTest):
""" """
Base smoke test case class for OpenStack Compute API (Nova) Base smoke test case class for OpenStack Compute API (Nova)
@ -64,15 +63,6 @@ class ComputeWhiteboxTest(test.ComputeFuzzClientTest, WhiteboxTest):
cls.nova_dir = cls.config.whitebox.source_dir cls.nova_dir = cls.config.whitebox.source_dir
cls.compute_bin_dir = cls.config.whitebox.bin_dir cls.compute_bin_dir = cls.config.whitebox.bin_dir
cls.compute_config_path = cls.config.whitebox.config_path cls.compute_config_path = cls.config.whitebox.config_path
cls.servers_client = cls.manager.servers_client
cls.images_client = cls.manager.images_client
cls.flavors_client = cls.manager.flavors_client
cls.extensions_client = cls.manager.extensions_client
cls.floating_ips_client = cls.manager.floating_ips_client
cls.keypairs_client = cls.manager.keypairs_client
cls.security_groups_client = cls.manager.security_groups_client
cls.limits_client = cls.manager.limits_client
cls.volumes_client = cls.manager.volumes_client
cls.build_interval = cls.config.compute.build_interval cls.build_interval = cls.config.compute.build_interval
cls.build_timeout = cls.config.compute.build_timeout cls.build_timeout = cls.config.compute.build_timeout
cls.ssh_user = cls.config.compute.ssh_user cls.ssh_user = cls.config.compute.ssh_user
@ -80,38 +70,27 @@ class ComputeWhiteboxTest(test.ComputeFuzzClientTest, WhiteboxTest):
cls.image_ref_alt = cls.config.compute.image_ref_alt cls.image_ref_alt = cls.config.compute.image_ref_alt
cls.flavor_ref = cls.config.compute.flavor_ref cls.flavor_ref = cls.config.compute.flavor_ref
cls.flavor_ref_alt = cls.config.compute.flavor_ref_alt cls.flavor_ref_alt = cls.config.compute.flavor_ref_alt
cls.servers = []
#NOTE(afazekas): Mimics the helper method used in the api tests
@classmethod @classmethod
def tearDownClass(cls): def create_server(cls, **kwargs):
# NOTE(jaypipes): Tests often add things in a particular order flavor_ref = cls.config.compute.flavor_ref
# so we destroy resources in the reverse order in which resources image_ref = cls.config.compute.image_ref
# are added to the test class object name = rand_name(cls.__name__ + "-instance")
if not cls.os_resources: if 'name' in kwargs:
return name = kwargs.pop('name')
thing = cls.os_resources.pop() flavor = kwargs.get('flavor', flavor_ref)
while True: image_id = kwargs.get('image_id', image_ref)
LOG.debug("Deleting %r from shared resources of %s" %
(thing, cls.__name__))
# Resources in novaclient all have a delete() method
# which destroys the resource...
thing.delete()
if not cls.os_resources:
return
thing = cls.os_resources.pop()
@classmethod server = cls.compute_client.servers.create(
def create_server(cls, image_id=None): name, image_id, flavor, **kwargs)
"""Wrapper utility that returns a test server."""
server_name = rand_name(cls.__name__ + "-instance")
flavor = cls.flavor_ref
if not image_id:
image_id = cls.image_ref
resp, server = cls.servers_client.create_server( if 'wait_until' in kwargs:
server_name, image_id, flavor) cls.status_timeout(cls.compute_client.servers, server.id,
cls.servers_client.wait_for_server_status(server['id'], 'ACTIVE') server['id'], kwargs['wait_until'])
cls.servers.append(server)
server = cls.compute_client.servers.get(server.id)
cls.set_resource(name, server)
return server return server
@classmethod @classmethod

View File

@ -15,23 +15,19 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from tempest.api.compute import base
from tempest.common.utils.data_utils import rand_name from tempest.common.utils.data_utils import rand_name
from tempest import exceptions
from tempest.whitebox import manager from tempest.whitebox import manager
#TODO(afazekas): The whitebox tests are using complex testclass/manager from novaclient import exceptions
# hierarchy, without a real need. It is difficult to maintain.
# They could share more code with scenario tests.
class ImagesWhiteboxTest(manager.ComputeWhiteboxTest, base.BaseComputeTest): class ImagesWhiteboxTest(manager.ComputeWhiteboxTest):
_interface = 'json' _interface = 'json'
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(ImagesWhiteboxTest, cls).setUpClass() super(ImagesWhiteboxTest, cls).setUpClass()
cls.client = cls.images_client cls.create_image = cls.compute_client.servers.create_image
cls.connection, cls.meta = cls.get_db_handle_and_meta() cls.connection, cls.meta = cls.get_db_handle_and_meta()
cls.shared_server = cls.create_server() cls.shared_server = cls.create_server()
cls.image_ids = [] cls.image_ids = []
@ -39,7 +35,6 @@ class ImagesWhiteboxTest(manager.ComputeWhiteboxTest, base.BaseComputeTest):
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
"""Delete images and server after a test is executed.""" """Delete images and server after a test is executed."""
cls.servers_client.delete_server(cls.shared_server['id'])
for image_id in cls.image_ids: for image_id in cls.image_ids:
cls.client.delete_image(image_id) cls.client.delete_image(image_id)
cls.image_ids.remove(image_id) cls.image_ids.remove(image_id)
@ -62,18 +57,18 @@ class ImagesWhiteboxTest(manager.ComputeWhiteboxTest, base.BaseComputeTest):
def _test_create_image_409_base(self, vm_state, task_state, deleted=0): def _test_create_image_409_base(self, vm_state, task_state, deleted=0):
"""Base method for create image tests based on vm and task states.""" """Base method for create image tests based on vm and task states."""
try: try:
self.update_state(self.shared_server['id'], vm_state, self.update_state(self.shared_server.id, vm_state,
task_state, deleted) task_state, deleted)
image_name = rand_name('snap-') image_name = rand_name('snap-')
self.assertRaises(exceptions.Duplicate, self.assertRaises(exceptions.Conflict,
self.client.create_image, self.create_image,
self.shared_server['id'], image_name) self.shared_server.id, image_name)
except Exception: except Exception:
self.fail("Should not allow create image when vm_state=%s and " self.fail("Should not allow create image when vm_state=%s and "
"task_state=%s" % (vm_state, task_state)) "task_state=%s" % (vm_state, task_state))
finally: finally:
self.update_state(self.shared_server['id'], 'active', None) self.update_state(self.shared_server.id, 'active', None)
def test_create_image_when_vm_eq_building_task_eq_scheduling(self): def test_create_image_when_vm_eq_building_task_eq_scheduling(self):
# 409 error when instance states are building,scheduling # 409 error when instance states are building,scheduling