Merge lp:~gary/launchpad/bug164196-3 into lp:launchpad/db-devel

Proposed by Gary Poster
Status: Merged
Approved by: Gary Poster
Approved revision: no longer in the source branch.
Merged at revision: 10215
Proposed branch: lp:~gary/launchpad/bug164196-3
Merge into: lp:launchpad/db-devel
Prerequisite: lp:~gary/launchpad/bug164196-2
Diff against target: 519 lines (+140/-30)
13 files modified
cronscripts/send-bug-notifications.py (+8/-1)
database/schema/comments.sql (+1/-0)
database/schema/patch-2208-45-0.sql (+12/-0)
lib/lp/bugs/doc/bugnotification-sending.txt (+61/-19)
lib/lp/bugs/doc/bugnotification-threading.txt (+3/-3)
lib/lp/bugs/enum.py (+27/-0)
lib/lp/bugs/interfaces/bugnotification.py (+9/-0)
lib/lp/bugs/mail/tests/test_bug_task_assignment.py (+2/-2)
lib/lp/bugs/mail/tests/test_bug_task_modification.py (+1/-1)
lib/lp/bugs/model/bugnotification.py (+6/-0)
lib/lp/bugs/scripts/bugnotification.py (+4/-1)
lib/lp/bugs/scripts/tests/test_bugnotification.py (+4/-2)
lib/lp/bugs/tests/test_bugchanges.py (+2/-1)
To merge this branch: bzr merge lp:~gary/launchpad/bug164196-3
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Stuart Bishop db Approve
Aaron Bentley (community) Approve
Review via email: mp+49980@code.launchpad.net

Commit message

[r=abentley,stub][bug=164196] makes sure that the omitted notification objects left over from duplicate actions are marked as processed so that they are not perpetually considered for subsequent notification cronscript runs.

Description of the change

This is the last of three branches that address bug 164196, and one of two that have a database patch. The other two are lp:~gary/launchpad/bug164196-1 and lp:~gary/launchpad/bug164196-3. My pre-implementation call for these changes was with Graham Binns.

This branch makes sure that the omitted notification objects left over from actions in the previous branch are marked as processed so that they are not perpetually considered for subsequent notification cronscript runs. It also marks these omitted notification objects with a flag in case we want to analyze them for debugging later, if we get a report of something gone wrong in this regard.

The database changes simply add the flag as described above.

The code in lib/lp/bugs/scripts/bugnotification.py now includes the omitted notifications so that the cronscript can mark them. This required small changes to a number of tests.

lib/lp/bugs/doc/bugnotification-sending.txt had the test for the cronscript and were a natural place for a smoketest of this behavior.

Thank you

Gary

To post a comment you must log in.
Aaron Bentley (abentley) wrote :

Per our IRC discussion, I recommend providing a status enum, rather than just is_omitted. The values could include PENDING, SENT, SKIPPED.

I believe ResultSets support slicing, so it might be clearer in the doctest to get a ResultSet and then slice it.

However, the branch as it stands is a worthwhile improvement, so I'll approve it.

review: Approve
Gary Poster (gary) wrote :

I have followed both of Aaron's suggestions, because I agreed that they were nicer. If Stuart prefers a bool after all (presumably because of space reasons), I can revert that bit pretty easily.

Thank you

Stuart Bishop (stub) wrote :

patch-2208-45-0.sql

Please add the following statement after the ALTER TABLE (all rows are going to be rewritten, so we want to repack the table):

CLUSTER BugNotification USING bugnotification__date_emailed__idx

Bug notification is regularly trimmed, so there are not too many rows to deal with - should be fast enough for a db patch.

I prefer status rather than the boolean too.

review: Approve (db)
Robert Collins (lifeless) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cronscripts/send-bug-notifications.py'
2--- cronscripts/send-bug-notifications.py 2010-11-08 12:52:43 +0000
3+++ cronscripts/send-bug-notifications.py 2011-02-17 17:43:44 +0000
4@@ -20,6 +20,7 @@
5 from canonical.config import config
6 from canonical.database.constants import UTC_NOW
7 from canonical.launchpad.mail import sendmail
8+from lp.bugs.enum import BugNotificationStatus
9 from lp.bugs.interfaces.bugnotification import IBugNotificationSet
10 from lp.bugs.scripts.bugnotification import get_email_notifications
11 from lp.services.scripts.base import LaunchpadCronScript
12@@ -30,7 +31,9 @@
13 notifications_sent = False
14 pending_notifications = get_email_notifications(getUtility(
15 IBugNotificationSet).getNotificationsToSend())
16- for bug_notifications, messages in pending_notifications:
17+ for (bug_notifications,
18+ omitted_notifications,
19+ messages) in pending_notifications:
20 for message in messages:
21 self.logger.info("Notifying %s about bug %d." % (
22 message['To'], bug_notifications[0].bug.id))
23@@ -38,6 +41,10 @@
24 self.logger.debug(message.as_string())
25 for notification in bug_notifications:
26 notification.date_emailed = UTC_NOW
27+ notification.status = BugNotificationStatus.SENT
28+ for notification in omitted_notifications:
29+ notification.date_emailed = UTC_NOW
30+ notification.status = BugNotificationStatus.OMITTED
31 notifications_sent = True
32 # Commit after each batch of email sent, so that we won't
33 # re-mail the notifications in case of something going wrong
34
35=== modified file 'database/schema/comments.sql'
36--- database/schema/comments.sql 2011-02-17 17:43:43 +0000
37+++ database/schema/comments.sql 2011-02-17 17:43:44 +0000
38@@ -281,6 +281,7 @@
39 COMMENT ON COLUMN BugNotification.is_comment IS 'Is the change a comment addition.';
40 COMMENT ON COLUMN BugNotification.date_emailed IS 'When this notification was emailed to the bug subscribers.';
41 COMMENT ON COLUMN BugNotification.activity IS 'The BugActivity record corresponding to this notification, if any.';
42+COMMENT ON COLUMN BugNotification.status IS 'The status of this bug notification: pending, omitted, or sent.';
43
44
45 -- BugNotificationAttachment
46
47=== added file 'database/schema/patch-2208-45-0.sql'
48--- database/schema/patch-2208-45-0.sql 1970-01-01 00:00:00 +0000
49+++ database/schema/patch-2208-45-0.sql 2011-02-17 17:43:44 +0000
50@@ -0,0 +1,12 @@
51+-- Copyright 2011 Canonical Ltd. This software is licensed under the
52+-- GNU Affero General Public License version 3 (see the file LICENSE).
53+SET client_min_messages=ERROR;
54+
55+-- The default value for status can be found in the
56+-- BugNotificationStatus DBEnum in lib/lp/bugs/enum.py.
57+ALTER TABLE BugNotification
58+ ADD COLUMN status INTEGER NOT NULL DEFAULT 10;
59+
60+CLUSTER BugNotification USING bugnotification__date_emailed__idx;
61+
62+INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 45, 0);
63
64=== modified file 'lib/lp/bugs/doc/bugnotification-sending.txt'
65--- lib/lp/bugs/doc/bugnotification-sending.txt 2011-02-17 17:43:43 +0000
66+++ lib/lp/bugs/doc/bugnotification-sending.txt 2011-02-17 17:43:44 +0000
67@@ -63,7 +63,7 @@
68 >>> from lp.bugs.scripts.bugnotification import (
69 ... get_email_notifications)
70 >>> email_notifications = get_email_notifications(notifications)
71- >>> for bug_notifications, messages in email_notifications:
72+ >>> for bug_notifications, omitted, messages in email_notifications:
73 ... for message in messages:
74 ... print_notification(message)
75 To: foo.bar@canonical.com
76@@ -176,7 +176,7 @@
77 >>> pending_notifications = getUtility(
78 ... IBugNotificationSet).getNotificationsToSend()
79 >>> email_notifications = get_email_notifications(pending_notifications)
80- >>> for bug_notifications, messages in email_notifications:
81+ >>> for bug_notifications, omitted, messages in email_notifications:
82 ... for message in messages:
83 ... print_notification(message)
84 To: foo.bar@canonical.com
85@@ -222,7 +222,7 @@
86 2
87
88 >>> email_notifications = get_email_notifications(pending_notifications)
89- >>> for bug_notifications, messages in email_notifications:
90+ >>> for bug_notifications, omitted, messages in email_notifications:
91 ... for message in messages:
92 ... print_notification(message)
93 To: foo.bar@canonical.com
94@@ -275,7 +275,7 @@
95 in the order they were added:
96
97 >>> email_notifications = get_email_notifications(pending_notifications)
98- >>> for bug_notifications, messages in email_notifications:
99+ >>> for bug_notifications, omitted, messages in email_notifications:
100 ... for message in messages:
101 ... print_notification(message)
102 To: foo.bar@canonical.com
103@@ -371,7 +371,7 @@
104 1
105
106 >>> email_notifications = get_email_notifications(pending_notifications)
107- >>> for bug_notifications, messages in email_notifications:
108+ >>> for bug_notifications, omitted, messages in email_notifications:
109 ... for message in messages:
110 ... print message['To']
111 foo.bar@canonical.com
112@@ -414,7 +414,7 @@
113 >>> len(notifications)
114 1
115
116- >>> for bug_notifications, messages in (
117+ >>> for bug_notifications, omitted, messages in (
118 ... get_email_notifications(notifications)):
119 ... for message in messages:
120 ... print_notification(message)
121@@ -485,7 +485,7 @@
122 >>> notifications = (
123 ... getUtility(IBugNotificationSet).getNotificationsToSend())
124 >>> email_notifications = get_email_notifications(notifications)
125- >>> for bug_notifications, messages in email_notifications:
126+ >>> for bug_notifications, omitted, messages in email_notifications:
127 ... for message in messages:
128 ... print_notification(message)
129 To: support@ubuntu.com
130@@ -509,7 +509,7 @@
131 >>> notifications = (
132 ... getUtility(IBugNotificationSet).getNotificationsToSend())
133 >>> email_notifications = get_email_notifications(notifications)
134- >>> for bug_notifications, messages in email_notifications:
135+ >>> for bug_notifications, omitted, messages in email_notifications:
136 ... for message in messages:
137 ... print_notification(message)
138 To: support@ubuntu.com
139@@ -556,11 +556,19 @@
140 ... BugTitleChange(
141 ... ten_minutes_ago, sample_person, "title",
142 ... "Old summary", "New summary"))
143+ >>> bug_two.addChange(
144+ ... BugVisibilityChange(
145+ ... ten_minutes_ago, sample_person, "title",
146+ ... False, True))
147+ >>> bug_two.addChange(
148+ ... BugVisibilityChange(
149+ ... ten_minutes_ago, sample_person, "title",
150+ ... True, False))
151
152 >>> notifications = getUtility(
153 ... IBugNotificationSet).getNotificationsToSend()
154 >>> len(notifications)
155- 6
156+ 8
157
158 We need to commit the transaction so that the cronscript will see the
159 notifications.
160@@ -648,7 +656,41 @@
161 INFO Notifying test@canonical.com about bug 1.
162 ...
163
164- >>> flush_notifications()
165+Note that the message omitted the undone visibility change.
166+
167+The cronscript has to be sure to mark all notifications, omitted and
168+otherwise, as sent. It also marks the omitted notifications with a status,
169+so if there are any problems we can identify which notifications were omitted
170+during analysis. We'll commit a transaction to synchronize the database,
171+and then look at the notifications available.
172+
173+ >>> transaction.commit()
174+
175+ >>> notifications = getUtility(
176+ ... IBugNotificationSet).getNotificationsToSend()
177+ >>> len(notifications)
178+ 0
179+
180+They have all been marked as sent, including the omitted ones. Let's look
181+more carefully at the notifications just to see that the status has
182+been set properly.
183+
184+ >>> from lp.bugs.model.bugnotification import BugNotification
185+ >>> from lp.bugs.enum import BugNotificationStatus
186+ >>> for notification in BugNotification.select(orderBy='id')[-8:]:
187+ ... if notification.is_comment:
188+ ... identifier = 'comment'
189+ ... else:
190+ ... identifier = notification.activity.whatchanged
191+ ... print identifier, notification.status.title
192+ comment Sent
193+ summary Sent
194+ comment Sent
195+ summary Sent
196+ comment Sent
197+ summary Sent
198+ visibility Omitted
199+ visibility Omitted
200
201
202 The X-Launchpad-Bug header
203@@ -673,7 +715,7 @@
204 X-Launchpad-Bug headers were added:
205
206 >>> email_notifications = get_email_notifications(notifications)
207- >>> for bug_notifications, messages in email_notifications:
208+ >>> for bug_notifications, omitted, messages in email_notifications:
209 ... for message in messages:
210 ... sorted(message.get_all('X-Launchpad-Bug'))
211 [u'distribution=debian; distroseries=sarge;... milestone=3.1;...',
212@@ -707,7 +749,7 @@
213
214 >>> def get_email_messages(notifications):
215 ... messages = (message
216- ... for bug_notifications, messages in
217+ ... for bug_notifications, omitted, messages in
218 ... get_email_notifications(notifications)
219 ... for message in messages)
220 ... return sorted(messages, key=lambda message: message['To'])
221@@ -963,7 +1005,7 @@
222
223 >>> from itertools import chain
224 >>> collated_messages = collate_messages_by_recipient(
225- ... chain(*(messages for bug_notifications, messages in
226+ ... chain(*(messages for bug_notifications, omitted, messages in
227 ... get_email_notifications(notifications))))
228
229 We can see that Concise Person doesn't receive verbose notifications:
230@@ -1151,7 +1193,7 @@
231 >>> pending_notifications = getUtility(
232 ... IBugNotificationSet).getNotificationsToSend()
233 >>> email_notifications = get_email_notifications(pending_notifications)
234- >>> for bug_notifications, messages in email_notifications:
235+ >>> for bug_notifications, omitted, messages in email_notifications:
236 ... for message in messages:
237 ... print_notification(message)
238 To: foo.bar@canonical.com
239@@ -1212,7 +1254,7 @@
240 >>> pending_notifications = getUtility(
241 ... IBugNotificationSet).getNotificationsToSend()
242 >>> email_notifications = get_email_notifications(pending_notifications)
243- >>> for bug_notifications, messages in email_notifications:
244+ >>> for bug_notifications, omitted, messages in email_notifications:
245 ... for message in messages:
246 ... print_notification(message)
247 To: foo.bar@canonical.com
248@@ -1271,7 +1313,7 @@
249 >>> pending_notifications = getUtility(
250 ... IBugNotificationSet).getNotificationsToSend()
251 >>> email_notifications = get_email_notifications(pending_notifications)
252- >>> for bug_notifications, messages in email_notifications:
253+ >>> for bug_notifications, omitted, messages in email_notifications:
254 ... for message in messages:
255 ... print_notification(message)
256 To: foo.bar@canonical.com
257@@ -1322,7 +1364,7 @@
258 >>> pending_notifications = getUtility(
259 ... IBugNotificationSet).getNotificationsToSend()
260 >>> email_notifications = get_email_notifications(pending_notifications)
261- >>> for bug_notifications, messages in email_notifications:
262+ >>> for bug_notifications, omitted, messages in email_notifications:
263 ... for message in messages:
264 ... print_notification(message)
265 To: foo.bar@canonical.com
266@@ -1386,7 +1428,7 @@
267 >>> pending_notifications = getUtility(
268 ... IBugNotificationSet).getNotificationsToSend()
269 >>> email_notifications = get_email_notifications(pending_notifications)
270- >>> for bug_notifications, messages in email_notifications:
271+ >>> for bug_notifications, omitted, messages in email_notifications:
272 ... for message in messages:
273 ... print_notification(message)
274 To: foo.bar@canonical.com
275@@ -1448,7 +1490,7 @@
276 >>> pending_notifications = getUtility(
277 ... IBugNotificationSet).getNotificationsToSend()
278 >>> email_notifications = get_email_notifications(pending_notifications)
279- >>> for bug_notifications, messages in email_notifications:
280+ >>> for bug_notifications, omitted, messages in email_notifications:
281 ... for message in messages:
282 ... print_notification(message)
283 To: foo.bar@canonical.com
284
285=== modified file 'lib/lp/bugs/doc/bugnotification-threading.txt'
286--- lib/lp/bugs/doc/bugnotification-threading.txt 2011-02-02 17:33:21 +0000
287+++ lib/lp/bugs/doc/bugnotification-threading.txt 2011-02-17 17:43:44 +0000
288@@ -35,7 +35,7 @@
289 >>> notifications = getUtility(
290 ... IBugNotificationSet).getNotificationsToSend()
291
292- >>> messages = [emails for dummy, emails in
293+ >>> messages = [emails for notifications, omitted, emails in
294 ... get_email_notifications(notifications)]
295 >>> len(messages)
296 1
297@@ -73,7 +73,7 @@
298 ... True, False))
299 >>> notifications = getUtility(
300 ... IBugNotificationSet).getNotificationsToSend()
301- >>> messages = [emails for dummy, emails in
302+ >>> messages = [emails for notifications, omitted, emails in
303 ... get_email_notifications(notifications)]
304 >>> len(messages)
305 1
306@@ -106,7 +106,7 @@
307
308 >>> notifications = getUtility(
309 ... IBugNotificationSet).getNotificationsToSend()
310- >>> messages = [emails for dummy, emails in
311+ >>> messages = [emails for notifications, omitted, emails in
312 ... get_email_notifications(notifications)]
313 >>> len(messages)
314 1
315
316=== modified file 'lib/lp/bugs/enum.py'
317--- lib/lp/bugs/enum.py 2011-02-01 17:52:45 +0000
318+++ lib/lp/bugs/enum.py 2011-02-17 17:43:44 +0000
319@@ -6,6 +6,7 @@
320 __metaclass__ = type
321 __all__ = [
322 'BugNotificationLevel',
323+ 'BugNotificationStatus',
324 ]
325
326 from lazr.enum import (
327@@ -47,3 +48,29 @@
328 notifications about new events in the bugs's discussion, like new
329 comments.
330 """)
331+
332+
333+class BugNotificationStatus(DBEnumeratedType):
334+ """The status of a bug notification.
335+
336+ A notification may be pending, sent, or omitted."""
337+
338+ PENDING = DBItem(10, """
339+ Pending
340+
341+ The notification has not yet been sent.
342+ """)
343+
344+ OMITTED = DBItem(20, """
345+ Omitted
346+
347+ The system considered sending the notification, but omitted it.
348+ This is generally because the action reported by the notification
349+ was immediately undone.
350+ """)
351+
352+ SENT = DBItem(30, """
353+ Sent
354+
355+ The notification has been sent.
356+ """)
357
358=== modified file 'lib/lp/bugs/interfaces/bugnotification.py'
359--- lib/lp/bugs/interfaces/bugnotification.py 2011-02-17 17:43:43 +0000
360+++ lib/lp/bugs/interfaces/bugnotification.py 2011-02-17 17:43:44 +0000
361@@ -18,11 +18,13 @@
362 )
363 from zope.schema import (
364 Bool,
365+ Choice,
366 Datetime,
367 TextLine,
368 )
369
370 from canonical.launchpad import _
371+from lp.bugs.enum import BugNotificationStatus
372 from lp.registry.interfaces.role import IHasOwner
373 from lp.services.fields import BugField
374
375@@ -51,6 +53,13 @@
376 required=False)
377 recipients = Attribute(
378 "The people to which this notification should be sent.")
379+ status = Choice(
380+ title=_("Status"), required=True,
381+ vocabulary=BugNotificationStatus,
382+ default=BugNotificationStatus.PENDING,
383+ description=_(
384+ "The status of this bug notification."),
385+ )
386
387
388 class IBugNotificationSet(Interface):
389
390=== modified file 'lib/lp/bugs/mail/tests/test_bug_task_assignment.py'
391--- lib/lp/bugs/mail/tests/test_bug_task_assignment.py 2010-12-21 19:11:49 +0000
392+++ lib/lp/bugs/mail/tests/test_bug_task_assignment.py 2011-02-17 17:43:44 +0000
393@@ -90,7 +90,7 @@
394 self.bug_task, self.bug_task_before_modification,
395 ['assignee'], user=self.user))
396 latest_notification = BugNotification.selectFirst(orderBy='-id')
397- notifications, messages = construct_email_notifications(
398+ notifications, omitted, messages = construct_email_notifications(
399 [latest_notification])
400 self.assertEqual(len(notifications), 1,
401 'email notication not created')
402@@ -107,7 +107,7 @@
403 self.bug_task, self.bug_task_before_modification,
404 ['assignee'], user=self.user))
405 latest_notification = BugNotification.selectFirst(orderBy='-id')
406- notifications, messages = construct_email_notifications(
407+ notifications, omitted, messages = construct_email_notifications(
408 [latest_notification])
409 self.assertEqual(len(notifications), 1,
410 'email notification not created')
411
412=== modified file 'lib/lp/bugs/mail/tests/test_bug_task_modification.py'
413--- lib/lp/bugs/mail/tests/test_bug_task_modification.py 2010-10-04 19:50:45 +0000
414+++ lib/lp/bugs/mail/tests/test_bug_task_modification.py 2011-02-17 17:43:44 +0000
415@@ -44,7 +44,7 @@
416 ['status'], user=self.user))
417 transaction.commit()
418 latest_notification = BugNotification.selectFirst(orderBy='-id')
419- notifications, messages = construct_email_notifications(
420+ notifications, omitted, messages = construct_email_notifications(
421 [latest_notification])
422 self.assertEqual(len(notifications), 1,
423 'email notification not created')
424
425=== modified file 'lib/lp/bugs/model/bugnotification.py'
426--- lib/lp/bugs/model/bugnotification.py 2011-02-17 17:43:43 +0000
427+++ lib/lp/bugs/model/bugnotification.py 2011-02-17 17:43:44 +0000
428@@ -28,10 +28,12 @@
429
430 from canonical.config import config
431 from canonical.database.datetimecol import UtcDateTimeCol
432+from canonical.database.enumcol import EnumCol
433 from canonical.database.sqlbase import (
434 SQLBase,
435 sqlvalues,
436 )
437+from lp.bugs.enum import BugNotificationStatus
438 from lp.bugs.interfaces.bugnotification import (
439 IBugNotification,
440 IBugNotificationRecipient,
441@@ -49,6 +51,10 @@
442 bug = ForeignKey(dbName='bug', notNull=True, foreignKey='Bug')
443 is_comment = BoolCol(notNull=True)
444 date_emailed = UtcDateTimeCol(notNull=False)
445+ status = EnumCol(
446+ dbName='status',
447+ schema=BugNotificationStatus, default=BugNotificationStatus.PENDING,
448+ notNull=True)
449
450 @property
451 def recipients(self):
452
453=== modified file 'lib/lp/bugs/scripts/bugnotification.py'
454--- lib/lp/bugs/scripts/bugnotification.py 2011-02-17 17:43:43 +0000
455+++ lib/lp/bugs/scripts/bugnotification.py 2011-02-17 17:43:44 +0000
456@@ -97,6 +97,7 @@
457
458 recipients = {}
459 filtered_notifications = []
460+ omitted_notifications = []
461 for notification in bug_notifications:
462 key = get_activity_key(notification)
463 if (notification.is_comment or
464@@ -111,6 +112,8 @@
465 email_people.remove(actor)
466 for email_person in email_people:
467 recipients[email_person] = recipient
468+ else:
469+ omitted_notifications.append(notification)
470
471 if bug.duplicateof is not None:
472 text_notifications.append(
473@@ -203,7 +206,7 @@
474 rationale, references, msgid)
475 messages.append(msg)
476
477- return filtered_notifications, messages
478+ return filtered_notifications, omitted_notifications, messages
479
480
481 def notification_comment_batches(notifications):
482
483=== modified file 'lib/lp/bugs/scripts/tests/test_bugnotification.py'
484--- lib/lp/bugs/scripts/tests/test_bugnotification.py 2011-02-17 17:43:43 +0000
485+++ lib/lp/bugs/scripts/tests/test_bugnotification.py 2011-02-17 17:43:44 +0000
486@@ -248,7 +248,7 @@
487 email_notifications = get_email_notifications(notifications_to_send)
488 to_addresses = set()
489 sent_notifications = []
490- for notifications, messages in email_notifications:
491+ for notifications, omitted, messages in email_notifications:
492 for message in messages:
493 to_addresses.add(message['to'])
494 recipients = {}
495@@ -572,7 +572,9 @@
496 def get_messages(self):
497 notifications = self.notification_set.getNotificationsToSend()
498 email_notifications = get_email_notifications(notifications)
499- for bug_notifications, messages in email_notifications:
500+ for (bug_notifications,
501+ omitted_notifications,
502+ messages) in email_notifications:
503 for message in messages:
504 yield message, message.get_payload(decode=True)
505
506
507=== modified file 'lib/lp/bugs/tests/test_bugchanges.py'
508--- lib/lp/bugs/tests/test_bugchanges.py 2011-02-17 17:43:43 +0000
509+++ lib/lp/bugs/tests/test_bugchanges.py 2011-02-17 17:43:44 +0000
510@@ -183,7 +183,8 @@
511
512 def assertRecipients(self, expected_recipients):
513 notifications = self.getNewNotifications()
514- notifications, messages = construct_email_notifications(notifications)
515+ notifications, omitted, messages = construct_email_notifications(
516+ notifications)
517 recipients = set(message['to'] for message in messages)
518
519 self.assertEqual(

Subscribers

People subscribed via source and target branches

to status/vote changes: