13811.2.1
by Jeroen Vermeulen
Fix some of the lint people left in the past few days. |
1 |
# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
|
11526.4.35
by Gavin Panella
Add StructuralSubscription.bug_filters. |
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
3 |
||
4 |
"""Tests for `StructuralSubscription`."""
|
|
5 |
||
6 |
__metaclass__ = type |
|
7 |
||
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
8 |
from storm.store import ( |
9 |
EmptyResultSet, |
|
10 |
ResultSet, |
|
11 |
Store, |
|
12 |
)
|
|
13 |
from testtools.matchers import StartsWith |
|
12164.3.14
by Gavin Panella
Restrict newBugFilter() to subscriber only. |
14 |
from zope.security.interfaces import Unauthorized |
15 |
||
12541.2.3
by Gary Poster
move tests from test_structuralsubscriptiontarget.py to test_structuralsubscription.py |
16 |
from lp.bugs.enum import BugNotificationLevel |
17 |
from lp.bugs.interfaces.bugtask import ( |
|
18 |
BugTaskImportance, |
|
19 |
BugTaskStatus, |
|
20 |
)
|
|
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
21 |
from lp.bugs.mail.bugnotificationrecipients import BugNotificationRecipients |
7675.1094.3
by Graham Binns
Added mute, unmute and isMuteAllowed() methods. Bit of a code-drop. |
22 |
from lp.bugs.model.bugsubscriptionfilter import ( |
23 |
BugSubscriptionFilter, |
|
24 |
BugSubscriptionFilterMute, |
|
7675.1094.5
by Graham Binns
Added tests to cover errors when you're not allowed to mute. |
25 |
MuteNotAllowed, |
7675.1094.3
by Graham Binns
Added mute, unmute and isMuteAllowed() methods. Bit of a code-drop. |
26 |
)
|
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
27 |
from lp.bugs.model.structuralsubscription import ( |
28 |
get_structural_subscribers, |
|
29 |
get_structural_subscription_targets, |
|
13811.2.1
by Jeroen Vermeulen
Fix some of the lint people left in the past few days. |
30 |
get_structural_subscriptions_for_bug, |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
31 |
)
|
12164.3.14
by Gavin Panella
Restrict newBugFilter() to subscriber only. |
32 |
from lp.testing import ( |
33 |
anonymous_logged_in, |
|
12541.2.3
by Gary Poster
move tests from test_structuralsubscriptiontarget.py to test_structuralsubscription.py |
34 |
login_person, |
12164.3.14
by Gavin Panella
Restrict newBugFilter() to subscriber only. |
35 |
person_logged_in, |
36 |
TestCaseWithFactory, |
|
37 |
)
|
|
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
38 |
from lp.testing.factory import is_security_proxied_or_harmless |
14612.2.1
by William Grant
format-imports on lib/. So many imports. |
39 |
from lp.testing.layers import ( |
40 |
DatabaseFunctionalLayer, |
|
41 |
LaunchpadFunctionalLayer, |
|
42 |
)
|
|
11526.4.35
by Gavin Panella
Add StructuralSubscription.bug_filters. |
43 |
|
44 |
||
45 |
class TestStructuralSubscription(TestCaseWithFactory): |
|
46 |
||
12164.3.14
by Gavin Panella
Restrict newBugFilter() to subscriber only. |
47 |
layer = DatabaseFunctionalLayer |
11526.4.35
by Gavin Panella
Add StructuralSubscription.bug_filters. |
48 |
|
12164.3.15
by Gavin Panella
Refactor test_structuralsubscription. |
49 |
def setUp(self): |
50 |
super(TestStructuralSubscription, self).setUp() |
|
51 |
self.product = self.factory.makeProduct() |
|
52 |
with person_logged_in(self.product.owner): |
|
53 |
self.subscription = self.product.addSubscription( |
|
54 |
self.product.owner, self.product.owner) |
|
12399.3.1
by Danilo Segan
Automatically create an empty BugSubscriptionFilter for every StructuralSubscription. |
55 |
self.original_filter = self.subscription.bug_filters[0] |
12164.3.15
by Gavin Panella
Refactor test_structuralsubscription. |
56 |
|
7675.1030.2
by Gary Poster
make it possible to delete a structural subscription that has a filter, by adding a delete method to structural subscriptions that performs the cascading delete. |
57 |
def test_delete_requires_Edit_permission(self): |
58 |
# delete() is only available to the subscriber.
|
|
7675.1030.4
by Gary Poster
improve comments, per review |
59 |
# We use a lambda here because a security proxy around
|
60 |
# self.subscription is giving us the behavior we want to
|
|
61 |
# demonstrate. Merely accessing the "delete" name raises
|
|
62 |
# Unauthorized, before the method is even called. Therefore,
|
|
63 |
# we use a lambda to make the trigger happen within "assertRaises".
|
|
7675.1030.2
by Gary Poster
make it possible to delete a structural subscription that has a filter, by adding a delete method to structural subscriptions that performs the cascading delete. |
64 |
with anonymous_logged_in(): |
65 |
self.assertRaises(Unauthorized, lambda: self.subscription.delete) |
|
66 |
with person_logged_in(self.factory.makePerson()): |
|
67 |
self.assertRaises(Unauthorized, lambda: self.subscription.delete) |
|
68 |
||
69 |
def test_simple_delete(self): |
|
70 |
with person_logged_in(self.product.owner): |
|
71 |
self.subscription.delete() |
|
72 |
self.assertEqual( |
|
73 |
self.product.getSubscription(self.product.owner), None) |
|
74 |
||
75 |
def test_delete_cascades_to_filters(self): |
|
76 |
with person_logged_in(self.product.owner): |
|
77 |
subscription_id = self.subscription.id |
|
78 |
self.subscription.newBugFilter() |
|
79 |
self.subscription.delete() |
|
80 |
self.assertEqual( |
|
81 |
self.product.getSubscription(self.product.owner), None) |
|
82 |
store = Store.of(self.product) |
|
7675.1030.4
by Gary Poster
improve comments, per review |
83 |
# We know that the filter is gone, because we know the
|
84 |
# subscription is gone, and the database would have
|
|
85 |
# prevented the deletion of a subscription without first
|
|
86 |
# deleting the filters. We'll double-check, to be sure.
|
|
7675.1030.2
by Gary Poster
make it possible to delete a structural subscription that has a filter, by adding a delete method to structural subscriptions that performs the cascading delete. |
87 |
self.assertEqual( |
88 |
store.find( |
|
89 |
BugSubscriptionFilter, |
|
90 |
BugSubscriptionFilter.structural_subscription_id == |
|
12399.3.4
by Danilo Segan
Lint fixes. |
91 |
subscription_id).one(), |
7675.1030.2
by Gary Poster
make it possible to delete a structural subscription that has a filter, by adding a delete method to structural subscriptions that performs the cascading delete. |
92 |
None) |
93 |
||
12399.3.1
by Danilo Segan
Automatically create an empty BugSubscriptionFilter for every StructuralSubscription. |
94 |
def test_bug_filters_default(self): |
12411.3.6
by Danilo Segan
Update StructuralSubscription API test. |
95 |
# The bug_filters attribute has a default non-filtering bug filter
|
12399.3.1
by Danilo Segan
Automatically create an empty BugSubscriptionFilter for every StructuralSubscription. |
96 |
# to begin with.
|
97 |
self.assertEqual([self.original_filter], |
|
98 |
list(self.subscription.bug_filters)) |
|
11526.4.35
by Gavin Panella
Add StructuralSubscription.bug_filters. |
99 |
|
100 |
def test_bug_filters(self): |
|
12164.3.15
by Gavin Panella
Refactor test_structuralsubscription. |
101 |
# The bug_filters attribute returns the BugSubscriptionFilter records
|
102 |
# associated with this subscription.
|
|
103 |
subscription_filter = BugSubscriptionFilter() |
|
104 |
subscription_filter.structural_subscription = self.subscription |
|
12399.3.1
by Danilo Segan
Automatically create an empty BugSubscriptionFilter for every StructuralSubscription. |
105 |
self.assertContentEqual( |
106 |
[subscription_filter, self.original_filter], |
|
12164.3.15
by Gavin Panella
Refactor test_structuralsubscription. |
107 |
list(self.subscription.bug_filters)) |
11526.4.36
by Gavin Panella
Test for StructuralSubscription.newBugFilter(). |
108 |
|
109 |
def test_newBugFilter(self): |
|
12164.3.15
by Gavin Panella
Refactor test_structuralsubscription. |
110 |
# newBugFilter() creates a new subscription filter linked to the
|
111 |
# subscription.
|
|
112 |
with person_logged_in(self.product.owner): |
|
113 |
subscription_filter = self.subscription.newBugFilter() |
|
114 |
self.assertEqual( |
|
115 |
self.subscription, |
|
116 |
subscription_filter.structural_subscription) |
|
12399.3.1
by Danilo Segan
Automatically create an empty BugSubscriptionFilter for every StructuralSubscription. |
117 |
self.assertContentEqual( |
118 |
[subscription_filter, self.original_filter], |
|
12164.3.15
by Gavin Panella
Refactor test_structuralsubscription. |
119 |
list(self.subscription.bug_filters)) |
12164.3.14
by Gavin Panella
Restrict newBugFilter() to subscriber only. |
120 |
|
12164.3.15
by Gavin Panella
Refactor test_structuralsubscription. |
121 |
def test_newBugFilter_by_anonymous(self): |
122 |
# newBugFilter() is not available to anonymous users.
|
|
12164.3.14
by Gavin Panella
Restrict newBugFilter() to subscriber only. |
123 |
with anonymous_logged_in(): |
124 |
self.assertRaises( |
|
12164.3.15
by Gavin Panella
Refactor test_structuralsubscription. |
125 |
Unauthorized, lambda: self.subscription.newBugFilter) |
126 |
||
127 |
def test_newBugFilter_by_other_user(self): |
|
128 |
# newBugFilter() is only available to the subscriber.
|
|
12164.3.14
by Gavin Panella
Restrict newBugFilter() to subscriber only. |
129 |
with person_logged_in(self.factory.makePerson()): |
130 |
self.assertRaises( |
|
12164.3.15
by Gavin Panella
Refactor test_structuralsubscription. |
131 |
Unauthorized, lambda: self.subscription.newBugFilter) |
12541.2.3
by Gary Poster
move tests from test_structuralsubscriptiontarget.py to test_structuralsubscription.py |
132 |
|
133 |
||
134 |
class FilteredStructuralSubscriptionTestBase: |
|
135 |
"""Tests for filtered structural subscriptions."""
|
|
136 |
||
137 |
layer = LaunchpadFunctionalLayer |
|
138 |
||
139 |
def makeTarget(self): |
|
140 |
raise NotImplementedError(self.makeTarget) |
|
141 |
||
142 |
def makeBugTask(self): |
|
143 |
return self.factory.makeBugTask(target=self.target) |
|
144 |
||
145 |
def setUp(self): |
|
146 |
super(FilteredStructuralSubscriptionTestBase, self).setUp() |
|
147 |
self.ordinary_subscriber = self.factory.makePerson() |
|
148 |
login_person(self.ordinary_subscriber) |
|
149 |
self.target = self.makeTarget() |
|
150 |
self.bugtask = self.makeBugTask() |
|
151 |
self.bug = self.bugtask.bug |
|
152 |
self.subscription = self.target.addSubscription( |
|
153 |
self.ordinary_subscriber, self.ordinary_subscriber) |
|
154 |
self.initial_filter = self.subscription.bug_filters[0] |
|
155 |
||
156 |
def assertSubscribers( |
|
7675.1139.1
by Danilo Segan
Get rid of all NOTHING usage. |
157 |
self, expected_subscribers, level=BugNotificationLevel.LIFECYCLE): |
12541.2.3
by Gary Poster
move tests from test_structuralsubscriptiontarget.py to test_structuralsubscription.py |
158 |
observed_subscribers = list( |
159 |
get_structural_subscribers(self.bugtask, None, level)) |
|
160 |
self.assertEqual(expected_subscribers, observed_subscribers) |
|
161 |
||
162 |
def test_getStructuralSubscribers(self): |
|
163 |
# If no one has a filtered subscription for the given bug, the result
|
|
164 |
# of get_structural_subscribers() is the same as for
|
|
165 |
# the set of people from each subscription in getSubscriptions().
|
|
166 |
subscriptions = self.target.getSubscriptions() |
|
167 |
self.assertSubscribers([sub.subscriber for sub in subscriptions]) |
|
168 |
||
169 |
def test_getStructuralSubscribers_with_filter_on_status(self): |
|
170 |
# If a status filter exists for a subscription, the result of
|
|
171 |
# get_structural_subscribers() may be a subset of getSubscriptions().
|
|
172 |
||
173 |
# Without any filters the subscription is found.
|
|
174 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
175 |
||
176 |
# Filter the subscription to bugs in the CONFIRMED state.
|
|
177 |
self.initial_filter.statuses = [BugTaskStatus.CONFIRMED] |
|
178 |
||
179 |
# With the filter the subscription is not found.
|
|
180 |
self.assertSubscribers([]) |
|
181 |
||
182 |
# If the filter is adjusted, the subscription is found again.
|
|
183 |
self.initial_filter.statuses = [self.bugtask.status] |
|
184 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
185 |
||
186 |
def test_getStructuralSubscribers_with_filter_on_importance(self): |
|
187 |
# If an importance filter exists for a subscription, the result of
|
|
188 |
# get_structural_subscribers() may be a subset of getSubscriptions().
|
|
189 |
||
190 |
# Without any filters the subscription is found.
|
|
191 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
192 |
||
193 |
# Filter the subscription to bugs in the CRITICAL state.
|
|
194 |
self.initial_filter.importances = [BugTaskImportance.CRITICAL] |
|
195 |
||
196 |
# With the filter the subscription is not found.
|
|
197 |
self.assertSubscribers([]) |
|
198 |
||
199 |
# If the filter is adjusted, the subscription is found again.
|
|
200 |
self.initial_filter.importances = [self.bugtask.importance] |
|
201 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
202 |
||
203 |
def test_getStructuralSubscribers_with_filter_on_level(self): |
|
204 |
# All structural subscriptions have a level for bug notifications
|
|
205 |
# which get_structural_subscribers() observes.
|
|
206 |
||
207 |
# Adjust the subscription level to METADATA.
|
|
208 |
self.initial_filter.bug_notification_level = ( |
|
209 |
BugNotificationLevel.METADATA) |
|
210 |
||
7675.1139.1
by Danilo Segan
Get rid of all NOTHING usage. |
211 |
# The subscription is found when looking for LIFECYCLE or above.
|
12541.2.3
by Gary Poster
move tests from test_structuralsubscriptiontarget.py to test_structuralsubscription.py |
212 |
self.assertSubscribers( |
7675.1139.1
by Danilo Segan
Get rid of all NOTHING usage. |
213 |
[self.ordinary_subscriber], BugNotificationLevel.LIFECYCLE) |
12541.2.3
by Gary Poster
move tests from test_structuralsubscriptiontarget.py to test_structuralsubscription.py |
214 |
# The subscription is found when looking for METADATA or above.
|
215 |
self.assertSubscribers( |
|
216 |
[self.ordinary_subscriber], BugNotificationLevel.METADATA) |
|
217 |
# The subscription is not found when looking for COMMENTS or above.
|
|
218 |
self.assertSubscribers( |
|
219 |
[], BugNotificationLevel.COMMENTS) |
|
220 |
||
221 |
def test_getStructuralSubscribers_with_filter_include_any_tags(self): |
|
222 |
# If a subscription filter has include_any_tags, a bug with one or
|
|
223 |
# more tags is matched.
|
|
224 |
||
225 |
self.initial_filter.include_any_tags = True |
|
226 |
||
227 |
# Without any tags the subscription is not found.
|
|
228 |
self.assertSubscribers([]) |
|
229 |
||
230 |
# With any tag the subscription is found.
|
|
231 |
self.bug.tags = ["foo"] |
|
232 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
233 |
||
234 |
def test_getStructuralSubscribers_with_filter_exclude_any_tags(self): |
|
235 |
# If a subscription filter has exclude_any_tags, only bugs with no
|
|
236 |
# tags are matched.
|
|
237 |
||
238 |
self.initial_filter.exclude_any_tags = True |
|
239 |
||
240 |
# Without any tags the subscription is found.
|
|
241 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
242 |
||
243 |
# With any tag the subscription is not found.
|
|
244 |
self.bug.tags = ["foo"] |
|
245 |
self.assertSubscribers([]) |
|
246 |
||
247 |
def test_getStructuralSubscribers_with_filter_for_any_tag(self): |
|
248 |
# If a subscription filter specifies that any of one or more specific
|
|
249 |
# tags must be present, bugs with any of those tags are matched.
|
|
250 |
||
251 |
# Looking for either the "foo" or the "bar" tag.
|
|
252 |
self.initial_filter.tags = [u"foo", u"bar"] |
|
253 |
self.initial_filter.find_all_tags = False |
|
254 |
||
255 |
# Without either tag the subscription is not found.
|
|
256 |
self.assertSubscribers([]) |
|
257 |
||
258 |
# With either tag the subscription is found.
|
|
259 |
self.bug.tags = ["bar", "baz"] |
|
260 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
261 |
||
262 |
def test_getStructuralSubscribers_with_filter_for_all_tags(self): |
|
263 |
# If a subscription filter specifies that all of one or more specific
|
|
264 |
# tags must be present, bugs with all of those tags are matched.
|
|
265 |
||
266 |
# Looking for both the "foo" and the "bar" tag.
|
|
267 |
self.initial_filter.tags = [u"foo", u"bar"] |
|
268 |
self.initial_filter.find_all_tags = True |
|
269 |
||
270 |
# Without either tag the subscription is not found.
|
|
271 |
self.assertSubscribers([]) |
|
272 |
||
273 |
# Without only one of the required tags the subscription is not found.
|
|
274 |
self.bug.tags = ["foo"] |
|
275 |
self.assertSubscribers([]) |
|
276 |
||
277 |
# With both required tags the subscription is found.
|
|
278 |
self.bug.tags = ["foo", "bar"] |
|
279 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
280 |
||
281 |
def test_getStructuralSubscribers_with_filter_for_not_any_tag(self): |
|
282 |
# If a subscription filter specifies that any of one or more specific
|
|
283 |
# tags must not be present, bugs without any of those tags are
|
|
284 |
# matched.
|
|
285 |
||
286 |
# Looking to exclude the "foo" or "bar" tags.
|
|
287 |
self.initial_filter.tags = [u"-foo", u"-bar"] |
|
288 |
self.initial_filter.find_all_tags = False |
|
289 |
||
290 |
# Without either tag the subscription is found.
|
|
291 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
292 |
||
293 |
# With both tags, the subscription is omitted.
|
|
294 |
self.bug.tags = ["foo", "bar"] |
|
295 |
self.assertSubscribers([]) |
|
296 |
||
297 |
# With only one tag, the subscription is found again.
|
|
298 |
self.bug.tags = ["foo"] |
|
299 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
300 |
||
301 |
# However, if find_all_tags is True, even a single excluded tag
|
|
302 |
# causes the subscription to be skipped.
|
|
303 |
self.initial_filter.find_all_tags = True |
|
304 |
self.assertSubscribers([]) |
|
305 |
||
306 |
# This is also true, of course, if the bug has both tags.
|
|
307 |
self.bug.tags = ["foo", "bar"] |
|
308 |
self.assertSubscribers([]) |
|
309 |
||
310 |
def test_getStructuralSubscribers_with_filter_for_not_all_tags(self): |
|
311 |
# If a subscription filter specifies that all of one or more specific
|
|
312 |
# tags must not be present, bugs without all of those tags are
|
|
313 |
# matched.
|
|
314 |
||
315 |
# Looking to exclude the "foo" and "bar" tags.
|
|
316 |
self.initial_filter.tags = [u"-foo", u"-bar"] |
|
317 |
self.initial_filter.find_all_tags = True |
|
318 |
||
319 |
# Without either tag the subscription is found.
|
|
320 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
321 |
||
322 |
# With only one of the excluded tags the subscription is not
|
|
323 |
# found--we are saying that we want to find both an absence of foo
|
|
324 |
# and an absence of bar, and yet foo exists.
|
|
325 |
self.bug.tags = ["foo"] |
|
326 |
self.assertSubscribers([]) |
|
327 |
||
328 |
# With both tags the subscription is also not found.
|
|
329 |
self.bug.tags = ["foo", "bar"] |
|
330 |
self.assertSubscribers([]) |
|
331 |
||
332 |
def test_getStructuralSubscribers_with_multiple_filters(self): |
|
333 |
# If multiple filters exist for a subscription, all filters must
|
|
334 |
# match.
|
|
335 |
||
336 |
# Add the "foo" tag to the bug.
|
|
337 |
self.bug.tags = ["foo"] |
|
338 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
339 |
||
340 |
# Filter the subscription to bugs in the CRITICAL state.
|
|
341 |
self.initial_filter.statuses = [BugTaskStatus.CONFIRMED] |
|
342 |
self.initial_filter.importances = [BugTaskImportance.CRITICAL] |
|
343 |
||
344 |
# With the filter the subscription is not found.
|
|
345 |
self.assertSubscribers([]) |
|
346 |
||
347 |
# If the filter is adjusted to match status but not importance, the
|
|
348 |
# subscription is still not found.
|
|
349 |
self.initial_filter.statuses = [self.bugtask.status] |
|
350 |
self.assertSubscribers([]) |
|
351 |
||
352 |
# If the filter is adjusted to also match importance, the subscription
|
|
353 |
# is found again.
|
|
354 |
self.initial_filter.importances = [self.bugtask.importance] |
|
355 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
356 |
||
357 |
# If the filter is given some tag criteria, the subscription is not
|
|
358 |
# found.
|
|
359 |
self.initial_filter.tags = [u"-foo", u"bar", u"baz"] |
|
360 |
self.initial_filter.find_all_tags = False |
|
361 |
self.assertSubscribers([]) |
|
362 |
||
363 |
# After removing the "foo" tag and adding the "bar" tag, the
|
|
364 |
# subscription is found.
|
|
365 |
self.bug.tags = ["bar"] |
|
366 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
367 |
||
368 |
# Requiring that all tag criteria are fulfilled causes the
|
|
369 |
# subscription to no longer be found.
|
|
370 |
self.initial_filter.find_all_tags = True |
|
371 |
self.assertSubscribers([]) |
|
372 |
||
373 |
# After adding the "baz" tag, the subscription is found again.
|
|
374 |
self.bug.tags = ["bar", "baz"] |
|
375 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
376 |
||
377 |
def test_getStructuralSubscribers_any_filter_is_a_match(self): |
|
378 |
# If a subscription has multiple filters, the subscription is selected
|
|
379 |
# when any filter is found to match. Put another way, the filters are
|
|
380 |
# ORed together.
|
|
381 |
subscription_filter1 = self.initial_filter |
|
382 |
subscription_filter1.statuses = [BugTaskStatus.CONFIRMED] |
|
383 |
subscription_filter2 = self.subscription.newBugFilter() |
|
384 |
subscription_filter2.tags = [u"foo"] |
|
385 |
||
386 |
# With the filter the subscription is not found.
|
|
387 |
self.assertSubscribers([]) |
|
388 |
||
389 |
# If the bugtask is adjusted to match the criteria of the first filter
|
|
390 |
# but not those of the second, the subscription is found.
|
|
391 |
self.bugtask.transitionToStatus( |
|
392 |
BugTaskStatus.CONFIRMED, self.ordinary_subscriber) |
|
393 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
394 |
||
395 |
# If the filter is adjusted to also match the criteria of the second
|
|
396 |
# filter, the subscription is still found.
|
|
397 |
self.bugtask.bug.tags = [u"foo"] |
|
398 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
399 |
||
400 |
# If the bugtask is adjusted to no longer match the criteria of the
|
|
401 |
# first filter, the subscription is still found.
|
|
402 |
self.bugtask.transitionToStatus( |
|
403 |
BugTaskStatus.INPROGRESS, self.ordinary_subscriber) |
|
404 |
self.assertSubscribers([self.ordinary_subscriber]) |
|
405 |
||
406 |
||
407 |
class TestStructuralSubscriptionFiltersForDistro( |
|
408 |
FilteredStructuralSubscriptionTestBase, TestCaseWithFactory): |
|
409 |
||
410 |
def makeTarget(self): |
|
411 |
return self.factory.makeDistribution() |
|
412 |
||
413 |
||
414 |
class TestStructuralSubscriptionFiltersForProduct( |
|
415 |
FilteredStructuralSubscriptionTestBase, TestCaseWithFactory): |
|
416 |
||
417 |
def makeTarget(self): |
|
418 |
return self.factory.makeProduct() |
|
419 |
||
420 |
||
421 |
class TestStructuralSubscriptionFiltersForDistroSourcePackage( |
|
422 |
FilteredStructuralSubscriptionTestBase, TestCaseWithFactory): |
|
423 |
||
424 |
def makeTarget(self): |
|
425 |
return self.factory.makeDistributionSourcePackage() |
|
426 |
||
427 |
||
428 |
class TestStructuralSubscriptionFiltersForMilestone( |
|
429 |
FilteredStructuralSubscriptionTestBase, TestCaseWithFactory): |
|
430 |
||
431 |
def makeTarget(self): |
|
432 |
return self.factory.makeMilestone() |
|
433 |
||
434 |
def makeBugTask(self): |
|
435 |
bug = self.factory.makeBug(milestone=self.target) |
|
436 |
return bug.bugtasks[0] |
|
437 |
||
438 |
||
439 |
class TestStructuralSubscriptionFiltersForDistroSeries( |
|
440 |
FilteredStructuralSubscriptionTestBase, TestCaseWithFactory): |
|
441 |
||
442 |
def makeTarget(self): |
|
443 |
return self.factory.makeDistroSeries() |
|
444 |
||
445 |
||
446 |
class TestStructuralSubscriptionFiltersForProjectGroup( |
|
447 |
FilteredStructuralSubscriptionTestBase, TestCaseWithFactory): |
|
448 |
||
449 |
def makeTarget(self): |
|
450 |
return self.factory.makeProject() |
|
451 |
||
452 |
def makeBugTask(self): |
|
453 |
return self.factory.makeBugTask( |
|
454 |
target=self.factory.makeProduct(project=self.target)) |
|
455 |
||
456 |
||
457 |
class TestStructuralSubscriptionFiltersForProductSeries( |
|
458 |
FilteredStructuralSubscriptionTestBase, TestCaseWithFactory): |
|
459 |
||
460 |
def makeTarget(self): |
|
461 |
return self.factory.makeProductSeries() |
|
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
462 |
|
463 |
||
464 |
class TestGetStructuralSubscriptionTargets(TestCaseWithFactory): |
|
465 |
||
466 |
layer = DatabaseFunctionalLayer |
|
467 |
||
468 |
def test_product_target(self): |
|
469 |
product = self.factory.makeProduct() |
|
470 |
bug = self.factory.makeBug(product=product) |
|
471 |
bugtask = bug.bugtasks[0] |
|
472 |
result = get_structural_subscription_targets(bug.bugtasks) |
|
473 |
self.assertEqual(list(result), [(bugtask, product)]) |
|
474 |
||
475 |
def test_milestone_target(self): |
|
476 |
actor = self.factory.makePerson() |
|
477 |
login_person(actor) |
|
478 |
product = self.factory.makeProduct() |
|
479 |
milestone = self.factory.makeMilestone(product=product) |
|
480 |
bug = self.factory.makeBug(product=product, milestone=milestone) |
|
481 |
bugtask = bug.bugtasks[0] |
|
482 |
result = get_structural_subscription_targets(bug.bugtasks) |
|
483 |
self.assertEqual(set(result), set( |
|
484 |
((bugtask, product), (bugtask, milestone)))) |
|
485 |
||
486 |
def test_sourcepackage_target(self): |
|
487 |
actor = self.factory.makePerson() |
|
488 |
login_person(actor) |
|
489 |
distroseries = self.factory.makeDistroSeries() |
|
490 |
sourcepackage = self.factory.makeSourcePackage( |
|
13756.1.1
by William Grant
Fix tests broken by fixing tests in r13754. |
491 |
distroseries=distroseries, publish=True) |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
492 |
product = self.factory.makeProduct() |
493 |
bug = self.factory.makeBug(product=product) |
|
494 |
bug.addTask(actor, sourcepackage) |
|
495 |
product_bugtask = bug.bugtasks[0] |
|
496 |
sourcepackage_bugtask = bug.bugtasks[1] |
|
497 |
result = get_structural_subscription_targets(bug.bugtasks) |
|
498 |
self.assertEqual(set(result), set( |
|
499 |
((product_bugtask, product), |
|
500 |
(sourcepackage_bugtask, distroseries)))) |
|
501 |
||
502 |
def test_distribution_source_package_target(self): |
|
503 |
actor = self.factory.makePerson() |
|
504 |
login_person(actor) |
|
505 |
distribution = self.factory.makeDistribution() |
|
506 |
dist_sourcepackage = self.factory.makeDistributionSourcePackage( |
|
507 |
distribution=distribution) |
|
508 |
product = self.factory.makeProduct() |
|
509 |
bug = self.factory.makeBug(product=product) |
|
510 |
bug.addTask(actor, dist_sourcepackage) |
|
511 |
product_bugtask = bug.bugtasks[0] |
|
512 |
dist_sourcepackage_bugtask = bug.bugtasks[1] |
|
513 |
result = get_structural_subscription_targets(bug.bugtasks) |
|
514 |
self.assertEqual(set(result), set( |
|
515 |
((product_bugtask, product), |
|
516 |
(dist_sourcepackage_bugtask, dist_sourcepackage), |
|
517 |
(dist_sourcepackage_bugtask, distribution)))) |
|
518 |
||
13023.5.1
by Graham Binns
Added regression tests. |
519 |
def test_product_with_project_group(self): |
520 |
# get_structural_subscription_targets() will yield both a
|
|
521 |
# product and its parent project group if it has one.
|
|
522 |
project = self.factory.makeProject() |
|
523 |
product = self.factory.makeProduct( |
|
524 |
project=project, owner=project.owner) |
|
525 |
subscriber = self.factory.makePerson() |
|
526 |
with person_logged_in(subscriber): |
|
13811.2.1
by Jeroen Vermeulen
Fix some of the lint people left in the past few days. |
527 |
project.addBugSubscription(subscriber, subscriber) |
13023.5.1
by Graham Binns
Added regression tests. |
528 |
# This is a sanity check.
|
529 |
self.assertEqual(project, product.parent_subscription_target) |
|
530 |
bug = self.factory.makeBug(product=product) |
|
531 |
result = get_structural_subscription_targets(bug.bugtasks) |
|
532 |
self.assertEqual( |
|
533 |
set([(bug.bugtasks[0], product), (bug.bugtasks[0], project)]), |
|
534 |
set(result)) |
|
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
535 |
|
13811.2.1
by Jeroen Vermeulen
Fix some of the lint people left in the past few days. |
536 |
|
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
537 |
class TestGetStructuralSubscriptionsForBug(TestCaseWithFactory): |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
538 |
|
539 |
layer = DatabaseFunctionalLayer |
|
540 |
||
541 |
def setUp(self): |
|
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
542 |
super(TestGetStructuralSubscriptionsForBug, self).setUp() |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
543 |
self.subscriber = self.factory.makePerson() |
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
544 |
self.team = self.factory.makeTeam(members=[self.subscriber]) |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
545 |
login_person(self.subscriber) |
546 |
self.product = self.factory.makeProduct() |
|
547 |
self.milestone = self.factory.makeMilestone(product=self.product) |
|
548 |
self.bug = self.factory.makeBug( |
|
549 |
product=self.product, milestone=self.milestone) |
|
550 |
||
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
551 |
def getSubscriptions(self, person=None): |
552 |
result = get_structural_subscriptions_for_bug(self.bug, person) |
|
553 |
self.assertTrue(is_security_proxied_or_harmless(result)) |
|
554 |
return result |
|
555 |
||
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
556 |
def test_no_subscriptions(self): |
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
557 |
subscriptions = self.getSubscriptions(self.subscriber) |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
558 |
self.assertEqual([], list(subscriptions)) |
559 |
||
560 |
def test_one_subscription(self): |
|
561 |
sub = self.product.addBugSubscription( |
|
562 |
self.subscriber, self.subscriber) |
|
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
563 |
subscriptions = self.getSubscriptions(self.subscriber) |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
564 |
self.assertEqual([sub], list(subscriptions)) |
565 |
||
566 |
def test_two_subscriptions(self): |
|
567 |
sub1 = self.product.addBugSubscription( |
|
568 |
self.subscriber, self.subscriber) |
|
569 |
sub2 = self.milestone.addBugSubscription( |
|
570 |
self.subscriber, self.subscriber) |
|
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
571 |
subscriptions = self.getSubscriptions(self.subscriber) |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
572 |
self.assertEqual(set([sub1, sub2]), set(subscriptions)) |
573 |
||
574 |
def test_two_bugtasks_one_subscription(self): |
|
575 |
sub = self.product.addBugSubscription( |
|
576 |
self.subscriber, self.subscriber) |
|
577 |
product2 = self.factory.makeProduct() |
|
578 |
self.bug.addTask(self.subscriber, product2) |
|
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
579 |
subscriptions = self.getSubscriptions(self.subscriber) |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
580 |
self.assertEqual([sub], list(subscriptions)) |
581 |
||
582 |
def test_two_bugtasks_two_subscriptions(self): |
|
583 |
sub1 = self.product.addBugSubscription( |
|
584 |
self.subscriber, self.subscriber) |
|
585 |
product2 = self.factory.makeProduct() |
|
586 |
self.bug.addTask(self.subscriber, product2) |
|
587 |
sub2 = product2.addBugSubscription( |
|
588 |
self.subscriber, self.subscriber) |
|
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
589 |
subscriptions = self.getSubscriptions(self.subscriber) |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
590 |
self.assertEqual(set([sub1, sub2]), set(subscriptions)) |
591 |
||
592 |
def test_ignore_other_subscriptions(self): |
|
593 |
sub1 = self.product.addBugSubscription( |
|
594 |
self.subscriber, self.subscriber) |
|
595 |
another_subscriber = self.factory.makePerson() |
|
596 |
login_person(another_subscriber) |
|
597 |
sub2 = self.product.addBugSubscription( |
|
598 |
another_subscriber, another_subscriber) |
|
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
599 |
subscriptions = self.getSubscriptions(self.subscriber) |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
600 |
self.assertEqual([sub1], list(subscriptions)) |
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
601 |
subscriptions = self.getSubscriptions(another_subscriber) |
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
602 |
self.assertEqual([sub2], list(subscriptions)) |
603 |
||
12393.10.2
by Gary Poster
fix some broken code, and eliminate some redendant code. JS is still broken. |
604 |
def test_team_subscription(self): |
605 |
with person_logged_in(self.team.teamowner): |
|
606 |
sub = self.product.addBugSubscription( |
|
607 |
self.team, self.team.teamowner) |
|
608 |
subscriptions = self.getSubscriptions(self.subscriber) |
|
609 |
self.assertEqual([sub], list(subscriptions)) |
|
610 |
||
611 |
def test_both_subscriptions(self): |
|
612 |
self_sub = self.product.addBugSubscription( |
|
613 |
self.subscriber, self.subscriber) |
|
614 |
with person_logged_in(self.team.teamowner): |
|
615 |
team_sub = self.product.addBugSubscription( |
|
616 |
self.team, self.team.teamowner) |
|
617 |
subscriptions = self.getSubscriptions(self.subscriber) |
|
618 |
self.assertEqual(set([self_sub, team_sub]), set(subscriptions)) |
|
619 |
||
13023.5.1
by Graham Binns
Added regression tests. |
620 |
def test_subscriptions_from_parent(self): |
621 |
# get_structural_subscriptions_for_bug() will return any
|
|
622 |
# structural subscriptions from the parents of the targets of
|
|
623 |
# that bug.
|
|
624 |
project = self.factory.makeProject() |
|
625 |
product = self.factory.makeProduct( |
|
626 |
project=project, owner=project.owner) |
|
627 |
subscriber = self.factory.makePerson() |
|
628 |
self_sub = project.addBugSubscription(subscriber, subscriber) |
|
629 |
# This is a sanity check.
|
|
630 |
self.assertEqual(project, product.parent_subscription_target) |
|
631 |
bug = self.factory.makeBug(product=product) |
|
632 |
subscriptions = get_structural_subscriptions_for_bug( |
|
633 |
bug, subscriber) |
|
634 |
self.assertEqual(set([self_sub]), set(subscriptions)) |
|
635 |
||
12541.2.7
by Gary Poster
make remaining changes to eliminate unneccessary APIs |
636 |
|
637 |
class TestGetStructuralSubscribers(TestCaseWithFactory): |
|
638 |
||
639 |
layer = DatabaseFunctionalLayer |
|
640 |
||
641 |
def make_product_with_bug(self): |
|
642 |
product = self.factory.makeProduct() |
|
643 |
bug = self.factory.makeBug(product=product) |
|
644 |
return product, bug |
|
645 |
||
646 |
def test_getStructuralSubscribers_no_subscribers(self): |
|
647 |
# If there are no subscribers for any of the bug's targets then no
|
|
648 |
# subscribers will be returned by get_structural_subscribers().
|
|
649 |
product, bug = self.make_product_with_bug() |
|
650 |
subscribers = get_structural_subscribers(bug, None, None, None) |
|
651 |
self.assertIsInstance(subscribers, (ResultSet, EmptyResultSet)) |
|
652 |
self.assertEqual([], list(subscribers)) |
|
653 |
||
654 |
def test_getStructuralSubscribers_single_target(self): |
|
655 |
# Subscribers for any of the bug's targets are returned.
|
|
656 |
subscriber = self.factory.makePerson() |
|
657 |
login_person(subscriber) |
|
658 |
product, bug = self.make_product_with_bug() |
|
659 |
product.addBugSubscription(subscriber, subscriber) |
|
660 |
self.assertEqual( |
|
661 |
[subscriber], list( |
|
662 |
get_structural_subscribers(bug, None, None, None))) |
|
663 |
||
664 |
def test_getStructuralSubscribers_multiple_targets(self): |
|
665 |
# Subscribers for any of the bug's targets are returned.
|
|
666 |
actor = self.factory.makePerson() |
|
667 |
login_person(actor) |
|
668 |
||
669 |
subscriber1 = self.factory.makePerson() |
|
670 |
subscriber2 = self.factory.makePerson() |
|
671 |
||
672 |
product1 = self.factory.makeProduct(owner=actor) |
|
673 |
product1.addBugSubscription(subscriber1, subscriber1) |
|
674 |
product2 = self.factory.makeProduct(owner=actor) |
|
675 |
product2.addBugSubscription(subscriber2, subscriber2) |
|
676 |
||
677 |
bug = self.factory.makeBug(product=product1) |
|
678 |
bug.addTask(actor, product2) |
|
679 |
||
680 |
subscribers = get_structural_subscribers(bug, None, None, None) |
|
681 |
self.assertIsInstance(subscribers, ResultSet) |
|
682 |
self.assertEqual(set([subscriber1, subscriber2]), set(subscribers)) |
|
683 |
||
684 |
def test_getStructuralSubscribers_recipients(self): |
|
685 |
# If provided, get_structural_subscribers() calls the appropriate
|
|
686 |
# methods on a BugNotificationRecipients object.
|
|
687 |
subscriber = self.factory.makePerson() |
|
688 |
login_person(subscriber) |
|
689 |
product, bug = self.make_product_with_bug() |
|
690 |
product.addBugSubscription(subscriber, subscriber) |
|
691 |
recipients = BugNotificationRecipients() |
|
692 |
subscribers = get_structural_subscribers(bug, recipients, None, None) |
|
693 |
# The return value is a list only when populating recipients.
|
|
694 |
self.assertIsInstance(subscribers, list) |
|
695 |
self.assertEqual([subscriber], recipients.getRecipients()) |
|
696 |
reason, header = recipients.getReason(subscriber) |
|
697 |
self.assertThat( |
|
698 |
reason, StartsWith( |
|
699 |
u"You received this bug notification because " |
|
700 |
u"you are subscribed to ")) |
|
701 |
self.assertThat(header, StartsWith(u"Subscriber ")) |
|
702 |
||
703 |
def test_getStructuralSubscribers_level(self): |
|
704 |
# get_structural_subscribers() respects the given level.
|
|
705 |
subscriber = self.factory.makePerson() |
|
706 |
login_person(subscriber) |
|
707 |
product, bug = self.make_product_with_bug() |
|
708 |
subscription = product.addBugSubscription(subscriber, subscriber) |
|
709 |
filter = subscription.bug_filters.one() |
|
710 |
filter.bug_notification_level = BugNotificationLevel.METADATA |
|
711 |
self.assertEqual( |
|
712 |
[subscriber], list( |
|
713 |
get_structural_subscribers( |
|
714 |
bug, None, BugNotificationLevel.METADATA, None))) |
|
715 |
filter.bug_notification_level = BugNotificationLevel.METADATA |
|
716 |
self.assertEqual( |
|
717 |
[], list( |
|
718 |
get_structural_subscribers( |
|
719 |
bug, None, BugNotificationLevel.COMMENTS, None))) |
|
7675.1094.3
by Graham Binns
Added mute, unmute and isMuteAllowed() methods. Bit of a code-drop. |
720 |
|
721 |
||
722 |
class TestBugSubscriptionFilterMute(TestCaseWithFactory): |
|
723 |
"""Tests for the BugSubscriptionFilterMute class."""
|
|
724 |
||
725 |
layer = DatabaseFunctionalLayer |
|
726 |
||
727 |
def setUp(self): |
|
728 |
super(TestBugSubscriptionFilterMute, self).setUp() |
|
729 |
self.target = self.factory.makeProduct() |
|
730 |
self.team = self.factory.makeTeam() |
|
731 |
self.team_member = self.factory.makePerson() |
|
732 |
with person_logged_in(self.team.teamowner): |
|
733 |
self.team.addMember(self.team_member, self.team.teamowner) |
|
734 |
self.team_subscription = self.target.addBugSubscription( |
|
735 |
self.team, self.team.teamowner) |
|
736 |
self.filter = self.team_subscription.bug_filters.one() |
|
737 |
||
738 |
def test_isMuteAllowed_returns_true_for_team_subscriptions(self): |
|
739 |
# BugSubscriptionFilter.isMuteAllowed() will return True for
|
|
740 |
# subscriptions where the owner of the subscription is a team.
|
|
7675.1094.5
by Graham Binns
Added tests to cover errors when you're not allowed to mute. |
741 |
self.assertTrue(self.filter.isMuteAllowed(self.team_member)) |
7675.1094.3
by Graham Binns
Added mute, unmute and isMuteAllowed() methods. Bit of a code-drop. |
742 |
|
743 |
def test_isMuteAllowed_returns_false_for_non_team_subscriptions(self): |
|
744 |
# BugSubscriptionFilter.isMuteAllowed() will return False for
|
|
745 |
# subscriptions where the owner of the subscription is not a team.
|
|
746 |
person = self.factory.makePerson() |
|
747 |
with person_logged_in(person): |
|
748 |
non_team_subscription = self.target.addBugSubscription( |
|
749 |
person, person) |
|
750 |
filter = non_team_subscription.bug_filters.one() |
|
7675.1094.5
by Graham Binns
Added tests to cover errors when you're not allowed to mute. |
751 |
self.assertFalse(filter.isMuteAllowed(person)) |
752 |
||
753 |
def test_isMuteAllowed_returns_false_for_non_team_members(self): |
|
754 |
# BugSubscriptionFilter.isMuteAllowed() will return False if the
|
|
755 |
# user passed to it is not a member of the subscribing team.
|
|
756 |
non_team_person = self.factory.makePerson() |
|
757 |
self.assertFalse(self.filter.isMuteAllowed(non_team_person)) |
|
7675.1094.3
by Graham Binns
Added mute, unmute and isMuteAllowed() methods. Bit of a code-drop. |
758 |
|
759 |
def test_mute_adds_mute(self): |
|
760 |
# BugSubscriptionFilter.mute() adds a mute for the filter.
|
|
761 |
filter_id = self.filter.id |
|
762 |
person_id = self.team_member.id |
|
763 |
store = Store.of(self.filter) |
|
764 |
mutes = store.find( |
|
765 |
BugSubscriptionFilterMute, |
|
766 |
BugSubscriptionFilterMute.filter == filter_id, |
|
767 |
BugSubscriptionFilterMute.person == person_id) |
|
768 |
self.assertTrue(mutes.is_empty()) |
|
7675.1096.4
by Gary Poster
add UI to mute and unmute structural subsscriptions per person |
769 |
self.assertFalse(self.filter.muted(self.team_member)) |
7675.1094.3
by Graham Binns
Added mute, unmute and isMuteAllowed() methods. Bit of a code-drop. |
770 |
self.filter.mute(self.team_member) |
7675.1096.4
by Gary Poster
add UI to mute and unmute structural subsscriptions per person |
771 |
self.assertTrue(self.filter.muted(self.team_member)) |
7675.1094.3
by Graham Binns
Added mute, unmute and isMuteAllowed() methods. Bit of a code-drop. |
772 |
store.flush() |
7675.1096.3
by Gary Poster
add more server side changes needed for UI |
773 |
self.assertFalse(mutes.is_empty()) |
7675.1094.3
by Graham Binns
Added mute, unmute and isMuteAllowed() methods. Bit of a code-drop. |
774 |
|
775 |
def test_unmute_removes_mute(self): |
|
776 |
# BugSubscriptionFilter.unmute() removes any mute for a given
|
|
777 |
# person on that filter.
|
|
778 |
filter_id = self.filter.id |
|
779 |
person_id = self.team_member.id |
|
780 |
store = Store.of(self.filter) |
|
781 |
self.filter.mute(self.team_member) |
|
782 |
store.flush() |
|
783 |
mutes = store.find( |
|
784 |
BugSubscriptionFilterMute, |
|
785 |
BugSubscriptionFilterMute.filter == filter_id, |
|
786 |
BugSubscriptionFilterMute.person == person_id) |
|
787 |
self.assertFalse(mutes.is_empty()) |
|
7675.1096.4
by Gary Poster
add UI to mute and unmute structural subsscriptions per person |
788 |
self.assertTrue(self.filter.muted(self.team_member)) |
7675.1094.3
by Graham Binns
Added mute, unmute and isMuteAllowed() methods. Bit of a code-drop. |
789 |
self.filter.unmute(self.team_member) |
7675.1096.4
by Gary Poster
add UI to mute and unmute structural subsscriptions per person |
790 |
self.assertFalse(self.filter.muted(self.team_member)) |
7675.1094.3
by Graham Binns
Added mute, unmute and isMuteAllowed() methods. Bit of a code-drop. |
791 |
store.flush() |
792 |
self.assertTrue(mutes.is_empty()) |
|
7675.1094.4
by Graham Binns
Added tests for idempotence. |
793 |
|
794 |
def test_mute_is_idempotent(self): |
|
795 |
# Muting works even if the user is already muted.
|
|
796 |
store = Store.of(self.filter) |
|
797 |
mute = self.filter.mute(self.team_member) |
|
798 |
store.flush() |
|
799 |
second_mute = self.filter.mute(self.team_member) |
|
800 |
self.assertEqual(mute, second_mute) |
|
801 |
||
802 |
def test_unmute_is_idempotent(self): |
|
803 |
# Unmuting works even if the user is not muted
|
|
804 |
store = Store.of(self.filter) |
|
805 |
mutes = store.find( |
|
806 |
BugSubscriptionFilterMute, |
|
807 |
BugSubscriptionFilterMute.filter == self.filter.id, |
|
808 |
BugSubscriptionFilterMute.person == self.team_member.id) |
|
809 |
self.assertTrue(mutes.is_empty()) |
|
810 |
self.filter.unmute(self.team_member) |
|
811 |
self.assertTrue(mutes.is_empty()) |
|
7675.1094.5
by Graham Binns
Added tests to cover errors when you're not allowed to mute. |
812 |
|
813 |
def test_mute_raises_error_for_non_team_subscriptions(self): |
|
814 |
# BugSubscriptionFilter.mute() will raise an error if called on
|
|
815 |
# a non-team subscription.
|
|
816 |
person = self.factory.makePerson() |
|
817 |
with person_logged_in(person): |
|
818 |
non_team_subscription = self.target.addBugSubscription( |
|
819 |
person, person) |
|
820 |
filter = non_team_subscription.bug_filters.one() |
|
821 |
self.assertFalse(filter.isMuteAllowed(person)) |
|
822 |
self.assertRaises(MuteNotAllowed, filter.mute, person) |
|
823 |
||
824 |
def test_mute_raises_error_for_non_team_members(self): |
|
825 |
# BugSubscriptionFilter.mute() will raise an error if called on
|
|
826 |
# a subscription of which the calling person is not a member.
|
|
827 |
non_team_person = self.factory.makePerson() |
|
828 |
self.assertFalse(self.filter.isMuteAllowed(non_team_person)) |
|
829 |
self.assertRaises(MuteNotAllowed, self.filter.mute, non_team_person) |