Merge "Try to register all service clients"
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index cdb8be9..c538c72 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -44,6 +44,9 @@
     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 5f230b7..4fa7a7a 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 @@
     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 @@
                     '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 @@
                     '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 @@
         # 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 @@
                 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 a837199..6d0f27a 100644
--- a/tempest/tests/lib/services/test_clients.py
+++ b/tempest/tests/lib/services/test_clients.py
@@ -16,6 +16,7 @@
 
 import fixtures
 import mock
+import six
 import testtools
 
 from tempest.lib import auth
@@ -258,6 +259,58 @@
             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()