Merge lp:~stevenk/launchpad/bugnotification-testcases into lp:launchpad

Proposed by Steve Kowalik on 2012-07-24
Status: Merged
Approved by: William Grant on 2012-07-24
Approved revision: no longer in the source branch.
Merged at revision: 15678
Proposed branch: lp:~stevenk/launchpad/bugnotification-testcases
Merge into: lp:launchpad
Diff against target: 516 lines (+144/-308)
4 files modified
lib/lp/bugs/browser/tests/test_bugsupervisor.py (+32/-1)
lib/lp/bugs/stories/initial-bug-contacts/xx-initial-bug-contacts.txt (+0/-237)
lib/lp/bugs/tests/test_bug_notification_recipients.py (+112/-0)
lib/lp/bugs/tests/test_bugnotification.py (+0/-70)
To merge this branch: bzr merge lp:~stevenk/launchpad/bugnotification-testcases
Reviewer Review Type Date Requested Status
William Grant code 2012-07-24 Approve on 2012-07-24
Review via email: mp+116402@code.launchpad.net

Commit Message

Clean up tests related to bug notification to prepare for the work that will force structural subscriptions to work with private bugs.

Description of the Change

Clean up tests related to bug notification to prepare for the work that will force structural subscriptions to work with private bugs. I have removed xx-initial-bug-contacts.txt for being a doctest, due to that once the aforementioned structural subscription work lands, it will no longer match reality, and so I can claw back some LoC credit for this branch. I have removed three tests from test_bugnotifications which were frankly horrible, and also won't match reality after the aforementioned work lands.

To post a comment you must log in.
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/browser/tests/test_bugsupervisor.py'
2--- lib/lp/bugs/browser/tests/test_bugsupervisor.py 2012-01-01 02:58:52 +0000
3+++ lib/lp/bugs/browser/tests/test_bugsupervisor.py 2012-07-24 06:29:26 +0000
4@@ -6,15 +6,22 @@
5 __metaclass__ = type
6
7 from zope.app.form.interfaces import ConversionError
8+from zope.component import getUtility
9
10 from lp.bugs.browser.bugsupervisor import BugSupervisorEditSchema
11-from lp.registry.interfaces.person import PersonVisibility
12+from lp.registry.interfaces.person import (
13+ IPersonSet,
14+ PersonVisibility,
15+ )
16+from lp.services.webapp.publisher import canonical_url
17 from lp.testing import (
18+ BrowserTestCase,
19 login,
20 login_person,
21 TestCaseWithFactory,
22 )
23 from lp.testing.layers import DatabaseFunctionalLayer
24+from lp.testing.sampledata import ADMIN_EMAIL
25 from lp.testing.views import create_initialized_view
26
27
28@@ -180,3 +187,27 @@
29 self.product, name='+bugsupervisor', form=form)
30 self.assertEqual([], view.errors)
31 self.assertEqual(private_team, self.product.bug_supervisor)
32+
33+
34+class TestBugSupervisorLink(BrowserTestCase):
35+
36+ layer = DatabaseFunctionalLayer
37+
38+ def test_with_no_access(self):
39+ product = self.factory.makeProduct(official_malone=True)
40+ url = canonical_url(product, rootsite="bugs", view_name='+bugs')
41+ browser = self.getUserBrowser(url, user=self.factory.makePerson())
42+ self.assertNotIn('Change bug supervisor', browser.contents)
43+
44+ def test_with_access(self):
45+ product = self.factory.makeProduct(official_malone=True)
46+ url = canonical_url(product, rootsite="bugs", view_name='+bugs')
47+ browser = self.getUserBrowser(url, user=product.owner)
48+ self.assertIn('Change bug supervisor', browser.contents)
49+
50+ def test_as_admin(self):
51+ product = self.factory.makeProduct(official_malone=True)
52+ url = canonical_url(product, rootsite="bugs", view_name='+bugs')
53+ admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
54+ browser = self.getUserBrowser(url, user=admin)
55+ self.assertIn('Change bug supervisor', browser.contents)
56
57=== removed file 'lib/lp/bugs/stories/initial-bug-contacts/xx-initial-bug-contacts.txt'
58--- lib/lp/bugs/stories/initial-bug-contacts/xx-initial-bug-contacts.txt 2012-07-19 15:51:37 +0000
59+++ lib/lp/bugs/stories/initial-bug-contacts/xx-initial-bug-contacts.txt 1970-01-01 00:00:00 +0000
60@@ -1,237 +0,0 @@
61-To set a bug supervisor for a distribution, we need to go to the Bug page
62-of that distribution:
63-
64- >>> browser.open('http://launchpad.dev/ubuntu/+bugs')
65-
66-But the link is not available if you are not logged in with permission
67-to change the bug supervisor.
68-
69- >>> browser.getLink("Change bug supervisor")
70- Traceback (most recent call last):
71- ...
72- LinkNotFoundError
73-
74-Colin is an Ubuntu owner and can set the bug supervisor role.
75-
76- >>> colin_browser = setupBrowser(
77- ... auth='Basic colin.watson@ubuntulinux.com:test')
78- >>> colin_browser.open('http://bugs.launchpad.dev/ubuntu/+bugs')
79-
80-...and he can see that the link on Ubuntu's bugs page.
81-
82- >>> bug_supervisor_link = colin_browser.getLink("Change bug supervisor")
83- >>> bug_supervisor_link.url
84- 'http://bugs.launchpad.dev/ubuntu/+bugsupervisor'
85-
86-Anyone with launchpad.Edit permission can edit the distribution bug
87-supervisor, but most users can select only themselves and the teams they
88-administer. In this example, Colin will set himself as the distribution
89-bug supervisor.
90-
91- >>> bug_supervisor_link.click()
92- >>> colin_browser.url
93- 'http://bugs.launchpad.dev/ubuntu/+bugsupervisor'
94-
95-The bug supervisor page takes just one simple value: the bug supervisor email
96-or nickname. Let's set colin.watson@ubuntulinux.com as the bug supervisor for
97-Ubuntu.
98-
99- >>> colin_browser.getControl("Bug Supervisor").value = (
100- ... ' colin.watson@ubuntulinux.com ')
101- >>> colin_browser.getControl("Change").click()
102-
103-And then Colin is redirected to the distribution bugs page.
104-
105- >>> print extract_text(find_tag_by_id(
106- ... colin_browser.contents, 'bug-supervisor'))
107- Bug supervisor: Colin Watson
108-
109-== Setting Upstream Bug Supervisor ==
110-
111-Setting the bug supervisor for an upstream requires launchpad.Edit
112-permission on the product. But regular users can only appoint
113-themselves as bug supervisors and teams they administer.
114-
115- >>> sample_browser = setupBrowser()
116- >>> sample_browser.addHeader("Authorization",
117- ... "Basic test@canonical.com:test")
118-
119- >>> sample_browser.open(
120- ... "http://bugs.launchpad.dev/firefox/+bugsupervisor")
121- >>> sample_browser.getControl(name="field.bug_supervisor").value = (
122- ... "test@canonical.com")
123- >>> sample_browser.getControl("Change").click()
124-
125-He is now redirected to the main product page, and he sees a confirmation
126-message.
127-
128- >>> print extract_text(find_tag_by_id(
129- ... sample_browser.contents, 'bug-supervisor'))
130- Bug supervisor: Sample Person
131-
132-Another example, this time with a team that has no "preferred email" set.
133-
134- >>> sample_browser.open(
135- ... "http://bugs.launchpad.dev/firefox/+bugsupervisor")
136- >>> sample_browser.getControl(name="field.bug_supervisor").value = (
137- ... "landscape-developers")
138- >>> sample_browser.getControl("Change").click()
139- >>> print extract_text(find_tag_by_id(
140- ... sample_browser.contents, 'bug-supervisor'))
141- Bug supervisor: Landscape Developers
142-
143-Launchpad administrators can appoint anybody.
144-
145- >>> admin_browser = setupBrowser()
146- >>> admin_browser.addHeader("Authorization",
147- ... "Basic foo.bar@canonical.com:test")
148-
149- >>> admin_browser.open("http://bugs.launchpad.dev/firefox/+bugsupervisor")
150- >>> admin_browser.getControl(name="field.bug_supervisor").value = (
151- ... "robertc@robertcollins.net")
152- >>> admin_browser.getControl("Change").click()
153- >>> print extract_text(find_tag_by_id(
154- ... admin_browser.contents, 'bug-supervisor'))
155- Bug supervisor: Robert Collins
156-
157-Filing a public bug on an upstream will subscribe the bug supervisor, as
158-well.
159-
160- >>> browser.addHeader("Authorization", "Basic mark@example.com:test")
161-
162- >>> browser.open("http://launchpad.dev/firefox/+filebug")
163-
164- >>> browser.getControl(name="field.title", index=0).value = "bug supervisor test"
165- >>> browser.getControl('Continue').click()
166-
167- >>> browser.getControl(name="field.comment").value = "a public bug"
168- >>> browser.getControl("Submit Bug Report").click()
169-
170- >>> bug_id = browser.url.split("/")[-1]
171- >>> print browser.url.replace(bug_id, "BUG-ID")
172- http://bugs.launchpad.dev/firefox/+bug/BUG-ID
173-
174-Now mark (because he's the bug reporter), Sample Person (a former bug
175-supervisor), Landscape Developers (another former bug supervisor) and
176-Robert Collins (the current bug supervisor) are subscribed to this bug:
177-
178- >>> from itertools import chain
179- >>> from zope.component import getUtility
180- >>> from lp.bugs.interfaces.bug import IBugSet
181- >>> from lp.testing import login, logout, ANONYMOUS
182-
183- >>> def subscriber_names(bug):
184- ... subscribers = chain(
185- ... bug.getDirectSubscribers(),
186- ... bug.getIndirectSubscribers())
187- ... return sorted(subscriber.displayname for subscriber in subscribers)
188-
189- >>> login(ANONYMOUS)
190- >>> bugset = getUtility(IBugSet)
191- >>> subscriber_names(bugset.get(bug_id))
192- [u'Landscape Developers', u'Mark Shuttleworth', u'Robert Collins',
193- u'Sample Person']
194-
195-For a security bug, only the reporter and the registrant gets
196-subscribed, because Firefox does not have a security contact.
197-
198- >>> from lp.registry.interfaces.product import IProductSet
199-
200- >>> login(ANONYMOUS)
201- >>> firefox = getUtility(IProductSet).getByName("firefox")
202- >>> firefox.security_contact is None
203- True
204- >>> logout()
205-
206- >>> browser.open("http://launchpad.dev/firefox/+filebug")
207-
208- >>> browser.getControl(name="field.title", index=0).value = "bug supervisor test"
209- >>> browser.getControl('Continue').click()
210-
211- >>> browser.getControl(name="field.comment").value = "a PRIVATE bug"
212- >>> browser.getControl("Private Security").selected = True
213- >>> browser.getControl("Submit Bug Report").click()
214-
215- >>> other_bug_id = browser.url.split("/")[-1]
216- >>> print browser.url.replace(other_bug_id, "BUG-ID")
217- http://bugs.launchpad.dev/firefox/+bug/BUG-ID
218-
219- >>> login("mark@example.com")
220-
221- >>> subscriber_names(bugset.get(other_bug_id))
222- [u'Mark Shuttleworth', u'Sample Person']
223-
224- >>> logout()
225-
226-Filing a public bug on a distribution source package subscribes the bug
227-reporter, the distribution bug supervisor, if there is one, and all the
228-package subscribers, if there are any.
229-
230- >>> browser.addHeader("Authorization", "Basic mark@example.com:test")
231-
232- >>> browser.open(
233- ... "http://localhost:9000/ubuntu/+source/mozilla-firefox/"
234- ... "+filebug")
235-
236- >>> browser.getControl(name="field.title", index=0).value = "a public bug"
237- >>> browser.getControl('Continue').click()
238-
239- >>> browser.getControl(name="field.comment").value = (
240- ... "anyone can see this")
241- >>> browser.getControl("Submit Bug Report").click()
242-
243- >>> bug_id = browser.url.split("/")[-1]
244- >>> print browser.url.replace(bug_id, "BUG-ID")
245- http://bugs.launchpad.dev/ubuntu/+source/mozilla-firefox/+bug/BUG-ID
246-
247-We should have three subscribers now. The bug reporter (also a package
248-subscriber), mark, the distro bug supervisor kamion, and foobar, who is
249-subscribed to the distribution.
250-
251- >>> from zope.component import getUtility
252- >>> from lp.bugs.interfaces.bug import IBugSet
253- >>> from lp.testing import login, logout, ANONYMOUS
254-
255- >>> def subscriber_names(bug):
256- ... subscribers = chain(
257- ... bug.getDirectSubscribers(),
258- ... bug.getIndirectSubscribers())
259- ... return sorted(subscriber.name for subscriber in subscribers)
260-
261- >>> login(ANONYMOUS)
262-
263- >>> bugset = getUtility(IBugSet)
264- >>> subscriber_names(bugset.get(bug_id))
265- [u'kamion', u'mark', u'name16']
266-
267-
268-When filing a security bug, only the bug reporter and registrant are explicitly
269-Cc'd, because the Ubuntu distribution does not have a security contact.
270-
271- >>> from lp.registry.interfaces.distribution import IDistributionSet
272-
273- >>> ubuntu = getUtility(IDistributionSet).getByName("ubuntu")
274- >>> ubuntu.security_contact is None
275- True
276- >>> logout()
277-
278- >>> browser.open(
279- ... "http://localhost:9000/ubuntu/+source/mozilla-firefox/"
280- ... "+filebug")
281- >>> browser.getControl(name="field.title", index=0).value = "a PRIVATE bug"
282- >>> browser.getControl('Continue').click()
283-
284- >>> browser.getControl(name="field.comment").value = "top sekrit"
285- >>> browser.getControl("Private Security").selected = True
286- >>> browser.getControl("Submit Bug Report").click()
287-
288- >>> other_bug_id = browser.url.split("/")[-1]
289- >>> print browser.url.replace(other_bug_id, "BUG-ID")
290- http://bugs.launchpad.dev/ubuntu/+source/mozilla-firefox/+bug/BUG-ID
291-
292- >>> login("mark@example.com")
293-
294- >>> subscriber_names(bugset.get(other_bug_id))
295- [u'mark', u'ubuntu-team']
296-
297- >>> logout()
298
299=== added file 'lib/lp/bugs/tests/test_bug_notification_recipients.py'
300--- lib/lp/bugs/tests/test_bug_notification_recipients.py 1970-01-01 00:00:00 +0000
301+++ lib/lp/bugs/tests/test_bug_notification_recipients.py 2012-07-24 06:29:26 +0000
302@@ -0,0 +1,112 @@
303+# Copyright 2012 Canonical Ltd. This software is licensed under the
304+# GNU Affero General Public License version 3 (see the file LICENSE).
305+
306+"""Tests related to bug notification recipients."""
307+
308+__metaclass__ = type
309+
310+from lp.registry.enums import InformationType
311+from lp.testing import (
312+ person_logged_in,
313+ TestCaseWithFactory,
314+ )
315+from lp.testing.layers import DatabaseFunctionalLayer
316+
317+
318+class TestBugNotificationRecipients(TestCaseWithFactory):
319+
320+ layer = DatabaseFunctionalLayer
321+
322+ def test_public_bug(self):
323+ bug = self.factory.makeBug()
324+ self.assertContentEqual(
325+ [bug.owner], bug.getBugNotificationRecipients())
326+
327+ def test_public_bug_with_subscriber(self):
328+ bug = self.factory.makeBug()
329+ subscriber = self.factory.makePerson()
330+ with person_logged_in(bug.owner):
331+ bug.subscribe(subscriber, bug.owner)
332+ self.assertContentEqual(
333+ [bug.owner, subscriber], bug.getBugNotificationRecipients())
334+
335+ def test_public_bug_with_structural_subscriber(self):
336+ subscriber = self.factory.makePerson()
337+ product = self.factory.makeProduct()
338+ with person_logged_in(subscriber):
339+ product.addBugSubscription(subscriber, subscriber)
340+ bug = self.factory.makeBug(product=product)
341+ self.assertContentEqual(
342+ [bug.owner, subscriber], bug.getBugNotificationRecipients())
343+
344+ def test_public_bug_assignee(self):
345+ assignee = self.factory.makePerson()
346+ bug = self.factory.makeBug()
347+ with person_logged_in(bug.owner):
348+ bug.default_bugtask.transitionToAssignee(assignee)
349+ self.assertContentEqual(
350+ [bug.owner, assignee], bug.getBugNotificationRecipients())
351+
352+ def test_public_bug_with_duplicate_subscriber(self):
353+ subscriber = self.factory.makePerson()
354+ bug = self.factory.makeBug()
355+ dupe = self.factory.makeBug()
356+ with person_logged_in(dupe.owner):
357+ dupe.subscribe(subscriber, dupe.owner)
358+ dupe.markAsDuplicate(bug)
359+ self.assertContentEqual(
360+ [bug.owner, dupe.owner, subscriber],
361+ bug.getBugNotificationRecipients())
362+
363+ def test_private_bug(self):
364+ owner = self.factory.makePerson()
365+ bug = self.factory.makeBug(
366+ owner=owner, information_type=InformationType.USERDATA)
367+ with person_logged_in(owner):
368+ self.assertContentEqual(
369+ [owner], bug.getBugNotificationRecipients())
370+
371+ def test_private_bug_with_subscriber(self):
372+ owner = self.factory.makePerson()
373+ subscriber = self.factory.makePerson()
374+ bug = self.factory.makeBug(
375+ owner=owner, information_type=InformationType.USERDATA)
376+ with person_logged_in(owner):
377+ bug.subscribe(subscriber, owner)
378+ self.assertContentEqual(
379+ [owner, subscriber], bug.getBugNotificationRecipients())
380+
381+ def test_private_bug_with_structural_subscriber(self):
382+ owner = self.factory.makePerson()
383+ subscriber = self.factory.makePerson()
384+ product = self.factory.makeProduct()
385+ with person_logged_in(subscriber):
386+ product.addBugSubscription(subscriber, subscriber)
387+ bug = self.factory.makeBug(
388+ product=product, owner=owner,
389+ information_type=InformationType.USERDATA)
390+ with person_logged_in(owner):
391+ self.assertContentEqual(
392+ [owner], bug.getBugNotificationRecipients())
393+
394+ def test_private_bug_assignee(self):
395+ owner = self.factory.makePerson()
396+ assignee = self.factory.makePerson()
397+ bug = self.factory.makeBug(
398+ owner=owner, information_type=InformationType.USERDATA)
399+ with person_logged_in(owner):
400+ bug.default_bugtask.transitionToAssignee(assignee)
401+ self.assertContentEqual(
402+ [owner], bug.getBugNotificationRecipients())
403+
404+ def test_private_bug_with_duplicate_subscriber(self):
405+ owner = self.factory.makePerson()
406+ subscriber = self.factory.makePerson()
407+ bug = self.factory.makeBug(
408+ owner=owner, information_type=InformationType.USERDATA)
409+ dupe = self.factory.makeBug(owner=owner)
410+ with person_logged_in(owner):
411+ dupe.subscribe(subscriber, owner)
412+ dupe.markAsDuplicate(bug)
413+ self.assertContentEqual(
414+ [owner], bug.getBugNotificationRecipients())
415
416=== modified file 'lib/lp/bugs/tests/test_bugnotification.py'
417--- lib/lp/bugs/tests/test_bugnotification.py 2012-07-19 04:40:03 +0000
418+++ lib/lp/bugs/tests/test_bugnotification.py 2012-07-24 06:29:26 +0000
419@@ -7,7 +7,6 @@
420
421 from datetime import datetime
422 from itertools import chain
423-import unittest
424
425 from lazr.lifecycle.event import ObjectModifiedEvent
426 from lazr.lifecycle.snapshot import Snapshot
427@@ -32,90 +31,21 @@
428 BugNotificationSet,
429 )
430 from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilterMute
431-from lp.registry.enums import InformationType
432 from lp.services.config import config
433 from lp.services.messages.interfaces.message import IMessageSet
434 from lp.services.messages.model.message import MessageSet
435 from lp.testing import (
436- login,
437 person_logged_in,
438 TestCaseWithFactory,
439 )
440 from lp.testing.dbuser import switch_dbuser
441-from lp.testing.factory import LaunchpadObjectFactory
442 from lp.testing.layers import (
443 DatabaseFunctionalLayer,
444- LaunchpadFunctionalLayer,
445 LaunchpadZopelessLayer,
446 )
447 from lp.testing.matchers import Contains
448
449
450-class TestNotificationRecipientsOfPrivateBugs(unittest.TestCase):
451- """Test who get notified of changes to private bugs."""
452-
453- layer = LaunchpadFunctionalLayer
454-
455- def setUp(self):
456- login('foo.bar@canonical.com')
457- factory = LaunchpadObjectFactory()
458- self.product_owner = factory.makePerson(name="product-owner")
459- self.product = factory.makeProduct(owner=self.product_owner)
460- self.product_subscriber = factory.makePerson(
461- name="product-subscriber")
462- self.product.addBugSubscription(
463- self.product_subscriber, self.product_subscriber)
464- self.bug_subscriber = factory.makePerson(name="bug-subscriber")
465- self.bug_owner = factory.makePerson(name="bug-owner")
466- self.private_bug = factory.makeBug(
467- product=self.product, owner=self.bug_owner,
468- information_type=InformationType.USERDATA)
469- self.reporter = self.private_bug.owner
470- self.private_bug.subscribe(self.bug_subscriber, self.reporter)
471- [self.product_bugtask] = self.private_bug.bugtasks
472- self.direct_subscribers = set(
473- person.name for person in [self.bug_subscriber, self.reporter])
474-
475- def test_status_change(self):
476- # Status changes are sent to the direct subscribers only.
477- bugtask_before_modification = Snapshot(
478- self.product_bugtask, providing=providedBy(self.product_bugtask))
479- self.product_bugtask.transitionToStatus(
480- BugTaskStatus.INVALID, self.private_bug.owner)
481- notify(ObjectModifiedEvent(
482- self.product_bugtask, bugtask_before_modification, ['status'],
483- user=self.reporter))
484- latest_notification = BugNotification.selectFirst(orderBy='-id')
485- notified_people = set(
486- recipient.person.name
487- for recipient in latest_notification.recipients)
488- self.assertEqual(self.direct_subscribers, notified_people)
489-
490- def test_add_comment(self):
491- # Comment additions are sent to the direct subscribers only.
492- self.private_bug.newMessage(
493- self.reporter, subject='subject', content='content')
494- latest_notification = BugNotification.selectFirst(orderBy='-id')
495- notified_people = set(
496- recipient.person.name
497- for recipient in latest_notification.recipients)
498- self.assertEqual(self.direct_subscribers, notified_people)
499-
500- def test_bug_edit(self):
501- # Bug edits are sent to direct the subscribers only.
502- bug_before_modification = Snapshot(
503- self.private_bug, providing=providedBy(self.private_bug))
504- self.private_bug.description = 'description'
505- notify(ObjectModifiedEvent(
506- self.private_bug, bug_before_modification, ['description'],
507- user=self.reporter))
508- latest_notification = BugNotification.selectFirst(orderBy='-id')
509- notified_people = set(
510- recipient.person.name
511- for recipient in latest_notification.recipients)
512- self.assertEqual(self.direct_subscribers, notified_people)
513-
514-
515 class TestNotificationsSentForBugExpiration(TestCaseWithFactory):
516 """Ensure that question subscribers are notified about bug expiration."""
517