Merge lp:~michael.nelson/launchpad/db-build-farm-job-model into lp:launchpad/db-devel

Proposed by Michael Nelson
Status: Merged
Approved by: Michael Nelson
Approved revision: no longer in the source branch.
Merged at revision: 9405
Proposed branch: lp:~michael.nelson/launchpad/db-build-farm-job-model
Merge into: lp:launchpad/db-devel
Prerequisite: lp:~michael.nelson/launchpad/db-build-generalisation-db-changes
Diff against target: 484 lines (+327/-37)
6 files modified
lib/canonical/launchpad/interfaces/_schema_circular_imports.py (+5/-0)
lib/lp/buildmaster/configure.zcml (+15/-0)
lib/lp/buildmaster/interfaces/buildfarmjob.py (+82/-14)
lib/lp/buildmaster/model/buildfarmjob.py (+102/-22)
lib/lp/buildmaster/model/packagebuildfarmjob.py (+3/-1)
lib/lp/buildmaster/tests/test_buildfarmjob.py (+120/-0)
To merge this branch: bzr merge lp:~michael.nelson/launchpad/db-build-farm-job-model
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) Abstain
Abel Deuring (community) code Approve
Review via email: mp+23913@code.launchpad.net

Description of the change

This branch is part of a pipeline for

https://blueprints.edge.launchpad.net/soyuz/+spec/build-generalisation
https://dev.launchpad.net/LEP/GeneralBuildHistories

In particular, this branch turns BuildFarmJob into a concrete class, while at the same time, continuing support temporarily for classes that still expect this to be an in-memory object.

It is dependent on the pending schema patch in a previous branch.

To test
=======

First update the test db schema (required as the db patch still needs to be updated to remove the old build table):
psql launchpad_ftest_template -f database/schema/pending/michaeln-build-generalisation.sql
bin/py database/schema/security.py -d launchpad_ftest_template

And then:
bin/test -vvt test_buildfarmjob -t doc/build.txt -t test_buildqueue -t test_sourcepackagerecipebuild -t test_translationtemplatesbuildjob

The next stage will be a similar conversion for PackageBuildFarmJob, followed by switching the BinaryPackageBuild from the old build table to the new binarypackagebuild table.

To post a comment you must log in.
Revision history for this message
Abel Deuring (adeuring) wrote :

This branch is part of a pipeline for

https://blueprints.edge.launchpad.net/soyuz/+spec/build-generalisation
https://dev.launchpad.net/LEP/GeneralBuildHistories

In particular, this branch turns BuildFarmJob into a concrete class, while at the same time, continuing support temporarily for classes that still expect this to be an in-memory object.

It is dependent on the pending schema patch in a previous branch.

To test
=======

First update the test db schema (required as the db patch still needs to be updated to remove the old build table):
psql launchpad_ftest_template -f database/schema/pending/michaeln-build-generalisation.sql
bin/py database/schema/security.py -d launchpad_ftest_template

And then:
bin/test -vvt test_buildfarmjob -t doc/build.txt -t test_buildqueue -t test_sourcepackagerecipebuild -t test_translationtemplatesbuildjob

The next stage will be a similar conversion for PackageBuildFarmJob, followed by switching the BinaryPackageBuild from the old build table to the new binarypackagebuild table.

review: Approve (code)
Revision history for this message
Abel Deuring (adeuring) wrote :
Download full text (4.8 KiB)

Hi Michael,

a nice branch; just just have a few formal nitpicks.

> === modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
> --- lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-04-21 07:15:40 +0000
> +++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-04-22 07:42:23 +0000
> @@ -9,15 +9,20 @@
>
> __all__ = [
> 'IBuildFarmJob',
> + 'IBuildFarmJobSource',
> 'IBuildFarmJobDerived',
> 'BuildFarmJobType',
> ]
>
> from zope.interface import Interface, Attribute
> -
> -from canonical.launchpad import _
> +from zope.schema import Bool, Choice, Datetime
> from lazr.enum import DBEnumeratedType, DBItem
> from lazr.restful.fields import Reference
> +
> +from canonical.launchpad import _
> +from canonical.launchpad.interfaces.librarian import ILibraryFileAlias
> +
> +from lp.buildmaster.interfaces.builder import IBuilder
> from lp.soyuz.interfaces.processor import IProcessor
>
>
> @@ -56,6 +61,66 @@
> class IBuildFarmJob(Interface):
> """Operations that jobs for the build farm must implement."""
>
> + id = Attribute('The build farm job ID.')
> +
> + processor = Reference(
> + IProcessor, title=_("Processor"), required=False, readonly=True,
> + description=_(
> + "The Processor required by this build farm job. "
> + "For processor-independent job types please return None."))

It is perhaps my limited English knowledge, but this sounds to me
like a polite request to the implementation class to do the right
thing ;) What about "should|must be None for processor-independent jobs"?

> +
> + virtualized = Bool(
> + title=_('Virtualized'), required=False, readonly=True,
> + description=_(
> + "The virtualization setting required by this build farm job. "
> + "For job types that do not care about virtualization please "
> + "return None."))

Same here.

> +
> + date_created = Datetime(
> + title=_("Date created"), required=True, readonly=True,
> + description=_("The timestamp when the build farm job was created."))
> +
> + date_started = Datetime(
> + title=_("Date started"), required=False, readonly=True,
> + description=_("The timestamp when the build farm job was started."))
> +
> + date_finished = Datetime(
> + title=_("Date finished"), required=False, readonly=True,
> + description=_("The timestamp when the build farm job was finished."))
> +
> + date_first_dispatched = Datetime(
> + title=_("Date finished"), required=False, readonly=True,
> + description=_("The timestamp when the build farm job was finished."))

s/finished/dispatched/

> +
> + builder = Reference(
> + title=_("Builder"), schema=IBuilder, required=False, readonly=True,
> + description=_("The builder assigned to this job."))
> +
> + status = Choice(
> + title=_('Status'), required=True,
> + # Really PackagePublishingPocket, patched in

s/PackagePublishingPocket/BuildStatus/

[...]

> @@ -149,3 +202,17 @@
> accurately based on this job's properties.
> """
>
> +
> +class IBuildFarmJobSource(Interface):
> + """A utility of Build...

Read more...

Revision history for this message
Michael Nelson (michael.nelson) wrote :
Download full text (6.0 KiB)

On Fri, Apr 23, 2010 at 12:53 PM, Abel Deuring
<email address hidden> wrote:
> Hi Michael,
>
> a nice branch; just just have a few formal nitpicks.

Thanks Abel, comments below.

>
>> === modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
>> --- lib/lp/buildmaster/interfaces/buildfarmjob.py     2010-04-21 07:15:40 +0000
>> +++ lib/lp/buildmaster/interfaces/buildfarmjob.py     2010-04-22 07:42:23 +0000
>> @@ -9,15 +9,20 @@
>>
>>  __all__ = [
>>      'IBuildFarmJob',
>> +    'IBuildFarmJobSource',
>>      'IBuildFarmJobDerived',
>>      'BuildFarmJobType',
>>      ]
>>
>>  from zope.interface import Interface, Attribute
>> -
>> -from canonical.launchpad import _
>> +from zope.schema import Bool, Choice, Datetime
>>  from lazr.enum import DBEnumeratedType, DBItem
>>  from lazr.restful.fields import Reference
>> +
>> +from canonical.launchpad import _
>> +from canonical.launchpad.interfaces.librarian import ILibraryFileAlias
>> +
>> +from lp.buildmaster.interfaces.builder import IBuilder
>>  from lp.soyuz.interfaces.processor import IProcessor
>>
>>
>> @@ -56,6 +61,66 @@
>>  class IBuildFarmJob(Interface):
>>      """Operations that jobs for the build farm must implement."""
>>
>> +    id = Attribute('The build farm job ID.')
>> +
>> +    processor = Reference(
>> +        IProcessor, title=_("Processor"), required=False, readonly=True,
>> +        description=_(
>> +            "The Processor required by this build farm job. "
>> +            "For processor-independent job types please return None."))
>
> It is perhaps my limited English knowledge, but this sounds to me
> like a polite request to the implementation class to do the right
> thing ;) What about "should|must be None for processor-independent jobs"?

Yep. This was just a copy-n-paste, but you're right. Updated.

>
>
>> +
>> +    virtualized = Bool(
>> +        title=_('Virtualized'), required=False, readonly=True,
>> +        description=_(
>> +            "The virtualization setting required by this build farm job. "
>> +            "For job types that do not care about virtualization please "
>> +            "return None."))
>
> Same here.

Ditto.

>
>> +
>> +    date_created = Datetime(
>> +        title=_("Date created"), required=True, readonly=True,
>> +        description=_("The timestamp when the build farm job was created."))
>> +
>> +    date_started = Datetime(
>> +        title=_("Date started"), required=False, readonly=True,
>> +        description=_("The timestamp when the build farm job was started."))
>> +
>> +    date_finished = Datetime(
>> +        title=_("Date finished"), required=False, readonly=True,
>> +        description=_("The timestamp when the build farm job was finished."))
>> +
>> +    date_first_dispatched = Datetime(
>> +        title=_("Date finished"), required=False, readonly=True,
>> +        description=_("The timestamp when the build farm job was finished."))
>
> s/finished/dispatched/

Done.

>
>> +
>> +    builder = Reference(
>> +        title=_("Builder"), schema=IBuilder, required=False, readonly=True,
>> +        description=_("The builder assigned to this job."))
>> +
>> +    status = Choice(
>> +        title=_('Status'...

Read more...

=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
--- lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-04-21 16:08:35 +0000
+++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-04-23 12:13:43 +0000
@@ -67,14 +67,14 @@
67 IProcessor, title=_("Processor"), required=False, readonly=True,67 IProcessor, title=_("Processor"), required=False, readonly=True,
68 description=_(68 description=_(
69 "The Processor required by this build farm job. "69 "The Processor required by this build farm job. "
70 "For processor-independent job types please return None."))70 "This should be None for processor-independent job types."))
7171
72 virtualized = Bool(72 virtualized = Bool(
73 title=_('Virtualized'), required=False, readonly=True,73 title=_('Virtualized'), required=False, readonly=True,
74 description=_(74 description=_(
75 "The virtualization setting required by this build farm job. "75 "The virtualization setting required by this build farm job. "
76 "For job types that do not care about virtualization please "76 "This should be None for job types that do not care whether "
77 "return None."))77 "they run virtualized."))
7878
79 date_created = Datetime(79 date_created = Datetime(
80 title=_("Date created"), required=True, readonly=True,80 title=_("Date created"), required=True, readonly=True,
@@ -90,7 +90,7 @@
9090
91 date_first_dispatched = Datetime(91 date_first_dispatched = Datetime(
92 title=_("Date finished"), required=False, readonly=True,92 title=_("Date finished"), required=False, readonly=True,
93 description=_("The timestamp when the build farm job was finished."))93 description=_("The timestamp when the build farm job was dispatched."))
9494
95 builder = Reference(95 builder = Reference(
96 title=_("Builder"), schema=IBuilder, required=False, readonly=True,96 title=_("Builder"), schema=IBuilder, required=False, readonly=True,
@@ -98,7 +98,7 @@
9898
99 status = Choice(99 status = Choice(
100 title=_('Status'), required=True,100 title=_('Status'), required=True,
101 # Really PackagePublishingPocket, patched in101 # Really BuildStatus, patched in
102 # _schema_circular_imports.py102 # _schema_circular_imports.py
103 vocabulary=DBEnumeratedType,103 vocabulary=DBEnumeratedType,
104 description=_("The current status of the job."))104 description=_("The current status of the job."))
105105
=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
--- lib/lp/buildmaster/model/buildfarmjob.py 2010-04-21 16:08:35 +0000
+++ lib/lp/buildmaster/model/buildfarmjob.py 2010-04-23 12:20:34 +0000
@@ -71,10 +71,8 @@
71 job_type = DBEnum(71 job_type = DBEnum(
72 name='job_type', allow_none=False, enum=BuildFarmJobType)72 name='job_type', allow_none=False, enum=BuildFarmJobType)
7373
74 def __init__(self, job_type, status=None, processor=None,74 def __init__(self, job_type, status=BuildStatus.NEEDSBUILD,
75 virtualized=None):75 processor=None, virtualized=None):
76 if status is None:
77 status = BuildStatus.NEEDSBUILD
78 self.job_type, self.status, self.process, self.virtualized = (76 self.job_type, self.status, self.process, self.virtualized = (
79 job_type,77 job_type,
80 status,78 status,
@@ -83,7 +81,7 @@
83 )81 )
8482
85 @classmethod83 @classmethod
86 def new(cls, job_type, status=None, processor=None,84 def new(cls, job_type, status=BuildStatus.NEEDSBUILD, processor=None,
87 virtualized=None):85 virtualized=None):
88 """See `IBuildFarmJobSource`."""86 """See `IBuildFarmJobSource`."""
89 build_farm_job = BuildFarmJob(87 build_farm_job = BuildFarmJob(
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Abstain

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py'
--- lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-04-23 03:16:22 +0000
+++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-05-05 15:46:51 +0000
@@ -34,6 +34,7 @@
34from lp.bugs.interfaces.bugtracker import IBugTracker34from lp.bugs.interfaces.bugtracker import IBugTracker
35from lp.bugs.interfaces.bugwatch import IBugWatch35from lp.bugs.interfaces.bugwatch import IBugWatch
36from lp.buildmaster.interfaces.buildbase import BuildStatus36from lp.buildmaster.interfaces.buildbase import BuildStatus
37from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
37from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuild38from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuild
38from lp.soyuz.interfaces.buildrecords import IHasBuildRecords39from lp.soyuz.interfaces.buildrecords import IHasBuildRecords
39from lp.blueprints.interfaces.specification import ISpecification40from lp.blueprints.interfaces.specification import ISpecification
@@ -271,6 +272,10 @@
271patch_plain_parameter_type(272patch_plain_parameter_type(
272 IArchive, 'deletePackagesetUploader', 'packageset', IPackageset)273 IArchive, 'deletePackagesetUploader', 'packageset', IPackageset)
273274
275
276# IBuildFarmJob
277IBuildFarmJob['status'].vocabulary = BuildStatus
278
274# IDistribution279# IDistribution
275IDistribution['series'].value_type.schema = IDistroSeries280IDistribution['series'].value_type.schema = IDistroSeries
276patch_reference_property(281patch_reference_property(
277282
=== modified file 'lib/lp/buildmaster/configure.zcml'
--- lib/lp/buildmaster/configure.zcml 2010-03-05 13:52:32 +0000
+++ lib/lp/buildmaster/configure.zcml 2010-05-05 15:46:51 +0000
@@ -42,6 +42,21 @@
42 permission="zope.Public"/>42 permission="zope.Public"/>
4343
4444
45 <!-- BuildFarmJob -->
46 <class
47 class="lp.buildmaster.model.buildfarmjob.BuildFarmJob">
48 <allow
49 interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob" />
50 </class>
51 <securedutility
52 component="lp.buildmaster.model.buildfarmjob.BuildFarmJob"
53 provides="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJobSource">
54
55 <allow
56 interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJobSource" />
57 </securedutility>
58
59
45 <!-- BuildQueue -->60 <!-- BuildQueue -->
46 <class61 <class
47 class="lp.buildmaster.model.buildqueue.BuildQueue">62 class="lp.buildmaster.model.buildqueue.BuildQueue">
4863
=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
--- lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-04-28 08:24:54 +0000
+++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-05-05 15:46:51 +0000
@@ -9,15 +9,20 @@
99
10__all__ = [10__all__ = [
11 'IBuildFarmJob',11 'IBuildFarmJob',
12 'IBuildFarmJobSource',
12 'IBuildFarmJobDerived',13 'IBuildFarmJobDerived',
13 'BuildFarmJobType',14 'BuildFarmJobType',
14 ]15 ]
1516
16from zope.interface import Interface, Attribute17from zope.interface import Interface, Attribute
1718from zope.schema import Bool, Choice, Datetime
18from canonical.launchpad import _
19from lazr.enum import DBEnumeratedType, DBItem19from lazr.enum import DBEnumeratedType, DBItem
20from lazr.restful.fields import Reference20from lazr.restful.fields import Reference
21
22from canonical.launchpad import _
23from canonical.launchpad.interfaces.librarian import ILibraryFileAlias
24
25from lp.buildmaster.interfaces.builder import IBuilder
21from lp.soyuz.interfaces.processor import IProcessor26from lp.soyuz.interfaces.processor import IProcessor
2227
2328
@@ -56,6 +61,66 @@
56class IBuildFarmJob(Interface):61class IBuildFarmJob(Interface):
57 """Operations that jobs for the build farm must implement."""62 """Operations that jobs for the build farm must implement."""
5863
64 id = Attribute('The build farm job ID.')
65
66 processor = Reference(
67 IProcessor, title=_("Processor"), required=False, readonly=True,
68 description=_(
69 "The Processor required by this build farm job. "
70 "This should be None for processor-independent job types."))
71
72 virtualized = Bool(
73 title=_('Virtualized'), required=False, readonly=True,
74 description=_(
75 "The virtualization setting required by this build farm job. "
76 "This should be None for job types that do not care whether "
77 "they run virtualized."))
78
79 date_created = Datetime(
80 title=_("Date created"), required=True, readonly=True,
81 description=_("The timestamp when the build farm job was created."))
82
83 date_started = Datetime(
84 title=_("Date started"), required=False, readonly=True,
85 description=_("The timestamp when the build farm job was started."))
86
87 date_finished = Datetime(
88 title=_("Date finished"), required=False, readonly=True,
89 description=_("The timestamp when the build farm job was finished."))
90
91 date_first_dispatched = Datetime(
92 title=_("Date finished"), required=False, readonly=True,
93 description=_("The timestamp when the build farm job was dispatched."))
94
95 builder = Reference(
96 title=_("Builder"), schema=IBuilder, required=False, readonly=True,
97 description=_("The builder assigned to this job."))
98
99 status = Choice(
100 title=_('Status'), required=True,
101 # Really BuildStatus, patched in
102 # _schema_circular_imports.py
103 vocabulary=DBEnumeratedType,
104 description=_("The current status of the job."))
105
106 log = Reference(
107 schema=ILibraryFileAlias, required=False,
108 title=_(
109 "The LibraryFileAlias containing the entire log for this job."))
110
111 job_type = Choice(
112 title=_("Job type"), required=True, readonly=True,
113 vocabulary=BuildFarmJobType,
114 description=_("The specific type of job."))
115
116 # XXX 2010-04-21 michael.nelson bug=567922. This property
117 # can be removed once all *Build classes use the concrete
118 # BuildFarmJob.
119 has_concrete_build_farm_job = Bool(
120 title=_('Has concrete build farm job'), required=False,
121 readonly=True, description=_(
122 'Whether this instance is or has a concrete build farm job.'))
123
59 def score():124 def score():
60 """Calculate a job score appropriate for the job type in question."""125 """Calculate a job score appropriate for the job type in question."""
61126
@@ -77,18 +142,6 @@
77 def jobAborted():142 def jobAborted():
78 """'Job aborted' life cycle event, handle as appropriate."""143 """'Job aborted' life cycle event, handle as appropriate."""
79144
80 processor = Reference(
81 IProcessor, title=_("Processor"),
82 description=_(
83 "The Processor required by this build farm job. "
84 "For processor-independent job types please return None."))
85
86 virtualized = Attribute(
87 _(
88 "The virtualization setting required by this build farm job. "
89 "For job types that do not care about virtualization please "
90 "return None."))
91
92145
93class IBuildFarmJobDerived(Interface):146class IBuildFarmJobDerived(Interface):
94 """Common functionality required by classes delegating IBuildFarmJob.147 """Common functionality required by classes delegating IBuildFarmJob.
@@ -151,3 +204,18 @@
151204
152 def cleanUp():205 def cleanUp():
153 """Job's finished. Delete its supporting data."""206 """Job's finished. Delete its supporting data."""
207
208
209class IBuildFarmJobSource(Interface):
210 """A utility of BuildFarmJob used to create _things_."""
211
212 def new(job_type, status=None, processor=None,
213 virtualized=None):
214 """Create a new `IBuildFarmJob`.
215
216 :param job_type: A `BuildFarmJobType` item.
217 :param status: A `BuildStatus` item, defaulting to PENDING.
218 :param processor: An optional processor for this job.
219 :param virtualized: An optional boolean indicating whether
220 this job should be run virtualized.
221 """
154222
=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
--- lib/lp/buildmaster/model/buildfarmjob.py 2010-04-28 08:24:54 +0000
+++ lib/lp/buildmaster/model/buildfarmjob.py 2010-05-05 15:46:51 +0000
@@ -12,23 +12,93 @@
1212
13from lazr.delegates import delegates13from lazr.delegates import delegates
1414
15import hashlib
16import pytz
17
18from storm.info import get_obj_info
19from storm.locals import Bool, DateTime, Int, Reference, Storm
20from storm.store import Store
21
15from zope.component import getUtility22from zope.component import getUtility
16from zope.interface import implements23from zope.interface import classProvides, implements
17from zope.security.proxy import removeSecurityProxy24from zope.security.proxy import removeSecurityProxy
1825
19from storm.store import Store26from canonical.database.constants import UTC_NOW
2027from canonical.database.enumcol import DBEnum
28from canonical.launchpad.interfaces.lpstorm import IMasterStore
21from canonical.launchpad.webapp.interfaces import (29from canonical.launchpad.webapp.interfaces import (
22 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE)30 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE)
2331
32from lp.buildmaster.interfaces.buildbase import BuildStatus
24from lp.buildmaster.interfaces.buildfarmjob import (33from lp.buildmaster.interfaces.buildfarmjob import (
25 IBuildFarmJob, IBuildFarmJobDerived)34 BuildFarmJobType, IBuildFarmJob, IBuildFarmJobDerived,
35 IBuildFarmJobSource)
26from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet36from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
2737
2838
29class BuildFarmJob:39class BuildFarmJob(Storm):
30 """A base implementation for `IBuildFarmJob` classes."""40 """A base implementation for `IBuildFarmJob` classes."""
41
42 __storm_table__ = 'BuildFarmJob'
43
31 implements(IBuildFarmJob)44 implements(IBuildFarmJob)
45 classProvides(IBuildFarmJobSource)
46
47 id = Int(primary=True)
48
49 processor_id = Int(name='processor', allow_none=True)
50 processor = Reference(processor_id, 'Processor.id')
51
52 virtualized = Bool()
53
54 date_created = DateTime(
55 name='date_created', allow_none=False, tzinfo=pytz.UTC)
56
57 date_started = DateTime(
58 name='date_started', allow_none=True, tzinfo=pytz.UTC)
59
60 date_finished = DateTime(
61 name='date_finished', allow_none=True, tzinfo=pytz.UTC)
62
63 date_first_dispatched = DateTime(
64 name='date_first_dispatched', allow_none=True, tzinfo=pytz.UTC)
65
66 builder_id = Int(name='builder', allow_none=True)
67 builder = Reference(builder_id, 'Builder.id')
68
69 status = DBEnum(name='status', allow_none=False, enum=BuildStatus)
70
71 log_id = Int(name='log', allow_none=True)
72 log = Reference(log_id, 'LibraryFileAlias.id')
73
74 job_type = DBEnum(
75 name='job_type', allow_none=False, enum=BuildFarmJobType)
76
77 def __init__(self, job_type, status=BuildStatus.NEEDSBUILD,
78 processor=None, virtualized=None):
79 self.job_type, self.status, self.process, self.virtualized = (
80 job_type,
81 status,
82 processor,
83 virtualized,
84 )
85
86 @classmethod
87 def new(cls, job_type, status=BuildStatus.NEEDSBUILD, processor=None,
88 virtualized=None):
89 """See `IBuildFarmJobSource`."""
90 build_farm_job = BuildFarmJob(
91 job_type, status, processor, virtualized)
92
93 store = IMasterStore(BuildFarmJob)
94 store.add(build_farm_job)
95 return build_farm_job
96
97 @property
98 def has_concrete_build_farm_job(self):
99 """See `IBuildFarmJob`."""
100 # Check if the object has been added to the store.
101 return get_obj_info(self).get('store') is not None
32102
33 def score(self):103 def score(self):
34 """See `IBuildFarmJob`."""104 """See `IBuildFarmJob`."""
@@ -48,25 +118,34 @@
48118
49 def jobStarted(self):119 def jobStarted(self):
50 """See `IBuildFarmJob`."""120 """See `IBuildFarmJob`."""
51 pass121 if not self.has_concrete_build_farm_job:
122 return
123 self.status = BuildStatus.BUILDING
124 # The build started, set the start time if not set already.
125 self.date_started = UTC_NOW
126 if self.date_first_dispatched is None:
127 self.date_first_dispatched = UTC_NOW
52128
53 def jobReset(self):129 def jobReset(self):
54 """See `IBuildFarmJob`."""130 """See `IBuildFarmJob`."""
55 pass131 if not self.has_concrete_build_farm_job:
56132 return
57 def jobAborted(self):133 self.status = BuildStatus.NEEDSBUILD
58 """See `IBuildFarmJob`."""134 self.date_started = None
59 pass135
60136 # The implementation of aborting a job is the same as resetting
61 @property137 # a job.
62 def processor(self):138 jobAborted = jobReset
63 """See `IBuildFarmJob`."""139
64 return None140 @staticmethod
65141 def addCandidateSelectionCriteria(processor, virtualized):
66 @property142 """See `IBuildFarmJob`."""
67 def virtualized(self):143 return ('')
68 """See `IBuildFarmJob`."""144
69 return None145 @staticmethod
146 def postprocessCandidate(job, logger):
147 """See `IBuildFarmJob`."""
148 return True
70149
71150
72class BuildFarmJobDerived:151class BuildFarmJobDerived:
@@ -92,7 +171,8 @@
92171
93 Sub-classes can override as required.172 Sub-classes can override as required.
94 """173 """
95 self._build_farm_job = BuildFarmJob()174 self._build_farm_job = BuildFarmJob(
175 job_type=BuildFarmJobType.PACKAGEBUILD)
96176
97 @classmethod177 @classmethod
98 def getByJob(cls, job):178 def getByJob(cls, job):
99179
=== modified file 'lib/lp/buildmaster/model/packagebuildfarmjob.py'
--- lib/lp/buildmaster/model/packagebuildfarmjob.py 2010-04-28 08:24:54 +0000
+++ lib/lp/buildmaster/model/packagebuildfarmjob.py 2010-05-05 15:46:51 +0000
@@ -26,7 +26,9 @@
26 itself a concrete class. This class (PackageBuildFarmJob)26 itself a concrete class. This class (PackageBuildFarmJob)
27 will also be renamed PackageBuild and turned into a concrete class.27 will also be renamed PackageBuild and turned into a concrete class.
28 """28 """
29 super(PackageBuildFarmJob, self).__init__()29 # Classes that initialise with a build are not yet using
30 # the concrete class, so we don't call the superclass'
31 # initialisation.
30 self.build = build32 self.build = build
3133
32 def getTitle(self):34 def getTitle(self):
3335
=== added file 'lib/lp/buildmaster/tests/test_buildfarmjob.py'
--- lib/lp/buildmaster/tests/test_buildfarmjob.py 1970-01-01 00:00:00 +0000
+++ lib/lp/buildmaster/tests/test_buildfarmjob.py 2010-05-05 15:46:51 +0000
@@ -0,0 +1,120 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Tests for `IBuildFarmJob`."""
5
6__metaclass__ = type
7
8import unittest
9
10from storm.store import Store
11from zope.component import getUtility
12
13from canonical.database.sqlbase import flush_database_updates
14from canonical.testing.layers import DatabaseFunctionalLayer
15
16from lp.buildmaster.interfaces.buildbase import BuildStatus
17from lp.buildmaster.interfaces.buildfarmjob import (
18 BuildFarmJobType, IBuildFarmJob, IBuildFarmJobSource)
19from lp.buildmaster.model.buildfarmjob import BuildFarmJob
20from lp.testing import TestCaseWithFactory
21
22
23class TestBuildFarmJob(TestCaseWithFactory):
24 """Tests for the build farm job object."""
25
26 layer = DatabaseFunctionalLayer
27
28 def setUp(self):
29 """Create a build farm job with which to test."""
30 super(TestBuildFarmJob, self).setUp()
31 self.build_farm_job = self.makeBuildFarmJob()
32
33 def makeBuildFarmJob(self):
34 return getUtility(IBuildFarmJobSource).new(
35 job_type=BuildFarmJobType.PACKAGEBUILD)
36
37 def test_has_concrete_build_farm_job(self):
38 # This temporary property returns true if the instance
39 # corresponds to a concrete database record, even if
40 # db updates have not yet been flushed, and false
41 # otherwise.
42 concrete_build_farm_job = self.makeBuildFarmJob()
43 self.failUnless(concrete_build_farm_job.has_concrete_build_farm_job)
44
45 mem_build_farm_job = BuildFarmJob(
46 job_type=BuildFarmJobType.PACKAGEBUILD)
47 self.failIf(mem_build_farm_job.has_concrete_build_farm_job)
48
49 def test_providesInterface(self):
50 # BuildFarmJob provides IBuildFarmJob
51 self.assertProvides(self.build_farm_job, IBuildFarmJob)
52
53 def test_saves_record(self):
54 # A build farm job can be stored in the database.
55 flush_database_updates()
56 store = Store.of(self.build_farm_job)
57 retrieved_job = store.find(
58 BuildFarmJob,
59 BuildFarmJob.id == self.build_farm_job.id).one()
60 self.assertEqual(self.build_farm_job, retrieved_job)
61
62 def test_default_values(self):
63 # A build farm job defaults to the NEEDSBUILD status.
64 # We flush the database updates to ensure sql defaults
65 # are set for various attributes.
66 flush_database_updates()
67 self.assertEqual(
68 BuildStatus.NEEDSBUILD, self.build_farm_job.status)
69 # The date_created is set automatically.
70 self.assertTrue(self.build_farm_job.date_created is not None)
71 # The job type is required to create a build farm job.
72 self.assertEqual(
73 BuildFarmJobType.PACKAGEBUILD, self.build_farm_job.job_type)
74 # Other attributes are unset by default.
75 self.assertEqual(None, self.build_farm_job.processor)
76 self.assertEqual(None, self.build_farm_job.virtualized)
77 self.assertEqual(None, self.build_farm_job.date_started)
78 self.assertEqual(None, self.build_farm_job.date_finished)
79 self.assertEqual(None, self.build_farm_job.date_first_dispatched)
80 self.assertEqual(None, self.build_farm_job.builder)
81 self.assertEqual(None, self.build_farm_job.log)
82
83 def test_unimplemented_methods(self):
84 # A build farm job leaves the implementation of various
85 # methods for derived classes.
86 self.assertRaises(NotImplementedError, self.build_farm_job.score)
87 self.assertRaises(NotImplementedError, self.build_farm_job.getName)
88 self.assertRaises(NotImplementedError, self.build_farm_job.getTitle)
89
90 def test_jobStarted(self):
91 # Starting a job sets the date_started and status, as well as
92 # the date first dispatched, if it is the first dispatch of
93 # this job.
94 self.build_farm_job.jobStarted()
95 self.assertTrue(self.build_farm_job.date_first_dispatched is not None)
96 self.assertTrue(self.build_farm_job.date_started is not None)
97 self.assertEqual(
98 BuildStatus.BUILDING, self.build_farm_job.status)
99
100 def test_jobReset(self):
101 # Resetting a job sets its status back to NEEDSBUILD and unsets
102 # the date_started.
103 self.build_farm_job.jobStarted()
104 self.build_farm_job.jobReset()
105 self.failUnlessEqual(
106 BuildStatus.NEEDSBUILD, self.build_farm_job.status)
107 self.failUnless(self.build_farm_job.date_started is None)
108
109 def test_jobAborted(self):
110 # Aborting a job sets its status back to NEEDSBUILD and unsets
111 # the date_started.
112 self.build_farm_job.jobStarted()
113 self.build_farm_job.jobAborted()
114 self.failUnlessEqual(
115 BuildStatus.NEEDSBUILD, self.build_farm_job.status)
116 self.failUnless(self.build_farm_job.date_started is None)
117
118
119def test_suite():
120 return unittest.TestLoader().loadTestsFromName(__name__)

Subscribers

People subscribed via source and target branches

to status/vote changes: