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
diff --git a/lib/lp/answers/browser/tests/views.txt b/lib/lp/answers/browser/tests/views.txt
index 975bb8f..b8cf752 100644
--- a/lib/lp/answers/browser/tests/views.txt
+++ b/lib/lp/answers/browser/tests/views.txt
@@ -30,13 +30,14 @@ Register an event listener that will print events it receives.
3030
31 >>> from lazr.lifecycle.interfaces import IObjectModifiedEvent31 >>> from lazr.lifecycle.interfaces import IObjectModifiedEvent
32 >>> from lp.answers.interfaces.question import IQuestion32 >>> from lp.answers.interfaces.question import IQuestion
33 >>> from lp.testing.event import TestEventListener33 >>> from lp.testing.fixture import ZopeEventHandlerFixture
3434
35 >>> def print_modified_event(object, event):35 >>> def print_modified_event(object, event):
36 ... print("Received ObjectModifiedEvent: %s" % (36 ... print("Received ObjectModifiedEvent: %s" % (
37 ... ", ".join(sorted(event.edited_fields))))37 ... ", ".join(sorted(event.edited_fields))))
38 >>> question_event_listener = TestEventListener(38 >>> question_event_listener = ZopeEventHandlerFixture(
39 ... IQuestion, IObjectModifiedEvent, print_modified_event)39 ... print_modified_event, (IQuestion, IObjectModifiedEvent))
40 >>> question_event_listener.setUp()
4041
41 >>> view = create_initialized_view(question_three, name='+subscribe')42 >>> view = create_initialized_view(question_three, name='+subscribe')
42 >>> print(view.label)43 >>> print(view.label)
@@ -82,7 +83,7 @@ Unsubscription works in a similar manner.
82 >>> view.request.response.getHeader('Location')83 >>> view.request.response.getHeader('Location')
83 '.../+question/3'84 '.../+question/3'
8485
85 >>> question_event_listener.unregister()86 >>> question_event_listener.cleanUp()
8687
8788
88QuestionWorkflowView89QuestionWorkflowView
diff --git a/lib/lp/answers/doc/workflow.txt b/lib/lp/answers/doc/workflow.txt
index bdb5841..3cabebb 100644
--- a/lib/lp/answers/doc/workflow.txt
+++ b/lib/lp/answers/doc/workflow.txt
@@ -604,17 +604,19 @@ the message they create and a ObjectModifiedEvent for the question.
604 # Register an event listener that will print events it receives.604 # Register an event listener that will print events it receives.
605 >>> from lazr.lifecycle.interfaces import (605 >>> from lazr.lifecycle.interfaces import (
606 ... IObjectCreatedEvent, IObjectModifiedEvent)606 ... IObjectCreatedEvent, IObjectModifiedEvent)
607 >>> from lp.testing.event import TestEventListener607 >>> from lp.testing.fixture import ZopeEventHandlerFixture
608 >>> from lp.answers.interfaces.question import IQuestion608 >>> from lp.answers.interfaces.question import IQuestion
609609
610 >>> def print_event(object, event):610 >>> def print_event(object, event):
611 ... print("Received %s on %s" % (611 ... print("Received %s on %s" % (
612 ... event.__class__.__name__.split('.')[-1],612 ... event.__class__.__name__.split('.')[-1],
613 ... object.__class__.__name__.split('.')[-1]))613 ... object.__class__.__name__.split('.')[-1]))
614 >>> questionmessage_event_listener = TestEventListener(614 >>> questionmessage_event_listener = ZopeEventHandlerFixture(
615 ... IQuestionMessage, IObjectCreatedEvent, print_event)615 ... print_event, (IQuestionMessage, IObjectCreatedEvent))
616 >>> question_event_listener = TestEventListener(616 >>> questionmessage_event_listener.setUp()
617 ... IQuestion, IObjectModifiedEvent, print_event)617 >>> question_event_listener = ZopeEventHandlerFixture(
618 ... print_event, (IQuestion, IObjectModifiedEvent))
619 >>> question_event_listener.setUp()
618620
619Changing the status triggers the event.621Changing the status triggers the event.
620622
@@ -639,8 +641,8 @@ these events.
639 Received ObjectModifiedEvent on Question641 Received ObjectModifiedEvent on Question
640642
641 # Cleanup643 # Cleanup
642 >>> questionmessage_event_listener.unregister()644 >>> questionmessage_event_listener.cleanUp()
643 >>> question_event_listener.unregister()645 >>> question_event_listener.cleanUp()
644646
645647
646Reopening the question648Reopening the question
@@ -652,8 +654,9 @@ is reopened, a QuestionReopening is created.
652 # Register an event listener to notify us whenever a QuestionReopening is654 # Register an event listener to notify us whenever a QuestionReopening is
653 # created.655 # created.
654 >>> from lp.answers.interfaces.questionreopening import IQuestionReopening656 >>> from lp.answers.interfaces.questionreopening import IQuestionReopening
655 >>> reopening_event_listener = TestEventListener(657 >>> reopening_event_listener = ZopeEventHandlerFixture(
656 ... IQuestionReopening, IObjectCreatedEvent, print_event)658 ... print_event, (IQuestionReopening, IObjectCreatedEvent))
659 >>> reopening_event_listener.setUp()
657660
658The most common use case is when a user confirms a solution, and then661The most common use case is when a user confirms a solution, and then
659comes back to say that it doesn't, in fact, work.662comes back to say that it doesn't, in fact, work.
@@ -732,7 +735,7 @@ having been rejected.
732 INVALID735 INVALID
733736
734 # Cleanup737 # Cleanup
735 >>> reopening_event_listener.unregister()738 >>> reopening_event_listener.cleanUp()
736739
737740
738Using an IMessage as an explanation741Using an IMessage as an explanation
diff --git a/lib/lp/answers/tests/test_question_workflow.py b/lib/lp/answers/tests/test_question_workflow.py
index d2af2e1..6450d61 100644
--- a/lib/lp/answers/tests/test_question_workflow.py
+++ b/lib/lp/answers/tests/test_question_workflow.py
@@ -20,7 +20,6 @@ from datetime import (
20 timedelta,20 timedelta,
21 )21 )
22import traceback22import traceback
23import unittest
2423
25from lazr.lifecycle.interfaces import (24from lazr.lifecycle.interfaces import (
26 IObjectCreatedEvent,25 IObjectCreatedEvent,
@@ -54,12 +53,13 @@ from lp.testing import (
54 ANONYMOUS,53 ANONYMOUS,
55 login,54 login,
56 login_person,55 login_person,
56 TestCase,
57 )57 )
58from lp.testing.event import TestEventListener58from lp.testing.fixture import ZopeEventHandlerFixture
59from lp.testing.layers import DatabaseFunctionalLayer59from lp.testing.layers import DatabaseFunctionalLayer
6060
6161
62class BaseAnswerTrackerWorkflowTestCase(unittest.TestCase):62class BaseAnswerTrackerWorkflowTestCase(TestCase):
63 """Base class for test cases related to the Answer Tracker workflow.63 """Base class for test cases related to the Answer Tracker workflow.
6464
65 It provides the common fixture and test helper methods.65 It provides the common fixture and test helper methods.
@@ -68,6 +68,8 @@ class BaseAnswerTrackerWorkflowTestCase(unittest.TestCase):
68 layer = DatabaseFunctionalLayer68 layer = DatabaseFunctionalLayer
6969
70 def setUp(self):70 def setUp(self):
71 super(BaseAnswerTrackerWorkflowTestCase, self).setUp()
72
71 self.now = datetime.now(UTC)73 self.now = datetime.now(UTC)
7274
73 # Login as the question owner.75 # Login as the question owner.
@@ -90,10 +92,7 @@ class BaseAnswerTrackerWorkflowTestCase(unittest.TestCase):
90 self.owner, 'Help!', 'I need help with Ubuntu',92 self.owner, 'Help!', 'I need help with Ubuntu',
91 datecreated=self.now)93 datecreated=self.now)
9294
93 def tearDown(self):95 self.registered_event_listeners = False
94 if hasattr(self, 'created_event_listener'):
95 self.created_event_listener.unregister()
96 self.modified_event_listener.unregister()
9796
98 def setQuestionStatus(self, question, new_status,97 def setQuestionStatus(self, question, new_status,
99 comment="Status change."):98 comment="Status change."):
@@ -110,13 +109,12 @@ class BaseAnswerTrackerWorkflowTestCase(unittest.TestCase):
110 def setUpEventListeners(self):109 def setUpEventListeners(self):
111 """Install a listener for events emitted during the test."""110 """Install a listener for events emitted during the test."""
112 self.collected_events = []111 self.collected_events = []
113 if hasattr(self, 'modified_event_listener'):112 if not self.registered_event_listeners:
114 # Event listeners is already registered.113 self.useFixture(ZopeEventHandlerFixture(
115 return114 self.collectEvent, (IQuestion, IObjectModifiedEvent)))
116 self.modified_event_listener = TestEventListener(115 self.useFixture(ZopeEventHandlerFixture(
117 IQuestion, IObjectModifiedEvent, self.collectEvent)116 self.collectEvent, (IQuestionMessage, IObjectCreatedEvent)))
118 self.created_event_listener = TestEventListener(117 self.registered_event_listeners = True
119 IQuestionMessage, IObjectCreatedEvent, self.collectEvent)
120118
121 def collectEvent(self, object, event):119 def collectEvent(self, object, event):
122 """Collect events"""120 """Collect events"""
@@ -518,7 +516,7 @@ class LinkFAQTestCase(BaseAnswerTrackerWorkflowTestCase):
518516
519 def setUp(self):517 def setUp(self):
520 """Create an additional FAQ."""518 """Create an additional FAQ."""
521 BaseAnswerTrackerWorkflowTestCase.setUp(self)519 super(LinkFAQTestCase, self).setUp()
522520
523 # Only admin can create FAQ on ubuntu.521 # Only admin can create FAQ on ubuntu.
524 login_person(self.admin)522 login_person(self.admin)
diff --git a/lib/lp/bugs/browser/tests/bug-views.txt b/lib/lp/bugs/browser/tests/bug-views.txt
index fb41886..2e89e54 100644
--- a/lib/lp/bugs/browser/tests/bug-views.txt
+++ b/lib/lp/bugs/browser/tests/bug-views.txt
@@ -8,16 +8,18 @@ There are three objects on which you can file a bug. An
8ObjectCreatedEvent is published when the bug is filed. Let's register8ObjectCreatedEvent is published when the bug is filed. Let's register
9an event listener to demonstrate this.9an event listener to demonstrate this.
1010
11 >>> from lp.services.database.sqlbase import flush_database_updates11 >>> from lazr.lifecycle.event import IObjectCreatedEvent
12 >>> import transaction12 >>> import transaction
1313
14 >>> from lp.testing.event import TestEventListener
15 >>> from lazr.lifecycle.event import IObjectCreatedEvent
16 >>> from lp.bugs.interfaces.bug import IBug14 >>> from lp.bugs.interfaces.bug import IBug
15 >>> from lp.services.database.sqlbase import flush_database_updates
16 >>> from lp.testing.fixture import ZopeEventHandlerFixture
17
17 >>> def on_created_event(object, event):18 >>> def on_created_event(object, event):
18 ... print("ObjectCreatedEvent: %r" % object)19 ... print("ObjectCreatedEvent: %r" % object)
19 >>> on_created_listener = TestEventListener(20 >>> on_created_listener = ZopeEventHandlerFixture(
20 ... IBug, IObjectCreatedEvent, on_created_event)21 ... on_created_event, (IBug, IObjectCreatedEvent))
22 >>> on_created_listener.setUp()
2123
221. Filing a bug on a distribution.241. Filing a bug on a distribution.
2325
@@ -210,7 +212,7 @@ indentical to the second, we really only display one comment:
210212
211(Unregister our listener, since we no longer need it.)213(Unregister our listener, since we no longer need it.)
212214
213 >>> on_created_listener.unregister()215 >>> on_created_listener.cleanUp()
214216
215217
216Bug Portlets218Bug Portlets
diff --git a/lib/lp/bugs/browser/tests/buglinktarget-views.txt b/lib/lp/bugs/browser/tests/buglinktarget-views.txt
index 99fd6a2..86e5baf 100644
--- a/lib/lp/bugs/browser/tests/buglinktarget-views.txt
+++ b/lib/lp/bugs/browser/tests/buglinktarget-views.txt
@@ -13,11 +13,12 @@ The +linkbug and +unlinkbug views operates on IBugLinkTarget.
13 >>> cve = getUtility(ICveSet)['2005-2730']13 >>> cve = getUtility(ICveSet)['2005-2730']
1414
15 (Setup an event listener.)15 (Setup an event listener.)
16 >>> from lp.testing.event import TestEventListener16 >>> from lp.testing.fixture import ZopeEventHandlerFixture
17 >>> collected_events = []17 >>> collected_events = []
18 >>> modified_listener = TestEventListener(18 >>> modified_listener = ZopeEventHandlerFixture(
19 ... IBugLinkTarget, ObjectModifiedEvent,19 ... lambda object, event: collected_events.append(event),
20 ... lambda object, event: collected_events.append(event))20 ... (IBugLinkTarget, ObjectModifiedEvent))
21 >>> modified_listener.setUp()
2122
22 (Login because bug link management is only available to registered users.)23 (Login because bug link management is only available to registered users.)
23 >>> login('no-priv@canonical.com')24 >>> login('no-priv@canonical.com')
@@ -151,4 +152,4 @@ The notification contains the escaped bug title.
151== Cleanup ==152== Cleanup ==
152153
153 (Deactivate the event listener.)154 (Deactivate the event listener.)
154 >>> modified_listener.unregister()155 >>> modified_listener.cleanUp()
diff --git a/lib/lp/bugs/browser/tests/bugtask-adding-views.txt b/lib/lp/bugs/browser/tests/bugtask-adding-views.txt
index f1d3c87..b0200e2 100644
--- a/lib/lp/bugs/browser/tests/bugtask-adding-views.txt
+++ b/lib/lp/bugs/browser/tests/bugtask-adding-views.txt
@@ -171,14 +171,15 @@ In order to show that all the events get fired off, let's create an
171event listener and register it:171event listener and register it:
172172
173 >>> from zope.interface import Interface173 >>> from zope.interface import Interface
174 >>> from lp.testing.event import TestEventListener
175 >>> from lazr.lifecycle.interfaces import IObjectCreatedEvent174 >>> from lazr.lifecycle.interfaces import IObjectCreatedEvent
175 >>> from lp.testing.fixture import ZopeEventHandlerFixture
176176
177 >>> def on_created_event(object, event):177 >>> def on_created_event(object, event):
178 ... print("ObjectCreatedEvent: %r" % object)178 ... print("ObjectCreatedEvent: %r" % object)
179179
180 >>> on_created_listener = TestEventListener(180 >>> on_created_listener = ZopeEventHandlerFixture(
181 ... Interface, IObjectCreatedEvent, on_created_event)181 ... on_created_event, (Interface, IObjectCreatedEvent))
182 >>> on_created_listener.setUp()
182183
183184
184If an invalid product is specified, or a product that fails the185If an invalid product is specified, or a product that fails the
@@ -449,7 +450,7 @@ package will be converted to the corresponding source package.
449 ...450 ...
450 mozilla-firefox (Ubuntu)451 mozilla-firefox (Ubuntu)
451452
452 >>> on_created_listener.unregister()453 >>> on_created_listener.cleanUp()
453454
454455
455Registering a product while adding a bugtask456Registering a product while adding a bugtask
diff --git a/lib/lp/bugs/doc/bugattachments.txt b/lib/lp/bugs/doc/bugattachments.txt
index 4788804..bbd23bd 100644
--- a/lib/lp/bugs/doc/bugattachments.txt
+++ b/lib/lp/bugs/doc/bugattachments.txt
@@ -28,12 +28,13 @@ ObjectCreatedEvent in order to trigger email notifications:
2828
29 >>> from io import BytesIO29 >>> from io import BytesIO
3030
31 >>> from lp.testing.event import TestEventListener
32 >>> from lazr.lifecycle.event import IObjectCreatedEvent31 >>> from lazr.lifecycle.event import IObjectCreatedEvent
32 >>> from lp.testing.fixture import ZopeEventHandlerFixture
33 >>> def attachment_added(attachment, event):33 >>> def attachment_added(attachment, event):
34 ... print("Attachment added: %r" % attachment.libraryfile.filename)34 ... print("Attachment added: %r" % attachment.libraryfile.filename)
35 >>> event_listener = TestEventListener(35 >>> event_listener = ZopeEventHandlerFixture(
36 ... IBugAttachment, IObjectCreatedEvent, attachment_added)36 ... attachment_added, (IBugAttachment, IObjectCreatedEvent))
37 >>> event_listener.setUp()
3738
38 >>> filecontent = b"Some useful information."39 >>> filecontent = b"Some useful information."
39 >>> data = BytesIO(filecontent)40 >>> data = BytesIO(filecontent)
@@ -293,7 +294,7 @@ from the librarian.
293 'http://.../foo-bar-baz'294 'http://.../foo-bar-baz'
294295
295 >>> config_data = config.pop('max_attachment_size')296 >>> config_data = config.pop('max_attachment_size')
296 >>> event_listener.unregister()297 >>> event_listener.cleanUp()
297298
298299
299Security300Security
diff --git a/lib/lp/bugs/doc/bugwatch.txt b/lib/lp/bugs/doc/bugwatch.txt
index 7dba686..c280375 100644
--- a/lib/lp/bugs/doc/bugwatch.txt
+++ b/lib/lp/bugs/doc/bugwatch.txt
@@ -263,11 +263,12 @@ we can confirm that an event is indeed fired off.
263 ... if bugtask.importance != old_bugtask.importance:263 ... if bugtask.importance != old_bugtask.importance:
264 ... print("%s => %s" % (old_bugtask.importance.title,264 ... print("%s => %s" % (old_bugtask.importance.title,
265 ... bugtask.importance.title))265 ... bugtask.importance.title))
266 >>> from lp.testing.event import TestEventListener
267 >>> from lazr.lifecycle.interfaces import IObjectModifiedEvent266 >>> from lazr.lifecycle.interfaces import IObjectModifiedEvent
268 >>> from lp.bugs.interfaces.bugtask import IBugTask267 >>> from lp.bugs.interfaces.bugtask import IBugTask
269 >>> event_listener = TestEventListener(268 >>> from lp.testing.fixture import ZopeEventHandlerFixture
270 ... IBugTask, IObjectModifiedEvent, print_bugtask_modified)269 >>> event_listener = ZopeEventHandlerFixture(
270 ... print_bugtask_modified, (IBugTask, IObjectModifiedEvent))
271 >>> event_listener.setUp()
271272
272If we pass in a different Malone status than the existing one, an event273If we pass in a different Malone status than the existing one, an event
273will be fired off, even though the remote status stays the same.274will be fired off, even though the remote status stays the same.
@@ -391,7 +392,7 @@ manner:
391 ** Changed in: mozilla-firefox (Debian)392 ** Changed in: mozilla-firefox (Debian)
392 Importance: Low => Critical393 Importance: Low => Critical
393394
394 >>> event_listener.unregister()395 >>> event_listener.cleanUp()
395396
396The Bug Watch Updater can transition a bug to any status or importance:397The Bug Watch Updater can transition a bug to any status or importance:
397398
diff --git a/lib/lp/bugs/doc/malone-xmlrpc.txt b/lib/lp/bugs/doc/malone-xmlrpc.txt
index 78a0ddb..1d4ace3 100644
--- a/lib/lp/bugs/doc/malone-xmlrpc.txt
+++ b/lib/lp/bugs/doc/malone-xmlrpc.txt
@@ -49,15 +49,16 @@ First, let's define a simple event listener to show that the
49IObjectCreatedEvent is being published when a bug is reported through49IObjectCreatedEvent is being published when a bug is reported through
50the XML-RPC interface.50the XML-RPC interface.
5151
52 >>> from lp.testing.event import TestEventListener
53 >>> from lazr.lifecycle.interfaces import IObjectCreatedEvent52 >>> from lazr.lifecycle.interfaces import IObjectCreatedEvent
54 >>> from lp.bugs.interfaces.bug import IBug53 >>> from lp.bugs.interfaces.bug import IBug
54 >>> from lp.testing.fixture import ZopeEventHandlerFixture
5555
56 >>> def on_created_event(obj, event):56 >>> def on_created_event(obj, event):
57 ... print("ObjectCreatedEvent: %r" % obj)57 ... print("ObjectCreatedEvent: %r" % obj)
5858
59 >>> on_created_listener = TestEventListener(59 >>> on_created_listener = ZopeEventHandlerFixture(
60 ... IBug, IObjectCreatedEvent, on_created_event)60 ... on_created_event, (IBug, IObjectCreatedEvent))
61 >>> on_created_listener.setUp()
6162
62Reporting a product bug.63Reporting a product bug.
6364
@@ -228,7 +229,7 @@ Invalid subscriber.
228 Fault: <Fault 20: 'Invalid subscriber: No user with the email address229 Fault: <Fault 20: 'Invalid subscriber: No user with the email address
229 "nosuch@subscriber.com" was found'>230 "nosuch@subscriber.com" was found'>
230231
231 >>> on_created_listener.unregister()232 >>> on_created_listener.cleanUp()
232233
233234
234Generating bugtracker authentication tokens235Generating bugtracker authentication tokens
diff --git a/lib/lp/bugs/tests/buglinktarget.txt b/lib/lp/bugs/tests/buglinktarget.txt
index 733d8c1..556b67c 100644
--- a/lib/lp/bugs/tests/buglinktarget.txt
+++ b/lib/lp/bugs/tests/buglinktarget.txt
@@ -46,11 +46,12 @@ fired.
46 >>> from zope.interface import Interface46 >>> from zope.interface import Interface
47 >>> from lp.bugs.interfaces.buglink import (47 >>> from lp.bugs.interfaces.buglink import (
48 ... IObjectLinkedEvent, IObjectUnlinkedEvent)48 ... IObjectLinkedEvent, IObjectUnlinkedEvent)
49 >>> from lp.testing.event import TestEventListener49 >>> from lp.testing.fixture import ZopeEventHandlerFixture
50 >>> linked_events = []50 >>> linked_events = []
51 >>> linked_event_listener = TestEventListener(51 >>> linked_event_listener = ZopeEventHandlerFixture(
52 ... Interface, IObjectLinkedEvent,52 ... lambda object, event: linked_events.append(event),
53 ... lambda object, event: linked_events.append(event))53 ... (Interface, IObjectLinkedEvent))
54 >>> linked_event_listener.setUp()
5455
55 >>> bug2 = bugset.get(2)56 >>> bug2 = bugset.get(2)
56 >>> target.linkBug(bugset.get(2))57 >>> target.linkBug(bugset.get(2))
@@ -125,9 +126,10 @@ The method returns whether the link existed. It should also send an
125IObjectUnlinkedEvent for each of the removed link:126IObjectUnlinkedEvent for each of the removed link:
126127
127 >>> unlinked_events = []128 >>> unlinked_events = []
128 >>> unlinked_event_listener = TestEventListener(129 >>> unlinked_event_listener = ZopeEventHandlerFixture(
129 ... Interface, IObjectUnlinkedEvent,130 ... lambda object, event: unlinked_events.append(event),
130 ... lambda object, event: unlinked_events.append(event))131 ... (Interface, IObjectUnlinkedEvent))
132 >>> unlinked_event_listener.setUp()
131133
132 >>> target.unlinkBug(bug1, factory.makePerson())134 >>> target.unlinkBug(bug1, factory.makePerson())
133 True135 True
@@ -167,5 +169,5 @@ the bug or if they are an administrator.
167== Cleanup ==169== Cleanup ==
168170
169 # Unregister event listeners.171 # Unregister event listeners.
170 >>> linked_event_listener.unregister()172 >>> linked_event_listener.cleanUp()
171 >>> unlinked_event_listener.unregister()173 >>> unlinked_event_listener.cleanUp()
diff --git a/lib/lp/bugs/tests/bugs-emailinterface.txt b/lib/lp/bugs/tests/bugs-emailinterface.txt
index ab8fd0d..2bc5460 100644
--- a/lib/lp/bugs/tests/bugs-emailinterface.txt
+++ b/lib/lp/bugs/tests/bugs-emailinterface.txt
@@ -1600,12 +1600,14 @@ An email can contain multiple commands, even for different bugs.
1600 ... bugtask.importance.title))1600 ... bugtask.importance.title))
1601 >>> from lazr.lifecycle.interfaces import (1601 >>> from lazr.lifecycle.interfaces import (
1602 ... IObjectCreatedEvent, IObjectModifiedEvent)1602 ... IObjectCreatedEvent, IObjectModifiedEvent)
1603 >>> from lp.testing.event import TestEventListener
1604 >>> from lp.bugs.interfaces.bugtask import IBugTask1603 >>> from lp.bugs.interfaces.bugtask import IBugTask
1605 >>> bugtask_modified_listener = TestEventListener(1604 >>> from lp.testing.fixture import ZopeEventHandlerFixture
1606 ... IBugTask, IObjectModifiedEvent, print_bugtask_modified_event)1605 >>> bugtask_modified_listener = ZopeEventHandlerFixture(
1607 >>> bugtask_created_listener = TestEventListener(1606 ... print_bugtask_modified_event, (IBugTask, IObjectModifiedEvent))
1608 ... IBugTask, IObjectCreatedEvent, print_bugtask_created_event)1607 >>> bugtask_modified_listener.setUp()
1608 >>> bugtask_created_listener = ZopeEventHandlerFixture(
1609 ... print_bugtask_created_event, (IBugTask, IObjectCreatedEvent))
1610 >>> bugtask_created_listener.setUp()
1609 >>> bug_four_upstream_task = bug_four.bugtasks[0]1611 >>> bug_four_upstream_task = bug_four.bugtasks[0]
1610 >>> print(bug_four_upstream_task.status.name)1612 >>> print(bug_four_upstream_task.status.name)
1611 NEW1613 NEW
@@ -1634,8 +1636,8 @@ An email can contain multiple commands, even for different bugs.
1634 >>> print(bug_five_upstream_task.importance.name)1636 >>> print(bug_five_upstream_task.importance.name)
1635 HIGH1637 HIGH
16361638
1637 >>> bugtask_modified_listener.unregister()1639 >>> bugtask_modified_listener.cleanUp()
1638 >>> bugtask_created_listener.unregister()1640 >>> bugtask_created_listener.cleanUp()
16391641
16401642
1641Default 'affects' target1643Default 'affects' target
diff --git a/lib/lp/code/model/tests/test_codereviewkarma.py b/lib/lp/code/model/tests/test_codereviewkarma.py
index bd6a4de..d763ba5 100644
--- a/lib/lp/code/model/tests/test_codereviewkarma.py
+++ b/lib/lp/code/model/tests/test_codereviewkarma.py
@@ -14,7 +14,7 @@ from lp.testing import (
14 login_person,14 login_person,
15 TestCaseWithFactory,15 TestCaseWithFactory,
16 )16 )
17from lp.testing.event import TestEventListener17from lp.testing.fixture import ZopeEventHandlerFixture
18from lp.testing.layers import DatabaseFunctionalLayer18from lp.testing.layers import DatabaseFunctionalLayer
1919
2020
@@ -27,30 +27,15 @@ class TestCodeReviewKarma(TestCaseWithFactory):
27 """27 """
2828
29 layer = DatabaseFunctionalLayer29 layer = DatabaseFunctionalLayer
30 karma_listener = None
3130
32 def setUp(self):31 def setUp(self):
33 # Use an admin to get launchpad.Edit on all the branches to easily32 # Use an admin to get launchpad.Edit on all the branches to easily
34 # approve and reject the proposals.33 # approve and reject the proposals.
35 super(TestCodeReviewKarma, self).setUp('admin@canonical.com')34 super(TestCodeReviewKarma, self).setUp('admin@canonical.com')
36 # The way the zope infrastructure works is that we can register35 self.useFixture(ZopeEventHandlerFixture(
37 # subscribers easily, but there is no way to unregister them (bug36 self._on_karma_assigned, (IPerson, IKarmaAssignedEvent)))
38 # 2338). TestEventListener does this with by setting a property to
39 # stop calling the callback function. Instead of ending up with a
40 # whole pile of registered inactive event listeners, we just
41 # reactivate the one we have if there is one.
42 if self.karma_listener is None:
43 self.karma_listener = TestEventListener(
44 IPerson, IKarmaAssignedEvent, self._on_karma_assigned)
45 else:
46 self.karma_listener._active = True
47
48 self.karma_events = []37 self.karma_events = []
4938
50 def tearDown(self):
51 self.karma_listener.unregister()
52 super(TestCodeReviewKarma, self).tearDown()
53
54 def _on_karma_assigned(self, object, event):39 def _on_karma_assigned(self, object, event):
55 # Store the karma event for checking in the test method.40 # Store the karma event for checking in the test method.
56 self.karma_events.append(event.karma)41 self.karma_events.append(event.karma)
diff --git a/lib/lp/registry/doc/milestone.txt b/lib/lp/registry/doc/milestone.txt
index 451bb8e..2ad094c 100644
--- a/lib/lp/registry/doc/milestone.txt
+++ b/lib/lp/registry/doc/milestone.txt
@@ -510,9 +510,9 @@ When a milestone with bug tasks creates a release, those bug tasks in
510fix committed status are updated to fix released. An ObjectModifiedEvent510fix committed status are updated to fix released. An ObjectModifiedEvent
511event is signaled for each changed bug task.511event is signaled for each changed bug task.
512512
513 >>> from lp.testing.event import TestEventListener
514 >>> from lazr.lifecycle.interfaces import IObjectModifiedEvent513 >>> from lazr.lifecycle.interfaces import IObjectModifiedEvent
515 >>> from lp.bugs.interfaces.bugtask import BugTaskStatus, IBugTask514 >>> from lp.bugs.interfaces.bugtask import BugTaskStatus, IBugTask
515 >>> from lp.testing.fixture import ZopeEventHandlerFixture
516516
517 >>> def print_event(object, event):517 >>> def print_event(object, event):
518 ... print "Received %s on %s" % (518 ... print "Received %s on %s" % (
@@ -527,8 +527,9 @@ event is signaled for each changed bug task.
527 >>> triaged_bugtask.transitionToMilestone(milestone, owner)527 >>> triaged_bugtask.transitionToMilestone(milestone, owner)
528 >>> triaged_bugtask.transitionToStatus(BugTaskStatus.TRIAGED, owner)528 >>> triaged_bugtask.transitionToStatus(BugTaskStatus.TRIAGED, owner)
529 >>> release = milestone.createProductRelease(owner, datetime.now(UTC))529 >>> release = milestone.createProductRelease(owner, datetime.now(UTC))
530 >>> bugtask_event_listener = TestEventListener(530 >>> bugtask_event_listener = ZopeEventHandlerFixture(
531 ... IBugTask, IObjectModifiedEvent, print_event)531 ... print_event, (IBugTask, IObjectModifiedEvent))
532 >>> bugtask_event_listener.setUp()
532533
533 >>> milestone.closeBugsAndBlueprints(owner)534 >>> milestone.closeBugsAndBlueprints(owner)
534 Received ObjectModifiedEvent on BugTask535 Received ObjectModifiedEvent on BugTask
@@ -539,6 +540,6 @@ event is signaled for each changed bug task.
539 >>> triaged_bugtask.status540 >>> triaged_bugtask.status
540 <DBItem BugTaskStatus.TRIAGED, (21) Triaged>541 <DBItem BugTaskStatus.TRIAGED, (21) Triaged>
541542
542 >>> bugtask_event_listener.unregister()543 >>> bugtask_event_listener.cleanUp()
543544
544545
diff --git a/lib/lp/registry/doc/person.txt b/lib/lp/registry/doc/person.txt
index 9a49a80..11abc90 100644
--- a/lib/lp/registry/doc/person.txt
+++ b/lib/lp/registry/doc/person.txt
@@ -442,16 +442,17 @@ PersonSet.newTeam() will also fire an ObjectCreatedEvent for the newly
442created team.442created team.
443443
444 >>> from zope.lifecycleevent.interfaces import IObjectCreatedEvent444 >>> from zope.lifecycleevent.interfaces import IObjectCreatedEvent
445 >>> from lp.testing.event import TestEventListener445 >>> from lp.testing.fixture import ZopeEventHandlerFixture
446 >>> def print_event(team, event):446 >>> def print_event(team, event):
447 ... print "ObjectCreatedEvent fired for team '%s'" % team.name447 ... print "ObjectCreatedEvent fired for team '%s'" % team.name
448448
449 >>> listener = TestEventListener(449 >>> listener = ZopeEventHandlerFixture(
450 ... ITeam, IObjectCreatedEvent, print_event)450 ... print_event, (ITeam, IObjectCreatedEvent))
451 >>> listener.setUp()
451 >>> another_team = personset.newTeam(ddaa, 'new3', 'Another a new team')452 >>> another_team = personset.newTeam(ddaa, 'new3', 'Another a new team')
452 ObjectCreatedEvent fired for team 'new3'453 ObjectCreatedEvent fired for team 'new3'
453454
454 >>> listener.unregister()455 >>> listener.cleanUp()
455456
456457
457Turning people into teams458Turning people into teams
diff --git a/lib/lp/registry/tests/test_product.py b/lib/lp/registry/tests/test_product.py
index 6dc0e96..00e840d 100644
--- a/lib/lp/registry/tests/test_product.py
+++ b/lib/lp/registry/tests/test_product.py
@@ -103,7 +103,7 @@ from lp.testing import (
103 TestCaseWithFactory,103 TestCaseWithFactory,
104 WebServiceTestCase,104 WebServiceTestCase,
105 )105 )
106from lp.testing.event import TestEventListener106from lp.testing.fixture import ZopeEventHandlerFixture
107from lp.testing.layers import (107from lp.testing.layers import (
108 DatabaseFunctionalLayer,108 DatabaseFunctionalLayer,
109 LaunchpadFunctionalLayer,109 LaunchpadFunctionalLayer,
@@ -1514,16 +1514,11 @@ class ProductLicensingTestCase(TestCaseWithFactory):
1514 """Test the rules of licences and commercial subscriptions."""1514 """Test the rules of licences and commercial subscriptions."""
15151515
1516 layer = DatabaseFunctionalLayer1516 layer = DatabaseFunctionalLayer
1517 event_listener = None
15181517
1519 def setup_event_listener(self):1518 def setup_event_listener(self):
1520 self.events = []1519 self.events = []
1521 if self.event_listener is None:1520 self.useFixture(ZopeEventHandlerFixture(
1522 self.event_listener = TestEventListener(1521 self.on_event, (IProduct, IObjectModifiedEvent)))
1523 IProduct, IObjectModifiedEvent, self.on_event)
1524 else:
1525 self.event_listener._active = True
1526 self.addCleanup(self.event_listener.unregister)
15271522
1528 def on_event(self, thing, event):1523 def on_event(self, thing, event):
1529 self.events.append(event)1524 self.events.append(event)
diff --git a/lib/lp/testing/event.py b/lib/lp/testing/event.py
1530deleted file mode 1006441525deleted file mode 100644
index 4bf85ab..0000000
--- a/lib/lp/testing/event.py
+++ /dev/null
@@ -1,41 +0,0 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Helper class for checking the event notifications."""
5
6__metaclass__ = type
7
8from zope.app.testing import ztapi
9
10
11class TestEventListener:
12 """Listen for a specific object event in tests.
13
14 When an event of the specified type is fired off for an object with
15 the specifed type, the given callback is called.
16
17 The callback function should take an object and an event.
18
19 At the end of the test you have to unregister the event listener
20 using event_listener.unregister().
21 """
22
23 def __init__(self, object_type, event_type, callback):
24 self.object_type = object_type
25 self.event_type = event_type
26 self.callback = callback
27 self._active = True
28 ztapi.subscribe((object_type, event_type), None, self)
29
30 def __call__(self, object, event):
31 if not self._active:
32 return
33 self.callback(object, event)
34
35 def unregister(self):
36 """Stop the event listener from listening to events."""
37 # XXX: Bjorn Tillenius 2006-02-14 bug=2338: There is currently no way
38 # of unsubscribing an event handler, so we simply set
39 # self._active to False in order to make the handler return
40 # without doing anything.
41 self._active = False
diff --git a/lib/lp/testing/fixture.py b/lib/lp/testing/fixture.py
index 9a530fe..557a385 100644
--- a/lib/lp/testing/fixture.py
+++ b/lib/lp/testing/fixture.py
@@ -42,7 +42,6 @@ from wsgi_intercept.urllib2_intercept import (
42from zope.component import (42from zope.component import (
43 adapter,43 adapter,
44 getGlobalSiteManager,44 getGlobalSiteManager,
45 provideHandler,
46 )45 )
47from zope.interface import Interface46from zope.interface import Interface
48from zope.publisher.interfaces.browser import IDefaultBrowserLayer47from zope.publisher.interfaces.browser import IDefaultBrowserLayer
@@ -169,14 +168,16 @@ class ZopeAdapterFixture(Fixture):
169class ZopeEventHandlerFixture(Fixture):168class ZopeEventHandlerFixture(Fixture):
170 """A fixture that provides and then unprovides a Zope event handler."""169 """A fixture that provides and then unprovides a Zope event handler."""
171170
172 def __init__(self, handler):171 def __init__(self, handler, required=None):
173 super(ZopeEventHandlerFixture, self).__init__()172 super(ZopeEventHandlerFixture, self).__init__()
174 self._handler = handler173 self._handler = handler
174 self._required = required
175175
176 def _setUp(self):176 def _setUp(self):
177 gsm = getGlobalSiteManager()177 gsm = getGlobalSiteManager()
178 provideHandler(self._handler)178 gsm.registerHandler(self._handler, required=self._required)
179 self.addCleanup(gsm.unregisterHandler, self._handler)179 self.addCleanup(
180 gsm.unregisterHandler, self._handler, required=self._required)
180181
181182
182class ZopeViewReplacementFixture(Fixture):183class ZopeViewReplacementFixture(Fixture):
diff --git a/lib/lp/testing/karma.py b/lib/lp/testing/karma.py
index c0eaf8a..801b9ff 100644
--- a/lib/lp/testing/karma.py
+++ b/lib/lp/testing/karma.py
@@ -13,9 +13,10 @@ __all__ = [
1313
14from lp.registry.interfaces.karma import IKarmaAssignedEvent14from lp.registry.interfaces.karma import IKarmaAssignedEvent
15from lp.registry.interfaces.person import IPerson15from lp.registry.interfaces.person import IPerson
16from lp.testing.event import TestEventListener16from lp.testing.fixture import ZopeEventHandlerFixture
1717
1818
19# XXX cjwatson 2019-10-23: This should be a fixture.
19class KarmaRecorder:20class KarmaRecorder:
20 """Helper that records selected karma events.21 """Helper that records selected karma events.
2122
@@ -80,12 +81,14 @@ class KarmaRecorder:
8081
81 def register_listener(self):82 def register_listener(self):
82 """Register listener. Must be `unregister`ed later."""83 """Register listener. Must be `unregister`ed later."""
83 self.listener = TestEventListener(84 self.listener = ZopeEventHandlerFixture(
84 IPerson, IKarmaAssignedEvent, self.receive)85 self.receive, (IPerson, IKarmaAssignedEvent))
86 self.listener.setUp()
8587
86 def unregister_listener(self):88 def unregister_listener(self):
87 """Unregister listener after `register`."""89 """Unregister listener after `register`."""
88 self.listener.unregister()90 self.listener.cleanUp()
91 self.listener = None
8992
9093
91class KarmaAssignedEventListener(KarmaRecorder):94class KarmaAssignedEventListener(KarmaRecorder):

Subscribers

People subscribed via source and target branches

to status/vote changes: