Merge lp:~jtv/launchpad/bug-507678 into lp:launchpad/db-devel
- bug-507678
- Merge into db-devel
Proposed by
Jeroen T. Vermeulen
Status: | Rejected | ||||
---|---|---|---|---|---|
Rejected by: | Jeroen T. Vermeulen | ||||
Proposed branch: | lp:~jtv/launchpad/bug-507678 | ||||
Merge into: | lp:launchpad/db-devel | ||||
Diff against target: |
575 lines (+418/-39) (has conflicts) 8 files modified
lib/lp/buildmaster/model/buildfarmjobbehavior.py (+15/-4) lib/lp/buildmaster/tests/test_buildfarmjobbehavior.py (+41/-0) lib/lp/testing/factory.py (+19/-0) lib/lp/testing/fakemethod.py (+51/-0) lib/lp/testing/tests/test_fakemethod.py (+85/-0) lib/lp/translations/model/translationtemplatesbuildbehavior.py (+50/-1) lib/lp/translations/tests/test_translationtemplatesbuildbehavior.py (+157/-0) lib/lp/translations/tests/test_translationtemplatesbuildjob.py (+0/-34) Text conflict in lib/lp/testing/factory.py |
||||
To merge this branch: | bzr merge lp:~jtv/launchpad/bug-507678 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Eleanor Berger | code | Pending | |
Review via email: mp+19131@code.launchpad.net |
Commit message
Retrieve results from translation-
Description of the change
To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/buildmaster/model/buildfarmjobbehavior.py' |
2 | --- lib/lp/buildmaster/model/buildfarmjobbehavior.py 2010-01-29 17:15:31 +0000 |
3 | +++ lib/lp/buildmaster/model/buildfarmjobbehavior.py 2010-02-11 19:48:24 +0000 |
4 | @@ -164,6 +164,20 @@ |
5 | queueItem.job.fail() |
6 | queueItem.specific_job.jobAborted() |
7 | |
8 | + def extractBuildStatus(self, slave_status): |
9 | + """Read build status name. |
10 | + |
11 | + :param slave_status: build status dict as passed to the |
12 | + updateBuild_* methods. |
13 | + :return: the unqualified status name, e.g. "OK". |
14 | + """ |
15 | + status_string = slave_status['build_status'] |
16 | + lead_string = 'BuildStatus.' |
17 | + assert status_string.startswith(lead_string), ( |
18 | + "Malformed status string: '%s'" % status_string) |
19 | + |
20 | + return status_string[len(lead_string):] |
21 | + |
22 | def updateBuild_WAITING(self, queueItem, slave_status, logtail, logger): |
23 | """Perform the actions needed for a slave in a WAITING state |
24 | |
25 | @@ -178,13 +192,10 @@ |
26 | the uploader for processing. |
27 | """ |
28 | librarian = getUtility(ILibrarianClient) |
29 | - build_status = slave_status['build_status'] |
30 | + build_status = self.extractBuildStatus(slave_status) |
31 | |
32 | # XXX: dsilvers 2005-03-02: Confirm the builder has the right build? |
33 | - assert build_status.startswith('BuildStatus.'), ( |
34 | - 'Malformed status string: %s' % build_status) |
35 | |
36 | - build_status = build_status[len('BuildStatus.'):] |
37 | queueItem.specific_job.build.handleStatus( |
38 | build_status, librarian, slave_status) |
39 | |
40 | |
41 | === added file 'lib/lp/buildmaster/tests/test_buildfarmjobbehavior.py' |
42 | --- lib/lp/buildmaster/tests/test_buildfarmjobbehavior.py 1970-01-01 00:00:00 +0000 |
43 | +++ lib/lp/buildmaster/tests/test_buildfarmjobbehavior.py 2010-02-11 19:48:24 +0000 |
44 | @@ -0,0 +1,41 @@ |
45 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
46 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
47 | + |
48 | +"""Unit tests for BuildFarmJobBehaviorBase.""" |
49 | + |
50 | +from unittest import TestCase, TestLoader |
51 | + |
52 | +from lp.buildmaster.model.buildfarmjobbehavior import BuildFarmJobBehaviorBase |
53 | +from lp.soyuz.interfaces.build import BuildStatus |
54 | + |
55 | + |
56 | +class FakeBuildFarmJob: |
57 | + """Dummy BuildFarmJob.""" |
58 | + pass |
59 | + |
60 | + |
61 | +class TestBuildFarmJobBehaviorBase(TestCase): |
62 | + """Test very small, basic bits of BuildFarmJobBehaviorBase.""" |
63 | + |
64 | + def setUp(self): |
65 | + self.behavior = BuildFarmJobBehaviorBase(FakeBuildFarmJob()) |
66 | + |
67 | + def test_extractBuildStatus_baseline(self): |
68 | + # extractBuildStatus picks the name of the build status out of a |
69 | + # dict describing the slave's status. |
70 | + slave_status = {'build_status': 'BuildStatus.BUILDING'} |
71 | + self.assertEqual( |
72 | + BuildStatus.BUILDING.name, |
73 | + self.behavior.extractBuildStatus(slave_status)) |
74 | + |
75 | + def test_extractBuildStatus_malformed(self): |
76 | + # extractBuildStatus errors out when the status string is not |
77 | + # of the form it expects. |
78 | + slave_status = {'build_status': 'BUILDING'} |
79 | + self.assertRaises( |
80 | + AssertionError, |
81 | + self.behavior.extractBuildStatus, slave_status) |
82 | + |
83 | + |
84 | +def test_suite(): |
85 | + return TestLoader().loadTestsFromName(__name__) |
86 | |
87 | === modified file 'lib/lp/testing/factory.py' |
88 | --- lib/lp/testing/factory.py 2010-02-11 05:08:47 +0000 |
89 | +++ lib/lp/testing/factory.py 2010-02-11 19:48:24 +0000 |
90 | @@ -129,6 +129,7 @@ |
91 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus |
92 | from lp.soyuz.interfaces.section import ISectionSet |
93 | from lp.soyuz.model.buildqueue import BuildQueue |
94 | +<<<<<<< TREE |
95 | from lp.soyuz.model.processor import ProcessorFamilySet |
96 | from lp.soyuz.model.publishing import ( |
97 | SecureSourcePackagePublishingHistory, |
98 | @@ -142,6 +143,12 @@ |
99 | ITranslationGroupSet) |
100 | from lp.translations.interfaces.translationsperson import ITranslationsPerson |
101 | from lp.translations.interfaces.translator import ITranslatorSet |
102 | +======= |
103 | +from lp.testing import run_with_login, time_counter |
104 | +from lp.translations.interfaces.translationtemplatesbuildjob import ( |
105 | + ITranslationTemplatesBuildJobSource) |
106 | + |
107 | +>>>>>>> MERGE-SOURCE |
108 | |
109 | SPACE = ' ' |
110 | |
111 | @@ -1714,6 +1721,18 @@ |
112 | store.add(bq) |
113 | return bq |
114 | |
115 | + def makeTranslationTemplatesBuildJob(self, branch=None): |
116 | + """Make a new `TranslationTemplatesBuildJob`. |
117 | + |
118 | + :param branch: The branch that the job should be for. If none |
119 | + is given, one will be created. |
120 | + """ |
121 | + if branch is None: |
122 | + branch = self.makeBranch() |
123 | + |
124 | + jobset = getUtility(ITranslationTemplatesBuildJobSource) |
125 | + return jobset.create(branch) |
126 | + |
127 | def makePOTemplate(self, productseries=None, distroseries=None, |
128 | sourcepackagename=None, owner=None, name=None, |
129 | translation_domain=None, path=None): |
130 | |
131 | === added file 'lib/lp/testing/fakemethod.py' |
132 | --- lib/lp/testing/fakemethod.py 1970-01-01 00:00:00 +0000 |
133 | +++ lib/lp/testing/fakemethod.py 2010-02-11 19:48:24 +0000 |
134 | @@ -0,0 +1,51 @@ |
135 | +# Copyright 2009, 2010 Canonical Ltd. This software is licensed under the |
136 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
137 | + |
138 | +# pylint: disable-msg=E0702 |
139 | + |
140 | + |
141 | +__metaclass__ = type |
142 | +__all__ = [ |
143 | + 'FakeMethod', |
144 | + ] |
145 | + |
146 | + |
147 | +class FakeMethod: |
148 | + """Catch any function or method call, and record the fact. |
149 | + |
150 | + Use this for easy stubbing. The call operator can return a fixed |
151 | + value, or raise a fixed exception object. |
152 | + |
153 | + This is useful when unit-testing code that does things you don't |
154 | + want to integration-test, e.g. because it wants to talk to remote |
155 | + systems. |
156 | + """ |
157 | + |
158 | + # How many times has this fake method been called? |
159 | + call_count = 0 |
160 | + |
161 | + def __init__(self, result=None, failure=None): |
162 | + """Set up a fake function or method. |
163 | + |
164 | + :param result: Value to return. |
165 | + :param failure: Exception to raise. |
166 | + """ |
167 | + self.result = result |
168 | + self.failure = failure |
169 | + |
170 | + def __call__(self, *args, **kwargs): |
171 | + """Catch an invocation to the method. Increment `call_count`. |
172 | + |
173 | + Accepts any and all parameters. Raises the failure passed to |
174 | + the constructor, if any; otherwise, returns the result value |
175 | + passed to the constructor. |
176 | + """ |
177 | + self.call_count += 1 |
178 | + |
179 | + if self.failure is None: |
180 | + return self.result |
181 | + else: |
182 | + # pylint thinks this raises None, which is clearly not |
183 | + # possible. That's why this test disables pylint message |
184 | + # E0702. |
185 | + raise self.failure |
186 | |
187 | === added file 'lib/lp/testing/tests/test_fakemethod.py' |
188 | --- lib/lp/testing/tests/test_fakemethod.py 1970-01-01 00:00:00 +0000 |
189 | +++ lib/lp/testing/tests/test_fakemethod.py 2010-02-11 19:48:24 +0000 |
190 | @@ -0,0 +1,85 @@ |
191 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
192 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
193 | + |
194 | +from unittest import TestCase, TestLoader |
195 | + |
196 | +from lp.testing.fakemethod import FakeMethod |
197 | + |
198 | + |
199 | +class RealActualClass: |
200 | + """A class that's hard to test.""" |
201 | + |
202 | + doing_impossible_stuff = False |
203 | + doing_possible_stuff = False |
204 | + |
205 | + def impossibleMethod(self): |
206 | + """A method that you can't afford to invoke in your test. |
207 | + |
208 | + This is the method you're going to want to avoid calling. The |
209 | + way to do that is to replace this method with a fake method. |
210 | + """ |
211 | + self.doing_impossible_stuff = True |
212 | + raise AssertionError("Trying to do impossible stuff.") |
213 | + |
214 | + def testableMethod(self): |
215 | + """This part of the class logic that you do want to exercise.""" |
216 | + self.doing_possible_stuff = True |
217 | + |
218 | + def doComplicatedThings(self, argument): |
219 | + """This is the top-level method you want to test. |
220 | + |
221 | + Unfortunately this invokes impossibleMethod, making it hard. |
222 | + """ |
223 | + self.impossibleMethod() |
224 | + self.testableMethod() |
225 | + return argument |
226 | + |
227 | + |
228 | +class CustomException(Exception): |
229 | + """Some specific error that you want raised.""" |
230 | + |
231 | + |
232 | +class TestFakeMethod(TestCase): |
233 | + def test_fakeMethod(self): |
234 | + # A class that you're testing can continue normally despite some |
235 | + # of its methods being stubbed. |
236 | + thing = RealActualClass() |
237 | + thing.impossibleMethod = FakeMethod() |
238 | + |
239 | + result = thing.doComplicatedThings(99) |
240 | + |
241 | + self.assertEqual(99, result) |
242 | + self.assertFalse(thing.doing_impossible_stuff) |
243 | + self.assertTrue(thing.doing_possible_stuff) |
244 | + |
245 | + def test_raiseFailure(self): |
246 | + # A FakeMethod can raise an exception you specify. |
247 | + ouch = CustomException("Ouch!") |
248 | + func = FakeMethod(failure=ouch) |
249 | + self.assertRaises(CustomException, func) |
250 | + |
251 | + def test_returnResult(self): |
252 | + # A FakeMethod can return a value you specify. |
253 | + value = "Fixed return value." |
254 | + func = FakeMethod(result=value) |
255 | + self.assertEqual(value, func()) |
256 | + |
257 | + def test_countCalls(self): |
258 | + # A FakeMethod counts the number of times it's been invoked. |
259 | + func = FakeMethod() |
260 | + for count in xrange(3): |
261 | + self.assertEqual(count, func.call_count) |
262 | + func() |
263 | + self.assertEqual(count + 1, func.call_count) |
264 | + |
265 | + def test_takeArguments(self): |
266 | + # A FakeMethod invocation accepts any arguments it gets. |
267 | + func = FakeMethod() |
268 | + func() |
269 | + func(1) |
270 | + func(2, kwarg=3) |
271 | + self.assertEqual(3, func.call_count) |
272 | + |
273 | + |
274 | +def test_suite(): |
275 | + return TestLoader().loadTestsFromName(__name__) |
276 | |
277 | === modified file 'lib/lp/translations/model/translationtemplatesbuildbehavior.py' |
278 | --- lib/lp/translations/model/translationtemplatesbuildbehavior.py 2010-01-15 01:20:20 +0000 |
279 | +++ lib/lp/translations/model/translationtemplatesbuildbehavior.py 2010-02-11 19:48:24 +0000 |
280 | @@ -13,6 +13,7 @@ |
281 | |
282 | from zope.component import getUtility |
283 | from zope.interface import implements |
284 | +from zope.security.proxy import removeSecurityProxy |
285 | |
286 | from canonical.launchpad.interfaces import ILaunchpadCelebrities |
287 | |
288 | @@ -29,6 +30,9 @@ |
289 | # Identify the type of job to the slave. |
290 | build_type = 'translation-templates' |
291 | |
292 | + # Filename for the tarball of templates that the slave builds. |
293 | + templates_tarball_path = 'translation-templates.tar.gz' |
294 | + |
295 | def dispatchBuildToSlave(self, build_queue_item, logger): |
296 | """See `IBuildFarmJobBehavior`.""" |
297 | chroot = self._getChroot() |
298 | @@ -39,7 +43,7 @@ |
299 | args = { 'branch_url': self.buildfarmjob.branch.url } |
300 | filemap = {} |
301 | |
302 | - status, info = self._builder.slave.build( |
303 | + self._builder.slave.build( |
304 | buildid, self.build_type, chroot_sha1, filemap, args) |
305 | |
306 | def _getChroot(self): |
307 | @@ -49,3 +53,48 @@ |
308 | def logStartBuild(self, logger): |
309 | """See `IBuildFarmJobBehavior`.""" |
310 | logger.info("Starting templates build.") |
311 | + |
312 | + def _readTarball(self, buildqueue, filemap, logger): |
313 | + """Read tarball with generated translation templates from slave.""" |
314 | + slave_filename = filemap.get(self.templates_tarball_path) |
315 | + if slave_filename is None: |
316 | + logger.error("Did not find templates tarball in slave output.") |
317 | + return None |
318 | + |
319 | + slave = removeSecurityProxy(buildqueue.builder.slave) |
320 | + return slave.getFile(slave_filename).read() |
321 | + |
322 | + def _uploadTarball(self, branch, tarball, logger): |
323 | + """Upload tarball to productseries that want it.""" |
324 | + # XXX JeroenVermeulen 2010-01-28 bug=507680: Find productseries |
325 | + # that want these templates, and upload to there. |
326 | + |
327 | + def updateBuild_WAITING(self, queue_item, slave_status, logtail, logger): |
328 | + """Deal with a finished ("WAITING" state, perversely) build job. |
329 | + |
330 | + Retrieves tarball and logs from the slave, then cleans up the |
331 | + slave so it's ready for a next job and destroys the queue item. |
332 | + |
333 | + If this fails for whatever unforeseen reason, a future run will |
334 | + retry it. |
335 | + """ |
336 | + build_status = self.extractBuildStatus(slave_status) |
337 | + build_id = slave_status['build_id'] |
338 | + filemap = slave_status['filemap'] |
339 | + |
340 | + logger.debug("Templates generation job %s finished with status %s" % ( |
341 | + build_id, build_status)) |
342 | + |
343 | + if build_status == 'OK': |
344 | + logger.debug("Processing templates build %s" % build_id) |
345 | + tarball = self._readTarball(queue_item, filemap, logger) |
346 | + if tarball is None: |
347 | + logger.error("Successful build %s produced no tarball." % ( |
348 | + build_id)) |
349 | + else: |
350 | + logger.debug("Uploading translation templates tarball.") |
351 | + self._uploadTarball(tarball, logger) |
352 | + logger.debug("Upload complete.") |
353 | + |
354 | + queue_item.builder.cleanSlave() |
355 | + queue_item.destroySelf() |
356 | |
357 | === added file 'lib/lp/translations/tests/test_translationtemplatesbuildbehavior.py' |
358 | --- lib/lp/translations/tests/test_translationtemplatesbuildbehavior.py 1970-01-01 00:00:00 +0000 |
359 | +++ lib/lp/translations/tests/test_translationtemplatesbuildbehavior.py 2010-02-11 19:48:24 +0000 |
360 | @@ -0,0 +1,157 @@ |
361 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
362 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
363 | + |
364 | +"""Unit tests for TranslationTemplatesBuildBehavior.""" |
365 | + |
366 | +import logging |
367 | +from StringIO import StringIO |
368 | +from unittest import TestLoader |
369 | + |
370 | +from zope.component import getUtility |
371 | +from zope.security.proxy import removeSecurityProxy |
372 | + |
373 | +from canonical.testing import ZopelessDatabaseLayer |
374 | + |
375 | +from canonical.launchpad.interfaces import ILaunchpadCelebrities |
376 | +from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet |
377 | +from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
378 | + IBuildFarmJobBehavior) |
379 | +from lp.soyuz.interfaces.build import BuildStatus |
380 | +from lp.soyuz.interfaces.buildqueue import IBuildQueueSet |
381 | +from lp.testing import TestCaseWithFactory |
382 | +from lp.testing.fakemethod import FakeMethod |
383 | + |
384 | + |
385 | +class FakeChrootContent: |
386 | + """Pretend chroot contents.""" |
387 | + sha1 = "shasha" |
388 | + |
389 | + |
390 | +class FakeChroot: |
391 | + """Pretend chroot.""" |
392 | + def __init__(self, *args, **kwargs): |
393 | + """Constructor acts as a fake _getChroot.""" |
394 | + self.content = FakeChrootContent() |
395 | + |
396 | + |
397 | +class FakeSlave: |
398 | + """Pretend build slave.""" |
399 | + def __init__(self, builderstatus): |
400 | + self.build_started = False |
401 | + self.status = { |
402 | + 'build_status': 'BuildStatus.%s' % builderstatus.name, |
403 | + } |
404 | + |
405 | + self.cacheFile = FakeMethod() |
406 | + self.getFile = FakeMethod(result=StringIO("File from the slave.")) |
407 | + |
408 | + def build(self, buildid, build_type, chroot_sha1, filemap, args): |
409 | + """Pretend to start a build.""" |
410 | + self.status['build_id'] = buildid |
411 | + self.status['filemap'] = filemap |
412 | + self.build_started = True |
413 | + |
414 | + |
415 | +class FakeBuilder: |
416 | + """Pretend `Builder`.""" |
417 | + def __init__(self, slave): |
418 | + self.slave = slave |
419 | + self.cleanSlave = FakeMethod() |
420 | + |
421 | + def slaveStatus(self): |
422 | + return self.slave.status |
423 | + |
424 | + |
425 | +class FakeBuildQueue: |
426 | + """Pretend `BuildQueue`.""" |
427 | + def __init__(self, behavior): |
428 | + """Pretend to be a BuildQueue item for the given build behavior. |
429 | + |
430 | + Copies its builder from the behavior object. |
431 | + """ |
432 | + self.builder = behavior._builder |
433 | + self.destroySelf = FakeMethod() |
434 | + |
435 | + |
436 | +class TestTranslationTemplatesBuildBehavior(TestCaseWithFactory): |
437 | + """Test `TranslationTemplatesBuildBehavior`.""" |
438 | + |
439 | + layer = ZopelessDatabaseLayer |
440 | + |
441 | + def _makeBehavior(self): |
442 | + """Create a TranslationTemplatesBuildBehavior. |
443 | + |
444 | + Anything that might communicate with build slaves and such |
445 | + (which we can't really do here) is mocked up. |
446 | + """ |
447 | + specific_job = self.factory.makeTranslationTemplatesBuildJob() |
448 | + behavior = IBuildFarmJobBehavior(specific_job) |
449 | + slave = FakeSlave(BuildStatus.NEEDSBUILD) |
450 | + behavior._builder = FakeBuilder(slave) |
451 | + return behavior |
452 | + |
453 | + def _getBuildQueueItem(self, behavior): |
454 | + """Get `BuildQueue` for an `IBuildFarmJobBehavior`.""" |
455 | + job = removeSecurityProxy(behavior.buildfarmjob.job) |
456 | + return getUtility(IBuildQueueSet).getByJob(job.id) |
457 | + |
458 | + def test_dispatchBuildToSlave(self): |
459 | + behavior = self._makeBehavior() |
460 | + behavior._getChroot = FakeChroot |
461 | + buildqueue_item = self._getBuildQueueItem(behavior) |
462 | + |
463 | + behavior.dispatchBuildToSlave(buildqueue_item, logging) |
464 | + |
465 | + self.assertTrue(behavior._builder.slave.build_started) |
466 | + |
467 | + def test_getChroot(self): |
468 | + # _getChroot produces the current chroot for the current Ubuntu |
469 | + # release, on the nominated architecture for |
470 | + # architecture-independent builds. |
471 | + ubuntu = getUtility(ILaunchpadCelebrities).ubuntu |
472 | + current_ubuntu = ubuntu.currentseries |
473 | + distroarchseries = current_ubuntu.nominatedarchindep |
474 | + |
475 | + # Set an arbitrary chroot file. |
476 | + fake_chroot_file = getUtility(ILibraryFileAliasSet)[1] |
477 | + distroarchseries.addOrUpdateChroot(fake_chroot_file) |
478 | + |
479 | + behavior = self._makeBehavior() |
480 | + chroot = behavior._getChroot() |
481 | + |
482 | + self.assertNotEqual(None, chroot) |
483 | + self.assertEqual(fake_chroot_file, chroot) |
484 | + |
485 | + def test_readTarball(self): |
486 | + behavior = self._makeBehavior() |
487 | + buildqueue = FakeBuildQueue(behavior) |
488 | + path = behavior.templates_tarball_path |
489 | + self.assertEqual( |
490 | + "File from the slave.", |
491 | + behavior._readTarball(buildqueue, {path: path}, logging)) |
492 | + |
493 | + def test_updateBuild_WAITING(self): |
494 | + behavior = self._makeBehavior() |
495 | + behavior._getChroot = FakeChroot |
496 | + behavior._uploadTarball = FakeMethod() |
497 | + queue_item = FakeBuildQueue(behavior) |
498 | + slave_status = behavior._builder.slave.status |
499 | + builder = behavior._builder |
500 | + slave = builder.slave |
501 | + |
502 | + behavior.dispatchBuildToSlave(queue_item, logging) |
503 | + |
504 | + self.assertEqual(0, queue_item.destroySelf.call_count) |
505 | + self.assertEqual(0, builder.cleanSlave.call_count) |
506 | + self.assertEqual(0, behavior._uploadTarball.call_count) |
507 | + |
508 | + behavior.updateBuild_WAITING(queue_item, slave_status, None, logging) |
509 | + |
510 | + self.assertEqual(1, queue_item.destroySelf.call_count) |
511 | + self.assertEqual(1, builder.cleanSlave.call_count) |
512 | + self.assertEqual(0, behavior._uploadTarball.call_count) |
513 | + |
514 | + |
515 | +def test_suite(): |
516 | + return TestLoader().loadTestsFromName(__name__) |
517 | + |
518 | |
519 | === modified file 'lib/lp/translations/tests/test_translationtemplatesbuildjob.py' |
520 | --- lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-01-15 01:20:20 +0000 |
521 | +++ lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-02-11 19:48:24 +0000 |
522 | @@ -8,8 +8,6 @@ |
523 | from zope.component import getUtility |
524 | from zope.security.proxy import removeSecurityProxy |
525 | |
526 | -from canonical.launchpad.interfaces import ( |
527 | - ILaunchpadCelebrities, ILibraryFileAliasSet) |
528 | from canonical.launchpad.webapp.testing import verifyObject |
529 | from canonical.testing import ZopelessDatabaseLayer |
530 | |
531 | @@ -17,8 +15,6 @@ |
532 | |
533 | from lp.buildmaster.interfaces.buildfarmjob import ( |
534 | IBuildFarmJob, ISpecificBuildFarmJobClass) |
535 | -from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
536 | - IBuildFarmJobBehavior) |
537 | from lp.code.interfaces.branchjob import IBranchJob |
538 | from lp.services.job.model.job import Job |
539 | from lp.soyuz.interfaces.buildqueue import IBuildQueueSet |
540 | @@ -102,35 +98,5 @@ |
541 | self.assertEqual(1000, self.specific_job.score()) |
542 | |
543 | |
544 | -class TestTranslationTemplatesBuildBehavior(TestCaseWithFactory): |
545 | - """Test `TranslationTemplatesBuildBehavior`.""" |
546 | - |
547 | - layer = ZopelessDatabaseLayer |
548 | - |
549 | - def setUp(self): |
550 | - super(TestTranslationTemplatesBuildBehavior, self).setUp() |
551 | - self.jobset = getUtility(ITranslationTemplatesBuildJobSource) |
552 | - self.branch = self.factory.makeBranch() |
553 | - self.specific_job = self.jobset.create(self.branch) |
554 | - self.behavior = IBuildFarmJobBehavior(self.specific_job) |
555 | - |
556 | - def test_getChroot(self): |
557 | - # _getChroot produces the current chroot for the current Ubuntu |
558 | - # release, on the nominated architecture for |
559 | - # architecture-independent builds. |
560 | - ubuntu = getUtility(ILaunchpadCelebrities).ubuntu |
561 | - current_ubuntu = ubuntu.currentseries |
562 | - distroarchseries = current_ubuntu.nominatedarchindep |
563 | - |
564 | - # Set an arbitrary chroot file. |
565 | - fake_chroot_file = getUtility(ILibraryFileAliasSet)[1] |
566 | - distroarchseries.addOrUpdateChroot(fake_chroot_file) |
567 | - |
568 | - chroot = self.behavior._getChroot() |
569 | - |
570 | - self.assertNotEqual(None, chroot) |
571 | - self.assertEqual(fake_chroot_file, chroot) |
572 | - |
573 | - |
574 | def test_suite(): |
575 | return TestLoader().loadTestsFromName(__name__) |
= Bug 507678 =
Continuing work on making the buildfarm generate translation templates from source branches. Here I'm jumping through the hoops to let the IBuildFarmJobBe havior implementation that we have for this kind of build-farm job retrieve a tarball produced by the slave.
The default BuildFarmJobBeh aviorBase code for this assumed that there's an IBuildBase object (basically a generalization of soyuz's Build) attached to a build-farm job. It didn't seem worth it to implement IBuildBase just for this (I tried), I now override the only BuildFarmJobBeh aviorBase method that requires it. I had to extend the infrastructure a bit along the way.
An important thing to note is that these pieces are still coming together; they're not actually a functional whole yet. But with the ongoing work on build-farm generalization, it's important to get and keep them integrated before bit-rot sets in.
Going through the diff step by step:
lib/lp/ buildmaster/ model/buildfarm jobbehavior. py
I extracted a method for reading and checking build status from a slave status dict. That makes it easy for my behavior class to reuse it.
lib/lp/ buildmaster/ tests/test_ buildfarmjobbeh avior.py
Tests the method I abstracted.
lib/lp/ testing/ factory. py
New factory method for the type of build-farm job that generates translation templates.
lib/lp/ testing/ fakemethod. py
Provides a generic stub for all sorts of functions and methods. I got tired of writing one-liners, injecting ad-hoc status variables into objects, and building one-off mock classes. Need to override a method in an object to return a dummy value or fail in a particular way? Just assign it to a FakeMethod.
Pylint had a truly silly complaint about this file, so I silenced it. There's a comment to the effect.
lib/lp/ testing/ tests/test_ fakemethod. py
Unit-tests FakeMethod.
lib/lp/ translations/ model/translati ontemplatesbuil dbehavior. py
Grew some methods for retrieving a tarball of results from the build-farm slave. As yet we do not have the code in place that will generate the real templates.
lib/lp/ translations/ tests/test_ translationtemp latesbuildbehav ior.py
Tests the extensions to the behavior class. The starting point for this was an existing unit test that I ripped out of the next file in the diff.
Interaction with slaves makes testing this stuff very hard. About the best I can do is mock up all the infrastructure, unit-test my part, and hope the other classes do their job. It's not perfect, but it's a lot more automated testing than a lot of the other buildfarm work gets.
For this test I had to strike a balance black-box and white-box approaches: obviously the test needs a lot of inside knowledge about the classes it's dealing with, but I didn't make it check the fidgety details of what values are being passed around where. Those could change easily, as work on the build farm is still ongoing. Moreover, I have no real requirements for them other than "they should work."
lib/lp/ translations/ tests/test_ translationtemp latesbuildjob. py
Lost a test case to the file above. What there was got simplified a bit, and setUp got replaced with explicit creation of objects.
To test these changes...