예제 #1
0
    def test_no_detectable_bounce_addresses(self):
        # A bounce message was received, but no addresses could be detected.
        # A message will be logged in the bounce log though, and the message
        # can be forwarded to someone who can do something about it.
        self._mlist.forward_unrecognized_bounces_to = (
            UnrecognizedBounceDisposition.site_owner)
        bogus = message_from_string("""\
From: [email protected]
To: [email protected]
Message-Id: <third>

""")
        self._bounceq.enqueue(bogus, self._msgdata)
        mark = LogFileMark('mailman.bounce')
        self._runner.run()
        self.assertEqual(len(get_queue_messages('bounces')), 0)
        events = list(self._processor.events)
        self.assertEqual(len(events), 0)
        line = mark.readline()
        self.assertEqual(
            line[-51:-1],
            'Bounce message w/no discernable addresses: <third>')
        # Here's the forwarded message to the site owners.
        forwards = get_queue_messages('virgin')
        self.assertEqual(len(forwards), 1)
        self.assertEqual(forwards[0].msg['to'], '*****@*****.**')
예제 #2
0
    def test_no_detectable_bounce_addresses(self):
        # A bounce message was received, but no addresses could be detected.
        # A message will be logged in the bounce log though, and the message
        # can be forwarded to someone who can do something about it.
        self._mlist.forward_unrecognized_bounces_to = (
            UnrecognizedBounceDisposition.site_owner)
        bogus = message_from_string("""\
From: [email protected]
To: [email protected]
Message-Id: <third>

""")
        self._bounceq.enqueue(bogus, 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)
        line = mark.readline()
        self.assertEqual(
            line[-51:-1],
            'Bounce message w/no discernable addresses: <third>')
        # Here's the forwarded message to the site owners.
        items = get_queue_messages('virgin', expected_count=1)
        self.assertEqual(items[0].msg['to'], '*****@*****.**')
예제 #3
0
파일: test_nntp.py 프로젝트: aregee/Mailman
 def test_connect_with_socket_failure(self, class_mock):
     self._nntpq.enqueue(self._msg, {}, listname='*****@*****.**')
     mark = LogFileMark('mailman.error')
     self._runner.run()
     log_message = mark.readline()[:-1]
     self.assertTrue(log_message.endswith(
         'NNTP socket error for [email protected]'))
예제 #4
0
    def test_bad_regexp(self):
        # Take a mark on the error log file.
        mark = LogFileMark('mailman.error')
        # A bad regexp in header_checks should just get ignored, but
        # with an error message logged.
        header_matches = IHeaderMatchList(self._mlist)
        header_matches.append('Foo', '+a bad regexp', 'reject')
        msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: A message
Message-ID: <ant>
Foo: foo
MIME-Version: 1.0

A message body.
""")
        msgdata = {}
        # This event subscriber records the event that occurs when the message
        # is processed by the header-match chain.
        events = []
        with event_subscribers(events.append):
            process(self._mlist, msg, msgdata, start_chain='header-match')
        self.assertEqual(len(events), 0)
        # Check the error log.
        self.assertEqual(mark.readline()[-89:-1],
                         "Invalid regexp '+a bad regexp' in header_matches "
                         'for test.example.com: nothing to repeat')
예제 #5
0
 def test_connect_with_socket_failure(self, class_mock):
     self._nntpq.enqueue(self._msg, {}, listid='test.example.com')
     mark = LogFileMark('mailman.error')
     self._runner.run()
     log_message = mark.readline()[:-1]
     self.assertTrue(
         log_message.endswith('NNTP socket error for [email protected]'))
예제 #6
0
 def test_bad_configuration_line(self):
     # Take a mark on the error log file.
     mark = LogFileMark('mailman.error')
     # A bad value in [antispam]header_checks should just get ignored, but
     # with an error message logged.
     chain = config.chains['header-match']
     # The links are created dynamically; the rule names will all start
     # with the same prefix, but have a variable suffix.  The actions will
     # all be to jump to the named chain.  Do these checks now, while we
     # collect other useful information.
     post_checks = []
     saw_any_rule = False
     for link in chain.get_links(self._mlist, Message(), {}):
         if link.rule.name == 'any':
             saw_any_rule = True
             self.assertEqual(link.action, LinkAction.jump)
         elif saw_any_rule:
             raise AssertionError("'any' rule was not last")
         else:
             self.assertEqual(link.rule.name[:13], 'header-match-')
             self.assertEqual(link.action, LinkAction.defer)
             post_checks.append((link.rule.header, link.rule.pattern))
     self.assertListEqual(post_checks, [
         ('Foo', 'foo'),
         ('Bar', 'bar'),
         ])
     # Check the error log.
     self.assertEqual(mark.readline()[-77:-1],
                      'Configuration error: [antispam]header_checks '
                      'contains bogus line: A-bad-line')
예제 #7
0
 def test_archive_lock_used(self):
     # Test that locking the maildir when adding works as a failure here
     # could mean we lose mail.
     lock_file = os.path.join(
         config.LOCK_DIR, '{0}-maildir.lock'.format(
             self._mlist.fqdn_listname))
     with Lock(lock_file):
         # Acquire the archiver lock, then make sure the archiver logs the
         # fact that it could not acquire the lock.
         archive_thread = threading.Thread(
             target=Prototype.archive_message,
             args=(self._mlist, self._msg))
         mark = LogFileMark('mailman.error')
         archive_thread.run()
         # Test that the archiver output the correct error.
         line = mark.readline()
         # XXX 2012-03-15 BAW: we really should remove timestamp prefixes
         # from the loggers when under test.
         self.assertTrue(line.endswith(
             'Unable to acquire prototype archiver lock for {0}, '
             'discarding: {1}\n'.format(
                 self._mlist.fqdn_listname,
                 self._msg.get('message-id'))))
     # Check that the message didn't get archived.
     created_files = self._find(config.ARCHIVE_DIR)
     self.assertEqual(self._expected_dir_structure, created_files)
예제 #8
0
 def test_bad_configuration_line(self):
     # Take a mark on the error log file.
     mark = LogFileMark('mailman.error')
     # A bad value in [antispam]header_checks should just get ignored, but
     # with an error message logged.
     chain = config.chains['header-match']
     # The links are created dynamically; the rule names will all start
     # with the same prefix, but have a variable suffix.  The actions will
     # all be to jump to the named chain.  Do these checks now, while we
     # collect other useful information.
     post_checks = []
     saw_any_rule = False
     for link in chain.get_links(self._mlist, Message(), {}):
         if link.rule.name == 'any':
             saw_any_rule = True
             self.assertEqual(link.action, LinkAction.jump)
         elif saw_any_rule:
             raise AssertionError("'any' rule was not last")
         else:
             self.assertEqual(link.rule.name[:13], 'header-match-')
             self.assertEqual(link.action, LinkAction.defer)
             post_checks.append((link.rule.header, link.rule.pattern))
     self.assertListEqual(post_checks, [
         ('Foo', 'foo'),
         ('Bar', 'bar'),
         ])
     # Check the error log.
     self.assertEqual(mark.readline()[-77:-1],
                      'Configuration error: [antispam]header_checks '
                      'contains bogus line: A-bad-line')
예제 #9
0
 def test_archive_lock_used(self):
     # Test that locking the maildir when adding works as a failure here
     # could mean we lose mail.
     lock_file = os.path.join(
         config.LOCK_DIR, '{0}-maildir.lock'.format(
             self._mlist.fqdn_listname))
     with Lock(lock_file):
         # Acquire the archiver lock, then make sure the archiver logs the
         # fact that it could not acquire the lock.
         archive_thread = threading.Thread(
             target=Prototype.archive_message,
             args=(self._mlist, self._msg))
         mark = LogFileMark('mailman.error')
         archive_thread.run()
         # Test that the archiver output the correct error.
         line = mark.readline()
         # XXX 2012-03-15 BAW: we really should remove timestamp prefixes
         # from the loggers when under test.
         self.assertTrue(line.endswith(
             'Unable to acquire prototype archiver lock for {0}, '
             'discarding: {1}\n'.format(
                 self._mlist.fqdn_listname,
                 self._msg.get('message-id'))))
     # Check that the message didn't get archived.
     created_files = self._find(config.ARCHIVE_DIR)
     self.assertEqual(self._expected_dir_structure, created_files)
예제 #10
0
 def test_discarding_pipeline(self):
     # If a handler in the pipeline raises DiscardMessage, the message will
     # be thrown away, but with a log message.
     mark = LogFileMark('mailman.vette')
     process(self._mlist, self._msg, {}, 'test-discarding')
     line = mark.readline()[:-1]
     self.assertTrue(line.endswith(
         '<ant> discarded by "test-discarding" pipeline handler '
         '"discarding": by test handler'))
예제 #11
0
 def test_discarding_pipeline(self):
     # If a handler in the pipeline raises DiscardMessage, the message will
     # be thrown away, but with a log message.
     mark = LogFileMark('mailman.vette')
     process(self._mlist, self._msg, {}, 'test-discarding')
     line = mark.readline()[:-1]
     self.assertTrue(line.endswith(
         '<ant> discarded by "test-discarding" pipeline handler '
         '"discarding": by test handler'))
예제 #12
0
 def test_header_matches_anything(self):
     # Check that a wild card header pattern is skipped.
     self._pckdict['header_filter_rules'] = [
         ('.*', 7, False),
         ]
     error_log = LogFileMark('mailman.error')
     self._import()
     self.assertListEqual(self._mlist.header_matches, [])
     self.assertIn('Unsupported header_filter_rules pattern',
                   error_log.readline())
예제 #13
0
 def test_header_matches_header_only(self):
     # Check that an empty pattern is skipped.
     self._pckdict['header_filter_rules'] = [
         ('SomeHeaderName', 3, False),
     ]
     error_log = LogFileMark('mailman.error')
     self._import()
     self.assertListEqual(self._mlist.header_matches, [])
     self.assertIn('Unsupported header_filter_rules pattern',
                   error_log.readline())
예제 #14
0
 def test_header_matches_anything(self):
     # Check that a wild card header pattern is skipped.
     self._pckdict['header_filter_rules'] = [
         ('.*', 7, False),
     ]
     error_log = LogFileMark('mailman.error')
     self._import()
     self.assertListEqual(self._mlist.header_matches, [])
     self.assertIn('Unsupported header_filter_rules pattern',
                   error_log.readline())
예제 #15
0
 def test_header_matches_invalid_re(self):
     # Check that an invalid regular expression pattern is skipped.
     self._pckdict['header_filter_rules'] = [
         ('SomeHeaderName: *invalid-re', 3, False),
         ]
     error_log = LogFileMark('mailman.error')
     self._import()
     self.assertListEqual(self._mlist.header_matches, [])
     self.assertIn('Skipping header_filter rule because of an invalid '
                   'regular expression', error_log.readline())
예제 #16
0
 def test_header_matches_invalid_re(self):
     # Check that an invalid regular expression pattern is skipped.
     self._pckdict['header_filter_rules'] = [
         ('SomeHeaderName: *invalid-re', 3, False),
         ]
     error_log = LogFileMark('mailman.error')
     self._import()
     self.assertListEqual(self._mlist.header_matches, [])
     self.assertIn('Skipping header_filter rule because of an invalid '
                   'regular expression', error_log.readline())
예제 #17
0
 def test_header_matches_header_only(self):
     # Check that an empty pattern is skipped.
     self._pckdict['header_filter_rules'] = [
         ('SomeHeaderName', 3, False),
         ]
     error_log = LogFileMark('mailman.error')
     self._import()
     self.assertListEqual(self._mlist.header_matches, [])
     self.assertIn('Unsupported header_filter_rules pattern',
                   error_log.readline())
예제 #18
0
 def test_maybe_forward_discard(self):
     # When forward_unrecognized_bounces_to is set to discard, no bounce
     # messages are forwarded.
     self._mlist.forward_unrecognized_bounces_to = (
         UnrecognizedBounceDisposition.discard)
     # The only artifact of this call is a log file entry.
     mark = LogFileMark('mailman.bounce')
     maybe_forward(self._mlist, self._msg)
     get_queue_messages('virgin', expected_count=0)
     line = mark.readline()
     self.assertEqual(line[-40:-1],
                      'Discarding unrecognized bounce: <first>')
예제 #19
0
 def test_header_matches_duplicate(self):
     # Check that duplicate patterns don't cause tracebacks.
     self._pckdict['header_filter_rules'] = [
         ('SomeHeaderName: test-pattern', 3, False),
         ('SomeHeaderName: test-pattern', 2, False),
     ]
     error_log = LogFileMark('mailman.error')
     self._import()
     self.assertListEqual([(hm.header, hm.pattern, hm.chain)
                           for hm in self._mlist.header_matches],
                          [('someheadername', 'test-pattern', 'discard')])
     self.assertIn('Skipping duplicate header_filter rule',
                   error_log.readline())
예제 #20
0
 def test_maybe_forward_discard(self):
     # When forward_unrecognized_bounces_to is set to discard, no bounce
     # messages are forwarded.
     self._mlist.forward_unrecognized_bounces_to = (
         UnrecognizedBounceDisposition.discard)
     # The only artifact of this call is a log file entry.
     mark = LogFileMark('mailman.bounce')
     maybe_forward(self._mlist, self._msg)
     get_queue_messages('virgin', expected_count=0)
     line = mark.readline()
     self.assertEqual(
         line[-40:-1],
         'Discarding unrecognized bounce: <first>')
예제 #21
0
 def test_bad_config_listname_chars(self):
     mark = LogFileMark('mailman.error')
     # This list create should succeed but log an error
     mlist = create_list('*****@*****.**')
     # Check the error log.
     self.assertRegex(
         mark.readline(),
         r'^.*Bad config\.mailman\.listname_chars setting: '
         r'\[a-z0-9-\+\\]: '
         '(unterminated character set|'
         'unexpected end of regular expression)$')
     # Check that the list was actually created.
     self.assertIs(os.path.isdir(mlist.data_path), True)
예제 #22
0
 def test_rejecting_pipeline(self):
     # If a handler in the pipeline raises DiscardMessage, the message will
     # be thrown away, but with a log message.
     mark = LogFileMark('mailman.vette')
     process(self._mlist, self._msg, {}, 'test-rejecting')
     line = mark.readline()[:-1]
     self.assertTrue(line.endswith(
         '<ant> rejected by "test-rejecting" pipeline handler '
         '"rejecting": by test handler'))
     # In the rejection case, the original message will also be in the
     # virgin queue.
     items = get_queue_messages('virgin', expected_count=1)
     self.assertEqual(str(items[0].msg['subject']), 'a test')
예제 #23
0
 def test_rejecting_pipeline(self):
     # If a handler in the pipeline raises DiscardMessage, the message will
     # be thrown away, but with a log message.
     mark = LogFileMark('mailman.vette')
     process(self._mlist, self._msg, {}, 'test-rejecting')
     line = mark.readline()[:-1]
     self.assertTrue(
         line.endswith(
             '<ant> rejected by "test-rejecting" pipeline handler '
             '"rejecting": by test handler'))
     # In the rejection case, the original message will also be in the
     # virgin queue.
     items = get_queue_messages('virgin', expected_count=1)
     self.assertEqual(str(items[0].msg['subject']), 'a test')
예제 #24
0
 def test_error_with_numeric_port(self):
     # Test the code path where a socket.error is raised in the delivery
     # function, and the MTA port is set to zero.  The only real effect of
     # that is a log message.  Start by opening the error log and reading
     # the current file position.
     mark = LogFileMark('mailman.error')
     self._outq.enqueue(self._msg, {}, listid='test.example.com')
     with configuration('mta', smtp_port=2112):
         self._runner.run()
     line = mark.readline()
     # The log line will contain a variable timestamp, the PID, and a
     # trailing newline.  Ignore these.
     self.assertEqual(
         line[-53:-1],
         'Cannot connect to SMTP server localhost on port 2112')
예제 #25
0
 def test_get_moderator_approval_log_on_hold(self):
     # When the subscription is held for moderator approval, a message is
     # logged.
     mark = LogFileMark('mailman.subscribe')
     self._mlist.subscription_policy = SubscriptionPolicy.moderate
     anne = self._user_manager.create_address(self._anne)
     workflow = SubscriptionWorkflow(self._mlist,
                                     anne,
                                     pre_verified=True,
                                     pre_confirmed=True)
     # Consume the entire state machine.
     list(workflow)
     self.assertIn(
         '[email protected]: held subscription request from [email protected]',
         mark.readline())
예제 #26
0
 def test_get_moderator_approval_log_on_hold(self):
     # When the subscription is held for moderator approval, a message is
     # logged.
     mark = LogFileMark('mailman.subscribe')
     self._mlist.subscription_policy = SubscriptionPolicy.moderate
     anne = self._user_manager.create_address(self._anne)
     workflow = SubscriptionWorkflow(self._mlist, anne,
                                     pre_verified=True,
                                     pre_confirmed=True)
     # Consume the entire state machine.
     list(workflow)
     self.assertIn(
        '[email protected]: held subscription request from [email protected]',
        mark.readline()
        )
예제 #27
0
 def test_header_matches_duplicate(self):
     # Check that duplicate patterns don't cause tracebacks.
     self._pckdict['header_filter_rules'] = [
         ('SomeHeaderName: test-pattern', 3, False),
         ('SomeHeaderName: test-pattern', 2, False),
         ]
     error_log = LogFileMark('mailman.error')
     self._import()
     self.assertListEqual(
         [(hm.header, hm.pattern, hm.chain)
          for hm in self._mlist.header_matches],
         [('someheadername', 'test-pattern', 'discard')]
         )
     self.assertIn('Skipping duplicate header_filter rule',
                   error_log.readline())
예제 #28
0
 def test_error_with_numeric_port(self):
     # Test the code path where a socket.error is raised in the delivery
     # function, and the MTA port is set to zero.  The only real effect of
     # that is a log message.  Start by opening the error log and reading
     # the current file position.
     mark = LogFileMark('mailman.error')
     self._outq.enqueue(self._msg, {}, listid='test.example.com')
     with configuration('mta', smtp_port=2112):
         self._runner.run()
     line = mark.readline()
     # The log line will contain a variable timestamp, the PID, and a
     # trailing newline.  Ignore these.
     self.assertEqual(
         line[-53:-1],
         'Cannot connect to SMTP server localhost on port 2112')
예제 #29
0
 def test_connect_with_other_failure(self, class_mock):
     # In this failure mode, the message stays queued, so we can only run
     # the nntp runner once.
     def once(runner):
         # I.e. stop immediately, since the queue will not be empty.
         return True
     runner = make_testable_runner(nntp.NNTPRunner, 'nntp', predicate=once)
     self._nntpq.enqueue(self._msg, {}, listid='test.example.com')
     mark = LogFileMark('mailman.error')
     runner.run()
     log_message = mark.readline()[:-1]
     self.assertTrue(log_message.endswith(
         'NNTP unexpected exception for [email protected]'))
     items = get_queue_messages('nntp', expected_count=1)
     self.assertEqual(items[0].msgdata['listid'], 'test.example.com')
     self.assertEqual(items[0].msg['subject'], 'A newsgroup posting')
예제 #30
0
 def test_bad_action(self):
     # This should never happen, but what if it does?
     # FilterAction.accept, FilterAction.hold, and FilterAction.defer are
     # not valid.  They are treated as discard actions, but the problem is
     # also logged.
     for action in (FilterAction.accept, FilterAction.hold,
                    FilterAction.defer):
         self._mlist.filter_action = action
         mark = LogFileMark('mailman.error')
         with self.assertRaises(errors.DiscardMessage) as cm:
             mime_delete.dispose(self._mlist, self._msg, {}, 'bad action')
         self.assertEqual(cm.exception.message, 'bad action')
         line = mark.readline()[:-1]
         self.assertTrue(
             line.endswith('{0} invalid FilterAction: [email protected].  '
                           'Treating as discard'.format(action.name)))
예제 #31
0
 def test_connect_with_other_failure(self, class_mock):
     # In this failure mode, the message stays queued, so we can only run
     # the nntp runner once.
     def once(runner):
         # I.e. stop immediately, since the queue will not be empty.
         return True
     runner = make_testable_runner(nntp.NNTPRunner, 'nntp', predicate=once)
     self._nntpq.enqueue(self._msg, {}, listid='test.example.com')
     mark = LogFileMark('mailman.error')
     runner.run()
     log_message = mark.readline()[:-1]
     self.assertTrue(log_message.endswith(
         'NNTP unexpected exception for [email protected]'))
     items = get_queue_messages('nntp', expected_count=1)
     self.assertEqual(items[0].msgdata['listid'], 'test.example.com')
     self.assertEqual(items[0].msg['subject'], 'A newsgroup posting')
예제 #32
0
 def test_header_matches_unsupported_action(self):
     # Check that unsupported actions are skipped.
     for action_num in (1, 4, 5):
         self._pckdict['header_filter_rules'] = [
             ('HeaderName: test-re', action_num, False),
         ]
         error_log = LogFileMark('mailman.error')
         self._import()
         self.assertListEqual(self._mlist.header_matches, [])
         self.assertIn('Unsupported header_filter_rules action',
                       error_log.readline())
         # Avoid a useless warning.
         for member in self._mlist.members.members:
             member.unsubscribe()
         for member in self._mlist.owners.members:
             member.unsubscribe()
예제 #33
0
 def test_header_matches_unsupported_action(self):
     # Check that unsupported actions are skipped.
     for action_num in (1, 4, 5):
         self._pckdict['header_filter_rules'] = [
             ('HeaderName: test-re', action_num, False),
             ]
         error_log = LogFileMark('mailman.error')
         self._import()
         self.assertListEqual(self._mlist.header_matches, [])
         self.assertIn('Unsupported header_filter_rules action',
                       error_log.readline())
         # Avoid a useless warning.
         for member in self._mlist.members.members:
             member.unsubscribe()
         for member in self._mlist.owners.members:
             member.unsubscribe()
예제 #34
0
 def test_get_moderator_approval_log_on_hold(self):
     # When the unsubscription is held for moderator approval, a message is
     # logged.
     mark = LogFileMark('mailman.subscribe')
     self._mlist.unsubscription_policy = SubscriptionPolicy.moderate
     workflow = UnSubscriptionWorkflow(self._mlist,
                                       self.anne,
                                       pre_confirmed=True)
     # Run the entire workflow.
     list(workflow)
     self.assertIn(
         '[email protected]: held unsubscription request from [email protected]',
         mark.readline())
     # The state machine stopped at the moderator approval step so there
     # will be one token still in the database.
     self._expected_pendings_count = 1
예제 #35
0
 def test_bad_action(self):
     # This should never happen, but what if it does?
     # FilterAction.accept, FilterAction.hold, and FilterAction.defer are
     # not valid.  They are treated as discard actions, but the problem is
     # also logged.
     for action in (FilterAction.accept,
                    FilterAction.hold,
                    FilterAction.defer):
         self._mlist.filter_action = action
         mark = LogFileMark('mailman.error')
         with self.assertRaises(errors.DiscardMessage) as cm:
             mime_delete.dispose(self._mlist, self._msg, {}, 'bad action')
         self.assertEqual(cm.exception.message, 'bad action')
         line = mark.readline()[:-1]
         self.assertTrue(line.endswith(
             '{0} invalid FilterAction: [email protected].  '
             'Treating as discard'.format(action.name)))
예제 #36
0
    def test_multiple_records(self):
        mlist = create_list('*****@*****.**')
        # Use action reject.  The rule only hits on reject and discard.
        mlist.dmarc_mitigate_action = DMARCMitigateAction.reject
        msg = mfs("""\
From: [email protected]
To: [email protected]

""")
        mark = LogFileMark('mailman.error')
        rule = dmarc.DMARCMitigation()
        with get_dns_resolver(rmult=True):
            self.assertTrue(rule.check(mlist, msg, {}))
        line = mark.readline()
        self.assertEqual(
            line[-85:], 'RRset of TXT records for _dmarc.example.biz has 2 '
            'v=DMARC1 entries; testing them all\n')
예제 #37
0
    def test_dmarc_nonameservers_exception(self):
        mlist = create_list('*****@*****.**')
        # Use action reject.  The rule only hits on reject and discard.
        mlist.dmarc_mitigate_action = DMARCMitigateAction.reject
        msg = mfs("""\
From: [email protected]
To: [email protected]

""")
        mark = LogFileMark('mailman.error')
        rule = dmarc.DMARCMitigation()
        with get_dns_resolver():
            self.assertTrue(rule.check(mlist, msg, {}))
        line = mark.readline()
        self.assertEqual(
            line[-84:], 'DNSException: No Nameservers available for '
            '[email protected] (_dmarc.example.home).\n')
예제 #38
0
 def test_rejecting_pipeline(self):
     # If a handler in the pipeline raises RejectMessage, the post will
     # be bounced with a log message.
     mark = LogFileMark('mailman.vette')
     process(self._mlist, self._msg, {}, 'test-rejecting')
     line = mark.readline()[:-1]
     self.assertEqual(
         line[-80:], '<ant> rejected by "test-rejecting" pipeline handler '
         '"rejecting": by test handler', line)
     # In the rejection case, the original message will also be in the
     # virgin queue.
     items = get_queue_messages('virgin', expected_count=1)
     self.assertEqual(
         str(items[0].msg.get_payload(1).get_payload(0)['subject']),
         'a test')
     # The first payload contains the rejection reason.
     payload = items[0].msg.get_payload(0).get_payload()
     self.assertEqual(payload, 'by test handler')
예제 #39
0
    def test_dmarc_dns_exception(self):
        mlist = create_list('*****@*****.**')
        # Use action reject.  The rule only hits on reject and discard.
        mlist.dmarc_mitigate_action = DMARCMitigateAction.reject
        msg = mfs("""\
From: [email protected]
To: [email protected]

""")
        mark = LogFileMark('mailman.error')
        rule = dmarc.DMARCMitigation()
        with get_dns_resolver():
            self.assertTrue(rule.check(mlist, msg, {}))
        line = mark.readline()
        self.assertEqual(
            line[-144:], 'DNSException: Unable to query DMARC policy for '
            '[email protected] (_dmarc.example.info). '
            'Abstract base class shared by all dnspython exceptions.\n')
예제 #40
0
    def test_looping_cnames(self):
        mlist = create_list('*****@*****.**')
        # Use action reject.  The rule only hits on reject and discard.
        mlist.dmarc_mitigate_action = DMARCMitigateAction.reject
        msg = mfs("""\
From: [email protected]
To: [email protected]

""")
        mark = LogFileMark('mailman.vette')
        rule = dmarc.DMARCMitigation()
        with get_dns_resolver(cloop=True):
            self.assertTrue(rule.check(mlist, msg, {}))
        line = mark.readline()
        self.assertEqual(
            line[-120:],
            'ant: DMARC lookup for [email protected] (_dmarc.example.biz) '
            'found p=reject in _dmarc.example.org. = v=DMARC1; p=reject;\n')
예제 #41
0
 def test_connection_got_two_quit_after_post_failure(self, class_mock):
     # The NNTP connection does get closed after a unsuccessful post.
     # Add a side-effect to the instance mock's .post() method.
     conn_mock = class_mock()
     conn_mock.post.side_effect = nntplib.NNTPTemporaryError
     self._nntpq.enqueue(self._msg, {}, listid='test.example.com')
     mark = LogFileMark('mailman.error')
     self._runner.run()
     # The connection object's post() method was called twice with a
     # file-like object containing the message's bytes.  The
     # NNTPTemporaryError is retried with a munged Message-ID because it
     # might have been due to a duplicate Message-ID.  Check that quit is
     # called twice.
     self.assertEqual(conn_mock.quit.call_count, 2)
     # There should be a log message with the original Message-ID.
     log_message = mark.readline()[:-1]
     self.assertTrue(
         log_message.endswith('<ant> NNTP error for [email protected]'),
         log_message)
예제 #42
0
    def test_missing_html_to_plain_text_command(self):
        # Calling a missing html_to_plain_text_command is properly logged.
        msg = mfs("""\
From: [email protected]
Content-Type: text/html
MIME-Version: 1.0

<html><head></head>
<body></body></html>
""")
        process = config.handlers['mime-delete'].process
        mark = LogFileMark('mailman.error')
        with dummy_script('nonexist'):
            process(self._mlist, msg, {})
        line = mark.readline()[:-1]
        self.assertTrue(line.endswith('HTML -> text/plain command error'))
        self.assertEqual(msg.get_content_type(), 'text/html')
        self.assertIsNone(msg['x-content-filtered-by'])
        payload_lines = msg.get_payload().splitlines()
        self.assertEqual(payload_lines[0], '<html><head></head>')
예제 #43
0
 def test_rejecting_pipeline_without_message(self):
     # Similar to above, but without a rejection message.
     pipeline = config.pipelines['test-rejecting']
     message = pipeline.message
     self.addCleanup(setattr, pipeline, 'message', message)
     pipeline.message = None
     mark = LogFileMark('mailman.vette')
     process(self._mlist, self._msg, {}, 'test-rejecting')
     line = mark.readline()[:-1]
     self.assertEqual(
         line[-91:], '<ant> rejected by "test-rejecting" pipeline handler '
         '"rejecting": [No details are available]', line)
     # In the rejection case, the original message will also be in the
     # virgin queue.
     items = get_queue_messages('virgin', expected_count=1)
     self.assertEqual(
         str(items[0].msg.get_payload(1).get_payload(0)['subject']),
         'a test')
     # The first payload contains the rejection reason.
     payload = items[0].msg.get_payload(0).get_payload()
     self.assertEqual(payload, '[No details are available]')
예제 #44
0
 def test_no_progress_on_retries_with_expired_retry_period(self):
     # We've had temporary failures with no progress, and the retry period
     # has expired.  In that case, a log entry is written and message is
     # discarded.  There's nothing more that can be done.
     temporary_failures.append('*****@*****.**')
     temporary_failures.append('*****@*****.**')
     retry_period = as_timedelta(config.mta.delivery_retry_period)
     deliver_until = datetime(2005, 8, 1, 7, 49, 23) + retry_period
     msgdata = dict(last_recip_count=2, deliver_until=deliver_until)
     self._outq.enqueue(self._msg, msgdata, listid='test.example.com')
     # Before the runner runs, several days pass.
     factory.fast_forward(retry_period.days + 1)
     mark = LogFileMark('mailman.smtp')
     self._runner.run()
     # There should be no message in the retry or outgoing queues.
     get_queue_messages('retry', expected_count=0)
     get_queue_messages('out', expected_count=0)
     # There should be a log message in the smtp log indicating that the
     # message has been discarded.
     line = mark.readline()
     self.assertEqual(
         line[-63:-1],
         'Discarding message with persistent temporary failures: <first>')
예제 #45
0
 def test_no_progress_on_retries_with_expired_retry_period(self):
     # We've had temporary failures with no progress, and the retry period
     # has expired.  In that case, a log entry is written and message is
     # discarded.  There's nothing more that can be done.
     temporary_failures.append('*****@*****.**')
     temporary_failures.append('*****@*****.**')
     retry_period = as_timedelta(config.mta.delivery_retry_period)
     deliver_until = datetime(2005, 8, 1, 7, 49, 23) + retry_period
     msgdata = dict(last_recip_count=2,
                    deliver_until=deliver_until)
     self._outq.enqueue(self._msg, msgdata, listid='test.example.com')
     # Before the runner runs, several days pass.
     factory.fast_forward(retry_period.days + 1)
     mark = LogFileMark('mailman.smtp')
     self._runner.run()
     # There should be no message in the retry or outgoing queues.
     get_queue_messages('retry', expected_count=0)
     get_queue_messages('out', expected_count=0)
     # There should be a log message in the smtp log indicating that the
     # message has been discarded.
     line = mark.readline()
     self.assertEqual(
         line[-63:-1],
         'Discarding message with persistent temporary failures: <first>')
예제 #46
0
 def test_dispose_discard_no_spurious_log(self):
     self._mlist.filter_action = FilterAction.discard
     mark = LogFileMark('mailman.error')
     with self.assertRaises(DiscardMessage):
         mime_delete.dispose(self._mlist, self._msg, {}, 'discarding')
     self.assertEqual(mark.readline(), '')