Merge ~cjwatson/launchpad:remove-test-event-listener into launchpad: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)
Reviewer Review Type Date Requested Status
Tom Wardill (community) Approve
Review via email: mp+374628@code.launchpad.net

Commit message

Replace TestEventListener with ZopeEventHandlerFixture

Description of the change

After adding optional support to ZopeEventHandlerFixture for specifying
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
ZopeEventHandlerFixture.

(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
Tom Wardill (twom) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/answers/browser/tests/views.txt b/lib/lp/answers/browser/tests/views.txt
2index 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
32diff --git a/lib/lp/answers/doc/workflow.txt b/lib/lp/answers/doc/workflow.txt
33index 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
93diff --git a/lib/lp/answers/tests/test_question_workflow.py b/lib/lp/answers/tests/test_question_workflow.py
94index 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)
171diff --git a/lib/lp/bugs/browser/tests/bug-views.txt b/lib/lp/bugs/browser/tests/bug-views.txt
172index 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
208diff --git a/lib/lp/bugs/browser/tests/buglinktarget-views.txt b/lib/lp/bugs/browser/tests/buglinktarget-views.txt
209index 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()
235diff --git a/lib/lp/bugs/browser/tests/bugtask-adding-views.txt b/lib/lp/bugs/browser/tests/bugtask-adding-views.txt
236index 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
267diff --git a/lib/lp/bugs/doc/bugattachments.txt b/lib/lp/bugs/doc/bugattachments.txt
268index 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
297diff --git a/lib/lp/bugs/doc/bugwatch.txt b/lib/lp/bugs/doc/bugwatch.txt
298index 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
326diff --git a/lib/lp/bugs/doc/malone-xmlrpc.txt b/lib/lp/bugs/doc/malone-xmlrpc.txt
327index 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
359diff --git a/lib/lp/bugs/tests/buglinktarget.txt b/lib/lp/bugs/tests/buglinktarget.txt
360index 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()
402diff --git a/lib/lp/bugs/tests/bugs-emailinterface.txt b/lib/lp/bugs/tests/bugs-emailinterface.txt
403index 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
437diff --git a/lib/lp/code/model/tests/test_codereviewkarma.py b/lib/lp/code/model/tests/test_codereviewkarma.py
438index 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)
483diff --git a/lib/lp/registry/doc/milestone.txt b/lib/lp/registry/doc/milestone.txt
484index 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
518diff --git a/lib/lp/registry/doc/person.txt b/lib/lp/registry/doc/person.txt
519index 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
544diff --git a/lib/lp/registry/tests/test_product.py b/lib/lp/registry/tests/test_product.py
545index 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)
576diff --git a/lib/lp/testing/event.py b/lib/lp/testing/event.py
577deleted file mode 100644
578index 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
623diff --git a/lib/lp/testing/fixture.py b/lib/lp/testing/fixture.py
624index 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):
655diff --git a/lib/lp/testing/karma.py b/lib/lp/testing/karma.py
656index 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):

Subscribers

People subscribed via source and target branches

to status/vote changes: