Merge lp:~sinzui/launchpad/mailman-email-addresses into lp:launchpad

Proposed by Curtis Hovey on 2012-09-13
Status: Merged
Approved by: j.c.sackett on 2012-09-13
Approved revision: no longer in the source branch.
Merged at revision: 15954
Proposed branch: lp:~sinzui/launchpad/mailman-email-addresses
Merge into: lp:launchpad
Diff against target: 176 lines (+36/-87)
3 files modified
lib/lp/registry/doc/message-holds.txt (+0/-84)
lib/lp/registry/model/mailinglist.py (+3/-3)
lib/lp/registry/tests/test_mailinglist.py (+33/-0)
To merge this branch: bzr merge lp:~sinzui/launchpad/mailman-email-addresses
Reviewer Review Type Date Requested Status
j.c.sackett (community) 2012-09-13 Approve on 2012-09-13
Review via email: mp+124273@code.launchpad.net

Commit Message

Send mailmain lowercased email addresses.

Description of the Change

This is triggering nagios alerts, as the current MARK delta alert is set
to 40 minutes. Mailman is configured to write write MARKs to the log every
5 minutes.

Mailman's xmlrpc runner log shows it spends more than 99% of its time
acquiring locks to mailing lists to write email address cases changes to
disk. The email address are lower-cased though, so the change is no-op.

--------------------------------------------------------------------

RULES

    Pre-implementation: no one
    * Lowercase the email addresses that are sent to mailman.

QA

    * Review the staging mailman/xmlrc log or run
      fgrep MARK /path/to/mailman/logs/xmlrpc | tail -100
    * Verify the log does not show mix-case changes.
    * After release and after logs mailman logs are sync to carob
      review the tail of /srv/launchpad.net-logs/mailman/polevik/xmlrpc
    * verify the log does not show wasted work saving mixed-case email
      addresses.
    * Is MARK appearing closer to every 5 minutes?

LINT

    lib/lp/registry/doc/message-holds.txt
    lib/lp/registry/model/mailinglist.py
    lib/lp/registry/tests/test_mailinglist.py

TEST

    ./bin/test -vv -t TestMailinglistSet lp.registry.tests.test_mailinglist

LoC

    This branch adds two tests, but removes "Posting privileges" section
    from a doctest because the behaviour is test elsewhere in the doctest
    and explicitly in:
    TestMailinglistSetMessages.test_getSenderAddresses_approved_dict_values

IMPLEMENTATION

Lowercase the email address return by IMailingListSet getSenderAddresses()
and getSubscribedAddresses().
    lib/lp/registry/model/mailinglist.py
    lib/lp/registry/tests/test_mailinglist.py

Removed test that shows approving a held message add the use to
getSubscribedAddresses().
    lib/lp/registry/doc/message-holds.txt

To post a comment you must log in.
j.c.sackett (jcsackett) wrote :

Thanks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/doc/message-holds.txt'
2--- lib/lp/registry/doc/message-holds.txt 2012-01-04 06:52:11 +0000
3+++ lib/lp/registry/doc/message-holds.txt 2012-09-13 18:04:22 +0000
4@@ -372,90 +372,6 @@
5 The Launchpad team
6 ----------------------------------------
7
8-
9-== Posting privileges ==
10-Message approvals are also used to derived posting privileges for non-team
11-members. To start with, only the team owner can post to the list.
12-
13- >>> login('no-priv@canonical.com')
14- >>> team_three, list_three = mailinglists_helper.new_team(
15- ... 'test-three', True)
16- >>> sorted(list_three.getSenderAddresses())
17- [u'no-priv@canonical.com']
18-
19-Salgado posts a message to the list, but because he is not a team member, it
20-gets held for approval.
21-
22- >>> message = message_set.fromEmail("""\
23- ... From: guilherme.salgado@canonical.com
24- ... To: test-one@lists.launchpad.dev
25- ... Subject: My first test
26- ... Message-ID: <zebra>
27- ... Date: Fri, 01 Aug 2000 01:08:59 -0000
28- ...
29- ... This is my first post!
30- ... """)
31- >>> held_message = list_three.holdMessage(message)
32- >>> transaction.commit()
33-
34-If the message gets discarded (or rejected), Salgado is still not allowed to
35-post to the mailing list.
36-
37- >>> held_message.discard(owner)
38- >>> held_message.acknowledge()
39- >>> transaction.commit()
40-
41- >>> sorted(list_three.getSenderAddresses())
42- [u'no-priv@canonical.com']
43-
44- >>> from lp.registry.interfaces.mailinglist import IMailingListSet
45- >>> mailinglist_set = getUtility(IMailingListSet)
46- >>> bulk_addresses = mailinglist_set.getSenderAddresses(['test-three'])
47- >>> sorted(email for name, email in bulk_addresses['test-three'])
48- [u'no-priv@canonical.com']
49-
50-Salgado posts another message to the list, but this time it's approved.
51-
52- >>> message = message_set.fromEmail("""\
53- ... From: guilherme.salgado@canonical.com
54- ... To: test-one@lists.launchpad.dev
55- ... Subject: My first test
56- ... Message-ID: <yeti>
57- ... Date: Fri, 01 Aug 2000 01:08:59 -0000
58- ...
59- ... This is my second post!
60- ... """)
61- >>> held_message = list_three.holdMessage(message)
62- >>> transaction.commit()
63-
64- >>> held_message.approve(owner)
65- >>> held_message.acknowledge()
66- >>> transaction.commit()
67-
68-Now, Salgado is on the list of approved posters.
69-
70- >>> sorted(list_three.getSenderAddresses())
71- [u'guilherme.salgado@canonical.com', u'no-priv@canonical.com']
72-
73- >>> bulk_addresses = mailinglist_set.getSenderAddresses(['test-three'])
74- >>> sorted(email for name, email in bulk_addresses['test-three'])
75- [u'guilherme.salgado@canonical.com', u'no-priv@canonical.com']
76-
77-But he will still not get messages delivered to his address, since he's not
78-subscribed to the team mailing list.
79-
80- >>> sorted(list_three.getSubscribedAddresses())
81- []
82-
83-Of course, Salgado still cannot post to a mailing list that he has not been
84-approved for, because he has not had three approved moderations.
85-
86- >>> team_four, list_four = mailinglists_helper.new_team(
87- ... 'test-four', True)
88- >>> sorted(list_four.getSenderAddresses())
89- [u'no-priv@canonical.com']
90-
91-
92 == Duplicates ==
93
94 When a person responds to a bug email, the message can end up in the database
95
96=== modified file 'lib/lp/registry/model/mailinglist.py'
97--- lib/lp/registry/model/mailinglist.py 2012-01-04 22:30:45 +0000
98+++ lib/lp/registry/model/mailinglist.py 2012-09-13 18:04:22 +0000
99@@ -616,7 +616,7 @@
100 for email, display_name, team_name in preferred:
101 assert team_name in team_names, (
102 'Unexpected team name in results: %s' % team_name)
103- value = (display_name, email)
104+ value = (display_name, email.lower())
105 by_team[team_name].add(value)
106 explicit = store.using(*tables).find(
107 (EmailAddress.email, Person.displayname, Team.name),
108@@ -628,7 +628,7 @@
109 for email, display_name, team_name in explicit:
110 assert team_name in team_names, (
111 'Unexpected team name in results: %s' % team_name)
112- value = (display_name, email)
113+ value = (display_name, email.lower())
114 by_team[team_name].add(value)
115 # Turn the results into a mapping of lists.
116 results = {}
117@@ -688,7 +688,7 @@
118 for team_name, person_displayname, email in all_posters:
119 assert team_name in team_names, (
120 'Unexpected team name in results: %s' % team_name)
121- value = (person_displayname, email)
122+ value = (person_displayname, email.lower())
123 by_team[team_name].add(value)
124 # Turn the results into a mapping of lists.
125 results = {}
126
127=== modified file 'lib/lp/registry/tests/test_mailinglist.py'
128--- lib/lp/registry/tests/test_mailinglist.py 2012-08-13 19:51:16 +0000
129+++ lib/lp/registry/tests/test_mailinglist.py 2012-09-13 18:04:22 +0000
130@@ -108,6 +108,20 @@
131 for m in team1.allmembers])
132 self.assertEqual(list_senders, sorted(result[team1.name]))
133
134+ def test_getSenderAddresses_multiple_and_lowercase_email(self):
135+ # getSenderAddresses() contains multiple email addresses for
136+ # users and they are lowercased for mailman.
137+ # {team_name: [(member_displayname, member_email) ...]}
138+ team1, member1 = self.factory.makeTeamWithMailingListSubscribers(
139+ 'team1', auto_subscribe=False)
140+ email = self.factory.makeEmail('me@EG.dom', member1)
141+ result = self.mailing_list_set.getSenderAddresses([team1.name])
142+ list_senders = sorted([
143+ (m.displayname, m.preferredemail.email)
144+ for m in team1.allmembers])
145+ list_senders.append((member1.displayname, email.email.lower()))
146+ self.assertContentEqual(list_senders, result[team1.name])
147+
148 def test_getSenderAddresses_participation_dict_values(self):
149 # getSenderAddresses() dict values includes indirect participants.
150 team1, member1 = self.factory.makeTeamWithMailingListSubscribers(
151@@ -140,6 +154,25 @@
152 (member1.displayname, member1.preferredemail.email)]
153 self.assertEqual(list_subscribers, result[team1.name])
154
155+ def test_getSubscribedAddresses_multiple_lowercase_email(self):
156+ # getSubscribedAddresses() contains email addresses for
157+ # users and they are lowercased for mailman. The email maybe
158+ # explicitly set instead of the preferred email.
159+ # {team_name: [(member_displayname, member_email) ...]}
160+ team1, member1 = self.factory.makeTeamWithMailingListSubscribers(
161+ 'team1')
162+ with person_logged_in(member1):
163+ email1 = self.factory.makeEmail('me@EG.dom', member1)
164+ member1.setPreferredEmail(email1)
165+ with person_logged_in(team1.teamowner):
166+ email2 = self.factory.makeEmail('you@EG.dom', team1.teamowner)
167+ team1.mailing_list.subscribe(team1.teamowner, email2)
168+ result = self.mailing_list_set.getSubscribedAddresses([team1.name])
169+ list_subscribers = [
170+ (member1.displayname, email1.email.lower()),
171+ (team1.teamowner.displayname, email2.email.lower())]
172+ self.assertContentEqual(list_subscribers, result[team1.name])
173+
174 def test_getSubscribedAddresses_participation_dict_values(self):
175 # getSubscribedAddresses() dict values includes indirect participants.
176 team1, member1 = self.factory.makeTeamWithMailingListSubscribers(