Merge lp:~abentley/launchpad/branch-scanner-zcml into lp:launchpad

Proposed by Aaron Bentley
Status: Merged
Approved by: Brad Crittenden
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~abentley/launchpad/branch-scanner-zcml
Merge into: lp:launchpad
Diff against target: 678 lines (+162/-102)
15 files modified
lib/lp/code/configure.zcml (+24/-0)
lib/lp/code/model/branchjob.py (+3/-20)
lib/lp/codehosting/scanner/branch_scanner.py (+3/-17)
lib/lp/codehosting/scanner/buglinks.py (+2/-4)
lib/lp/codehosting/scanner/bzrsync.py (+1/-4)
lib/lp/codehosting/scanner/email.py (+1/-4)
lib/lp/codehosting/scanner/events.py (+31/-5)
lib/lp/codehosting/scanner/fixture.py (+0/-5)
lib/lp/codehosting/scanner/mergedetection.py (+1/-5)
lib/lp/codehosting/scanner/tests/test_buglinks.py (+28/-8)
lib/lp/codehosting/scanner/tests/test_bzrsync.py (+1/-9)
lib/lp/codehosting/scanner/tests/test_email.py (+37/-15)
lib/lp/codehosting/scanner/tests/test_mergedetection.py (+12/-6)
lib/lp/translations/model/translationtemplatesbuildjob.py (+3/-0)
lib/lp/translations/tests/test_translationtemplatesbuildjob.py (+15/-0)
To merge this branch: bzr merge lp:~abentley/launchpad/branch-scanner-zcml
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code Approve
Review via email: mp+20471@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Aaron Bentley (abentley) wrote :

= Summary =
Make branch scanner event handling less fragile and surprising.

== Proposed fix ==
Use the standard zcml subscription mechanism.

== Pre-implementation notes ==
Pre-implementation was with thumper. jml and gary were also consulted.

== Implementation details ==
The bulk of this change is tests to verify that the handlers are subscribed
to the appropriate events.

The meat of it is configure.zcml, branchmailjob.py and branch_scanner.py, where
the homegrown subscription mechanism was replaced with configure.zcml.

Marking the event handlers as adapters is no longer necessary, so this was
changed. ZCML subscription requires that the events being subscribed to are
interfaces, so new interfaces were added for each event type.

ScannerEvent is (or became?) a classic class, so it and its subclasses were
switched from super...__init__ to Class.__init__self.

make_zope_event_fixture

== Tests ==
bin/test -vt test_buglinks -t test_bzrsync -t test_email -t test_mergedetection -t test_translationtemplatesbuildjob

== Demo and Q/A ==
N/A

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/lp/codehosting/scanner/tests/test_bzrsync.py
  lib/lp/code/configure.zcml
  lib/lp/translations/model/translationtemplatesbuildjob.py
  lib/lp/codehosting/scanner/tests/test_mergedetection.py
  lib/lp/codehosting/scanner/events.py
  lib/lp/codehosting/scanner/branch_scanner.py
  lib/lp/codehosting/scanner/buglinks.py
  lib/lp/translations/tests/test_translationtemplatesbuildjob.py
  lib/lp/codehosting/scanner/tests/test_email.py
  lib/lp/codehosting/scanner/fixture.py
  lib/lp/codehosting/scanner/tests/test_buglinks.py
  lib/lp/codehosting/scanner/bzrsync.py
  lib/lp/codehosting/scanner/mergedetection.py
  lib/lp/codehosting/scanner/email.py
  lib/lp/code/model/branchjob.py

== Pylint notices ==

lib/lp/codehosting/scanner/tests/test_mergedetection.py
    102: [C0301] Line too long (79/78)

lib/lp/codehosting/scanner/bzrsync.py
    29: [F0401] Unable to import 'lazr.uri' (No module named uri)

lib/lp/code/model/branchjob.py
    30: [F0401] Unable to import 'lazr.enum' (No module named enum)
    31: [F0401] Unable to import 'lazr.delegates' (No module named delegates)

Revision history for this message
Brad Crittenden (bac) wrote :

Hi Aaron,

The branch looks good with one silly comment:

> === modified file 'lib/lp/codehosting/scanner/branch_scanner.py'
> --- lib/lp/codehosting/scanner/branch_scanner.py 2010-02-15 16:46:42 +0000
> +++ lib/lp/codehosting/scanner/branch_scanner.py 2010-03-02 19:43:21 +0000
> @@ -14,17 +14,13 @@
>
> from bzrlib.errors import NotBranchError, ConnectionError
> # This non-standard import is necessary to hook up the event system.

Can you delete the comment now?

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/configure.zcml'
2--- lib/lp/code/configure.zcml 2010-02-20 04:51:43 +0000
3+++ lib/lp/code/configure.zcml 2010-03-04 02:17:22 +0000
4@@ -529,6 +529,30 @@
5 for="lp.code.interfaces.branch.IBranch
6 lazr.lifecycle.interfaces.IObjectCreatedEvent"
7 handler="canonical.launchpad.subscribers.karma.branch_created"/>
8+ <subscriber
9+ for="lp.codehosting.scanner.events.ITipChanged"
10+ handler="lp.codehosting.scanner.email.queue_tip_changed_email_jobs"/>
11+ <subscriber
12+ for="lp.codehosting.scanner.events.ITipChanged"
13+ handler="lp.codehosting.scanner.bzrsync.schedule_diff_updates"/>
14+ <subscriber
15+ for="lp.codehosting.scanner.events.ITipChanged"
16+ handler="lp.codehosting.scanner.bzrsync.schedule_translation_templates_build"/>
17+ <subscriber
18+ for="lp.codehosting.scanner.events.ITipChanged"
19+ handler="lp.codehosting.scanner.bzrsync.schedule_translation_upload"/>
20+ <subscriber
21+ for="lp.codehosting.scanner.events.IRevisionsRemoved"
22+ handler="lp.codehosting.scanner.email.send_removed_revision_emails"/>
23+ <subscriber
24+ for="lp.codehosting.scanner.events.INewRevision"
25+ handler="lp.codehosting.scanner.buglinks.got_new_revision"/>
26+ <subscriber
27+ for="lp.codehosting.scanner.events.IScanCompleted"
28+ handler="lp.codehosting.scanner.mergedetection.auto_merge_proposals"/>
29+ <subscriber
30+ for="lp.codehosting.scanner.events.IScanCompleted"
31+ handler="lp.codehosting.scanner.mergedetection.auto_merge_branches"/>
32
33 <!-- Temporarily disabling queues
34 <browser:page
35
36=== modified file 'lib/lp/code/model/branchjob.py'
37--- lib/lp/code/model/branchjob.py 2010-02-22 12:28:46 +0000
38+++ lib/lp/code/model/branchjob.py 2010-03-04 02:17:22 +0000
39@@ -49,12 +49,7 @@
40 from lp.code.model.branchmergeproposal import BranchMergeProposal
41 from lp.code.model.diff import StaticDiff
42 from lp.code.model.revision import RevisionSet
43-from lp.codehosting.scanner import buglinks, email, mergedetection
44-from lp.codehosting.scanner.fixture import (
45- Fixtures, ServerFixture, make_zope_event_fixture)
46-from lp.codehosting.scanner.bzrsync import (
47- BzrSync, schedule_diff_updates, schedule_translation_templates_build,
48- schedule_translation_upload)
49+from lp.codehosting.scanner.bzrsync import BzrSync
50 from lp.codehosting.vfs import (branch_id_to_path, get_multi_server,
51 get_scanner_server)
52 from lp.services.job.model.job import Job
53@@ -290,21 +285,9 @@
54 """See `IBranchScanJobSource`."""
55 errorlog.globalErrorUtility.configure('branchscanner')
56 cls.server = get_scanner_server()
57- event_handlers = [
58- email.queue_tip_changed_email_jobs,
59- buglinks.got_new_revision,
60- mergedetection.auto_merge_branches,
61- mergedetection.auto_merge_proposals,
62- schedule_diff_updates,
63- schedule_translation_templates_build,
64- schedule_translation_upload,
65- ]
66- fixture = Fixtures([
67- ServerFixture(cls.server),
68- make_zope_event_fixture(*event_handlers)])
69- fixture.setUp()
70+ cls.server.start_server()
71 yield
72- fixture.tearDown()
73+ cls.server.stop_server()
74
75
76 class BranchUpgradeJob(BranchJobDerived):
77
78=== modified file 'lib/lp/codehosting/scanner/branch_scanner.py'
79--- lib/lp/codehosting/scanner/branch_scanner.py 2010-02-15 16:46:42 +0000
80+++ lib/lp/codehosting/scanner/branch_scanner.py 2010-03-04 02:17:22 +0000
81@@ -14,17 +14,13 @@
82
83 from bzrlib.errors import NotBranchError, ConnectionError
84 # This non-standard import is necessary to hook up the event system.
85-import zope.component.event
86 from zope.component import getUtility
87
88 from lp.code.interfaces.branchscanner import IBranchScanner
89 from lp.codehosting.vfs import get_scanner_server
90-from lp.codehosting.scanner import buglinks, email, mergedetection
91-from lp.codehosting.scanner.bzrsync import (
92- BzrSync, schedule_diff_updates, schedule_translation_templates_build,
93- schedule_translation_upload)
94+from lp.codehosting.scanner.bzrsync import BzrSync
95 from lp.codehosting.scanner.fixture import (
96- Fixtures, make_zope_event_fixture, run_with_fixture, ServerFixture)
97+ run_with_fixture, ServerFixture)
98 from canonical.launchpad.webapp import canonical_url, errorlog
99
100
101@@ -92,18 +88,8 @@
102
103 def scanAllBranches(self):
104 """Run Bzrsync on all branches, and intercept most exceptions."""
105- event_handlers = [
106- email.queue_tip_changed_email_jobs,
107- buglinks.got_new_revision,
108- mergedetection.auto_merge_branches,
109- mergedetection.auto_merge_proposals,
110- schedule_diff_updates,
111- schedule_translation_templates_build,
112- schedule_translation_upload,
113- ]
114 server = get_scanner_server()
115- fixture = Fixtures(
116- [ServerFixture(server), make_zope_event_fixture(*event_handlers)])
117+ fixture = ServerFixture(server)
118 self.log.info('Starting branch scanning')
119 branches = getUtility(IBranchScanner).getBranchesToScan()
120 run_with_fixture(fixture, self.scanBranches, branches)
121
122=== modified file 'lib/lp/codehosting/scanner/buglinks.py'
123--- lib/lp/codehosting/scanner/buglinks.py 2009-07-17 00:26:05 +0000
124+++ lib/lp/codehosting/scanner/buglinks.py 2010-03-04 02:17:22 +0000
125@@ -11,11 +11,10 @@
126 import urlparse
127
128 from bzrlib.errors import InvalidBugStatus
129-from zope.component import adapter, getUtility
130+from zope.component import getUtility
131
132-from lp.codehosting.scanner import events
133 from canonical.launchpad.interfaces import (
134- IBugBranchSet, IBugSet, ILaunchpadCelebrities, NotFoundError)
135+ IBugSet, ILaunchpadCelebrities, NotFoundError)
136
137
138 class BugBranchLinker:
139@@ -89,7 +88,6 @@
140 registrant=getUtility(ILaunchpadCelebrities).janitor)
141
142
143-@adapter(events.NewRevision)
144 def got_new_revision(new_revision):
145 if new_revision.isMainline():
146 linker = BugBranchLinker(new_revision.db_branch)
147
148=== modified file 'lib/lp/codehosting/scanner/bzrsync.py'
149--- lib/lp/codehosting/scanner/bzrsync.py 2010-02-17 17:49:36 +0000
150+++ lib/lp/codehosting/scanner/bzrsync.py 2010-03-04 02:17:22 +0000
151@@ -18,7 +18,7 @@
152 import pytz
153 import transaction
154
155-from zope.component import adapter, getUtility
156+from zope.component import getUtility
157 from zope.event import notify
158
159 from bzrlib.branch import BzrBranchFormat4
160@@ -352,18 +352,15 @@
161 self.db_branch.updateScannedDetails(revision, revision_count)
162
163
164-@adapter(events.TipChanged)
165 def schedule_translation_upload(tip_changed):
166 getUtility(IRosettaUploadJobSource).create(
167 tip_changed.db_branch, tip_changed.old_tip_revision_id)
168
169
170-@adapter(events.TipChanged)
171 def schedule_translation_templates_build(tip_changed):
172 utility = getUtility(ITranslationTemplatesBuildJobSource)
173 utility.scheduleTranslationTemplatesBuild(tip_changed.db_branch)
174
175
176-@adapter(events.TipChanged)
177 def schedule_diff_updates(tip_changed):
178 tip_changed.db_branch.scheduleDiffUpdates()
179
180=== modified file 'lib/lp/codehosting/scanner/email.py'
181--- lib/lp/codehosting/scanner/email.py 2010-02-22 08:40:20 +0000
182+++ lib/lp/codehosting/scanner/email.py 2010-03-04 02:17:22 +0000
183@@ -9,13 +9,12 @@
184 'queue_tip_changed_email_jobs',
185 ]
186
187-from zope.component import adapter, getUtility
188+from zope.component import getUtility
189
190 from canonical.config import config
191 from lp.code.enums import BranchSubscriptionNotificationLevel
192 from lp.code.interfaces.branchjob import (
193 IRevisionsAddedJobSource, IRevisionMailJobSource)
194-from lp.codehosting.scanner import events
195
196
197 def subscribers_want_notification(db_branch):
198@@ -26,7 +25,6 @@
199 return subscriptions.count() > 0
200
201
202-@adapter(events.RevisionsRemoved)
203 def send_removed_revision_emails(revisions_removed):
204 """Notify subscribers of removed revisions.
205
206@@ -52,7 +50,6 @@
207 body=contents, perform_diff=False, subject=subject)
208
209
210-@adapter(events.TipChanged)
211 def queue_tip_changed_email_jobs(tip_changed):
212 if not subscribers_want_notification(tip_changed.db_branch):
213 return
214
215=== modified file 'lib/lp/codehosting/scanner/events.py'
216--- lib/lp/codehosting/scanner/events.py 2009-06-30 16:56:07 +0000
217+++ lib/lp/codehosting/scanner/events.py 2010-03-04 02:17:22 +0000
218@@ -11,7 +11,10 @@
219 ]
220
221
222-class ScannerEvent:
223+from zope.component.interfaces import IObjectEvent, implements, ObjectEvent
224+
225+
226+class ScannerEvent(ObjectEvent):
227 """Base scanner event."""
228
229 def __init__(self, db_branch, bzr_branch):
230@@ -20,13 +23,20 @@
231 :param db_branch: The database IBranch.
232 :param bzr_branch: The Bazaar branch being scanned.
233 """
234+ ObjectEvent.__init__(self, db_branch)
235 self.db_branch = db_branch
236 self.bzr_branch = bzr_branch
237
238
239+class INewRevision(IObjectEvent):
240+ """A new revision has been found in the branch."""
241+
242+
243 class NewRevision(ScannerEvent):
244 """A new revision has been found in the branch."""
245
246+ implements(INewRevision)
247+
248 def __init__(self, db_branch, bzr_branch, db_revision, bzr_revision,
249 revno):
250 """Construct a `NewRevision` event.
251@@ -38,7 +48,7 @@
252 :param revno: The revision number of the new revision, None if not
253 mainline.
254 """
255- super(NewRevision, self).__init__(db_branch, bzr_branch)
256+ ScannerEvent.__init__(self, db_branch, bzr_branch)
257 self.db_revision = db_revision
258 self.bzr_revision = bzr_revision
259 self.revno = revno
260@@ -48,8 +58,13 @@
261 return self.revno is not None
262
263
264+class ITipChanged(IObjectEvent):
265+ """The tip of the branch has changed."""
266+
267+
268 class TipChanged(ScannerEvent):
269 """The tip of the branch has changed."""
270+ implements(ITipChanged)
271
272 def __init__(self, db_branch, bzr_branch, initial_scan):
273 """Construct a `TipChanged` event.
274@@ -58,7 +73,7 @@
275 :param bzr_branch: The Bazaar branch.
276 :param initial_scan: Is this the first scan of the branch?
277 """
278- super(TipChanged, self).__init__(db_branch, bzr_branch)
279+ ScannerEvent.__init__(self, db_branch, bzr_branch)
280 self.initial_scan = initial_scan
281
282 @property
283@@ -72,9 +87,15 @@
284 return self.bzr_branch.last_revision()
285
286
287+class IRevisionsRemoved(IObjectEvent):
288+ """Revisions have been removed from the branch."""
289+
290+
291 class RevisionsRemoved(ScannerEvent):
292 """Revisions have been removed from the branch."""
293
294+ implements(IRevisionsRemoved)
295+
296 def __init__(self, db_branch, bzr_branch, removed_history):
297 """Construct a `RevisionsRemoved` event.
298
299@@ -83,13 +104,18 @@
300 :param removed_history: The mainline database `IRevision` objects that
301 are no longer present in the mainline of the Bazaar branch.
302 """
303- super(RevisionsRemoved, self).__init__(db_branch, bzr_branch)
304+ ScannerEvent.__init__(self, db_branch, bzr_branch)
305 self.removed_history = removed_history
306
307+class IScanCompleted(IObjectEvent):
308+ """The scan has been completed and the database is up-to-date."""
309+
310
311 class ScanCompleted(ScannerEvent):
312 """The scan has been completed and the database is up-to-date."""
313
314+ implements(IScanCompleted)
315+
316 def __init__(self, db_branch, bzr_branch, bzr_ancestry, logger):
317 """Construct a `ScanCompleted` event.
318
319@@ -100,7 +126,7 @@
320 :param logger: A Python logger object that's used to report incidental
321 information, such as merges that we find.
322 """
323- super(ScanCompleted, self).__init__(db_branch, bzr_branch)
324+ ScannerEvent.__init__(self, db_branch, bzr_branch)
325 self.bzr_ancestry = bzr_ancestry
326 # This is kind of ick. In a strict Zope sense, the logger should
327 # probably be a registered utility.
328
329=== modified file 'lib/lp/codehosting/scanner/fixture.py'
330--- lib/lp/codehosting/scanner/fixture.py 2010-02-01 04:37:39 +0000
331+++ lib/lp/codehosting/scanner/fixture.py 2010-03-04 02:17:22 +0000
332@@ -14,7 +14,6 @@
333 'Fixtures',
334 'FixtureWithCleanup',
335 'IFixture',
336- 'make_zope_event_fixture',
337 'run_with_fixture',
338 'ServerFixture',
339 'with_fixture',
340@@ -120,10 +119,6 @@
341 self.addCleanup(gsm.unregisterHandler, self._handler)
342
343
344-def make_zope_event_fixture(*handlers):
345- return Fixtures(map(ZopeEventHandlerFixture, handlers))
346-
347-
348 class ServerFixture:
349 """Adapt a bzrlib `Server` into an `IFixture`."""
350
351
352=== modified file 'lib/lp/codehosting/scanner/mergedetection.py'
353--- lib/lp/codehosting/scanner/mergedetection.py 2009-08-06 19:07:32 +0000
354+++ lib/lp/codehosting/scanner/mergedetection.py 2010-03-04 02:17:22 +0000
355@@ -11,9 +11,7 @@
356
357 from bzrlib.revision import NULL_REVISION
358
359-from zope.component import adapter, getUtility
360-
361-from lp.codehosting.scanner import events
362+from zope.component import getUtility
363
364 from lp.code.enums import BranchLifecycleStatus
365 from lp.code.interfaces.branchcollection import IAllBranches
366@@ -70,7 +68,6 @@
367 mark_branch_merged(logger, proposal.source_branch)
368
369
370-@adapter(events.ScanCompleted)
371 def auto_merge_branches(scan_completed):
372 """Detect branches that have been merged.
373
374@@ -117,7 +114,6 @@
375 merge_detected(logger, branch, db_branch)
376
377
378-@adapter(events.ScanCompleted)
379 def auto_merge_proposals(scan_completed):
380 """Detect merged proposals."""
381 db_branch = scan_completed.db_branch
382
383=== modified file 'lib/lp/codehosting/scanner/tests/test_buglinks.py'
384--- lib/lp/codehosting/scanner/tests/test_buglinks.py 2009-08-28 06:39:38 +0000
385+++ lib/lp/codehosting/scanner/tests/test_buglinks.py 2010-03-04 02:17:22 +0000
386@@ -8,8 +8,7 @@
387 import unittest
388
389 from bzrlib.revision import Revision
390-# This non-standard import is necessary to hook up the event system.
391-import zope.component.event
392+from zope.event import notify
393 from zope.component import getUtility
394
395 from canonical.config import config
396@@ -17,11 +16,12 @@
397 IBugBranchSet, IBugSet, NotFoundError)
398 from canonical.testing.layers import LaunchpadZopelessLayer
399
400-from lp.codehosting.scanner.buglinks import got_new_revision, BugBranchLinker
401-from lp.codehosting.scanner.fixture import make_zope_event_fixture
402+from lp.code.interfaces.revision import IRevisionSet
403+from lp.codehosting.scanner import events
404+from lp.codehosting.scanner.buglinks import BugBranchLinker
405 from lp.codehosting.scanner.tests.test_bzrsync import BzrSyncTestCase
406 from lp.registry.interfaces.pocket import PackagePublishingPocket
407-from lp.testing import TestCase
408+from lp.testing import TestCase, TestCaseWithFactory
409
410
411 class RevisionPropertyParsing(TestCase):
412@@ -108,9 +108,6 @@
413
414 def setUp(self):
415 BzrSyncTestCase.setUp(self)
416- fixture = make_zope_event_fixture(got_new_revision)
417- fixture.setUp()
418- self.addCleanup(fixture.tearDown)
419
420 def makeFixtures(self):
421 super(TestBugLinking, self).makeFixtures()
422@@ -243,5 +240,28 @@
423 self.assertBugBranchLinked(self.bug2, self.db_branch)
424
425
426+class TestSubscription(TestCaseWithFactory):
427+
428+ layer = LaunchpadZopelessLayer
429+
430+ def test_got_new_revision_subscribed(self):
431+ """got_new_revision is subscribed to NewRevision."""
432+ self.useBzrBranches()
433+ db_branch, tree = self.create_branch_and_tree()
434+ bug = self.factory.makeBug()
435+ self.layer.txn.commit()
436+ LaunchpadZopelessLayer.switchDbUser(config.branchscanner.dbuser)
437+ revision_id = tree.commit('fix revision',
438+ revprops={'bugs': 'https://launchpad.net/bugs/%d fixed' % bug.id})
439+ bzr_revision = tree.branch.repository.get_revision(revision_id)
440+ revno = 1
441+ revision_set = getUtility(IRevisionSet)
442+ db_revision = revision_set.newFromBazaarRevision(bzr_revision)
443+ notify(events.NewRevision(
444+ db_branch, tree.branch, db_revision, bzr_revision, revno))
445+ bug_branch = getUtility(IBugBranchSet).getBugBranch(bug, db_branch)
446+ self.assertIsNot(None, bug_branch)
447+
448+
449 def test_suite():
450 return unittest.TestLoader().loadTestsFromName(__name__)
451
452=== modified file 'lib/lp/codehosting/scanner/tests/test_bzrsync.py'
453--- lib/lp/codehosting/scanner/tests/test_bzrsync.py 2010-01-20 23:10:44 +0000
454+++ lib/lp/codehosting/scanner/tests/test_bzrsync.py 2010-03-04 02:17:22 +0000
455@@ -33,9 +33,7 @@
456 from lp.code.model.branchmergeproposaljob import IUpdatePreviewDiffJobSource
457 from lp.code.model.revision import Revision, RevisionAuthor, RevisionParent
458 from lp.codehosting.scanner.bzrsync import (
459- BzrSync, InvalidStackedBranchURL, schedule_diff_updates,
460- schedule_translation_upload)
461-from lp.codehosting.scanner.fixture import make_zope_event_fixture
462+ BzrSync, InvalidStackedBranchURL)
463 from lp.testing.factory import LaunchpadObjectFactory
464 from canonical.testing import LaunchpadZopelessLayer
465
466@@ -599,9 +597,6 @@
467
468 def setUp(self):
469 BzrSyncTestCase.setUp(self)
470- fixture = make_zope_event_fixture(schedule_translation_upload)
471- fixture.setUp()
472- self.addCleanup(fixture.tearDown)
473
474 def _makeProductSeries(self, mode = None):
475 """Switch to the Launchpad db user to create and configure a
476@@ -656,9 +651,6 @@
477 def setUp(self):
478 """Set up `schedule_diff_updates` to handle tip changes."""
479 BzrSyncTestCase.setUp(self)
480- fixture = make_zope_event_fixture(schedule_diff_updates)
481- fixture.setUp()
482- self.addCleanup(fixture.tearDown)
483
484 @run_as_db_user(config.launchpad.dbuser)
485 def test_create_on_new_revision(self):
486
487=== modified file 'lib/lp/codehosting/scanner/tests/test_email.py'
488--- lib/lp/codehosting/scanner/tests/test_email.py 2010-02-22 08:40:20 +0000
489+++ lib/lp/codehosting/scanner/tests/test_email.py 2010-03-04 02:17:22 +0000
490@@ -8,23 +8,22 @@
491 import email
492 import unittest
493
494-# This non-standard import is necessary to hook up the event system.
495-import zope.component.event
496+from zope.event import notify
497 from zope.component import getUtility
498
499+from canonical.testing import LaunchpadZopelessLayer
500 from lp.code.enums import (
501 BranchSubscriptionDiffSize, BranchSubscriptionNotificationLevel,
502 CodeReviewNotificationLevel)
503-from lp.codehosting.scanner.email import (
504- send_removed_revision_emails, queue_tip_changed_email_jobs)
505-from lp.codehosting.scanner.fixture import make_zope_event_fixture
506-from lp.codehosting.scanner.tests.test_bzrsync import BzrSyncTestCase
507 from lp.code.interfaces.branchjob import (
508 IRevisionMailJobSource, IRevisionsAddedJobSource)
509+from lp.code.model.branchjob import (RevisionMailJob)
510+from lp.codehosting.scanner import events
511+from lp.codehosting.scanner.tests.test_bzrsync import BzrSyncTestCase
512 from lp.registry.interfaces.person import IPersonSet
513 from lp.services.job.runner import JobRunner
514 from lp.services.mail import stub
515-from canonical.testing import LaunchpadZopelessLayer
516+from lp.testing import TestCaseWithFactory
517
518
519 class TestBzrSyncEmail(BzrSyncTestCase):
520@@ -32,10 +31,6 @@
521
522 def setUp(self):
523 BzrSyncTestCase.setUp(self)
524- fixture = make_zope_event_fixture(
525- queue_tip_changed_email_jobs, send_removed_revision_emails)
526- fixture.setUp()
527- self.addCleanup(fixture.tearDown)
528 stub.test_emails = []
529
530 def makeDatabaseBranch(self):
531@@ -141,6 +136,37 @@
532 self.assertTextIn(bit, recommit_email_body)
533
534
535+class TestScanBranches(TestCaseWithFactory):
536+
537+ layer = LaunchpadZopelessLayer
538+
539+ def test_queue_tip_changed_email_jobs_subscribed(self):
540+ """A queue_tip_changed_email_jobs is run when TipChanged emitted."""
541+ self.useBzrBranches()
542+ db_branch, tree = self.create_branch_and_tree()
543+ db_branch.subscribe(
544+ db_branch.registrant,
545+ BranchSubscriptionNotificationLevel.FULL,
546+ BranchSubscriptionDiffSize.WHOLEDIFF,
547+ CodeReviewNotificationLevel.FULL)
548+ self.assertEqual(0, len(list(RevisionMailJob.iterReady())))
549+ notify(events.TipChanged(db_branch, tree.branch, True))
550+ self.assertEqual(1, len(list(RevisionMailJob.iterReady())))
551+
552+ def test_send_removed_revision_emails_subscribed(self):
553+ """send_removed_revision_emails run when RevisionsRemoved emitted."""
554+ self.useBzrBranches()
555+ db_branch, tree = self.create_branch_and_tree()
556+ db_branch.subscribe(
557+ db_branch.registrant,
558+ BranchSubscriptionNotificationLevel.FULL,
559+ BranchSubscriptionDiffSize.WHOLEDIFF,
560+ CodeReviewNotificationLevel.FULL)
561+ self.assertEqual(0, len(list(RevisionMailJob.iterReady())))
562+ notify(events.RevisionsRemoved(db_branch, tree.branch, ['x']))
563+ self.assertEqual(1, len(list(RevisionMailJob.iterReady())))
564+
565+
566 class TestBzrSyncNoEmail(BzrSyncTestCase):
567 """Tests BzrSync support for not generating branch email notifications
568 when no one is interested.
569@@ -148,10 +174,6 @@
570
571 def setUp(self):
572 BzrSyncTestCase.setUp(self)
573- fixture = make_zope_event_fixture(
574- queue_tip_changed_email_jobs, send_removed_revision_emails)
575- fixture.setUp()
576- self.addCleanup(fixture.tearDown)
577 stub.test_emails = []
578
579 def assertNoPendingEmails(self):
580
581=== modified file 'lib/lp/codehosting/scanner/tests/test_mergedetection.py'
582--- lib/lp/codehosting/scanner/tests/test_mergedetection.py 2009-08-06 19:07:32 +0000
583+++ lib/lp/codehosting/scanner/tests/test_mergedetection.py 2010-03-04 02:17:22 +0000
584@@ -12,9 +12,9 @@
585 import transaction
586
587 from zope.component import getUtility
588+from zope.event import notify
589
590 from lp.codehosting.scanner import events
591-from lp.codehosting.scanner.fixture import make_zope_event_fixture
592 from lp.codehosting.scanner import mergedetection
593 from lp.codehosting.scanner.tests.test_bzrsync import (
594 BzrSyncTestCase, run_as_db_user)
595@@ -31,11 +31,6 @@
596
597 def setUp(self):
598 BzrSyncTestCase.setUp(self)
599- fixture = make_zope_event_fixture(
600- mergedetection.auto_merge_branches,
601- mergedetection.auto_merge_proposals)
602- fixture.setUp()
603- self.addCleanup(fixture.tearDown)
604
605 @run_as_db_user(config.launchpad.dbuser)
606 def createProposal(self, source, target):
607@@ -326,6 +321,17 @@
608 self.assertNotEqual(
609 BranchLifecycleStatus.MERGED, source.lifecycle_status)
610
611+ def test_auto_merge_branches_subscribed(self):
612+ """Auto merging is triggered by ScanCompleted."""
613+ source = self.factory.makeBranch()
614+ source.last_scanned_id = '23foo'
615+ target = self.factory.makeBranchTargetBranch(source.target)
616+ target.product.development_focus.branch = target
617+ logger = logging.getLogger('test')
618+ notify(events.ScanCompleted(target, None, ['23foo'], logger))
619+ self.assertEqual(
620+ BranchLifecycleStatus.MERGED, source.lifecycle_status)
621+
622
623 def test_suite():
624 return unittest.TestLoader().loadTestsFromName(__name__)
625
626=== modified file 'lib/lp/translations/model/translationtemplatesbuildjob.py'
627--- lib/lp/translations/model/translationtemplatesbuildjob.py 2010-02-17 23:31:40 +0000
628+++ lib/lp/translations/model/translationtemplatesbuildjob.py 2010-03-04 02:17:22 +0000
629@@ -35,6 +35,9 @@
630 Implementation-wise, this is actually a `BranchJob`.
631 """
632 implements(IBranchJob, IBuildFarmJob)
633+
634+ class_job_type = BranchJobType.TRANSLATION_TEMPLATES_BUILD
635+
636 classProvides(
637 ISpecificBuildFarmJobClass, ITranslationTemplatesBuildJobSource)
638
639
640=== modified file 'lib/lp/translations/tests/test_translationtemplatesbuildjob.py'
641--- lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-02-17 23:31:40 +0000
642+++ lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-03-04 02:17:22 +0000
643@@ -6,6 +6,7 @@
644 from unittest import TestLoader
645
646 from zope.component import getUtility
647+from zope.event import notify
648 from zope.security.proxy import removeSecurityProxy
649
650 from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
651@@ -23,6 +24,8 @@
652 IBuildFarmJobBehavior)
653 from lp.code.interfaces.branchjob import IBranchJob
654 from lp.code.model.branchjob import BranchJob
655+from lp.code.model.directbranchcommit import DirectBranchCommit
656+from lp.codehosting.scanner import events
657 from lp.services.job.model.job import Job
658 from lp.soyuz.interfaces.buildqueue import IBuildQueueSet
659 from lp.soyuz.model.buildqueue import BuildQueue
660@@ -214,6 +217,18 @@
661 removeSecurityProxy(branch).private = True
662 self.assertFalse(self.jobsource.generatesTemplates(branch))
663
664+ def test_scheduleTranslationTemplatesBuild_subscribed(self):
665+ # If the feature is enabled, a TipChanged event for a branch that
666+ # generates templates will schedule a templates build.
667+ branch = self._makeTranslationBranch()
668+ commit = DirectBranchCommit(branch, to_mirror=True)
669+ commit.writeFile('POTFILES.in', 'foo')
670+ commit.commit('message')
671+ notify(events.TipChanged(branch, None, False))
672+ branchjobs = list(TranslationTemplatesBuildJob.iterReady())
673+ self.assertEqual(1, len(branchjobs))
674+ self.assertEqual(branch, branchjobs[0].branch)
675+
676 def test_scheduleTranslationTemplatesBuild(self):
677 # If the feature is enabled, scheduleTranslationTemplatesBuild
678 # will schedule a templates build whenever a change is pushed to