Merge lp:~barry/launchpad/435604-mailman into lp:launchpad

Proposed by Barry Warsaw
Status: Merged
Approved by: Brad Crittenden
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~barry/launchpad/435604-mailman
Merge into: lp:launchpad
Diff against target: 824 lines
17 files modified
lib/canonical/launchpad/mailman/monkeypatches/__init__.py (+35/-80)
lib/canonical/launchpad/mailman/monkeypatches/mm_cfg.py.in (+65/-0)
lib/lp/services/mailman/doc/basic-integration.txt (+89/-0)
lib/lp/services/mailman/doc/bounces.txt (+1/-0)
lib/lp/services/mailman/doc/contact-address.txt (+2/-2)
lib/lp/services/mailman/doc/create-lists.txt (+2/-2)
lib/lp/services/mailman/doc/decorations.txt (+1/-2)
lib/lp/services/mailman/doc/logging.txt (+27/-24)
lib/lp/services/mailman/doc/messages.txt (+3/-1)
lib/lp/services/mailman/doc/modify-lists.txt (+5/-3)
lib/lp/services/mailman/doc/postings.txt (+17/-16)
lib/lp/services/mailman/doc/reactivate-lists.txt (+4/-2)
lib/lp/services/mailman/doc/recovery.txt (+9/-5)
lib/lp/services/mailman/doc/staging.txt (+2/-3)
lib/lp/services/mailman/doc/subscriptions.txt (+11/-7)
lib/lp/services/mailman/testing/helpers.py (+1/-1)
lib/lp/services/mailman/testing/logwatcher.py (+2/-2)
To merge this branch: bzr merge lp:~barry/launchpad/435604-mailman
Reviewer Review Type Date Requested Status
Brad Crittenden (community) release-critical Approve
Paul Hummer (community) Approve
Review via email: mp+12380@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Barry Warsaw (barry) wrote :
Download full text (6.5 KiB)

 reviewer rockstar

= Summary =

Bug 435604 describes a critical problem we discovered while rolling out LP 3.0
on forster, the Mailman (and other) server. The problem is that with the move
to buildout for a lot of our packages, the sys.path that the Mailman binary
uses was not correct. The binary uses the system Python, not bin/py so none
of the buildout eggs were visible to it.

== Proposed fix ==

Extend the path hacking done in Mailman's mm_cfg.py to pick up the necessary
buildout eggs. Do this by importing _pythonpath.

== Pre-implementation notes ==

Discussion during cowboy rollout with gary, spm, and stub.

== Implementation details ==

Along the way, I updated all the MailmanLayer tests. These should all pass
now, with the usual caveat that these tests are flaky. That's why we don't
run them as part of our normal test suite.

== Tests ==

To test the specific critical fix in this branch, run:

% bin/test -vv --layer=MailmanLayer -t basic-integration

To see that all the tests have been updated for LP 3.0, run:

% bin/test -vv --layer=MailmanLayer

You may get spurious failures from the above. Your choices are to run each
test in lib/lp/services/mailman/doc separately, or/and do 'make clean && make'
between each run.

== Demo and Q/A ==

No demo or Q/A. Once we cherry pick this onto forster, if the mailing lists
work, we're gold.

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/lp/services/mailman/doc/logging.txt
  lib/lp/services/mailman/doc/subscriptions.txt
  lib/canonical/launchpad/mailman/monkeypatches/__init__.py
  lib/lp/services/mailman/testing/logwatcher.py
  lib/lp/services/mailman/doc/postings.txt
  lib/lp/services/mailman/doc/bounces.txt
  lib/lp/services/mailman/doc/basic-integration.txt
  lib/lp/services/mailman/doc/decorations.txt
  lib/lp/services/mailman/doc/messages.txt
  lib/lp/services/mailman/doc/recovery.txt
  lib/lp/services/mailman/doc/reactivate-lists.txt
  lib/lp/services/mailman/doc/create-lists.txt
  lib/canonical/launchpad/mailman/monkeypatches/mm_cfg.py.in
  lib/lp/services/mailman/doc/contact-address.txt
  lib/lp/services/mailman/doc/staging.txt
  lib/lp/services/mailman/testing/helpers.py
  lib/lp/services/mailman/doc/modify-lists.txt

== Pyflakes Doctest notices ==

lib/lp/services/mailman/doc/logging.txt
    70: undefined name 'error_watcher'
    71: undefined name 'error_watcher'
    74: undefined name 'error_watcher'
    75: undefined name 'error_watcher'

lib/lp/services/mailman/doc/postings.txt
    14: undefined name 'smtpd'
    35: undefined name 'vette_watcher'
    36: undefined name 'smtpd'
    73: undefined name 'vette_watcher'
    74: undefined name 'smtpd'
    88: undefined name 'smtpd'
    89: undefined name 'smtpd'
    99: undefined name 'vette_watcher'
    103: undefined name 'smtpd_watcher'
    104: undefined name 'smtpd'
    156: undefined name 'Browser'
    168: undefined name 'smtpd_watcher'
    169: undefined name 'smtpd'
    212: undefined name 'vette_watcher'
    213: undefined name 'smtpd'
    244: undefined name 'smtpd'
    259: undefine...

Read more...

Revision history for this message
Paul Hummer (rockstar) :
review: Approve
Revision history for this message
Brad Crittenden (bac) wrote :

Hi Barry,

Thanks for the fix. Not to beat a dead horse, but in the future try to keep RC candidate branches as tiny as possible.

Thanks also for hanging around last night as the release happened to ensure everything worked.

review: Approve (release-critical)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/mailman/monkeypatches/__init__.py'
2--- lib/canonical/launchpad/mailman/monkeypatches/__init__.py 2009-07-17 00:26:05 +0000
3+++ lib/canonical/launchpad/mailman/monkeypatches/__init__.py 2009-09-24 20:25:22 +0000
4@@ -38,7 +38,8 @@
5 # will get appended to Mailman's sys.path.
6 import canonical
7 from canonical.launchpad.mailman.config import configure_siteowner
8- launchpad_top = os.path.dirname(os.path.dirname(canonical.__file__))
9+ launchpad_top = os.path.dirname(
10+ os.path.dirname(os.path.dirname(canonical.__file__)))
11 # Read the email footer template for all Launchpad messages.
12 from canonical.launchpad.helpers import get_email_template
13 footer = get_email_template('mailinglist-footer.txt')
14@@ -46,85 +47,39 @@
15 host, port = as_host_port(config.mailman.smtp)
16 owner_address, owner_password = configure_siteowner(
17 config.mailman.build_site_list_owner)
18- config_path = os.path.join(mailman_path, 'Mailman', 'mm_cfg.py')
19- config_file = open(config_path, 'w')
20- try:
21- print >> config_file, """\
22-# Automatically generated by runlaunchpad.py
23-
24-# Set up Mailman's sys.path to pick up the top of Launchpad's tree
25-import sys
26-sys.path.insert(0, '%(launchpad_top)s')
27-
28-# Pick up Launchpad static overrides. This will also pick up the standard
29-# Mailman.Defaults.* variables.
30-from canonical.launchpad.mailman.monkeypatches.defaults import *
31-
32-# Our dynamic overrides of all the static defaults.
33-SMTPHOST = '%(smtp_host)s'
34-SMTPPORT = %(smtp_port)d
35-
36-# Configuration options for the XMLRPCRunner.
37-XMLRPC_URL = '%(xmlrpc_url)s'
38-XMLRPC_SLEEPTIME = %(xmlrpc_sleeptime)s
39-XMLRPC_SUBSCRIPTION_BATCH_SIZE = %(xmlrpc_subscription_batch_size)s
40-LAUNCHPAD_SHARED_SECRET = '%(shared_secret)s'
41-
42-# RFC 2369 header information.
43-LIST_HELP_HEADER = '%(list_help_header)s'
44-LIST_SUBSCRIPTION_HEADERS = '%(list_subscription_headers)s'
45-LIST_ARCHIVE_HEADER_TEMPLATE = '%(archive_url_template)s'
46-LIST_OWNER_HEADER_TEMPLATE = '%(list_owner_header_template)s'
47-
48-# Soft and hard maximum message size limits. Anything below the soft limit is
49-# allowed directly through. Between the soft and hard limits, the message is
50-# held for approval. Above the hard limit, the message is logged and
51-# discarded. Note that the normal Mailman size thresholds are ignored.
52-LAUNCHPAD_SOFT_MAX_SIZE = %(soft_max_size)d
53-LAUNCHPAD_HARD_MAX_SIZE = %(hard_max_size)d
54-
55-SITE_LIST_OWNER = '%(site_list_owner)s'
56-
57-DEFAULT_MSG_FOOTER = '''_______________________________________________
58-%(footer)s'''
59-
60-# Set up MHonArc archiving.
61-PUBLIC_EXTERNAL_ARCHIVER = '/usr/bin/mhonarc \
62--add \
63--dbfile %(var_dir)s/archives/private/%%(listname)s.mbox/mhonarc.db \
64--outdir %(var_dir)s/mhonarc/%%(listname)s \
65--definevar ML-NAME=%%(listname)s \
66--rcfile %(var_dir)s/data/lp-mhonarc-common.mrc \
67--stderr %(var_dir)s/logs/mhonarc \
68--stdout %(var_dir)s/logs/mhonarc \
69--spammode \
70--umask 022'
71-PRIVATE_EXTERNAL_ARCHIVER = PUBLIC_EXTERNAL_ARCHIVER
72-
73-# How often do we run the bounce processor? For production, the default 15
74-# minutes is fine, for testing we want to run it more often.
75-REGISTER_BOUNCES_EVERY = %(register_bounces_every)d
76-""" % dict(
77- launchpad_top=launchpad_top,
78- smtp_host=host,
79- smtp_port=port,
80- xmlrpc_url=config.mailman.xmlrpc_url,
81- xmlrpc_sleeptime=config.mailman.xmlrpc_runner_sleep,
82- xmlrpc_subscription_batch_size=config.mailman.subscription_batch_size,
83- site_list_owner=owner_address,
84- list_help_header=config.mailman.list_help_header,
85- list_subscription_headers=config.mailman.list_subscription_headers,
86- archive_url_template=config.mailman.archive_url_template,
87- list_owner_header_template=config.mailman.list_owner_header_template,
88- footer=footer,
89- var_dir=config.mailman.build_var_dir,
90- shared_secret=config.mailman.shared_secret,
91- soft_max_size=config.mailman.soft_max_size,
92- hard_max_size=config.mailman.hard_max_size,
93- register_bounces_every=config.mailman.register_bounces_every,
94- )
95- finally:
96- config_file.close()
97+ config_path_in = os.path.join(os.path.dirname(__file__), 'mm_cfg.py.in')
98+ config_file_in = open(config_path_in)
99+ try:
100+ config_template = config_file_in.read()
101+ finally:
102+ config_file_in.close()
103+ config_path_out = os.path.join(mailman_path, 'Mailman', 'mm_cfg.py')
104+ config_file_out = open(config_path_out, 'w')
105+ try:
106+ print >> config_file_out, config_template % dict(
107+ launchpad_top=launchpad_top,
108+ smtp_host=host,
109+ smtp_port=port,
110+ xmlrpc_url=config.mailman.xmlrpc_url,
111+ xmlrpc_sleeptime=config.mailman.xmlrpc_runner_sleep,
112+ xmlrpc_subscription_batch_size
113+ =config.mailman.subscription_batch_size,
114+ site_list_owner=owner_address,
115+ list_help_header=config.mailman.list_help_header,
116+ list_subscription_headers
117+ =config.mailman.list_subscription_headers,
118+ archive_url_template=config.mailman.archive_url_template,
119+ list_owner_header_template
120+ =config.mailman.list_owner_header_template,
121+ footer=footer,
122+ var_dir=config.mailman.build_var_dir,
123+ shared_secret=config.mailman.shared_secret,
124+ soft_max_size=config.mailman.soft_max_size,
125+ hard_max_size=config.mailman.hard_max_size,
126+ register_bounces_every=config.mailman.register_bounces_every,
127+ )
128+ finally:
129+ config_file_out.close()
130 # Mailman's qrunner system requires runner modules to live in the
131 # Mailman.Queue package. Set things up so that there's a hook module in
132 # there for the XMLRPCRunner.
133
134=== added file 'lib/canonical/launchpad/mailman/monkeypatches/mm_cfg.py.in'
135--- lib/canonical/launchpad/mailman/monkeypatches/mm_cfg.py.in 1970-01-01 00:00:00 +0000
136+++ lib/canonical/launchpad/mailman/monkeypatches/mm_cfg.py.in 2009-09-24 20:25:22 +0000
137@@ -0,0 +1,65 @@
138+# Automatically generated by runlaunchpad.py
139+
140+# Initialize sys.path so that the Mailman processes, which use the standard
141+# system Python instead of buildout's bin/py, can find all the necessary
142+# packages and modules. Some of these are in sourcecode and some are in
143+# buildout eggs.
144+#
145+# This is a two-step process. First, we hack sys.path in order to find a
146+# directory containing _pythonpath. Then the _pythonpath module does all the
147+# subsequent sys.path hacking necessary.
148+
149+# Set up Mailman's sys.path to pick up the top of Launchpad's tree. This only
150+# gets us a sys.path
151+import sys
152+sys.path.insert(0, '%(launchpad_top)s')
153+import _pythonpath
154+
155+# Pick up Launchpad static overrides. This will also pick up the standard
156+# Mailman.Defaults.* variables.
157+from canonical.launchpad.mailman.monkeypatches.defaults import *
158+
159+# Our dynamic overrides of all the static defaults.
160+SMTPHOST = '%(smtp_host)s'
161+SMTPPORT = %(smtp_port)d
162+
163+# Configuration options for the XMLRPCRunner.
164+XMLRPC_URL = '%(xmlrpc_url)s'
165+XMLRPC_SLEEPTIME = %(xmlrpc_sleeptime)s
166+XMLRPC_SUBSCRIPTION_BATCH_SIZE = %(xmlrpc_subscription_batch_size)s
167+LAUNCHPAD_SHARED_SECRET = '%(shared_secret)s'
168+
169+# RFC 2369 header information.
170+LIST_HELP_HEADER = '%(list_help_header)s'
171+LIST_SUBSCRIPTION_HEADERS = '%(list_subscription_headers)s'
172+LIST_ARCHIVE_HEADER_TEMPLATE = '%(archive_url_template)s'
173+LIST_OWNER_HEADER_TEMPLATE = '%(list_owner_header_template)s'
174+
175+# Soft and hard maximum message size limits. Anything below the soft limit is
176+# allowed directly through. Between the soft and hard limits, the message is
177+# held for approval. Above the hard limit, the message is logged and
178+# discarded. Note that the normal Mailman size thresholds are ignored.
179+LAUNCHPAD_SOFT_MAX_SIZE = %(soft_max_size)d
180+LAUNCHPAD_HARD_MAX_SIZE = %(hard_max_size)d
181+
182+SITE_LIST_OWNER = '%(site_list_owner)s'
183+
184+DEFAULT_MSG_FOOTER = '''_______________________________________________
185+%(footer)s'''
186+
187+# Set up MHonArc archiving.
188+PUBLIC_EXTERNAL_ARCHIVER = '/usr/bin/mhonarc \
189+-add \
190+-dbfile %(var_dir)s/archives/private/%%(listname)s.mbox/mhonarc.db \
191+-outdir %(var_dir)s/mhonarc/%%(listname)s \
192+-definevar ML-NAME=%%(listname)s \
193+-rcfile %(var_dir)s/data/lp-mhonarc-common.mrc \
194+-stderr %(var_dir)s/logs/mhonarc \
195+-stdout %(var_dir)s/logs/mhonarc \
196+-spammode \
197+-umask 022'
198+PRIVATE_EXTERNAL_ARCHIVER = PUBLIC_EXTERNAL_ARCHIVER
199+
200+# How often do we run the bounce processor? For production, the default 15
201+# minutes is fine, for testing we want to run it more often.
202+REGISTER_BOUNCES_EVERY = %(register_bounces_every)d
203
204=== modified file 'lib/lp/services/mailman/doc/basic-integration.txt'
205--- lib/lp/services/mailman/doc/basic-integration.txt 2009-06-23 17:51:24 +0000
206+++ lib/lp/services/mailman/doc/basic-integration.txt 2009-09-24 20:25:22 +0000
207@@ -29,3 +29,92 @@
208
209 >>> withlist('withlist_2.can_import', '-q')
210 99
211+
212+
213+Binaries
214+========
215+
216+Mailman contains a number of binary wrappers for integration between the MTA
217+and Mailman. Mailman's 'post' command accepts standard input from the MTA and
218+drops the resulting message in Mailman's incoming queue.
219+
220+ # See `subscriptions.txt`_ for more details.
221+ >>> from lp.services.mailman.testing import helpers
222+ >>> alpha = helpers.create_list('alpha')
223+ >>> helpers.subscribe('Anne', 'alpha')
224+
225+ # Ignore the list creation notification message.
226+ >>> smtpd.reset()
227+
228+ >>> sample_message = """\
229+ ... From: anne.person@example.com
230+ ... To: alpha@lists.launchpad.dev
231+ ... Subject: A test message
232+ ... Message-ID: <aardvark>
233+ ...
234+ ... This is a test message.
235+ ... """
236+
237+ # The path to the binary we're testing is relative to the top of the
238+ # Launchpad source tree.
239+ >>> import canonical
240+ >>> launchpad_top = os.path.dirname(
241+ ... os.path.dirname(os.path.dirname(canonical.__file__)))
242+ >>> binary = os.path.join(launchpad_top,
243+ ... 'lib/mailman/mail/mailman')
244+
245+ >>> mailman = subprocess.Popen(
246+ ... (binary, 'post', 'alpha'),
247+ ... stdin=subprocess.PIPE,
248+ ... stdout=subprocess.PIPE,
249+ ... stderr=subprocess.PIPE)
250+
251+ >>> stdout, stderr = mailman.communicate(sample_message)
252+ >>> mailman.returncode
253+ 0
254+ >>> print stdout
255+ <BLANKLINE>
256+ >>> print stderr
257+ <BLANKLINE>
258+
259+The message was delivered to Anne and the archiver.
260+
261+ >>> smtpd_watcher.wait_for_mbox_delivery('aardvark')
262+ >>> messages = list(smtpd)
263+ >>> len(messages)
264+ 2
265+
266+ >>> for message in messages:
267+ ... if message['x-rcptto'] == 'anne.person@example.com':
268+ ... break
269+
270+ >>> print message.as_string()
271+ From: anne.person@example.com
272+ To: alpha@lists.launchpad.dev
273+ Message-ID: <aardvark>
274+ Subject: [Alpha] A test message
275+ X-BeenThere: alpha@lists.launchpad.dev
276+ X-Mailman-Version: ...
277+ Precedence: list
278+ List-Id: <alpha.lists.launchpad.dev>
279+ List-Help: <http://help.launchpad.dev/ListHelp>
280+ List-Subscribe: <http://launchpad.dev/~alpha>
281+ List-Unsubscribe: <http://launchpad.dev/~alpha>
282+ List-Post: <mailto:alpha@lists.launchpad.dev>
283+ List-Archive: <http://lists.launchpad.dev/alpha>
284+ List-Owner: <http://launchpad.dev/~alpha>
285+ MIME-Version: 1.0
286+ Content-Type: text/plain; charset="us-ascii"
287+ Content-Transfer-Encoding: 7bit
288+ Sender: alpha-bounces+anne.person=example.com@lists.launchpad.dev
289+ Errors-To: alpha-bounces+anne.person=example.com@lists.launchpad.dev
290+ X-Peer: ...
291+ X-MailFrom: alpha-bounces+anne.person=example.com@lists.launchpad.dev
292+ X-RcptTo: anne.person@example.com
293+ <BLANKLINE>
294+ This is a test message.
295+ _______________________________________________
296+ Mailing list: http://launchpad.dev/~alpha
297+ Post to : alpha@lists.launchpad.dev
298+ Unsubscribe : http://launchpad.dev/~alpha
299+ More help : http://help.launchpad.dev/ListHelp
300
301=== modified file 'lib/lp/services/mailman/doc/bounces.txt'
302--- lib/lp/services/mailman/doc/bounces.txt 2009-06-03 16:03:04 +0000
303+++ lib/lp/services/mailman/doc/bounces.txt 2009-09-24 20:25:22 +0000
304@@ -1,3 +1,4 @@
305+=================
306 Bounce processing
307 =================
308
309
310=== modified file 'lib/lp/services/mailman/doc/contact-address.txt'
311--- lib/lp/services/mailman/doc/contact-address.txt 2009-06-26 21:58:35 +0000
312+++ lib/lp/services/mailman/doc/contact-address.txt 2009-09-24 20:25:22 +0000
313@@ -28,7 +28,7 @@
314 >>> browser.getControl('Change').click()
315
316 >>> browser.getLink('Change details').click()
317- >>> browser.getLink('Change contact address').click()
318+ >>> browser.getLink('Set contact address').click()
319 >>> control = browser.getControl(name='field.contact_method')
320 >>> [strip_label(label) for label in control.displayValue]
321 ['The Launchpad mailing list for this team...]
322@@ -237,7 +237,7 @@
323 >>> browser.getControl('Change').click()
324
325 >>> browser.getLink('Change details').click()
326- >>> browser.getLink('Change contact address').click()
327+ >>> browser.getLink('Set contact address').click()
328 >>> control = browser.getControl(name='field.contact_method')
329 >>> [strip_label(label) for label in control.displayValue]
330 ['Each member individually']
331
332=== modified file 'lib/lp/services/mailman/doc/create-lists.txt'
333--- lib/lp/services/mailman/doc/create-lists.txt 2009-06-23 17:51:24 +0000
334+++ lib/lp/services/mailman/doc/create-lists.txt 2009-09-24 20:25:22 +0000
335@@ -21,7 +21,7 @@
336 To request a mailing list, No Privileges Person navigates to the 'Configure
337 mailing list' page and registers their application for a mailing list.
338
339- >>> browser.getLink('Configure mailing list').click()
340+ >>> browser.getLink('Create a mailing list').click()
341 >>> browser.getControl('Apply for Mailing List').click()
342
343 At this point, Mailman has still not created the mailing list.
344@@ -56,7 +56,7 @@
345 >>> browser.getControl(name='field.subscriptionpolicy').displayValue = [
346 ... 'Open Team']
347 >>> browser.getControl('Create').click()
348- >>> browser.getLink('Configure mailing list').click()
349+ >>> browser.getLink('Create a mailing list').click()
350 >>> browser.getControl('Apply for Mailing List').click()
351
352 This time, however, the mailing list expert declines the application for a new
353
354=== modified file 'lib/lp/services/mailman/doc/decorations.txt'
355--- lib/lp/services/mailman/doc/decorations.txt 2009-06-23 19:33:57 +0000
356+++ lib/lp/services/mailman/doc/decorations.txt 2009-09-24 20:25:22 +0000
357@@ -117,8 +117,7 @@
358 >>> browser = Browser('no-priv@canonical.com:test')
359 >>> browser.open('http://launchpad.dev:8085/~itest-one')
360 >>> browser.getLink(id='mailing-list-archive')
361- <Link text='Mailing list archive'
362- url='http://lists.launchpad.dev/itest-one'>
363+ <Link text='View archive' url='http://lists.launchpad.dev/itest-one'>
364 >>> print message['list-archive']
365 <http://lists.launchpad.dev/itest-one>
366
367
368=== modified file 'lib/lp/services/mailman/doc/logging.txt'
369--- lib/lp/services/mailman/doc/logging.txt 2009-04-17 10:32:16 +0000
370+++ lib/lp/services/mailman/doc/logging.txt 2009-09-24 20:25:22 +0000
371@@ -1,9 +1,12 @@
372-= Logging and OOPS reporting =
373+==========================
374+Logging and OOPS reporting
375+==========================
376
377 The Mailman XMLRPCRunner logs errors and reports OOPSes.
378
379
380-= MailmanErrorUtility =
381+MailmanErrorUtility
382+===================
383
384 The MailmanErrorUtility is a ErrorReportingUtility that is configured
385 in the [mailman] section of config.
386@@ -13,21 +16,22 @@
387 ... MailmanErrorUtility)
388
389 >>> error_utility = MailmanErrorUtility()
390- >>> error_utility._default_config_section
391- 'mailman'
392-
393- >>> error_utility.prefix
394- 'TMMX'
395- >>> config.mailman.oops_prefix
396- 'TMMX'
397-
398- >>> error_utility.error_dir
399- '/var/tmp/mailman-xmlrpc.test'
400- >>> config.mailman.error_dir
401- '/var/tmp/mailman-xmlrpc.test'
402-
403-
404-= Error logging =
405+ >>> print error_utility._default_config_section
406+ mailman
407+
408+ >>> print error_utility.prefix
409+ TMMX
410+ >>> print config.mailman.oops_prefix
411+ TMMX
412+
413+ >>> print error_utility.error_dir
414+ /var/tmp/mailman-xmlrpc.test
415+ >>> print config.mailman.error_dir
416+ /var/tmp/mailman-xmlrpc.test
417+
418+
419+Error logging
420+=============
421
422 The log_exception() function is used by XMLRPCRunner to report known
423 exceptions. It reports the OOPS.
424@@ -44,12 +48,12 @@
425
426 >>> test_log_exception()
427 >>> oops = error_utility.getLastOopsReport()
428- >>> oops.id
429- 'OOPS-...TMMX...'
430- >>> oops.type
431- 'AssertionError'
432- >>> oops.value
433- 'There is an OOPS in progress.'
434+ >>> print oops.id
435+ OOPS-...TMMX...
436+ >>> print oops.type
437+ AssertionError
438+ >>> print oops.value
439+ There is an OOPS in progress.
440 >>> print oops.tb_text
441 Traceback (most recent call last):
442 ...
443@@ -77,4 +81,3 @@
444 the _create() method. The create-lists-txt test was run to generate a
445 "NameError: global name 'defect' is not defined". The error was written
446 to the xmlrpc log, and an OOPS was reported.
447-
448
449=== modified file 'lib/lp/services/mailman/doc/messages.txt'
450--- lib/lp/services/mailman/doc/messages.txt 2009-04-17 10:32:16 +0000
451+++ lib/lp/services/mailman/doc/messages.txt 2009-09-24 20:25:22 +0000
452@@ -1,4 +1,6 @@
453-= Messages =
454+========
455+Messages
456+========
457
458 Launchpad uses a custom set of message templates that it installs
459 in mailman/templates/site. The installation conforms to the standard
460
461=== modified file 'lib/lp/services/mailman/doc/modify-lists.txt'
462--- lib/lp/services/mailman/doc/modify-lists.txt 2009-06-03 16:03:04 +0000
463+++ lib/lp/services/mailman/doc/modify-lists.txt 2009-09-24 20:25:22 +0000
464@@ -1,4 +1,6 @@
465-= Modifying lists =
466+===============
467+Modifying lists
468+===============
469
470 A team administrator can make changes to the mailing list, although currently
471 the only thing they can change is the list's welcome message.
472@@ -13,7 +15,7 @@
473 >>> browser.getControl(name='field.subscriptionpolicy').displayValue = [
474 ... 'Open Team']
475 >>> browser.getControl('Create').click()
476- >>> browser.getLink('Configure mailing list').click()
477+ >>> browser.getLink('Create a mailing list').click()
478 >>> browser.getControl('Apply for Mailing List').click()
479
480 Before approving the creation of the mailing list, let's set the welcome
481@@ -26,7 +28,7 @@
482 >>> from canonical.launchpad.interfaces import (
483 ... ILaunchpadCelebrities, IMailingListSet, MailingListStatus)
484
485- >>> login('foo.bar@canonical.com')
486+ >>> login('admin@canonical.com')
487 >>> list_set = getUtility(IMailingListSet)
488 >>> list_one = list_set.get('itest-one')
489 >>> list_one.welcome_message = 'Greetings team members!'
490
491=== modified file 'lib/lp/services/mailman/doc/postings.txt'
492--- lib/lp/services/mailman/doc/postings.txt 2009-06-26 21:42:20 +0000
493+++ lib/lp/services/mailman/doc/postings.txt 2009-09-24 20:25:22 +0000
494@@ -1,3 +1,4 @@
495+=======
496 Posting
497 =======
498
499@@ -14,7 +15,7 @@
500
501
502 Non-member postings
503--------------------
504+===================
505
506 Postings from addresses that are not registered and verified with Launchpad
507 are summarily discarded.
508@@ -37,7 +38,7 @@
509
510
511 Non-validated member postings
512------------------------------
513+=============================
514
515 Similarly, an address that has been registered with Launchpad but not verified
516 will also be summarily discarded. Anne registers with Launchpad but does not
517@@ -48,7 +49,7 @@
518 >>> from canonical.launchpad.ftests import login, logout
519 >>> from canonical.launchpad.interfaces import EmailAddressStatus
520
521- >>> login('foo.bar@canonical.com')
522+ >>> login('admin@canonical.com')
523 >>> anne = factory.makePersonByName('Anne')
524 >>> alternative_email = get_alternative_email(anne)
525
526@@ -75,7 +76,7 @@
527
528
529 Unsubscribed Launchpad members
530-------------------------------
531+==============================
532
533 Anne's preferred email address is still validated, and she posts a message
534 from that address. However, because she has not yet joined the team or
535@@ -336,7 +337,7 @@
536
537
538 Unsubscribed team member
539-------------------------
540+========================
541
542 Once Anne joins the team, she may post to it, though until she subscribes to
543 the mailing list, she will not get a copy of the message.
544@@ -356,7 +357,7 @@
545
546 >>> from zope.component import getUtility
547 >>> from canonical.launchpad.interfaces import IPersonSet
548- >>> login('foo.bar@canonical.com')
549+ >>> login('admin@canonical.com')
550 >>> team_one = getUtility(IPersonSet).getByName('itest-one')
551 >>> anne.join(team_one)
552 >>> transaction.commit()
553@@ -407,7 +408,7 @@
554
555
556 Verified and registered member postings
557----------------------------------------
558+=======================================
559
560 Anne now subscribes to the team's mailing list. She gets a copy of each
561 message posted to the mailing list.
562@@ -503,7 +504,7 @@
563
564 However, once she validates this address, she can post from it.
565
566- >>> login('foo.bar@canonical.com')
567+ >>> login('admin@canonical.com')
568 >>> alternative_email.status = EmailAddressStatus.VALIDATED
569 >>> logout()
570 >>> transaction.commit()
571@@ -570,11 +571,11 @@
572
573
574 Leaving and re-joining the team
575--------------------------------
576+===============================
577
578 Anne now leaves the team, but she does not unsubscribe from the mailing list.
579
580- >>> login('foo.bar@canonical.com')
581+ >>> login('admin@canonical.com')
582 >>> team_one = getUtility(IPersonSet).getByName('itest-one')
583 >>> anne.leave(team_one)
584 >>> logout()
585@@ -619,7 +620,7 @@
586 Anne re-joins the team and once again can post to the mailing list. She does
587 not need to re-subscribe to the mailing list.
588
589- >>> login('foo.bar@canonical.com')
590+ >>> login('admin@canonical.com')
591 >>> anne.join(team_one)
592 >>> logout()
593 >>> transaction.commit()
594@@ -654,12 +655,12 @@
595
596
597 First post moderation
598----------------------
599+=====================
600
601 Normally, Launchpad members who are not subscribed to the mailing list will
602 have their posts held for moderation.
603
604- >>> login('foo.bar@canonical.com')
605+ >>> login('admin@canonical.com')
606 >>> bart = factory.makePersonByName('Bart')
607 >>> transaction.commit()
608 >>> bart.personal_standing
609@@ -694,7 +695,7 @@
610 list.
611
612 >>> from canonical.launchpad.interfaces import PersonalStanding
613- >>> login('foo.bar@canonical.com')
614+ >>> login('admin@canonical.com')
615 >>> bart.personal_standing = PersonalStanding.GOOD
616 >>> transaction.commit()
617
618@@ -809,7 +810,7 @@
619
620
621 Preventing archiver forgeries
622------------------------------
623+=============================
624
625 We archive messages by sending them to a special address owned by the Mail
626 Archive <http://www.mail-archive.com>. This address becomes a recipient of
627@@ -834,7 +835,7 @@
628
629
630 Large messages
631---------------
632+==============
633
634 Only messages which are less than about 40k in size are allowed straight
635 through on the mailing list. A message bigger than that will be held for
636
637=== modified file 'lib/lp/services/mailman/doc/reactivate-lists.txt'
638--- lib/lp/services/mailman/doc/reactivate-lists.txt 2009-05-06 15:13:39 +0000
639+++ lib/lp/services/mailman/doc/reactivate-lists.txt 2009-09-24 20:25:22 +0000
640@@ -1,4 +1,6 @@
641-= Re-activating mailing lists =
642+===========================
643+Re-activating mailing lists
644+===========================
645
646 A team administrator may re-activate a previously deactivated mailing list
647 without the need for approval from a Launchpad administrator. When the
648@@ -48,7 +50,7 @@
649
650 Now the team owner reactivates the list.
651
652- >>> browser.getLink('Configure mailing list').click()
653+ >>> browser.getLink('Create a mailing list').click()
654 >>> browser.getControl('Reactivate this Mailing List').click()
655 >>> xmlrpc_watcher.wait_for_reactivation('itest-one')
656
657
658=== modified file 'lib/lp/services/mailman/doc/recovery.txt'
659--- lib/lp/services/mailman/doc/recovery.txt 2009-06-03 16:03:04 +0000
660+++ lib/lp/services/mailman/doc/recovery.txt 2009-09-24 20:25:22 +0000
661@@ -1,4 +1,6 @@
662-= Error recovery =
663+==============
664+Error recovery
665+==============
666
667 Under various conditions, reporting status from Mailman to Launchpad can
668 fail. For example, if during construction, the reportStatus() call has
669@@ -18,14 +20,15 @@
670 >>> browser.getControl(name='field.subscriptionpolicy').displayValue = [
671 ... 'Open Team']
672 >>> browser.getControl('Create').click()
673- >>> browser.getLink('Configure mailing list').click()
674+ >>> browser.getLink('Create a mailing list').click()
675 >>> browser.getControl('Apply for Mailing List').click()
676
677 >>> from lp.services.mailman.testing import helpers
678 >>> list_one = helpers.review_list('itest-one')
679
680
681-== Lost construction ==
682+Lost construction
683+=================
684
685 The mailing list is now active, but let's say that the status reporting
686 failed. The mailing list would be in the CONSTRUCTING state. We
687@@ -37,7 +40,7 @@
688 >>> from canonical.launchpad.interfaces import (
689 ... IMailingListSet, MailingListStatus)
690 >>> from canonical.launchpad.ftests import login, logout
691- >>> login('foo.bar@canonical.com')
692+ >>> login('admin@canonical.com')
693 >>> mailing_list_set = getUtility(IMailingListSet)
694 >>> itest_one = removeSecurityProxy(mailing_list_set.get('itest-one'))
695 >>> itest_one.status = MailingListStatus.CONSTRUCTING
696@@ -84,7 +87,8 @@
697 <DBItem MailingListStatus.ACTIVE, (5) Active>
698
699
700-== Lost updates ==
701+Lost updates
702+============
703
704 Another situation can occur if the team owner updates the mailing list,
705 say by giving it a welcome message.
706
707=== modified file 'lib/lp/services/mailman/doc/staging.txt'
708--- lib/lp/services/mailman/doc/staging.txt 2009-06-30 17:37:35 +0000
709+++ lib/lp/services/mailman/doc/staging.txt 2009-09-24 20:25:22 +0000
710@@ -20,8 +20,7 @@
711
712 >>> from canonical.launchpad.ftests import login, logout
713
714- >>> login('foo.bar@canonical.com')
715- >>> from zope.component import getUtility
716+ >>> login('admin@canonical.com')
717
718 >>> owner = factory.makePerson()
719 >>> team_one = factory.makeTeam(owner=owner, name='staging-one')
720@@ -127,7 +126,7 @@
721 >>> from canonical.launchpad.interfaces import (
722 ... EmailAddressStatus, IEmailAddressSet, IPersonSet)
723 >>> from zope.component import getUtility
724- >>> login('foo.bar@canonical.com')
725+ >>> login('admin@canonical.com')
726 >>> team = getUtility(IPersonSet).getByName('staging-two')
727 >>> email = getUtility(IEmailAddressSet).new(
728 ... 'contact@example.com', team, EmailAddressStatus.VALIDATED)
729
730=== modified file 'lib/lp/services/mailman/doc/subscriptions.txt'
731--- lib/lp/services/mailman/doc/subscriptions.txt 2009-06-03 16:03:04 +0000
732+++ lib/lp/services/mailman/doc/subscriptions.txt 2009-09-24 20:25:22 +0000
733@@ -1,4 +1,6 @@
734-= Mailing list subscriptions =
735+==========================
736+Mailing list subscriptions
737+==========================
738
739 Both direct and indirect members of a team may subscribe to a team's mailing
740 list. First, create the mailing list, which will send a notification messages
741@@ -57,7 +59,7 @@
742 >>> from lp.registry.interfaces.person import IPersonSet
743 >>> from zope.component import getUtility
744
745- >>> login('foo.bar@canonical.com')
746+ >>> login('admin@canonical.com')
747 >>> person_set = getUtility(IPersonSet)
748
749 >>> anne = person_set.getByName('anne')
750@@ -88,7 +90,7 @@
751
752 Bart now leaves the team. His subscription is removed.
753
754- >>> login('foo.bar@canonical.com')
755+ >>> login('admin@canonical.com')
756 >>> bart = person_set.getByName('bart')
757 >>> team_one = person_set.getByName('itest-one')
758 >>> bart.leave(team_one)
759@@ -97,7 +99,8 @@
760 >>> helpers.ensure_nonmembership('itest-one', bart)
761
762
763-== Alternative addresses ==
764+Alternative addresses
765+=====================
766
767 Now Anne decides to register another email address with Launchpad, however
768 before she can validate this address, subscriptions for the list are
769@@ -105,7 +108,7 @@
770 the membership list, either as an enabled or disabled address.
771
772 >>> from canonical.launchpad.interfaces import IEmailAddressSet
773- >>> login('foo.bar@canonical.com')
774+ >>> login('admin@canonical.com')
775 >>> email_set = getUtility(IEmailAddressSet)
776 >>> email = email_set.new(
777 ... 'anne.x.person@example.net', anne, account=anne.account)
778@@ -145,7 +148,8 @@
779 No Privileges Person <no-priv@canonical.com> DISABLED
780
781
782-== Case-preservation ==
783+Case-preservation
784+=================
785
786 Mailing lists preserve the case of the subscribed email address,
787 although for subscription purposes, two email addresses that differs
788@@ -154,7 +158,7 @@
789 Emma joins Launchpad as normal, then subscribes a mixed-case alternative
790 email address.
791
792- >>> login('foo.bar@canonical.com')
793+ >>> login('admin@canonical.com')
794 >>> emma = factory.makePersonByName('Emma')
795 >>> email = email_set.new(
796 ... 'EmmaXPerson@example.org', emma, account=emma.account)
797
798=== modified file 'lib/lp/services/mailman/testing/helpers.py'
799--- lib/lp/services/mailman/testing/helpers.py 2009-06-25 04:06:00 +0000
800+++ lib/lp/services/mailman/testing/helpers.py 2009-09-24 20:25:22 +0000
801@@ -103,7 +103,7 @@
802 'Open Team']
803 browser.getControl('Create').click()
804 # Create the mailing list.
805- browser.getLink('Configure mailing list').click()
806+ browser.getLink('Create a mailing list').click()
807 browser.getControl('Apply for Mailing List').click()
808 mailing_list = review_list(team_name)
809 # pylint: disable-msg=F0401
810
811=== modified file 'lib/lp/services/mailman/testing/logwatcher.py'
812--- lib/lp/services/mailman/testing/logwatcher.py 2009-07-17 00:26:05 +0000
813+++ lib/lp/services/mailman/testing/logwatcher.py 2009-09-24 20:25:22 +0000
814@@ -33,8 +33,8 @@
815
816 BREAK_ON_TIMEOUT = bool(os.getenv('BREAK_ON_TIMEOUT'))
817 LINES_TO_CAPTURE = 50
818-LOG_GROWTH_WAIT_INTERVAL = datetime.timedelta(seconds=20)
819-FAILURE_CAPTURE_INTERVAL = datetime.timedelta(seconds=60)
820+LOG_GROWTH_WAIT_INTERVAL = datetime.timedelta(seconds=10)
821+FAILURE_CAPTURE_INTERVAL = datetime.timedelta(seconds=10)
822 SECONDS_TO_SNOOZE = 0.1
823 Empty = object()
824 NL = '\n'