Handle SetupError exception to avoid spamming into log files.

Change-Id: Id360d6e1638fc5bfb6adaa41412a977526795fe5
This commit is contained in:
Federico Ressi 2020-09-25 13:45:02 +02:00
parent 6395db0bb6
commit 2dcf72cda3
4 changed files with 54 additions and 5 deletions

View File

@ -123,18 +123,23 @@ def exc_info(reraise=True):
return info
def log_unhandled_exception(exc_type, exc_value, ex_tb):
LOG.exception("Unhandled exception",
exc_info=(exc_type, exc_value, ex_tb))
@contextlib.contextmanager
def handle_multiple_exceptions():
def handle_multiple_exceptions(handle_exception=log_unhandled_exception):
try:
yield
except testtools.MultipleExceptions as exc:
except testtools.MultipleExceptions as ex:
exc_infos = list_exc_infos()
if exc_infos:
for info in exc_infos[1:]:
LOG.exception("Unhandled exception:", exc_info=info)
handle_exception(*info)
reraise(*exc_infos[0])
else:
LOG.debug('empty MultipleExceptions: %s', str(exc))
LOG.debug(f"Empty MultipleExceptions: '{ex}'")
def list_exc_infos(exc_info=None):

View File

@ -13,6 +13,7 @@
# under the License.
from __future__ import absolute_import
import json
import os
import inspect
@ -99,11 +100,24 @@ def remove_fixture(obj, fixture_id=None, manager=None):
def setup_fixture(obj, fixture_id=None, manager=None):
'''Get registered fixture and setup it up'''
fixture = get_fixture(obj, fixture_id=fixture_id, manager=manager)
with _exception.handle_multiple_exceptions():
with _exception.handle_multiple_exceptions(
handle_exception=handle_setup_error):
fixture.setUp()
return fixture
def handle_setup_error(ex_type, ex_value, ex_tb):
if issubclass(ex_type, fixtures.SetupError):
details = ex_value.args[0]
if details:
details = {k: v.as_text() for k, v in details.items()}
pretty_details = json.dumps(details, indent=4, sort_keys=True)
LOG.debug(f"Fixture setup error details:\n{pretty_details}\n")
else:
LOG.exception("Unhandled setup exception",
exc_info=(ex_type, ex_value, ex_tb))
def reset_fixture(obj, fixture_id=None, manager=None):
'''Get registered fixture and reset it'''
fixture = get_fixture(obj, fixture_id=fixture_id, manager=manager)

View File

@ -210,6 +210,28 @@ class TestHandleMultipleExceptions(unit.TobikoUnitTest):
ex = self.assertRaises(RuntimeError, run)
self.assertEqual(a[1], ex)
def test_handle_multiple_exceptions_with_handle_exceptions(self):
a = make_exception(RuntimeError, 'a')
b = make_exception(ValueError, 'b')
c = make_exception(TypeError, 'c')
d = make_exception(IndexError, 'd')
inner = make_exception(testtools.MultipleExceptions, b, c)
handled_exceptions = []
def handle_exception(ex_type, ex_value, ex_tb):
self.assertIsInstance(ex_value, ex_type)
handled_exceptions.append((ex_type, ex_value, ex_tb))
def run():
with tobiko.handle_multiple_exceptions(
handle_exception=handle_exception):
raise testtools.MultipleExceptions(a, inner, d)
ex = self.assertRaises(RuntimeError, run)
self.assertIs(a[1], ex)
self.assertEqual([b, c, d], handled_exceptions)
def make_exception(cls, *args, **kwargs):
try:

View File

@ -19,6 +19,7 @@ import sys
import fixtures
import mock
import testtools
from testtools import content
import tobiko
from tobiko.tests import unit
@ -228,6 +229,13 @@ class FailingFixture(tobiko.SharedFixture):
def cleanup_fixture(self):
raise RuntimeError('raised by cleanup_fixture')
def getDetails(self):
content_object = tobiko.details_content(
content_type=content.UTF8_TEXT,
content_id=self.fixture_name,
get_text=lambda: 'My failure details')
return {'failing fixture': content_object}
class FailingSetupFixtureWhenFailingTest(unit.TobikoUnitTest):