1 # Copyright (C) 2012-2015 by the Free Software Foundation, Inc.
3 # This file is part of GNU Mailman.
5 # GNU Mailman is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
10 # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 # You should have received a copy of the GNU General Public License along with
16 # GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
18 """Test some Runner base class behavior."""
27 from mailman
.app
.lifecycle
import create_list
28 from mailman
.config
import config
29 from mailman
.core
.runner
import Runner
30 from mailman
.interfaces
.member
import DeliveryMode
31 from mailman
.interfaces
.runner
import RunnerCrashEvent
32 from mailman
.runners
.virgin
import VirginRunner
33 from mailman
.testing
.helpers
import (
34 LogFileMark
, configuration
, event_subscribers
, get_queue_messages
,
35 make_digest_messages
, make_testable_runner
,
36 specialized_message_from_string
as mfs
,
38 from mailman
.testing
.layers
import ConfigLayer
42 class CrashingRunner(Runner
):
43 def _dispose(self
, mlist
, msg
, msgdata
):
44 raise RuntimeError('borked')
48 class TestRunner(unittest
.TestCase
):
49 """Test the Runner base class behavior."""
54 self
._mlist
= create_list('test@example.com')
57 def _got_event(self
, event
):
58 self
._events
.append(event
)
60 @configuration('runner.crashing',
61 **{'class': 'mailman.core.tests.CrashingRunner'})
62 def test_crash_event(self
):
63 runner
= make_testable_runner(CrashingRunner
, 'in')
64 # When an exception occurs in Runner._process_one_file(), a zope.event
65 # gets triggered containing the exception object.
67 From: anne@example.com
72 config
.switchboards
['in'].enqueue(msg
, listid
='test.example.com')
73 with
event_subscribers(self
._got
_event
):
75 # We should now have exactly one event, which will contain the
76 # exception, plus additional metadata containing the mailing list,
77 # message, and metadata.
78 self
.assertEqual(len(self
._events
), 1)
79 event
= self
._events
[0]
80 self
.assertTrue(isinstance(event
, RunnerCrashEvent
))
81 self
.assertEqual(event
.mailing_list
, self
._mlist
)
82 self
.assertEqual(event
.message
['message-id'], '<ant>')
83 self
.assertEqual(event
.metadata
['listid'], 'test.example.com')
84 self
.assertTrue(isinstance(event
.error
, RuntimeError))
85 self
.assertEqual(str(event
.error
), 'borked')
86 self
.assertTrue(isinstance(event
.runner
, CrashingRunner
))
87 # The message should also have ended up in the shunt queue.
88 shunted
= get_queue_messages('shunt')
89 self
.assertEqual(len(shunted
), 1)
90 self
.assertEqual(shunted
[0].msg
['message-id'], '<ant>')
92 def test_digest_messages(self
):
93 # In LP: #1130697, the digest runner creates MIME digests using the
94 # stdlib MIMEMutlipart class, however this class does not have the
95 # extended attributes we require (e.g. .sender). The fix is to use a
96 # subclass of MIMEMultipart and our own Message subclass; this adds
97 # back the required attributes. (LP: #1130696)
98 self
._mlist
.send_welcome_message
= False
99 # Subscribe some users receiving digests.
100 anne
= subscribe(self
._mlist
, 'Anne')
101 anne
.preferences
.delivery_mode
= DeliveryMode
.mime_digests
102 bart
= subscribe(self
._mlist
, 'Bart')
103 bart
.preferences
.delivery_mode
= DeliveryMode
.plaintext_digests
104 # Start by creating the raw ingredients for the digests. This also
105 # runs the digest runner, thus producing the digest messages into the
107 make_digest_messages(self
._mlist
)
108 # Run the virgin queue processor, which runs the cook-headers and
109 # to-outgoing handlers. This should produce no error.
110 error_log
= LogFileMark('mailman.error')
111 runner
= make_testable_runner(VirginRunner
, 'virgin')
113 error_text
= error_log
.read()
114 self
.assertEqual(len(error_text
), 0, error_text
)
115 self
.assertEqual(len(get_queue_messages('shunt')), 0)
116 messages
= get_queue_messages('out')
117 self
.assertEqual(len(messages
), 2)
118 # Which one is the MIME digest?
121 if bag
.msg
.get_content_type() == 'multipart/mixed':
122 assert mime_digest
is None, 'Found two MIME digests'
123 mime_digest
= bag
.msg
124 # The cook-headers handler ran.
125 self
.assertIn('x-mailman-version', mime_digest
)
126 self
.assertEqual(mime_digest
['precedence'], 'list')
127 # The list's -request address is the original sender.
128 self
.assertEqual(bag
.msgdata
['original_sender'],
129 'test-request@example.com')