Merge ~cjwatson/launchpad:remove-test-event-listener into launchpad:master
- Git
- lp:~cjwatson/launchpad
- remove-test-event-listener
- Merge into master
Proposed by
Colin Watson
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | 73b39993ef5529ab878950a21b78e8fb65f99472 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:remove-test-event-listener |
Merge into: | launchpad:master |
Diff against target: |
688 lines (+113/-155) 18 files modified
dev/null (+0/-41) lib/lp/answers/browser/tests/views.txt (+5/-4) lib/lp/answers/doc/workflow.txt (+13/-10) lib/lp/answers/tests/test_question_workflow.py (+13/-15) lib/lp/bugs/browser/tests/bug-views.txt (+8/-6) lib/lp/bugs/browser/tests/buglinktarget-views.txt (+6/-5) lib/lp/bugs/browser/tests/bugtask-adding-views.txt (+5/-4) lib/lp/bugs/doc/bugattachments.txt (+5/-4) lib/lp/bugs/doc/bugwatch.txt (+5/-4) lib/lp/bugs/doc/malone-xmlrpc.txt (+5/-4) lib/lp/bugs/tests/buglinktarget.txt (+11/-9) lib/lp/bugs/tests/bugs-emailinterface.txt (+9/-7) lib/lp/code/model/tests/test_codereviewkarma.py (+3/-18) lib/lp/registry/doc/milestone.txt (+5/-4) lib/lp/registry/doc/person.txt (+5/-4) lib/lp/registry/tests/test_product.py (+3/-8) lib/lp/testing/fixture.py (+5/-4) lib/lp/testing/karma.py (+7/-4) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tom Wardill (community) | Approve | ||
Review via email:
|
Commit message
Replace TestEventListener with ZopeEventHandle
Description of the change
After adding optional support to ZopeEventHandle
required interfaces, it becomes a superset of the old TestEventListener,
with two clear advantages: it can unregister event handlers on cleanup,
and it uses the fixture pattern which is much more common for this sort
of thing nowadays. Convert all users of TestEventListener to
ZopeEventHandle
(This is very slightly more verbose in doctests because we have to call
the fixture's setUp method separately; but this is minor, and in
exchange self.useFixture makes it less verbose in tests using
testtools.)
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Tom Wardill (twom) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/answers/browser/tests/views.txt b/lib/lp/answers/browser/tests/views.txt |
2 | index 975bb8f..b8cf752 100644 |
3 | --- a/lib/lp/answers/browser/tests/views.txt |
4 | +++ b/lib/lp/answers/browser/tests/views.txt |
5 | @@ -30,13 +30,14 @@ Register an event listener that will print events it receives. |
6 | |
7 | >>> from lazr.lifecycle.interfaces import IObjectModifiedEvent |
8 | >>> from lp.answers.interfaces.question import IQuestion |
9 | - >>> from lp.testing.event import TestEventListener |
10 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
11 | |
12 | >>> def print_modified_event(object, event): |
13 | ... print("Received ObjectModifiedEvent: %s" % ( |
14 | ... ", ".join(sorted(event.edited_fields)))) |
15 | - >>> question_event_listener = TestEventListener( |
16 | - ... IQuestion, IObjectModifiedEvent, print_modified_event) |
17 | + >>> question_event_listener = ZopeEventHandlerFixture( |
18 | + ... print_modified_event, (IQuestion, IObjectModifiedEvent)) |
19 | + >>> question_event_listener.setUp() |
20 | |
21 | >>> view = create_initialized_view(question_three, name='+subscribe') |
22 | >>> print(view.label) |
23 | @@ -82,7 +83,7 @@ Unsubscription works in a similar manner. |
24 | >>> view.request.response.getHeader('Location') |
25 | '.../+question/3' |
26 | |
27 | - >>> question_event_listener.unregister() |
28 | + >>> question_event_listener.cleanUp() |
29 | |
30 | |
31 | QuestionWorkflowView |
32 | diff --git a/lib/lp/answers/doc/workflow.txt b/lib/lp/answers/doc/workflow.txt |
33 | index bdb5841..3cabebb 100644 |
34 | --- a/lib/lp/answers/doc/workflow.txt |
35 | +++ b/lib/lp/answers/doc/workflow.txt |
36 | @@ -604,17 +604,19 @@ the message they create and a ObjectModifiedEvent for the question. |
37 | # Register an event listener that will print events it receives. |
38 | >>> from lazr.lifecycle.interfaces import ( |
39 | ... IObjectCreatedEvent, IObjectModifiedEvent) |
40 | - >>> from lp.testing.event import TestEventListener |
41 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
42 | >>> from lp.answers.interfaces.question import IQuestion |
43 | |
44 | >>> def print_event(object, event): |
45 | ... print("Received %s on %s" % ( |
46 | ... event.__class__.__name__.split('.')[-1], |
47 | ... object.__class__.__name__.split('.')[-1])) |
48 | - >>> questionmessage_event_listener = TestEventListener( |
49 | - ... IQuestionMessage, IObjectCreatedEvent, print_event) |
50 | - >>> question_event_listener = TestEventListener( |
51 | - ... IQuestion, IObjectModifiedEvent, print_event) |
52 | + >>> questionmessage_event_listener = ZopeEventHandlerFixture( |
53 | + ... print_event, (IQuestionMessage, IObjectCreatedEvent)) |
54 | + >>> questionmessage_event_listener.setUp() |
55 | + >>> question_event_listener = ZopeEventHandlerFixture( |
56 | + ... print_event, (IQuestion, IObjectModifiedEvent)) |
57 | + >>> question_event_listener.setUp() |
58 | |
59 | Changing the status triggers the event. |
60 | |
61 | @@ -639,8 +641,8 @@ these events. |
62 | Received ObjectModifiedEvent on Question |
63 | |
64 | # Cleanup |
65 | - >>> questionmessage_event_listener.unregister() |
66 | - >>> question_event_listener.unregister() |
67 | + >>> questionmessage_event_listener.cleanUp() |
68 | + >>> question_event_listener.cleanUp() |
69 | |
70 | |
71 | Reopening the question |
72 | @@ -652,8 +654,9 @@ is reopened, a QuestionReopening is created. |
73 | # Register an event listener to notify us whenever a QuestionReopening is |
74 | # created. |
75 | >>> from lp.answers.interfaces.questionreopening import IQuestionReopening |
76 | - >>> reopening_event_listener = TestEventListener( |
77 | - ... IQuestionReopening, IObjectCreatedEvent, print_event) |
78 | + >>> reopening_event_listener = ZopeEventHandlerFixture( |
79 | + ... print_event, (IQuestionReopening, IObjectCreatedEvent)) |
80 | + >>> reopening_event_listener.setUp() |
81 | |
82 | The most common use case is when a user confirms a solution, and then |
83 | comes back to say that it doesn't, in fact, work. |
84 | @@ -732,7 +735,7 @@ having been rejected. |
85 | INVALID |
86 | |
87 | # Cleanup |
88 | - >>> reopening_event_listener.unregister() |
89 | + >>> reopening_event_listener.cleanUp() |
90 | |
91 | |
92 | Using an IMessage as an explanation |
93 | diff --git a/lib/lp/answers/tests/test_question_workflow.py b/lib/lp/answers/tests/test_question_workflow.py |
94 | index d2af2e1..6450d61 100644 |
95 | --- a/lib/lp/answers/tests/test_question_workflow.py |
96 | +++ b/lib/lp/answers/tests/test_question_workflow.py |
97 | @@ -20,7 +20,6 @@ from datetime import ( |
98 | timedelta, |
99 | ) |
100 | import traceback |
101 | -import unittest |
102 | |
103 | from lazr.lifecycle.interfaces import ( |
104 | IObjectCreatedEvent, |
105 | @@ -54,12 +53,13 @@ from lp.testing import ( |
106 | ANONYMOUS, |
107 | login, |
108 | login_person, |
109 | + TestCase, |
110 | ) |
111 | -from lp.testing.event import TestEventListener |
112 | +from lp.testing.fixture import ZopeEventHandlerFixture |
113 | from lp.testing.layers import DatabaseFunctionalLayer |
114 | |
115 | |
116 | -class BaseAnswerTrackerWorkflowTestCase(unittest.TestCase): |
117 | +class BaseAnswerTrackerWorkflowTestCase(TestCase): |
118 | """Base class for test cases related to the Answer Tracker workflow. |
119 | |
120 | It provides the common fixture and test helper methods. |
121 | @@ -68,6 +68,8 @@ class BaseAnswerTrackerWorkflowTestCase(unittest.TestCase): |
122 | layer = DatabaseFunctionalLayer |
123 | |
124 | def setUp(self): |
125 | + super(BaseAnswerTrackerWorkflowTestCase, self).setUp() |
126 | + |
127 | self.now = datetime.now(UTC) |
128 | |
129 | # Login as the question owner. |
130 | @@ -90,10 +92,7 @@ class BaseAnswerTrackerWorkflowTestCase(unittest.TestCase): |
131 | self.owner, 'Help!', 'I need help with Ubuntu', |
132 | datecreated=self.now) |
133 | |
134 | - def tearDown(self): |
135 | - if hasattr(self, 'created_event_listener'): |
136 | - self.created_event_listener.unregister() |
137 | - self.modified_event_listener.unregister() |
138 | + self.registered_event_listeners = False |
139 | |
140 | def setQuestionStatus(self, question, new_status, |
141 | comment="Status change."): |
142 | @@ -110,13 +109,12 @@ class BaseAnswerTrackerWorkflowTestCase(unittest.TestCase): |
143 | def setUpEventListeners(self): |
144 | """Install a listener for events emitted during the test.""" |
145 | self.collected_events = [] |
146 | - if hasattr(self, 'modified_event_listener'): |
147 | - # Event listeners is already registered. |
148 | - return |
149 | - self.modified_event_listener = TestEventListener( |
150 | - IQuestion, IObjectModifiedEvent, self.collectEvent) |
151 | - self.created_event_listener = TestEventListener( |
152 | - IQuestionMessage, IObjectCreatedEvent, self.collectEvent) |
153 | + if not self.registered_event_listeners: |
154 | + self.useFixture(ZopeEventHandlerFixture( |
155 | + self.collectEvent, (IQuestion, IObjectModifiedEvent))) |
156 | + self.useFixture(ZopeEventHandlerFixture( |
157 | + self.collectEvent, (IQuestionMessage, IObjectCreatedEvent))) |
158 | + self.registered_event_listeners = True |
159 | |
160 | def collectEvent(self, object, event): |
161 | """Collect events""" |
162 | @@ -518,7 +516,7 @@ class LinkFAQTestCase(BaseAnswerTrackerWorkflowTestCase): |
163 | |
164 | def setUp(self): |
165 | """Create an additional FAQ.""" |
166 | - BaseAnswerTrackerWorkflowTestCase.setUp(self) |
167 | + super(LinkFAQTestCase, self).setUp() |
168 | |
169 | # Only admin can create FAQ on ubuntu. |
170 | login_person(self.admin) |
171 | diff --git a/lib/lp/bugs/browser/tests/bug-views.txt b/lib/lp/bugs/browser/tests/bug-views.txt |
172 | index fb41886..2e89e54 100644 |
173 | --- a/lib/lp/bugs/browser/tests/bug-views.txt |
174 | +++ b/lib/lp/bugs/browser/tests/bug-views.txt |
175 | @@ -8,16 +8,18 @@ There are three objects on which you can file a bug. An |
176 | ObjectCreatedEvent is published when the bug is filed. Let's register |
177 | an event listener to demonstrate this. |
178 | |
179 | - >>> from lp.services.database.sqlbase import flush_database_updates |
180 | + >>> from lazr.lifecycle.event import IObjectCreatedEvent |
181 | >>> import transaction |
182 | |
183 | - >>> from lp.testing.event import TestEventListener |
184 | - >>> from lazr.lifecycle.event import IObjectCreatedEvent |
185 | >>> from lp.bugs.interfaces.bug import IBug |
186 | + >>> from lp.services.database.sqlbase import flush_database_updates |
187 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
188 | + |
189 | >>> def on_created_event(object, event): |
190 | ... print("ObjectCreatedEvent: %r" % object) |
191 | - >>> on_created_listener = TestEventListener( |
192 | - ... IBug, IObjectCreatedEvent, on_created_event) |
193 | + >>> on_created_listener = ZopeEventHandlerFixture( |
194 | + ... on_created_event, (IBug, IObjectCreatedEvent)) |
195 | + >>> on_created_listener.setUp() |
196 | |
197 | 1. Filing a bug on a distribution. |
198 | |
199 | @@ -210,7 +212,7 @@ indentical to the second, we really only display one comment: |
200 | |
201 | (Unregister our listener, since we no longer need it.) |
202 | |
203 | - >>> on_created_listener.unregister() |
204 | + >>> on_created_listener.cleanUp() |
205 | |
206 | |
207 | Bug Portlets |
208 | diff --git a/lib/lp/bugs/browser/tests/buglinktarget-views.txt b/lib/lp/bugs/browser/tests/buglinktarget-views.txt |
209 | index 99fd6a2..86e5baf 100644 |
210 | --- a/lib/lp/bugs/browser/tests/buglinktarget-views.txt |
211 | +++ b/lib/lp/bugs/browser/tests/buglinktarget-views.txt |
212 | @@ -13,11 +13,12 @@ The +linkbug and +unlinkbug views operates on IBugLinkTarget. |
213 | >>> cve = getUtility(ICveSet)['2005-2730'] |
214 | |
215 | (Setup an event listener.) |
216 | - >>> from lp.testing.event import TestEventListener |
217 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
218 | >>> collected_events = [] |
219 | - >>> modified_listener = TestEventListener( |
220 | - ... IBugLinkTarget, ObjectModifiedEvent, |
221 | - ... lambda object, event: collected_events.append(event)) |
222 | + >>> modified_listener = ZopeEventHandlerFixture( |
223 | + ... lambda object, event: collected_events.append(event), |
224 | + ... (IBugLinkTarget, ObjectModifiedEvent)) |
225 | + >>> modified_listener.setUp() |
226 | |
227 | (Login because bug link management is only available to registered users.) |
228 | >>> login('no-priv@canonical.com') |
229 | @@ -151,4 +152,4 @@ The notification contains the escaped bug title. |
230 | == Cleanup == |
231 | |
232 | (Deactivate the event listener.) |
233 | - >>> modified_listener.unregister() |
234 | + >>> modified_listener.cleanUp() |
235 | diff --git a/lib/lp/bugs/browser/tests/bugtask-adding-views.txt b/lib/lp/bugs/browser/tests/bugtask-adding-views.txt |
236 | index f1d3c87..b0200e2 100644 |
237 | --- a/lib/lp/bugs/browser/tests/bugtask-adding-views.txt |
238 | +++ b/lib/lp/bugs/browser/tests/bugtask-adding-views.txt |
239 | @@ -171,14 +171,15 @@ In order to show that all the events get fired off, let's create an |
240 | event listener and register it: |
241 | |
242 | >>> from zope.interface import Interface |
243 | - >>> from lp.testing.event import TestEventListener |
244 | >>> from lazr.lifecycle.interfaces import IObjectCreatedEvent |
245 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
246 | |
247 | >>> def on_created_event(object, event): |
248 | ... print("ObjectCreatedEvent: %r" % object) |
249 | |
250 | - >>> on_created_listener = TestEventListener( |
251 | - ... Interface, IObjectCreatedEvent, on_created_event) |
252 | + >>> on_created_listener = ZopeEventHandlerFixture( |
253 | + ... on_created_event, (Interface, IObjectCreatedEvent)) |
254 | + >>> on_created_listener.setUp() |
255 | |
256 | |
257 | If an invalid product is specified, or a product that fails the |
258 | @@ -449,7 +450,7 @@ package will be converted to the corresponding source package. |
259 | ... |
260 | mozilla-firefox (Ubuntu) |
261 | |
262 | - >>> on_created_listener.unregister() |
263 | + >>> on_created_listener.cleanUp() |
264 | |
265 | |
266 | Registering a product while adding a bugtask |
267 | diff --git a/lib/lp/bugs/doc/bugattachments.txt b/lib/lp/bugs/doc/bugattachments.txt |
268 | index 4788804..bbd23bd 100644 |
269 | --- a/lib/lp/bugs/doc/bugattachments.txt |
270 | +++ b/lib/lp/bugs/doc/bugattachments.txt |
271 | @@ -28,12 +28,13 @@ ObjectCreatedEvent in order to trigger email notifications: |
272 | |
273 | >>> from io import BytesIO |
274 | |
275 | - >>> from lp.testing.event import TestEventListener |
276 | >>> from lazr.lifecycle.event import IObjectCreatedEvent |
277 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
278 | >>> def attachment_added(attachment, event): |
279 | ... print("Attachment added: %r" % attachment.libraryfile.filename) |
280 | - >>> event_listener = TestEventListener( |
281 | - ... IBugAttachment, IObjectCreatedEvent, attachment_added) |
282 | + >>> event_listener = ZopeEventHandlerFixture( |
283 | + ... attachment_added, (IBugAttachment, IObjectCreatedEvent)) |
284 | + >>> event_listener.setUp() |
285 | |
286 | >>> filecontent = b"Some useful information." |
287 | >>> data = BytesIO(filecontent) |
288 | @@ -293,7 +294,7 @@ from the librarian. |
289 | 'http://.../foo-bar-baz' |
290 | |
291 | >>> config_data = config.pop('max_attachment_size') |
292 | - >>> event_listener.unregister() |
293 | + >>> event_listener.cleanUp() |
294 | |
295 | |
296 | Security |
297 | diff --git a/lib/lp/bugs/doc/bugwatch.txt b/lib/lp/bugs/doc/bugwatch.txt |
298 | index 7dba686..c280375 100644 |
299 | --- a/lib/lp/bugs/doc/bugwatch.txt |
300 | +++ b/lib/lp/bugs/doc/bugwatch.txt |
301 | @@ -263,11 +263,12 @@ we can confirm that an event is indeed fired off. |
302 | ... if bugtask.importance != old_bugtask.importance: |
303 | ... print("%s => %s" % (old_bugtask.importance.title, |
304 | ... bugtask.importance.title)) |
305 | - >>> from lp.testing.event import TestEventListener |
306 | >>> from lazr.lifecycle.interfaces import IObjectModifiedEvent |
307 | >>> from lp.bugs.interfaces.bugtask import IBugTask |
308 | - >>> event_listener = TestEventListener( |
309 | - ... IBugTask, IObjectModifiedEvent, print_bugtask_modified) |
310 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
311 | + >>> event_listener = ZopeEventHandlerFixture( |
312 | + ... print_bugtask_modified, (IBugTask, IObjectModifiedEvent)) |
313 | + >>> event_listener.setUp() |
314 | |
315 | If we pass in a different Malone status than the existing one, an event |
316 | will be fired off, even though the remote status stays the same. |
317 | @@ -391,7 +392,7 @@ manner: |
318 | ** Changed in: mozilla-firefox (Debian) |
319 | Importance: Low => Critical |
320 | |
321 | - >>> event_listener.unregister() |
322 | + >>> event_listener.cleanUp() |
323 | |
324 | The Bug Watch Updater can transition a bug to any status or importance: |
325 | |
326 | diff --git a/lib/lp/bugs/doc/malone-xmlrpc.txt b/lib/lp/bugs/doc/malone-xmlrpc.txt |
327 | index 78a0ddb..1d4ace3 100644 |
328 | --- a/lib/lp/bugs/doc/malone-xmlrpc.txt |
329 | +++ b/lib/lp/bugs/doc/malone-xmlrpc.txt |
330 | @@ -49,15 +49,16 @@ First, let's define a simple event listener to show that the |
331 | IObjectCreatedEvent is being published when a bug is reported through |
332 | the XML-RPC interface. |
333 | |
334 | - >>> from lp.testing.event import TestEventListener |
335 | >>> from lazr.lifecycle.interfaces import IObjectCreatedEvent |
336 | >>> from lp.bugs.interfaces.bug import IBug |
337 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
338 | |
339 | >>> def on_created_event(obj, event): |
340 | ... print("ObjectCreatedEvent: %r" % obj) |
341 | |
342 | - >>> on_created_listener = TestEventListener( |
343 | - ... IBug, IObjectCreatedEvent, on_created_event) |
344 | + >>> on_created_listener = ZopeEventHandlerFixture( |
345 | + ... on_created_event, (IBug, IObjectCreatedEvent)) |
346 | + >>> on_created_listener.setUp() |
347 | |
348 | Reporting a product bug. |
349 | |
350 | @@ -228,7 +229,7 @@ Invalid subscriber. |
351 | Fault: <Fault 20: 'Invalid subscriber: No user with the email address |
352 | "nosuch@subscriber.com" was found'> |
353 | |
354 | - >>> on_created_listener.unregister() |
355 | + >>> on_created_listener.cleanUp() |
356 | |
357 | |
358 | Generating bugtracker authentication tokens |
359 | diff --git a/lib/lp/bugs/tests/buglinktarget.txt b/lib/lp/bugs/tests/buglinktarget.txt |
360 | index 733d8c1..556b67c 100644 |
361 | --- a/lib/lp/bugs/tests/buglinktarget.txt |
362 | +++ b/lib/lp/bugs/tests/buglinktarget.txt |
363 | @@ -46,11 +46,12 @@ fired. |
364 | >>> from zope.interface import Interface |
365 | >>> from lp.bugs.interfaces.buglink import ( |
366 | ... IObjectLinkedEvent, IObjectUnlinkedEvent) |
367 | - >>> from lp.testing.event import TestEventListener |
368 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
369 | >>> linked_events = [] |
370 | - >>> linked_event_listener = TestEventListener( |
371 | - ... Interface, IObjectLinkedEvent, |
372 | - ... lambda object, event: linked_events.append(event)) |
373 | + >>> linked_event_listener = ZopeEventHandlerFixture( |
374 | + ... lambda object, event: linked_events.append(event), |
375 | + ... (Interface, IObjectLinkedEvent)) |
376 | + >>> linked_event_listener.setUp() |
377 | |
378 | >>> bug2 = bugset.get(2) |
379 | >>> target.linkBug(bugset.get(2)) |
380 | @@ -125,9 +126,10 @@ The method returns whether the link existed. It should also send an |
381 | IObjectUnlinkedEvent for each of the removed link: |
382 | |
383 | >>> unlinked_events = [] |
384 | - >>> unlinked_event_listener = TestEventListener( |
385 | - ... Interface, IObjectUnlinkedEvent, |
386 | - ... lambda object, event: unlinked_events.append(event)) |
387 | + >>> unlinked_event_listener = ZopeEventHandlerFixture( |
388 | + ... lambda object, event: unlinked_events.append(event), |
389 | + ... (Interface, IObjectUnlinkedEvent)) |
390 | + >>> unlinked_event_listener.setUp() |
391 | |
392 | >>> target.unlinkBug(bug1, factory.makePerson()) |
393 | True |
394 | @@ -167,5 +169,5 @@ the bug or if they are an administrator. |
395 | == Cleanup == |
396 | |
397 | # Unregister event listeners. |
398 | - >>> linked_event_listener.unregister() |
399 | - >>> unlinked_event_listener.unregister() |
400 | + >>> linked_event_listener.cleanUp() |
401 | + >>> unlinked_event_listener.cleanUp() |
402 | diff --git a/lib/lp/bugs/tests/bugs-emailinterface.txt b/lib/lp/bugs/tests/bugs-emailinterface.txt |
403 | index ab8fd0d..2bc5460 100644 |
404 | --- a/lib/lp/bugs/tests/bugs-emailinterface.txt |
405 | +++ b/lib/lp/bugs/tests/bugs-emailinterface.txt |
406 | @@ -1600,12 +1600,14 @@ An email can contain multiple commands, even for different bugs. |
407 | ... bugtask.importance.title)) |
408 | >>> from lazr.lifecycle.interfaces import ( |
409 | ... IObjectCreatedEvent, IObjectModifiedEvent) |
410 | - >>> from lp.testing.event import TestEventListener |
411 | >>> from lp.bugs.interfaces.bugtask import IBugTask |
412 | - >>> bugtask_modified_listener = TestEventListener( |
413 | - ... IBugTask, IObjectModifiedEvent, print_bugtask_modified_event) |
414 | - >>> bugtask_created_listener = TestEventListener( |
415 | - ... IBugTask, IObjectCreatedEvent, print_bugtask_created_event) |
416 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
417 | + >>> bugtask_modified_listener = ZopeEventHandlerFixture( |
418 | + ... print_bugtask_modified_event, (IBugTask, IObjectModifiedEvent)) |
419 | + >>> bugtask_modified_listener.setUp() |
420 | + >>> bugtask_created_listener = ZopeEventHandlerFixture( |
421 | + ... print_bugtask_created_event, (IBugTask, IObjectCreatedEvent)) |
422 | + >>> bugtask_created_listener.setUp() |
423 | >>> bug_four_upstream_task = bug_four.bugtasks[0] |
424 | >>> print(bug_four_upstream_task.status.name) |
425 | NEW |
426 | @@ -1634,8 +1636,8 @@ An email can contain multiple commands, even for different bugs. |
427 | >>> print(bug_five_upstream_task.importance.name) |
428 | HIGH |
429 | |
430 | - >>> bugtask_modified_listener.unregister() |
431 | - >>> bugtask_created_listener.unregister() |
432 | + >>> bugtask_modified_listener.cleanUp() |
433 | + >>> bugtask_created_listener.cleanUp() |
434 | |
435 | |
436 | Default 'affects' target |
437 | diff --git a/lib/lp/code/model/tests/test_codereviewkarma.py b/lib/lp/code/model/tests/test_codereviewkarma.py |
438 | index bd6a4de..d763ba5 100644 |
439 | --- a/lib/lp/code/model/tests/test_codereviewkarma.py |
440 | +++ b/lib/lp/code/model/tests/test_codereviewkarma.py |
441 | @@ -14,7 +14,7 @@ from lp.testing import ( |
442 | login_person, |
443 | TestCaseWithFactory, |
444 | ) |
445 | -from lp.testing.event import TestEventListener |
446 | +from lp.testing.fixture import ZopeEventHandlerFixture |
447 | from lp.testing.layers import DatabaseFunctionalLayer |
448 | |
449 | |
450 | @@ -27,30 +27,15 @@ class TestCodeReviewKarma(TestCaseWithFactory): |
451 | """ |
452 | |
453 | layer = DatabaseFunctionalLayer |
454 | - karma_listener = None |
455 | |
456 | def setUp(self): |
457 | # Use an admin to get launchpad.Edit on all the branches to easily |
458 | # approve and reject the proposals. |
459 | super(TestCodeReviewKarma, self).setUp('admin@canonical.com') |
460 | - # The way the zope infrastructure works is that we can register |
461 | - # subscribers easily, but there is no way to unregister them (bug |
462 | - # 2338). TestEventListener does this with by setting a property to |
463 | - # stop calling the callback function. Instead of ending up with a |
464 | - # whole pile of registered inactive event listeners, we just |
465 | - # reactivate the one we have if there is one. |
466 | - if self.karma_listener is None: |
467 | - self.karma_listener = TestEventListener( |
468 | - IPerson, IKarmaAssignedEvent, self._on_karma_assigned) |
469 | - else: |
470 | - self.karma_listener._active = True |
471 | - |
472 | + self.useFixture(ZopeEventHandlerFixture( |
473 | + self._on_karma_assigned, (IPerson, IKarmaAssignedEvent))) |
474 | self.karma_events = [] |
475 | |
476 | - def tearDown(self): |
477 | - self.karma_listener.unregister() |
478 | - super(TestCodeReviewKarma, self).tearDown() |
479 | - |
480 | def _on_karma_assigned(self, object, event): |
481 | # Store the karma event for checking in the test method. |
482 | self.karma_events.append(event.karma) |
483 | diff --git a/lib/lp/registry/doc/milestone.txt b/lib/lp/registry/doc/milestone.txt |
484 | index 451bb8e..2ad094c 100644 |
485 | --- a/lib/lp/registry/doc/milestone.txt |
486 | +++ b/lib/lp/registry/doc/milestone.txt |
487 | @@ -510,9 +510,9 @@ When a milestone with bug tasks creates a release, those bug tasks in |
488 | fix committed status are updated to fix released. An ObjectModifiedEvent |
489 | event is signaled for each changed bug task. |
490 | |
491 | - >>> from lp.testing.event import TestEventListener |
492 | >>> from lazr.lifecycle.interfaces import IObjectModifiedEvent |
493 | >>> from lp.bugs.interfaces.bugtask import BugTaskStatus, IBugTask |
494 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
495 | |
496 | >>> def print_event(object, event): |
497 | ... print "Received %s on %s" % ( |
498 | @@ -527,8 +527,9 @@ event is signaled for each changed bug task. |
499 | >>> triaged_bugtask.transitionToMilestone(milestone, owner) |
500 | >>> triaged_bugtask.transitionToStatus(BugTaskStatus.TRIAGED, owner) |
501 | >>> release = milestone.createProductRelease(owner, datetime.now(UTC)) |
502 | - >>> bugtask_event_listener = TestEventListener( |
503 | - ... IBugTask, IObjectModifiedEvent, print_event) |
504 | + >>> bugtask_event_listener = ZopeEventHandlerFixture( |
505 | + ... print_event, (IBugTask, IObjectModifiedEvent)) |
506 | + >>> bugtask_event_listener.setUp() |
507 | |
508 | >>> milestone.closeBugsAndBlueprints(owner) |
509 | Received ObjectModifiedEvent on BugTask |
510 | @@ -539,6 +540,6 @@ event is signaled for each changed bug task. |
511 | >>> triaged_bugtask.status |
512 | <DBItem BugTaskStatus.TRIAGED, (21) Triaged> |
513 | |
514 | - >>> bugtask_event_listener.unregister() |
515 | + >>> bugtask_event_listener.cleanUp() |
516 | |
517 | |
518 | diff --git a/lib/lp/registry/doc/person.txt b/lib/lp/registry/doc/person.txt |
519 | index 9a49a80..11abc90 100644 |
520 | --- a/lib/lp/registry/doc/person.txt |
521 | +++ b/lib/lp/registry/doc/person.txt |
522 | @@ -442,16 +442,17 @@ PersonSet.newTeam() will also fire an ObjectCreatedEvent for the newly |
523 | created team. |
524 | |
525 | >>> from zope.lifecycleevent.interfaces import IObjectCreatedEvent |
526 | - >>> from lp.testing.event import TestEventListener |
527 | + >>> from lp.testing.fixture import ZopeEventHandlerFixture |
528 | >>> def print_event(team, event): |
529 | ... print "ObjectCreatedEvent fired for team '%s'" % team.name |
530 | |
531 | - >>> listener = TestEventListener( |
532 | - ... ITeam, IObjectCreatedEvent, print_event) |
533 | + >>> listener = ZopeEventHandlerFixture( |
534 | + ... print_event, (ITeam, IObjectCreatedEvent)) |
535 | + >>> listener.setUp() |
536 | >>> another_team = personset.newTeam(ddaa, 'new3', 'Another a new team') |
537 | ObjectCreatedEvent fired for team 'new3' |
538 | |
539 | - >>> listener.unregister() |
540 | + >>> listener.cleanUp() |
541 | |
542 | |
543 | Turning people into teams |
544 | diff --git a/lib/lp/registry/tests/test_product.py b/lib/lp/registry/tests/test_product.py |
545 | index 6dc0e96..00e840d 100644 |
546 | --- a/lib/lp/registry/tests/test_product.py |
547 | +++ b/lib/lp/registry/tests/test_product.py |
548 | @@ -103,7 +103,7 @@ from lp.testing import ( |
549 | TestCaseWithFactory, |
550 | WebServiceTestCase, |
551 | ) |
552 | -from lp.testing.event import TestEventListener |
553 | +from lp.testing.fixture import ZopeEventHandlerFixture |
554 | from lp.testing.layers import ( |
555 | DatabaseFunctionalLayer, |
556 | LaunchpadFunctionalLayer, |
557 | @@ -1514,16 +1514,11 @@ class ProductLicensingTestCase(TestCaseWithFactory): |
558 | """Test the rules of licences and commercial subscriptions.""" |
559 | |
560 | layer = DatabaseFunctionalLayer |
561 | - event_listener = None |
562 | |
563 | def setup_event_listener(self): |
564 | self.events = [] |
565 | - if self.event_listener is None: |
566 | - self.event_listener = TestEventListener( |
567 | - IProduct, IObjectModifiedEvent, self.on_event) |
568 | - else: |
569 | - self.event_listener._active = True |
570 | - self.addCleanup(self.event_listener.unregister) |
571 | + self.useFixture(ZopeEventHandlerFixture( |
572 | + self.on_event, (IProduct, IObjectModifiedEvent))) |
573 | |
574 | def on_event(self, thing, event): |
575 | self.events.append(event) |
576 | diff --git a/lib/lp/testing/event.py b/lib/lp/testing/event.py |
577 | deleted file mode 100644 |
578 | index 4bf85ab..0000000 |
579 | --- a/lib/lp/testing/event.py |
580 | +++ /dev/null |
581 | @@ -1,41 +0,0 @@ |
582 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
583 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
584 | - |
585 | -"""Helper class for checking the event notifications.""" |
586 | - |
587 | -__metaclass__ = type |
588 | - |
589 | -from zope.app.testing import ztapi |
590 | - |
591 | - |
592 | -class TestEventListener: |
593 | - """Listen for a specific object event in tests. |
594 | - |
595 | - When an event of the specified type is fired off for an object with |
596 | - the specifed type, the given callback is called. |
597 | - |
598 | - The callback function should take an object and an event. |
599 | - |
600 | - At the end of the test you have to unregister the event listener |
601 | - using event_listener.unregister(). |
602 | - """ |
603 | - |
604 | - def __init__(self, object_type, event_type, callback): |
605 | - self.object_type = object_type |
606 | - self.event_type = event_type |
607 | - self.callback = callback |
608 | - self._active = True |
609 | - ztapi.subscribe((object_type, event_type), None, self) |
610 | - |
611 | - def __call__(self, object, event): |
612 | - if not self._active: |
613 | - return |
614 | - self.callback(object, event) |
615 | - |
616 | - def unregister(self): |
617 | - """Stop the event listener from listening to events.""" |
618 | - # XXX: Bjorn Tillenius 2006-02-14 bug=2338: There is currently no way |
619 | - # of unsubscribing an event handler, so we simply set |
620 | - # self._active to False in order to make the handler return |
621 | - # without doing anything. |
622 | - self._active = False |
623 | diff --git a/lib/lp/testing/fixture.py b/lib/lp/testing/fixture.py |
624 | index 9a530fe..557a385 100644 |
625 | --- a/lib/lp/testing/fixture.py |
626 | +++ b/lib/lp/testing/fixture.py |
627 | @@ -42,7 +42,6 @@ from wsgi_intercept.urllib2_intercept import ( |
628 | from zope.component import ( |
629 | adapter, |
630 | getGlobalSiteManager, |
631 | - provideHandler, |
632 | ) |
633 | from zope.interface import Interface |
634 | from zope.publisher.interfaces.browser import IDefaultBrowserLayer |
635 | @@ -169,14 +168,16 @@ class ZopeAdapterFixture(Fixture): |
636 | class ZopeEventHandlerFixture(Fixture): |
637 | """A fixture that provides and then unprovides a Zope event handler.""" |
638 | |
639 | - def __init__(self, handler): |
640 | + def __init__(self, handler, required=None): |
641 | super(ZopeEventHandlerFixture, self).__init__() |
642 | self._handler = handler |
643 | + self._required = required |
644 | |
645 | def _setUp(self): |
646 | gsm = getGlobalSiteManager() |
647 | - provideHandler(self._handler) |
648 | - self.addCleanup(gsm.unregisterHandler, self._handler) |
649 | + gsm.registerHandler(self._handler, required=self._required) |
650 | + self.addCleanup( |
651 | + gsm.unregisterHandler, self._handler, required=self._required) |
652 | |
653 | |
654 | class ZopeViewReplacementFixture(Fixture): |
655 | diff --git a/lib/lp/testing/karma.py b/lib/lp/testing/karma.py |
656 | index c0eaf8a..801b9ff 100644 |
657 | --- a/lib/lp/testing/karma.py |
658 | +++ b/lib/lp/testing/karma.py |
659 | @@ -13,9 +13,10 @@ __all__ = [ |
660 | |
661 | from lp.registry.interfaces.karma import IKarmaAssignedEvent |
662 | from lp.registry.interfaces.person import IPerson |
663 | -from lp.testing.event import TestEventListener |
664 | +from lp.testing.fixture import ZopeEventHandlerFixture |
665 | |
666 | |
667 | +# XXX cjwatson 2019-10-23: This should be a fixture. |
668 | class KarmaRecorder: |
669 | """Helper that records selected karma events. |
670 | |
671 | @@ -80,12 +81,14 @@ class KarmaRecorder: |
672 | |
673 | def register_listener(self): |
674 | """Register listener. Must be `unregister`ed later.""" |
675 | - self.listener = TestEventListener( |
676 | - IPerson, IKarmaAssignedEvent, self.receive) |
677 | + self.listener = ZopeEventHandlerFixture( |
678 | + self.receive, (IPerson, IKarmaAssignedEvent)) |
679 | + self.listener.setUp() |
680 | |
681 | def unregister_listener(self): |
682 | """Unregister listener after `register`.""" |
683 | - self.listener.unregister() |
684 | + self.listener.cleanUp() |
685 | + self.listener = None |
686 | |
687 | |
688 | class KarmaAssignedEventListener(KarmaRecorder): |