Merge ~cjwatson/launchpad:fix-bugnotification-script-tests into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 6075c9e1dbeb94463d1774b63eeb63efb3c1efb9
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:fix-bugnotification-script-tests
Merge into: launchpad:master
Diff against target: 211 lines (+49/-46)
1 file modified
lib/lp/bugs/scripts/tests/test_bugnotification.py (+49/-46)
Reviewer Review Type Date Requested Status
Tom Wardill (community) Approve
Review via email: mp+393917@code.launchpad.net

Commit message

Fix get_email_notifications tests to be effective

Description of the change

The tests for get_email_notifications didn't test what they claimed to test, because refactorings of the code under test some years ago meant that getBugNotificationRecipients is no longer called there, and it looks as though the tests were fixed up incorrectly. Fix the tests to actually be effective, and add assertions on the log output to ensure that this can't regress in the same way in future.

To post a comment you must log in.
Revision history for this message
Tom Wardill (twom) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/bugs/scripts/tests/test_bugnotification.py b/lib/lp/bugs/scripts/tests/test_bugnotification.py
2index 38d11d9..7454ad4 100644
3--- a/lib/lp/bugs/scripts/tests/test_bugnotification.py
4+++ b/lib/lp/bugs/scripts/tests/test_bugnotification.py
5@@ -1,4 +1,4 @@
6-# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
7+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
8 # GNU Affero General Public License version 3 (see the file LICENSE).
9 """Tests for constructing bug notification emails for sending."""
10
11@@ -10,13 +10,12 @@ from datetime import (
12 datetime,
13 timedelta,
14 )
15-import logging
16 import re
17 from smtplib import SMTPException
18 import unittest
19
20+from fixtures import FakeLogger
21 import pytz
22-import six
23 from testtools.matchers import (
24 MatchesRegex,
25 Not,
26@@ -54,6 +53,7 @@ from lp.bugs.interfaces.bugnotification import IBugNotificationSet
27 from lp.bugs.interfaces.bugtask import (
28 BugTaskImportance,
29 BugTaskStatus,
30+ IBugTaskSet,
31 )
32 from lp.bugs.mail.bugnotificationrecipients import BugNotificationRecipients
33 from lp.bugs.model.bugnotification import (
34@@ -62,7 +62,6 @@ from lp.bugs.model.bugnotification import (
35 BugNotificationRecipient,
36 )
37 from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilterMute
38-from lp.bugs.model.bugtask import BugTask
39 from lp.bugs.scripts.bugnotification import (
40 construct_email_notifications,
41 get_activity_key,
42@@ -120,36 +119,11 @@ class MockBug:
43 def title(self):
44 return "Mock Bug #%s" % self.id
45
46- def getBugNotificationRecipients(self, level=None):
47- recipients = BugNotificationRecipients()
48- no_priv = getUtility(IPersonSet).getByEmail(
49- 'no-priv@canonical.com')
50- recipients.addDirectSubscriber(no_priv)
51- return recipients
52-
53 def __eq__(self, other):
54 """Compare by id to make different subclasses of MockBug be equal."""
55 return self.id == other.id
56
57
58-class ExceptionBug(MockBug):
59- """A bug which causes an exception to be raised."""
60-
61- def getBugNotificationRecipients(self, level=None):
62- raise Exception('FUBAR')
63-
64-
65-class DBExceptionBug(MockBug):
66- """A bug which causes a DB constraint to be triggered."""
67-
68- def getBugNotificationRecipients(self, level=None):
69- # Trigger a DB constraint, resulting in the transaction being
70- # unusable.
71- firefox = getUtility(IProductSet).getByName('firefox')
72- bug_one = getUtility(IBugSet).get(1)
73- BugTask(bug=bug_one, product=firefox, owner=self.owner)
74-
75-
76 class MockBugNotificationRecipient:
77 """A mock BugNotificationRecipient for testing."""
78
79@@ -172,9 +146,32 @@ class MockBugNotification:
80 self.bug = bug
81 self.is_comment = is_comment
82 self.date_emailed = date_emailed
83- self.recipients = [MockBugNotificationRecipient()]
84 self.activity = None
85
86+ @property
87+ def recipients(self):
88+ return [MockBugNotificationRecipient()]
89+
90+
91+class ExceptionBugNotification(MockBugNotification):
92+ """A bug notification which causes an exception to be raised."""
93+
94+ @property
95+ def recipients(self):
96+ raise Exception('FUBAR')
97+
98+
99+class DBExceptionBugNotification(MockBugNotification):
100+ """A bug notification which causes a DB constraint to be triggered."""
101+
102+ @property
103+ def recipients(self):
104+ # Trigger a DB constraint, resulting in the transaction being
105+ # unusable.
106+ firefox = getUtility(IProductSet).getByName('firefox')
107+ bug_one = getUtility(IBugSet).get(1)
108+ getUtility(IBugTaskSet).createTask(bug_one, self.bug.owner, firefox)
109+
110
111 class FakeNotification:
112 """An even simpler fake notification.
113@@ -277,15 +274,15 @@ class TestGetEmailNotifications(TestCase):
114 # A comment notification for bug one which raises an exception.
115 msg = getUtility(IMessageSet).fromText(
116 'Subject', "Comment on bug 1", owner=sample_person)
117- self.bug_one_exception_notification = MockBugNotification(
118- message=msg, bug=ExceptionBug(1, sample_person),
119+ self.bug_one_exception_notification = ExceptionBugNotification(
120+ message=msg, bug=MockBug(1, sample_person),
121 is_comment=True, date_emailed=None)
122
123 # A comment notification for bug one which raises a DB exception.
124 msg = getUtility(IMessageSet).fromText(
125 'Subject', "Comment on bug 1", owner=sample_person)
126- self.bug_one_dbexception_notification = MockBugNotification(
127- message=msg, bug=DBExceptionBug(1, sample_person),
128+ self.bug_one_dbexception_notification = DBExceptionBugNotification(
129+ message=msg, bug=MockBug(1, sample_person),
130 is_comment=True, date_emailed=None)
131
132 # We need to commit the transaction, since the error handling
133@@ -298,6 +295,8 @@ class TestGetEmailNotifications(TestCase):
134 self._fake_utility = FakeBugNotificationSetUtility()
135 sm.registerUtility(self._fake_utility)
136
137+ self.logger = self.useFixture(FakeLogger())
138+
139 def tearDown(self):
140 super(TestGetEmailNotifications, self).tearDown()
141 sm = getSiteManager()
142@@ -339,7 +338,8 @@ class TestGetEmailNotifications(TestCase):
143 ]
144 sent_notifications = self._getAndCheckSentNotifications(
145 notifications_to_send)
146- self.assertEqual(sent_notifications, notifications_to_send)
147+ self.assertEqual(sent_notifications, [self.bug_one_notification])
148+ self.assertIn('Exception: FUBAR', self.logger.output)
149
150 def test_catch_simple_exception_in_the_middle(self):
151 # Make sure that the first and last notifications are sent even
152@@ -353,7 +353,8 @@ class TestGetEmailNotifications(TestCase):
153 notifications_to_send)
154 self.assertEqual(
155 sent_notifications,
156- notifications_to_send)
157+ [self.bug_one_notification, self.bug_one_another_notification])
158+ self.assertIn('Exception: FUBAR', self.logger.output)
159
160 def test_catch_db_exception_last(self):
161 # Make sure that the first notification is sent even if the
162@@ -365,7 +366,11 @@ class TestGetEmailNotifications(TestCase):
163 ]
164 sent_notifications = self._getAndCheckSentNotifications(
165 notifications_to_send)
166- self.assertEqual(sent_notifications, notifications_to_send)
167+ self.assertEqual(sent_notifications, [self.bug_one_notification])
168+ self.assertIn(
169+ 'IllegalTarget: A fix for this bug has already been requested for '
170+ 'Mozilla Firefox',
171+ self.logger.output)
172
173 # The transaction should have been rolled back and restarted
174 # properly, so getting something from the database shouldn't
175@@ -385,7 +390,12 @@ class TestGetEmailNotifications(TestCase):
176 sent_notifications = self._getAndCheckSentNotifications(
177 notifications_to_send)
178 self.assertEqual(
179- sent_notifications, notifications_to_send)
180+ sent_notifications,
181+ [self.bug_one_notification, self.bug_one_another_notification])
182+ self.assertIn(
183+ 'IllegalTarget: A fix for this bug has already been requested for '
184+ 'Mozilla Firefox',
185+ self.logger.output)
186
187 # The transaction should have been rolled back and restarted
188 # properly, so getting something from the database shouldn't
189@@ -401,13 +411,6 @@ class TestGetEmailNotifications(TestCase):
190 # verifies that the fix for that bug (re-raising the exception) stays
191 # in place.
192
193- # Set up logging so we can later assert that no exceptions are logged.
194- log_output = six.StringIO()
195- logger = logging.getLogger()
196- log_handler = logging.StreamHandler(log_output)
197- logger.addHandler(logging.StreamHandler(log_output))
198- self.addCleanup(logger.removeHandler, log_handler)
199-
200 # Make some data to feed to get_email_notifications.
201 person = getUtility(IPersonSet).getByEmail('test@canonical.com')
202 msg = getUtility(IMessageSet).fromText('', '', owner=person)
203@@ -429,7 +432,7 @@ class TestGetEmailNotifications(TestCase):
204 email_notifications.close()
205
206 # Verify that no "Error while building email notifications." is logged.
207- self.assertEqual('', log_output.getvalue())
208+ self.assertEqual('', self.logger.output)
209
210
211 class TestNotificationCommentBatches(unittest.TestCase):

Subscribers

People subscribed via source and target branches

to status/vote changes: