Beispiel #1
0
    def test_no_action_defaults_to_site_wide_action(self):
        # If the list-specific header check matches, but there is no defined
        # action, the site-wide antispam action is used.
        msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: A message
Message-ID: <ant>
Foo: foo
MIME-Version: 1.0

A message body.
""")
        header_matches = IHeaderMatchList(self._mlist)
        header_matches.append('Foo', 'foo')
        # This event subscriber records the event that occurs when the message
        # is processed by the owner chain, which holds its for approval.
        events = []
        def record_holds(event):                    # noqa
            if not isinstance(event, HoldEvent):
                return
            events.append(event)
        with event_subscribers(record_holds):
            # Set the site-wide antispam action to hold the message.
            with configuration('antispam', header_checks="""
                Spam: [*]{3,}
                """, jump_chain='hold'):            # noqa
                process(self._mlist, msg, {}, start_chain='header-match')
            self.assertEqual(len(events), 1)
            event = events[0]
            self.assertIsInstance(event, HoldEvent)
            self.assertEqual(event.chain, config.chains['hold'])
            self.assertEqual(event.mlist, self._mlist)
            self.assertEqual(event.msg, msg)
        events = []
        def record_discards(event):                 # noqa
            if not isinstance(event, DiscardEvent):
                return
            events.append(event)
        with event_subscribers(record_discards):
            # Set the site-wide default to discard the message.
            msg.replace_header('Message-Id', '<bee>')
            with configuration('antispam', header_checks="""
                Spam: [*]{3,}
                """, jump_chain='discard'):         # noqa
                process(self._mlist, msg, {}, start_chain='header-match')
            self.assertEqual(len(events), 1)
            event = events[0]
            self.assertIsInstance(event, DiscardEvent)
            self.assertEqual(event.chain, config.chains['discard'])
            self.assertEqual(event.mlist, self._mlist)
            self.assertEqual(event.msg, msg)
Beispiel #2
0
    def test_crash_event(self):
        runner = make_testable_runner(CrashingRunner, 'in')
        # When an exception occurs in Runner._process_one_file(), a zope.event
        # gets triggered containing the exception object.
        msg = mfs("""\
From: [email protected]
To: [email protected]
Message-ID: <ant>

""")
        config.switchboards['in'].enqueue(msg, listid='test.example.com')
        with event_subscribers(self._got_event):
            runner.run()
        # We should now have exactly one event, which will contain the
        # exception, plus additional metadata containing the mailing list,
        # message, and metadata.
        self.assertEqual(len(self._events), 1)
        event = self._events[0]
        self.assertTrue(isinstance(event, RunnerCrashEvent))
        self.assertEqual(event.mailing_list, self._mlist)
        self.assertEqual(event.message['message-id'], '<ant>')
        self.assertEqual(event.metadata['listid'], 'test.example.com')
        self.assertTrue(isinstance(event.error, RuntimeError))
        self.assertEqual(str(event.error), 'borked')
        self.assertTrue(isinstance(event.runner, CrashingRunner))
        # The message should also have ended up in the shunt queue.
        shunted = get_queue_messages('shunt')
        self.assertEqual(len(shunted), 1)
        self.assertEqual(shunted[0].msg['message-id'], '<ant>')
Beispiel #3
0
    def test_priority_site_over_list(self):
        # Test that the site-wide checks take precedence over the list-specific
        # checks.
        msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: A message
Message-ID: <ant>
Foo: foo
MIME-Version: 1.0

A message body.
""")
        msgdata = {}
        header_matches = IHeaderMatchList(self._mlist)
        header_matches.append('Foo', 'foo', 'accept')
        # This event subscriber records the event that occurs when the message
        # is processed by the owner chain.
        events = []
        with event_subscribers(events.append):
            process(self._mlist, msg, msgdata, start_chain='header-match')
        self.assertEqual(len(events), 1)
        event = events[0]
        # Site-wide wants to hold the message, the list wants to accept it.
        self.assertIsInstance(event, HoldEvent)
        self.assertEqual(event.chain, config.chains['hold'])
Beispiel #4
0
 def test_create_list_event(self):
     # Test that creating a list in the list manager propagates the
     # expected events.
     with event_subscribers(self._record_event):
         mlist = getUtility(IListManager).create('*****@*****.**')
     self.assertEqual(len(self._events), 2)
     self.assertTrue(isinstance(self._events[0], ListCreatingEvent))
     self.assertEqual(self._events[0].fqdn_listname, '*****@*****.**')
     self.assertTrue(isinstance(self._events[1], ListCreatedEvent))
     self.assertEqual(self._events[1].mailing_list, mlist)
Beispiel #5
0
 def test_create_list_event(self):
     # Test that creating a list in the list manager propagates the
     # expected events.
     with event_subscribers(self._record_event):
         mlist = getUtility(IListManager).create('*****@*****.**')
     self.assertEqual(len(self._events), 2)
     self.assertIsInstance(self._events[0], ListCreatingEvent)
     self.assertEqual(self._events[0].fqdn_listname, '*****@*****.**')
     self.assertIsInstance(self._events[1], ListCreatedEvent)
     self.assertEqual(self._events[1].mailing_list, mlist)
Beispiel #6
0
 def test_create_domain_event(self):
     # Test that creating a domain in the domain manager propagates the
     # expected events.
     with event_subscribers(self._record_event):
         domain = self._manager.add('example.org')
     self.assertEqual(len(self._events), 2)
     self.assertTrue(isinstance(self._events[0], DomainCreatingEvent))
     self.assertEqual(self._events[0].mail_host, 'example.org')
     self.assertTrue(isinstance(self._events[1], DomainCreatedEvent))
     self.assertEqual(self._events[1].domain, domain)
Beispiel #7
0
 def test_create_domain_event(self):
     # Test that creating a domain in the domain manager propagates the
     # expected events.
     with event_subscribers(self._record_event):
         domain = getUtility(IDomainManager).add('example.org')
     self.assertEqual(len(self._events), 2)
     self.assertTrue(isinstance(self._events[0], DomainCreatingEvent))
     self.assertEqual(self._events[0].mail_host, 'example.org')
     self.assertTrue(isinstance(self._events[1], DomainCreatedEvent))
     self.assertEqual(self._events[1].domain, domain)
Beispiel #8
0
 def test_rule_hits(self):
     config.chains['mine'] = MyChain()
     self.addCleanup(config.chains.pop, 'mine')
     hits = None
     def handler(event):                         # noqa
         nonlocal hits
         if isinstance(event, AcceptEvent):
             hits = event.msg['x-mailman-rule-hits']
     with event_subscribers(handler):
         process_chain(self._mlist, self._msg, {}, start_chain='mine')
     self.assertEqual(hits, 'first; second; third')
Beispiel #9
0
 def test_delete_list_event(self):
     # Test that deleting a list in the list manager propagates the
     # expected event.
     mlist = create_list('*****@*****.**')
     with event_subscribers(self._record_event):
         getUtility(IListManager).delete(mlist)
     self.assertEqual(len(self._events), 2)
     self.assertTrue(isinstance(self._events[0], ListDeletingEvent))
     self.assertEqual(self._events[0].mailing_list, mlist)
     self.assertTrue(isinstance(self._events[1], ListDeletedEvent))
     self.assertEqual(self._events[1].fqdn_listname, '*****@*****.**')
Beispiel #10
0
 def test_rule_hits(self):
     config.chains['mine'] = MyChain()
     self.addCleanup(config.chains.pop, 'mine')
     hits = None
     def handler(event):                                # noqa: E306
         nonlocal hits
         if isinstance(event, AcceptEvent):
             hits = event.msg['x-mailman-rule-hits']
     with event_subscribers(handler):
         process_chain(self._mlist, self._msg, {}, start_chain='mine')
     self.assertEqual(hits, 'first; second; third')
Beispiel #11
0
 def test_delete_list_event(self):
     # Test that deleting a list in the list manager propagates the
     # expected event.
     mlist = create_list('*****@*****.**')
     with event_subscribers(self._record_event):
         getUtility(IListManager).delete(mlist)
     self.assertEqual(len(self._events), 2)
     self.assertIsInstance(self._events[0], ListDeletingEvent)
     self.assertEqual(self._events[0].mailing_list, mlist)
     self.assertIsInstance(self._events[1], ListDeletedEvent)
     self.assertEqual(self._events[1].fqdn_listname, '*****@*****.**')
Beispiel #12
0
 def test_delete_domain_event(self):
     # Test that deleting a domain in the domain manager propagates the
     # expected event.
     domain = self._manager.add('example.org')
     with event_subscribers(self._record_event):
         self._manager.remove('example.org')
     self.assertEqual(len(self._events), 2)
     self.assertIsInstance(self._events[0], DomainDeletingEvent)
     self.assertEqual(self._events[0].domain, domain)
     self.assertIsInstance(self._events[1], DomainDeletedEvent)
     self.assertEqual(self._events[1].mail_host, 'example.org')
Beispiel #13
0
 def test_delete_domain_event(self):
     # Test that deleting a domain in the domain manager propagates the
     # expected event.
     domain = self._manager.add('example.org')
     with event_subscribers(self._record_event):
         self._manager.remove('example.org')
     self.assertEqual(len(self._events), 2)
     self.assertTrue(isinstance(self._events[0], DomainDeletingEvent))
     self.assertEqual(self._events[0].domain, domain)
     self.assertTrue(isinstance(self._events[1], DomainDeletedEvent))
     self.assertEqual(self._events[1].mail_host, 'example.org')
Beispiel #14
0
 def test_token(self):
     # Registering the email address returns a token, and this token links
     # back to the pendable.
     captured_events = []
     def capture_event(event):
         captured_events.append(event)
     with event_subscribers(capture_event):
         token = self.registrar.register(self.mlist, '*****@*****.**')
     self.assertEqual(len(captured_events), 1)
     event = captured_events[0]
     self.assertEqual(event.token, token)
     pending = getUtility(IPendings).confirm(token)
     self.assertEqual(pending, event.pendable)
Beispiel #15
0
 def test_event_pendable(self):
     # The event has an IPendable which contains additional information.
     def capture_event(event):
         pendable = event.pendable
         self.assertEqual(pendable['type'], 'registration')
         self.assertEqual(pendable['email'], '*****@*****.**')
         # The key is present, but the value is None.
         self.assertIsNone(pendable['display_name'])
         # The default is regular delivery.
         self.assertEqual(pendable['delivery_mode'], 'regular')
         self.assertEqual(pendable['list_id'], 'alpha.example.com')
     with event_subscribers(capture_event):
         self.registrar.register(self.mlist, '*****@*****.**')
 def test_push_and_pop_trigger_events(self):
     # Pushing a new configuration onto the stack triggers a
     # post-processing event.
     events = []
     def on_event(event):
         if isinstance(event, ConfigurationUpdatedEvent):
             # Record both the event and the top overlay.
             events.append(event.config.overlays[0].name)
     # Do two pushes, and then pop one of them.
     with event_subscribers(on_event):
         with configuration('test', _configname='first'):
             with configuration('test', _configname='second'):
                 pass
             self.assertEqual(events, ['first', 'second', 'first'])
Beispiel #17
0
    def test_discard(self):
        msgdata = dict(dmarc_action='discard')
        # When a message is discarded, the only artifacts are a log message
        # and an event.  Catch the event to prove it happened.
        events = []

        def handler(event):  # noqa: E306
            if isinstance(event, DiscardEvent):
                events.append(event)

        with event_subscribers(handler):
            process_chain(self._mlist, self._msg, msgdata, start_chain='dmarc')
        self.assertEqual(len(events), 1)
        self.assertIs(events[0].msg, self._msg)
    def test_event_pendable(self):
        # The event has an IPendable which contains additional information.
        def capture_event(event):
            pendable = event.pendable
            self.assertEqual(pendable['type'], 'registration')
            self.assertEqual(pendable['email'], '*****@*****.**')
            # The key is present, but the value is None.
            self.assertIsNone(pendable['display_name'])
            # The default is regular delivery.
            self.assertEqual(pendable['delivery_mode'], 'regular')
            self.assertEqual(pendable['list_id'], 'alpha.example.com')

        with event_subscribers(capture_event):
            self.registrar.register(self.mlist, '*****@*****.**')
Beispiel #19
0
 def test_push_and_pop_trigger_events(self):
     # Pushing a new configuration onto the stack triggers a
     # post-processing event.
     events = []
     def on_event(event):                                     # noqa: E306
         if isinstance(event, ConfigurationUpdatedEvent):
             # Record both the event and the top overlay.
             events.append(event.config.overlays[0].name)
     # Do two pushes, and then pop one of them.
     with event_subscribers(on_event):
         with configuration('test', _configname='first'):
             with configuration('test', _configname='second'):
                 pass
             self.assertEqual(events, ['first', 'second', 'first'])
    def test_token(self):
        # Registering the email address returns a token, and this token links
        # back to the pendable.
        captured_events = []

        def capture_event(event):
            captured_events.append(event)

        with event_subscribers(capture_event):
            token = self.registrar.register(self.mlist, '*****@*****.**')
        self.assertEqual(len(captured_events), 1)
        event = captured_events[0]
        self.assertEqual(event.token, token)
        pending = getUtility(IPendings).confirm(token)
        self.assertEqual(pending, event.pendable)
Beispiel #21
0
 def test_push_and_pop_trigger_events(self):
     # Pushing a new configuration onto the stack triggers a
     # post-processing event.
     events = []
     def on_event(event):
         if isinstance(event, ConfigurationUpdatedEvent):
             # Record both the event and the top overlay.
             events.append(event.config.overlays[0].name)
     with event_subscribers(on_event):
         with configuration('test', _configname='my test'):
             pass
     # There should be two pushed configuration names on the list now, one
     # for the push leaving 'my test' on the top of the stack, and one for
     # the pop, leaving the ConfigLayer's 'test config' on top.
     self.assertEqual(events, ['my test', 'test config'])
Beispiel #22
0
 def test_owner_pipeline(self):
     # Messages processed through the default owners chain end up in the
     # pipeline queue, and an event gets sent.
     #
     # This event subscriber records the event that occurs when the message
     # is processed by the owner chain.
     events = []
     def catch_event(event):                                  # noqa: E306
         if isinstance(event, AcceptOwnerEvent):
             events.append(event)
     with event_subscribers(catch_event):
         process(self._mlist, self._msg, {}, 'default-owner-chain')
     self.assertEqual(len(events), 1)
     event = events[0]
     self.assertIsInstance(event, AcceptOwnerEvent)
     self.assertEqual(event.mlist, self._mlist)
     self.assertEqual(event.msg['message-id'], '<ant>')
     self.assertIsInstance(event.chain, BuiltInOwnerChain)
     items = get_queue_messages('pipeline', expected_count=1)
     message = items[0].msg
     self.assertEqual(message['message-id'], '<ant>')
Beispiel #23
0
 def test_owner_pipeline(self):
     # Messages processed through the default owners chain end up in the
     # pipeline queue, and an event gets sent.
     #
     # This event subscriber records the event that occurs when the message
     # is processed by the owner chain.
     events = []
     def catch_event(event):                                 # noqa
         if isinstance(event, AcceptOwnerEvent):
             events.append(event)
     with event_subscribers(catch_event):
         process(self._mlist, self._msg, {}, 'default-owner-chain')
     self.assertEqual(len(events), 1)
     event = events[0]
     self.assertIsInstance(event, AcceptOwnerEvent)
     self.assertEqual(event.mlist, self._mlist)
     self.assertEqual(event.msg['message-id'], '<ant>')
     self.assertIsInstance(event.chain, BuiltInOwnerChain)
     items = get_queue_messages('pipeline', expected_count=1)
     message = items[0].msg
     self.assertEqual(message['message-id'], '<ant>')
Beispiel #24
0
    def test_header_in_subpart(self):
        # Test that headers in sub-parts are also matched.
        msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: A message
Message-ID: <ant>
Foo: foo
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="================12345=="

--================12345==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

A message body.

--================12345==
Content-Type: application/junk
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

This is junk

--================12345==--
""")
        msgdata = {}
        header_matches = IHeaderMatchList(self._mlist)
        header_matches.append('Content-Type', 'application/junk', 'hold')
        # This event subscriber records the event that occurs when the message
        # is processed by the owner chain.
        events = []
        with event_subscribers(events.append):
            process(self._mlist, msg, msgdata, start_chain='header-match')
        self.assertEqual(len(events), 1)
        event = events[0]
        self.assertIsInstance(event, HoldEvent)
        self.assertEqual(event.chain, config.chains['hold'])
Beispiel #25
0
    def test_get_all_returns_non_string(self):
        # Test case where msg.get_all() returns header instance.
        msg = message_from_bytes(b"""\
From: [email protected]
To: [email protected]
Subject: Bad \x96 subject
Message-ID: <ant>

body

""", Message)
        msgdata = {}
        header_matches = IHeaderMatchList(self._mlist)
        header_matches.append('Subject', 'Bad', 'hold')
        # This event subscriber records the event that occurs when the message
        # is processed by the owner chain.
        events = []
        with event_subscribers(events.append):
            process(self._mlist, msg, msgdata, start_chain='header-match')
        self.assertEqual(len(events), 1)
        event = events[0]
        self.assertIsInstance(event, HoldEvent)
        self.assertEqual(event.chain, config.chains['hold'])
    def test_rfc2047_encodedheader(self):
        # Test case where msg.get_all() returns raw rfc2047 encoded string.
        msg = message_from_bytes(
            b"""\
From: [email protected]
To: [email protected]
Subject: =?utf-8?b?SSBsaWtlIElrZQo=?=
Message-ID: <ant>

body

""", Message)
        msgdata = {}
        header_matches = IHeaderMatchList(self._mlist)
        header_matches.append('Subject', 'I Like Ike', 'hold')
        # This event subscriber records the event that occurs when the message
        # is processed by the owner chain.
        events = []
        with event_subscribers(events.append):
            process(self._mlist, msg, msgdata, start_chain='header-match')
        self.assertEqual(len(events), 1)
        event = events[0]
        self.assertIsInstance(event, HoldEvent)
        self.assertEqual(event.chain, config.chains['hold'])
Beispiel #27
0
 def test_confirmation_event_received(self):
     # Registering an email address generates an event.
     def capture_event(event):
         self.assertIsInstance(event, ConfirmationNeededEvent)
     with event_subscribers(capture_event):
         self.registrar.register(self.mlist, '*****@*****.**')
Beispiel #28
0
 def test_event_mlist(self):
     # The event has a reference to the mailing list being subscribed to.
     def capture_event(event):
         self.assertIs(event.mlist, self.mlist)
     with event_subscribers(capture_event):
         self.registrar.register(self.mlist, '*****@*****.**')