Merge "Adds to verify_cinder_api_versions api_v3 check"
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 150e8af..3754637 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -49,6 +49,9 @@
name=snapshot_name,
wait_until='SAVING')
self.client.delete_image(image['id'])
+ msg = ('The image with ID {image_id} failed to be deleted'
+ .format(image_id=image['id']))
+ self.assertTrue(self.client.is_resource_deleted(image['id']), msg)
@test.idempotent_id('aaacd1d0-55a2-4ce8-818a-b5439df8adc9')
def test_create_image_from_stopped_server(self):
diff --git a/tempest/api/volume/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
index 1fdcb49..c501ffc 100644
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ b/tempest/api/volume/v2/test_volumes_list.py
@@ -42,22 +42,13 @@
super(VolumesV2ListTestJSON, cls).resource_setup()
# Create 3 test volumes
- cls.volume_list = []
cls.volume_id_list = []
cls.metadata = {'Type': 'work'}
for i in range(3):
volume = cls.create_volume(metadata=cls.metadata)
volume = cls.client.show_volume(volume['id'])['volume']
- cls.volume_list.append(volume)
cls.volume_id_list.append(volume['id'])
- @classmethod
- def resource_cleanup(cls):
- # Delete the created volumes
- for volid in cls.volume_id_list:
- cls.delete_volume(cls.client, volid)
- super(VolumesV2ListTestJSON, cls).resource_cleanup()
-
@test.idempotent_id('2a7064eb-b9c3-429b-b888-33928fc5edd3')
def test_volume_list_details_with_multiple_params(self):
# List volumes detail using combined condition
diff --git a/tempest/clients.py b/tempest/clients.py
index 406f9d5..e14f6f8 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -97,19 +97,16 @@
This uses `config.service_client_config` for all services to collect
most configuration items needed to init the clients.
"""
- # NOTE(andreaf) Configuration items will be passed in future patches
- # into ClientFactory objects, but for now we update all the
- # _set_*_client methods to consume them so we can verify that the
- # configuration collected is correct
+ # NOTE(andreaf) Once all service clients in Tempest are migrated
+ # to tempest.lib, their configuration will be picked up from the
+ # registry, and this method will become redundant.
configuration = {}
- # Setup the parameters for all Tempest services.
+ # Setup the parameters for all Tempest services which are not in lib.
# NOTE(andreaf) Since client.py is an internal module of Tempest,
# it doesn't have to consider plugin configuration.
- all_tempest_modules = (set(clients.tempest_modules()) |
- clients._tempest_internal_modules())
- for service in all_tempest_modules:
+ for service in clients._tempest_internal_modules():
try:
# NOTE(andreaf) Use the unversioned service name to fetch
# the configuration since configuration is not versioned.
diff --git a/tempest/config.py b/tempest/config.py
index 84edede..3fd20ab 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -26,6 +26,7 @@
import testtools
from tempest.lib import exceptions
+from tempest.lib.services import clients
from tempest.test_discover import plugins
@@ -1288,6 +1289,15 @@
lockutils.set_defaults(lock_dir)
self._config = TempestConfigPrivate(config_path=self._path)
+ # Pushing tempest internal service client configuration to the
+ # service clients register. Doing this in the config module ensures
+ # that the configuration is available by the time we register the
+ # service clients.
+ # NOTE(andreaf) This has to be done at the time the first
+ # attribute is accessed, to ensure all plugins have been already
+ # loaded, options registered, and _config is set.
+ _register_tempest_service_clients()
+
return getattr(self._config, attr)
def set_config_path(self, path):
@@ -1447,3 +1457,29 @@
# Set service
_parameters['service'] = getattr(options, 'catalog_type')
return _parameters
+
+
+def _register_tempest_service_clients():
+ # Register tempest own service clients using the same mechanism used
+ # for external plugins.
+ # The configuration data is pushed to the registry so that automatic
+ # configuration of tempest own service clients is possible both for
+ # tempest as well as for the plugins.
+ service_clients = clients.tempest_modules()
+ registry = clients.ClientsRegistry()
+ all_clients = []
+ for service_client in service_clients:
+ module = service_clients[service_client]
+ configs = service_client.split('.')[0]
+ service_client_data = dict(
+ name=service_client.replace('.', '_'),
+ service_version=service_client,
+ module_path=module.__name__,
+ client_names=module.__all__,
+ **service_client_config(configs)
+ )
+ all_clients.append(service_client_data)
+ # NOTE(andreaf) Internal service clients do not actually belong
+ # to a plugin, so using '__tempest__' to indicate a virtual plugin
+ # which holds internal service clients.
+ registry.register_service_client('__tempest__', all_clients)
diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py
index e782321..adf666b 100644
--- a/tempest/lib/services/clients.py
+++ b/tempest/lib/services/clients.py
@@ -18,7 +18,6 @@
import importlib
import inspect
import logging
-import six
from tempest.lib import auth
from tempest.lib.common.utils import misc
@@ -90,11 +89,14 @@
plug_service_versions))
raise exceptions.PluginRegistrationException(
name=plugin_name, detailed_error=detailed_error)
- if not plug_service_versions.isdisjoint(_tempest_modules):
+ # NOTE(andreaf) Once all tempest clients are stable, the following
+ # if will have to be removed.
+ if not plug_service_versions.isdisjoint(
+ _tempest_internal_modules()):
detailed_error = (
'Plugin %s is trying to register a service %s already '
'claimed by a Tempest one' % (plugin_name,
- _tempest_modules &
+ _tempest_internal_modules() &
plug_service_versions))
raise exceptions.PluginRegistrationException(
name=plugin_name, detailed_error=detailed_error)
@@ -351,15 +353,7 @@
raise exceptions.UnknownServiceClient(
services=list(client_parameters.keys()))
- # Register service clients owned by tempest
- for service, module in six.iteritems(tempest_modules()):
- attribute = service.replace('.', '_')
- configs = service.split('.')[0]
- self.register_service_client_module(
- attribute, service, module.__name__,
- module.__all__, **self.parameters[configs])
-
- # Register service clients from plugins
+ # Register service clients from the registry (__tempest__ and plugins)
clients_registry = ClientsRegistry()
plugin_service_clients = clients_registry.get_service_clients()
for plugin in plugin_service_clients:
@@ -432,6 +426,8 @@
@property
def registered_services(self):
+ # NOTE(andreaf) Once all tempest modules are stable this needs to
+ # be updated to remove _tempest_internal_modules
return self._registered_services | _tempest_internal_modules()
def _setup_parameters(self, parameters):
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 952c0c2..6da0570 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -127,6 +127,21 @@
wait_dict['client'] = waiter_client
self.cleanup_waits.append(wait_dict)
+ def _create_port(self, network_id, client=None, namestart='port-quotatest',
+ **kwargs):
+ if not client:
+ client = self.ports_client
+ name = data_utils.rand_name(namestart)
+ result = client.create_port(
+ name=name,
+ network_id=network_id,
+ **kwargs)
+ self.assertIsNotNone(result, 'Unable to allocate port')
+ port = result['port']
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ client.delete_port, port['id'])
+ return port
+
def _wait_for_cleanups(self):
# To handle async delete actions, a list of waits is added
# which will be iterated over as the last step of clearing the
@@ -209,18 +224,18 @@
networks = []
# If there are no networks passed to us we look up
- # for the project's private networks and create a port
- # if there is only one private network. The same behaviour
- # as we would expect when passing the call to the clients
- # with no networks
+ # for the project's private networks and create a port.
+ # The same behaviour as we would expect when passing
+ # the call to the clients with no networks
if not networks:
networks = clients.networks_client.list_networks(
- filters={'router:external': False})
- self.assertEqual(1, len(networks),
- "There is more than one"
- " network for the tenant")
+ **{'router:external': False, 'fields': 'id'})['networks']
+
+ # It's net['uuid'] if networks come from kwargs
+ # and net['id'] if they come from
+ # clients.networks_client.list_networks
for net in networks:
- net_id = net['uuid']
+ net_id = net.get('uuid', net['id'])
if 'port' not in net:
port = self._create_port(network_id=net_id,
client=clients.ports_client,
@@ -813,21 +828,6 @@
return subnet
- def _create_port(self, network_id, client=None, namestart='port-quotatest',
- **kwargs):
- if not client:
- client = self.ports_client
- name = data_utils.rand_name(namestart)
- result = client.create_port(
- name=name,
- network_id=network_id,
- **kwargs)
- self.assertIsNotNone(result, 'Unable to allocate port')
- port = result['port']
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- client.delete_port, port['id'])
- return port
-
def _get_server_port_id_and_ip4(self, server, ip_addr=None):
ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
# A port can have more then one IP address in some cases.