Merge lp:~jtv/launchpad/db-bug-499404 into lp:launchpad/db-devel
- db-bug-499404
- Merge into db-devel
Status: | Rejected |
---|---|
Rejected by: | Jeroen T. Vermeulen |
Proposed branch: | lp:~jtv/launchpad/db-bug-499404 |
Merge into: | lp:launchpad/db-devel |
Diff against target: |
462 lines (+376/-6) 9 files modified
database/schema/comments.sql (+5/-0) database/schema/patch-2207-22-0.sql (+16/-0) database/schema/security.cfg (+1/-0) lib/lp/buildmaster/interfaces/buildfarmjob.py (+6/-6) lib/lp/translations/configure.zcml (+16/-0) lib/lp/translations/interfaces/translationtemplatesbuildjob.py (+52/-0) lib/lp/translations/model/translationtemplatesbuildbehavior.py (+81/-0) lib/lp/translations/model/translationtemplatesbuildjob.py (+93/-0) lib/lp/translations/tests/test_translationtemplatesbuildjob.py (+106/-0) |
To merge this branch: | bzr merge lp:~jtv/launchpad/db-bug-499404 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jonathan Lange (community) | db | Needs Fixing | |
Tim Penhey (community) | Disapprove | ||
Stuart Bishop (community) | db | Approve | |
Muharem Hrnjadovic (community) | code | Approve | |
Review via email: mp+16564@code.launchpad.net |
Commit message
Description of the change
Jeroen T. Vermeulen (jtv) wrote : | # |
Muharem Hrnjadovic (al-maisan) wrote : | # |
This is still very much work in progress but as such it looks good!
Stuart Bishop (stub) wrote : | # |
Mainly fine.
I prefer the non-unique index names to have an __idx suffix (avoids some probably non-existant namespace issues).
The ON DELETE CASCADE is an issue. If someone attempts to delete a Branch that has a running job, I suspect we actually want to generate an error (or will things somehow progress just fine despite the branch disappearing part of the way through the process?). There is quite a bit of logic in branch deletion on when branches can be deleted, and the DB constraints serve as a safety net for that. The ON DELETE CASCADE on the job column seems sane.
The DB patch is already using an assigned patch number, so nothing to change there.
Jeroen T. Vermeulen (jtv) wrote : | # |
> I prefer the non-unique index names to have an __idx suffix (avoids some
> probably non-existant namespace issues).
Done.
> The ON DELETE CASCADE is an issue. If someone attempts to delete a Branch that
> has a running job, I suspect we actually want to generate an error (or will
> things somehow progress just fine despite the branch disappearing part of the
> way through the process?). There is quite a bit of logic in branch deletion on
> when branches can be deleted, and the DB constraints serve as a safety net for
> that. The ON DELETE CASCADE on the job column seems sane.
I didn't feel like weighing down that cleanup logic even further—only to simulate a regular cascade AFAICS. But I'll go the safe route and remove the cascading for now.
Jonathan Lange (jml) wrote : | # |
The database patch looks good, but it leaves me wondering, where do the results of the job go?
On the code side, the interface that you have there looks an awful lot like IBranchJob -- should it subclass from it? A lot of the branch jobs use IFooJobSource, rather than IFooJobSet. Perhaps it's worth considering using similar names.
jml
Jeroen T. Vermeulen (jtv) wrote : | # |
> The database patch looks good, but it leaves me wondering, where do the
> results of the job go?
That goes through completely separate channels. The slaves that run these jobs are untrusted, so they're not allowed anywhere near the database. A master-side script will pick up the files they produce (as already happens for the existing Soyuz build jobs) and "upload" them to the regular Translations import queue.
> On the code side, the interface that you have there looks an awful lot like
> IBranchJob -- should it subclass from it? A lot of the branch jobs use
> IFooJobSource, rather than IFooJobSet. Perhaps it's worth considering using
> similar names.
An interesting idea, but this class doesn't have a "metadata" attribute yet. It may still sprout one; at that point it'd be the sensible thing to do. I've added a note.
Stuart Bishop (stub) wrote : | # |
Fine if we drop ON DELETE CASCADE from the branch foreign key definition.
Tim Penhey (thumper) wrote : | # |
I don't think this database patch is necessary. The is a branch job, it should use the branch job table.
Stuart Bishop (stub) wrote : | # |
> Fine if we drop ON DELETE CASCADE from the branch foreign key definition.
And change the SERIAL UNIQUE to SERIAL PRIMARY KEY.
(which we would have picked up when staging failed to rebuild since we can't replicate tables without primary keys).
Using BranchJob may indeed be a better alternative - it already has everything you need. If you want a separate table I think we need some sort of rationalization.
Jonathan Lange (jml) wrote : | # |
Thinking more about it, I think that Tim is right -- we should use BranchJob for this. There are other branch job implementations with empty metadata dicts -- it's an entirely cromulent approach, and we shouldn't add new tables without a good reason.
Jonathan Lange (jml) : | # |
Preview Diff
1 | === modified file 'database/schema/comments.sql' |
2 | --- database/schema/comments.sql 2009-12-01 13:45:58 +0000 |
3 | +++ database/schema/comments.sql 2010-01-06 10:28:19 +0000 |
4 | @@ -1837,6 +1837,11 @@ |
5 | COMMENT ON COLUMN TranslationImportQueueEntry.status IS 'The status of the import: 1 Approved, 2 Imported, 3 Deleted, 4 Failed, 5 Needs Review, 6 Blocked.'; |
6 | COMMENT ON COLUMN TranslationImportQueueEntry.error_output IS 'Error output from last import attempt.'; |
7 | |
8 | +-- TranslationTemplatesBuildJob |
9 | +COMMENT ON TABLE TranslationTemplatesBuildJob IS 'Buildfarm job for generating translation templates from a branch.'; |
10 | +COMMENT ON COLUMN TranslationTemplatesBuildJob.branch IS 'Source code branch that the job will generate templates for.'; |
11 | +COMMENT ON COLUMN TranslationTemplatesBuildJob.job IS 'Base Job details.'; |
12 | + |
13 | -- Archive |
14 | COMMENT ON TABLE Archive IS 'A package archive. Commonly either a distribution''s main_archive or a ppa''s archive.'; |
15 | COMMENT ON COLUMN Archive.owner IS 'Identifies the PPA owner when it has one.'; |
16 | |
17 | === added file 'database/schema/patch-2207-22-0.sql' |
18 | --- database/schema/patch-2207-22-0.sql 1970-01-01 00:00:00 +0000 |
19 | +++ database/schema/patch-2207-22-0.sql 2010-01-06 10:28:20 +0000 |
20 | @@ -0,0 +1,16 @@ |
21 | +-- Copyright 2009 Canonical Ltd. This software is licensed under the |
22 | +-- GNU Affero General Public License version 3 (see the file LICENSE). |
23 | + |
24 | +SET client_min_messages=ERROR; |
25 | + |
26 | +CREATE TABLE TranslationTemplatesBuildJob ( |
27 | + id SERIAL UNIQUE, |
28 | + branch integer NOT NULL REFERENCES Branch(id), |
29 | + job integer NOT NULL REFERENCES Job(id) ON DELETE CASCADE); |
30 | + |
31 | +CREATE INDEX translationtemplatesbuildjob__branch__idx |
32 | + ON TranslationTemplatesBuildJob(branch); |
33 | +CREATE INDEX translationtemplatesbuildjob__job__idx |
34 | + ON TranslationTemplatesBuildJob(job); |
35 | + |
36 | +INSERT INTO LaunchpadDatabaseRevision VALUES (2207, 22, 0); |
37 | |
38 | === modified file 'database/schema/security.cfg' |
39 | --- database/schema/security.cfg 2010-01-06 07:05:19 +0000 |
40 | +++ database/schema/security.cfg 2010-01-06 10:28:20 +0000 |
41 | @@ -293,6 +293,7 @@ |
42 | public.translationgroup = SELECT, INSERT, UPDATE |
43 | public.translationimportqueueentry = SELECT, INSERT, UPDATE, DELETE |
44 | public.translationmessage = SELECT, INSERT, UPDATE |
45 | +public.translationtemplatesbuildjob = SELECT, INSERT |
46 | public.translator = SELECT, INSERT, UPDATE, DELETE |
47 | public.usertouseremail = SELECT, UPDATE |
48 | public.validpersoncache = SELECT |
49 | |
50 | === modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py' |
51 | --- lib/lp/buildmaster/interfaces/buildfarmjob.py 2009-12-24 14:18:35 +0000 |
52 | +++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-01-06 10:28:19 +0000 |
53 | @@ -46,24 +46,24 @@ |
54 | Build a package from a bazaar branch and a recipe. |
55 | """) |
56 | |
57 | - TRANSLATION = DBItem(4, """ |
58 | - TranslationJob |
59 | + TRANSLATIONTEMPLATESBUILD = DBItem(4, """ |
60 | + TranslationTemplatesBuildJob |
61 | |
62 | - Perform a translation job. |
63 | + Generate translation templates from a bazaar branch. |
64 | """) |
65 | |
66 | |
67 | class IBuildFarmJob(Interface): |
68 | - """Operations that Soyuz build farm jobs must implement.""" |
69 | + """Operations that jobs for the build farm must implement.""" |
70 | |
71 | def score(): |
72 | """Calculate a job score appropriate for the job type in question.""" |
73 | |
74 | def getLogFileName(): |
75 | - """The preferred file name for the log of this Soyuz job.""" |
76 | + """The preferred file name for the log of this job.""" |
77 | |
78 | def getName(): |
79 | - """An appropriate name for this Soyuz job.""" |
80 | + """An appropriate name for this job.""" |
81 | |
82 | def jobStarted(): |
83 | """'Job started' life cycle event, handle as appropriate.""" |
84 | |
85 | === modified file 'lib/lp/translations/configure.zcml' |
86 | --- lib/lp/translations/configure.zcml 2009-12-28 22:58:18 +0000 |
87 | +++ lib/lp/translations/configure.zcml 2010-01-06 10:28:20 +0000 |
88 | @@ -572,6 +572,22 @@ |
89 | interface="lp.translations.interfaces.poexportrequest.IPOExportRequestSet"/> |
90 | </securedutility> |
91 | |
92 | + <class |
93 | + class="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob"> |
94 | + <allow interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"/> |
95 | + <allow interface="lp.translations.interfaces.translationtemplatesbuildjob.ITranslationTemplatesBuildJob"/> |
96 | + </class> |
97 | + <securedutility |
98 | + class="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJobSet" |
99 | + provides="lp.translations.interfaces.translationtemplatesbuildjob.ITranslationTemplatesBuildJobSet"> |
100 | + <allow interface="lp.translations.interfaces.translationtemplatesbuildjob.ITranslationTemplatesBuildJobSet"/> |
101 | + </securedutility> |
102 | + <adapter |
103 | + for="lp.translations.interfaces.translationtemplatesbuildjob.ITranslationTemplatesBuildJob" |
104 | + provides="lp.buildmaster.interfaces.buildfarmjobbehavior.IBuildFarmJobBehavior" |
105 | + factory="lp.translations.model.translationtemplatesbuildbehavior.TranslationTemplatesBuildBehavior" |
106 | + permission="zope.Public"/> |
107 | + |
108 | <webservice:register module="lp.translations.interfaces.webservice" /> |
109 | |
110 | </configure> |
111 | |
112 | === added file 'lib/lp/translations/interfaces/translationtemplatesbuildjob.py' |
113 | --- lib/lp/translations/interfaces/translationtemplatesbuildjob.py 1970-01-01 00:00:00 +0000 |
114 | +++ lib/lp/translations/interfaces/translationtemplatesbuildjob.py 2010-01-06 10:28:19 +0000 |
115 | @@ -0,0 +1,52 @@ |
116 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
117 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
118 | + |
119 | +# pylint: disable-msg=E0213 |
120 | + |
121 | +__metaclass__ = type |
122 | + |
123 | +__all__ = [ |
124 | + 'ITranslationTemplatesBuildJob', |
125 | + 'ITranslationTemplatesBuildJobSet', |
126 | + ] |
127 | + |
128 | +from zope.interface import Interface |
129 | +from zope.schema import Int |
130 | + |
131 | +from lazr.restful.fields import Reference |
132 | + |
133 | +from canonical.launchpad import _ |
134 | + |
135 | +from lp.services.job.interfaces.job import IJob |
136 | +from lp.code.interfaces.branch import IBranch |
137 | + |
138 | + |
139 | +class ITranslationTemplatesBuildJob(Interface): |
140 | + """Build-farm job object for building translation templates.""" |
141 | + |
142 | + id = Int(title=_("ID"), required=True, readonly=True) |
143 | + |
144 | + job = Reference( |
145 | + title=_("Generic Job record"), |
146 | + readonly=True, required=True, schema=IJob) |
147 | + |
148 | + branch = Reference( |
149 | + title=_("Source code branch"), |
150 | + readonly=True, required=True, schema=IBranch) |
151 | + |
152 | + |
153 | +class ITranslationTemplatesBuildJobSet(Interface): |
154 | + """The container for `ITranslationTemplatesBuildJob`s.""" |
155 | + |
156 | + def new(branch): |
157 | + """Create new `ITranslationTemplatesBuildJob`. |
158 | + |
159 | + Also creates the matching `IBuildQueue` and `IJob` entries. |
160 | + |
161 | + :param branch: A `Branch` that this job is to check out and |
162 | + generate templates for. |
163 | + :return: A new `ITranslationTemplatesBuildJob`. |
164 | + """ |
165 | + |
166 | + def getForJob(job): |
167 | + """Find `ITranslationTemplatesBuildJob` matching given `Job`.""" |
168 | |
169 | === added file 'lib/lp/translations/model/translationtemplatesbuildbehavior.py' |
170 | --- lib/lp/translations/model/translationtemplatesbuildbehavior.py 1970-01-01 00:00:00 +0000 |
171 | +++ lib/lp/translations/model/translationtemplatesbuildbehavior.py 2010-01-06 10:28:19 +0000 |
172 | @@ -0,0 +1,81 @@ |
173 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
174 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
175 | + |
176 | +"""An `IBuildFarmJobBehavior` for `TranslationTemplatesBuildJob`. |
177 | + |
178 | +Dispatches translation template build jobs to build-farm slaves. |
179 | +""" |
180 | + |
181 | +__metaclass__ = type |
182 | +__all__ = [ |
183 | + 'TranslationTemplatesBuildBehavior', |
184 | + ] |
185 | + |
186 | +import socket |
187 | +import xmlrpclib |
188 | + |
189 | +from zope.component import getUtility |
190 | +from zope.interface import implements |
191 | + |
192 | +from canonical.launchpad.interfaces import ILaunchpadCelebrities |
193 | + |
194 | +from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
195 | + IBuildFarmJobBehavior) |
196 | +from lp.soyuz.interfaces.builder import BuildSlaveFailure |
197 | +from lp.translations.interfaces.translationtemplatesbuildjob import ( |
198 | + ITranslationTemplatesBuildJobSet) |
199 | +from lp.buildmaster.model.buildfarmjobbehavior import ( |
200 | + BuildFarmJobBehaviorBase) |
201 | + |
202 | + |
203 | +class TranslationTemplatesBuildBehavior(BuildFarmJobBehaviorBase): |
204 | + """Dispatches `TranslationTemplateBuildJob`s to slaves.""" |
205 | + # Note: If this class had a "metadata" dict, it'd effectively be |
206 | + # implementing IBranchJob as well. |
207 | + implements(IBuildFarmJobBehavior) |
208 | + |
209 | + # XXX JeroenVermeulen 2009-12-24 bug=499405: What really goes here? |
210 | + build_type = 'translation-templates' |
211 | + |
212 | + def dispatchBuildToSlave(self, build_queue_item, logger): |
213 | + """See `IBuildFarmJobBehavior`.""" |
214 | + # XXX JeroenVermeulen 2009-12-24 bug=500110: This method is not |
215 | + # covered by tests yet. Either unify it with Soyuz code into a |
216 | + # generalised method, or test it. |
217 | + templatesbuildjob = self._findTranslationTemplatesBuildJob( |
218 | + build_queue_item) |
219 | + chroot = self._getChroot() |
220 | + chroot_sha1 = chroot.content.sha1 |
221 | + self._builder.cacheFileOnSlave(logger, chroot) |
222 | + buildid = templatesbuildjob.getName() |
223 | + |
224 | + args = { 'branch_url': build_queue_item.branch.url } |
225 | + filemap = {} |
226 | + |
227 | + try: |
228 | + status, info = self._builder.slave.build( |
229 | + buildid, self.build_type, chroot_sha1, filemap, args) |
230 | + except xmlrpclib.Fault, info: |
231 | + # Mark builder as 'failed'. |
232 | + logger.debug( |
233 | + "Disabling builder: %s" % self._builder.url, exc_info=1) |
234 | + self._builder.failbuilder( |
235 | + "Exception (%s) when setting up to new job" % info) |
236 | + raise BuildSlaveFailure |
237 | + except socket.error, info: |
238 | + error_message = "Exception (%s) when setting up new job" % info |
239 | + self._builder.handleTimeout(logger, error_message) |
240 | + raise BuildSlaveFailure |
241 | + |
242 | + def _getChroot(self): |
243 | + ubuntu = getUtility(ILaunchpadCelebrities).ubuntu |
244 | + return ubuntu.currentseries.nominatedarchindep |
245 | + |
246 | + def _findTranslationTemplatesBuildJob(self, build_queue_item): |
247 | + """Find the `TranslationTemplatesBuildJob` for a job. |
248 | + |
249 | + :param build_queue_item: A `BuildQueue` entry. |
250 | + :return: The matching `TranslationTemplatesBuildJob`. |
251 | + """ |
252 | + buildjobset = getUtility(ITranslationTemplatesBuildJobSet) |
253 | + return buildjobset.getForJob(build_queue_item.job) |
254 | |
255 | === added file 'lib/lp/translations/model/translationtemplatesbuildjob.py' |
256 | --- lib/lp/translations/model/translationtemplatesbuildjob.py 1970-01-01 00:00:00 +0000 |
257 | +++ lib/lp/translations/model/translationtemplatesbuildjob.py 2010-01-06 10:28:20 +0000 |
258 | @@ -0,0 +1,93 @@ |
259 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
260 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
261 | + |
262 | +__metaclass__ = type |
263 | +__all__ = [ |
264 | + 'TranslationTemplatesBuildJob' |
265 | + ] |
266 | + |
267 | +import re |
268 | +from datetime import timedelta |
269 | + |
270 | +from zope.component import getUtility |
271 | +from zope.interface import implements |
272 | + |
273 | +from storm.locals import Int, Reference, Storm |
274 | + |
275 | +from canonical.launchpad.webapp.interfaces import ( |
276 | + DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE, MASTER_FLAVOR) |
277 | + |
278 | +from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType |
279 | +from lp.buildmaster.model.buildfarmjob import BuildFarmJob |
280 | +from lp.services.job.model.job import Job |
281 | +from lp.soyuz.model.buildqueue import BuildQueue |
282 | +from lp.translations.interfaces.translationtemplatesbuildjob import ( |
283 | + ITranslationTemplatesBuildJob, ITranslationTemplatesBuildJobSet) |
284 | + |
285 | + |
286 | +class TranslationTemplatesBuildJob(BuildFarmJob, Storm): |
287 | + """An `IBuildFarmJob` implementation that generates templates.""" |
288 | + implements(ITranslationTemplatesBuildJob) |
289 | + |
290 | + __storm_table__ = 'TranslationTemplatesBuildJob' |
291 | + |
292 | + unsafe_chars = '[^a-zA-Z0-9_+-]' |
293 | + |
294 | + id = Int(primary=True) |
295 | + |
296 | + job_id = Int(name='job', allow_none=False) |
297 | + job = Reference(job_id, 'Job.id') |
298 | + |
299 | + branch_id = Int(name='branch', allow_none=False) |
300 | + branch = Reference(branch_id, 'Branch.id') |
301 | + |
302 | + def score(self): |
303 | + """See `IBuildFarmJob`.""" |
304 | + # Arbitrary score that sorta-kinda seems to match the sort of |
305 | + # number that BuildPackageJob might give a job like this, |
306 | + # perhaps. It may not matter that much since these jobs are |
307 | + # fast. |
308 | + return 4010 |
309 | + |
310 | + def getLogFileName(self): |
311 | + """See `IBuildFarmJob`.""" |
312 | + sanitized_name = re.sub(self.unsafe_chars, '_', self.getName()) |
313 | + return "translationtemplates_%s" % sanitized_name |
314 | + |
315 | + def getName(self): |
316 | + """See `IBuildFarmJob`.""" |
317 | + return '%s-%d' % (self.branch.name, self.id) |
318 | + |
319 | + |
320 | +class TranslationTemplatesBuildJobSet: |
321 | + """See `ITranslationTemplatesBuildJobSet`.""" |
322 | + implements(ITranslationTemplatesBuildJobSet) |
323 | + |
324 | + duration_estimate = timedelta(seconds=10) |
325 | + |
326 | + def new(self, branch): |
327 | + """See `ITranslationTemplatesBuildJobSet`.""" |
328 | + store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR) |
329 | + job = Job() |
330 | + store.add(job) |
331 | + |
332 | + specific_job = TranslationTemplatesBuildJob() |
333 | + specific_job.branch = branch |
334 | + specific_job.job = job |
335 | + store.add(specific_job) |
336 | + |
337 | + duration_estimate = self.duration_estimate |
338 | + build_queue_entry = BuildQueue( |
339 | + estimated_duration=duration_estimate, |
340 | + job_type=BuildFarmJobType.TRANSLATIONTEMPLATESBUILD, |
341 | + job=job.id) |
342 | + store.add(build_queue_entry) |
343 | + |
344 | + return specific_job |
345 | + |
346 | + def getForJob(self, job): |
347 | + """See `ITranslationTemplatesBuildJobSet`.""" |
348 | + store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
349 | + return store.find( |
350 | + TranslationTemplatesBuildJob, |
351 | + TranslationTemplatesBuildJob.job == job).one() |
352 | |
353 | === added file 'lib/lp/translations/tests/test_translationtemplatesbuildjob.py' |
354 | --- lib/lp/translations/tests/test_translationtemplatesbuildjob.py 1970-01-01 00:00:00 +0000 |
355 | +++ lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-01-06 10:28:19 +0000 |
356 | @@ -0,0 +1,106 @@ |
357 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
358 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
359 | + |
360 | +__metaclass__ = type |
361 | + |
362 | +from unittest import TestLoader |
363 | + |
364 | +from zope.component import getUtility |
365 | +from zope.security.proxy import removeSecurityProxy |
366 | + |
367 | +from canonical.launchpad.webapp.testing import verifyObject |
368 | +from canonical.testing import ZopelessDatabaseLayer |
369 | + |
370 | +from lp.testing import TestCaseWithFactory |
371 | + |
372 | +from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob |
373 | +from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
374 | + IBuildFarmJobBehavior) |
375 | +from lp.services.job.model.job import Job |
376 | +from lp.soyuz.interfaces.buildqueue import IBuildQueueSet |
377 | +from lp.soyuz.model.buildqueue import BuildQueue |
378 | +from lp.translations.interfaces.translationtemplatesbuildjob import ( |
379 | + ITranslationTemplatesBuildJob, ITranslationTemplatesBuildJobSet) |
380 | + |
381 | + |
382 | +def get_job_id(job): |
383 | + """Peek inside a `Job` and retrieve its id.""" |
384 | + return removeSecurityProxy(job).id |
385 | + |
386 | + |
387 | +class TestTranslationTemplatesBuildJob(TestCaseWithFactory): |
388 | + """Test `TranslationTemplatesBuildJob`.""" |
389 | + |
390 | + layer = ZopelessDatabaseLayer |
391 | + |
392 | + def setUp(self): |
393 | + super(TestTranslationTemplatesBuildJob, self).setUp() |
394 | + self.jobset = getUtility(ITranslationTemplatesBuildJobSet) |
395 | + self.branch = self.factory.makeBranch() |
396 | + self.specific_job = self.jobset.new(self.branch) |
397 | + |
398 | + def test_new_TranslationTemplatesBuildJob(self): |
399 | + # TranslationTemplateBuildJob implements IBuildFarmJob and |
400 | + # ITranslationTemplatesBuildJob. |
401 | + verifyObject(IBuildFarmJob, self.specific_job) |
402 | + verifyObject(ITranslationTemplatesBuildJob, self.specific_job) |
403 | + |
404 | + # Each of these jobs knows the branch it will operate on. |
405 | + self.assertEqual(self.branch, self.specific_job.branch) |
406 | + |
407 | + def test_has_Job(self): |
408 | + # Associated with each TranslationTemplateBuildJob is a Job. |
409 | + base_job = self.specific_job.job |
410 | + self.assertIsInstance(base_job, Job) |
411 | + |
412 | + # From a Job, the TranslationTemplatesBuildJobSet can find the |
413 | + # TranslationTemplatesBuildJob back for us. |
414 | + self.assertEqual(self.specific_job, self.jobset.getForJob(base_job)) |
415 | + |
416 | + def test_has_BuildQueue(self): |
417 | + # There's also a BuildQueue item associated with the job. |
418 | + queueset = getUtility(IBuildQueueSet) |
419 | + job_id = get_job_id(self.specific_job.job) |
420 | + buildqueue = queueset.get(job_id) |
421 | + |
422 | + self.assertIsInstance(buildqueue, BuildQueue) |
423 | + self.assertEqual(job_id, get_job_id(buildqueue.job)) |
424 | + |
425 | + def test_getName(self): |
426 | + # Each job gets a unique name. |
427 | + other_job = self.jobset.new(self.branch) |
428 | + self.assertNotEqual(self.specific_job.getName(), other_job.getName()) |
429 | + |
430 | + def test_getLogFileName(self): |
431 | + # Each job has a unique log file name. |
432 | + other_job = self.jobset.new(self.branch) |
433 | + self.assertNotEqual( |
434 | + self.specific_job.getLogFileName(), other_job.getLogFileName()) |
435 | + |
436 | + |
437 | +class TestTranslationTemplatesBuildBehavior(TestCaseWithFactory): |
438 | + """Test `TranslationTemplatesBuildBehavior`.""" |
439 | + |
440 | + layer = ZopelessDatabaseLayer |
441 | + |
442 | + def setUp(self): |
443 | + super(TestTranslationTemplatesBuildBehavior, self).setUp() |
444 | + self.jobset = getUtility(ITranslationTemplatesBuildJobSet) |
445 | + self.branch = self.factory.makeBranch() |
446 | + self.specific_job = self.jobset.new(self.branch) |
447 | + self.behavior = IBuildFarmJobBehavior(self.specific_job) |
448 | + |
449 | + def test_getChroot(self): |
450 | + chroot = self.behavior._getChroot() |
451 | + self.assertNotEqual(None, chroot) |
452 | + |
453 | + def test_findTranslationTemplatesBuildJob(self): |
454 | + buildqueue = self.jobset.getForJob(self.specific_job.job) |
455 | + |
456 | + self.assertEqual( |
457 | + self.specific_job, |
458 | + self.behavior._findTranslationTemplatesBuildJob(buildqueue)) |
459 | + |
460 | + |
461 | +def test_suite(): |
462 | + return TestLoader().loadTestsFromName(__name__) |
= Bug 499404 =
This implements some new classes that will be needed for Rosetta to run jobs on the generalised build farm. The job in question is generating translation templates based on a source-code branch, and will require a lot more work before it goes operational.
Generalisation of the build farm is ongoing work, so its APIs etc. are not complete yet. What you find here is:
1. An implementation of IBuildFarmJob—a new class representing a job that can be dispatched to the build farm. It's called TranslationTemp latesBuildJob. The only "payload" in this new class is a reference to the branch that the job is to check out. There's also a reference to Job, which holds the generic part of the jobbing information.
2. A BuildFarmJobSet utility—to produce and navigate jobs of the new type. It also creates a BuildQueue record for each job it creates; these records are matched to the records of the new type in that they both refer to the same Job record.
3. A new IBuildFarmJobBe havior implementation for dispatching the new job type to the build farm, with an adapter associating it with TranslationTemp latesBuildJob. More may be needed there in the future.
There's not much I can do to test the main IBuildFarmJobBe havior method right now; we'll need more of the building to be operational before we get to that. But work is in progress and I'm filing separate bugs for this.
To test: latesbuild
{{{
./bin/test -vv -t translationtemp
}}}
No lint.
Jeroen