Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stricter signature for ErrorHandler.gui_error() #6846

Merged
merged 1 commit into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions src/tribler/gui/error_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,30 @@ def __init__(self, tribler_window):
self._handled_exceptions = set()
self._tribler_stopped = False

def gui_error(self, *exc_info):
if exc_info and len(exc_info) == 3:
info_type, info_error, tb = exc_info
text = "".join(traceback.format_exception(info_type, info_error, tb))
self._logger.error(text)
def gui_error(self, exc_type, exc, tb):
text = "".join(traceback.format_exception(exc_type, exc, tb))
self._logger.error(text)

if self._tribler_stopped:
return

if gui_sentry_reporter.global_strategy == SentryStrategy.SEND_SUPPRESSED:
self._logger.info(f'GUI error was suppressed and not sent to Sentry: {info_type.__name__}: {info_error}')
self._logger.info(f'GUI error was suppressed and not sent to Sentry: {exc_type.__name__}: {exc}')
return

if info_type in self._handled_exceptions:
if exc_type in self._handled_exceptions:
return
self._handled_exceptions.add(info_type)
self._handled_exceptions.add(exc_type)

is_core_exception = issubclass(info_type, CoreError)
is_core_exception = issubclass(exc_type, CoreError)
if is_core_exception:
text = text + self.tribler_window.core_manager.last_core_stderr_output
self._stop_tribler(text)

reported_error = ReportedError(
type=type(info_type).__name__,
type=type(exc_type).__name__,
text=text,
event=gui_sentry_reporter.event_from_exception(info_error),
event=gui_sentry_reporter.event_from_exception(exc),
)

if self.app_manager.quitting_app:
Expand Down
28 changes: 18 additions & 10 deletions src/tribler/gui/tests/test_error_handler.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
from unittest.mock import MagicMock, PropertyMock, patch

import pytest
Expand Down Expand Up @@ -25,32 +26,36 @@ def reported_error():


@patch('tribler.gui.error_handler.FeedbackDialog')
async def test_gui_error_tribler_stopped(mocked_feedback_dialog: MagicMock, error_handler: ErrorHandler):
async def test_gui_error_tribler_stopped(mocked_feedback_dialog: MagicMock, error_handler: ErrorHandler, caplog):
# test that while tribler_stopped is True FeedbackDialog is not called
error_handler._tribler_stopped = True
error_handler.gui_error()
error_handler.gui_error(AssertionError, AssertionError("error text"), None)
mocked_feedback_dialog.assert_not_called()
assert caplog.record_tuples == [('ErrorHandler', logging.ERROR, 'AssertionError: error text\n')]


@patch('tribler.gui.error_handler.FeedbackDialog')
@patch.object(SentryReporter, 'global_strategy', create=True,
new=PropertyMock(return_value=SentryStrategy.SEND_SUPPRESSED))
async def test_gui_error_suppressed(mocked_feedback_dialog: MagicMock, error_handler: ErrorHandler):
logger_info_mock = MagicMock()
error_handler._logger = MagicMock(info=logger_info_mock)
async def test_gui_error_suppressed(mocked_feedback_dialog: MagicMock, error_handler: ErrorHandler, caplog):
error_handler.gui_error(AssertionError, AssertionError('error_text'), None)
mocked_feedback_dialog.assert_not_called()
assert not error_handler._handled_exceptions
logger_info_mock.assert_called_with('GUI error was suppressed and not sent to Sentry: AssertionError: error_text')
assert caplog.record_tuples == [
('ErrorHandler', logging.ERROR, 'AssertionError: error_text\n'),
('ErrorHandler', logging.INFO, 'GUI error was suppressed and not sent to Sentry: AssertionError: error_text')
]


@patch('tribler.gui.error_handler.FeedbackDialog')
async def test_gui_info_type_in_handled_exceptions(mocked_feedback_dialog: MagicMock, error_handler: ErrorHandler):
async def test_gui_info_type_in_handled_exceptions(mocked_feedback_dialog: MagicMock, error_handler: ErrorHandler,
caplog):
# test that if exception type in _handled_exceptions then FeedbackDialog is not called
error_handler._handled_exceptions = {AssertionError}
error_handler.gui_error(AssertionError, None, None)
error_handler.gui_error(AssertionError, AssertionError("error text"), None)
mocked_feedback_dialog.assert_not_called()
assert len(error_handler._handled_exceptions) == 1
assert caplog.record_tuples == [('ErrorHandler', logging.ERROR, 'AssertionError: error text\n')]


@patch('tribler.gui.error_handler.FeedbackDialog')
Expand All @@ -59,16 +64,19 @@ async def test_gui_core_connect_timeout_error(mocked_stop_tribler, mocked_feedba
error_handler: ErrorHandler):
# test that in case of CoreConnectTimeoutError Tribler should stop it's work
error_handler.gui_error(CoreConnectTimeoutError, None, None)

mocked_feedback_dialog.assert_called_once()
mocked_stop_tribler.assert_called_once()


@patch('tribler.gui.error_handler.FeedbackDialog')
@patch.object(ErrorHandler, '_stop_tribler')
async def test_gui_core_connect_timeout_error(mocked_stop_tribler: MagicMock, mocked_feedback_dialog: MagicMock,
error_handler: ErrorHandler):
async def test_gui_core_crashed_error(mocked_stop_tribler: MagicMock, mocked_feedback_dialog: MagicMock,
error_handler: ErrorHandler):
# test that in case of CoreRuntimeError Tribler should stop it's work
error_handler.gui_error(CoreCrashedError, None, None)

mocked_feedback_dialog.assert_called_once()
mocked_stop_tribler.assert_called_once()


Expand Down