示例#1
0
    def test_can_send_message(self, with_msg_id):
        mailer = DebugMailer()
        msg_header = b'X-Header: somevalue\n'
        if with_msg_id:
            msg_id = '*****@*****.**' % uuid.uuid4()
            msg_header += b'Message-ID: <%s>\n' % msg_id.encode('ascii')
        msg_body = b'MsgBody\n'
        msg_bytes = msg_header + b'\n' + msg_body
        msg = inject_example_message(
            self.path_maildir,
            sender=b'*****@*****.**',
            recipient=b'*****@*****.**',
            msg_bytes=msg_bytes,
        )
        assert_true(os.path.exists(msg.path))

        with LogCapture() as lc:
            mh = MessageHandler([mailer], info_logger(lc))
            was_sent = mh.send_message(msg)
        assert_trueish(was_sent)
        expected_log_msg = '%s => %s' % ('*****@*****.**',
                                         '*****@*****.**')
        if with_msg_id:
            expected_log_msg += ' <%s>' % msg_id
        assert_did_log_message(lc, expected_msg=expected_log_msg)

        assert_length(1, mailer.sent_mails)
        sent_msg, = mailer.sent_mails
        assert_equals('*****@*****.**', sent_msg.from_addr)
        assert_equals(('*****@*****.**', ), sent_msg.to_addrs)
        assert_equals(msg_nl(msg_bytes), sent_msg.msg_fp.read())
        assert_false(os.path.exists(msg.path))
        # ensure there are no left-overs/tmp files
        assert_length(0, self.list_all_files(self.path_maildir))
示例#2
0
    def test_can_notify_plugin_after_delivery(self, delivery_successful):
        if delivery_successful:
            signal = MQSignal.delivery_successful
            mailer = DebugMailer()
        else:
            signal = MQSignal.delivery_failed
            mailer = DebugMailer(simulate_failed_sending=True)
        registry = SignalRegistry()
        plugin = MagicMock(return_value=None, spec={})
        connect_signals({signal: plugin}, registry.namespace)

        mh = MessageHandler([mailer], plugins=registry)
        mh.send_message(example_message(),
                        sender='*****@*****.**',
                        recipient='*****@*****.**')

        plugin.assert_called_once()
        # would be able to simplify this with Python 3 only:
        # call_kwargs = plugin.call_args.kwargs
        call_kwargs = plugin.call_args[-1]
        send_result = call_kwargs['send_result']
        if delivery_successful:
            assert_length(1, mailer.sent_mails)
            assert_trueish(send_result)
        else:
            assert_length(0, mailer.sent_mails)
            assert_falseish(send_result)
        assert_false(send_result.queued)
        assert_equals('debug', send_result.transport)
示例#3
0
    def test_can_enqueue_message_with_multiple_recipients_after_failed_sending(
            self):
        mailer = DebugMailer(simulate_failed_sending=True)
        mh = MessageHandler([mailer, MaildirBackend(self.path_maildir)])
        msg = example_message()
        recipients = ('*****@*****.**', '*****@*****.**')

        mh.send_message(msg, sender='*****@*****.**', recipients=recipients)
        msg_path, = self.msg_files(folder='new')
        with open(msg_path, 'rb') as msg_fp:
            stored_msg = parse_message_envelope(msg_fp)
        assert_equals(recipients, stored_msg.to_addrs)
示例#4
0
    def test_can_enqueue_message_after_failed_sending(self):
        mailer = DebugMailer(simulate_failed_sending=True)
        maildir_fallback = MaildirBackend(self.path_maildir)
        msg = example_message()

        mh = MessageHandler([mailer, maildir_fallback])
        was_sent = mh.send_message(msg,
                                   sender='*****@*****.**',
                                   recipient='*****@*****.**')
        assert_trueish(was_sent)
        assert_is_empty(mailer.sent_mails)
        msg_path, = self.msg_files(folder='new')
        with open(msg_path, 'rb') as msg_fp:
            stored_msg = parse_message_envelope(msg_fp)
        assert_equals('*****@*****.**', stored_msg.from_addr)
        assert_equals(('*****@*****.**', ), stored_msg.to_addrs)
示例#5
0
    def test_tries_to_lock_message_while_sending(self):
        mailer = DebugMailer()
        msg = inject_example_message(self.path_maildir)
        locked_msg = lock_file(msg.path, timeout=0.1)
        mh = MessageHandler([mailer])

        was_sent = mh.send_message(msg)
        assert_none(was_sent)
        assert_length(1, self.msg_files(folder='new'))
        assert_is_empty(mailer.sent_mails)

        locked_msg.close()
        was_sent = mh.send_message(msg)
        assert_trueish(was_sent)
        assert_is_empty(self.msg_files(folder='new'))
        assert_length(1, mailer.sent_mails)
示例#6
0
    def test_can_handle_non_existent_file_in_send(self):
        mailer = DebugMailer()
        invalid_path = os.path.join(self.path_maildir, 'new', 'invalid')
        msg_with_invalid_path = MaildirBackedMsg(invalid_path)

        was_sent = MessageHandler([mailer]).send_message(msg_with_invalid_path)
        assert_none(was_sent)
        assert_length(0, mailer.sent_mails)
示例#7
0
    def test_can_handle_sending_failure(self):
        mailer = DebugMailer(simulate_failed_sending=True)
        msg = inject_example_message(self.path_maildir)
        assert_true(os.path.exists(msg.path))

        was_sent = MessageHandler([mailer]).send_message(msg)
        assert_falseish(was_sent)
        assert_true(os.path.exists(msg.path))
        # no left-overs (e.g. in "tmp" folder) other than the initial message file
        assert_length(1, self.list_all_files(self.path_maildir))
示例#8
0
    def test_plugin_can_access_number_of_failed_deliveries(self):
        registry = SignalRegistry()

        def discard_after_two_attempts(sender, msg, send_result):
            return MQAction.DISCARD if (msg.retries > 1) else None

        connect_signals({MQSignal.delivery_failed: discard_after_two_attempts},
                        registry.namespace)

        msg = inject_example_message(self.path_maildir)
        mailer = DebugMailer(simulate_failed_sending=True)
        mh = MessageHandler([mailer], plugins=registry)

        mh.send_message(msg)
        assert_length(1, find_messages(self.path_maildir, log=l_(None)))

        send_result = mh.send_message(msg)
        assert_falseish(send_result)
        assert_length(0, mailer.sent_mails)
        assert_length(0, find_messages(self.path_maildir, log=l_(None)))
        assert_true(send_result.discarded)
示例#9
0
    def test_can_store_message_on_disk_before_sending(self):
        msg = example_message()
        md_msg = enqueue_message(
            msg,
            self.path_maildir,
            sender='*****@*****.**',
            recipients=('*****@*****.**', ),
            in_progress=True,
            return_msg=True,
        )
        assert_length(0, self.msg_files(folder='new'))
        assert_length(1, self.msg_files(folder='cur'))

        mailer = DebugMailer()
        mh = MessageHandler([mailer])
        send_result = mh.send_message(md_msg)
        assert_trueish(send_result)

        assert_length(1, mailer.sent_mails)
        assert_length(0, self.msg_files(folder='new'))
        assert_length(0, self.msg_files(folder='cur'))
示例#10
0
    def test_plugin_can_discard_message_after_failed_delivery(self):
        mailer = DebugMailer(simulate_failed_sending=True)
        sender = '*****@*****.**'
        recipient = '*****@*****.**'

        def discard_message(event_sender, msg, send_result):
            assert_falseish(send_result)
            assert_none(send_result.discarded)
            assert_equals(sender, msg.from_addr)
            assert_equals({recipient}, set(msg.to_addrs))
            return MQAction.DISCARD

        registry = SignalRegistry()
        connect_signals({MQSignal.delivery_failed: discard_message},
                        registry.namespace)
        msg = example_message()
        mh = MessageHandler([mailer], plugins=registry)
        send_result = mh.send_message(msg, sender=sender, recipient=recipient)

        assert_falseish(send_result)
        assert_false(send_result.queued)
        assert_true(send_result.discarded)
示例#11
0
    def test_can_handle_duplicate_file_in_cur_before_send(self):
        msg = inject_example_message(self.path_maildir)
        path_in_progress = msg.path.replace('new', 'cur')
        # this can happen on Unix/Posix because Python does not provide an
        # atomic "move without overwrite". Linux provides the "renameat2"
        # system call (with RENAME_NOREPLACE flag) but Python does not expose
        # that API.
        shutil.copy(msg.path, path_in_progress)
        mailer = DebugMailer()

        was_sent = MessageHandler([mailer]).send_message(msg)
        assert_none(was_sent)
        assert_length(0, mailer.sent_mails)
        assert_length(2, self.list_all_files(self.path_maildir))
示例#12
0
    def test_can_handle_vanished_file_after_successful_send(self):
        if IS_WINDOWS:
            self.skipTest('unable to unlink open file on Windows')
        msg = inject_example_message(self.path_maildir)
        path_in_progress = msg.path.replace('new', 'cur')

        def delete_on_send(*args):
            os.unlink(path_in_progress)
            return True

        mailer = DebugMailer(send_callback=delete_on_send)

        was_sent = MessageHandler([mailer]).send_message(msg)
        assert_true(was_sent)
        assert_length(1, mailer.sent_mails)
        assert_length(0, self.list_all_files(self.path_maildir))
示例#13
0
    def test_can_handle_duplicate_file_in_new_after_failed_send(self):
        msg = inject_example_message(self.path_maildir)
        path_in_progress = msg.path.replace('new', 'cur')

        # again: can happen because Python provides not atomic "move without
        # overwrite" on Linux (see also "renameat2" system call)
        def duplicate_on_failed_send(*args):
            shutil.copy(path_in_progress, msg.path)
            return False

        mailer = DebugMailer(send_callback=duplicate_on_failed_send)

        was_sent = MessageHandler([mailer]).send_message(msg)
        assert_false(was_sent)
        assert_length(0, mailer.sent_mails)
        assert_length(2, self.list_all_files(self.path_maildir))