Merge lp:~mwhudson/launchpad/pull-mirror-branches-separately-bug-520107 into lp:launchpad

Proposed by Michael Hudson-Doyle
Status: Merged
Approved by: Michael Hudson-Doyle
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~mwhudson/launchpad/pull-mirror-branches-separately-bug-520107
Merge into: lp:launchpad
Prerequisite: lp:~mwhudson/launchpad/remove-old-puller-xmlrpc-methods
Diff against target: 527 lines (+144/-46)
14 files modified
cronscripts/supermirror-pull.py (+3/-1)
lib/lp/code/errors.py (+5/-0)
lib/lp/code/interfaces/branch.py (+0/-4)
lib/lp/code/interfaces/branchpuller.py (+3/-1)
lib/lp/code/interfaces/codehosting.py (+4/-1)
lib/lp/code/model/branchpuller.py (+5/-2)
lib/lp/code/model/tests/test_branchpuller.py (+47/-9)
lib/lp/code/xmlrpc/codehosting.py (+11/-2)
lib/lp/code/xmlrpc/tests/test_codehosting.py (+17/-9)
lib/lp/codehosting/inmemory.py (+12/-2)
lib/lp/codehosting/puller/scheduler.py (+3/-2)
lib/lp/codehosting/puller/tests/test_acceptance.py (+19/-2)
lib/lp/codehosting/puller/tests/test_scheduler.py (+14/-10)
lib/lp/testing/factory.py (+1/-1)
To merge this branch: bzr merge lp:~mwhudson/launchpad/pull-mirror-branches-separately-bug-520107
Reviewer Review Type Date Requested Status
Tim Penhey (community) Approve
Review via email: mp+20032@code.launchpad.net

Commit message

Allow an invocation of supermirror-pull.py to only pull certain branch types.

To post a comment you must log in.
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

Mirrored branches are inherently less reliable to access than hosted or imported branches, so it makes sense to be able to handle them in a separate process, and that's what this branch does.

The default behavior is kept the same, we can coordinate with the LOSAs after rollout to set up two different cronjobs.

Revision history for this message
Tim Penhey (thumper) wrote :

Good except test_type_filter_hosted_imported_returns_imported which creates a hosted branch instead of an imported one.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cronscripts/supermirror-pull.py'
2--- cronscripts/supermirror-pull.py 2009-10-13 14:38:07 +0000
3+++ cronscripts/supermirror-pull.py 2010-02-24 19:04:21 +0000
4@@ -38,12 +38,14 @@
5 if __name__ == '__main__':
6 parser = OptionParser()
7 logger_options(parser)
8+ parser.add_option('--branch-type', action='append', default=[])
9 (options, arguments) = parser.parse_args()
10 if arguments:
11 parser.error("Unhandled arguments %s" % repr(arguments))
12 log = set_up_logging_for_script(options, 'supermirror_puller')
13 manager = scheduler.JobScheduler(
14- LoggingProxy(config.codehosting.branch_puller_endpoint, log), log)
15+ LoggingProxy(config.codehosting.branch_puller_endpoint, log), log,
16+ options.branch_type)
17
18 reactor.callWhenRunning(run_mirror, log, manager)
19 reactor.run()
20
21=== modified file 'lib/lp/code/errors.py'
22--- lib/lp/code/errors.py 2009-12-14 06:41:18 +0000
23+++ lib/lp/code/errors.py 2010-02-24 19:04:21 +0000
24@@ -11,6 +11,7 @@
25 'ClaimReviewFailed',
26 'InvalidBranchMergeProposal',
27 'ReviewNotPending',
28+ 'UnknownBranchTypeError',
29 'UserHasExistingReview',
30 'UserNotBranchReviewer',
31 'WrongBranchMergeProposal',
32@@ -59,3 +60,7 @@
33
34 class WrongBranchMergeProposal(Exception):
35 """The comment requested is not associated with this merge proposal."""
36+
37+
38+class UnknownBranchTypeError(Exception):
39+ """Raised when the user specifies an unrecognized branch type."""
40
41=== modified file 'lib/lp/code/interfaces/branch.py'
42--- lib/lp/code/interfaces/branch.py 2010-02-18 16:00:24 +0000
43+++ lib/lp/code/interfaces/branch.py 2010-02-24 19:04:21 +0000
44@@ -119,10 +119,6 @@
45 """The branch cannot be deleted at this time."""
46
47
48-class UnknownBranchTypeError(Exception):
49- """Raised when the user specifies an unrecognized branch type."""
50-
51-
52 class BranchCreationForbidden(BranchCreationException):
53 """A Branch visibility policy forbids branch creation.
54
55
56=== modified file 'lib/lp/code/interfaces/branchpuller.py'
57--- lib/lp/code/interfaces/branchpuller.py 2010-02-24 01:22:28 +0000
58+++ lib/lp/code/interfaces/branchpuller.py 2010-02-24 19:04:21 +0000
59@@ -23,9 +23,11 @@
60 MIRROR_TIME_INCREMENT = Attribute(
61 "How frequently we mirror branches.")
62
63- def acquireBranchToPull():
64+ def acquireBranchToPull(*branch_types):
65 """Return a Branch to pull and mark it as mirror-started.
66
67+ :param branch_types: Only return branches of these types. Passing no
68+ types means consider all types (apart from REMOTE).
69 :return: The branch object to pull next, or ``None`` if there is no
70 branch to pull.
71 """
72
73=== modified file 'lib/lp/code/interfaces/codehosting.py'
74--- lib/lp/code/interfaces/codehosting.py 2010-02-24 01:57:35 +0000
75+++ lib/lp/code/interfaces/codehosting.py 2010-02-24 19:04:21 +0000
76@@ -58,9 +58,12 @@
77 Published at 'branch_puller' on the private XML-RPC server.
78 """
79
80- def acquireBranchToPull():
81+ def acquireBranchToPull(branch_type_names):
82 """Return a Branch to pull and mark it as mirror-started.
83
84+ :param branch_type_names: Only consider branches of these type names.
85+ An empty list means consider HOSTED, MIRRORED and IMPORTED
86+ branches.
87 :return: A 5-tuple::
88
89 (branch_id, pull_url, unique_name, default_branch, branch_type)
90
91=== modified file 'lib/lp/code/model/branchpuller.py'
92--- lib/lp/code/model/branchpuller.py 2010-02-24 01:22:28 +0000
93+++ lib/lp/code/model/branchpuller.py 2010-02-24 19:04:21 +0000
94@@ -28,13 +28,16 @@
95 MAXIMUM_MIRROR_FAILURES = 5
96 MIRROR_TIME_INCREMENT = timedelta(hours=6)
97
98- def acquireBranchToPull(self):
99+ def acquireBranchToPull(self, *branch_types):
100 """See `IBranchPuller`."""
101+ if not branch_types:
102+ branch_types = (
103+ BranchType.HOSTED, BranchType.MIRRORED, BranchType.IMPORTED)
104 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
105 branch = store.find(
106 Branch,
107 Branch.next_mirror_time <= UTC_NOW,
108- Branch.branch_type != BranchType.REMOTE).order_by(
109+ Branch.branch_type.is_in(branch_types)).order_by(
110 Branch.next_mirror_time).first()
111 if branch is not None:
112 branch.startMirroring()
113
114=== modified file 'lib/lp/code/model/tests/test_branchpuller.py'
115--- lib/lp/code/model/tests/test_branchpuller.py 2010-02-24 01:22:28 +0000
116+++ lib/lp/code/model/tests/test_branchpuller.py 2010-02-24 19:04:21 +0000
117@@ -169,12 +169,22 @@
118 and `startMirroring` as appropriate.
119 """
120
121- def assertNoBranchIsAquired(self):
122- """Assert that there is no branch to pull."""
123+ def assertNoBranchIsAquired(self, *branch_types):
124+ """Assert that there is no branch to pull.
125+
126+ :param branch_types: A list of branch types to pass to
127+ acquireBranchToPull. Passing none means consider all types of
128+ branch.
129+ """
130 raise NotImplementedError(self.assertNoBranchIsAquired)
131
132- def assertBranchIsAquired(self, branch):
133- """Assert that ``branch`` is the next branch to be pulled."""
134+ def assertBranchIsAquired(self, branch, *branch_types):
135+ """Assert that ``branch`` is the next branch to be pulled.
136+
137+ :param branch_types: A list of branch types to pass to
138+ acquireBranchToPull. Passing none means consider all types of
139+ branch.
140+ """
141 raise NotImplementedError(self.assertBranchIsAquired)
142
143 def startMirroring(self, branch):
144@@ -202,7 +212,6 @@
145 removeSecurityProxy(branch).branch_type = BranchType.REMOTE
146 self.assertNoBranchIsAquired()
147
148-
149 def test_private(self):
150 # If there is a private branch that needs mirroring,
151 # acquireBranchToPull returns that.
152@@ -232,6 +241,33 @@
153 naked_second_branch.next_mirror_time -= timedelta(seconds=50)
154 self.assertBranchIsAquired(naked_first_branch)
155
156+ def test_type_filter_hosted_returns_hosted(self):
157+ branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED)
158+ branch.requestMirror()
159+ self.assertBranchIsAquired(branch, BranchType.HOSTED)
160+
161+ def test_type_filter_hosted_does_not_return_mirrored(self):
162+ branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)
163+ branch.requestMirror()
164+ self.assertNoBranchIsAquired(BranchType.HOSTED)
165+
166+ def test_type_filter_mirrored_does_not_return_hosted(self):
167+ branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED)
168+ branch.requestMirror()
169+ self.assertNoBranchIsAquired(BranchType.MIRRORED)
170+
171+ def test_type_filter_hosted_imported_returns_hosted(self):
172+ branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED)
173+ branch.requestMirror()
174+ self.assertBranchIsAquired(
175+ branch, BranchType.HOSTED, BranchType.IMPORTED)
176+
177+ def test_type_filter_hosted_imported_returns_imported(self):
178+ branch = self.factory.makeAnyBranch(branch_type=BranchType.IMPORTED)
179+ branch.requestMirror()
180+ self.assertBranchIsAquired(
181+ branch, BranchType.HOSTED, BranchType.IMPORTED)
182+
183
184 class TestAcquireBranchToPullDirectly(TestCaseWithFactory,
185 AcquireBranchToPullTests):
186@@ -239,14 +275,16 @@
187
188 layer = DatabaseFunctionalLayer
189
190- def assertNoBranchIsAquired(self):
191+ def assertNoBranchIsAquired(self, *branch_types):
192 """See `AcquireBranchToPullTests`."""
193- acquired_branch = getUtility(IBranchPuller).acquireBranchToPull()
194+ acquired_branch = getUtility(IBranchPuller).acquireBranchToPull(
195+ *branch_types)
196 self.assertEqual(None, acquired_branch)
197
198- def assertBranchIsAquired(self, branch):
199+ def assertBranchIsAquired(self, branch, *branch_types):
200 """See `AcquireBranchToPullTests`."""
201- acquired_branch = getUtility(IBranchPuller).acquireBranchToPull()
202+ acquired_branch = getUtility(IBranchPuller).acquireBranchToPull(
203+ *branch_types)
204 login_person(removeSecurityProxy(branch).owner)
205 self.assertEqual(branch, acquired_branch)
206 self.assertIsNot(None, acquired_branch.last_mirror_attempt)
207
208=== modified file 'lib/lp/code/xmlrpc/codehosting.py'
209--- lib/lp/code/xmlrpc/codehosting.py 2010-02-24 01:22:28 +0000
210+++ lib/lp/code/xmlrpc/codehosting.py 2010-02-24 19:04:21 +0000
211@@ -23,6 +23,7 @@
212 from zope.security.proxy import removeSecurityProxy
213
214 from canonical.launchpad.ftests import login_person, logout
215+from lp.code.errors import UnknownBranchTypeError
216 from lp.code.enums import BranchType
217 from lp.code.interfaces.branch import BranchCreationException
218 from lp.code.interfaces.branchlookup import IBranchLookup
219@@ -54,9 +55,17 @@
220
221 implements(IBranchPuller)
222
223- def acquireBranchToPull(self):
224+ def acquireBranchToPull(self, branch_type_names):
225 """See `IBranchPuller`."""
226- branch = getUtility(branchpuller.IBranchPuller).acquireBranchToPull()
227+ branch_types = []
228+ for branch_type_name in branch_type_names:
229+ try:
230+ branch_types.append(BranchType.items[branch_type_name])
231+ except KeyError:
232+ raise UnknownBranchTypeError(
233+ 'Unknown branch type: %r' % (branch_type_name,))
234+ branch = getUtility(branchpuller.IBranchPuller).acquireBranchToPull(
235+ *branch_types)
236 if branch is not None:
237 branch = removeSecurityProxy(branch)
238 default_branch = branch.target.default_stacked_on_branch
239
240=== modified file 'lib/lp/code/xmlrpc/tests/test_codehosting.py'
241--- lib/lp/code/xmlrpc/tests/test_codehosting.py 2010-02-24 01:57:35 +0000
242+++ lib/lp/code/xmlrpc/tests/test_codehosting.py 2010-02-24 19:04:21 +0000
243@@ -30,6 +30,7 @@
244 from canonical.testing import DatabaseFunctionalLayer, FunctionalLayer
245
246 from lp.code.enums import BranchType
247+from lp.code.errors import UnknownBranchTypeError
248 from lp.code.interfaces.branch import BRANCH_NAME_VALIDATION_ERROR_MESSAGE
249 from lp.code.interfaces.branchlookup import IBranchLookup
250 from lp.code.interfaces.branchtarget import IBranchTarget
251@@ -409,15 +410,17 @@
252 self.storage = frontend.getPullerEndpoint()
253 self.factory = frontend.getLaunchpadObjectFactory()
254
255- def assertNoBranchIsAquired(self):
256+ def assertNoBranchIsAquired(self, *branch_types):
257 """See `AcquireBranchToPullTests`."""
258- pull_info = self.storage.acquireBranchToPull()
259+ branch_types = tuple(branch_type.name for branch_type in branch_types)
260+ pull_info = self.storage.acquireBranchToPull(branch_types)
261 self.assertEqual((), pull_info)
262
263- def assertBranchIsAquired(self, branch):
264+ def assertBranchIsAquired(self, branch, *branch_types):
265 """See `AcquireBranchToPullTests`."""
266 branch = removeSecurityProxy(branch)
267- pull_info = self.storage.acquireBranchToPull()
268+ branch_types = tuple(branch_type.name for branch_type in branch_types)
269+ pull_info = self.storage.acquireBranchToPull(branch_types)
270 default_branch = branch.target.default_stacked_on_branch
271 if default_branch:
272 default_branch_name = default_branch
273@@ -437,21 +440,21 @@
274 def test_branch_type_returned_hosted(self):
275 branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED)
276 branch.requestMirror()
277- pull_info = self.storage.acquireBranchToPull()
278+ pull_info = self.storage.acquireBranchToPull(())
279 _, _, _, _, branch_type = pull_info
280 self.assertEqual('HOSTED', branch_type)
281
282 def test_branch_type_returned_mirrored(self):
283 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)
284 branch.requestMirror()
285- pull_info = self.storage.acquireBranchToPull()
286+ pull_info = self.storage.acquireBranchToPull(())
287 _, _, _, _, branch_type = pull_info
288 self.assertEqual('MIRRORED', branch_type)
289
290 def test_branch_type_returned_import(self):
291 branch = self.factory.makeAnyBranch(branch_type=BranchType.IMPORTED)
292 branch.requestMirror()
293- pull_info = self.storage.acquireBranchToPull()
294+ pull_info = self.storage.acquireBranchToPull(())
295 _, _, _, _, branch_type = pull_info
296 self.assertEqual('IMPORTED', branch_type)
297
298@@ -459,7 +462,7 @@
299 branch = self.factory.makeProductBranch()
300 self.factory.enableDefaultStackingForProduct(branch.product)
301 branch.requestMirror()
302- pull_info = self.storage.acquireBranchToPull()
303+ pull_info = self.storage.acquireBranchToPull(())
304 _, _, _, default_stacked_on_branch, _ = pull_info
305 self.assertEqual(
306 default_stacked_on_branch,
307@@ -475,11 +478,16 @@
308 mirrored_branch = self.factory.makeProductBranch(
309 branch_type=BranchType.MIRRORED, product=product)
310 mirrored_branch.requestMirror()
311- pull_info = self.storage.acquireBranchToPull()
312+ pull_info = self.storage.acquireBranchToPull(())
313 _, _, _, default_stacked_on_branch, _ = pull_info
314 self.assertEqual(
315 '', default_stacked_on_branch)
316
317+ def test_unknown_branch_type_name_raises(self):
318+ self.assertRaises(
319+ UnknownBranchTypeError, self.storage.acquireBranchToPull,
320+ ('NO_SUCH_TYPE',))
321+
322
323 class BranchFileSystemTest(TestCaseWithFactory):
324 """Tests for the implementation of `IBranchFileSystem`."""
325
326=== modified file 'lib/lp/codehosting/inmemory.py'
327--- lib/lp/codehosting/inmemory.py 2010-02-24 01:57:35 +0000
328+++ lib/lp/codehosting/inmemory.py 2010-02-24 19:04:21 +0000
329@@ -18,6 +18,7 @@
330 from zope.interface import implementer
331
332 from canonical.database.constants import UTC_NOW
333+from lp.code.errors import UnknownBranchTypeError
334 from lp.code.model.branchnamespace import BranchNamespaceSet
335 from lp.code.model.branchtarget import (
336 PackageBranchTarget, ProductBranchTarget)
337@@ -442,11 +443,20 @@
338 self._branch_set = branch_set
339 self._script_activity_set = script_activity_set
340
341- def acquireBranchToPull(self):
342+ def acquireBranchToPull(self, branch_type_names):
343+ if not branch_type_names:
344+ branch_type_names = 'HOSTED', 'MIRRORED', 'IMPORTED'
345+ branch_types = []
346+ for branch_type_name in branch_type_names:
347+ try:
348+ branch_types.append(BranchType.items[branch_type_name])
349+ except KeyError:
350+ raise UnknownBranchTypeError(
351+ 'Unknown branch type: %r' % (branch_type_name,))
352 branches = sorted(
353 [branch for branch in self._branch_set
354 if branch.next_mirror_time is not None
355- and branch.branch_type != BranchType.REMOTE],
356+ and branch.branch_type in branch_types],
357 key=operator.attrgetter('next_mirror_time'))
358 if branches:
359 branch = branches[-1]
360
361=== modified file 'lib/lp/codehosting/puller/scheduler.py'
362--- lib/lp/codehosting/puller/scheduler.py 2009-12-22 00:26:49 +0000
363+++ lib/lp/codehosting/puller/scheduler.py 2010-02-24 19:04:21 +0000
364@@ -417,9 +417,10 @@
365 branches.
366 """
367
368- def __init__(self, branch_puller_endpoint, logger):
369+ def __init__(self, branch_puller_endpoint, logger, branch_type_names):
370 self.branch_puller_endpoint = branch_puller_endpoint
371 self.logger = logger
372+ self.branch_type_names = branch_type_names
373 self.actualLock = None
374 self.name = 'branch-puller'
375 self.lockfilename = '/var/lock/launchpad-%s.lock' % self.name
376@@ -455,7 +456,7 @@
377
378 def _poll(self):
379 deferred = self.branch_puller_endpoint.callRemote(
380- 'acquireBranchToPull')
381+ 'acquireBranchToPull', self.branch_type_names)
382 deferred.addCallback(self._turnJobTupleIntoTask)
383 return deferred
384
385
386=== modified file 'lib/lp/codehosting/puller/tests/test_acceptance.py'
387--- lib/lp/codehosting/puller/tests/test_acceptance.py 2010-01-20 20:56:29 +0000
388+++ lib/lp/codehosting/puller/tests/test_acceptance.py 2010-02-24 19:04:21 +0000
389@@ -122,7 +122,7 @@
390 output, error = process.communicate()
391 return process.returncode, output, error
392
393- def runPuller(self):
394+ def runPuller(self, *args):
395 """Run the puller script for the given branch type.
396
397 :param branch_type: One of 'upload', 'mirror' or 'import'
398@@ -132,7 +132,7 @@
399 stdout and stderr respectively.
400 """
401 command = [
402- '%s/bin/py' % config.root, self._puller_script, '-q']
403+ '%s/bin/py' % config.root, self._puller_script, '-q'] + list(args)
404 retcode, output, error = self.runSubprocess(command)
405 return command, retcode, output, error
406
407@@ -430,6 +430,23 @@
408 command, retcode, output, error = self.runPuller()
409 self.assertRanSuccessfully(command, retcode, output, error)
410
411+ def test_type_filtering(self):
412+ # When run with --branch-type arguments, the puller only mirrors those
413+ # branches of the specified types.
414+ hosted_branch = self.factory.makeAnyBranch(
415+ branch_type=BranchType.HOSTED)
416+ mirrored_branch = self.factory.makeAnyBranch(
417+ branch_type=BranchType.MIRRORED)
418+ mirrored_branch.requestMirror()
419+ transaction.commit()
420+ self.pushBranch(hosted_branch)
421+ command, retcode, output, error = self.runPuller(
422+ '--branch-type', 'HOSTED')
423+ self.assertRanSuccessfully(command, retcode, output, error)
424+ self.assertMirrored(hosted_branch)
425+ self.assertIsNot(
426+ None, mirrored_branch.next_mirror_time)
427+
428 def test_records_script_activity(self):
429 # A record gets created in the ScriptActivity table.
430 script_activity_set = getUtility(IScriptActivitySet)
431
432=== modified file 'lib/lp/codehosting/puller/tests/test_scheduler.py'
433--- lib/lp/codehosting/puller/tests/test_scheduler.py 2010-01-08 03:07:25 +0000
434+++ lib/lp/codehosting/puller/tests/test_scheduler.py 2010-02-24 19:04:21 +0000
435@@ -8,7 +8,6 @@
436 from datetime import datetime
437 import logging
438 import os
439-import sys
440 import textwrap
441 import unittest
442
443@@ -42,8 +41,7 @@
444
445 class FakePullerEndpointProxy:
446
447- def __init__(self, branch_queues=None):
448- self.branch_queues = branch_queues
449+ def __init__(self):
450 self.calls = []
451
452 def callRemote(self, method_name, *args):
453@@ -58,8 +56,8 @@
454 def _default(self, *args):
455 return defer.succeed(None)
456
457- def _remote_getBranchPullQueue(self, branch_type):
458- return defer.succeed(self.branch_queues[branch_type])
459+ def _remote_acquireBranchToPull(self, *args):
460+ return defer.succeed(0)
461
462 def _remote_setStackedOn(self, branch_id, stacked_on_location):
463 if stacked_on_location == 'raise-branch-not-found':
464@@ -70,7 +68,7 @@
465 return defer.succeed(None)
466
467
468-class TestJobScheduler(unittest.TestCase):
469+class TestJobScheduler(TrialTestCase):
470
471 def setUp(self):
472 self.masterlock = 'master.lock'
473@@ -80,8 +78,9 @@
474 if os.path.exists(self.masterlock):
475 os.unlink(self.masterlock)
476
477- def makeJobScheduler(self):
478- return scheduler.JobScheduler(None, logging.getLogger())
479+ def makeJobScheduler(self, branch_type_names=()):
480+ return scheduler.JobScheduler(
481+ FakePullerEndpointProxy(), logging.getLogger(), branch_type_names)
482
483 def testManagerCreatesLocks(self):
484 manager = self.makeJobScheduler()
485@@ -100,6 +99,13 @@
486 self.failUnless(os.path.exists(self.masterlock))
487 manager.unlock()
488
489+ def test_run_calls_acquireBranchToPull(self):
490+ manager = self.makeJobScheduler(('HOSTED',))
491+ manager.run()
492+ self.assertEqual(
493+ [('acquireBranchToPull', ('HOSTED',))],
494+ manager.branch_puller_endpoint.calls)
495+
496
497 class TestPullerWireProtocol(TrialTestCase):
498 """Tests for the `PullerWireProtocol`.
499@@ -516,7 +522,6 @@
500 layer = TwistedLayer
501
502 def setUp(self):
503- from twisted.internet import reactor
504 self.factory = ObjectFactory()
505 self.available_oops_prefixes = set(['foo'])
506 self.eventHandler = self.makePullerMaster(
507@@ -526,7 +531,6 @@
508 self.commands_spawned = []
509
510 def tearDown(self):
511- from twisted.internet import reactor
512 reactor.spawnProcess = self._realSpawnProcess
513
514 def makePullerMaster(self, branch_type_name, default_stacked_on_url=None,
515
516=== modified file 'lib/lp/testing/factory.py'
517--- lib/lp/testing/factory.py 2010-02-23 20:02:07 +0000
518+++ lib/lp/testing/factory.py 2010-02-24 19:04:21 +0000
519@@ -93,7 +93,7 @@
520 BranchType, CodeImportMachineState, CodeImportReviewStatus,
521 CodeImportResultStatus, CodeReviewNotificationLevel,
522 RevisionControlSystems)
523-from lp.code.interfaces.branch import UnknownBranchTypeError
524+from lp.code.errors import UnknownBranchTypeError
525 from lp.code.interfaces.branchmergequeue import IBranchMergeQueueSet
526 from lp.code.interfaces.branchnamespace import get_branch_namespace
527 from lp.code.interfaces.codeimport import ICodeImportSet