Add a test and a fix for the no-args version of `mailman send-digests`.
[mailman.git] / src / mailman / commands / tests / test_send_digests.py
blobd0218ea126a218ccac4bad20f147e5cb3c2d885e
1 # Copyright (C) 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)
8 # any later version.
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
13 # more details.
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 the send-digests subcommand."""
20 __all__ = [
21 'TestSendDigests',
25 import os
26 import unittest
28 from io import StringIO
29 from mailman.app.lifecycle import create_list
30 from mailman.commands.cli_send_digests import Send
31 from mailman.config import config
32 from mailman.interfaces.member import DeliveryMode
33 from mailman.runners.digest import DigestRunner
34 from mailman.testing.helpers import (
35 get_queue_messages, make_testable_runner,
36 specialized_message_from_string as mfs, subscribe)
37 from mailman.testing.layers import ConfigLayer
38 from unittest.mock import patch
42 class FakeArgs:
43 def __init__(self):
44 self.lists = []
48 class TestSendDigests(unittest.TestCase):
49 """Test the send-digests subcommand."""
51 layer = ConfigLayer
53 def setUp(self):
54 self._mlist = create_list('ant@example.com')
55 self._mlist.digests_enabled = True
56 self._mlist.digest_size_threshold = 100000
57 self._mlist.send_welcome_message = False
58 self._command = Send()
59 self._handler = config.handlers['to-digest']
60 self._runner = make_testable_runner(DigestRunner, 'digest')
61 # The mailing list needs at least one digest recipient.
62 member = subscribe(self._mlist, 'Anne')
63 member.preferences.delivery_mode = DeliveryMode.plaintext_digests
65 def test_send_one_digest_by_list_id(self):
66 msg = mfs("""\
67 To: ant@example.com
68 From: anne@example.com
69 Subject: message 1
71 """)
72 self._handler.process(self._mlist, msg, {})
73 del msg['subject']
74 msg['subject'] = 'message 2'
75 self._handler.process(self._mlist, msg, {})
76 # There are no digests already being sent, but the ant mailing list
77 # does have a digest mbox collecting messages.
78 items = get_queue_messages('digest')
79 self.assertEqual(len(items), 0)
80 mailbox_path = os.path.join(self._mlist.data_path, 'digest.mmdf')
81 self.assertGreater(os.path.getsize(mailbox_path), 0)
82 args = FakeArgs()
83 args.lists.append('ant.example.com')
84 self._command.process(args)
85 self._runner.run()
86 # Now, there's no digest mbox and there's a plaintext digest in the
87 # outgoing queue.
88 self.assertFalse(os.path.exists(mailbox_path))
89 items = get_queue_messages('virgin')
90 self.assertEqual(len(items), 1)
91 digest_contents = str(items[0].msg)
92 self.assertIn('Subject: message 1', digest_contents)
93 self.assertIn('Subject: message 2', digest_contents)
95 def test_send_one_digest_by_fqdn_listname(self):
96 msg = mfs("""\
97 To: ant@example.com
98 From: anne@example.com
99 Subject: message 1
101 """)
102 self._handler.process(self._mlist, msg, {})
103 del msg['subject']
104 msg['subject'] = 'message 2'
105 self._handler.process(self._mlist, msg, {})
106 # There are no digests already being sent, but the ant mailing list
107 # does have a digest mbox collecting messages.
108 items = get_queue_messages('digest')
109 self.assertEqual(len(items), 0)
110 mailbox_path = os.path.join(self._mlist.data_path, 'digest.mmdf')
111 self.assertGreater(os.path.getsize(mailbox_path), 0)
112 args = FakeArgs()
113 args.lists.append('ant@example.com')
114 self._command.process(args)
115 self._runner.run()
116 # Now, there's no digest mbox and there's a plaintext digest in the
117 # outgoing queue.
118 self.assertFalse(os.path.exists(mailbox_path))
119 items = get_queue_messages('virgin')
120 self.assertEqual(len(items), 1)
121 digest_contents = str(items[0].msg)
122 self.assertIn('Subject: message 1', digest_contents)
123 self.assertIn('Subject: message 2', digest_contents)
125 def test_send_one_digest_to_missing_list_id(self):
126 msg = mfs("""\
127 To: ant@example.com
128 From: anne@example.com
129 Subject: message 1
131 """)
132 self._handler.process(self._mlist, msg, {})
133 del msg['subject']
134 msg['subject'] = 'message 2'
135 self._handler.process(self._mlist, msg, {})
136 # There are no digests already being sent, but the ant mailing list
137 # does have a digest mbox collecting messages.
138 items = get_queue_messages('digest')
139 self.assertEqual(len(items), 0)
140 mailbox_path = os.path.join(self._mlist.data_path, 'digest.mmdf')
141 self.assertGreater(os.path.getsize(mailbox_path), 0)
142 args = FakeArgs()
143 args.lists.append('bee.example.com')
144 stderr = StringIO()
145 with patch('mailman.commands.cli_send_digests.sys.stderr', stderr):
146 self._command.process(args)
147 self._runner.run()
148 # The warning was printed to stderr.
149 self.assertEqual(stderr.getvalue(),
150 'No such list found: bee.example.com\n')
151 # And no digest was prepared.
152 self.assertGreater(os.path.getsize(mailbox_path), 0)
153 items = get_queue_messages('virgin')
154 self.assertEqual(len(items), 0)
156 def test_send_one_digest_to_missing_fqdn_listname(self):
157 msg = mfs("""\
158 To: ant@example.com
159 From: anne@example.com
160 Subject: message 1
162 """)
163 self._handler.process(self._mlist, msg, {})
164 del msg['subject']
165 msg['subject'] = 'message 2'
166 self._handler.process(self._mlist, msg, {})
167 # There are no digests already being sent, but the ant mailing list
168 # does have a digest mbox collecting messages.
169 items = get_queue_messages('digest')
170 self.assertEqual(len(items), 0)
171 mailbox_path = os.path.join(self._mlist.data_path, 'digest.mmdf')
172 self.assertGreater(os.path.getsize(mailbox_path), 0)
173 args = FakeArgs()
174 args.lists.append('bee@example.com')
175 stderr = StringIO()
176 with patch('mailman.commands.cli_send_digests.sys.stderr', stderr):
177 self._command.process(args)
178 self._runner.run()
179 # The warning was printed to stderr.
180 self.assertEqual(stderr.getvalue(),
181 'No such list found: bee@example.com\n')
182 # And no digest was prepared.
183 self.assertGreater(os.path.getsize(mailbox_path), 0)
184 items = get_queue_messages('virgin')
185 self.assertEqual(len(items), 0)
187 def test_send_digest_to_one_missing_and_one_existing_list(self):
188 msg = mfs("""\
189 To: ant@example.com
190 From: anne@example.com
191 Subject: message 1
193 """)
194 self._handler.process(self._mlist, msg, {})
195 del msg['subject']
196 msg['subject'] = 'message 2'
197 self._handler.process(self._mlist, msg, {})
198 # There are no digests already being sent, but the ant mailing list
199 # does have a digest mbox collecting messages.
200 items = get_queue_messages('digest')
201 self.assertEqual(len(items), 0)
202 mailbox_path = os.path.join(self._mlist.data_path, 'digest.mmdf')
203 self.assertGreater(os.path.getsize(mailbox_path), 0)
204 args = FakeArgs()
205 args.lists.extend(('ant.example.com', 'bee.example.com'))
206 stderr = StringIO()
207 with patch('mailman.commands.cli_send_digests.sys.stderr', stderr):
208 self._command.process(args)
209 self._runner.run()
210 # The warning was printed to stderr.
211 self.assertEqual(stderr.getvalue(),
212 'No such list found: bee.example.com\n')
213 # But ant's digest was still prepared.
214 self.assertFalse(os.path.exists(mailbox_path))
215 items = get_queue_messages('virgin')
216 self.assertEqual(len(items), 1)
217 digest_contents = str(items[0].msg)
218 self.assertIn('Subject: message 1', digest_contents)
219 self.assertIn('Subject: message 2', digest_contents)
221 def test_send_digests_for_two_lists(self):
222 # Populate ant's digest.
223 msg = mfs("""\
224 To: ant@example.com
225 From: anne@example.com
226 Subject: message 1
228 """)
229 self._handler.process(self._mlist, msg, {})
230 del msg['subject']
231 msg['subject'] = 'message 2'
232 self._handler.process(self._mlist, msg, {})
233 # Create the second list.
234 bee = create_list('bee@example.com')
235 bee.digests_enabled = True
236 bee.digest_size_threshold = 100000
237 bee.send_welcome_message = False
238 member = subscribe(bee, 'Bart')
239 member.preferences.delivery_mode = DeliveryMode.plaintext_digests
240 # Populate bee's digest.
241 msg = mfs("""\
242 To: bee@example.com
243 From: bart@example.com
244 Subject: message 3
246 """)
247 self._handler.process(bee, msg, {})
248 del msg['subject']
249 msg['subject'] = 'message 4'
250 self._handler.process(bee, msg, {})
251 # There are no digests for either list already being sent, but the
252 # mailing lists do have a digest mbox collecting messages.
253 ant_mailbox_path = os.path.join(self._mlist.data_path, 'digest.mmdf')
254 self.assertGreater(os.path.getsize(ant_mailbox_path), 0)
255 # Check bee's digest.
256 bee_mailbox_path = os.path.join(bee.data_path, 'digest.mmdf')
257 self.assertGreater(os.path.getsize(bee_mailbox_path), 0)
258 # Both.
259 items = get_queue_messages('digest')
260 self.assertEqual(len(items), 0)
261 # Process both list's digests.
262 args = FakeArgs()
263 args.lists.extend(('ant.example.com', 'bee@example.com'))
264 self._command.process(args)
265 self._runner.run()
266 # Now, neither list has a digest mbox and but there are plaintext
267 # digest in the outgoing queue for both.
268 self.assertFalse(os.path.exists(ant_mailbox_path))
269 self.assertFalse(os.path.exists(bee_mailbox_path))
270 items = get_queue_messages('virgin')
271 self.assertEqual(len(items), 2)
272 # Figure out which digest is going to ant and which to bee.
273 if items[0].msg['to'] == 'ant@example.com':
274 ant = items[0].msg
275 bee = items[1].msg
276 else:
277 assert items[0].msg['to'] == 'bee@example.com'
278 ant = items[1].msg
279 bee = items[0].msg
280 # Check ant's digest.
281 digest_contents = str(ant)
282 self.assertIn('Subject: message 1', digest_contents)
283 self.assertIn('Subject: message 2', digest_contents)
284 # Check bee's digest.
285 digest_contents = str(bee)
286 self.assertIn('Subject: message 3', digest_contents)
287 self.assertIn('Subject: message 4', digest_contents)
289 def test_send_digests_for_all_lists(self):
290 # Populate ant's digest.
291 msg = mfs("""\
292 To: ant@example.com
293 From: anne@example.com
294 Subject: message 1
296 """)
297 self._handler.process(self._mlist, msg, {})
298 del msg['subject']
299 msg['subject'] = 'message 2'
300 self._handler.process(self._mlist, msg, {})
301 # Create the second list.
302 bee = create_list('bee@example.com')
303 bee.digests_enabled = True
304 bee.digest_size_threshold = 100000
305 bee.send_welcome_message = False
306 member = subscribe(bee, 'Bart')
307 member.preferences.delivery_mode = DeliveryMode.plaintext_digests
308 # Populate bee's digest.
309 msg = mfs("""\
310 To: bee@example.com
311 From: bart@example.com
312 Subject: message 3
314 """)
315 self._handler.process(bee, msg, {})
316 del msg['subject']
317 msg['subject'] = 'message 4'
318 self._handler.process(bee, msg, {})
319 # There are no digests for either list already being sent, but the
320 # mailing lists do have a digest mbox collecting messages.
321 ant_mailbox_path = os.path.join(self._mlist.data_path, 'digest.mmdf')
322 self.assertGreater(os.path.getsize(ant_mailbox_path), 0)
323 # Check bee's digest.
324 bee_mailbox_path = os.path.join(bee.data_path, 'digest.mmdf')
325 self.assertGreater(os.path.getsize(bee_mailbox_path), 0)
326 # Both.
327 items = get_queue_messages('digest')
328 self.assertEqual(len(items), 0)
329 # Process all mailing list digests by not setting any arguments.
330 self._command.process(FakeArgs())
331 self._runner.run()
332 # Now, neither list has a digest mbox and but there are plaintext
333 # digest in the outgoing queue for both.
334 self.assertFalse(os.path.exists(ant_mailbox_path))
335 self.assertFalse(os.path.exists(bee_mailbox_path))
336 items = get_queue_messages('virgin')
337 self.assertEqual(len(items), 2)
338 # Figure out which digest is going to ant and which to bee.
339 if items[0].msg['to'] == 'ant@example.com':
340 ant = items[0].msg
341 bee = items[1].msg
342 else:
343 assert items[0].msg['to'] == 'bee@example.com'
344 ant = items[1].msg
345 bee = items[0].msg
346 # Check ant's digest.
347 digest_contents = str(ant)
348 self.assertIn('Subject: message 1', digest_contents)
349 self.assertIn('Subject: message 2', digest_contents)
350 # Check bee's digest.
351 digest_contents = str(bee)
352 self.assertIn('Subject: message 3', digest_contents)
353 self.assertIn('Subject: message 4', digest_contents)