def test_nonverp_detectable_nonfatal_bounce(self):
        # Here's a bounce that is not VERPd, but which has a bouncing address
        # that can be parsed from a known bounce format.  The bounce is
        # non-fatal so no bounce event is registered and the bounce is not
        # reported as unrecognized.
        self._mlist.forward_unrecognized_bounces_to = (
            UnrecognizedBounceDisposition.site_owner)
        dsn = message_from_string("""\
From: [email protected]
To: [email protected]
Message-Id: <first>
Content-Type: multipart/report; report-type=delivery-status; boundary=AAA
MIME-Version: 1.0

--AAA
Content-Type: message/delivery-status

Action: delayed
Original-Recipient: rfc822; [email protected]

--AAA--
""")
        self._bounceq.enqueue(dsn, self._msgdata)
        mark = LogFileMark('mailman.bounce')
        self._runner.run()
        get_queue_messages('bounces', expected_count=0)
        events = list(self._processor.events)
        self.assertEqual(len(events), 0)
        # There should be nothing in the 'virgin' queue.
        get_queue_messages('virgin', expected_count=0)
        # There should be log event in the log file.
        log_lines = mark.read().splitlines()
        self.assertTrue(len(log_lines) > 0)
Ejemplo n.º 2
0
    def test_hold_chain(self):
        msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: A message
Message-ID: <ant>
MIME-Version: 1.0

A message body.
""")
        msgdata = dict(moderation_reasons=[
            'TEST-REASON-1',
            'TEST-REASON-2',
            ])
        logfile = LogFileMark('mailman.vette')
        process_chain(self._mlist, msg, msgdata, start_chain='hold')
        messages = get_queue_messages('virgin', expected_count=2)
        payloads = {}
        for item in messages:
            if item.msg['to'] == '*****@*****.**':
                part = item.msg.get_payload(0)
                payloads['owner'] = part.get_payload().splitlines()
            elif item.msg['To'] == '*****@*****.**':
                payloads['sender'] = item.msg.get_payload().splitlines()
            else:
                self.fail('Unexpected message: %s' % item.msg)
        self.assertIn('    TEST-REASON-1', payloads['owner'])
        self.assertIn('    TEST-REASON-2', payloads['owner'])
        self.assertIn('    TEST-REASON-1', payloads['sender'])
        self.assertIn('    TEST-REASON-2', payloads['sender'])
        logged = logfile.read()
        self.assertIn('TEST-REASON-1', logged)
        self.assertIn('TEST-REASON-2', logged)
Ejemplo n.º 3
0
 def test_digest_messages(self):
     # In LP: #1130697, the digest runner creates MIME digests using the
     # stdlib MIMEMutlipart class, however this class does not have the
     # extended attributes we require (e.g. .sender).  The fix is to use a
     # subclass of MIMEMultipart and our own Message subclass; this adds
     # back the required attributes.  (LP: #1130696)
     #
     # Start by creating the raw ingredients for the digests.  This also
     # runs the digest runner, thus producing the digest messages into the
     # virgin queue.
     make_digest_messages(self._mlist)
     # Run the virgin queue processor, which runs the cook-headers and
     # to-outgoing handlers.  This should produce no error.
     error_log = LogFileMark('mailman.error')
     runner = make_testable_runner(VirginRunner, 'virgin')
     runner.run()
     error_text = error_log.read()
     self.assertEqual(len(error_text), 0, error_text)
     self.assertEqual(len(get_queue_messages('shunt')), 0)
     messages = get_queue_messages('out')
     self.assertEqual(len(messages), 2)
     # Which one is the MIME digest?
     mime_digest = None
     for bag in messages:
         if bag.msg.get_content_type() == 'multipart/mixed':
             assert mime_digest is None, 'Found two MIME digests'
             mime_digest = bag.msg
     # The cook-headers handler ran.
     self.assertIn('x-mailman-version', mime_digest)
     self.assertEqual(mime_digest['precedence'], 'list')
     # The list's -request address is the original sender.
     self.assertEqual(bag.msgdata['original_sender'],
                      '*****@*****.**')
Ejemplo n.º 4
0
 def test_digest_messages(self):
     # In LP: #1130697, the digest runner creates MIME digests using the
     # stdlib MIMEMutlipart class, however this class does not have the
     # extended attributes we require (e.g. .sender).  The fix is to use a
     # subclass of MIMEMultipart and our own Message subclass; this adds
     # back the required attributes.  (LP: #1130696)
     #
     # Start by creating the raw ingredients for the digests.  This also
     # runs the digest runner, thus producing the digest messages into the
     # virgin queue.
     make_digest_messages(self._mlist)
     # Run the virgin queue processor, which runs the cook-headers and
     # to-outgoing handlers.  This should produce no error.
     error_log = LogFileMark('mailman.error')
     runner = make_testable_runner(VirginRunner, 'virgin')
     runner.run()
     error_text = error_log.read()
     self.assertEqual(len(error_text), 0, error_text)
     self.assertEqual(len(get_queue_messages('shunt')), 0)
     messages = get_queue_messages('out')
     self.assertEqual(len(messages), 2)
     # Which one is the MIME digest?
     mime_digest = None
     for bag in messages:
         if bag.msg.get_content_type() == 'multipart/mixed':
             assert mime_digest is None, 'Found two MIME digests'
             mime_digest = bag.msg
     # The cook-headers handler ran.
     self.assertIn('x-mailman-version', mime_digest)
     self.assertEqual(mime_digest['precedence'], 'list')
     # The list's -request address is the original sender.
     self.assertEqual(bag.msgdata['original_sender'],
                      '*****@*****.**')
Ejemplo n.º 5
0
 def test_non_ascii_message(self):
     msg = Message()
     msg['From'] = '*****@*****.**'
     msg['To'] = '*****@*****.**'
     msg['Content-Type'] = 'multipart/mixed'
     msg.attach(MIMEText('message with non-ascii chars: \xc3\xa9',
                         'plain', 'utf-8'))
     mbox = digest_mbox(self._mlist)
     mbox_path = os.path.join(self._mlist.data_path, 'digest.mmdf')
     mbox.add(msg.as_string())
     self._digestq.enqueue(
         msg,
         listname=self._mlist.fqdn_listname,
         digest_path=mbox_path,
         volume=1, digest_number=1)
     # Use any error logs as the error message if the test fails.
     error_log = LogFileMark('mailman.error')
     self._runner.run()
     # The runner will send the file to the shunt queue on exception.
     self.assertEqual(len(self._shuntq.files), 0, error_log.read())
     # There are two messages in the virgin queue: the digest as plain-text
     # and as multipart.
     messages = get_queue_messages('virgin')
     self.assertEqual(len(messages), 2)
     self.assertEqual(
         sorted(item.msg.get_content_type() for item in messages),
         ['multipart/mixed', 'text/plain'])
     for item in messages:
         self.assertEqual(item.msg['subject'],
                          'Test Digest, Vol 1, Issue 1')
Ejemplo n.º 6
0
 def test_discard_no_reasons(self):
     # The log message contains n/a if no moderation reasons.
     msgdata = {}
     log_file = LogFileMark('mailman.vette')
     process_chain(self._mlist, self._msg, msgdata, start_chain='discard')
     log_entry = log_file.read()
     self.assertIn('DISCARD: <*****@*****.**>', log_entry)
     self.assertIn('[n/a]', log_entry)
Ejemplo n.º 7
0
 def test_discard_reasons(self):
     # The log message must contain the moderation reasons.
     msgdata = dict(moderation_reasons=['TEST-REASON-1', 'TEST-REASON-2'])
     log_file = LogFileMark('mailman.vette')
     process_chain(self._mlist, self._msg, msgdata, start_chain='discard')
     log_entry = log_file.read()
     self.assertIn('DISCARD: <*****@*****.**>', log_entry)
     self.assertIn('TEST-REASON-1', log_entry)
     self.assertIn('TEST-REASON-2', log_entry)
Ejemplo n.º 8
0
 def test_uheader_multiline(self):
     # Multiline headers should be truncated (GL#273).
     mark = LogFileMark('mailman.error')
     header = cook_headers.uheader(self._mlist, 'A multiline\ndescription',
                                   'X-Header')
     self.assertEqual(header.encode(), 'A multiline [...]')
     log_messages = mark.read()
     self.assertIn('Header X-Header contains a newline, truncating it',
                   log_messages)
Ejemplo n.º 9
0
 def test_bad_group(self):
     self.mlist.linked_newsgroup = 'other.group'
     mark = LogFileMark('mailman.fromusenet')
     with get_nntplib_nntp():
         self._command.invoke(gatenews)
     lines = mark.read().splitlines()
     self.assertEqual(len(lines), 2)
     self.assertTrue(lines[0].endswith('NNTP error for list '
                                       '[email protected]:'))
     self.assertEqual(lines[1], 'No such group: other.group')
Ejemplo n.º 10
0
 def test_up_to_date(self):
     self.mlist.usenet_watermark = 3
     mark = LogFileMark('mailman.fromusenet')
     with get_nntplib_nntp():
         self._command.invoke(gatenews)
     lines = mark.read().splitlines()
     self.assertEqual(self.mlist.usenet_watermark, 3)
     self.assertEqual(len(lines), 3)
     self.assertTrue(lines[0].endswith('[email protected]: [1..3]'))
     self.assertTrue(lines[1].endswith('nothing new for list '
                                       '*****@*****.**'))
     self.assertTrue(lines[2].endswith('[email protected] watermark: 3'))
Ejemplo n.º 11
0
 def test_catchup_only(self):
     self.mlist.usenet_watermark = None
     mark = LogFileMark('mailman.fromusenet')
     with get_nntplib_nntp():
         self._command.invoke(gatenews)
     lines = mark.read().splitlines()
     self.assertEqual(self.mlist.usenet_watermark, 3)
     self.assertEqual(len(lines), 3)
     self.assertTrue(lines[0].endswith('[email protected]: [1..3]'))
     self.assertTrue(lines[1].endswith('[email protected] '
                                       'caught up to article 3'))
     self.assertTrue(lines[2].endswith('[email protected] watermark: 3'))
Ejemplo n.º 12
0
 def test_bad_nntp_connect(self):
     mark = LogFileMark('mailman.fromusenet')
     with get_nntplib_nntp(fail=1):
         self._command.invoke(gatenews)
     lines = mark.read().splitlines()
     self.assertEqual(len(lines), 4)
     self.assertTrue(lines[0].endswith('error opening connection '
                                       'to nntp_host: news.example.com'))
     self.assertEqual(lines[1], 'Bad call to NNTP')
     self.assertTrue(lines[2].endswith('NNTP error for list '
                                       '[email protected]:'))
     self.assertEqual(lines[3], 'Bad call to NNTP')
Ejemplo n.º 13
0
 def test_article_exception(self):
     mark = LogFileMark('mailman.fromusenet')
     with get_nntplib_nntp(fail=2):
         self._command.invoke(gatenews)
     lines = mark.read().splitlines()
     self.assertEqual(len(lines), 5)
     self.assertTrue(lines[0].endswith('[email protected]: [1..3]'))
     self.assertTrue(lines[1].endswith('gating [email protected] '
                                       'articles [1..3]'))
     self.assertTrue(lines[2].endswith('NNTP error for list '
                                       '[email protected]:       2'))
     self.assertEqual(lines[3], 'Bad call to article')
     self.assertTrue(lines[4].endswith('[email protected] watermark: 3'))
Ejemplo n.º 14
0
 def test_email_parser_exception(self):
     mark = LogFileMark('mailman.fromusenet')
     with get_email_exception():
         with get_nntplib_nntp():
             self._command.invoke(gatenews)
     lines = mark.read().splitlines()
     self.assertEqual(len(lines), 5)
     self.assertTrue(lines[0].endswith('[email protected]: [1..3]'))
     self.assertTrue(lines[1].endswith('gating [email protected] '
                                       'articles [1..3]'))
     self.assertTrue(lines[2].endswith('email package exception for '
                                       'my.group:2'))
     self.assertEqual(lines[3], 'Bad message')
     self.assertTrue(lines[4].endswith('[email protected] watermark: 3'))
Ejemplo n.º 15
0
 def test_broken_archiver(self):
     # GL issue #208 - IArchive messages raise exceptions, breaking the
     # rfc-2369 handler and shunting messages.
     mark = LogFileMark('mailman.archiver')
     self._archiveq.enqueue(self._msg, {},
                            listid=self._mlist.list_id,
                            received_time=now())
     IListArchiverSet(self._mlist).get('broken').is_enabled = True
     self._runner.run()
     # The archiver is broken, so there are no messages on the file system,
     # but there is a log message and the message was not shunted.
     log_messages = mark.read()
     self.assertIn('Exception in "broken" archiver', log_messages)
     self.assertIn('RuntimeError: Cannot archive message', log_messages)
     get_queue_messages('shunt', expected_count=0)
Ejemplo n.º 16
0
 def test_non_ascii_message(self):
     msg = Message()
     msg['From'] = '*****@*****.**'
     msg['To'] = '*****@*****.**'
     msg['Content-Type'] = 'multipart/mixed'
     msg.attach(MIMEText('message with non-ascii chars: \xc3\xa9',
                         'plain', 'utf-8'))
     mbox = digest_mbox(self._mlist)
     mbox.add(msg.as_string())
     # Use any error logs as the error message if the test fails.
     error_log = LogFileMark('mailman.error')
     make_digest_messages(self._mlist, msg)
     # The runner will send the file to the shunt queue on exception.
     self.assertEqual(len(self._shuntq.files), 0, error_log.read())
     self._check_virgin_queue()
Ejemplo n.º 17
0
 def test_broken_archiver(self):
     # GL issue #208 - IArchive messages raise exceptions, breaking the
     # rfc-2369 handler and shunting messages.
     mark = LogFileMark('mailman.archiver')
     self._archiveq.enqueue(
         self._msg, {},
         listid=self._mlist.list_id,
         received_time=now())
     IListArchiverSet(self._mlist).get('broken').is_enabled = True
     self._runner.run()
     # The archiver is broken, so there are no messages on the file system,
     # but there is a log message and the message was not shunted.
     log_messages = mark.read()
     self.assertIn('Exception in "broken" archiver', log_messages)
     self.assertIn('RuntimeError: Cannot archive message', log_messages)
     get_queue_messages('shunt', expected_count=0)
Ejemplo n.º 18
0
 def test_broken_permalink(self):
     # GL issue #208 - IArchive messages raise exceptions, breaking the
     # rfc-2369 handler and shunting messages.
     site_dir = os.path.join(config.TEMPLATE_DIR, 'site', 'en')
     os.makedirs(site_dir)
     footer_path = os.path.join(site_dir, 'myfooter.txt')
     with open(footer_path, 'w', encoding='utf-8') as fp:
         print('${broken_url}', file=fp)
     self._mlist.footer_uri = 'mailman:///myfooter.txt'
     self._mlist.preferred_language = 'en'
     mark = LogFileMark('mailman.archiver')
     decorate.process(self._mlist, self._msg, {})
     log_messages = mark.read()
     self.assertNotIn('http:', self._msg.as_string())
     self.assertIn('Exception in "broken" archiver', log_messages)
     self.assertIn('RuntimeError: Cannot get permalink', log_messages)
 def test_disable_delivery_already_disabled(self):
     # Attempting to disable delivery for an already disabled member does
     # nothing.
     self._mlist.send_welcome_message = False
     member = self._subscribe_and_add_bounce_event('*****@*****.**')
     events = list(self._processor.events)
     self.assertEqual(len(events), 1)
     member.total_warnings_sent = 3
     member.last_warning_sent = now() - timedelta(days=2)
     member.preferences.delivery_status = DeliveryStatus.by_bounces
     mark = LogFileMark('mailman.bounce')
     self._processor._disable_delivery(self._mlist, member, events[0])
     self.assertEqual(mark.read(), '')
     self.assertEqual(member.total_warnings_sent, 3)
     self.assertEqual(member.last_warning_sent, now() - timedelta(days=2))
     get_queue_messages('virgin', expected_count=0)
Ejemplo n.º 20
0
 def test_broken_permalink(self):
     # GL issue #208 - IArchive messages raise exceptions, breaking the
     # rfc-2369 handler and shunting messages.
     site_dir = os.path.join(config.TEMPLATE_DIR, 'site', 'en')
     os.makedirs(site_dir)
     footer_path = os.path.join(site_dir, 'myfooter.txt')
     with open(footer_path, 'w', encoding='utf-8') as fp:
         print('${broken_url}', file=fp)
     self._mlist.footer_uri = 'mailman:///myfooter.txt'
     self._mlist.preferred_language = 'en'
     mark = LogFileMark('mailman.archiver')
     decorate.process(self._mlist, self._msg, {})
     log_messages = mark.read()
     self.assertNotIn('http:', self._msg.as_string())
     self.assertIn('Exception in "broken" archiver', log_messages)
     self.assertIn('RuntimeError: Cannot get permalink', log_messages)
 def test_events_bounce_already_disabled(self):
     # A bounce received for an already disabled member is only logged.
     anne = self._subscribe_and_add_bounce_event('*****@*****.**',
                                                 subscribe=False,
                                                 create=False)
     self._mlist.bounce_score_threshold = 3
     anne.bounce_score = 3
     anne.preferences.delivery_status = DeliveryStatus.by_bounces
     anne.total_warnings_sent = 1
     anne.last_warning_sent = now() - timedelta(days=3)
     mark = LogFileMark('mailman.bounce')
     self._runner.run()
     get_queue_messages('virgin', expected_count=0)
     self.assertEqual(anne.total_warnings_sent, 1)
     self.assertIn(
         'Residual bounce received for member [email protected] '
         'on list test.example.com.', mark.read())
Ejemplo n.º 22
0
    def test_hold_chain(self):
        msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: A message
Message-ID: <ant>
MIME-Version: 1.0

A message body.
""")
        msgdata = dict(moderation_reasons=[
            'TEST-REASON-1',
            'TEST-REASON-2',
            ('TEST-{}-REASON-{}', 'FORMAT', 3),
            ])
        logfile = LogFileMark('mailman.vette')
        process_chain(self._mlist, msg, msgdata, start_chain='hold')
        messages = get_queue_messages('virgin', expected_count=2)
        payloads = {}
        for item in messages:
            if item.msg['to'] == '*****@*****.**':
                part = item.msg.get_payload(0)
                payloads['owner'] = part.get_payload().splitlines()
            elif item.msg['To'] == '*****@*****.**':
                payloads['sender'] = item.msg.get_payload().splitlines()
            else:
                self.fail('Unexpected message: %s' % item.msg)
        self.assertIn('    TEST-REASON-1', payloads['owner'])
        self.assertIn('    TEST-REASON-2', payloads['owner'])
        self.assertIn('    TEST-FORMAT-REASON-3', payloads['owner'])
        self.assertIn('    TEST-REASON-1', payloads['sender'])
        self.assertIn('    TEST-REASON-2', payloads['sender'])
        self.assertIn('    TEST-FORMAT-REASON-3', payloads['sender'])
        logged = logfile.read()
        self.assertIn('TEST-REASON-1', logged)
        self.assertIn('TEST-REASON-2', logged)
        self.assertIn('TEST-FORMAT-REASON-3', logged)
        # Check the reason passed to hold_message().
        requests = IListRequests(self._mlist)
        self.assertEqual(requests.count_of(RequestType.held_message), 1)
        request = requests.of_type(RequestType.held_message)[0]
        key, data = requests.get_request(request.id)
        self.assertEqual(
            data.get('_mod_reason'),
            'TEST-REASON-1; TEST-REASON-2; TEST-FORMAT-REASON-3')
Ejemplo n.º 23
0
 def test_post_only_one_of_three(self):
     mark = LogFileMark('mailman.fromusenet')
     with get_nntplib_nntp():
         self._command.invoke(gatenews)
     lines = mark.read().splitlines()
     self.assertEqual(self.mlist.usenet_watermark, 3)
     self.assertEqual(len(lines), 4)
     self.assertTrue(lines[0].endswith('[email protected]: [1..3]'))
     self.assertTrue(lines[1].endswith('gating [email protected] '
                                       'articles [1..3]'))
     self.assertTrue(lines[2].endswith('posted to list [email protected]:'
                                       '       2'))
     self.assertTrue(lines[3].endswith('[email protected] watermark: 3'))
     items = get_queue_messages('in', expected_count=1)
     msg = items[0].msg
     msgdata = items[0].msgdata
     self.assertTrue(msgdata.get('fromusenet', False))
     self.assertEqual(msg.get('message-id', ''), '<*****@*****.**>')
Ejemplo n.º 24
0
 def test_utf7_message_with_inline_ascii_sig(self):
     # The test message is bigger than 1K.  Set the threshold bigger to
     # avoid double processing in make_digest_messages.
     self._mlist.digest_size_threshold = 5
     # Subscribe some users receiving digests.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     with open_binary('mailman.runners.tests.data',
                      'ascii_in_utf7.eml') as fp:
         msg = message_from_binary_file(fp, Message)
     # Use any error logs as the error message if the test fails.
     error_log = LogFileMark('mailman.error')
     make_digest_messages(self._mlist, msg)
     # The runner will send the file to the shunt queue on exception.
     self.assertEqual(len(self._shuntq.files), 0, error_log.read())
     self._check_virgin_queue()
Ejemplo n.º 25
0
 def test_broken_archiver(self):
     # GL issue #208 - IArchive messages raise exceptions, breaking the
     # rfc-2369 handler and shunting messages.
     config.push('archiver', """
     [archiver.broken]
     class: {}.BrokenArchiver
     enable: yes
     """.format(BrokenArchiver.__module__))
     self.addCleanup(config.pop, 'archiver')
     mark = LogFileMark('mailman.archiver')
     rfc_2369.process(self._mlist, self._msg, {})
     log_messages = mark.read()
     # Because .list_url() was broken, there will be no List-Archive header.
     self.assertIsNone(self._msg.get('list-archive'))
     self.assertIn('Exception in "broken" archiver', log_messages)
     self.assertIn('RuntimeError: Cannot get list URL', log_messages)
     # Because .permalink() was broken, there will be no Archived-At header.
     self.assertIsNone(self._msg.get('archived-at'))
     self.assertIn('Exception in "broken" archiver', log_messages)
     self.assertIn('RuntimeError: Cannot get permalink', log_messages)
Ejemplo n.º 26
0
 def test_non_ascii_message(self):
     # Subscribe some users receiving digests.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     msg = Message()
     msg['From'] = '*****@*****.**'
     msg['To'] = '*****@*****.**'
     msg['Content-Type'] = 'multipart/mixed'
     msg.attach(MIMEText('message with non-ascii chars: \xc3\xa9',
                         'plain', 'utf-8'))
     mbox = digest_mbox(self._mlist)
     mbox.add(msg.as_string())
     # Use any error logs as the error message if the test fails.
     error_log = LogFileMark('mailman.error')
     make_digest_messages(self._mlist, msg)
     # The runner will send the file to the shunt queue on exception.
     self.assertEqual(len(self._shuntq.files), 0, error_log.read())
     self._check_virgin_queue()
Ejemplo n.º 27
0
 def test_non_ascii_message(self):
     # Subscribe some users receiving digests.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     msg = Message()
     msg['From'] = '*****@*****.**'
     msg['To'] = '*****@*****.**'
     msg['Content-Type'] = 'multipart/mixed'
     msg.attach(MIMEText('message with non-ascii chars: \xc3\xa9',
                         'plain', 'utf-8'))
     mbox = digest_mbox(self._mlist)
     mbox.add(msg.as_string())
     # Use any error logs as the error message if the test fails.
     error_log = LogFileMark('mailman.error')
     make_digest_messages(self._mlist, msg)
     # The runner will send the file to the shunt queue on exception.
     self.assertEqual(len(self._shuntq.files), 0, error_log.read())
     self._check_virgin_queue()
Ejemplo n.º 28
0
 def test_broken_archiver(self):
     # GL issue #208 - IArchive messages raise exceptions, breaking the
     # rfc-2369 handler and shunting messages.
     config.push('archiver', """
     [archiver.broken]
     class: {}.BrokenArchiver
     enable: yes
     """.format(BrokenArchiver.__module__))
     self.addCleanup(config.pop, 'archiver')
     mark = LogFileMark('mailman.archiver')
     rfc_2369.process(self._mlist, self._msg, {})
     log_messages = mark.read()
     # Because .list_url() was broken, there will be no List-Archive header.
     self.assertIsNone(self._msg.get('list-archive'))
     self.assertIn('Exception in "broken" archiver', log_messages)
     self.assertIn('RuntimeError: Cannot get list URL', log_messages)
     # Because .permalink() was broken, there will be no Archived-At header.
     self.assertIsNone(self._msg.get('archived-at'))
     self.assertIn('Exception in "broken" archiver', log_messages)
     self.assertIn('RuntimeError: Cannot get permalink', log_messages)
Ejemplo n.º 29
0
    def test_log_exception_in_finish(self):
        # If something bad happens in .finish(), the traceback should get
        # logged.  LP: #1165589.
        msg = mfs("""\
From: [email protected]
To: [email protected]
Message-ID: <ant>

""")
        switchboard = config.switchboards['shunt']
        # Enqueue the message.
        filebase = switchboard.enqueue(msg)
        error_log = LogFileMark('mailman.error')
        msg, data = switchboard.dequeue(filebase)
        # Now, cause .finish() to throw an exception.
        with patch('mailman.core.switchboard.os.rename',
                   side_effect=OSError('Oops!')):
            switchboard.finish(filebase, preserve=True)
        traceback = error_log.read().splitlines()
        self.assertEqual(traceback[1], 'Traceback (most recent call last):')
        self.assertEqual(traceback[-1], 'OSError: Oops!')
Ejemplo n.º 30
0
    def test_log_exception_in_finish(self):
        # If something bad happens in .finish(), the traceback should get
        # logged.  LP: #1165589.
        msg = mfs("""\
From: [email protected]
To: [email protected]
Message-ID: <ant>

""")
        switchboard = config.switchboards['shunt']
        # Enqueue the message.
        filebase = switchboard.enqueue(msg)
        error_log = LogFileMark('mailman.error')
        msg, data = switchboard.dequeue(filebase)
        # Now, cause .finish() to throw an exception.
        with patch('mailman.core.switchboard.os.rename',
                   side_effect=OSError('Oops!')):
            switchboard.finish(filebase, preserve=True)
        traceback = error_log.read().splitlines()
        self.assertEqual(traceback[1], 'Traceback (most recent call last):')
        self.assertEqual(traceback[-1], 'OSError: Oops!')
Ejemplo n.º 31
0
 def test_digest_messages(self):
     # In LP: #1130697, the digest runner creates MIME digests using the
     # stdlib MIMEMutlipart class, however this class does not have the
     # extended attributes we require (e.g. .sender).  The fix is to use a
     # subclass of MIMEMultipart and our own Message subclass; this adds
     # back the required attributes.  (LP: #1130696)
     self._mlist.send_welcome_message = False
     # Subscribe some users receiving digests.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     # Start by creating the raw ingredients for the digests.  This also
     # runs the digest runner, thus producing the digest messages into the
     # virgin queue.
     make_digest_messages(self._mlist)
     # Run the virgin queue processor, which runs the cook-headers and
     # to-outgoing handlers.  This should produce no error.
     error_log = LogFileMark('mailman.error')
     runner = make_testable_runner(VirginRunner, 'virgin')
     runner.run()
     error_text = error_log.read()
     self.assertEqual(len(error_text), 0, error_text)
     get_queue_messages('shunt', expected_count=0)
     items = get_queue_messages('out', expected_count=2)
     # Which one is the MIME digest?
     mime_digest = None
     for item in items:
         if item.msg.get_content_type() == 'multipart/mixed':
             assert mime_digest is None, 'Found two MIME digests'
             mime_digest = item.msg
     # The cook-headers handler ran.
     self.assertIn('x-mailman-version', mime_digest)
     self.assertEqual(mime_digest['precedence'], 'list')
     # The list's -request address is the original sender.
     self.assertEqual(item.msgdata['original_sender'],
                      '*****@*****.**')
Ejemplo n.º 32
0
 def test_digest_messages(self):
     # In LP: #1130697, the digest runner creates MIME digests using the
     # stdlib MIMEMutlipart class, however this class does not have the
     # extended attributes we require (e.g. .sender).  The fix is to use a
     # subclass of MIMEMultipart and our own Message subclass; this adds
     # back the required attributes.  (LP: #1130696)
     self._mlist.send_welcome_message = False
     # Subscribe some users receiving digests.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     # Start by creating the raw ingredients for the digests.  This also
     # runs the digest runner, thus producing the digest messages into the
     # virgin queue.
     make_digest_messages(self._mlist)
     # Run the virgin queue processor, which runs the cook-headers and
     # to-outgoing handlers.  This should produce no error.
     error_log = LogFileMark('mailman.error')
     runner = make_testable_runner(VirginRunner, 'virgin')
     runner.run()
     error_text = error_log.read()
     self.assertEqual(len(error_text), 0, error_text)
     get_queue_messages('shunt', expected_count=0)
     items = get_queue_messages('out', expected_count=2)
     # Which one is the MIME digest?
     mime_digest = None
     for item in items:
         if item.msg.get_content_type() == 'multipart/mixed':
             assert mime_digest is None, 'Found two MIME digests'
             mime_digest = item.msg
     # The cook-headers handler ran.
     self.assertIn('x-mailman-version', mime_digest)
     self.assertEqual(mime_digest['precedence'], 'list')
     # The list's -request address is the original sender.
     self.assertEqual(item.msgdata['original_sender'],
                      '*****@*****.**')
Ejemplo n.º 33
0
 def test_header_matches(self):
     # This test contail real cases of header_filter_rules
     self._pckdict['header_filter_rules'] = [
         ('X\\-Spam\\-Status\\: Yes.*', 3, False),
         ('^X-Spam-Status: Yes\r\n\r\n', 2, False),
         ('^X-Spam-Level: \\*\\*\\*.*$', 3, False),
         ('^X-Spam-Level:.\\*\\*\r\n^X-Spam:.\\Yes', 3, False),
         ('Subject: \\[SPAM\\].*', 3, False),
         ('^Subject: .*loan.*', 3, False),
         ('Original-Received: from *linkedin.com*\r\n', 3, False),
         ('X-Git-Module: rhq.*git', 6, False),
         ('Approved: verysecretpassword', 6, False),
         ('^Subject: dev-\r\n^Subject: staging-', 3, False),
         ('from: .*[email protected]\r\nfrom: .*@jw-express.com',
          2, False),
         ('^Received: from smtp-.*\\.fedoraproject\\.org\r\n'
          '^Received: from mx.*\\.redhat.com\r\n'
          '^Resent-date:\r\n'
          '^Resent-from:\r\n'
          '^Resent-Message-ID:\r\n'
          '^Resent-to:\r\n'
          '^Subject: [^mtv]\r\n',
          7, False),
         ('^Received: from fedorahosted\\.org.*by fedorahosted\\.org\r\n'
          '^Received: from hosted.*\\.fedoraproject.org.*by '
          'hosted.*\\.fedoraproject\\.org\r\n'
          '^Received: from hosted.*\\.fedoraproject.org.*by '
             'fedoraproject\\.org\r\n'
          '^Received: from hosted.*\\.fedoraproject.org.*by '
             'fedorahosted\\.org',
          6, False),
         ]
     error_log = LogFileMark('mailman.error')
     self._import()
     self.assertListEqual(
         [(hm.header, hm.pattern, hm.chain)
          for hm in self._mlist.header_matches], [
             ('x-spam-status', 'Yes.*', 'discard'),
             ('x-spam-status', 'Yes', 'reject'),
             ('x-spam-level', '\\*\\*\\*.*$', 'discard'),
             ('x-spam-level', '\\*\\*', 'discard'),
             ('x-spam', '\\Yes', 'discard'),
             ('subject', '\\[SPAM\\].*', 'discard'),
             ('subject', '.*loan.*', 'discard'),
             ('original-received', 'from *linkedin.com*', 'discard'),
             ('x-git-module', 'rhq.*git', 'accept'),
             ('approved', 'verysecretpassword', 'accept'),
             ('subject', 'dev-', 'discard'),
             ('subject', 'staging-', 'discard'),
             ('from', '.*[email protected]', 'reject'),
             ('from', '.*@jw-express.com', 'reject'),
             ('received', 'from smtp-.*\\.fedoraproject\\.org', 'hold'),
             ('received', 'from mx.*\\.redhat.com', 'hold'),
             ('resent-date', '.*', 'hold'),
             ('resent-from', '.*', 'hold'),
             ('resent-message-id', '.*', 'hold'),
             ('resent-to', '.*', 'hold'),
             ('subject', '[^mtv]', 'hold'),
             ('received', 'from fedorahosted\\.org.*by fedorahosted\\.org',
              'accept'),
             ('received',
              'from hosted.*\\.fedoraproject.org.*by '
                 'hosted.*\\.fedoraproject\\.org', 'accept'),
             ('received',
              'from hosted.*\\.fedoraproject.org.*by '
                 'fedoraproject\\.org', 'accept'),
             ('received',
              'from hosted.*\\.fedoraproject.org.*by '
                 'fedorahosted\\.org', 'accept'),
             ])
     loglines = error_log.read().strip()
     self.assertEqual(len(loglines), 0)
Ejemplo n.º 34
0
    def test_non_ascii_in_ascii_part(self):
        # Subscribe some users receiving digests.
        anne = subscribe(self._mlist, 'Anne')
        anne.preferences.delivery_mode = DeliveryMode.mime_digests
        bart = subscribe(self._mlist, 'Bart')
        bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
        msg = message_from_bytes(
            b"""\
From: [email protected]
To: [email protected]
Subject: Non-ascii in ascii message
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="abcxyz"

--abcxyz
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 8bit

Don\xe2\x80\x99t try this at home.
--abcxyz--
""", Message)
        # Use any error logs as the error message if the test fails.
        error_log = LogFileMark('mailman.error')
        make_digest_messages(self._mlist, msg)
        # The runner will send the file to the shunt queue on exception.
        self.assertEqual(len(self._shuntq.files), 0, error_log.read())
        items = self._check_virgin_queue()
        self.assertEqual(
            self._get_plain_body(items), b"""\
Send Test mailing list submissions to
\[email protected]

To subscribe or unsubscribe via email, send a message with subject or
body 'help' to
\[email protected]

You can reach the person managing the list at
\[email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Test digest..."

Today\'s Topics:

   1. Non-ascii in ascii message ([email protected])


----------------------------------------------------------------------

Message: 1
From: [email protected]
Subject: Non-ascii in ascii message
To: [email protected]
Content-Type: multipart/mixed; boundary="abcxyz"

Don\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbdt try this at home.

------------------------------

Subject: Digest Footer

_______________________________________________
Test mailing list -- [email protected]
To unsubscribe send an email to [email protected]


------------------------------

End of Test Digest, Vol 1, Issue 1
**********************************
""")
Ejemplo n.º 35
0
 def test_header_matches(self):
     # This test containes real cases of header_filter_rules.
     self._pckdict['header_filter_rules'] = [
         ('X\\-Spam\\-Status\\: Yes.*', 3, False),
         ('^X-Spam-Status: Yes\r\n\r\n', 2, False),
         ('^X-Spam-Level: \\*\\*\\*.*$', 3, False),
         ('^X-Spam-Level:.\\*\\*\r\n^X-Spam:.Yes', 3, False),
         ('Subject: \\[SPAM\\].*', 3, False),
         ('^Subject: .*loan.*', 3, False),
         ('Original-Received: from *linkedin.com*\r\n', 3, False),
         ('X-Git-Module: rhq.*git', 6, False),
         ('Approved: verysecretpassword', 6, False),
         ('^Subject: dev-\r\n^Subject: staging-', 3, False),
         ('from: .*[email protected]\r\nfrom: .*@jw-express.com', 2,
          False),
         ('^Subject:.*\\Wwas:\\W', 3, False),
         ('^Received: from smtp-.*\\.fedoraproject\\.org\r\n'
          '^Received: from mx.*\\.redhat.com\r\n'
          '^Resent-date:\r\n'
          '^Resent-from:\r\n'
          '^Resent-Message-ID:\r\n'
          '^Resent-to:\r\n'
          '^Subject: [^mtv]\r\n', 7, False),
         ('^Received: from fedorahosted\\.org.*by fedorahosted\\.org\r\n'
          '^Received: from hosted.*\\.fedoraproject.org.*by '
          'hosted.*\\.fedoraproject\\.org\r\n'
          '^Received: from hosted.*\\.fedoraproject.org.*by '
          'fedoraproject\\.org\r\n'
          '^Received: from hosted.*\\.fedoraproject.org.*by '
          'fedorahosted\\.org', 6, False),
     ]
     error_log = LogFileMark('mailman.error')
     self._import()
     self.assertListEqual(
         [(hm.header, hm.pattern, hm.chain)
          for hm in self._mlist.header_matches], [
              ('x-spam-status', 'Yes.*', 'discard'),
              ('x-spam-status', 'Yes', 'reject'),
              ('x-spam-level', '\\*\\*\\*.*$', 'discard'),
              ('x-spam-level', '\\*\\*', 'discard'),
              ('x-spam', 'Yes', 'discard'),
              ('subject', '\\[SPAM\\].*', 'discard'),
              ('subject', '.*loan.*', 'discard'),
              ('original-received', 'from *linkedin.com*', 'discard'),
              ('x-git-module', 'rhq.*git', 'accept'),
              ('approved', 'verysecretpassword', 'accept'),
              ('subject', 'dev-', 'discard'),
              ('subject', 'staging-', 'discard'),
              ('from', '.*[email protected]', 'reject'),
              ('from', '.*@jw-express.com', 'reject'),
              ('subject', '\\Wwas:\\W', 'discard'),
              ('received', 'from smtp-.*\\.fedoraproject\\.org', 'hold'),
              ('received', 'from mx.*\\.redhat.com', 'hold'),
              ('resent-date', '.*', 'hold'),
              ('resent-from', '.*', 'hold'),
              ('resent-message-id', '.*', 'hold'),
              ('resent-to', '.*', 'hold'),
              ('subject', '[^mtv]', 'hold'),
              ('received', 'from fedorahosted\\.org.*by fedorahosted\\.org',
               'accept'),
              ('received', 'from hosted.*\\.fedoraproject.org.*by '
               'hosted.*\\.fedoraproject\\.org', 'accept'),
              ('received', 'from hosted.*\\.fedoraproject.org.*by '
               'fedoraproject\\.org', 'accept'),
              ('received', 'from hosted.*\\.fedoraproject.org.*by '
               'fedorahosted\\.org', 'accept'),
          ])
     loglines = error_log.read().strip()
     self.assertEqual(len(loglines), 0)