Beispiel #1
0
 def test_multiple_retries(self, mock_get_current_time, mock_time):
     mock_get_current_time.side_effect = [
         self.current_time,  # First call to figure out the expiration time
         self.current_time,  # Check to see if the message has expired
         self.current_time,  # Time after attempting the send
         # This attempt fails and the app is instructed to wait for a second
         self.current_time + datetime.timedelta(
             seconds=1),  # Check again to see if it's expired
         self.current_time +
         datetime.timedelta(seconds=1),  # Time after second send attempt
         # This attempt fails and the app is instructed to wait for another second
         self.current_time +
         datetime.timedelta(seconds=2),  # Final expiration check
     ]
     self.mock_channel.deliver.side_effect = [
         RecoverableChannelDeliveryError(
             u'Try again later',
             self.current_time + datetime.timedelta(seconds=1)),
         RecoverableChannelDeliveryError(
             u'Try again later',
             self.current_time + datetime.timedelta(seconds=2)), True
     ]
     deliver(self.mock_channel, sentinel.rendered_email, self.message)
     assert mock_time.sleep.call_args_list == [call(1), call(1)]
     assert self.mock_channel.deliver.call_count == 3
Beispiel #2
0
    def _handle_error_response(self, response):
        u"""
        Handle an error response from SailThru, either by retrying or failing
        with an appropriate exception.

        Arguments:
            response: The HTTP response recieved from SailThru.
        """
        error = response.get_error()
        error_code = error.get_error_code()
        error_message = error.get_message()
        http_status_code = response.get_status_code()
        if error_code in RecoverableErrorCodes:
            next_attempt_time = None
            if error_code == RecoverableErrorCodes.RATE_LIMIT:
                next_attempt_time = self._get_rate_limit_reset_time(
                    sailthru_response=response)

            if next_attempt_time is None:
                # Sailthru advises waiting "a moment" and then trying again.
                next_attempt_time = get_current_time() + timedelta(
                    seconds=NEXT_ATTEMPT_DELAY_SECONDS + random.uniform(-2, 2))

            raise RecoverableChannelDeliveryError(
                u'Recoverable Sailthru error (error_code={error_code} status_code={http_status_code}): '
                u'{message}'.format(error_code=error_code,
                                    http_status_code=http_status_code,
                                    message=error_message), next_attempt_time)
        else:
            raise FatalChannelDeliveryError(
                u'Fatal Sailthru error (error_code={error_code} status_code={http_status_code}): '
                u'{message}'.format(error_code=error_code,
                                    http_status_code=http_status_code,
                                    message=error_message))
Beispiel #3
0
 def test_next_attempt_time_after_expiration(self, mock_get_current_time,
                                             mock_time):
     self.message.expiration_time = self.current_time + datetime.timedelta(
         seconds=10)
     mock_get_current_time.return_value = self.current_time
     self.mock_channel.deliver.side_effect = [
         RecoverableChannelDeliveryError(
             u'Try again later',
             self.current_time + datetime.timedelta(seconds=11)),
     ]
     deliver(self.mock_channel, sentinel.rendered_email, self.message)
     assert not mock_time.sleep.called
     assert self.mock_channel.deliver.call_count == 1
Beispiel #4
0
 def test_single_retry(self, mock_get_current_time, mock_time):
     mock_get_current_time.side_effect = [
         self.current_time,  # First call to figure out the expiration time
         self.current_time,  # Check to see if the message has expired
         self.current_time,  # Time after attempting the send
         self.current_time + datetime.timedelta(seconds=1.1),
     ]
     self.mock_channel.deliver.side_effect = [
         RecoverableChannelDeliveryError(
             u'Try again later',
             self.current_time + datetime.timedelta(seconds=1)), True
     ]
     deliver(self.mock_channel, sentinel.rendered_email, self.message)
     assert self.mock_channel.deliver.call_count == 2
     mock_time.sleep.assert_called_once_with(1)
Beispiel #5
0
    def _handle_error_response(self, response, message, exception):
        """
        Handle an error response from Braze, either by retrying or failing
        with an appropriate exception.

        Arguments:
            response: The HTTP response received from Braze.
            message: An error message from Braze.
            exception: The exception that triggered this error.
        """
        if response.status_code == 429 or 500 <= response.status_code < 600:
            next_attempt_time = get_current_time() + timedelta(
                seconds=NEXT_ATTEMPT_DELAY_SECONDS + random.uniform(-2, 2))
            raise RecoverableChannelDeliveryError(
                'Recoverable Braze error (status_code={http_status_code}): {message}'
                .format(http_status_code=response.status_code,
                        message=message), next_attempt_time) from exception

        raise FatalChannelDeliveryError(
            'Fatal Braze error (status_code={http_status_code}): {message}'.
            format(http_status_code=response.status_code,
                   message=message)) from exception
class SendActivationEmailTestCase(TestCase):
    """
    Test for send activation email to user
    """
    def setUp(self):
        """ Setup components used by each test."""
        super().setUp()
        self.student = UserFactory()

        registration = Registration()
        registration.register(self.student)

        self.msg = compose_activation_email("http://www.example.com", self.student, registration)

    def test_ComposeEmail(self):
        """
        Tests that attributes of the message are being filled correctly in compose_activation_email
        """
        # Check that variables used by the base template are present in generated context
        assert 'platform_name' in self.msg.context
        assert 'contact_mailing_address' in self.msg.context
        # Verify the presence of the activation-email specific attributes
        assert self.msg.recipient.lms_user_id == self.student.id
        assert self.msg.recipient.email_address == self.student.email
        assert self.msg.context['routed_user'] == self.student.username
        assert self.msg.context['routed_user_email'] == self.student.email
        assert self.msg.context['routed_profile_name'] == ''

    @mock.patch('time.sleep', mock.Mock(return_value=None))
    @mock.patch('common.djangoapps.student.tasks.log')
    @mock.patch('common.djangoapps.student.tasks.ace.send', mock.Mock(side_effect=RecoverableChannelDeliveryError(None, None)))  # lint-amnesty, pylint: disable=line-too-long
    def test_RetrySendUntilFail(self, mock_log):
        """
        Tests retries when the activation email doesn't send
        """
        from_address = '*****@*****.**'
        email_max_attempts = settings.RETRY_ACTIVATION_EMAIL_MAX_ATTEMPTS

        send_activation_email.delay(str(self.msg), from_address=from_address)

        # Asserts sending email retry logging.
        for attempt in range(email_max_attempts):
            mock_log.info.assert_any_call(
                'Retrying sending email to user {dest_addr}, attempt # {attempt} of {max_attempts}'.format(
                    dest_addr=self.student.email,
                    attempt=attempt,
                    max_attempts=email_max_attempts
                ))
        assert mock_log.info.call_count == 6

        # Asserts that the error was logged on crossing max retry attempts.
        mock_log.error.assert_called_with(
            'Unable to send activation email to user from "%s" to "%s"',
            from_address,
            self.student.email,
            exc_info=True
        )
        assert mock_log.error.call_count == 1

    @mock.patch('common.djangoapps.student.tasks.log')
    @mock.patch('common.djangoapps.student.tasks.ace.send', mock.Mock(side_effect=ChannelError))
    def test_UnrecoverableSendError(self, mock_log):
        """
        Tests that a major failure of the send is logged
        """
        from_address = '*****@*****.**'

        send_activation_email.delay(str(self.msg), from_address=from_address)

        # Asserts that the error was logged
        mock_log.exception.assert_called_with(
            'Unable to send activation email to user from "%s" to "%s"',
            from_address,
            self.student.email,
        )

        # Assert that nothing else was logged
        assert mock_log.info.call_count == 0
        assert mock_log.error.call_count == 0
        assert mock_log.exception.call_count == 1
class SendActivationEmailTestCase(TestCase):
    """
    Test for send activation email to user
    """
    def setUp(self):
        """ Setup components used by each test."""
        super(SendActivationEmailTestCase, self).setUp()
        self.student = UserFactory()

        registration = Registration()
        registration.register(self.student)

        self.msg = compose_activation_email("http://www.example.com",
                                            self.student, registration)

    def test_ComposeEmail(self):
        """
        Tests that attributes of the message are being filled correctly in compose_activation_email
        """
        self.assertEqual(self.msg.recipient.username, self.student.username)
        self.assertEqual(self.msg.recipient.email_address, self.student.email)
        self.assertEqual(self.msg.context['routed_user'],
                         self.student.username)
        self.assertEqual(self.msg.context['routed_user_email'],
                         self.student.email)
        self.assertEqual(self.msg.context['routed_profile_name'], '')

    @mock.patch('time.sleep', mock.Mock(return_value=None))
    @mock.patch('student.tasks.log')
    @mock.patch(
        'student.tasks.ace.send',
        mock.Mock(side_effect=RecoverableChannelDeliveryError(None, None)))
    def test_RetrySendUntilFail(self, mock_log):
        """
        Tests retries when the activation email doesn't send
        """
        from_address = '*****@*****.**'
        email_max_attempts = settings.RETRY_ACTIVATION_EMAIL_MAX_ATTEMPTS

        send_activation_email.delay(str(self.msg), from_address=from_address)

        # Asserts sending email retry logging.
        for attempt in range(email_max_attempts):
            mock_log.info.assert_any_call(
                'Retrying sending email to user {dest_addr}, attempt # {attempt} of {max_attempts}'
                .format(dest_addr=self.student.email,
                        attempt=attempt,
                        max_attempts=email_max_attempts))
        self.assertEqual(mock_log.info.call_count, 6)

        # Asserts that the error was logged on crossing max retry attempts.
        mock_log.error.assert_called_with(
            'Unable to send activation email to user from "%s" to "%s"',
            from_address,
            self.student.email,
            exc_info=True)
        self.assertEqual(mock_log.error.call_count, 1)

    @mock.patch('student.tasks.log')
    @mock.patch('student.tasks.ace.send', mock.Mock(side_effect=ChannelError))
    def test_UnrecoverableSendError(self, mock_log):
        """
        Tests that a major failure of the send is logged
        """
        from_address = '*****@*****.**'

        send_activation_email.delay(str(self.msg), from_address=from_address)

        # Asserts that the error was logged
        mock_log.exception.assert_called_with(
            'Unable to send activation email to user from "%s" to "%s"',
            from_address,
            self.student.email,
        )

        # Assert that nothing else was logged
        self.assertEqual(mock_log.info.call_count, 0)
        self.assertEqual(mock_log.error.call_count, 0)
        self.assertEqual(mock_log.exception.call_count, 1)
Beispiel #8
0
class SendCalendarSyncEmailTestCase(TestCase):
    """
    Test for send activation email to user
    """
    def setUp(self):
        """ Setup components used by each test."""
        super(SendCalendarSyncEmailTestCase, self).setUp()
        self.user = UserFactory()
        self.course_overview = CourseOverviewFactory()
        self.msg = compose_calendar_sync_email(self.user, self.course_overview)

    @mock.patch('time.sleep', mock.Mock(return_value=None))
    @mock.patch('openedx.features.calendar_sync.tasks.log')
    @mock.patch(
        'openedx.features.calendar_sync.tasks.ace.send',
        mock.Mock(side_effect=RecoverableChannelDeliveryError(None, None)))
    def test_RetrySendUntilFail(self, mock_log):
        """
        Tests retries when the activation email doesn't send
        """
        from_address = '*****@*****.**'
        email_max_attempts = settings.RETRY_ACTIVATION_EMAIL_MAX_ATTEMPTS

        send_calendar_sync_email.delay(str(self.msg),
                                       from_address=from_address)

        # Asserts sending email retry logging.
        for attempt in range(email_max_attempts):
            mock_log.info.assert_any_call(
                'Retrying sending email to user {dest_addr}, attempt # {attempt} of {max_attempts}'
                .format(dest_addr=self.user.email,
                        attempt=attempt,
                        max_attempts=email_max_attempts))
        self.assertEqual(mock_log.info.call_count, 6)

        # Asserts that the error was logged on crossing max retry attempts.
        mock_log.error.assert_called_with(
            'Unable to send calendar sync email to user from "%s" to "%s"',
            from_address,
            self.user.email,
            exc_info=True)
        self.assertEqual(mock_log.error.call_count, 1)

    @mock.patch('openedx.features.calendar_sync.tasks.log')
    @mock.patch('openedx.features.calendar_sync.tasks.ace.send',
                mock.Mock(side_effect=ChannelError))
    def test_UnrecoverableSendError(self, mock_log):
        """
        Tests that a major failure of the send is logged
        """
        from_address = '*****@*****.**'

        send_calendar_sync_email.delay(str(self.msg),
                                       from_address=from_address)

        # Asserts that the error was logged
        mock_log.exception.assert_called_with(
            'Unable to send calendar sync email to user from "%s" to "%s"',
            from_address, self.user.email)

        # Assert that nothing else was logged
        self.assertEqual(mock_log.info.call_count, 0)
        self.assertEqual(mock_log.error.call_count, 0)
        self.assertEqual(mock_log.exception.call_count, 1)