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
=== added file 'lib/lp/buildmaster/doc/buildfarmjob.txt'
--- lib/lp/buildmaster/doc/buildfarmjob.txt 1970-01-01 00:00:00 +0000
+++ lib/lp/buildmaster/doc/buildfarmjob.txt 2010-01-14 09:57:16 +0000
@@ -0,0 +1,20 @@
1= BuildFarmJob =
2
3 >>> from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
4 >>> from lp.buildmaster.model.buildfarmjob import BuildFarmJob
5
6BuildFarmJob provides a basic implementation of IBuildFarmJob. The
7specific build farm job classes should inherit from it.
8
9 >>> buildfarmjob = BuildFarmJob()
10 >>> verifyObject(IBuildFarmJob, buildfarmjob)
11 True
12
13As a class, it also provides ISpecificBuildFarmJobClass so that
14BuildQueue can find the instance of a specific build-farm job
15implementation associated with a given Job instance.
16
17 >>> from lp.buildmaster.interfaces.buildfarmjob import (
18 ... ISpecificBuildFarmJobClass)
19 >>> verifyObject(ISpecificBuildFarmJobClass, BuildFarmJob)
20 True
021
=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
--- lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-01-08 12:26:22 +0000
+++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-01-14 09:57:16 +0000
@@ -10,6 +10,7 @@
10__all__ = [10__all__ = [
11 'IBuildFarmJob',11 'IBuildFarmJob',
12 'IBuildFarmJobDispatchEstimation',12 'IBuildFarmJobDispatchEstimation',
13 'ISpecificBuildFarmJobClass',
13 'BuildFarmJobType',14 'BuildFarmJobType',
14 ]15 ]
1516
@@ -87,6 +88,22 @@
87 "return None."))88 "return None."))
8889
8990
91
92class ISpecificBuildFarmJobClass(Interface):
93 """Class interface provided by `IBuildFarmJob` classes.
94
95 Used by the `BuildQueue` to find the specific build-farm job objects
96 it needs to dispatch to builders.
97 """
98
99 def getByJob(job):
100 """Get the specific `IBuildFarmJob` for the given `Job`.
101
102 Invoked on the specific `IBuildFarmJob`-implementing class that
103 has an entry associated with `job`.
104 """
105
106
90class IBuildFarmJobDispatchEstimation(Interface):107class IBuildFarmJobDispatchEstimation(Interface):
91 """Operations needed for job dipatch time estimation."""108 """Operations needed for job dipatch time estimation."""
92109
93110
=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
--- lib/lp/buildmaster/model/buildfarmjob.py 2009-12-24 13:18:16 +0000
+++ lib/lp/buildmaster/model/buildfarmjob.py 2010-01-14 09:57:16 +0000
@@ -5,14 +5,20 @@
5__all__ = ['BuildFarmJob']5__all__ = ['BuildFarmJob']
66
77
8from zope.interface import implements8from zope.component import getUtility
99from zope.interface import classProvides, implements
10from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob10
11from canonical.launchpad.webapp.interfaces import (
12 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE)
13
14from lp.buildmaster.interfaces.buildfarmjob import (
15 IBuildFarmJob, ISpecificBuildFarmJobClass)
1116
1217
13class BuildFarmJob:18class BuildFarmJob:
14 """Mix-in class for `IBuildFarmJob` implementations."""19 """Mix-in class for `IBuildFarmJob` implementations."""
15 implements(IBuildFarmJob)20 implements(IBuildFarmJob)
21 classProvides(ISpecificBuildFarmJobClass)
1622
17 def score(self):23 def score(self):
18 """See `IBuildFarmJob`."""24 """See `IBuildFarmJob`."""
@@ -48,3 +54,12 @@
48 """See `IBuildFarmJob`."""54 """See `IBuildFarmJob`."""
49 return None55 return None
5056
57 @classmethod
58 def getByJob(cls, job):
59 """See `ISpecificBuildFarmJobClass`.
60
61 This base implementation should work for most build farm job
62 types, but some need to override it.
63 """
64 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
65 return store.find(cls, cls.job == job).one()
5166
=== modified file 'lib/lp/code/model/branchjob.py'
--- lib/lp/code/model/branchjob.py 2010-01-12 18:13:55 +0000
+++ lib/lp/code/model/branchjob.py 2010-01-14 09:57:16 +0000
@@ -3,6 +3,8 @@
33
4__all__ = [4__all__ = [
5 'BranchJob',5 'BranchJob',
6 'BranchJobDerived',
7 'BranchJobType',
6 'BranchUpgradeJob',8 'BranchUpgradeJob',
7 'RevisionsAddedJob',9 'RevisionsAddedJob',
8 'RevisionMailJob',10 'RevisionMailJob',
911
=== modified file 'lib/lp/soyuz/interfaces/buildqueue.py'
--- lib/lp/soyuz/interfaces/buildqueue.py 2010-01-07 04:07:09 +0000
+++ lib/lp/soyuz/interfaces/buildqueue.py 2010-01-14 09:57:16 +0000
@@ -126,14 +126,21 @@
126 def __iter__():126 def __iter__():
127 """Iterate over current build jobs."""127 """Iterate over current build jobs."""
128128
129 def __getitem__(job_id):129 def __getitem__(buildqueue_id):
130 """Retrieve a build job by id."""130 """Retrieve a build job by id."""
131131
132 def count():132 def count():
133 """Return the number of build jobs in the queue."""133 """Return the number of build jobs in the queue."""
134134
135 def get(job_id):135 def get(buildqueue_id):
136 """Return the IBuildQueue with the given job_id."""136 """Return the `IBuildQueue` with the given id."""
137
138 def getByJob(job):
139 """Find the `IBuildQueue` to which `job` belongs.
140
141 :param job: A `Job`.
142 :return: The matching `IBuildQueue`, or None.
143 """
137144
138 def getByBuilder(builder):145 def getByBuilder(builder):
139 """Return an IBuildQueue instance for a builder.146 """Return an IBuildQueue instance for a builder.
140147
=== modified file 'lib/lp/soyuz/model/buildpackagejob.py'
--- lib/lp/soyuz/model/buildpackagejob.py 2010-01-12 10:44:24 +0000
+++ lib/lp/soyuz/model/buildpackagejob.py 2010-01-14 09:57:16 +0000
@@ -17,6 +17,7 @@
1717
18from lp.buildmaster.interfaces.buildfarmjob import (18from lp.buildmaster.interfaces.buildfarmjob import (
19 BuildFarmJobType, IBuildFarmJobDispatchEstimation)19 BuildFarmJobType, IBuildFarmJobDispatchEstimation)
20from lp.buildmaster.model.buildfarmjob import BuildFarmJob
20from lp.registry.interfaces.sourcepackage import SourcePackageUrgency21from lp.registry.interfaces.sourcepackage import SourcePackageUrgency
21from lp.registry.interfaces.pocket import PackagePublishingPocket22from lp.registry.interfaces.pocket import PackagePublishingPocket
22from lp.services.job.interfaces.job import JobStatus23from lp.services.job.interfaces.job import JobStatus
@@ -25,7 +26,7 @@
25from lp.soyuz.interfaces.buildpackagejob import IBuildPackageJob26from lp.soyuz.interfaces.buildpackagejob import IBuildPackageJob
2627
2728
28class BuildPackageJob(Storm):29class BuildPackageJob(Storm, BuildFarmJob):
29 """See `IBuildPackageJob`."""30 """See `IBuildPackageJob`."""
30 implements(IBuildPackageJob)31 implements(IBuildPackageJob)
31 classProvides(IBuildFarmJobDispatchEstimation)32 classProvides(IBuildFarmJobDispatchEstimation)
3233
=== modified file 'lib/lp/soyuz/model/buildqueue.py'
--- lib/lp/soyuz/model/buildqueue.py 2010-01-11 23:48:25 +0000
+++ lib/lp/soyuz/model/buildqueue.py 2010-01-14 09:57:16 +0000
@@ -78,10 +78,7 @@
78 def specific_job(self):78 def specific_job(self):
79 """See `IBuildQueue`."""79 """See `IBuildQueue`."""
80 specific_class = self.specific_job_classes[self.job_type]80 specific_class = self.specific_job_classes[self.job_type]
81 store = Store.of(self)81 return specific_class.getByJob(self.job)
82 result_set = store.find(
83 specific_class, specific_class.job == self.job)
84 return result_set.one()
8582
86 @property83 @property
87 def date_started(self):84 def date_started(self):
@@ -324,16 +321,21 @@
324 """See `IBuildQueueSet`."""321 """See `IBuildQueueSet`."""
325 return iter(BuildQueue.select())322 return iter(BuildQueue.select())
326323
327 def __getitem__(self, job_id):324 def __getitem__(self, buildqueue_id):
328 """See `IBuildQueueSet`."""325 """See `IBuildQueueSet`."""
329 try:326 try:
330 return BuildQueue.get(job_id)327 return BuildQueue.get(buildqueue_id)
331 except SQLObjectNotFound:328 except SQLObjectNotFound:
332 raise NotFoundError(job_id)329 raise NotFoundError(buildqueue_id)
333330
334 def get(self, job_id):331 def get(self, buildqueue_id):
335 """See `IBuildQueueSet`."""332 """See `IBuildQueueSet`."""
336 return BuildQueue.get(job_id)333 return BuildQueue.get(buildqueue_id)
334
335 def getByJob(self, job):
336 """See `IBuildQueueSet`."""
337 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
338 return store.find(BuildQueue, BuildQueue.job == job).one()
337339
338 def count(self):340 def count(self):
339 """See `IBuildQueueSet`."""341 """See `IBuildQueueSet`."""
340342
=== modified file 'lib/lp/soyuz/tests/test_buildqueue.py'
--- lib/lp/soyuz/tests/test_buildqueue.py 2010-01-11 23:43:59 +0000
+++ lib/lp/soyuz/tests/test_buildqueue.py 2010-01-14 09:57:16 +0000
@@ -8,15 +8,19 @@
8from pytz import utc8from pytz import utc
99
10from zope.component import getUtility10from zope.component import getUtility
11from zope.interface.verify import verifyObject
1112
12from canonical.launchpad.webapp.interfaces import (13from canonical.launchpad.webapp.interfaces import (
13 IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)14 IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)
14from canonical.testing import LaunchpadZopelessLayer15from canonical.testing import LaunchpadZopelessLayer
1516
16from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType17from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType
18from lp.services.job.model.job import Job
17from lp.soyuz.interfaces.archive import ArchivePurpose19from lp.soyuz.interfaces.archive import ArchivePurpose
18from lp.soyuz.interfaces.build import BuildStatus20from lp.soyuz.interfaces.build import BuildStatus
19from lp.buildmaster.interfaces.builder import IBuilderSet21from lp.buildmaster.interfaces.builder import IBuilderSet
22from lp.soyuz.interfaces.buildqueue import IBuildQueueSet
23from lp.soyuz.model.buildqueue import BuildQueue
20from lp.soyuz.model.processor import ProcessorFamilySet24from lp.soyuz.model.processor import ProcessorFamilySet
21from lp.soyuz.interfaces.publishing import PackagePublishingStatus25from lp.soyuz.interfaces.publishing import PackagePublishingStatus
22from lp.soyuz.model.build import Build26from lp.soyuz.model.build import Build
@@ -98,6 +102,28 @@
98 datetime.utcnow().replace(tzinfo=utc) - timedelta(seconds=offset))102 datetime.utcnow().replace(tzinfo=utc) - timedelta(seconds=offset))
99103
100104
105class TestBuildQueueSet(TestCaseWithFactory):
106 """Test for `BuildQueueSet`."""
107
108 layer = LaunchpadZopelessLayer
109
110 def setUp(self):
111 super(TestBuildQueueSet, self).setUp()
112 self.buildqueueset = getUtility(IBuildQueueSet)
113
114 def test_baseline(self):
115 verifyObject(IBuildQueueSet, self.buildqueueset)
116
117 def test_getByJob_none(self):
118 job = Job()
119 self.assertEquals(None, self.buildqueueset.getByJob(job))
120
121 def test_getByJob(self):
122 job = Job()
123 buildqueue = BuildQueue(job=job.id)
124 self.assertEquals(buildqueue, self.buildqueueset.getByJob(job))
125
126
101class TestBuildQueueBase(TestCaseWithFactory):127class TestBuildQueueBase(TestCaseWithFactory):
102 """Setup the test publisher and some builders."""128 """Setup the test publisher and some builders."""
103129
104130
=== modified file 'lib/lp/translations/configure.zcml'
--- lib/lp/translations/configure.zcml 2010-01-12 02:54:07 +0000
+++ lib/lp/translations/configure.zcml 2010-01-14 09:57:16 +0000
@@ -576,7 +576,9 @@
576 <class576 <class
577 class="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob">577 class="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob">
578 <allow578 <allow
579 interface="lp.translations.interfaces.translationtemplatesbuildjob.ITranslationTemplatesBuildJob"/>579 interface="lp.code.interfaces.branchjob.IBranchJob"/>
580 <allow
581 interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"/>
580 </class>582 </class>
581 <securedutility583 <securedutility
582 component="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob"584 component="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob"
@@ -585,7 +587,7 @@
585 </securedutility>587 </securedutility>
586 <utility588 <utility
587 component="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob"589 component="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob"
588 provides="lp.translations.interfaces.translationtemplatesbuildjob.ITranslationTemplatesBuildJob"590 provides="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"
589 name="TRANSLATIONTEMPLATESBUILD"/>591 name="TRANSLATIONTEMPLATESBUILD"/>
590592
591 <!-- TranslationTemplateBuildBehavior -->593 <!-- TranslationTemplateBuildBehavior -->
592594
=== added file 'lib/lp/translations/doc/translationtemplatesbuildbehavior.txt'
--- lib/lp/translations/doc/translationtemplatesbuildbehavior.txt 1970-01-01 00:00:00 +0000
+++ lib/lp/translations/doc/translationtemplatesbuildbehavior.txt 2010-01-14 09:57:16 +0000
@@ -0,0 +1,82 @@
1= TranslationTemplatesBuildJobBehavior =
2
3== Setup ==
4
5Set up build environment.
6
7 >>> import transaction
8 >>> import logging
9 >>> logger = logging.getLogger()
10 >>> logger.setLevel(logging.CRITICAL)
11
12 >>> from lp.buildmaster.master import BuilddMaster
13 >>> from canonical.buildd.tests import BuilddSlaveTestSetup
14 >>> bm = BuilddMaster(logger, transaction)
15 >>> BuilddSlaveTestSetup().setUp()
16
17 >>> from canonical.librarian.interfaces import ILibrarianClient
18 >>> from StringIO import StringIO
19 >>> from canonical.launchpad.interfaces import ILibraryFileAliasSet
20 >>> from canonical.launchpad.interfaces import ILaunchpadCelebrities
21
22Choose an arbitrary file as the chroot tarball for the build slave. It
23won't actually build, so it doesn't matter what's in there.
24
25The build slave uses the nominated architecture for the current Ubuntu
26release.
27
28 >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
29 >>> librarian_client = getUtility(ILibrarianClient)
30 >>> content = 'arbitrary chroot file content'
31 >>> alias_id = librarian_client.addFile(
32 ... 'foo.tar.gz', len(content), StringIO(content), 'text/plain')
33 >>> archdistroseries = ubuntu.currentseries.nominatedarchindep
34 >>> chroot = getUtility(ILibraryFileAliasSet)[alias_id]
35 >>> pc = archdistroseries.addOrUpdateChroot(chroot=chroot)
36 >>> bm.addDistroArchSeries(archdistroseries)
37 >>> bm.setupBuilders(archdistroseries)
38 >>> processor = archdistroseries.processorfamily.processors[0]
39
40Make a builder to process our build request.
41
42 >>> builder = factory.makeBuilder(virtualized=False, processor=processor)
43
44
45== Get a job! ==
46
47Use the ITranslationTemplatesBuildJobSource to create a
48TranslationTemplatesBuildJob.
49
50 >>> from lp.translations.interfaces.translationtemplatesbuildjob import (
51 ... ITranslationTemplatesBuildJobSource)
52 >>> from lp.soyuz.interfaces.buildqueue import IBuildQueueSet
53 >>> branch = factory.makeBranch()
54 >>> specific_job_source = getUtility(ITranslationTemplatesBuildJobSource)
55 >>> specific_job = specific_job_source.create(branch)
56 >>> buildqueue = getUtility(IBuildQueueSet).getByJob(specific_job.job)
57
58The build has no start date yet.
59
60 >>> print buildqueue.date_started
61 None
62
63Dispatch the job to the build slave. The proper method to call here
64would have been Builder.findAndStartJob, but it has not been generalised
65to handle new job types yet.
66
67# XXX JeroenVermeulen bug=506617: call findAndStartJob instead.
68
69 >>> from zope.security.proxy import removeSecurityProxy
70 >>> removeSecurityProxy(builder)._dispatchBuildCandidate(buildqueue)
71
72The build is now marked as started.
73
74 >>> buildqueue.date_started is None
75 False
76
77
78== Teardown ==
79
80Clean up after this test.
81
82 >>> BuilddSlaveTestSetup().tearDown()
083
=== modified file 'lib/lp/translations/interfaces/translationtemplatesbuildjob.py'
--- lib/lp/translations/interfaces/translationtemplatesbuildjob.py 2010-01-08 12:26:22 +0000
+++ lib/lp/translations/interfaces/translationtemplatesbuildjob.py 2010-01-14 09:57:16 +0000
@@ -6,32 +6,21 @@
6__metaclass__ = type6__metaclass__ = type
77
8__all__ = [8__all__ = [
9 'ITranslationTemplatesBuildJob',
10 'ITranslationTemplatesBuildJobSource',9 'ITranslationTemplatesBuildJobSource',
11 ]10 ]
1211
13from zope.interface import Interface12from zope.interface import Interface
1413
15from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
16from lp.code.interfaces.branchjob import IBranchJob
17
18
19class ITranslationTemplatesBuildJob(IBranchJob, IBuildFarmJob):
20 """Build-farm job type for generating translation templates."""
21
2214
23class ITranslationTemplatesBuildJobSource(Interface):15class ITranslationTemplatesBuildJobSource(Interface):
24 """Container for `ITranslationTemplatesBuildJob`s."""16 """Container for `TranslationTemplatesBuildJob`s."""
2517
26 def create(branch):18 def create(branch):
27 """Create new `ITranslationTemplatesBuildJob`.19 """Create new `TranslationTemplatesBuildJob`.
2820
29 Also creates the matching `IBuildQueue` and `IJob`.21 Also creates the matching `IBuildQueue` and `IJob`.
3022
31 :param branch: A `Branch` that this job will check out and23 :param branch: A `Branch` that this job will check out and
32 generate templates for.24 generate templates for.
33 :return: A new `ITranslationTemplatesBuildJob`.25 :return: A new `TranslationTemplatesBuildJob`.
34 """26 """
35
36 def getForJob(job):
37 """Find `ITranslationTemplatesBuildJob` matching given `Job`."""
3827
=== modified file 'lib/lp/translations/model/translationtemplatesbuildbehavior.py'
--- lib/lp/translations/model/translationtemplatesbuildbehavior.py 2010-01-12 21:00:05 +0000
+++ lib/lp/translations/model/translationtemplatesbuildbehavior.py 2010-01-14 09:57:16 +0000
@@ -11,9 +11,6 @@
11 'TranslationTemplatesBuildBehavior',11 'TranslationTemplatesBuildBehavior',
12 ]12 ]
1313
14import socket
15import xmlrpclib
16
17from zope.component import getUtility14from zope.component import getUtility
18from zope.interface import implements15from zope.interface import implements
1916
@@ -23,9 +20,6 @@
23 IBuildFarmJobBehavior)20 IBuildFarmJobBehavior)
24from lp.buildmaster.model.buildfarmjobbehavior import (21from lp.buildmaster.model.buildfarmjobbehavior import (
25 BuildFarmJobBehaviorBase)22 BuildFarmJobBehaviorBase)
26from lp.buildmaster.interfaces.builder import BuildSlaveFailure
27from lp.translations.interfaces.translationtemplatesbuildjob import (
28 ITranslationTemplatesBuildJobSource)
2923
3024
31class TranslationTemplatesBuildBehavior(BuildFarmJobBehaviorBase):25class TranslationTemplatesBuildBehavior(BuildFarmJobBehaviorBase):
@@ -37,43 +31,21 @@
3731
38 def dispatchBuildToSlave(self, build_queue_item, logger):32 def dispatchBuildToSlave(self, build_queue_item, logger):
39 """See `IBuildFarmJobBehavior`."""33 """See `IBuildFarmJobBehavior`."""
40 # XXX JeroenVermeulen 2009-12-24 bug=500110: This method is not
41 # covered by tests yet. Either unify it with Soyuz code into a
42 # generalised method, or test it.
43 templatesbuildjob = self._findTranslationTemplatesBuildJob(
44 build_queue_item)
45 chroot = self._getChroot()34 chroot = self._getChroot()
46 chroot_sha1 = chroot.content.sha135 chroot_sha1 = chroot.content.sha1
47 self._builder.cacheFileOnSlave(logger, chroot)36 self._builder.slave.cacheFile(logger, chroot)
48 buildid = templatesbuildjob.getName()37 buildid = self.buildfarmjob.getName()
4938
50 args = { 'branch_url': build_queue_item.branch.url }39 args = { 'branch_url': self.buildfarmjob.branch.url }
51 filemap = {}40 filemap = {}
5241
53 try:42 status, info = self._builder.slave.build(
54 status, info = self._builder.slave.build(43 buildid, self.build_type, chroot_sha1, filemap, args)
55 buildid, self.build_type, chroot_sha1, filemap, args)
56 except xmlrpclib.Fault, info:
57 # Mark builder as 'failed'.
58 logger.debug(
59 "Disabling builder: %s" % self._builder.url, exc_info=1)
60 self._builder.failbuilder(
61 "Exception (%s) when setting up to new job" % info)
62 raise BuildSlaveFailure
63 except socket.error, info:
64 error_message = "Exception (%s) when setting up new job" % info
65 self._builder.handleTimeout(logger, error_message)
66 raise BuildSlaveFailure
6744
68 def _getChroot(self):45 def _getChroot(self):
69 ubuntu = getUtility(ILaunchpadCelebrities).ubuntu46 ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
70 return ubuntu.currentseries.nominatedarchindep.getChroot()47 return ubuntu.currentseries.nominatedarchindep.getChroot()
7148
72 def _findTranslationTemplatesBuildJob(self, build_queue_item):49 def logStartBuild(self, logger):
73 """Find the `TranslationTemplatesBuildJob` for a job.50 """See `IBuildFarmJobBehavior`."""
7451 logger.info("Starting templates build.")
75 :param build_queue_item: A `BuildQueue` entry.
76 :return: The matching `TranslationTemplatesBuildJob`.
77 """
78 jobsource = getUtility(ITranslationTemplatesBuildJobSource)
79 return jobsource.getForJob(build_queue_item.job)
8052
=== modified file 'lib/lp/translations/model/translationtemplatesbuildjob.py'
--- lib/lp/translations/model/translationtemplatesbuildjob.py 2010-01-11 03:27:28 +0000
+++ lib/lp/translations/model/translationtemplatesbuildjob.py 2010-01-14 09:57:16 +0000
@@ -15,12 +15,14 @@
15from canonical.launchpad.webapp.interfaces import (15from canonical.launchpad.webapp.interfaces import (
16 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE, MASTER_FLAVOR)16 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE, MASTER_FLAVOR)
1717
18from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType18from lp.buildmaster.interfaces.buildfarmjob import (
19 BuildFarmJobType, IBuildFarmJob, ISpecificBuildFarmJobClass)
19from lp.buildmaster.model.buildfarmjob import BuildFarmJob20from lp.buildmaster.model.buildfarmjob import BuildFarmJob
21from lp.code.interfaces.branchjob import IBranchJob
20from lp.code.model.branchjob import BranchJob, BranchJobDerived, BranchJobType22from lp.code.model.branchjob import BranchJob, BranchJobDerived, BranchJobType
21from lp.soyuz.model.buildqueue import BuildQueue23from lp.soyuz.model.buildqueue import BuildQueue
22from lp.translations.interfaces.translationtemplatesbuildjob import (24from lp.translations.interfaces.translationtemplatesbuildjob import (
23 ITranslationTemplatesBuildJob, ITranslationTemplatesBuildJobSource)25 ITranslationTemplatesBuildJobSource)
2426
2527
26class TranslationTemplatesBuildJob(BranchJobDerived, BuildFarmJob):28class TranslationTemplatesBuildJob(BranchJobDerived, BuildFarmJob):
@@ -28,8 +30,9 @@
2830
29 Implementation-wise, this is actually a `BranchJob`.31 Implementation-wise, this is actually a `BranchJob`.
30 """32 """
31 implements(ITranslationTemplatesBuildJob)33 implements(IBranchJob, IBuildFarmJob)
32 classProvides(ITranslationTemplatesBuildJobSource)34 classProvides(
35 ISpecificBuildFarmJobClass, ITranslationTemplatesBuildJobSource)
3336
34 duration_estimate = timedelta(seconds=10)37 duration_estimate = timedelta(seconds=10)
3538
@@ -75,8 +78,8 @@
75 return specific_job78 return specific_job
7679
77 @classmethod80 @classmethod
78 def getForJob(cls, job):81 def getByJob(cls, job):
79 """See `ITranslationTemplatesBuildJobSource`."""82 """See `ISpecificBuildFarmJobClass`."""
80 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)83 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
81 branch_job = store.find(BranchJob, BranchJob.job == job).one()84 branch_job = store.find(BranchJob, BranchJob.job == job).one()
82 if branch_job is None:85 if branch_job is None:
8386
=== modified file 'lib/lp/translations/tests/test_translationtemplatesbuildjob.py'
--- lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-01-12 03:35:33 +0000
+++ lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-01-14 09:57:16 +0000
@@ -15,14 +15,18 @@
1515
16from lp.testing import TestCaseWithFactory16from lp.testing import TestCaseWithFactory
1717
18from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob18from lp.buildmaster.interfaces.buildfarmjob import (
19 IBuildFarmJob, ISpecificBuildFarmJobClass)
19from lp.buildmaster.interfaces.buildfarmjobbehavior import (20from lp.buildmaster.interfaces.buildfarmjobbehavior import (
20 IBuildFarmJobBehavior)21 IBuildFarmJobBehavior)
22from lp.code.interfaces.branchjob import IBranchJob
21from lp.services.job.model.job import Job23from lp.services.job.model.job import Job
22from lp.soyuz.interfaces.buildqueue import IBuildQueueSet24from lp.soyuz.interfaces.buildqueue import IBuildQueueSet
23from lp.soyuz.model.buildqueue import BuildQueue25from lp.soyuz.model.buildqueue import BuildQueue
24from lp.translations.interfaces.translationtemplatesbuildjob import (26from lp.translations.interfaces.translationtemplatesbuildjob import (
25 ITranslationTemplatesBuildJob, ITranslationTemplatesBuildJobSource)27 ITranslationTemplatesBuildJobSource)
28from lp.translations.model.translationtemplatesbuildjob import (
29 TranslationTemplatesBuildJob)
2630
2731
28def get_job_id(job):32def get_job_id(job):
@@ -43,12 +47,14 @@
4347
44 def test_new_TranslationTemplatesBuildJob(self):48 def test_new_TranslationTemplatesBuildJob(self):
45 # TranslationTemplateBuildJob implements IBuildFarmJob and49 # TranslationTemplateBuildJob implements IBuildFarmJob and
46 # ITranslationTemplatesBuildJob.50 # IBranchJob.
51 verifyObject(IBranchJob, self.specific_job)
47 verifyObject(IBuildFarmJob, self.specific_job)52 verifyObject(IBuildFarmJob, self.specific_job)
48 verifyObject(ITranslationTemplatesBuildJob, self.specific_job)
4953
50 # The class also implements a utility.54 # The class also implements a utility and
55 # ISpecificBuildFarmJobClass.
51 verifyObject(ITranslationTemplatesBuildJobSource, self.jobset)56 verifyObject(ITranslationTemplatesBuildJobSource, self.jobset)
57 verifyObject(ISpecificBuildFarmJobClass, TranslationTemplatesBuildJob)
5258
53 # Each of these jobs knows the branch it will operate on.59 # Each of these jobs knows the branch it will operate on.
54 self.assertEqual(self.branch, self.specific_job.branch)60 self.assertEqual(self.branch, self.specific_job.branch)
@@ -61,7 +67,7 @@
61 # From a Job, the TranslationTemplatesBuildJobSource can find the67 # From a Job, the TranslationTemplatesBuildJobSource can find the
62 # TranslationTemplatesBuildJob back for us.68 # TranslationTemplatesBuildJob back for us.
63 specific_job_for_base_job = removeSecurityProxy(69 specific_job_for_base_job = removeSecurityProxy(
64 self.jobset.getForJob(base_job))70 TranslationTemplatesBuildJob.getByJob(base_job))
65 self.assertEqual(self.specific_job, specific_job_for_base_job)71 self.assertEqual(self.specific_job, specific_job_for_base_job)
6672
67 def test_has_BuildQueue(self):73 def test_has_BuildQueue(self):
@@ -119,14 +125,6 @@
119 self.assertNotEqual(None, chroot)125 self.assertNotEqual(None, chroot)
120 self.assertEqual(fake_chroot_file, chroot)126 self.assertEqual(fake_chroot_file, chroot)
121127
122 def test_findTranslationTemplatesBuildJob(self):
123 job = self.specific_job.job
124 job_id = removeSecurityProxy(job).id
125 buildqueue = getUtility(IBuildQueueSet).get(job_id)
126 specific_job_for_buildqueue = removeSecurityProxy(
127 self.behavior._findTranslationTemplatesBuildJob(buildqueue))
128 self.assertEqual(self.specific_job, specific_job_for_buildqueue)
129
130128
131def test_suite():129def test_suite():
132 return TestLoader().loadTestsFromName(__name__)130 return TestLoader().loadTestsFromName(__name__)