Merge lp://staging/~jtv/launchpad/bug-500110 into lp://staging/launchpad
- bug-500110
- Merge into devel
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 |
Related bugs: |
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.
Description of the change
To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote : | # |
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__) |
= Bug 500110 =
This code is what it takes to get a new IBuildFarmJobBe havior 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/buildfarmjo b.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 TranslationTemp latesBuildJob 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; TranslationTemp latesBuildJob 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 ISpecificBuildF armJobClass. 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 IBuildFarmJobBe havior that really aren't related to build behaviour.
lib/lp/ buildmaster/ model/buildfarm job.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/interface s/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 ITranslationTem platesBuildJob. Instead, TranslationTemp latesBuildJob implements IBranchJob and IBuildFarmJob directly.
lib/lp/ translations/ doc/translation templatesbuildb ehavior. 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...