From 41e82f5035b100a21ef23e034e31f16e4359ef7c Mon Sep 17 00:00:00 2001 From: Simone Robutti Date: Sun, 24 Oct 2021 21:43:09 +0200 Subject: [PATCH] better error handling (#92) * safe logging of notifier failure to send * added test --- mobilizon_reshare/publishers/coordinator.py | 7 +++- tests/publishers/test_coordinator.py | 44 ++++++++++++++++----- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/mobilizon_reshare/publishers/coordinator.py b/mobilizon_reshare/publishers/coordinator.py index fe8db0f..22378e1 100644 --- a/mobilizon_reshare/publishers/coordinator.py +++ b/mobilizon_reshare/publishers/coordinator.py @@ -154,9 +154,12 @@ class AbstractCoordinator: self.platforms = platforms def send_to_all(self): - # TODO: failure to send should fail safely and write to a dedicated log for platform in self.platforms: - platform.send(self.message) + try: + platform.send(self.message) + except Exception as e: + logger.critical(f"Notifier failed to send message:\n{self.message}") + logger.exception(e) class AbstractNotifiersCoordinator(AbstractCoordinator): diff --git a/tests/publishers/test_coordinator.py b/tests/publishers/test_coordinator.py index b9af503..19f7145 100644 --- a/tests/publishers/test_coordinator.py +++ b/tests/publishers/test_coordinator.py @@ -1,3 +1,4 @@ +import logging from uuid import UUID import pytest @@ -19,6 +20,17 @@ from mobilizon_reshare.publishers.coordinator import ( ) +@pytest.fixture() +def failure_report(mock_publisher_invalid): + return EventPublicationReport( + status=PublicationStatus.FAILED, + reason="some failure", + publication=EventPublication( + publisher=mock_publisher_invalid, formatter=None, event=None, id=UUID(int=1) + ), + ) + + @pytest.mark.parametrize( "statuses, successful", [ @@ -136,18 +148,13 @@ async def test_publication_coordinator_run_failure_response( @pytest.mark.asyncio -async def test_notifier_coordinator_publication_failed(mock_publisher_valid): +async def test_notifier_coordinator_publication_failed( + mock_publisher_valid, failure_report +): mock_send = MagicMock() mock_publisher_valid._send = mock_send - report = EventPublicationReport( - status=PublicationStatus.FAILED, - reason="some failure", - publication=EventPublication( - id=UUID(int=4), publisher=mock_publisher_valid, formatter=None, event=None - ), - ) coordinator = PublicationFailureNotifiersCoordinator( - report, [mock_publisher_valid, mock_publisher_valid] + failure_report, [mock_publisher_valid, mock_publisher_valid] ) coordinator.notify_failure() @@ -155,6 +162,25 @@ async def test_notifier_coordinator_publication_failed(mock_publisher_valid): assert mock_send.call_count == 2 +@pytest.mark.asyncio +async def test_notifier_coordinator_error( + failure_report, mock_publisher_invalid_response, caplog +): + mock_send = MagicMock() + mock_publisher_invalid_response._send = mock_send + + coordinator = PublicationFailureNotifiersCoordinator( + failure_report, + [mock_publisher_invalid_response, mock_publisher_invalid_response], + ) + with caplog.at_level(logging.CRITICAL): + coordinator.notify_failure() + assert "Notifier failed to send" in caplog.text + assert failure_report.get_failure_message() in caplog.text + # 4 = 2 reports * 2 notifiers + assert mock_send.call_count == 2 + + @pytest.mark.parametrize("num_publications", [2]) @pytest.mark.asyncio async def test_recap_coordinator_run_success(