diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py index 68ce57a6ef..1c93452a25 100644 --- a/tempest/lib/exceptions.py +++ b/tempest/lib/exceptions.py @@ -44,6 +44,9 @@ class TempestException(Exception): def __str__(self): return self._error_string + def __repr__(self): + return self._error_string + class RestClientException(TempestException, testtools.TestCase.failureException): diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py index cd3bab04f5..5d7fd32b95 100644 --- a/tempest/lib/services/clients.py +++ b/tempest/lib/services/clients.py @@ -17,10 +17,12 @@ import copy import importlib import inspect +import sys import warnings from debtcollector import removals from oslo_log import log as logging +import testtools from tempest.lib import auth from tempest.lib.common.utils import misc @@ -85,6 +87,7 @@ def available_modules(): extra_service_versions = set([]) _tempest_modules = set(tempest_modules()) plugin_services = ClientsRegistry().get_service_clients() + name_conflicts = [] for plugin_name in plugin_services: plug_service_versions = set([x['service_version'] for x in plugin_services[plugin_name]]) @@ -96,8 +99,8 @@ def available_modules(): 'claimed by another one' % (plugin_name, extra_service_versions & plug_service_versions)) - raise exceptions.PluginRegistrationException( - name=plugin_name, detailed_error=detailed_error) + name_conflicts.append(exceptions.PluginRegistrationException( + name=plugin_name, detailed_error=detailed_error)) # NOTE(andreaf) Once all tempest clients are stable, the following # if will have to be removed. if not plug_service_versions.isdisjoint( @@ -107,9 +110,14 @@ def available_modules(): 'claimed by a Tempest one' % (plugin_name, _tempest_internal_modules() & plug_service_versions)) - raise exceptions.PluginRegistrationException( - name=plugin_name, detailed_error=detailed_error) + name_conflicts.append(exceptions.PluginRegistrationException( + name=plugin_name, detailed_error=detailed_error)) extra_service_versions |= plug_service_versions + if name_conflicts: + LOG.error( + 'Failed to list available modules due to name conflicts: %s', + name_conflicts) + raise testtools.MultipleExceptions(*name_conflicts) return _tempest_modules | extra_service_versions @@ -375,6 +383,7 @@ class ServiceClients(object): # Register service clients from the registry (__tempest__ and plugins) clients_registry = ClientsRegistry() plugin_service_clients = clients_registry.get_service_clients() + registration_errors = [] for plugin in plugin_service_clients: service_clients = plugin_service_clients[plugin] # Each plugin returns a list of service client parameters @@ -385,10 +394,12 @@ class ServiceClients(object): try: self.register_service_client_module(**service_client) except Exception: + registration_errors.append(sys.exc_info()) LOG.exception( 'Failed to register service client from plugin %s ' 'with parameters %s', plugin, service_client) - raise + if registration_errors: + raise testtools.MultipleExceptions(*registration_errors) def register_service_client_module(self, name, service_version, module_path, client_names, **kwargs): diff --git a/tempest/tests/lib/services/test_clients.py b/tempest/tests/lib/services/test_clients.py index a837199c7c..6d0f27a602 100644 --- a/tempest/tests/lib/services/test_clients.py +++ b/tempest/tests/lib/services/test_clients.py @@ -16,6 +16,7 @@ import types import fixtures import mock +import six import testtools from tempest.lib import auth @@ -258,6 +259,58 @@ class TestServiceClients(base.TestCase): clients.ServiceClients(creds, identity_uri=uri, client_parameters=params) + def test___init___plugin_service_clients_cannot_load(self): + creds = fake_credentials.FakeKeystoneV3Credentials() + uri = 'fake_uri' + fake_service_clients = { + 'service1': [{'name': 'client1', + 'service_version': 'client1.v1', + 'module_path': 'I cannot load this', + 'client_names': ['SomeClient1']}], + 'service2': [{'name': 'client2', + 'service_version': 'client2.v1', + 'module_path': 'This neither', + 'client_names': ['SomeClient1']}]} + msg = "(?=.*{0})(?=.*{1})".format( + *[x[1][0]['module_path'] for x in six.iteritems( + fake_service_clients)]) + self.useFixture(fixtures.MockPatchObject( + clients.ClientsRegistry(), 'get_service_clients', + return_value=fake_service_clients)) + with testtools.ExpectedException( + testtools.MultipleExceptions, value_re=msg): + clients.ServiceClients(creds, identity_uri=uri) + + def test___init___plugin_service_clients_name_conflict(self): + creds = fake_credentials.FakeKeystoneV3Credentials() + uri = 'fake_uri' + fake_service_clients = { + 'serviceA': [{'name': 'client1', + 'service_version': 'client1.v1', + 'module_path': 'fake_path_1', + 'client_names': ['SomeClient1']}], + 'serviceB': [{'name': 'client1', + 'service_version': 'client1.v2', + 'module_path': 'fake_path_2', + 'client_names': ['SomeClient2']}], + 'serviceC': [{'name': 'client1', + 'service_version': 'client1.v1', + 'module_path': 'fake_path_2', + 'client_names': ['SomeClient1']}], + 'serviceD': [{'name': 'client1', + 'service_version': 'client1.v2', + 'module_path': 'fake_path_2', + 'client_names': ['SomeClient2']}]} + msg = "(?=.*{0})(?=.*{1})".format( + *[x[1][0]['service_version'] for x in six.iteritems( + fake_service_clients)]) + self.useFixture(fixtures.MockPatchObject( + clients.ClientsRegistry(), 'get_service_clients', + return_value=fake_service_clients)) + with testtools.ExpectedException( + testtools.MultipleExceptions, value_re=msg): + clients.ServiceClients(creds, identity_uri=uri) + def _get_manager(self, init_region='fake_region'): # Get a manager to invoke _setup_parameters on creds = fake_credentials.FakeKeystoneV2Credentials()