From 823721155a5e1a00026ac74d890adb531b0659b9 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sun, 6 Sep 2015 23:52:57 -0400 Subject: [PATCH] For now, treat `DeliveryMode.summary_digests` the same as `.mime_digests`. (Closes #141). Also, don't enqueue a particular digest if there are no recipients for that digest. --- src/mailman/core/tests/test_runner.py | 11 +++- src/mailman/handlers/tests/test_cook_headers.py | 9 ++- src/mailman/model/tests/test_member.py | 1 - src/mailman/runners/digest.py | 26 +++++---- src/mailman/runners/docs/digester.rst | 34 +++++++++-- src/mailman/runners/tests/test_digest.py | 78 ++++++++++++++++++++++++- 6 files changed, 138 insertions(+), 21 deletions(-) diff --git a/src/mailman/core/tests/test_runner.py b/src/mailman/core/tests/test_runner.py index 9e078ba29..0bf600477 100644 --- a/src/mailman/core/tests/test_runner.py +++ b/src/mailman/core/tests/test_runner.py @@ -27,12 +27,14 @@ import unittest from mailman.app.lifecycle import create_list from mailman.config import config from mailman.core.runner import Runner +from mailman.interfaces.member import DeliveryMode from mailman.interfaces.runner import RunnerCrashEvent from mailman.runners.virgin import VirginRunner from mailman.testing.helpers import ( LogFileMark, configuration, event_subscribers, get_queue_messages, make_digest_messages, make_testable_runner, - specialized_message_from_string as mfs) + specialized_message_from_string as mfs, + subscribe) from mailman.testing.layers import ConfigLayer @@ -93,7 +95,12 @@ Message-ID: # 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. diff --git a/src/mailman/handlers/tests/test_cook_headers.py b/src/mailman/handlers/tests/test_cook_headers.py index 193bf84b4..bb6e11cee 100644 --- a/src/mailman/handlers/tests/test_cook_headers.py +++ b/src/mailman/handlers/tests/test_cook_headers.py @@ -26,7 +26,9 @@ import unittest from mailman.app.lifecycle import create_list from mailman.handlers import cook_headers -from mailman.testing.helpers import get_queue_messages, make_digest_messages +from mailman.interfaces.member import DeliveryMode +from mailman.testing.helpers import ( + get_queue_messages, make_digest_messages, subscribe) from mailman.testing.layers import ConfigLayer @@ -38,9 +40,14 @@ class TestCookHeaders(unittest.TestCase): def setUp(self): self._mlist = create_list('test@example.com') + self._mlist.send_welcome_message = False def test_process_digest(self): # MIME digests messages are multiparts. + anne = subscribe(self._mlist, 'Anne') + anne.preferences.delivery_mode = DeliveryMode.mime_digests + bart = subscribe(self._mlist, 'Bart') + bart.preferences.delivery_mode = DeliveryMode.plaintext_digests make_digest_messages(self._mlist) messages = [bag.msg for bag in get_queue_messages('virgin')] self.assertEqual(len(messages), 2) diff --git a/src/mailman/model/tests/test_member.py b/src/mailman/model/tests/test_member.py index 4dfa4d6a6..3ad13b278 100644 --- a/src/mailman/model/tests/test_member.py +++ b/src/mailman/model/tests/test_member.py @@ -31,7 +31,6 @@ from mailman.interfaces.usermanager import IUserManager from mailman.model.member import Member from mailman.testing.layers import ConfigLayer from mailman.utilities.datetime import now - from zope.component import getUtility diff --git a/src/mailman/runners/digest.py b/src/mailman/runners/digest.py index ad6e0b1c5..388f7ffc2 100644 --- a/src/mailman/runners/digest.py +++ b/src/mailman/runners/digest.py @@ -358,7 +358,9 @@ class DigestRunner(Runner): email_address = member.address.original_email if member.delivery_mode == DeliveryMode.plaintext_digests: rfc1153_recipients.add(email_address) - elif member.delivery_mode == DeliveryMode.mime_digests: + # We currently treat summary_digests the same as mime_digests. + elif member.delivery_mode in (DeliveryMode.mime_digests, + DeliveryMode.summary_digests): mime_recipients.add(email_address) else: raise AssertionError( @@ -368,7 +370,9 @@ class DigestRunner(Runner): for address, delivery_mode in mlist.last_digest_recipients: if delivery_mode == DeliveryMode.plaintext_digests: rfc1153_recipients.add(address.original_email) - elif delivery_mode == DeliveryMode.mime_digests: + # We currently treat summary_digests the same as mime_digests. + elif delivery_mode in (DeliveryMode.mime_digests, + DeliveryMode.summary_digests): mime_recipients.add(address.original_email) else: raise AssertionError( @@ -376,11 +380,13 @@ class DigestRunner(Runner): address, delivery_mode)) # Send the digests to the virgin queue for final delivery. queue = config.switchboards['virgin'] - queue.enqueue(mime, - recipients=mime_recipients, - listid=mlist.list_id, - isdigest=True) - queue.enqueue(rfc1153, - recipients=rfc1153_recipients, - listid=mlist.list_id, - isdigest=True) + if len(mime_recipients) > 0: + queue.enqueue(mime, + recipients=mime_recipients, + listid=mlist.list_id, + isdigest=True) + if len(rfc1153_recipients) > 0: + queue.enqueue(rfc1153, + recipients=rfc1153_recipients, + listid=mlist.list_id, + isdigest=True) diff --git a/src/mailman/runners/docs/digester.rst b/src/mailman/runners/docs/digester.rst index fc59954bc..9ff604340 100644 --- a/src/mailman/runners/docs/digester.rst +++ b/src/mailman/runners/docs/digester.rst @@ -79,13 +79,35 @@ text (RFC 1153) digest and the MIME digest. >>> runner = make_testable_runner(DigestRunner) >>> runner.run() -The digest runner places both digests into the virgin queue for final -delivery. +If there are no members receiving digests, none are sent. >>> messages = get_queue_messages('virgin') >>> len(messages) + 0 + +Once some users are subscribed and receiving digests, the digest runner places +both digests into the virgin queue for final delivery. +:: + + >>> from mailman.testing.helpers import subscribe + >>> from mailman.interfaces.member import DeliveryMode + + >>> anne = subscribe(mlist, 'Anne') + >>> anne.preferences.delivery_mode = DeliveryMode.mime_digests + >>> bart = subscribe(mlist, 'Bart') + >>> bart.preferences.delivery_mode = DeliveryMode.plaintext_digests + + >>> fill_digest() + >>> runner.run() + >>> messages = get_queue_messages('virgin') + >>> len(messages) 2 +Anne and Bart unsubscribe from the mailing list. + + >>> anne.unsubscribe() + >>> bart.unsubscribe() + The MIME digest is a multipart, and the RFC 1153 digest is the other one. :: @@ -102,7 +124,7 @@ The MIME digest has lots of good stuff, all contained in the multipart. Content-Type: multipart/mixed; boundary="===============...==" MIME-Version: 1.0 From: test-request@example.com - Subject: Test Digest, Vol 1, Issue 1 + Subject: Test Digest, Vol 1, Issue 2 To: test@example.com Reply-To: test@example.com Date: ... @@ -112,7 +134,7 @@ The MIME digest has lots of good stuff, all contained in the multipart. Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit - Content-Description: Test Digest, Vol 1, Issue 1 + Content-Description: Test Digest, Vol 1, Issue 2 Send Test mailing list submissions to test@example.com @@ -202,7 +224,7 @@ The RFC 1153 contains the digest in a single plain text message. >>> print(rfc1153.msg.as_string()) From: test-request@example.com - Subject: Test Digest, Vol 1, Issue 1 + Subject: Test Digest, Vol 1, Issue 2 To: test@example.com Reply-To: test@example.com Date: ... @@ -277,7 +299,7 @@ The RFC 1153 contains the digest in a single plain text message. ------------------------------ - End of Test Digest, Vol 1, Issue 1 + End of Test Digest, Vol 1, Issue 2 ********************************** diff --git a/src/mailman/runners/tests/test_digest.py b/src/mailman/runners/tests/test_digest.py index f8b0c4b59..b22425948 100644 --- a/src/mailman/runners/tests/test_digest.py +++ b/src/mailman/runners/tests/test_digest.py @@ -31,11 +31,13 @@ from io import StringIO from mailman.app.lifecycle import create_list from mailman.config import config from mailman.email.message import Message +from mailman.interfaces.member import DeliveryMode from mailman.runners.digest import DigestRunner from mailman.testing.helpers import ( LogFileMark, digest_mbox, get_queue_messages, make_digest_messages, make_testable_runner, message_from_string, - specialized_message_from_string as mfs) + specialized_message_from_string as mfs, + subscribe) from mailman.testing.layers import ConfigLayer from string import Template @@ -49,6 +51,7 @@ class TestDigest(unittest.TestCase): def setUp(self): self._mlist = create_list('test@example.com') + self._mlist.send_welcome_message = False self._mlist.digest_size_threshold = 1 self._digestq = config.switchboards['digest'] self._shuntq = config.switchboards['shunt'] @@ -69,10 +72,20 @@ class TestDigest(unittest.TestCase): 'Test Digest, Vol 1, Issue 1') def test_simple_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 make_digest_messages(self._mlist) self._check_virgin_queue() 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'] = 'anne@example.org' msg['To'] = 'test@example.com' @@ -94,6 +107,11 @@ class TestDigest(unittest.TestCase): self._mlist.volume = 1 self._mlist.next_digest_number = 1 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 # Fill the digest. process = config.handlers['to-digest'].process size = 0 @@ -140,6 +158,57 @@ multipart/mixed text/plain """) + def test_issue141(self): + # Currently DigestMode.summary_digests are equivalent to mime_digests. + self._mlist.send_welcome_message = False + bart = subscribe(self._mlist, 'Bart') + bart.preferences.delivery_mode = DeliveryMode.summary_digests + make_digest_messages(self._mlist) + # There should be one message in the outgoing queue, destined for + # Bart, formatted as a MIME digest. + items = get_queue_messages('virgin') + self.assertEqual(len(items), 1) + # Bart is the only recipient. + self.assertEqual(items[0].msgdata['recipients'], + set(['bperson@example.com'])) + # The message is a MIME digest, with the structure we expect. + fp = StringIO() + structure(items[0].msg, fp) + self.assertMultiLineEqual(fp.getvalue(), """\ +multipart/mixed + text/plain + text/plain + message/rfc822 + text/plain + text/plain +""") + + def test_issue141_one_last_digest(self): + # Currently DigestMode.summary_digests are equivalent to mime_digests. + self._mlist.send_welcome_message = False + bart = subscribe(self._mlist, 'Bart') + self._mlist.send_one_last_digest_to( + bart.address, DeliveryMode.summary_digests) + make_digest_messages(self._mlist) + # There should be one message in the outgoing queue, destined for + # Bart, formatted as a MIME digest. + items = get_queue_messages('virgin') + self.assertEqual(len(items), 1) + # Bart is the only recipient. + self.assertEqual(items[0].msgdata['recipients'], + set(['bperson@example.com'])) + # The message is a MIME digest, with the structure we expect. + fp = StringIO() + structure(items[0].msg, fp) + self.assertMultiLineEqual(fp.getvalue(), """\ +multipart/mixed + text/plain + text/plain + message/rfc822 + text/plain + text/plain +""") + class TestI18nDigest(unittest.TestCase): @@ -153,6 +222,7 @@ class TestI18nDigest(unittest.TestCase): """) self.addCleanup(config.pop, 'french') self._mlist = create_list('test@example.com') + self._mlist.send_welcome_message = False self._mlist.preferred_language = 'fr' self._mlist.digest_size_threshold = 0 self._process = config.handlers['to-digest'].process @@ -162,6 +232,12 @@ class TestI18nDigest(unittest.TestCase): # When messages come in with a content-type character set different # than that of the list's preferred language, recipients will get an # internationalized digest. + # + # 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 = mfs("""\ From: aperson@example.org To: test@example.com -- 2.11.4.GIT