From ff50cc5b52b5bb24804c97de697b304b9f006715 Mon Sep 17 00:00:00 2001 From: "Andrea Frittoli (andreaf)" Date: Mon, 8 Aug 2016 10:34:31 +0100 Subject: [PATCH] Try to register all service clients Accumulate all exceptions from service client registrations, and raise them together at the end, so in case more than one service client has issues, we provide a full error report. Change-Id: I902cfdea0af371dfa222a9bbf41edc4ea2765926 --- tempest/lib/exceptions.py | 3 ++ tempest/lib/services/clients.py | 21 +++++++-- tempest/tests/lib/services/test_clients.py | 53 ++++++++++++++++++++++ 3 files changed, 72 insertions(+), 5 deletions(-) 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()