Skip to content

Commit

Permalink
Don't send misconfiguration to sentry (jsocol#143)
Browse files Browse the repository at this point in the history
* Don't send misconfiguration to sentry

* PR review

* Don't send sentry misconfig errors only if use_latest is True
  • Loading branch information
maxime-fender authored May 17, 2022
1 parent 7bd3d77 commit bf08541
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 41 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import logging
from typing import Type

import callee
import pytest
from pika.adapters.blocking_connection import BlockingChannel
from pytest import LogCaptureFixture
from pytest_mock import MockFixture

from tests.adapters.incoming_messages_consumer import helpers
from use_case_executor import constants
Expand All @@ -12,49 +18,28 @@
from use_case_executor.domain.errors import InvalidFlowConfiguration
from use_case_executor.domain.errors import InvalidFlowFormat
from use_case_executor.domain.errors import InvalidUseCaseConfiguration
from use_case_executor.domain.errors import Misconfiguration
from use_case_executor.domain.errors import NLPExtractionError
from use_case_executor.domain.errors import TechnicalException
from use_case_executor.domain.errors import UserEventSendError
from use_case_executor.domain.message_processing.answer_sender import AnswerSender
from use_case_executor.domain.monitoring.monitoring_timer import MonitoringTimer


@pytest.mark.parametrize(
"exception_class, fallback_text",
[
(ForbiddenUseCase, "Sorry, something looks misconfigured: test exception."),
(
InvalidUseCaseConfiguration,
"Sorry, something looks misconfigured: test exception.",
),
(
InvalidFlowConfiguration,
"Sorry, something looks misconfigured: test exception.",
),
(InvalidFlowFormat, InvalidFlowFormat().end_user_message),
(InvalidClientMessageFormat, InvalidClientMessageFormat().end_user_message),
(NLPExtractionError, NLPExtractionError().end_user_message),
(UserEventSendError, UserEventSendError().end_user_message),
(
ImpossibleHandoverAvailabilityCheck,
ImpossibleHandoverAvailabilityCheck().end_user_message,
),
(ImpossibleTicketCreation, ImpossibleTicketCreation().end_user_message),
(Exception, constants.FALLBACK_MESSAGE),
],
)
def test_process_incoming_message_raising_exception_sends_a_fallback_message(
mocker,
instance_id,
nlp_language,
content_language,
uce_incoming_messages_channel,
exception_class,
fallback_text,
):
def set_mocks_publish_message_and_check_mock_calls(
mocker: MockFixture,
exception: Exception,
instance_id: int,
nlp_language: str,
content_language: str,
use_latest: bool,
uce_incoming_messages_channel: BlockingChannel,
fallback_text: str,
) -> None:
process_incoming_message_mock = mocker.patch.object(
facade,
"process_incoming_message",
side_effect=exception_class("test exception"),
side_effect=exception,
autospec=True,
)
send_message_acknowledgement_and_fallback_answer_mock = mocker.patch.object(
Expand All @@ -63,12 +48,11 @@ def test_process_incoming_message_raising_exception_sends_a_fallback_message(
side_effect=None,
autospec=True,
)

incoming_message = helpers.make_incoming_message(
instance_id=instance_id,
nlp_language=nlp_language,
content_language=content_language,
use_latest=False,
use_latest=use_latest,
)
(
message_properties,
Expand All @@ -77,7 +61,6 @@ def test_process_incoming_message_raising_exception_sends_a_fallback_message(
message_to_send=incoming_message,
uce_incoming_messages_channel=uce_incoming_messages_channel,
)

process_incoming_message_mock.assert_called_once_with(
message_forward_data=BotMessageForwardData(
message_properties=message_properties, message_body=message_body
Expand All @@ -88,6 +71,134 @@ def test_process_incoming_message_raising_exception_sends_a_fallback_message(
)
send_message_acknowledgement_and_fallback_answer_mock.assert_called_once_with(
answer_sender=callee.InstanceOf(AnswerSender),
exception_raised=exception_class.__name__,
exception_raised=exception.__class__.__name__,
fallback_text=fallback_text,
)


@pytest.mark.parametrize("use_latest", [True, False])
def test_raising_exception_sends_default_fallback_message_and_log_exception_as_error(
mocker: MockFixture,
instance_id: int,
nlp_language: str,
content_language: str,
use_latest: bool,
uce_incoming_messages_channel: BlockingChannel,
caplog: LogCaptureFixture,
) -> None:
exception = Exception("test exception")
set_mocks_publish_message_and_check_mock_calls(
mocker=mocker,
exception=exception,
instance_id=instance_id,
nlp_language=nlp_language,
content_language=content_language,
use_latest=use_latest,
uce_incoming_messages_channel=uce_incoming_messages_channel,
fallback_text=constants.FALLBACK_MESSAGE,
)

with caplog.at_level(logging.ERROR):
assert f"{exception.__class__.__name__}: test exception" in caplog.text


@pytest.mark.parametrize("use_latest", [True, False])
@pytest.mark.parametrize(
"exception_class",
[
InvalidFlowFormat,
InvalidClientMessageFormat,
NLPExtractionError,
UserEventSendError,
ImpossibleHandoverAvailabilityCheck,
ImpossibleTicketCreation,
],
)
def test_raising_technical_exception_sends_custom_fallback_message_and_log_exception_as_error(
mocker: MockFixture,
instance_id: int,
nlp_language: str,
content_language: str,
use_latest: bool,
uce_incoming_messages_channel: BlockingChannel,
caplog: LogCaptureFixture,
exception_class: Type[TechnicalException],
) -> None:
exception = exception_class("test exception")
set_mocks_publish_message_and_check_mock_calls(
mocker=mocker,
exception=exception,
instance_id=instance_id,
nlp_language=nlp_language,
content_language=content_language,
use_latest=use_latest,
uce_incoming_messages_channel=uce_incoming_messages_channel,
fallback_text=exception.end_user_message,
)

with caplog.at_level(logging.ERROR):
assert f"{exception.__class__.__name__}: test exception" in caplog.text


@pytest.mark.parametrize(
"exception_class",
[ForbiddenUseCase, InvalidUseCaseConfiguration, InvalidFlowConfiguration],
)
def test_raising_misconfiguration_sends_custom_fallback_message_and_log_exception_as_error_if_not_use_latest(
mocker: MockFixture,
instance_id: int,
nlp_language: str,
content_language: str,
uce_incoming_messages_channel: BlockingChannel,
caplog: LogCaptureFixture,
exception_class: Type[Misconfiguration],
) -> None:
exception = exception_class("test exception")
set_mocks_publish_message_and_check_mock_calls(
mocker=mocker,
exception=exception,
instance_id=instance_id,
nlp_language=nlp_language,
content_language=content_language,
use_latest=False,
uce_incoming_messages_channel=uce_incoming_messages_channel,
fallback_text="Sorry, something looks misconfigured: test exception.",
)

with caplog.at_level(logging.ERROR):
assert f"{exception.__class__.__name__}: test exception" in caplog.text


@pytest.mark.parametrize(
"exception_class",
[ForbiddenUseCase, InvalidUseCaseConfiguration, InvalidFlowConfiguration],
)
def test_raising_misconfiguration_sends_custom_fallback_message_and_log_exception_as_info_if_use_latest(
mocker: MockFixture,
instance_id: int,
nlp_language: str,
content_language: str,
uce_incoming_messages_channel: BlockingChannel,
caplog: LogCaptureFixture,
exception_class: Type[Misconfiguration],
) -> None:
exception = exception_class("test exception")
set_mocks_publish_message_and_check_mock_calls(
mocker=mocker,
exception=exception,
instance_id=instance_id,
nlp_language=nlp_language,
content_language=content_language,
use_latest=True,
uce_incoming_messages_channel=uce_incoming_messages_channel,
fallback_text="Sorry, something looks misconfigured: test exception.",
)

with caplog.at_level(logging.INFO):
assert (
f"Caught misconfiguration error, ignoring it: {repr(exception)}"
in caplog.text
)

with caplog.at_level(logging.ERROR):
assert f"{exception.__class__.__name__}: test exception" not in caplog.text
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"use_latest, exception_message",
[
(True, "use case does not have any flow to execute"),
(False, "This use case is not published"),
(False, "this use case is not published"),
],
)
def test_incoming_message_with_matching_use_case_and_no_flow_returns_a_fallback_message(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def test_incoming_message_with_invalid_content_language_returns_a_fallback_messa
"use_latest, exception_message",
[
(True, "use case does not have any flow to execute"),
(False, "This use case is not published"),
(False, "this use case is not published"),
],
)
def test_incoming_message_with_matching_use_case_and_no_flow_returns_a_fallback_message(
Expand Down
6 changes: 6 additions & 0 deletions use_case_executor/adapters/incoming_messages_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from use_case_executor.adapters.bot_message_forwarder import BotMessageForwardData
from use_case_executor.domain import facade
from use_case_executor.domain.errors import DomainException
from use_case_executor.domain.errors import Misconfiguration
from use_case_executor.domain.message_processing.answer_sender import AnswerSender
from use_case_executor.domain.monitoring.monitoring_timer import MonitoringTimer
from use_case_executor.helpers import rmq_connection
Expand Down Expand Up @@ -151,4 +152,9 @@ def _process_uce_incoming_message(properties: BasicProperties, body: bytes) -> N
fallback_text=fallback_text,
)

# When use_latest is True, we do not send misconfiguration errors to Sentry
if message_json.get("use_latest") and isinstance(exc, Misconfiguration):
log.info("Caught misconfiguration error, ignoring it: %s", repr(exc))
return

raise
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def execute_use_case_and_send_answer(
monitoring_timer.step_done("load_use_case_flow")
if not flow:
if not execution_environment.use_latest:
raise InvalidUseCaseConfiguration("This use case is not published")
raise InvalidUseCaseConfiguration("this use case is not published")
raise InvalidUseCaseConfiguration("use case does not have any flow to execute")
log.info("Flow loaded")

Expand Down

0 comments on commit bf08541

Please sign in to comment.