Merge lp://staging/~jtv/launchpad/bug-500110 into lp://staging/launchpad

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: not available
Merged at revision: not available
Proposed branch: lp://staging/~jtv/launchpad/bug-500110
Merge into: lp://staging/launchpad
Diff against target: 599 lines (+226/-90)
14 files modified
lib/lp/buildmaster/doc/buildfarmjob.txt (+20/-0)
lib/lp/buildmaster/interfaces/buildfarmjob.py (+17/-0)
lib/lp/buildmaster/model/buildfarmjob.py (+18/-3)
lib/lp/code/model/branchjob.py (+2/-0)
lib/lp/soyuz/interfaces/buildqueue.py (+10/-3)
lib/lp/soyuz/model/buildpackagejob.py (+2/-1)
lib/lp/soyuz/model/buildqueue.py (+13/-11)
lib/lp/soyuz/tests/test_buildqueue.py (+26/-0)
lib/lp/translations/configure.zcml (+4/-2)
lib/lp/translations/doc/translationtemplatesbuildbehavior.txt (+82/-0)
lib/lp/translations/interfaces/translationtemplatesbuildjob.py (+3/-14)
lib/lp/translations/model/translationtemplatesbuildbehavior.py (+8/-36)
lib/lp/translations/model/translationtemplatesbuildjob.py (+9/-6)
lib/lp/translations/tests/test_translationtemplatesbuildjob.py (+12/-14)
To merge this branch: bzr merge lp://staging/~jtv/launchpad/bug-500110
Reviewer Review Type Date Requested Status
Muharem Hrnjadovic (community) code Approve
Review via email: mp+17272@code.staging.launchpad.net

Commit message

Get generalised IBuildFarmJobs into a testable state.

To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :
Download full text (4.7 KiB)

= Bug 500110 =

This code is what it takes to get a new IBuildFarmJobBehavior implementation tested. Actually the diff is quite diverse, so I'll go through it step by step.

The diff starts with lib/lp/buildmaster/doc/buildfarmjob.txt:

BuildQueue.specific_job retrieves a build farm job based on two elements: the specific class of build farm job that it wants (implementing IBuildFarmJob, of course), and the Job it's attached to. It takes those two elements straight into an ORM query. Unfortunately the TranslationTemplatesBuildJob has no database story of its own, and so can't be queried in this way.

To get around this, I had BuildQueue delegate this query to the specific build farm job class. BuildFarmJob, the base class for these classes, now contains the generic implementation that was previously in BuildQueue.specific_job; TranslationTemplatesBuildJob overrides it for its specific case.

The new method is called getByJob. It's a class method, not a regular method, and is declared in a new interface ISpecificBuildFarmJobClass. The new doctest verifies that BranchJob and its descendants provide this interface.

lib/lp/buildmaster/interfaces/buildfarmjob.py contains the new interface. It's very simple, but named to allow future extension. This can be useful if we find ourselves tempted to put methods in IBuildFarmJobBehavior that really aren't related to build behaviour.

lib/lp/buildmaster/model/buildfarmjob.py implements the new method for all build-farm job classes except the Translations one. This is one of the rare cases where the "cls" argument to class methods is actually useful: it is the specific build farm job class that the method needs to look up, not the one it is defined in.

lib/lp/code/model/branchjob.py exports a few extra classes. Without this, implementing BranchJob descendants outside of this class results in warnings about import policy violations.

lib/lp/soyuz/interfaces/buildqueue.py has two separate utility changes:
 1. Some job_id parameters are renamed buildqueue_id to avoid the impression that they might be job ids. They are really buildqueue ids; I haven't changed them apart from renaming them.
 2. A new method getByJob is similar to the one in BuildFarmJob, but looks up a BuildQueue instead.

lib/lp/soyuz/model/buildpackagejob.py: since BuildFarmJob now contains an essential bit of functionality for finding specific jobs, BuildPackageJob does now need to inherit from it to benefit from the generic implementation.

lib/lp/soyuz/model/buildqueue.py reflects the changes in the matching interface file.

lib/lp/soyuz/tests/test_buildqueue.py has grown a test for the BuildQueueSet utility.

lib/lp/translations/configure.zcml shows a simplification: now that the BuildFarmJob hierarchy has a getByJob, there is no longer any reason for ITranslationTemplatesBuildJob. Instead, TranslationTemplatesBuildJob implements IBranchJob and IBuildFarmJob directly.

lib/lp/translations/doc/translationtemplatesbuildbehavior.txt is where it all comes together. It started out as a copy of the initial part of lib/lp/soyuz/doc/buildd-dispatching.txt. I left out some irrelevant parts, generalized a bit, and removed some relia...

Read more...

Revision history for this message
Muharem Hrnjadovic (al-maisan) wrote :

Looks great! Go ahead and land it.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'lib/lp/buildmaster/doc/buildfarmjob.txt'
2--- lib/lp/buildmaster/doc/buildfarmjob.txt 1970-01-01 00:00:00 +0000
3+++ lib/lp/buildmaster/doc/buildfarmjob.txt 2010-01-14 09:57:16 +0000
4@@ -0,0 +1,20 @@
5+= BuildFarmJob =
6+
7+ >>> from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
8+ >>> from lp.buildmaster.model.buildfarmjob import BuildFarmJob
9+
10+BuildFarmJob provides a basic implementation of IBuildFarmJob. The
11+specific build farm job classes should inherit from it.
12+
13+ >>> buildfarmjob = BuildFarmJob()
14+ >>> verifyObject(IBuildFarmJob, buildfarmjob)
15+ True
16+
17+As a class, it also provides ISpecificBuildFarmJobClass so that
18+BuildQueue can find the instance of a specific build-farm job
19+implementation associated with a given Job instance.
20+
21+ >>> from lp.buildmaster.interfaces.buildfarmjob import (
22+ ... ISpecificBuildFarmJobClass)
23+ >>> verifyObject(ISpecificBuildFarmJobClass, BuildFarmJob)
24+ True
25
26=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
27--- lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-01-08 12:26:22 +0000
28+++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-01-14 09:57:16 +0000
29@@ -10,6 +10,7 @@
30 __all__ = [
31 'IBuildFarmJob',
32 'IBuildFarmJobDispatchEstimation',
33+ 'ISpecificBuildFarmJobClass',
34 'BuildFarmJobType',
35 ]
36
37@@ -87,6 +88,22 @@
38 "return None."))
39
40
41+
42+class ISpecificBuildFarmJobClass(Interface):
43+ """Class interface provided by `IBuildFarmJob` classes.
44+
45+ Used by the `BuildQueue` to find the specific build-farm job objects
46+ it needs to dispatch to builders.
47+ """
48+
49+ def getByJob(job):
50+ """Get the specific `IBuildFarmJob` for the given `Job`.
51+
52+ Invoked on the specific `IBuildFarmJob`-implementing class that
53+ has an entry associated with `job`.
54+ """
55+
56+
57 class IBuildFarmJobDispatchEstimation(Interface):
58 """Operations needed for job dipatch time estimation."""
59
60
61=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
62--- lib/lp/buildmaster/model/buildfarmjob.py 2009-12-24 13:18:16 +0000
63+++ lib/lp/buildmaster/model/buildfarmjob.py 2010-01-14 09:57:16 +0000
64@@ -5,14 +5,20 @@
65 __all__ = ['BuildFarmJob']
66
67
68-from zope.interface import implements
69-
70-from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
71+from zope.component import getUtility
72+from zope.interface import classProvides, implements
73+
74+from canonical.launchpad.webapp.interfaces import (
75+ DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE)
76+
77+from lp.buildmaster.interfaces.buildfarmjob import (
78+ IBuildFarmJob, ISpecificBuildFarmJobClass)
79
80
81 class BuildFarmJob:
82 """Mix-in class for `IBuildFarmJob` implementations."""
83 implements(IBuildFarmJob)
84+ classProvides(ISpecificBuildFarmJobClass)
85
86 def score(self):
87 """See `IBuildFarmJob`."""
88@@ -48,3 +54,12 @@
89 """See `IBuildFarmJob`."""
90 return None
91
92+ @classmethod
93+ def getByJob(cls, job):
94+ """See `ISpecificBuildFarmJobClass`.
95+
96+ This base implementation should work for most build farm job
97+ types, but some need to override it.
98+ """
99+ store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
100+ return store.find(cls, cls.job == job).one()
101
102=== modified file 'lib/lp/code/model/branchjob.py'
103--- lib/lp/code/model/branchjob.py 2010-01-12 18:13:55 +0000
104+++ lib/lp/code/model/branchjob.py 2010-01-14 09:57:16 +0000
105@@ -3,6 +3,8 @@
106
107 __all__ = [
108 'BranchJob',
109+ 'BranchJobDerived',
110+ 'BranchJobType',
111 'BranchUpgradeJob',
112 'RevisionsAddedJob',
113 'RevisionMailJob',
114
115=== modified file 'lib/lp/soyuz/interfaces/buildqueue.py'
116--- lib/lp/soyuz/interfaces/buildqueue.py 2010-01-07 04:07:09 +0000
117+++ lib/lp/soyuz/interfaces/buildqueue.py 2010-01-14 09:57:16 +0000
118@@ -126,14 +126,21 @@
119 def __iter__():
120 """Iterate over current build jobs."""
121
122- def __getitem__(job_id):
123+ def __getitem__(buildqueue_id):
124 """Retrieve a build job by id."""
125
126 def count():
127 """Return the number of build jobs in the queue."""
128
129- def get(job_id):
130- """Return the IBuildQueue with the given job_id."""
131+ def get(buildqueue_id):
132+ """Return the `IBuildQueue` with the given id."""
133+
134+ def getByJob(job):
135+ """Find the `IBuildQueue` to which `job` belongs.
136+
137+ :param job: A `Job`.
138+ :return: The matching `IBuildQueue`, or None.
139+ """
140
141 def getByBuilder(builder):
142 """Return an IBuildQueue instance for a builder.
143
144=== modified file 'lib/lp/soyuz/model/buildpackagejob.py'
145--- lib/lp/soyuz/model/buildpackagejob.py 2010-01-12 10:44:24 +0000
146+++ lib/lp/soyuz/model/buildpackagejob.py 2010-01-14 09:57:16 +0000
147@@ -17,6 +17,7 @@
148
149 from lp.buildmaster.interfaces.buildfarmjob import (
150 BuildFarmJobType, IBuildFarmJobDispatchEstimation)
151+from lp.buildmaster.model.buildfarmjob import BuildFarmJob
152 from lp.registry.interfaces.sourcepackage import SourcePackageUrgency
153 from lp.registry.interfaces.pocket import PackagePublishingPocket
154 from lp.services.job.interfaces.job import JobStatus
155@@ -25,7 +26,7 @@
156 from lp.soyuz.interfaces.buildpackagejob import IBuildPackageJob
157
158
159-class BuildPackageJob(Storm):
160+class BuildPackageJob(Storm, BuildFarmJob):
161 """See `IBuildPackageJob`."""
162 implements(IBuildPackageJob)
163 classProvides(IBuildFarmJobDispatchEstimation)
164
165=== modified file 'lib/lp/soyuz/model/buildqueue.py'
166--- lib/lp/soyuz/model/buildqueue.py 2010-01-11 23:48:25 +0000
167+++ lib/lp/soyuz/model/buildqueue.py 2010-01-14 09:57:16 +0000
168@@ -78,10 +78,7 @@
169 def specific_job(self):
170 """See `IBuildQueue`."""
171 specific_class = self.specific_job_classes[self.job_type]
172- store = Store.of(self)
173- result_set = store.find(
174- specific_class, specific_class.job == self.job)
175- return result_set.one()
176+ return specific_class.getByJob(self.job)
177
178 @property
179 def date_started(self):
180@@ -324,16 +321,21 @@
181 """See `IBuildQueueSet`."""
182 return iter(BuildQueue.select())
183
184- def __getitem__(self, job_id):
185+ def __getitem__(self, buildqueue_id):
186 """See `IBuildQueueSet`."""
187 try:
188- return BuildQueue.get(job_id)
189+ return BuildQueue.get(buildqueue_id)
190 except SQLObjectNotFound:
191- raise NotFoundError(job_id)
192-
193- def get(self, job_id):
194- """See `IBuildQueueSet`."""
195- return BuildQueue.get(job_id)
196+ raise NotFoundError(buildqueue_id)
197+
198+ def get(self, buildqueue_id):
199+ """See `IBuildQueueSet`."""
200+ return BuildQueue.get(buildqueue_id)
201+
202+ def getByJob(self, job):
203+ """See `IBuildQueueSet`."""
204+ store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
205+ return store.find(BuildQueue, BuildQueue.job == job).one()
206
207 def count(self):
208 """See `IBuildQueueSet`."""
209
210=== modified file 'lib/lp/soyuz/tests/test_buildqueue.py'
211--- lib/lp/soyuz/tests/test_buildqueue.py 2010-01-11 23:43:59 +0000
212+++ lib/lp/soyuz/tests/test_buildqueue.py 2010-01-14 09:57:16 +0000
213@@ -8,15 +8,19 @@
214 from pytz import utc
215
216 from zope.component import getUtility
217+from zope.interface.verify import verifyObject
218
219 from canonical.launchpad.webapp.interfaces import (
220 IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)
221 from canonical.testing import LaunchpadZopelessLayer
222
223 from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType
224+from lp.services.job.model.job import Job
225 from lp.soyuz.interfaces.archive import ArchivePurpose
226 from lp.soyuz.interfaces.build import BuildStatus
227 from lp.buildmaster.interfaces.builder import IBuilderSet
228+from lp.soyuz.interfaces.buildqueue import IBuildQueueSet
229+from lp.soyuz.model.buildqueue import BuildQueue
230 from lp.soyuz.model.processor import ProcessorFamilySet
231 from lp.soyuz.interfaces.publishing import PackagePublishingStatus
232 from lp.soyuz.model.build import Build
233@@ -98,6 +102,28 @@
234 datetime.utcnow().replace(tzinfo=utc) - timedelta(seconds=offset))
235
236
237+class TestBuildQueueSet(TestCaseWithFactory):
238+ """Test for `BuildQueueSet`."""
239+
240+ layer = LaunchpadZopelessLayer
241+
242+ def setUp(self):
243+ super(TestBuildQueueSet, self).setUp()
244+ self.buildqueueset = getUtility(IBuildQueueSet)
245+
246+ def test_baseline(self):
247+ verifyObject(IBuildQueueSet, self.buildqueueset)
248+
249+ def test_getByJob_none(self):
250+ job = Job()
251+ self.assertEquals(None, self.buildqueueset.getByJob(job))
252+
253+ def test_getByJob(self):
254+ job = Job()
255+ buildqueue = BuildQueue(job=job.id)
256+ self.assertEquals(buildqueue, self.buildqueueset.getByJob(job))
257+
258+
259 class TestBuildQueueBase(TestCaseWithFactory):
260 """Setup the test publisher and some builders."""
261
262
263=== modified file 'lib/lp/translations/configure.zcml'
264--- lib/lp/translations/configure.zcml 2010-01-12 02:54:07 +0000
265+++ lib/lp/translations/configure.zcml 2010-01-14 09:57:16 +0000
266@@ -576,7 +576,9 @@
267 <class
268 class="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob">
269 <allow
270- interface="lp.translations.interfaces.translationtemplatesbuildjob.ITranslationTemplatesBuildJob"/>
271+ interface="lp.code.interfaces.branchjob.IBranchJob"/>
272+ <allow
273+ interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"/>
274 </class>
275 <securedutility
276 component="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob"
277@@ -585,7 +587,7 @@
278 </securedutility>
279 <utility
280 component="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob"
281- provides="lp.translations.interfaces.translationtemplatesbuildjob.ITranslationTemplatesBuildJob"
282+ provides="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"
283 name="TRANSLATIONTEMPLATESBUILD"/>
284
285 <!-- TranslationTemplateBuildBehavior -->
286
287=== added file 'lib/lp/translations/doc/translationtemplatesbuildbehavior.txt'
288--- lib/lp/translations/doc/translationtemplatesbuildbehavior.txt 1970-01-01 00:00:00 +0000
289+++ lib/lp/translations/doc/translationtemplatesbuildbehavior.txt 2010-01-14 09:57:16 +0000
290@@ -0,0 +1,82 @@
291+= TranslationTemplatesBuildJobBehavior =
292+
293+== Setup ==
294+
295+Set up build environment.
296+
297+ >>> import transaction
298+ >>> import logging
299+ >>> logger = logging.getLogger()
300+ >>> logger.setLevel(logging.CRITICAL)
301+
302+ >>> from lp.buildmaster.master import BuilddMaster
303+ >>> from canonical.buildd.tests import BuilddSlaveTestSetup
304+ >>> bm = BuilddMaster(logger, transaction)
305+ >>> BuilddSlaveTestSetup().setUp()
306+
307+ >>> from canonical.librarian.interfaces import ILibrarianClient
308+ >>> from StringIO import StringIO
309+ >>> from canonical.launchpad.interfaces import ILibraryFileAliasSet
310+ >>> from canonical.launchpad.interfaces import ILaunchpadCelebrities
311+
312+Choose an arbitrary file as the chroot tarball for the build slave. It
313+won't actually build, so it doesn't matter what's in there.
314+
315+The build slave uses the nominated architecture for the current Ubuntu
316+release.
317+
318+ >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
319+ >>> librarian_client = getUtility(ILibrarianClient)
320+ >>> content = 'arbitrary chroot file content'
321+ >>> alias_id = librarian_client.addFile(
322+ ... 'foo.tar.gz', len(content), StringIO(content), 'text/plain')
323+ >>> archdistroseries = ubuntu.currentseries.nominatedarchindep
324+ >>> chroot = getUtility(ILibraryFileAliasSet)[alias_id]
325+ >>> pc = archdistroseries.addOrUpdateChroot(chroot=chroot)
326+ >>> bm.addDistroArchSeries(archdistroseries)
327+ >>> bm.setupBuilders(archdistroseries)
328+ >>> processor = archdistroseries.processorfamily.processors[0]
329+
330+Make a builder to process our build request.
331+
332+ >>> builder = factory.makeBuilder(virtualized=False, processor=processor)
333+
334+
335+== Get a job! ==
336+
337+Use the ITranslationTemplatesBuildJobSource to create a
338+TranslationTemplatesBuildJob.
339+
340+ >>> from lp.translations.interfaces.translationtemplatesbuildjob import (
341+ ... ITranslationTemplatesBuildJobSource)
342+ >>> from lp.soyuz.interfaces.buildqueue import IBuildQueueSet
343+ >>> branch = factory.makeBranch()
344+ >>> specific_job_source = getUtility(ITranslationTemplatesBuildJobSource)
345+ >>> specific_job = specific_job_source.create(branch)
346+ >>> buildqueue = getUtility(IBuildQueueSet).getByJob(specific_job.job)
347+
348+The build has no start date yet.
349+
350+ >>> print buildqueue.date_started
351+ None
352+
353+Dispatch the job to the build slave. The proper method to call here
354+would have been Builder.findAndStartJob, but it has not been generalised
355+to handle new job types yet.
356+
357+# XXX JeroenVermeulen bug=506617: call findAndStartJob instead.
358+
359+ >>> from zope.security.proxy import removeSecurityProxy
360+ >>> removeSecurityProxy(builder)._dispatchBuildCandidate(buildqueue)
361+
362+The build is now marked as started.
363+
364+ >>> buildqueue.date_started is None
365+ False
366+
367+
368+== Teardown ==
369+
370+Clean up after this test.
371+
372+ >>> BuilddSlaveTestSetup().tearDown()
373
374=== modified file 'lib/lp/translations/interfaces/translationtemplatesbuildjob.py'
375--- lib/lp/translations/interfaces/translationtemplatesbuildjob.py 2010-01-08 12:26:22 +0000
376+++ lib/lp/translations/interfaces/translationtemplatesbuildjob.py 2010-01-14 09:57:16 +0000
377@@ -6,32 +6,21 @@
378 __metaclass__ = type
379
380 __all__ = [
381- 'ITranslationTemplatesBuildJob',
382 'ITranslationTemplatesBuildJobSource',
383 ]
384
385 from zope.interface import Interface
386
387-from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
388-from lp.code.interfaces.branchjob import IBranchJob
389-
390-
391-class ITranslationTemplatesBuildJob(IBranchJob, IBuildFarmJob):
392- """Build-farm job type for generating translation templates."""
393-
394
395 class ITranslationTemplatesBuildJobSource(Interface):
396- """Container for `ITranslationTemplatesBuildJob`s."""
397+ """Container for `TranslationTemplatesBuildJob`s."""
398
399 def create(branch):
400- """Create new `ITranslationTemplatesBuildJob`.
401+ """Create new `TranslationTemplatesBuildJob`.
402
403 Also creates the matching `IBuildQueue` and `IJob`.
404
405 :param branch: A `Branch` that this job will check out and
406 generate templates for.
407- :return: A new `ITranslationTemplatesBuildJob`.
408+ :return: A new `TranslationTemplatesBuildJob`.
409 """
410-
411- def getForJob(job):
412- """Find `ITranslationTemplatesBuildJob` matching given `Job`."""
413
414=== modified file 'lib/lp/translations/model/translationtemplatesbuildbehavior.py'
415--- lib/lp/translations/model/translationtemplatesbuildbehavior.py 2010-01-12 21:00:05 +0000
416+++ lib/lp/translations/model/translationtemplatesbuildbehavior.py 2010-01-14 09:57:16 +0000
417@@ -11,9 +11,6 @@
418 'TranslationTemplatesBuildBehavior',
419 ]
420
421-import socket
422-import xmlrpclib
423-
424 from zope.component import getUtility
425 from zope.interface import implements
426
427@@ -23,9 +20,6 @@
428 IBuildFarmJobBehavior)
429 from lp.buildmaster.model.buildfarmjobbehavior import (
430 BuildFarmJobBehaviorBase)
431-from lp.buildmaster.interfaces.builder import BuildSlaveFailure
432-from lp.translations.interfaces.translationtemplatesbuildjob import (
433- ITranslationTemplatesBuildJobSource)
434
435
436 class TranslationTemplatesBuildBehavior(BuildFarmJobBehaviorBase):
437@@ -37,43 +31,21 @@
438
439 def dispatchBuildToSlave(self, build_queue_item, logger):
440 """See `IBuildFarmJobBehavior`."""
441- # XXX JeroenVermeulen 2009-12-24 bug=500110: This method is not
442- # covered by tests yet. Either unify it with Soyuz code into a
443- # generalised method, or test it.
444- templatesbuildjob = self._findTranslationTemplatesBuildJob(
445- build_queue_item)
446 chroot = self._getChroot()
447 chroot_sha1 = chroot.content.sha1
448- self._builder.cacheFileOnSlave(logger, chroot)
449- buildid = templatesbuildjob.getName()
450+ self._builder.slave.cacheFile(logger, chroot)
451+ buildid = self.buildfarmjob.getName()
452
453- args = { 'branch_url': build_queue_item.branch.url }
454+ args = { 'branch_url': self.buildfarmjob.branch.url }
455 filemap = {}
456
457- try:
458- status, info = self._builder.slave.build(
459- buildid, self.build_type, chroot_sha1, filemap, args)
460- except xmlrpclib.Fault, info:
461- # Mark builder as 'failed'.
462- logger.debug(
463- "Disabling builder: %s" % self._builder.url, exc_info=1)
464- self._builder.failbuilder(
465- "Exception (%s) when setting up to new job" % info)
466- raise BuildSlaveFailure
467- except socket.error, info:
468- error_message = "Exception (%s) when setting up new job" % info
469- self._builder.handleTimeout(logger, error_message)
470- raise BuildSlaveFailure
471+ status, info = self._builder.slave.build(
472+ buildid, self.build_type, chroot_sha1, filemap, args)
473
474 def _getChroot(self):
475 ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
476 return ubuntu.currentseries.nominatedarchindep.getChroot()
477
478- def _findTranslationTemplatesBuildJob(self, build_queue_item):
479- """Find the `TranslationTemplatesBuildJob` for a job.
480-
481- :param build_queue_item: A `BuildQueue` entry.
482- :return: The matching `TranslationTemplatesBuildJob`.
483- """
484- jobsource = getUtility(ITranslationTemplatesBuildJobSource)
485- return jobsource.getForJob(build_queue_item.job)
486+ def logStartBuild(self, logger):
487+ """See `IBuildFarmJobBehavior`."""
488+ logger.info("Starting templates build.")
489
490=== modified file 'lib/lp/translations/model/translationtemplatesbuildjob.py'
491--- lib/lp/translations/model/translationtemplatesbuildjob.py 2010-01-11 03:27:28 +0000
492+++ lib/lp/translations/model/translationtemplatesbuildjob.py 2010-01-14 09:57:16 +0000
493@@ -15,12 +15,14 @@
494 from canonical.launchpad.webapp.interfaces import (
495 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE, MASTER_FLAVOR)
496
497-from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType
498+from lp.buildmaster.interfaces.buildfarmjob import (
499+ BuildFarmJobType, IBuildFarmJob, ISpecificBuildFarmJobClass)
500 from lp.buildmaster.model.buildfarmjob import BuildFarmJob
501+from lp.code.interfaces.branchjob import IBranchJob
502 from lp.code.model.branchjob import BranchJob, BranchJobDerived, BranchJobType
503 from lp.soyuz.model.buildqueue import BuildQueue
504 from lp.translations.interfaces.translationtemplatesbuildjob import (
505- ITranslationTemplatesBuildJob, ITranslationTemplatesBuildJobSource)
506+ ITranslationTemplatesBuildJobSource)
507
508
509 class TranslationTemplatesBuildJob(BranchJobDerived, BuildFarmJob):
510@@ -28,8 +30,9 @@
511
512 Implementation-wise, this is actually a `BranchJob`.
513 """
514- implements(ITranslationTemplatesBuildJob)
515- classProvides(ITranslationTemplatesBuildJobSource)
516+ implements(IBranchJob, IBuildFarmJob)
517+ classProvides(
518+ ISpecificBuildFarmJobClass, ITranslationTemplatesBuildJobSource)
519
520 duration_estimate = timedelta(seconds=10)
521
522@@ -75,8 +78,8 @@
523 return specific_job
524
525 @classmethod
526- def getForJob(cls, job):
527- """See `ITranslationTemplatesBuildJobSource`."""
528+ def getByJob(cls, job):
529+ """See `ISpecificBuildFarmJobClass`."""
530 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
531 branch_job = store.find(BranchJob, BranchJob.job == job).one()
532 if branch_job is None:
533
534=== modified file 'lib/lp/translations/tests/test_translationtemplatesbuildjob.py'
535--- lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-01-12 03:35:33 +0000
536+++ lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-01-14 09:57:16 +0000
537@@ -15,14 +15,18 @@
538
539 from lp.testing import TestCaseWithFactory
540
541-from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
542+from lp.buildmaster.interfaces.buildfarmjob import (
543+ IBuildFarmJob, ISpecificBuildFarmJobClass)
544 from lp.buildmaster.interfaces.buildfarmjobbehavior import (
545 IBuildFarmJobBehavior)
546+from lp.code.interfaces.branchjob import IBranchJob
547 from lp.services.job.model.job import Job
548 from lp.soyuz.interfaces.buildqueue import IBuildQueueSet
549 from lp.soyuz.model.buildqueue import BuildQueue
550 from lp.translations.interfaces.translationtemplatesbuildjob import (
551- ITranslationTemplatesBuildJob, ITranslationTemplatesBuildJobSource)
552+ ITranslationTemplatesBuildJobSource)
553+from lp.translations.model.translationtemplatesbuildjob import (
554+ TranslationTemplatesBuildJob)
555
556
557 def get_job_id(job):
558@@ -43,12 +47,14 @@
559
560 def test_new_TranslationTemplatesBuildJob(self):
561 # TranslationTemplateBuildJob implements IBuildFarmJob and
562- # ITranslationTemplatesBuildJob.
563+ # IBranchJob.
564+ verifyObject(IBranchJob, self.specific_job)
565 verifyObject(IBuildFarmJob, self.specific_job)
566- verifyObject(ITranslationTemplatesBuildJob, self.specific_job)
567
568- # The class also implements a utility.
569+ # The class also implements a utility and
570+ # ISpecificBuildFarmJobClass.
571 verifyObject(ITranslationTemplatesBuildJobSource, self.jobset)
572+ verifyObject(ISpecificBuildFarmJobClass, TranslationTemplatesBuildJob)
573
574 # Each of these jobs knows the branch it will operate on.
575 self.assertEqual(self.branch, self.specific_job.branch)
576@@ -61,7 +67,7 @@
577 # From a Job, the TranslationTemplatesBuildJobSource can find the
578 # TranslationTemplatesBuildJob back for us.
579 specific_job_for_base_job = removeSecurityProxy(
580- self.jobset.getForJob(base_job))
581+ TranslationTemplatesBuildJob.getByJob(base_job))
582 self.assertEqual(self.specific_job, specific_job_for_base_job)
583
584 def test_has_BuildQueue(self):
585@@ -119,14 +125,6 @@
586 self.assertNotEqual(None, chroot)
587 self.assertEqual(fake_chroot_file, chroot)
588
589- def test_findTranslationTemplatesBuildJob(self):
590- job = self.specific_job.job
591- job_id = removeSecurityProxy(job).id
592- buildqueue = getUtility(IBuildQueueSet).get(job_id)
593- specific_job_for_buildqueue = removeSecurityProxy(
594- self.behavior._findTranslationTemplatesBuildJob(buildqueue))
595- self.assertEqual(self.specific_job, specific_job_for_buildqueue)
596-
597
598 def test_suite():
599 return TestLoader().loadTestsFromName(__name__)