summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Handlers/ToArchive.py5
-rw-r--r--Mailman/docs/archives.txt141
-rw-r--r--Mailman/testing/test_handlers.py57
3 files changed, 142 insertions, 61 deletions
diff --git a/Mailman/Handlers/ToArchive.py b/Mailman/Handlers/ToArchive.py
index df6492b47..6c4397daa 100644
--- a/Mailman/Handlers/ToArchive.py
+++ b/Mailman/Handlers/ToArchive.py
@@ -17,9 +17,6 @@
"""Add the message to the archives."""
-import time
-from cStringIO import StringIO
-
from Mailman.Queue.sbcache import get_switchboard
from Mailman.configuration import config
@@ -32,7 +29,7 @@ def process(mlist, msg, msgdata):
# Common practice seems to favor "X-No-Archive: yes". No other value for
# this header seems to make sense, so we'll just test for it's presence.
# I'm keeping "X-Archive: no" for backwards compatibility.
- if msg.has_key('x-no-archive') or msg.get('x-archive', '').lower() == 'no':
+ if 'x-no-archive' in msg or msg.get('x-archive', '').lower() == 'no':
return
# Send the message to the archiver queue
archq = get_switchboard(config.ARCHQUEUE_DIR)
diff --git a/Mailman/docs/archives.txt b/Mailman/docs/archives.txt
new file mode 100644
index 000000000..682ee8777
--- /dev/null
+++ b/Mailman/docs/archives.txt
@@ -0,0 +1,141 @@
+Archives
+========
+
+Updating the archives with posted messages is handled by a separate queue,
+which allows for better memory management and prevents blocking the main
+delivery processes while messages are archived. This also allows external
+archivers to work in a separate process from the main Mailman delivery
+processes.
+
+ >>> from Mailman.Handlers.ToArchive 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'
+ >>> flush()
+ >>> switchboard = Switchboard(config.ARCHQUEUE_DIR)
+
+A helper function.
+
+ >>> def clear():
+ ... for filebase in switchboard.files:
+ ... msg, msgdata = switchboard.dequeue(filebase)
+ ... switchboard.finish(filebase)
+
+
+The purpose of the ToArchive handler is to make a simple decision as to
+whether the message should get archived and if so, to drop the message in the
+archiving queue. Really the most important things are to determine when a
+message should /not/ get archived.
+
+For example, no digests should ever get archived.
+
+ >>> mlist.archive = True
+ >>> flush()
+ >>> msg = message_from_string("""\
+ ... Subject: A sample message
+ ...
+ ... A message of great import.
+ ... """, Message)
+ >>> process(mlist, msg, dict(isdigest=True))
+ >>> switchboard.files
+ []
+
+If the mailing list is not configured to archive, then even regular deliveries
+won't be archived.
+
+ >>> mlist.archive = False
+ >>> flush()
+ >>> process(mlist, msg, {})
+ >>> switchboard.files
+ []
+
+There are two de-facto standards for a message to indicate that it does not
+want to be archived. We've seen both in the wild so both are supported. The
+X-No-Archive: header can be used to indicate that the message should not be
+archived. Confusingly, this header's value is actually ignored.
+
+ >>> mlist.archive = True
+ >>> flush()
+ >>> msg = message_from_string("""\
+ ... Subject: A sample message
+ ... X-No-Archive: YES
+ ...
+ ... A message of great import.
+ ... """, Message)
+ >>> process(mlist, msg, dict(isdigest=True))
+ >>> switchboard.files
+ []
+
+Even a 'no' value will stop the archiving of the message.
+
+ >>> msg = message_from_string("""\
+ ... Subject: A sample message
+ ... X-No-Archive: No
+ ...
+ ... A message of great import.
+ ... """, Message)
+ >>> process(mlist, msg, dict(isdigest=True))
+ >>> switchboard.files
+ []
+
+Another header that's been observed is the X-Archive: header. Here, the
+header's case folded value must be 'no' in order to prevent archiving.
+
+ >>> msg = message_from_string("""\
+ ... Subject: A sample message
+ ... X-Archive: No
+ ...
+ ... A message of great import.
+ ... """, Message)
+ >>> process(mlist, msg, dict(isdigest=True))
+ >>> switchboard.files
+ []
+
+But if the value is 'yes', then the message will be archived.
+
+ >>> msg = message_from_string("""\
+ ... Subject: A sample message
+ ... X-Archive: Yes
+ ...
+ ... A message of great import.
+ ... """, Message)
+ >>> process(mlist, msg, {})
+ >>> len(switchboard.files)
+ 1
+ >>> filebase = switchboard.files[0]
+ >>> qmsg, qdata = switchboard.dequeue(filebase)
+ >>> switchboard.finish(filebase)
+ >>> print qmsg.as_string()
+ Subject: A sample message
+ X-Archive: Yes
+ <BLANKLINE>
+ A message of great import.
+ <BLANKLINE>
+ >>> sorted(qdata.items())
+ [('_parsemsg', False), ('received_time', ...), ('version', 3)]
+
+Without either archiving header, and all other things being the same, the
+message will get archived.
+
+ >>> msg = message_from_string("""\
+ ... Subject: A sample message
+ ...
+ ... A message of great import.
+ ... """, Message)
+ >>> process(mlist, msg, {})
+ >>> len(switchboard.files)
+ 1
+ >>> filebase = switchboard.files[0]
+ >>> qmsg, qdata = switchboard.dequeue(filebase)
+ >>> switchboard.finish(filebase)
+ >>> print qmsg.as_string()
+ Subject: A sample message
+ <BLANKLINE>
+ A message of great import.
+ <BLANKLINE>
+ >>> sorted(qdata.items())
+ [('_parsemsg', False), ('received_time', ...), ('version', 3)]
diff --git a/Mailman/testing/test_handlers.py b/Mailman/testing/test_handlers.py
index aa7ac0dae..e183f3b66 100644
--- a/Mailman/testing/test_handlers.py
+++ b/Mailman/testing/test_handlers.py
@@ -42,7 +42,6 @@ from Mailman.Handlers import Approve
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
@@ -219,64 +218,8 @@ Name: xtext.txt""")
-class TestToArchive(TestBase):
- def setUp(self):
- TestBase.setUp(self)
- # We're going to want to inspect this queue directory
- self._sb = Switchboard(config.ARCHQUEUE_DIR)
-
- def tearDown(self):
- for f in os.listdir(config.ARCHQUEUE_DIR):
- os.unlink(os.path.join(config.ARCHQUEUE_DIR, f))
- TestBase.tearDown(self)
-
- def test_short_circuit(self):
- eq = self.assertEqual
- msgdata = {'isdigest': 1}
- ToArchive.process(self._mlist, None, msgdata)
- eq(len(self._sb.files()), 0)
- # Try the other half of the or...
- self._mlist.archive = 0
- ToArchive.process(self._mlist, None, msgdata)
- eq(len(self._sb.files()), 0)
- # Now try the various message header shortcuts
- msg = email.message_from_string("""\
-X-No-Archive: YES
-
-""")
- self._mlist.archive = 1
- ToArchive.process(self._mlist, msg, {})
- eq(len(self._sb.files()), 0)
- # And for backwards compatibility
- msg = email.message_from_string("""\
-X-Archive: NO
-
-""")
- ToArchive.process(self._mlist, msg, {})
- eq(len(self._sb.files()), 0)
-
- def test_normal_archiving(self):
- eq = self.assertEqual
- msg = email.message_from_string("""\
-Subject: About Mailman
-
-It rocks!
-""")
- ToArchive.process(self._mlist, msg, {})
- files = self._sb.files()
- eq(len(files), 1)
- msg2, data = self._sb.dequeue(files[0])
- eq(len(data), 3)
- eq(data['version'], 3)
- # Clock skew makes this unreliable
- #self.failUnless(data['received_time'] <= time.time())
- eq(msg.as_string(unixfrom=0), msg2.as_string(unixfrom=0))
-
-
-
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestApprove))
suite.addTest(unittest.makeSuite(TestScrubber))
- suite.addTest(unittest.makeSuite(TestToArchive))
return suite