8687.15.15
by Karl Fogel
Add the copyright header block to files under lib/lp/bugs/. |
1 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
2770.1.40
by Guilherme Salgado
A few fixes Bjorn suggested and removing two unused templates. |
3 |
|
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
4 |
__metaclass__ = type |
5 |
||
13402.4.1
by Graham Binns
I can't quite believe this, but the tests pass. |
6 |
import transaction |
7 |
||
12075.3.15
by Gavin Panella
Move tests for group_comments_with_activity() over to test_bugcomment. |
8 |
from datetime import datetime |
2770.1.40
by Guilherme Salgado
A few fixes Bjorn suggested and removing two unused templates. |
9 |
|
12792.8.1
by William Grant
Add failing test for BugActivityItem assignee escaping. |
10 |
from lazr.lifecycle.event import ObjectModifiedEvent |
11 |
from lazr.lifecycle.snapshot import Snapshot |
|
12075.3.3
by Gavin Panella
Factor out the selection of interesting activity. |
12 |
from pytz import UTC |
11474.2.3
by Robert Collins
Add getSubscribersForPerson to IBug, permitting single query setup of bug index pages, which according to OOPS is about 1.2 seconds (but if we're underestimating could be more) and will make analysing performance on the page easier. |
13 |
from storm.store import Store |
11618.1.1
by Deryck Hodge
Drive the query count down by two for bugtask+index, and fix up |
14 |
from testtools.matchers import LessThan |
12799.1.2
by Ian Booth
Rework implementation and do unit tests instead of doc tests |
15 |
from zope.component import ( |
16 |
getMultiAdapter, |
|
17 |
getUtility, |
|
18 |
)
|
|
12792.8.1
by William Grant
Add failing test for BugActivityItem assignee escaping. |
19 |
from zope.event import notify |
20 |
from zope.interface import providedBy |
|
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
21 |
from zope.security.proxy import removeSecurityProxy |
2770.1.40
by Guilherme Salgado
A few fixes Bjorn suggested and removing two unused templates. |
22 |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
23 |
from canonical.launchpad.ftests import ( |
24 |
ANONYMOUS, |
|
25 |
login, |
|
26 |
login_person, |
|
27 |
)
|
|
11655.1.1
by Brad Crittenden
Do not show bug information on a project group page with no projects that use Launchpad. |
28 |
from canonical.launchpad.testing.pages import find_tag_by_id |
11582.2.2
by Robert Collins
Probably broken, but takes 46 queries off of a baseline BugTask:+index. |
29 |
from canonical.launchpad.webapp import canonical_url |
9521.3.1
by Tom Berger
patch from allenap |
30 |
from canonical.launchpad.webapp.servers import LaunchpadTestRequest |
12736.8.2
by William Grant
Test that BugTask:+index doesn't scale with attachments. |
31 |
from canonical.testing.layers import ( |
32 |
DatabaseFunctionalLayer, |
|
33 |
LaunchpadFunctionalLayer, |
|
34 |
)
|
|
13130.1.12
by Curtis Hovey
Sorted imports. |
35 |
from lp.app.interfaces.launchpad import ILaunchpadCelebrities |
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
36 |
from lp.bugs.browser.bugtask import ( |
12792.8.1
by William Grant
Add failing test for BugActivityItem assignee escaping. |
37 |
BugActivityItem, |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
38 |
BugTaskEditView, |
39 |
BugTasksAndNominationsView, |
|
40 |
)
|
|
12075.3.3
by Gavin Panella
Factor out the selection of interesting activity. |
41 |
from lp.bugs.interfaces.bugactivity import IBugActivitySet |
12799.1.2
by Ian Booth
Rework implementation and do unit tests instead of doc tests |
42 |
from lp.bugs.interfaces.bugnomination import IBugNomination |
43 |
from lp.bugs.interfaces.bugtask import ( |
|
44 |
BugTaskStatus, |
|
45 |
IBugTask, |
|
46 |
IBugTaskSet, |
|
47 |
)
|
|
12075.3.3
by Gavin Panella
Factor out the selection of interesting activity. |
48 |
from lp.services.propertycache import get_property_cache |
12561.3.20
by Curtis Hovey
Reconstructed the BugTasksAndNominationsView.getTargetLinkTitle test. |
49 |
from lp.soyuz.interfaces.component import IComponentSet |
11655.1.1
by Brad Crittenden
Do not show bug information on a project group page with no projects that use Launchpad. |
50 |
from lp.testing import ( |
12736.8.2
by William Grant
Test that BugTask:+index doesn't scale with attachments. |
51 |
celebrity_logged_in, |
11655.1.1
by Brad Crittenden
Do not show bug information on a project group page with no projects that use Launchpad. |
52 |
person_logged_in, |
53 |
TestCaseWithFactory, |
|
54 |
)
|
|
11582.2.2
by Robert Collins
Probably broken, but takes 46 queries off of a baseline BugTask:+index. |
55 |
from lp.testing._webservice import QueryCollector |
12736.8.2
by William Grant
Test that BugTask:+index doesn't scale with attachments. |
56 |
from lp.testing.matchers import ( |
57 |
BrowsesWithQueryLimit, |
|
58 |
HasQueryCount, |
|
59 |
)
|
|
11474.2.1
by Robert Collins
Use sampledata constants. |
60 |
from lp.testing.sampledata import ( |
61 |
ADMIN_EMAIL, |
|
62 |
NO_PRIVILEGE_EMAIL, |
|
63 |
USER_EMAIL, |
|
64 |
)
|
|
11655.1.3
by Brad Crittenden
De-lint |
65 |
from lp.testing.views import create_initialized_view |
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
66 |
|
67 |
||
11474.2.3
by Robert Collins
Add getSubscribersForPerson to IBug, permitting single query setup of bug index pages, which according to OOPS is about 1.2 seconds (but if we're underestimating could be more) and will make analysing performance on the page easier. |
68 |
class TestBugTaskView(TestCaseWithFactory): |
69 |
||
12736.8.2
by William Grant
Test that BugTask:+index doesn't scale with attachments. |
70 |
layer = LaunchpadFunctionalLayer |
11474.2.3
by Robert Collins
Add getSubscribersForPerson to IBug, permitting single query setup of bug index pages, which according to OOPS is about 1.2 seconds (but if we're underestimating could be more) and will make analysing performance on the page easier. |
71 |
|
72 |
def invalidate_caches(self, obj): |
|
73 |
store = Store.of(obj) |
|
74 |
# Make sure everything is in the database.
|
|
75 |
store.flush() |
|
76 |
# And invalidate the cache (not a reset, because that stops us using
|
|
77 |
# the domain objects)
|
|
78 |
store.invalidate() |
|
79 |
||
11582.2.2
by Robert Collins
Probably broken, but takes 46 queries off of a baseline BugTask:+index. |
80 |
def test_rendered_query_counts_constant_with_team_memberships(self): |
11474.2.3
by Robert Collins
Add getSubscribersForPerson to IBug, permitting single query setup of bug index pages, which according to OOPS is about 1.2 seconds (but if we're underestimating could be more) and will make analysing performance on the page easier. |
81 |
login(ADMIN_EMAIL) |
11618.1.1
by Deryck Hodge
Drive the query count down by two for bugtask+index, and fix up |
82 |
task = self.factory.makeBugTask() |
11582.2.2
by Robert Collins
Probably broken, but takes 46 queries off of a baseline BugTask:+index. |
83 |
person_no_teams = self.factory.makePerson(password='test') |
84 |
person_with_teams = self.factory.makePerson(password='test') |
|
11474.2.4
by Robert Collins
Testing tweaks per review. |
85 |
for _ in range(10): |
86 |
self.factory.makeTeam(members=[person_with_teams]) |
|
11474.2.3
by Robert Collins
Add getSubscribersForPerson to IBug, permitting single query setup of bug index pages, which according to OOPS is about 1.2 seconds (but if we're underestimating could be more) and will make analysing performance on the page easier. |
87 |
# count with no teams
|
11618.1.1
by Deryck Hodge
Drive the query count down by two for bugtask+index, and fix up |
88 |
url = canonical_url(task) |
11582.2.2
by Robert Collins
Probably broken, but takes 46 queries off of a baseline BugTask:+index. |
89 |
recorder = QueryCollector() |
90 |
recorder.register() |
|
91 |
self.addCleanup(recorder.unregister) |
|
11618.1.1
by Deryck Hodge
Drive the query count down by two for bugtask+index, and fix up |
92 |
self.invalidate_caches(task) |
11582.2.2
by Robert Collins
Probably broken, but takes 46 queries off of a baseline BugTask:+index. |
93 |
self.getUserBrowser(url, person_no_teams) |
11655.1.3
by Brad Crittenden
De-lint |
94 |
# This may seem large: it is; there is easily another 30% fat in
|
95 |
# there.
|
|
13247.1.1
by Danilo Segan
Reapply bug 772754 fix with packagecopyjob changes removed. |
96 |
self.assertThat(recorder, HasQueryCount(LessThan(74))) |
11474.2.3
by Robert Collins
Add getSubscribersForPerson to IBug, permitting single query setup of bug index pages, which according to OOPS is about 1.2 seconds (but if we're underestimating could be more) and will make analysing performance on the page easier. |
97 |
count_with_no_teams = recorder.count |
11474.2.4
by Robert Collins
Testing tweaks per review. |
98 |
# count with many teams
|
11618.1.1
by Deryck Hodge
Drive the query count down by two for bugtask+index, and fix up |
99 |
self.invalidate_caches(task) |
11582.2.2
by Robert Collins
Probably broken, but takes 46 queries off of a baseline BugTask:+index. |
100 |
self.getUserBrowser(url, person_with_teams) |
11474.2.3
by Robert Collins
Add getSubscribersForPerson to IBug, permitting single query setup of bug index pages, which according to OOPS is about 1.2 seconds (but if we're underestimating could be more) and will make analysing performance on the page easier. |
101 |
# Allow an increase of one because storm bug 619017 causes additional
|
11474.2.4
by Robert Collins
Testing tweaks per review. |
102 |
# queries, revalidating things unnecessarily. An increase which is
|
103 |
# less than the number of new teams shows it is definitely not
|
|
104 |
# growing per-team.
|
|
11582.2.2
by Robert Collins
Probably broken, but takes 46 queries off of a baseline BugTask:+index. |
105 |
self.assertThat(recorder, HasQueryCount( |
11474.2.4
by Robert Collins
Testing tweaks per review. |
106 |
LessThan(count_with_no_teams + 3), |
11474.2.3
by Robert Collins
Add getSubscribersForPerson to IBug, permitting single query setup of bug index pages, which according to OOPS is about 1.2 seconds (but if we're underestimating could be more) and will make analysing performance on the page easier. |
107 |
))
|
108 |
||
12736.8.2
by William Grant
Test that BugTask:+index doesn't scale with attachments. |
109 |
def test_rendered_query_counts_constant_with_attachments(self): |
110 |
with celebrity_logged_in('admin'): |
|
111 |
browses_under_limit = BrowsesWithQueryLimit( |
|
13247.1.1
by Danilo Segan
Reapply bug 772754 fix with packagecopyjob changes removed. |
112 |
78, self.factory.makePerson()) |
12736.8.2
by William Grant
Test that BugTask:+index doesn't scale with attachments. |
113 |
|
114 |
# First test with a single attachment.
|
|
115 |
task = self.factory.makeBugTask() |
|
116 |
self.factory.makeBugAttachment(bug=task.bug) |
|
117 |
self.assertThat(task, browses_under_limit) |
|
118 |
||
119 |
with celebrity_logged_in('admin'): |
|
120 |
# And now with 10.
|
|
121 |
task = self.factory.makeBugTask() |
|
122 |
self.factory.makeBugTask(bug=task.bug) |
|
123 |
for i in range(10): |
|
124 |
self.factory.makeBugAttachment(bug=task.bug) |
|
125 |
self.assertThat(task, browses_under_limit) |
|
126 |
||
12075.3.3
by Gavin Panella
Factor out the selection of interesting activity. |
127 |
def test_interesting_activity(self): |
128 |
# The interesting_activity property returns a tuple of interesting
|
|
129 |
# `BugActivityItem`s.
|
|
130 |
bug = self.factory.makeBug() |
|
131 |
view = create_initialized_view( |
|
132 |
bug.default_bugtask, name=u'+index', rootsite='bugs') |
|
133 |
||
134 |
def add_activity(what, old=None, new=None, message=None): |
|
135 |
getUtility(IBugActivitySet).new( |
|
136 |
bug, datetime.now(UTC), bug.owner, whatchanged=what, |
|
137 |
oldvalue=old, newvalue=new, message=message) |
|
138 |
del get_property_cache(view).interesting_activity |
|
139 |
||
140 |
# A fresh bug has no interesting activity.
|
|
141 |
self.assertEqual((), view.interesting_activity) |
|
142 |
||
143 |
# Some activity is not considered interesting.
|
|
144 |
add_activity("boring") |
|
145 |
self.assertEqual((), view.interesting_activity) |
|
146 |
||
147 |
# A description change is interesting.
|
|
148 |
add_activity("description") |
|
149 |
self.assertEqual(1, len(view.interesting_activity)) |
|
150 |
[activity] = view.interesting_activity |
|
151 |
self.assertEqual("description", activity.whatchanged) |
|
152 |
||
13402.4.1
by Graham Binns
I can't quite believe this, but the tests pass. |
153 |
def test_error_for_changing_target_with_invalid_status(self): |
154 |
# If a user moves a bug task with a restricted status (say,
|
|
155 |
# Triaged) to a target where they do not have permission to set
|
|
156 |
# that status, they will be unable to complete the retargeting
|
|
157 |
# and will instead receive an error in the UI.
|
|
158 |
person = self.factory.makePerson() |
|
159 |
product = self.factory.makeProduct( |
|
160 |
name='product1', owner=person, official_malone=True) |
|
161 |
with person_logged_in(person): |
|
162 |
product.setBugSupervisor(person, person) |
|
163 |
product_2 = self.factory.makeProduct( |
|
164 |
name='product2', official_malone=True) |
|
165 |
with person_logged_in(product_2.owner): |
|
166 |
product_2.setBugSupervisor(product_2.owner, product_2.owner) |
|
167 |
bug = self.factory.makeBug( |
|
168 |
product=product, owner=person) |
|
169 |
# We need to commit here, otherwise all the sample data we
|
|
170 |
# created gets destroyed when the transaction is rolled back.
|
|
171 |
transaction.commit() |
|
172 |
with person_logged_in(person): |
|
173 |
form_data = { |
|
174 |
'%s.product' % product.name: product_2.name, |
|
175 |
'%s.status' % product.name: BugTaskStatus.TRIAGED.title, |
|
176 |
'%s.actions.save' % product.name: 'Save Changes', |
|
177 |
}
|
|
178 |
view = create_initialized_view( |
|
179 |
bug.default_bugtask, name=u'+editstatus', |
|
180 |
form=form_data) |
|
181 |
# The bugtask's target won't have changed, since an error
|
|
182 |
# happend. The error will be listed in the view.
|
|
13402.4.5
by Graham Binns
Tweaked according to Rob's requirements. |
183 |
self.assertEqual(1, len(view.errors)) |
13402.4.1
by Graham Binns
I can't quite believe this, but the tests pass. |
184 |
self.assertEqual(product, bug.default_bugtask.target) |
185 |
||
11474.2.3
by Robert Collins
Add getSubscribersForPerson to IBug, permitting single query setup of bug index pages, which according to OOPS is about 1.2 seconds (but if we're underestimating could be more) and will make analysing performance on the page easier. |
186 |
|
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
187 |
class TestBugTasksAndNominationsView(TestCaseWithFactory): |
188 |
||
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
189 |
layer = DatabaseFunctionalLayer |
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
190 |
|
191 |
def setUp(self): |
|
192 |
super(TestBugTasksAndNominationsView, self).setUp() |
|
11474.2.1
by Robert Collins
Use sampledata constants. |
193 |
login(ADMIN_EMAIL) |
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
194 |
self.bug = self.factory.makeBug() |
9521.3.1
by Tom Berger
patch from allenap |
195 |
self.view = BugTasksAndNominationsView( |
196 |
self.bug, LaunchpadTestRequest()) |
|
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
197 |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
198 |
def refresh(self): |
11582.2.6
by Robert Collins
More tests not-quite-right. |
199 |
# The view caches, to see different scenarios, a refresh is needed.
|
11582.2.5
by Robert Collins
Fix up test fallout. |
200 |
self.view = BugTasksAndNominationsView( |
201 |
self.bug, LaunchpadTestRequest()) |
|
202 |
||
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
203 |
def test_current_user_affected_status(self): |
204 |
self.failUnlessEqual( |
|
205 |
None, self.view.current_user_affected_status) |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
206 |
self.bug.markUserAffected(self.view.user, True) |
207 |
self.refresh() |
|
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
208 |
self.failUnlessEqual( |
209 |
True, self.view.current_user_affected_status) |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
210 |
self.bug.markUserAffected(self.view.user, False) |
211 |
self.refresh() |
|
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
212 |
self.failUnlessEqual( |
213 |
False, self.view.current_user_affected_status) |
|
214 |
||
215 |
def test_current_user_affected_js_status(self): |
|
216 |
self.failUnlessEqual( |
|
217 |
'null', self.view.current_user_affected_js_status) |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
218 |
self.bug.markUserAffected(self.view.user, True) |
219 |
self.refresh() |
|
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
220 |
self.failUnlessEqual( |
221 |
'true', self.view.current_user_affected_js_status) |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
222 |
self.bug.markUserAffected(self.view.user, False) |
223 |
self.refresh() |
|
8971.26.2
by Gavin Panella
New property current_user_affected_js_status, and tests. |
224 |
self.failUnlessEqual( |
225 |
'false', self.view.current_user_affected_js_status) |
|
226 |
||
9521.3.1
by Tom Berger
patch from allenap |
227 |
def test_not_many_bugtasks(self): |
228 |
for count in range(10 - len(self.bug.bugtasks) - 1): |
|
229 |
self.factory.makeBugTask(bug=self.bug) |
|
230 |
self.view.initialize() |
|
231 |
self.failIf(self.view.many_bugtasks) |
|
232 |
row_view = self.view._getTableRowView( |
|
233 |
self.bug.default_bugtask, False, False) |
|
234 |
self.failIf(row_view.many_bugtasks) |
|
235 |
||
236 |
def test_many_bugtasks(self): |
|
237 |
for count in range(10 - len(self.bug.bugtasks)): |
|
238 |
self.factory.makeBugTask(bug=self.bug) |
|
239 |
self.view.initialize() |
|
240 |
self.failUnless(self.view.many_bugtasks) |
|
241 |
row_view = self.view._getTableRowView( |
|
242 |
self.bug.default_bugtask, False, False) |
|
243 |
self.failUnless(row_view.many_bugtasks) |
|
244 |
||
10015.1.2
by Gavin Panella
New view property other_users_affected_count. |
245 |
def test_other_users_affected_count(self): |
246 |
# The number of other users affected does not change when the
|
|
247 |
# logged-in user marked him or herself as affected or not.
|
|
248 |
self.failUnlessEqual( |
|
249 |
1, self.view.other_users_affected_count) |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
250 |
self.bug.markUserAffected(self.view.user, True) |
251 |
self.refresh() |
|
10015.1.2
by Gavin Panella
New view property other_users_affected_count. |
252 |
self.failUnlessEqual( |
253 |
1, self.view.other_users_affected_count) |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
254 |
self.bug.markUserAffected(self.view.user, False) |
255 |
self.refresh() |
|
10015.1.2
by Gavin Panella
New view property other_users_affected_count. |
256 |
self.failUnlessEqual( |
257 |
1, self.view.other_users_affected_count) |
|
258 |
||
259 |
def test_other_users_affected_count_other_users(self): |
|
260 |
# The number of other users affected only changes when other
|
|
261 |
# users mark themselves as affected.
|
|
262 |
self.failUnlessEqual( |
|
263 |
1, self.view.other_users_affected_count) |
|
264 |
other_user_1 = self.factory.makePerson() |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
265 |
self.bug.markUserAffected(other_user_1, True) |
10015.1.2
by Gavin Panella
New view property other_users_affected_count. |
266 |
self.failUnlessEqual( |
267 |
2, self.view.other_users_affected_count) |
|
268 |
other_user_2 = self.factory.makePerson() |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
269 |
self.bug.markUserAffected(other_user_2, True) |
10015.1.2
by Gavin Panella
New view property other_users_affected_count. |
270 |
self.failUnlessEqual( |
271 |
3, self.view.other_users_affected_count) |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
272 |
self.bug.markUserAffected(other_user_1, False) |
10015.1.2
by Gavin Panella
New view property other_users_affected_count. |
273 |
self.failUnlessEqual( |
274 |
2, self.view.other_users_affected_count) |
|
11582.2.5
by Robert Collins
Fix up test fallout. |
275 |
self.bug.markUserAffected(self.view.user, True) |
276 |
self.refresh() |
|
10015.1.2
by Gavin Panella
New view property other_users_affected_count. |
277 |
self.failUnlessEqual( |
278 |
2, self.view.other_users_affected_count) |
|
279 |
||
10015.1.3
by Gavin Panella
New view property affected_statement. |
280 |
def test_affected_statement_no_one_affected(self): |
281 |
self.bug.markUserAffected(self.bug.owner, False) |
|
282 |
self.failUnlessEqual( |
|
283 |
0, self.view.other_users_affected_count) |
|
284 |
self.failUnlessEqual( |
|
285 |
"Does this bug affect you?", |
|
286 |
self.view.affected_statement) |
|
287 |
||
288 |
def test_affected_statement_only_you(self): |
|
289 |
self.view.context.markUserAffected(self.view.user, True) |
|
290 |
self.failUnless(self.bug.isUserAffected(self.view.user)) |
|
291 |
self.view.context.markUserAffected(self.bug.owner, False) |
|
292 |
self.failUnlessEqual( |
|
293 |
0, self.view.other_users_affected_count) |
|
294 |
self.failUnlessEqual( |
|
10015.1.7
by Gavin Panella
Remove trailing full-stops from the affected statement. |
295 |
"This bug affects you", |
10015.1.3
by Gavin Panella
New view property affected_statement. |
296 |
self.view.affected_statement) |
297 |
||
10015.1.8
by Gavin Panella
Make affected_statement different when a user has explicitly said they are not affected, and when they have not. |
298 |
def test_affected_statement_only_not_you(self): |
299 |
self.view.context.markUserAffected(self.view.user, False) |
|
300 |
self.failIf(self.bug.isUserAffected(self.view.user)) |
|
301 |
self.view.context.markUserAffected(self.bug.owner, False) |
|
302 |
self.failUnlessEqual( |
|
303 |
0, self.view.other_users_affected_count) |
|
304 |
self.failUnlessEqual( |
|
10015.1.10
by Gavin Panella
Say "doesn't" instead of "does not". |
305 |
"This bug doesn't affect you", |
10015.1.8
by Gavin Panella
Make affected_statement different when a user has explicitly said they are not affected, and when they have not. |
306 |
self.view.affected_statement) |
307 |
||
10015.1.3
by Gavin Panella
New view property affected_statement. |
308 |
def test_affected_statement_1_person_not_you(self): |
309 |
self.assertIs(None, self.bug.isUserAffected(self.view.user)) |
|
310 |
self.failUnlessEqual( |
|
311 |
1, self.view.other_users_affected_count) |
|
312 |
self.failUnlessEqual( |
|
313 |
"This bug affects 1 person. Does this bug affect you?", |
|
314 |
self.view.affected_statement) |
|
315 |
||
316 |
def test_affected_statement_1_person_and_you(self): |
|
317 |
self.view.context.markUserAffected(self.view.user, True) |
|
318 |
self.failUnless(self.bug.isUserAffected(self.view.user)) |
|
319 |
self.failUnlessEqual( |
|
320 |
1, self.view.other_users_affected_count) |
|
321 |
self.failUnlessEqual( |
|
10015.1.7
by Gavin Panella
Remove trailing full-stops from the affected statement. |
322 |
"This bug affects you and 1 other person", |
10015.1.3
by Gavin Panella
New view property affected_statement. |
323 |
self.view.affected_statement) |
324 |
||
10015.1.8
by Gavin Panella
Make affected_statement different when a user has explicitly said they are not affected, and when they have not. |
325 |
def test_affected_statement_1_person_and_not_you(self): |
326 |
self.view.context.markUserAffected(self.view.user, False) |
|
327 |
self.failIf(self.bug.isUserAffected(self.view.user)) |
|
328 |
self.failUnlessEqual( |
|
329 |
1, self.view.other_users_affected_count) |
|
330 |
self.failUnlessEqual( |
|
331 |
"This bug affects 1 person, but not you", |
|
332 |
self.view.affected_statement) |
|
333 |
||
10015.1.3
by Gavin Panella
New view property affected_statement. |
334 |
def test_affected_statement_more_than_1_person_not_you(self): |
335 |
self.assertIs(None, self.bug.isUserAffected(self.view.user)) |
|
336 |
other_user = self.factory.makePerson() |
|
337 |
self.view.context.markUserAffected(other_user, True) |
|
338 |
self.failUnlessEqual( |
|
339 |
2, self.view.other_users_affected_count) |
|
340 |
self.failUnlessEqual( |
|
341 |
"This bug affects 2 people. Does this bug affect you?", |
|
342 |
self.view.affected_statement) |
|
343 |
||
344 |
def test_affected_statement_more_than_1_person_and_you(self): |
|
345 |
self.view.context.markUserAffected(self.view.user, True) |
|
346 |
self.failUnless(self.bug.isUserAffected(self.view.user)) |
|
347 |
other_user = self.factory.makePerson() |
|
348 |
self.view.context.markUserAffected(other_user, True) |
|
349 |
self.failUnlessEqual( |
|
350 |
2, self.view.other_users_affected_count) |
|
351 |
self.failUnlessEqual( |
|
10015.1.7
by Gavin Panella
Remove trailing full-stops from the affected statement. |
352 |
"This bug affects you and 2 other people", |
10015.1.3
by Gavin Panella
New view property affected_statement. |
353 |
self.view.affected_statement) |
354 |
||
10015.1.8
by Gavin Panella
Make affected_statement different when a user has explicitly said they are not affected, and when they have not. |
355 |
def test_affected_statement_more_than_1_person_and_not_you(self): |
356 |
self.view.context.markUserAffected(self.view.user, False) |
|
357 |
self.failIf(self.bug.isUserAffected(self.view.user)) |
|
358 |
other_user = self.factory.makePerson() |
|
359 |
self.view.context.markUserAffected(other_user, True) |
|
360 |
self.failUnlessEqual( |
|
361 |
2, self.view.other_users_affected_count) |
|
362 |
self.failUnlessEqual( |
|
363 |
"This bug affects 2 people, but not you", |
|
364 |
self.view.affected_statement) |
|
365 |
||
10015.1.18
by Gavin Panella
New view property anon_affected_statement. |
366 |
def test_anon_affected_statement_no_one_affected(self): |
367 |
self.bug.markUserAffected(self.bug.owner, False) |
|
368 |
self.failUnlessEqual(0, self.bug.users_affected_count) |
|
369 |
self.assertIs(None, self.view.anon_affected_statement) |
|
370 |
||
371 |
def test_anon_affected_statement_1_user_affected(self): |
|
372 |
self.failUnlessEqual(1, self.bug.users_affected_count) |
|
373 |
self.failUnlessEqual( |
|
374 |
"This bug affects 1 person", |
|
375 |
self.view.anon_affected_statement) |
|
376 |
||
377 |
def test_anon_affected_statement_2_users_affected(self): |
|
378 |
self.view.context.markUserAffected(self.view.user, True) |
|
379 |
self.failUnlessEqual(2, self.bug.users_affected_count) |
|
380 |
self.failUnlessEqual( |
|
381 |
"This bug affects 2 people", |
|
382 |
self.view.anon_affected_statement) |
|
383 |
||
12561.3.19
by Curtis Hovey
Moved product and productseries getTargetLinkTitle tests to a unit test. |
384 |
def test_getTargetLinkTitle_product(self): |
385 |
# The target link title is always none for products.
|
|
386 |
target = self.factory.makeProduct() |
|
387 |
bug_task = self.factory.makeBugTask(bug=self.bug, target=target) |
|
12561.3.20
by Curtis Hovey
Reconstructed the BugTasksAndNominationsView.getTargetLinkTitle test. |
388 |
self.view.initialize() |
389 |
self.assertEqual(None, self.view.getTargetLinkTitle(bug_task.target)) |
|
12561.3.19
by Curtis Hovey
Moved product and productseries getTargetLinkTitle tests to a unit test. |
390 |
|
391 |
def test_getTargetLinkTitle_productseries(self): |
|
12561.3.20
by Curtis Hovey
Reconstructed the BugTasksAndNominationsView.getTargetLinkTitle test. |
392 |
# The target link title is always none for productseries.
|
12561.3.19
by Curtis Hovey
Moved product and productseries getTargetLinkTitle tests to a unit test. |
393 |
target = self.factory.makeProductSeries() |
394 |
bug_task = self.factory.makeBugTask(bug=self.bug, target=target) |
|
12561.3.20
by Curtis Hovey
Reconstructed the BugTasksAndNominationsView.getTargetLinkTitle test. |
395 |
self.view.initialize() |
396 |
self.assertEqual(None, self.view.getTargetLinkTitle(bug_task.target)) |
|
397 |
||
398 |
def test_getTargetLinkTitle_distribution(self): |
|
399 |
# The target link title is always none for distributions.
|
|
400 |
target = self.factory.makeDistribution() |
|
401 |
bug_task = self.factory.makeBugTask(bug=self.bug, target=target) |
|
402 |
self.view.initialize() |
|
403 |
self.assertEqual(None, self.view.getTargetLinkTitle(bug_task.target)) |
|
404 |
||
405 |
def test_getTargetLinkTitle_distroseries(self): |
|
406 |
# The target link title is always none for distroseries.
|
|
407 |
target = self.factory.makeDistroSeries() |
|
408 |
bug_task = self.factory.makeBugTask(bug=self.bug, target=target) |
|
409 |
self.view.initialize() |
|
410 |
self.assertEqual(None, self.view.getTargetLinkTitle(bug_task.target)) |
|
411 |
||
412 |
def test_getTargetLinkTitle_unpublished_distributionsourcepackage(self): |
|
413 |
# The target link title states that the package is not published
|
|
414 |
# in the current release.
|
|
415 |
distribution = self.factory.makeDistribution(name='boy') |
|
416 |
spn = self.factory.makeSourcePackageName('badger') |
|
417 |
component = getUtility(IComponentSet)['universe'] |
|
418 |
maintainer = self.factory.makePerson(name="jim") |
|
419 |
creator = self.factory.makePerson(name="tim") |
|
420 |
self.factory.makeSourcePackagePublishingHistory( |
|
421 |
distroseries=distribution.currentseries, version='2.0', |
|
422 |
component=component, sourcepackagename=spn, |
|
423 |
date_uploaded=datetime(2008, 7, 18, 10, 20, 30, tzinfo=UTC), |
|
424 |
maintainer=maintainer, creator=creator) |
|
425 |
target = distribution.getSourcePackage('badger') |
|
426 |
bug_task = self.factory.makeBugTask( |
|
427 |
bug=self.bug, target=target, publish=False) |
|
428 |
self.view.initialize() |
|
12561.3.21
by Curtis Hovey
Removed duplicate test. |
429 |
self.assertEqual({}, self.view.target_releases) |
12561.3.20
by Curtis Hovey
Reconstructed the BugTasksAndNominationsView.getTargetLinkTitle test. |
430 |
self.assertEqual( |
431 |
'No current release for this source package in Boy', |
|
432 |
self.view.getTargetLinkTitle(bug_task.target)) |
|
433 |
||
434 |
def test_getTargetLinkTitle_published_distributionsourcepackage(self): |
|
435 |
# The target link title states the information about the current
|
|
436 |
# package in the distro.
|
|
437 |
distribution = self.factory.makeDistribution(name='koi') |
|
438 |
distroseries = self.factory.makeDistroSeries( |
|
439 |
distribution=distribution) |
|
440 |
spn = self.factory.makeSourcePackageName('finch') |
|
441 |
component = getUtility(IComponentSet)['universe'] |
|
442 |
maintainer = self.factory.makePerson(name="jim") |
|
443 |
creator = self.factory.makePerson(name="tim") |
|
444 |
self.factory.makeSourcePackagePublishingHistory( |
|
445 |
distroseries=distroseries, version='2.0', |
|
446 |
component=component, sourcepackagename=spn, |
|
447 |
date_uploaded=datetime(2008, 7, 18, 10, 20, 30, tzinfo=UTC), |
|
448 |
maintainer=maintainer, creator=creator) |
|
449 |
target = distribution.getSourcePackage('finch') |
|
450 |
bug_task = self.factory.makeBugTask( |
|
451 |
bug=self.bug, target=target, publish=False) |
|
452 |
self.view.initialize() |
|
12561.3.21
by Curtis Hovey
Removed duplicate test. |
453 |
self.assertTrue( |
454 |
target in self.view.target_releases.keys()) |
|
12561.3.20
by Curtis Hovey
Reconstructed the BugTasksAndNominationsView.getTargetLinkTitle test. |
455 |
self.assertEqual( |
456 |
'Latest release: 2.0, uploaded to universe on '
|
|
457 |
'2008-07-18 10:20:30+00:00 by Tim (tim), maintained by Jim (jim)', |
|
458 |
self.view.getTargetLinkTitle(bug_task.target)) |
|
459 |
||
460 |
def test_getTargetLinkTitle_published_sourcepackage(self): |
|
461 |
# The target link title states the information about the current
|
|
462 |
# package in the distro.
|
|
463 |
distroseries = self.factory.makeDistroSeries() |
|
464 |
spn = self.factory.makeSourcePackageName('bunny') |
|
465 |
component = getUtility(IComponentSet)['universe'] |
|
466 |
maintainer = self.factory.makePerson(name="jim") |
|
467 |
creator = self.factory.makePerson(name="tim") |
|
468 |
self.factory.makeSourcePackagePublishingHistory( |
|
469 |
distroseries=distroseries, version='2.0', |
|
470 |
component=component, sourcepackagename=spn, |
|
471 |
date_uploaded=datetime(2008, 7, 18, 10, 20, 30, tzinfo=UTC), |
|
472 |
maintainer=maintainer, creator=creator) |
|
473 |
target = distroseries.getSourcePackage('bunny') |
|
474 |
bug_task = self.factory.makeBugTask( |
|
475 |
bug=self.bug, target=target, publish=False) |
|
476 |
self.view.initialize() |
|
12561.3.21
by Curtis Hovey
Removed duplicate test. |
477 |
self.assertTrue( |
478 |
target in self.view.target_releases.keys()) |
|
12561.3.20
by Curtis Hovey
Reconstructed the BugTasksAndNominationsView.getTargetLinkTitle test. |
479 |
self.assertEqual( |
480 |
'Latest release: 2.0, uploaded to universe on '
|
|
481 |
'2008-07-18 10:20:30+00:00 by Tim (tim), maintained by Jim (jim)', |
|
482 |
self.view.getTargetLinkTitle(bug_task.target)) |
|
12561.3.19
by Curtis Hovey
Moved product and productseries getTargetLinkTitle tests to a unit test. |
483 |
|
12799.1.2
by Ian Booth
Rework implementation and do unit tests instead of doc tests |
484 |
def _get_object_type(self, task_or_nomination): |
485 |
if IBugTask.providedBy(task_or_nomination): |
|
486 |
return "bugtask" |
|
487 |
elif IBugNomination.providedBy(task_or_nomination): |
|
488 |
return "nomination" |
|
489 |
else: |
|
490 |
return "unknown" |
|
491 |
||
492 |
def test_bugtask_listing_for_inactive_projects(self): |
|
493 |
# Bugtasks should only be listed for active projects.
|
|
494 |
||
495 |
product_foo = self.factory.makeProduct(name="foo") |
|
496 |
product_bar = self.factory.makeProduct(name="bar") |
|
497 |
foo_bug = self.factory.makeBug(product=product_foo) |
|
498 |
bugtask_set = getUtility(IBugTaskSet) |
|
13571.2.2
by William Grant
BugTaskSet.createTask now takes an IBugTarget, not a key. Blergh. |
499 |
bugtask_set.createTask(foo_bug, foo_bug.owner, product_bar) |
12799.1.2
by Ian Booth
Rework implementation and do unit tests instead of doc tests |
500 |
|
501 |
removeSecurityProxy(product_bar).active = False |
|
502 |
||
503 |
request = LaunchpadTestRequest() |
|
504 |
foo_bugtasks_and_nominations_view = getMultiAdapter( |
|
505 |
(foo_bug, request), name="+bugtasks-and-nominations-table") |
|
506 |
foo_bugtasks_and_nominations_view.initialize() |
|
507 |
||
508 |
task_and_nomination_views = ( |
|
509 |
foo_bugtasks_and_nominations_view.getBugTaskAndNominationViews()) |
|
510 |
actual_results = [] |
|
511 |
for task_or_nomination_view in task_and_nomination_views: |
|
512 |
task_or_nomination = task_or_nomination_view.context |
|
513 |
actual_results.append(( |
|
514 |
self._get_object_type(task_or_nomination), |
|
515 |
task_or_nomination.status.title, |
|
516 |
task_or_nomination.target.bugtargetdisplayname)) |
|
517 |
# Only the one active project's task should be listed.
|
|
518 |
self.assertEqual([("bugtask", "New", "Foo")], actual_results) |
|
519 |
||
520 |
def test_listing_with_no_bugtasks(self): |
|
521 |
# Test the situation when there are no bugtasks to show.
|
|
522 |
||
523 |
product_foo = self.factory.makeProduct(name="foo") |
|
524 |
foo_bug = self.factory.makeBug(product=product_foo) |
|
525 |
removeSecurityProxy(product_foo).active = False |
|
526 |
||
527 |
request = LaunchpadTestRequest() |
|
528 |
foo_bugtasks_and_nominations_view = getMultiAdapter( |
|
529 |
(foo_bug, request), name="+bugtasks-and-nominations-table") |
|
530 |
foo_bugtasks_and_nominations_view.initialize() |
|
531 |
||
532 |
task_and_nomination_views = ( |
|
533 |
foo_bugtasks_and_nominations_view.getBugTaskAndNominationViews()) |
|
534 |
self.assertEqual([], task_and_nomination_views) |
|
535 |
||
13543.10.1
by William Grant
Display a faded statusless row for the parents of orphaned bugtasks. |
536 |
def test_bugtarget_parent_shown_for_orphaned_series_tasks(self): |
537 |
# Test that a row is shown for the parent of a series task, even
|
|
538 |
# if the parent doesn't actually have a task.
|
|
539 |
series = self.factory.makeProductSeries() |
|
540 |
bug = self.factory.makeBug(series=series) |
|
541 |
self.assertEqual(2, len(bug.bugtasks)) |
|
542 |
new_prod = self.factory.makeProduct() |
|
543 |
bug.getBugTask(series.product).transitionToTarget(new_prod) |
|
544 |
||
545 |
view = create_initialized_view(bug, "+bugtasks-and-nominations-table") |
|
546 |
subviews = view.getBugTaskAndNominationViews() |
|
547 |
self.assertEqual([ |
|
548 |
(series.product, '+bugtasks-and-nominations-table-row'), |
|
549 |
(bug.getBugTask(series), '+bugtasks-and-nominations-table-row'), |
|
550 |
(bug.getBugTask(new_prod), '+bugtasks-and-nominations-table-row'), |
|
551 |
], [(v.context, v.__name__) for v in subviews]) |
|
552 |
||
553 |
content = subviews[0]() |
|
554 |
self.assertIn( |
|
555 |
'href="%s"' % canonical_url( |
|
556 |
series.product, path_only_if_possible=True), |
|
557 |
content) |
|
558 |
self.assertIn(series.product.displayname, content) |
|
559 |
||
2770.1.40
by Guilherme Salgado
A few fixes Bjorn suggested and removing two unused templates. |
560 |
|
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
561 |
class TestBugTaskEditViewStatusField(TestCaseWithFactory): |
562 |
"""We show only those options as possible value in the status
|
|
563 |
field that the user can select.
|
|
564 |
"""
|
|
565 |
||
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
566 |
layer = DatabaseFunctionalLayer |
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
567 |
|
568 |
def setUp(self): |
|
569 |
super(TestBugTaskEditViewStatusField, self).setUp() |
|
10680.2.4
by Abel Deuring
replaced the no longer existing method factoy.makPersonNoCommit(9 by makePerson(); ensure that only project owners and supervisors can set a bugtask status to 'expired' |
570 |
product_owner = self.factory.makePerson(name='product-owner') |
571 |
bug_supervisor = self.factory.makePerson(name='bug-supervisor') |
|
572 |
product = self.factory.makeProduct( |
|
10680.2.2
by Abel Deuring
implemented reviewer's comments |
573 |
owner=product_owner, bug_supervisor=bug_supervisor) |
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
574 |
self.bug = self.factory.makeBug(product=product) |
575 |
||
576 |
def getWidgetOptionTitles(self, widget): |
|
577 |
"""Return the titles of options of the given choice widget."""
|
|
578 |
return [ |
|
579 |
item.value.title for item in widget.field.vocabulary] |
|
580 |
||
581 |
def test_status_field_items_for_anonymous(self): |
|
582 |
# Anonymous users see only the current value.
|
|
583 |
login(ANONYMOUS) |
|
584 |
view = BugTaskEditView( |
|
585 |
self.bug.default_bugtask, LaunchpadTestRequest()) |
|
586 |
view.initialize() |
|
587 |
self.assertEqual( |
|
588 |
['New'], self.getWidgetOptionTitles(view.form_fields['status'])) |
|
589 |
||
590 |
def test_status_field_items_for_ordinary_users(self): |
|
591 |
# Ordinary users can set the status to all values except Won't fix,
|
|
592 |
# Expired, Triaged, Unknown.
|
|
11474.2.1
by Robert Collins
Use sampledata constants. |
593 |
login(NO_PRIVILEGE_EMAIL) |
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
594 |
view = BugTaskEditView( |
595 |
self.bug.default_bugtask, LaunchpadTestRequest()) |
|
596 |
view.initialize() |
|
597 |
self.assertEqual( |
|
7675.718.1
by Abel Deuring
add a bug task status OPINION |
598 |
['New', 'Incomplete', 'Opinion', 'Invalid', 'Confirmed', |
599 |
'In Progress', 'Fix Committed', 'Fix Released'], |
|
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
600 |
self.getWidgetOptionTitles(view.form_fields['status'])) |
601 |
||
602 |
def test_status_field_privileged_persons(self): |
|
603 |
# The bug target owner and the bug target supervisor can set
|
|
604 |
# the status to any value except Unknown and Expired.
|
|
605 |
for user in ( |
|
606 |
self.bug.default_bugtask.pillar.owner, |
|
607 |
self.bug.default_bugtask.pillar.bug_supervisor): |
|
608 |
login_person(user) |
|
609 |
view = BugTaskEditView( |
|
610 |
self.bug.default_bugtask, LaunchpadTestRequest()) |
|
611 |
view.initialize() |
|
612 |
self.assertEqual( |
|
7675.718.1
by Abel Deuring
add a bug task status OPINION |
613 |
['New', 'Incomplete', 'Opinion', 'Invalid', "Won't Fix", |
614 |
'Confirmed', 'Triaged', 'In Progress', 'Fix Committed', |
|
615 |
'Fix Released'], |
|
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
616 |
self.getWidgetOptionTitles(view.form_fields['status']), |
617 |
'Unexpected set of settable status options for %s' |
|
618 |
% user.name) |
|
619 |
||
620 |
def test_status_field_bug_task_in_status_unknown(self): |
|
621 |
# If a bugtask has the status Unknown, this status is included
|
|
622 |
# in the options.
|
|
10680.2.2
by Abel Deuring
implemented reviewer's comments |
623 |
owner = self.bug.default_bugtask.pillar.owner |
624 |
login_person(owner) |
|
625 |
self.bug.default_bugtask.transitionToStatus( |
|
626 |
BugTaskStatus.UNKNOWN, owner) |
|
11474.2.1
by Robert Collins
Use sampledata constants. |
627 |
login(NO_PRIVILEGE_EMAIL) |
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
628 |
view = BugTaskEditView( |
629 |
self.bug.default_bugtask, LaunchpadTestRequest()) |
|
630 |
view.initialize() |
|
631 |
self.assertEqual( |
|
7675.718.1
by Abel Deuring
add a bug task status OPINION |
632 |
['New', 'Incomplete', 'Opinion', 'Invalid', 'Confirmed', |
633 |
'In Progress', 'Fix Committed', 'Fix Released', 'Unknown'], |
|
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
634 |
self.getWidgetOptionTitles(view.form_fields['status'])) |
635 |
||
636 |
def test_status_field_bug_task_in_status_expired(self): |
|
10680.2.2
by Abel Deuring
implemented reviewer's comments |
637 |
# If a bugtask has the status Expired, this status is included
|
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
638 |
# in the options.
|
639 |
removeSecurityProxy(self.bug.default_bugtask).status = ( |
|
640 |
BugTaskStatus.EXPIRED) |
|
11474.2.1
by Robert Collins
Use sampledata constants. |
641 |
login(NO_PRIVILEGE_EMAIL) |
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
642 |
view = BugTaskEditView( |
643 |
self.bug.default_bugtask, LaunchpadTestRequest()) |
|
644 |
view.initialize() |
|
645 |
self.assertEqual( |
|
7675.718.1
by Abel Deuring
add a bug task status OPINION |
646 |
['New', 'Incomplete', 'Opinion', 'Invalid', 'Expired', |
647 |
'Confirmed', 'In Progress', 'Fix Committed', 'Fix Released'], |
|
10680.2.1
by Abel Deuring
Add a new bug task status 'Expired'; the bug task expiration script sets expired bug tasks to this status; related adjustments to the bug task views |
648 |
self.getWidgetOptionTitles(view.form_fields['status'])) |
649 |
||
650 |
||
10788.5.2
by Abel Deuring
ordinary users can (un)assign a bug task only to hemselves and their teams |
651 |
class TestBugTaskEditViewAssigneeField(TestCaseWithFactory): |
652 |
||
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
653 |
layer = DatabaseFunctionalLayer |
10788.5.2
by Abel Deuring
ordinary users can (un)assign a bug task only to hemselves and their teams |
654 |
|
655 |
def setUp(self): |
|
656 |
super(TestBugTaskEditViewAssigneeField, self).setUp() |
|
11435.6.11
by Deryck Hodge
Fix browser test. |
657 |
self.owner = self.factory.makePerson() |
658 |
self.product = self.factory.makeProduct(owner=self.owner) |
|
659 |
self.bugtask = self.factory.makeBug( |
|
660 |
product=self.product).default_bugtask |
|
10788.5.2
by Abel Deuring
ordinary users can (un)assign a bug task only to hemselves and their teams |
661 |
|
11435.6.11
by Deryck Hodge
Fix browser test. |
662 |
def test_assignee_vocabulary_regular_user_with_bug_supervisor(self): |
10788.5.2
by Abel Deuring
ordinary users can (un)assign a bug task only to hemselves and their teams |
663 |
# For regular users, the assignee vocabulary is
|
11435.6.11
by Deryck Hodge
Fix browser test. |
664 |
# AllUserTeamsParticipation if there is a bug supervisor defined.
|
665 |
login_person(self.owner) |
|
666 |
self.product.setBugSupervisor(self.owner, self.owner) |
|
11474.2.1
by Robert Collins
Use sampledata constants. |
667 |
login(USER_EMAIL) |
10788.5.2
by Abel Deuring
ordinary users can (un)assign a bug task only to hemselves and their teams |
668 |
view = BugTaskEditView(self.bugtask, LaunchpadTestRequest()) |
669 |
view.initialize() |
|
670 |
self.assertEqual( |
|
671 |
'AllUserTeamsParticipation', |
|
672 |
view.form_fields['assignee'].field.vocabularyName) |
|
673 |
||
11435.6.11
by Deryck Hodge
Fix browser test. |
674 |
def test_assignee_vocabulary_regular_user_without_bug_supervisor(self): |
675 |
# For regular users, the assignee vocabulary is
|
|
676 |
# ValidAssignee is there is not a bug supervisor defined.
|
|
677 |
login_person(self.owner) |
|
678 |
self.product.setBugSupervisor(None, self.owner) |
|
11474.2.7
by Robert Collins
Resolve conflicts with trunk. |
679 |
login(USER_EMAIL) |
11435.6.11
by Deryck Hodge
Fix browser test. |
680 |
view = BugTaskEditView(self.bugtask, LaunchpadTestRequest()) |
681 |
view.initialize() |
|
682 |
self.assertEqual( |
|
683 |
'ValidAssignee', |
|
684 |
view.form_fields['assignee'].field.vocabularyName) |
|
685 |
||
10788.5.2
by Abel Deuring
ordinary users can (un)assign a bug task only to hemselves and their teams |
686 |
def test_assignee_field_vocabulary_privileged_user(self): |
687 |
# Privileged users, like the bug task target owner, can
|
|
688 |
# assign anybody.
|
|
689 |
login_person(self.bugtask.target.owner) |
|
690 |
view = BugTaskEditView(self.bugtask, LaunchpadTestRequest()) |
|
691 |
view.initialize() |
|
692 |
self.assertEqual( |
|
693 |
'ValidAssignee', |
|
694 |
view.form_fields['assignee'].field.vocabularyName) |
|
695 |
||
696 |
||
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
697 |
class TestBugTaskEditView(TestCaseWithFactory): |
12622.5.1
by Curtis Hovey
Always remove the bugtask milestone when retargeting the product. |
698 |
"""Test the bug task edit form."""
|
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
699 |
|
700 |
layer = DatabaseFunctionalLayer |
|
701 |
||
12599.4.2
by Leonard Richardson
Merge from trunk. |
702 |
def test_retarget_already_exists_error(self): |
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
703 |
user = self.factory.makePerson() |
704 |
login_person(user) |
|
705 |
ubuntu = getUtility(ILaunchpadCelebrities).ubuntu |
|
706 |
dsp_1 = self.factory.makeDistributionSourcePackage( |
|
707 |
distribution=ubuntu, sourcepackagename='mouse') |
|
13247.1.1
by Danilo Segan
Reapply bug 772754 fix with packagecopyjob changes removed. |
708 |
self.factory.makeSourcePackagePublishingHistory( |
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
709 |
distroseries=ubuntu.currentseries, |
710 |
sourcepackagename=dsp_1.sourcepackagename) |
|
711 |
bug_task_1 = self.factory.makeBugTask(target=dsp_1) |
|
712 |
dsp_2 = self.factory.makeDistributionSourcePackage( |
|
713 |
distribution=ubuntu, sourcepackagename='rabbit') |
|
13247.1.1
by Danilo Segan
Reapply bug 772754 fix with packagecopyjob changes removed. |
714 |
self.factory.makeSourcePackagePublishingHistory( |
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
715 |
distroseries=ubuntu.currentseries, |
716 |
sourcepackagename=dsp_2.sourcepackagename) |
|
717 |
bug_task_2 = self.factory.makeBugTask( |
|
718 |
bug=bug_task_1.bug, target=dsp_2) |
|
719 |
form = { |
|
720 |
'ubuntu_rabbit.actions.save': 'Save Changes', |
|
721 |
'ubuntu_rabbit.status': 'In Progress', |
|
722 |
'ubuntu_rabbit.importance': 'High', |
|
723 |
'ubuntu_rabbit.assignee.option': |
|
724 |
'ubuntu_rabbit.assignee.assign_to_nobody', |
|
725 |
'ubuntu_rabbit.sourcepackagename': 'mouse', |
|
726 |
}
|
|
727 |
view = create_initialized_view( |
|
12599.4.2
by Leonard Richardson
Merge from trunk. |
728 |
bug_task_2, name='+editstatus', form=form, principal=user) |
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
729 |
self.assertEqual(1, len(view.errors)) |
730 |
self.assertEqual( |
|
13506.4.17
by William Grant
Fix test. |
731 |
'A fix for this bug has already been requested for mouse in '
|
732 |
'Ubuntu', |
|
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
733 |
view.errors[0]) |
734 |
||
12622.5.2
by Curtis Hovey
Added a test to verify that assiging a milestone during a retargeting is ignored. |
735 |
def setUpRetargetMilestone(self): |
736 |
"""Setup a bugtask with a milestone and a product to retarget to."""
|
|
12622.5.1
by Curtis Hovey
Always remove the bugtask milestone when retargeting the product. |
737 |
first_product = self.factory.makeProduct(name='bunny') |
738 |
with person_logged_in(first_product.owner): |
|
739 |
first_product.official_malone = True |
|
740 |
bug = self.factory.makeBug(product=first_product) |
|
741 |
bug_task = bug.bugtasks[0] |
|
742 |
milestone = self.factory.makeMilestone( |
|
743 |
productseries=first_product.development_focus, name='1.0') |
|
744 |
bug_task.transitionToMilestone(milestone, first_product.owner) |
|
745 |
second_product = self.factory.makeProduct(name='duck') |
|
746 |
with person_logged_in(second_product.owner): |
|
747 |
second_product.official_malone = True |
|
12622.5.2
by Curtis Hovey
Added a test to verify that assiging a milestone during a retargeting is ignored. |
748 |
return bug_task, second_product |
749 |
||
750 |
def test_retarget_product_with_milestone(self): |
|
751 |
# Milestones are always cleared when retargeting a product bug task.
|
|
752 |
bug_task, second_product = self.setUpRetargetMilestone() |
|
12622.5.1
by Curtis Hovey
Always remove the bugtask milestone when retargeting the product. |
753 |
user = self.factory.makePerson() |
754 |
login_person(user) |
|
755 |
form = { |
|
756 |
'bunny.status': 'In Progress', |
|
757 |
'bunny.assignee.option': 'bunny.assignee.assign_to_nobody', |
|
758 |
'bunny.product': 'duck', |
|
759 |
'bunny.actions.save': 'Save Changes', |
|
760 |
}
|
|
761 |
view = create_initialized_view( |
|
762 |
bug_task, name='+editstatus', form=form) |
|
763 |
self.assertEqual([], view.errors) |
|
764 |
self.assertEqual(second_product, bug_task.target) |
|
765 |
self.assertEqual(None, bug_task.milestone) |
|
12622.5.2
by Curtis Hovey
Added a test to verify that assiging a milestone during a retargeting is ignored. |
766 |
notifications = view.request.response.notifications |
767 |
self.assertEqual(1, len(notifications)) |
|
768 |
expected = ('The Bunny 1.0 milestone setting has been removed') |
|
769 |
self.assertTrue(notifications.pop().message.startswith(expected)) |
|
770 |
||
771 |
def test_retarget_product_and_assign_milestone(self): |
|
772 |
# Milestones are always cleared when retargeting a product bug task.
|
|
773 |
bug_task, second_product = self.setUpRetargetMilestone() |
|
774 |
login_person(bug_task.target.owner) |
|
775 |
milestone_id = bug_task.milestone.id |
|
776 |
bug_task.transitionToMilestone(None, bug_task.target.owner) |
|
777 |
form = { |
|
778 |
'bunny.status': 'In Progress', |
|
779 |
'bunny.assignee.option': 'bunny.assignee.assign_to_nobody', |
|
780 |
'bunny.product': 'duck', |
|
781 |
'bunny.milestone': milestone_id, |
|
782 |
'bunny.actions.save': 'Save Changes', |
|
783 |
}
|
|
784 |
view = create_initialized_view( |
|
785 |
bug_task, name='+editstatus', form=form) |
|
786 |
self.assertEqual([], view.errors) |
|
787 |
self.assertEqual(second_product, bug_task.target) |
|
788 |
self.assertEqual(None, bug_task.milestone) |
|
789 |
notifications = view.request.response.notifications |
|
790 |
self.assertEqual(1, len(notifications)) |
|
791 |
expected = ('The milestone setting was ignored') |
|
792 |
self.assertTrue(notifications.pop().message.startswith(expected)) |
|
12622.5.1
by Curtis Hovey
Always remove the bugtask milestone when retargeting the product. |
793 |
|
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
794 |
|
11655.1.1
by Brad Crittenden
Do not show bug information on a project group page with no projects that use Launchpad. |
795 |
class TestProjectGroupBugs(TestCaseWithFactory): |
796 |
"""Test the bugs overview page for Project Groups."""
|
|
797 |
||
12561.3.12
by Curtis Hovey
Fixed broken view while rewriting a broken test. |
798 |
layer = DatabaseFunctionalLayer |
11655.1.1
by Brad Crittenden
Do not show bug information on a project group page with no projects that use Launchpad. |
799 |
|
800 |
def setUp(self): |
|
801 |
super(TestProjectGroupBugs, self).setUp() |
|
802 |
self.owner = self.factory.makePerson(name='bob') |
|
803 |
self.projectgroup = self.factory.makeProject(name='container', |
|
804 |
owner=self.owner) |
|
805 |
||
806 |
def makeSubordinateProduct(self, tracks_bugs_in_lp): |
|
807 |
"""Create a new product and add it to the project group."""
|
|
808 |
product = self.factory.makeProduct(official_malone=tracks_bugs_in_lp) |
|
809 |
with person_logged_in(product.owner): |
|
810 |
product.project = self.projectgroup |
|
811 |
||
812 |
def test_empty_project_group(self): |
|
813 |
# An empty project group does not use Launchpad for bugs.
|
|
814 |
view = create_initialized_view( |
|
815 |
self.projectgroup, name=u'+bugs', rootsite='bugs') |
|
816 |
self.assertFalse(self.projectgroup.hasProducts()) |
|
817 |
self.assertFalse(view.should_show_bug_information) |
|
818 |
||
819 |
def test_project_group_with_subordinate_not_using_launchpad(self): |
|
820 |
# A project group with all subordinates not using Launchpad
|
|
821 |
# will itself be marked as not using Launchpad for bugs.
|
|
822 |
self.makeSubordinateProduct(False) |
|
823 |
self.assertTrue(self.projectgroup.hasProducts()) |
|
824 |
view = create_initialized_view( |
|
825 |
self.projectgroup, name=u'+bugs', rootsite='bugs') |
|
826 |
self.assertFalse(view.should_show_bug_information) |
|
827 |
||
828 |
def test_project_group_with_subordinate_using_launchpad(self): |
|
829 |
# A project group with one subordinate using Launchpad
|
|
830 |
# will itself be marked as using Launchpad for bugs.
|
|
831 |
self.makeSubordinateProduct(True) |
|
832 |
self.assertTrue(self.projectgroup.hasProducts()) |
|
833 |
view = create_initialized_view( |
|
834 |
self.projectgroup, name=u'+bugs', rootsite='bugs') |
|
835 |
self.assertTrue(view.should_show_bug_information) |
|
836 |
||
837 |
def test_project_group_with_mixed_subordinates(self): |
|
838 |
# A project group with one or more subordinates using Launchpad
|
|
839 |
# will itself be marked as using Launchpad for bugs.
|
|
840 |
self.makeSubordinateProduct(False) |
|
841 |
self.makeSubordinateProduct(True) |
|
842 |
self.assertTrue(self.projectgroup.hasProducts()) |
|
843 |
view = create_initialized_view( |
|
844 |
self.projectgroup, name=u'+bugs', rootsite='bugs') |
|
845 |
self.assertTrue(view.should_show_bug_information) |
|
846 |
||
847 |
def test_project_group_has_no_portlets_if_not_using_LP(self): |
|
11655.1.5
by Brad Crittenden
Post review fixes |
848 |
# A project group that has no projects using Launchpad will not have
|
849 |
# bug portlets.
|
|
11655.1.1
by Brad Crittenden
Do not show bug information on a project group page with no projects that use Launchpad. |
850 |
self.makeSubordinateProduct(False) |
851 |
view = create_initialized_view( |
|
852 |
self.projectgroup, name=u'+bugs', rootsite='bugs', |
|
853 |
current_request=True) |
|
854 |
self.assertFalse(view.should_show_bug_information) |
|
855 |
contents = view.render() |
|
856 |
report_a_bug = find_tag_by_id(contents, 'bug-portlets') |
|
857 |
self.assertIs(None, report_a_bug) |
|
858 |
||
859 |
def test_project_group_has_portlets_link_if_using_LP(self): |
|
11655.1.5
by Brad Crittenden
Post review fixes |
860 |
# A project group that has projects using Launchpad will have a
|
861 |
# portlets.
|
|
11655.1.1
by Brad Crittenden
Do not show bug information on a project group page with no projects that use Launchpad. |
862 |
self.makeSubordinateProduct(True) |
863 |
view = create_initialized_view( |
|
864 |
self.projectgroup, name=u'+bugs', rootsite='bugs', |
|
865 |
current_request=True) |
|
866 |
self.assertTrue(view.should_show_bug_information) |
|
867 |
contents = view.render() |
|
868 |
report_a_bug = find_tag_by_id(contents, 'bug-portlets') |
|
869 |
self.assertIsNot(None, report_a_bug) |
|
870 |
||
11655.1.9
by Brad Crittenden
Add help link for configuring bugs |
871 |
def test_project_group_has_help_link_if_not_using_LP(self): |
872 |
# A project group that has no projects using Launchpad will have
|
|
873 |
# a 'Getting started' help link.
|
|
874 |
self.makeSubordinateProduct(False) |
|
875 |
view = create_initialized_view( |
|
876 |
self.projectgroup, name=u'+bugs', rootsite='bugs', |
|
877 |
current_request=True) |
|
878 |
contents = view.render() |
|
879 |
help_link = find_tag_by_id(contents, 'getting-started-help') |
|
880 |
self.assertIsNot(None, help_link) |
|
881 |
||
882 |
def test_project_group_has_no_help_link_if_using_LP(self): |
|
883 |
# A project group that has no projects using Launchpad will not have
|
|
884 |
# a 'Getting started' help link.
|
|
885 |
self.makeSubordinateProduct(True) |
|
886 |
view = create_initialized_view( |
|
887 |
self.projectgroup, name=u'+bugs', rootsite='bugs', |
|
888 |
current_request=True) |
|
889 |
contents = view.render() |
|
890 |
help_link = find_tag_by_id(contents, 'getting-started-help') |
|
891 |
self.assertIs(None, help_link) |
|
12792.8.1
by William Grant
Add failing test for BugActivityItem assignee escaping. |
892 |
|
893 |
||
894 |
class TestBugActivityItem(TestCaseWithFactory): |
|
895 |
||
896 |
layer = DatabaseFunctionalLayer |
|
897 |
||
898 |
def setAttribute(self, obj, attribute, value): |
|
899 |
obj_before_modification = Snapshot(obj, providing=providedBy(obj)) |
|
900 |
setattr(removeSecurityProxy(obj), attribute, value) |
|
901 |
notify(ObjectModifiedEvent( |
|
902 |
obj, obj_before_modification, [attribute], |
|
903 |
self.factory.makePerson())) |
|
904 |
||
905 |
def test_escapes_assignee(self): |
|
906 |
with celebrity_logged_in('admin'): |
|
907 |
task = self.factory.makeBugTask() |
|
908 |
self.setAttribute( |
|
909 |
task, 'assignee', |
|
910 |
self.factory.makePerson(displayname="Foo &<>", name='foo')) |
|
911 |
self.assertEquals( |
|
912 |
"nobody → Foo &<> (foo)", |
|
913 |
BugActivityItem(task.bug.activity[-1]).change_details) |
|
914 |
||
915 |
def test_escapes_title(self): |
|
916 |
with celebrity_logged_in('admin'): |
|
917 |
bug = self.factory.makeBug(title="foo") |
|
918 |
self.setAttribute(bug, 'title', "bar &<>") |
|
919 |
self.assertEquals( |
|
920 |
"- foo<br />+ bar &<>", |
|
921 |
BugActivityItem(bug.activity[-1]).change_details) |