diff options
| -rw-r--r-- | Mailman/Handlers/ToDigest.py | 60 | ||||
| -rw-r--r-- | Mailman/bin/testall.py | 3 | ||||
| -rw-r--r-- | Mailman/database/model/mailinglist.py | 2 | ||||
| -rw-r--r-- | Mailman/docs/digests.txt | 539 | ||||
| -rw-r--r-- | Mailman/testing/test_documentation.py | 12 | ||||
| -rw-r--r-- | Mailman/testing/test_handlers.py | 116 |
6 files changed, 587 insertions, 145 deletions
diff --git a/Mailman/Handlers/ToDigest.py b/Mailman/Handlers/ToDigest.py index 17ea2f89b..d30f05c71 100644 --- a/Mailman/Handlers/ToDigest.py +++ b/Mailman/Handlers/ToDigest.py @@ -52,6 +52,7 @@ from Mailman.Mailbox import Mailbox from Mailman.MemberAdaptor import ENABLED from Mailman.Queue.sbcache import get_switchboard from Mailman.configuration import config +from Mailman.constants import DeliveryMode, DeliveryStatus _ = i18n._ __i18n_templates__ = True @@ -67,7 +68,7 @@ def process(mlist, msg, msgdata): # Short circuit non-digestable lists. if not mlist.digestable or msgdata.get('isdigest'): return - mboxfile = os.path.join(mlist.fullpath(), 'digest.mbox') + mboxfile = os.path.join(mlist.full_path, 'digest.mbox') mboxfp = open(mboxfile, 'a+') mbox = Mailbox(mboxfp) mbox.AppendMessage(msg) @@ -77,7 +78,7 @@ def process(mlist, msg, msgdata): # whether the size threshold has been reached. mboxfp.flush() size = os.path.getsize(mboxfile) - if size / 1024.0 >= mlist.digest_size_threshhold: + if size / 1024.0 >= mlist.digest_size_threshold: # This is a bit of a kludge to get the mbox file moved to the digest # queue directory. try: @@ -91,7 +92,7 @@ def process(mlist, msg, msgdata): except Exception, errmsg: # Bare except is generally prohibited in Mailman, but we can't # forecast what exceptions can occur here. - log.error('send_digests() failed: %s', errmsg) + log.exception('send_digests() failed: %s', errmsg) mboxfp.close() @@ -155,19 +156,19 @@ def send_i18n_digests(mlist, mboxfp): mimemsg = Message.Message() mimemsg['Content-Type'] = 'multipart/mixed' mimemsg['MIME-Version'] = '1.0' - mimemsg['From'] = mlist.GetRequestEmail() + mimemsg['From'] = mlist.request_address mimemsg['Subject'] = digestsubj - mimemsg['To'] = mlist.GetListEmail() - mimemsg['Reply-To'] = mlist.GetListEmail() + mimemsg['To'] = mlist.posting_address + mimemsg['Reply-To'] = mlist.posting_address mimemsg['Date'] = formatdate(localtime=1) mimemsg['Message-ID'] = Utils.unique_message_id(mlist) # Set things up for the rfc1153 digest plainmsg = StringIO() rfc1153msg = Message.Message() - rfc1153msg['From'] = mlist.GetRequestEmail() + rfc1153msg['From'] = mlist.request_address rfc1153msg['Subject'] = digestsubj - rfc1153msg['To'] = mlist.GetListEmail() - rfc1153msg['Reply-To'] = mlist.GetListEmail() + rfc1153msg['To'] = mlist.posting_address + rfc1153msg['Reply-To'] = mlist.posting_address rfc1153msg['Date'] = formatdate(localtime=1) rfc1153msg['Message-ID'] = Utils.unique_message_id(mlist) separator70 = '-' * 70 @@ -179,10 +180,10 @@ def send_i18n_digests(mlist, mboxfp): mastheadtxt = Utils.maketext( 'masthead.txt', {'real_name' : mlist.real_name, - 'got_list_email': mlist.GetListEmail(), + 'got_list_email': mlist.posting_address, 'got_listinfo_url': mlist.GetScriptURL('listinfo', absolute=1), - 'got_request_email': mlist.GetRequestEmail(), - 'got_owner_email': mlist.GetOwnerEmail(), + 'got_request_email': mlist.request_address, + 'got_owner_email': mlist.owner_address, }, mlist=mlist) # MIME masthead = MIMEText(mastheadtxt.encode(lcset), _charset=lcset) @@ -377,20 +378,31 @@ def send_i18n_digests(mlist, mboxfp): mlist.next_digest_number += 1 virginq = get_switchboard(config.VIRGINQUEUE_DIR) # Calculate the recipients lists - plainrecips = [] - mimerecips = [] - drecips = mlist.getDigestMemberKeys() + mlist.one_last_digest.keys() - for user in mlist.getMemberCPAddresses(drecips): - # user might be None if someone who toggled off digest delivery - # subsequently unsubscribed from the mailing list. Also, filter out - # folks who have disabled delivery. - if user is None or mlist.getDeliveryStatus(user) <> ENABLED: + plainrecips = set() + mimerecips = set() + # When someone turns off digest delivery, they will get one last digest to + # ensure that there will be no gaps in the messages they receive. + # Currently, this dictionary contains the email addresses of those folks + # who should get one last digest. We need to find the corresponding + # IMember records. + digest_members = set(mlist.digest_members.members) + for address in mlist.one_last_digest: + member = mlist.digest_members.get_member(address) + if member: + digest_members.add(member) + for member in digest_members: + if member.delivery_status <> DeliveryStatus.enabled: continue - # Otherwise, decide whether they get MIME or RFC 1153 digests - if mlist.getMemberOption(user, config.DisableMime): - plainrecips.append(user) + # Send the digest to the case-preserved address of the digest members. + email_address = member.address.original_address + if member.delivery_mode == DeliveryMode.plaintext_digests: + plainrecips.add(email_address) + elif member.delivery_mode == DeliveryMode.mime_digests: + mimerecips.add(email_address) else: - mimerecips.append(user) + raise AssertionError( + 'Digest member "%s" unexpected delivery mode: %s' % + (email_address, member.delivery_mode)) # Zap this since we're now delivering the last digest to these folks. mlist.one_last_digest.clear() # MIME diff --git a/Mailman/bin/testall.py b/Mailman/bin/testall.py index 0b8f6db6b..005808cfe 100644 --- a/Mailman/bin/testall.py +++ b/Mailman/bin/testall.py @@ -152,6 +152,9 @@ def main(): if not args: args = ['.'] + # Store the options some place that other code can get to it. + config.opts = opts + # Turn on code coverage if selected. if opts.coverage: try: diff --git a/Mailman/database/model/mailinglist.py b/Mailman/database/model/mailinglist.py index 71007b83f..fce73cf25 100644 --- a/Mailman/database/model/mailinglist.py +++ b/Mailman/database/model/mailinglist.py @@ -91,7 +91,7 @@ class MailingList(Entity): has_field('digest_header', Unicode), has_field('digest_is_default', Boolean), has_field('digest_send_periodic', Boolean), - has_field('digest_size_threshhold', Integer), + has_field('digest_size_threshold', Integer), has_field('digest_volume_frequency', Integer), has_field('digestable', Boolean), has_field('discard_these_nonmembers', PickleType), diff --git a/Mailman/docs/digests.txt b/Mailman/docs/digests.txt new file mode 100644 index 000000000..3788651f9 --- /dev/null +++ b/Mailman/docs/digests.txt @@ -0,0 +1,539 @@ +Digests +======= + +Digests are a way for a user to receive list traffic in collections instead of +as individual messages when immediately posted. There are several forms of +digests, although only two are currently supported: MIME digests and RFC 1153 +(a.k.a. plain text) digests. + + >>> from Mailman.Handlers.ToDigest import process + >>> from Mailman.Message import Message + >>> from Mailman.Queue.Switchboard import Switchboard + >>> from Mailman.configuration import config + >>> from Mailman.database import flush + >>> from email import message_from_string + >>> mlist = config.list_manager.create('_xtest@example.com') + >>> mlist.preferred_language = 'en' + >>> mlist.web_page_url = 'http://www.example.com/' + >>> mlist.real_name = 'XTest' + >>> mlist.subject_prefix = '[_XTest] ' + >>> mlist.one_last_digest = set() + >>> flush() + >>> switchboard = Switchboard(config.VIRGINQUEUE_DIR) + +This is a helper function used to iterate through all the accumulated digest +messages, in the order in which they were posted. This makes it easier to +update the tests when we switch to a different mailbox format. + + >>> import os, mailbox + >>> def digest_mbox(): + ... path = os.path.join(mlist.full_path, 'digest.mbox') + ... return mailbox.mbox(path) + + >>> def clear_mbox(): + ... path = os.path.join(mlist.full_path, 'digest.mbox') + ... os.remove(path) + + >>> from itertools import count + >>> from string import Template + >>> def makemsg(): + ... for i in count(1): + ... text = Template("""\ + ... From: aperson@example.com + ... To: _xtest@example.com + ... Subject: Test message $i + ... + ... Here is message $i + ... """).substitute(i=i) + ... yield message_from_string(text, Message) + + +Short circuiting +---------------- + +When a message is posted to the mailing list, it is generally added to a +running collection of messages. For now, this is a Unix mailbox file, +although in the future this may end up being converted to a maildir style +mailbox. In any event, there are several factors that would bypass the +storing of posted messages to the mailbox. For example, the mailing list may +not allow digests... + + >>> mlist.digestable = False + >>> flush() + >>> msg = makemsg().next() + >>> process(mlist, msg, {}) + >>> sum(1 for mboxmsg in digest_mbox()) + 0 + >>> switchboard.files + [] + +...or they may allow digests but the message is already a digest. + + >>> mlist.digestable = True + >>> flush() + >>> process(mlist, msg, dict(isdigest=True)) + >>> sum(1 for mboxmsg in digest_mbox()) + 0 + >>> switchboard.files + [] + + +Sending a digest +---------------- + +For messages which are not digests, but which are posted to a digestable +mailing list, the messages will be stored until they reach a criteria +triggering the sending of the digest. If none of those criteria are met, then +the message will just sit in the mailbox for a while. + + >>> mlist.digest_size_threshold = 10000 + >>> flush() + >>> process(mlist, msg, {}) + >>> switchboard.files + [] + >>> sum(1 for mboxmsg in digest_mbox()) + 1 + >>> clear_mbox() + +When the size of the digest mbox reaches the maximum size threshold, a digest +is crafted and sent out. This puts two messages in the virgin queue, an HTML +digest and an RFC 1153 plain text digest. The size threshold is in KB. + + >>> mlist.digest_size_threshold = 1 + >>> mlist.volume = 2 + >>> mlist.next_digest_number = 10 + >>> flush() + >>> size = 0 + >>> for msg in makemsg(): + ... process(mlist, msg, {}) + ... size += len(str(msg)) + ... if size > mlist.digest_size_threshold * 1024: + ... break + >>> sum(1 for mboxmsg in digest_mbox()) + 0 + >>> len(switchboard.files) + 2 + >>> for filebase in switchboard.files: + ... qmsg, qdata = switchboard.dequeue(filebase) + ... switchboard.finish(filebase) + ... if qmsg.is_multipart(): + ... mimemsg = qmsg + ... mimedata = qdata + ... else: + ... rfc1153msg = qmsg + ... rfc1153data = qdata + >>> print mimemsg.as_string() + Content-Type: multipart/mixed; boundary="..." + MIME-Version: 1.0 + From: _xtest-request@example.com + Subject: XTest Digest, Vol 2, Issue 10 + To: _xtest@example.com + Reply-To: _xtest@example.com + Date: ... + Message-ID: ... + <BLANKLINE> + --... + Content-Type: text/plain; charset="us-ascii" + MIME-Version: 1.0 + Content-Transfer-Encoding: 7bit + Content-Description: XTest Digest, Vol 2, Issue 10 + <BLANKLINE> + Send XTest mailing list submissions to + _xtest@example.com + <BLANKLINE> + To subscribe or unsubscribe via the World Wide Web, visit + http://www.example.com/listinfo/_xtest@example.com + or, via email, send a message with subject or body 'help' to + _xtest-request@example.com + <BLANKLINE> + You can reach the person managing the list at + _xtest-owner@example.com + <BLANKLINE> + When replying, please edit your Subject line so it is more specific + than "Re: Contents of XTest digest..." + <BLANKLINE> + --... + Content-Type: text/plain; charset="us-ascii" + MIME-Version: 1.0 + Content-Transfer-Encoding: 7bit + Content-Description: Today's Topics (8 messages) + <BLANKLINE> + Today's Topics: + <BLANKLINE> + 1. Test message 1 (aperson@example.com) + 2. Test message 2 (aperson@example.com) + 3. Test message 3 (aperson@example.com) + 4. Test message 4 (aperson@example.com) + 5. Test message 5 (aperson@example.com) + 6. Test message 6 (aperson@example.com) + 7. Test message 7 (aperson@example.com) + 8. Test message 8 (aperson@example.com) + <BLANKLINE> + --... + Content-Type: multipart/digest; boundary="..." + MIME-Version: 1.0 + <BLANKLINE> + --... + Content-Type: message/rfc822 + MIME-Version: 1.0 + <BLANKLINE> + From: aperson@example.com + To: _xtest@example.com + Subject: Test message 1 + Message: 1 + <BLANKLINE> + Here is message 1 + <BLANKLINE> + <BLANKLINE> + --... + Content-Type: message/rfc822 + MIME-Version: 1.0 + <BLANKLINE> + From: aperson@example.com + To: _xtest@example.com + Subject: Test message 2 + Message: 2 + <BLANKLINE> + Here is message 2 + <BLANKLINE> + <BLANKLINE> + --... + Content-Type: message/rfc822 + MIME-Version: 1.0 + <BLANKLINE> + From: aperson@example.com + To: _xtest@example.com + Subject: Test message 3 + Message: 3 + <BLANKLINE> + Here is message 3 + <BLANKLINE> + <BLANKLINE> + --... + Content-Type: message/rfc822 + MIME-Version: 1.0 + <BLANKLINE> + From: aperson@example.com + To: _xtest@example.com + Subject: Test message 4 + Message: 4 + <BLANKLINE> + Here is message 4 + <BLANKLINE> + <BLANKLINE> + --... + Content-Type: message/rfc822 + MIME-Version: 1.0 + <BLANKLINE> + From: aperson@example.com + To: _xtest@example.com + Subject: Test message 5 + Message: 5 + <BLANKLINE> + Here is message 5 + <BLANKLINE> + <BLANKLINE> + --... + Content-Type: message/rfc822 + MIME-Version: 1.0 + <BLANKLINE> + From: aperson@example.com + To: _xtest@example.com + Subject: Test message 6 + Message: 6 + <BLANKLINE> + Here is message 6 + <BLANKLINE> + <BLANKLINE> + --... + Content-Type: message/rfc822 + MIME-Version: 1.0 + <BLANKLINE> + From: aperson@example.com + To: _xtest@example.com + Subject: Test message 7 + Message: 7 + <BLANKLINE> + Here is message 7 + <BLANKLINE> + <BLANKLINE> + --... + Content-Type: message/rfc822 + MIME-Version: 1.0 + <BLANKLINE> + From: aperson@example.com + To: _xtest@example.com + Subject: Test message 8 + Message: 8 + <BLANKLINE> + Here is message 8 + <BLANKLINE> + <BLANKLINE> + --... + --... + >>> sorted(mimedata.items()) + [('_parsemsg', False), + ('isdigest', True), + ('listname', '_xtest@example.com'), + ('received_time', ...), + ('recips', set([])), ('version', 3)] + >>> print rfc1153msg.as_string() + From: _xtest-request@example.com + Subject: XTest Digest, Vol 2, Issue 10 + To: _xtest@example.com + Reply-To: _xtest@example.com + Date: ... + Message-ID: ... + MIME-Version: 1.0 + Content-Type: text/plain; charset="us-ascii" + Content-Transfer-Encoding: 7bit + <BLANKLINE> + Send XTest mailing list submissions to + _xtest@example.com + <BLANKLINE> + To subscribe or unsubscribe via the World Wide Web, visit + http://www.example.com/listinfo/_xtest@example.com + or, via email, send a message with subject or body 'help' to + _xtest-request@example.com + <BLANKLINE> + You can reach the person managing the list at + _xtest-owner@example.com + <BLANKLINE> + When replying, please edit your Subject line so it is more specific + than "Re: Contents of XTest digest..." + <BLANKLINE> + <BLANKLINE> + Today's Topics: + <BLANKLINE> + 1. Test message 1 (aperson@example.com) + 2. Test message 2 (aperson@example.com) + 3. Test message 3 (aperson@example.com) + 4. Test message 4 (aperson@example.com) + 5. Test message 5 (aperson@example.com) + 6. Test message 6 (aperson@example.com) + 7. Test message 7 (aperson@example.com) + 8. Test message 8 (aperson@example.com) + <BLANKLINE> + <BLANKLINE> + ---------------------------------------------------------------------- + <BLANKLINE> + Message: 1 + From: aperson@example.com + Subject: Test message 1 + To: _xtest@example.com + Message-ID: ... + <BLANKLINE> + Here is message 1 + <BLANKLINE> + <BLANKLINE> + ------------------------------ + <BLANKLINE> + Message: 2 + From: aperson@example.com + Subject: Test message 2 + To: _xtest@example.com + Message-ID: ... + <BLANKLINE> + Here is message 2 + <BLANKLINE> + <BLANKLINE> + ------------------------------ + <BLANKLINE> + Message: 3 + From: aperson@example.com + Subject: Test message 3 + To: _xtest@example.com + Message-ID: ... + <BLANKLINE> + Here is message 3 + <BLANKLINE> + <BLANKLINE> + ------------------------------ + <BLANKLINE> + Message: 4 + From: aperson@example.com + Subject: Test message 4 + To: _xtest@example.com + Message-ID: ... + <BLANKLINE> + Here is message 4 + <BLANKLINE> + <BLANKLINE> + ------------------------------ + <BLANKLINE> + Message: 5 + From: aperson@example.com + Subject: Test message 5 + To: _xtest@example.com + Message-ID: ... + <BLANKLINE> + Here is message 5 + <BLANKLINE> + <BLANKLINE> + ------------------------------ + <BLANKLINE> + Message: 6 + From: aperson@example.com + Subject: Test message 6 + To: _xtest@example.com + Message-ID: ... + <BLANKLINE> + Here is message 6 + <BLANKLINE> + <BLANKLINE> + ------------------------------ + <BLANKLINE> + Message: 7 + From: aperson@example.com + Subject: Test message 7 + To: _xtest@example.com + Message-ID: ... + <BLANKLINE> + Here is message 7 + <BLANKLINE> + <BLANKLINE> + ------------------------------ + <BLANKLINE> + Message: 8 + From: aperson@example.com + Subject: Test message 8 + To: _xtest@example.com + Message-ID: ... + <BLANKLINE> + Here is message 8 + <BLANKLINE> + <BLANKLINE> + End of XTest Digest, Vol 2, Issue 10 + ************************************ + <BLANKLINE> + >>> sorted(rfc1153data.items()) + [('_parsemsg', False), + ('isdigest', True), + ('listname', '_xtest@example.com'), + ('received_time', ...), + ('recips', set([])), ('version', 3)] + + +Internationalized digests +------------------------- + +When messages come in with a content-type character set different than that of +the list's preferred language, recipients wil get an internationalized digest. + + >>> mlist.preferred_language = 'fr' + >>> msg = message_from_string("""\ + ... From: aperson@example.org + ... To: _xtest@example.com + ... Subject: =?iso-2022-jp?b?GyRCMGxIVhsoQg==?= + ... MIME-Version: 1.0 + ... Content-Type: text/plain; charset=iso-2022-jp + ... Content-Transfer-Encoding: 7bit + ... + ... \x1b$B0lHV\x1b(B + ... """, Message) + +Set the digest threshold to zero so that the digests will be sent immediately. + + >>> mlist.digest_size_threshold = 0 + >>> flush() + >>> process(mlist, msg, {}) + >>> sum(1 for mboxmsg in digest_mbox()) + 0 + >>> len(switchboard.files) + 2 + >>> for filebase in switchboard.files: + ... qmsg, qdata = switchboard.dequeue(filebase) + ... switchboard.finish(filebase) + ... if qmsg.is_multipart(): + ... mimemsg = qmsg + ... mimedata = qdata + ... else: + ... rfc1153msg = qmsg + ... rfc1153data = qdata + >>> print mimemsg.as_string() + Content-Type: multipart/mixed; boundary="..." + MIME-Version: 1.0 + From: _xtest-request@example.com + Subject: XTest Digest, Vol 2, Issue 11 + To: _xtest@example.com + Reply-To: _xtest@example.com + Date: ... + Message-ID: ... + <BLANKLINE> + --... + Content-Type: text/plain; charset="iso-8859-1" + MIME-Version: 1.0 + Content-Transfer-Encoding: quoted-printable + Content-Description: XTest Digest, Vol 2, Issue 11 + <BLANKLINE> + Envoyez vos messages pour la liste XTest =E0 + _xtest@example.com + <BLANKLINE> + Pour vous (d=E9s)abonner par le web, consultez + http://www.example.com/listinfo/_xtest@example.com + <BLANKLINE> + ou, par courriel, envoyez un message avec =AB=A0help=A0=BB dans le corps ou + dans le sujet =E0 + _xtest-request@example.com + <BLANKLINE> + Vous pouvez contacter l'administrateur de la liste =E0 l'adresse + _xtest-owner@example.com + <BLANKLINE> + Si vous r=E9pondez, n'oubliez pas de changer l'objet du message afin + qu'il soit plus sp=E9cifique que =AB=A0Re: Contenu du groupe de XTest...=A0= + =BB + <BLANKLINE> + --... + Content-Type: text/plain; charset="utf-8" + MIME-Version: 1.0 + Content-Transfer-Encoding: base64 + Content-Description: Today's Topics (1 messages) + <BLANKLINE> + VGjDqG1lcyBkdSBqb3VyIDoKCiAgIDEuIOS4gOeVqiAoYXBlcnNvbkBleGFtcGxlLm9yZykK + <BLANKLINE> + --... + Content-Type: multipart/digest; boundary="..." + MIME-Version: 1.0 + <BLANKLINE> + --... + Content-Type: message/rfc822 + MIME-Version: 1.0 + <BLANKLINE> + Content-Transfer-Encoding: 7bit + From: aperson@example.org + MIME-Version: 1.0 + To: _xtest@example.com + Content-Type: text/plain; charset=iso-2022-jp + Subject: =?iso-2022-jp?b?GyRCMGxIVhsoQg==?= + Message: 1 + <BLANKLINE> + 一番 + <BLANKLINE> + <BLANKLINE> + --... + --... + >>> sorted(mimedata.items()) + [('_parsemsg', False), + ('isdigest', True), + ('listname', '_xtest@example.com'), + ('received_time', ...), + ('recips', set([])), ('version', 3)] + >>> print rfc1153msg.as_string() + From: _xtest-request@example.com + Subject: XTest Digest, Vol 2, Issue 11 + To: _xtest@example.com + Reply-To: _xtest@example.com + Date: ... + Message-ID: ... + MIME-Version: 1.0 + Content-Type: text/plain; charset="utf-8" + Content-Transfer-Encoding: base64 + <BLANKLINE> + ... + <BLANKLINE> + >>> sorted(rfc1153data.items()) + [('_parsemsg', False), + ('isdigest', True), + ('listname', '_xtest@example.com'), + ('received_time', ...), + ('recips', set([])), ('version', 3)] diff --git a/Mailman/testing/test_documentation.py b/Mailman/testing/test_documentation.py index 23641d57b..c5fb62302 100644 --- a/Mailman/testing/test_documentation.py +++ b/Mailman/testing/test_documentation.py @@ -60,15 +60,19 @@ def cleaning_teardown(testobj): def test_suite(): suite = unittest.TestSuite() docsdir = os.path.join(os.path.dirname(Mailman.__file__), 'docs') + # Under higher verbosity settings, report all doctest errors, not just the + # first one. + flags = (doctest.ELLIPSIS | + doctest.NORMALIZE_WHITESPACE | + doctest.REPORT_NDIFF) + if config.opts.verbosity <= 2: + flags |= doctest.REPORT_ONLY_FIRST_FAILURE for filename in os.listdir(docsdir): if os.path.splitext(filename)[1] == '.txt': test = doctest.DocFileSuite( 'docs/' + filename, package=Mailman, - optionflags=(doctest.ELLIPSIS - | doctest.NORMALIZE_WHITESPACE - | doctest.REPORT_NDIFF - | doctest.REPORT_ONLY_FIRST_FAILURE), + optionflags=flags, tearDown=cleaning_teardown) suite.addTest(test) return suite diff --git a/Mailman/testing/test_handlers.py b/Mailman/testing/test_handlers.py index 8b1f11e98..aa7ac0dae 100644 --- a/Mailman/testing/test_handlers.py +++ b/Mailman/testing/test_handlers.py @@ -43,7 +43,6 @@ from Mailman.Handlers import Moderate from Mailman.Handlers import Scrubber # Don't test handlers such as SMTPDirect and Sendmail here from Mailman.Handlers import ToArchive -from Mailman.Handlers import ToDigest @@ -275,124 +274,9 @@ It rocks! -class TestToDigest(TestBase): - def _makemsg(self, i=0): - msg = email.message_from_string("""From: aperson@example.org -To: _xtest@example.com -Subject: message number %(i)d - -Here is message %(i)d -""" % {'i' : i}) - return msg - - def setUp(self): - TestBase.setUp(self) - self._path = os.path.join(self._mlist.fullpath(), 'digest.mbox') - fp = open(self._path, 'w') - g = Generator(fp) - for i in range(5): - g.flatten(self._makemsg(i), unixfrom=1) - fp.close() - self._sb = Switchboard(config.VIRGINQUEUE_DIR) - - def tearDown(self): - try: - os.unlink(self._path) - except OSError, e: - if e.errno <> errno.ENOENT: raise - for f in os.listdir(config.VIRGINQUEUE_DIR): - os.unlink(os.path.join(config.VIRGINQUEUE_DIR, f)) - TestBase.tearDown(self) - - def test_short_circuit(self): - eq = self.assertEqual - mlist = self._mlist - mlist.digestable = 0 - eq(ToDigest.process(mlist, None, {}), None) - mlist.digestable = 1 - eq(ToDigest.process(mlist, None, {'isdigest': 1}), None) - eq(self._sb.files(), []) - - def test_undersized(self): - msg = self._makemsg(99) - size = os.path.getsize(self._path) + len(str(msg)) - self._mlist.digest_size_threshhold = (size + 1) * 1024 - ToDigest.process(self._mlist, msg, {}) - self.assertEqual(self._sb.files(), []) - - def test_send_a_digest(self): - eq = self.assertEqual - mlist = self._mlist - msg = self._makemsg(99) - size = os.path.getsize(self._path) + len(str(msg)) - mlist.digest_size_threshhold = 0 - ToDigest.process(mlist, msg, {}) - files = self._sb.files() - # There should be two files in the queue, one for the MIME digest and - # one for the RFC 1153 digest. - eq(len(files), 2) - # Now figure out which of the two files is the MIME digest and which - # is the RFC 1153 digest. - for filebase in files: - qmsg, qdata = self._sb.dequeue(filebase) - if qmsg.get_content_maintype() == 'multipart': - mimemsg = qmsg - mimedata = qdata - else: - rfc1153msg = qmsg - rfc1153data = qdata - eq(rfc1153msg.get_content_type(), 'text/plain') - eq(mimemsg.get_content_type(), 'multipart/mixed') - eq(mimemsg['from'], mlist.GetRequestEmail()) - eq(mimemsg['subject'], - '%(realname)s Digest, Vol %(volume)d, Issue %(issue)d' % { - 'realname': mlist.real_name, - 'volume' : mlist.volume, - 'issue' : mlist.next_digest_number - 1, - }) - eq(mimemsg['to'], mlist.GetListEmail()) - # BAW: this test is incomplete... - - def test_send_i18n_digest(self): - eq = self.assertEqual - mlist = self._mlist - mlist.preferred_language = 'fr' - msg = email.message_from_string("""\ -From: aperson@example.org -To: _xtest@example.com -Subject: =?iso-2022-jp?b?GyRCMGxIVhsoQg==?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=iso-2022-jp -Content-Transfer-Encoding: 7bit - -\x1b$B0lHV\x1b(B -""") - mlist.digest_size_threshhold = 0 - ToDigest.process(mlist, msg, {}) - files = self._sb.files() - eq(len(files), 2) - for filebase in files: - qmsg, qdata = self._sb.dequeue(filebase) - if qmsg.get_content_maintype() == 'multipart': - mimemsg = qmsg - mimedata = qdata - else: - rfc1153msg = qmsg - rfc1153data = qdata - eq(rfc1153msg.get_content_type(), 'text/plain') - eq(rfc1153msg.get_content_charset(), 'utf-8') - eq(rfc1153msg['content-transfer-encoding'], 'base64') - toc = mimemsg.get_payload()[1] - eq(toc.get_content_type(), 'text/plain') - eq(toc.get_content_charset(), 'utf-8') - eq(toc['content-transfer-encoding'], 'base64') - - - def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TestApprove)) suite.addTest(unittest.makeSuite(TestScrubber)) suite.addTest(unittest.makeSuite(TestToArchive)) - suite.addTest(unittest.makeSuite(TestToDigest)) return suite |
