Merge lp:~michael.nelson/launchpad/587113-buildbase-handleStatus into lp:launchpad
- 587113-buildbase-handleStatus
- Merge into devel
Proposed by
Michael Nelson
on 2010-06-08
| Status: | Merged | ||||
|---|---|---|---|---|---|
| Approved by: | Graham Binns on 2010-06-08 | ||||
| Approved revision: | no longer in the source branch. | ||||
| Merged at revision: | 10970 | ||||
| Proposed branch: | lp:~michael.nelson/launchpad/587113-buildbase-handleStatus | ||||
| Merge into: | lp:launchpad | ||||
| Diff against target: |
531 lines (+198/-69) 10 files modified
lib/canonical/launchpad/webapp/configure.zcml (+1/-1) lib/canonical/launchpad/webapp/tales.py (+2/-2) lib/lp/buildmaster/interfaces/buildbase.py (+27/-12) lib/lp/buildmaster/model/buildbase.py (+24/-13) lib/lp/buildmaster/model/packagebuild.py (+2/-2) lib/lp/buildmaster/tests/test_buildbase.py (+76/-35) lib/lp/code/model/sourcepackagerecipebuild.py (+7/-1) lib/lp/code/model/tests/test_sourcepackagerecipebuild.py (+31/-1) lib/lp/soyuz/tests/test_binarypackagebuild.py (+23/-0) lib/lp/testing/factory.py (+5/-2) |
||||
| To merge this branch: | bzr merge lp:~michael.nelson/launchpad/587113-buildbase-handleStatus | ||||
| Related bugs: |
|
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Graham Binns (community) | code | 2010-06-08 | Approve on 2010-06-08 |
|
Review via email:
|
|||
Commit Message
Description of the Change
This branch fixes the core issue of bug 587113.
It refactors the tests so that handleStatus() is called for both BinaryPackageBuilds and SourcePackageRe
It also adds other tests to ensure log files and other attributes are correctly added for both build types.
To enable the shared implementation to work for both classes (until SourcePackageRe
To test:
bin/test -vv -m test_sourcepack
To post a comment you must log in.
review:
Approve
(code)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
| 1 | === modified file 'lib/canonical/launchpad/webapp/configure.zcml' |
| 2 | --- lib/canonical/launchpad/webapp/configure.zcml 2010-06-05 05:05:43 +0000 |
| 3 | +++ lib/canonical/launchpad/webapp/configure.zcml 2010-06-08 16:04:27 +0000 |
| 4 | @@ -421,7 +421,7 @@ |
| 5 | <adapter |
| 6 | for="lp.buildmaster.interfaces.packagebuild.IPackageBuild" |
| 7 | provides="zope.traversing.interfaces.IPathAdapter" |
| 8 | - factory="canonical.launchpad.webapp.tales.BuildBaseFormatterAPI" |
| 9 | + factory="canonical.launchpad.webapp.tales.PackageBuildFormatterAPI" |
| 10 | name="fmt" |
| 11 | /> |
| 12 | |
| 13 | |
| 14 | === modified file 'lib/canonical/launchpad/webapp/tales.py' |
| 15 | --- lib/canonical/launchpad/webapp/tales.py 2010-06-05 05:05:43 +0000 |
| 16 | +++ lib/canonical/launchpad/webapp/tales.py 2010-06-08 16:04:27 +0000 |
| 17 | @@ -1515,8 +1515,8 @@ |
| 18 | return url |
| 19 | |
| 20 | |
| 21 | -class BuildBaseFormatterAPI(ObjectFormatterAPI): |
| 22 | - """Adapter providing fmt support for `IBuildBase` objects.""" |
| 23 | +class PackageBuildFormatterAPI(ObjectFormatterAPI): |
| 24 | + """Adapter providing fmt support for `IPackageBuild` objects.""" |
| 25 | def _composeArchiveReference(self, archive): |
| 26 | if archive.is_ppa: |
| 27 | return " [%s/%s]" % ( |
| 28 | |
| 29 | === modified file 'lib/lp/buildmaster/interfaces/buildbase.py' |
| 30 | --- lib/lp/buildmaster/interfaces/buildbase.py 2010-05-19 15:39:52 +0000 |
| 31 | +++ lib/lp/buildmaster/interfaces/buildbase.py 2010-06-08 16:04:27 +0000 |
| 32 | @@ -116,7 +116,22 @@ |
| 33 | """Common interface shared by farm jobs that build a package.""" |
| 34 | # XXX 2010-04-21 michael.nelson bug=567922. This interface |
| 35 | # can be removed once all *Build classes inherit from |
| 36 | - # IBuildFarmJob/IPackageBuild. |
| 37 | + # IBuildFarmJob/IPackageBuild. Until that time, to allow the shared |
| 38 | + # implementation of handling build status, IBuildBase needs to |
| 39 | + # provide aliases for buildstate, buildlog and datebuilt as follows: |
| 40 | + # status => buildstate |
| 41 | + # log => buildlog |
| 42 | + # date_finished => datebuilt |
| 43 | + status = Choice( |
| 44 | + title=_('State'), required=True, vocabulary=BuildStatus, |
| 45 | + description=_("The current build state.")) |
| 46 | + log = Object( |
| 47 | + schema=ILibraryFileAlias, required=False, |
| 48 | + title=_("The LibraryFileAlias containing the entire buildlog.")) |
| 49 | + date_finished = Datetime( |
| 50 | + title=_('Date built'), required=False, |
| 51 | + description=_("The time when the build result got collected.")) |
| 52 | + |
| 53 | |
| 54 | build_farm_job_type = Choice( |
| 55 | title=_("Job type"), required=True, readonly=True, |
| 56 | @@ -130,10 +145,7 @@ |
| 57 | title=_('Date created'), required=True, readonly=True, |
| 58 | description=_("The time when the build request was created."))) |
| 59 | |
| 60 | - buildstate = exported( |
| 61 | - Choice( |
| 62 | - title=_('State'), required=True, vocabulary=BuildStatus, |
| 63 | - description=_("The current build state."))) |
| 64 | + buildstate = exported(status) |
| 65 | |
| 66 | date_first_dispatched = exported( |
| 67 | Datetime( |
| 68 | @@ -146,19 +158,14 @@ |
| 69 | title=_("Builder"), schema=IBuilder, required=False, |
| 70 | description=_("The Builder which address this build request.")) |
| 71 | |
| 72 | - datebuilt = exported( |
| 73 | - Datetime( |
| 74 | - title=_('Date built'), required=False, |
| 75 | - description=_("The time when the build result got collected."))) |
| 76 | + datebuilt = exported(date_finished) |
| 77 | |
| 78 | buildduration = Timedelta( |
| 79 | title=_("Build Duration"), required=False, |
| 80 | description=_("Build duration interval, calculated when the " |
| 81 | "build result gets collected.")) |
| 82 | |
| 83 | - buildlog = Object( |
| 84 | - schema=ILibraryFileAlias, required=False, |
| 85 | - title=_("The LibraryFileAlias containing the entire buildlog.")) |
| 86 | + buildlog = log |
| 87 | |
| 88 | build_log_url = exported( |
| 89 | TextLine( |
| 90 | @@ -225,6 +232,14 @@ |
| 91 | executable. |
| 92 | """ |
| 93 | |
| 94 | + def getUploadLogContent(root, leaf): |
| 95 | + """Retrieve the upload log contents. |
| 96 | + |
| 97 | + :param root: Root directory for the uploads |
| 98 | + :param leaf: Leaf for this particular upload |
| 99 | + :return: Contents of log file or message saying no log file was found. |
| 100 | + """ |
| 101 | + |
| 102 | def handleStatus(build, status, librarian, slave_status): |
| 103 | """Handle a finished build status from a slave. |
| 104 | |
| 105 | |
| 106 | === modified file 'lib/lp/buildmaster/model/buildbase.py' |
| 107 | --- lib/lp/buildmaster/model/buildbase.py 2010-05-21 09:42:21 +0000 |
| 108 | +++ lib/lp/buildmaster/model/buildbase.py 2010-06-08 16:04:27 +0000 |
| 109 | @@ -9,7 +9,10 @@ |
| 110 | |
| 111 | __metaclass__ = type |
| 112 | |
| 113 | -__all__ = ['BuildBase'] |
| 114 | +__all__ = [ |
| 115 | + 'handle_status_for_build', |
| 116 | + 'BuildBase', |
| 117 | + ] |
| 118 | |
| 119 | import datetime |
| 120 | import logging |
| 121 | @@ -37,6 +40,24 @@ |
| 122 | UPLOAD_LOG_FILENAME = 'uploader.log' |
| 123 | |
| 124 | |
| 125 | +def handle_status_for_build(build, status, librarian, slave_status): |
| 126 | + """Find and call the correct method for handling the build status. |
| 127 | + |
| 128 | + This is extracted from build base so that the implementation |
| 129 | + can be shared by the newer IPackageBuild class. |
| 130 | + """ |
| 131 | + logger = logging.getLogger(BUILDD_MANAGER_LOG_NAME) |
| 132 | + |
| 133 | + method = getattr(BuildBase, '_handleStatus_' + status, None) |
| 134 | + |
| 135 | + if method is None: |
| 136 | + logger.critical("Unknown BuildStatus '%s' for builder '%s'" |
| 137 | + % (status, build.buildqueue_record.builder.url)) |
| 138 | + return |
| 139 | + |
| 140 | + method(build, librarian, slave_status, logger) |
| 141 | + |
| 142 | + |
| 143 | class BuildBase: |
| 144 | """A mixin class providing functionality for farm jobs that build a |
| 145 | package. |
| 146 | @@ -127,19 +148,9 @@ |
| 147 | return None |
| 148 | return self._getProxiedFileURL(self.upload_log) |
| 149 | |
| 150 | - @staticmethod |
| 151 | - def handleStatus(build, status, librarian, slave_status): |
| 152 | + def handleStatus(self, status, librarian, slave_status): |
| 153 | """See `IBuildBase`.""" |
| 154 | - logger = logging.getLogger(BUILDD_MANAGER_LOG_NAME) |
| 155 | - |
| 156 | - method = getattr(build, '_handleStatus_' + status, None) |
| 157 | - |
| 158 | - if method is None: |
| 159 | - logger.critical("Unknown BuildStatus '%s' for builder '%s'" |
| 160 | - % (status, build.buildqueue_record.builder.url)) |
| 161 | - return |
| 162 | - |
| 163 | - method(librarian, slave_status, logger) |
| 164 | + return handle_status_for_build(self, status, librarian, slave_status) |
| 165 | |
| 166 | @staticmethod |
| 167 | def _handleStatus_OK(build, librarian, slave_status, logger): |
| 168 | |
| 169 | === modified file 'lib/lp/buildmaster/model/packagebuild.py' |
| 170 | --- lib/lp/buildmaster/model/packagebuild.py 2010-05-21 09:42:21 +0000 |
| 171 | +++ lib/lp/buildmaster/model/packagebuild.py 2010-06-08 16:04:27 +0000 |
| 172 | @@ -24,7 +24,7 @@ |
| 173 | from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource |
| 174 | from lp.buildmaster.interfaces.packagebuild import ( |
| 175 | IPackageBuild, IPackageBuildSource) |
| 176 | -from lp.buildmaster.model.buildbase import BuildBase |
| 177 | +from lp.buildmaster.model.buildbase import handle_status_for_build, BuildBase |
| 178 | from lp.buildmaster.model.buildfarmjob import BuildFarmJobDerived |
| 179 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
| 180 | from lp.soyuz.adapters.archivedependencies import ( |
| 181 | @@ -185,7 +185,7 @@ |
| 182 | |
| 183 | def handleStatus(self, status, librarian, slave_status): |
| 184 | """See `IPackageBuild`.""" |
| 185 | - return BuildBase.handleStatus(self, status, librarian, slave_status) |
| 186 | + return handle_status_for_build(self, status, librarian, slave_status) |
| 187 | |
| 188 | # The following private handlers currently re-use the BuildBase |
| 189 | # implementation until it is no longer in use. If we find in the |
| 190 | |
| 191 | === modified file 'lib/lp/buildmaster/tests/test_buildbase.py' |
| 192 | --- lib/lp/buildmaster/tests/test_buildbase.py 2010-05-21 09:42:21 +0000 |
| 193 | +++ lib/lp/buildmaster/tests/test_buildbase.py 2010-06-08 16:04:27 +0000 |
| 194 | @@ -15,17 +15,16 @@ |
| 195 | from datetime import datetime |
| 196 | import os |
| 197 | import unittest |
| 198 | +from zope.security.proxy import removeSecurityProxy |
| 199 | |
| 200 | from canonical.config import config |
| 201 | from canonical.database.constants import UTC_NOW |
| 202 | -from canonical.testing.layers import ( |
| 203 | - DatabaseFunctionalLayer, LaunchpadZopelessLayer) |
| 204 | +from canonical.testing.layers import LaunchpadZopelessLayer |
| 205 | from lp.buildmaster.interfaces.buildbase import BuildStatus |
| 206 | from lp.buildmaster.model.buildbase import BuildBase |
| 207 | from lp.registry.interfaces.pocket import pocketsuffix |
| 208 | from lp.soyuz.tests.soyuzbuilddhelpers import WaitingSlave |
| 209 | -from lp.soyuz.tests.test_publishing import SoyuzTestPublisher |
| 210 | -from lp.testing import TestCase, TestCaseWithFactory |
| 211 | +from lp.testing import TestCase |
| 212 | from lp.testing.fakemethod import FakeMethod |
| 213 | |
| 214 | |
| 215 | @@ -62,27 +61,41 @@ |
| 216 | self.package_build = BuildBase() |
| 217 | |
| 218 | |
| 219 | -class TestBuildBaseWithDatabase(TestCaseWithFactory): |
| 220 | +class TestGetUploadMethodsMixin: |
| 221 | """Tests for `IBuildBase` that need objects from the rest of Launchpad.""" |
| 222 | |
| 223 | - layer = DatabaseFunctionalLayer |
| 224 | + layer = LaunchpadZopelessLayer |
| 225 | + |
| 226 | + def makeBuild(self): |
| 227 | + """Allow classes to override the build with which the test runs. |
| 228 | + |
| 229 | + XXX michaeln 2010-06-03 bug=567922 |
| 230 | + Until buildbase is removed, we need to ensure these tests |
| 231 | + run against new IPackageBuild builds (BinaryPackageBuild) |
| 232 | + and the IBuildBase builds (SPRecipeBuild). They assume the build |
| 233 | + is successfully built and check that incorrect upload paths will |
| 234 | + set the status to FAILEDTOUPLOAD. |
| 235 | + """ |
| 236 | + raise NotImplemented |
| 237 | + |
| 238 | + def setUp(self): |
| 239 | + super(TestGetUploadMethodsMixin, self).setUp() |
| 240 | + self.build = self.makeBuild() |
| 241 | |
| 242 | def test_getUploadLogContent_nolog(self): |
| 243 | """If there is no log file there, a string explanation is returned. |
| 244 | """ |
| 245 | self.useTempDir() |
| 246 | - build_base = BuildBase() |
| 247 | self.assertEquals('Could not find upload log file', |
| 248 | - build_base.getUploadLogContent(os.getcwd(), "myleaf")) |
| 249 | + self.build.getUploadLogContent(os.getcwd(), "myleaf")) |
| 250 | |
| 251 | def test_getUploadLogContent_only_dir(self): |
| 252 | """If there is a directory but no log file, expect the error string, |
| 253 | not an exception.""" |
| 254 | self.useTempDir() |
| 255 | os.makedirs("accepted/myleaf") |
| 256 | - build_base = BuildBase() |
| 257 | self.assertEquals('Could not find upload log file', |
| 258 | - build_base.getUploadLogContent(os.getcwd(), "myleaf")) |
| 259 | + self.build.getUploadLogContent(os.getcwd(), "myleaf")) |
| 260 | |
| 261 | def test_getUploadLogContent_readsfile(self): |
| 262 | """If there is a log file, return its contents.""" |
| 263 | @@ -90,47 +103,53 @@ |
| 264 | os.makedirs("accepted/myleaf") |
| 265 | with open('accepted/myleaf/uploader.log', 'w') as f: |
| 266 | f.write('foo') |
| 267 | - build_base = BuildBase() |
| 268 | self.assertEquals('foo', |
| 269 | - build_base.getUploadLogContent(os.getcwd(), "myleaf")) |
| 270 | + self.build.getUploadLogContent(os.getcwd(), "myleaf")) |
| 271 | |
| 272 | def test_getUploaderCommand(self): |
| 273 | - build_base = BuildBase() |
| 274 | upload_leaf = self.factory.getUniqueString('upload-leaf') |
| 275 | - build_base.distro_series = self.factory.makeDistroSeries() |
| 276 | - build_base.distribution = build_base.distro_series.distribution |
| 277 | - build_base.pocket = self.factory.getAnyPocket() |
| 278 | - build_base.id = self.factory.getUniqueInteger() |
| 279 | - build_base.policy_name = self.factory.getUniqueString('policy-name') |
| 280 | config_args = list(config.builddmaster.uploader.split()) |
| 281 | log_file = self.factory.getUniqueString('logfile') |
| 282 | config_args.extend( |
| 283 | ['--log-file', log_file, |
| 284 | - '-d', build_base.distribution.name, |
| 285 | - '-s', (build_base.distro_series.name |
| 286 | - + pocketsuffix[build_base.pocket]), |
| 287 | - '-b', str(build_base.id), |
| 288 | + '-d', self.build.distribution.name, |
| 289 | + '-s', (self.build.distro_series.name |
| 290 | + + pocketsuffix[self.build.pocket]), |
| 291 | + '-b', str(self.build.id), |
| 292 | '-J', upload_leaf, |
| 293 | - '--context=%s' % build_base.policy_name, |
| 294 | + '--context=%s' % self.build.policy_name, |
| 295 | os.path.abspath(config.builddmaster.root), |
| 296 | ]) |
| 297 | - uploader_command = build_base.getUploaderCommand( |
| 298 | - build_base, upload_leaf, log_file) |
| 299 | + uploader_command = self.build.getUploaderCommand( |
| 300 | + self.build, upload_leaf, log_file) |
| 301 | self.assertEqual(config_args, uploader_command) |
| 302 | |
| 303 | |
| 304 | -class TestBuildBaseHandleStatus(TestCaseWithFactory): |
| 305 | - """Tests for `IBuildBase`s handleStatus method.""" |
| 306 | +class TestHandleStatusMixin: |
| 307 | + """Tests for `IBuildBase`s handleStatus method. |
| 308 | + |
| 309 | + Note: these tests do *not* test the updating of the build |
| 310 | + status to FULLYBUILT as this happens during the upload which |
| 311 | + is stubbed out by a mock function. |
| 312 | + """ |
| 313 | |
| 314 | layer = LaunchpadZopelessLayer |
| 315 | |
| 316 | + def makeBuild(self): |
| 317 | + """Allow classes to override the build with which the test runs. |
| 318 | + |
| 319 | + XXX michaeln 2010-06-03 bug=567922 |
| 320 | + Until buildbase is removed, we need to ensure these tests |
| 321 | + run against new IPackageBuild builds (BinaryPackageBuild) |
| 322 | + and the IBuildBase builds (SPRecipeBuild). They assume the build |
| 323 | + is successfully built and check that incorrect upload paths will |
| 324 | + set the status to FAILEDTOUPLOAD. |
| 325 | + """ |
| 326 | + raise NotImplementedError |
| 327 | + |
| 328 | def setUp(self): |
| 329 | - super(TestBuildBaseHandleStatus, self).setUp() |
| 330 | - test_publisher = SoyuzTestPublisher() |
| 331 | - test_publisher.prepareBreezyAutotest() |
| 332 | - binaries = test_publisher.getPubBinaries() |
| 333 | - self.build = binaries[0].binarypackagerelease.build |
| 334 | - |
| 335 | + super(TestHandleStatusMixin, self).setUp() |
| 336 | + self.build = self.makeBuild() |
| 337 | # For the moment, we require a builder for the build so that |
| 338 | # handleStatus_OK can get a reference to the slave. |
| 339 | builder = self.factory.makeBuilder() |
| 340 | @@ -149,10 +168,14 @@ |
| 341 | config.push('tmp_builddmaster_root', tmp_builddmaster_root) |
| 342 | |
| 343 | # We stub out our builds getUploaderCommand() method so |
| 344 | - # we can check whether it was called. |
| 345 | + # we can check whether it was called as well as |
| 346 | + # verifySuccessfulUpload(). |
| 347 | self.fake_getUploaderCommand = FakeMethod( |
| 348 | result=['echo', 'noop']) |
| 349 | - self.build.getUploaderCommand = self.fake_getUploaderCommand |
| 350 | + removeSecurityProxy(self.build).getUploaderCommand = ( |
| 351 | + self.fake_getUploaderCommand) |
| 352 | + removeSecurityProxy(self.build).verifySuccessfulUpload = FakeMethod( |
| 353 | + result=True) |
| 354 | |
| 355 | def test_handleStatus_OK_normal_file(self): |
| 356 | # A filemap with plain filenames should not cause a problem. |
| 357 | @@ -183,6 +206,24 @@ |
| 358 | self.assertEqual(BuildStatus.FAILEDTOUPLOAD, self.build.status) |
| 359 | self.assertEqual(0, self.fake_getUploaderCommand.call_count) |
| 360 | |
| 361 | + def test_handleStatus_OK_sets_build_log(self): |
| 362 | + # The build log is set during handleStatus. |
| 363 | + removeSecurityProxy(self.build).log = None |
| 364 | + self.assertEqual(None, self.build.log) |
| 365 | + self.build.handleStatus('OK', None, { |
| 366 | + 'filemap': { 'myfile.py': 'test_file_hash'}, |
| 367 | + }) |
| 368 | + self.assertNotEqual(None, self.build.log) |
| 369 | + |
| 370 | + def test_date_finished_set(self): |
| 371 | + # The date finished is updated during handleStatus_OK. |
| 372 | + removeSecurityProxy(self.build).date_finished = None |
| 373 | + self.assertEqual(None, self.build.date_finished) |
| 374 | + self.build.handleStatus('OK', None, { |
| 375 | + 'filemap': { 'myfile.py': 'test_file_hash'}, |
| 376 | + }) |
| 377 | + self.assertNotEqual(None, self.build.date_finished) |
| 378 | + |
| 379 | |
| 380 | def test_suite(): |
| 381 | return unittest.TestLoader().loadTestsFromName(__name__) |
| 382 | |
| 383 | === modified file 'lib/lp/code/model/sourcepackagerecipebuild.py' |
| 384 | --- lib/lp/code/model/sourcepackagerecipebuild.py 2010-05-27 22:18:16 +0000 |
| 385 | +++ lib/lp/code/model/sourcepackagerecipebuild.py 2010-06-08 16:04:27 +0000 |
| 386 | @@ -75,7 +75,6 @@ |
| 387 | buildlog = Reference(buildlog_id, 'LibraryFileAlias.id') |
| 388 | |
| 389 | buildstate = DBEnum(enum=BuildStatus, name='build_state') |
| 390 | - |
| 391 | dependencies = Unicode(allow_none=True) |
| 392 | |
| 393 | upload_log_id = Int(name='upload_log', allow_none=True) |
| 394 | @@ -88,6 +87,13 @@ |
| 395 | datecreated = UtcDateTimeCol(notNull=True, dbName='date_created') |
| 396 | datebuilt = UtcDateTimeCol(notNull=False, dbName='date_built') |
| 397 | |
| 398 | + # See `IBuildBase` - the following attributes are aliased |
| 399 | + # to allow a shared implementation of the handleStatus methods |
| 400 | + # until IBuildBase is removed. |
| 401 | + status = buildstate |
| 402 | + date_finished = datebuilt |
| 403 | + log = buildlog |
| 404 | + |
| 405 | @property |
| 406 | def datestarted(self): |
| 407 | """See `IBuild`.""" |
| 408 | |
| 409 | === modified file 'lib/lp/code/model/tests/test_sourcepackagerecipebuild.py' |
| 410 | --- lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2010-05-27 22:18:16 +0000 |
| 411 | +++ lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2010-06-08 16:04:27 +0000 |
| 412 | @@ -20,11 +20,14 @@ |
| 413 | |
| 414 | from canonical.launchpad.interfaces.launchpad import NotFoundError |
| 415 | from canonical.launchpad.webapp.authorization import check_permission |
| 416 | -from lp.buildmaster.interfaces.buildbase import IBuildBase |
| 417 | +from lp.buildmaster.interfaces.buildbase import BuildStatus, IBuildBase |
| 418 | from lp.buildmaster.interfaces.buildqueue import IBuildQueue |
| 419 | +from lp.buildmaster.tests.test_buildbase import ( |
| 420 | + TestGetUploadMethodsMixin, TestHandleStatusMixin) |
| 421 | from lp.code.interfaces.sourcepackagerecipebuild import ( |
| 422 | ISourcePackageRecipeBuildJob, ISourcePackageRecipeBuild, |
| 423 | ISourcePackageRecipeBuildSource) |
| 424 | +from lp.soyuz.interfaces.processor import IProcessorFamilySet |
| 425 | from lp.soyuz.model.processor import ProcessorFamily |
| 426 | from lp.testing import ANONYMOUS, login, person_logged_in, TestCaseWithFactory |
| 427 | |
| 428 | @@ -193,6 +196,33 @@ |
| 429 | self.assertEqual([binary], list(spb.binary_builds)) |
| 430 | |
| 431 | |
| 432 | +class MakeSPRecipeBuildMixin: |
| 433 | + """Provide the common makeBuild method returning a queued build.""" |
| 434 | + |
| 435 | + def makeBuild(self): |
| 436 | + person = self.factory.makePerson() |
| 437 | + distroseries = self.factory.makeDistroSeries() |
| 438 | + processor_fam = getUtility(IProcessorFamilySet).getByName('x86') |
| 439 | + distroseries_i386 = distroseries.newArch( |
| 440 | + 'i386', processor_fam, False, person, |
| 441 | + supports_virtualized=True) |
| 442 | + distroseries.nominatedarchindep = distroseries_i386 |
| 443 | + build = self.factory.makeSourcePackageRecipeBuild( |
| 444 | + distroseries=distroseries, |
| 445 | + status=BuildStatus.FULLYBUILT) |
| 446 | + build.queueBuild(build) |
| 447 | + return build |
| 448 | + |
| 449 | + |
| 450 | +class TestGetUploadMethodsForSPRecipeBuild( |
| 451 | + MakeSPRecipeBuildMixin, TestGetUploadMethodsMixin, TestCaseWithFactory): |
| 452 | + """IBuildBase.getUpload-related methods work with SPRecipe builds.""" |
| 453 | + |
| 454 | + |
| 455 | +class TestHandleStatusForSPRBuild( |
| 456 | + MakeSPRecipeBuildMixin, TestHandleStatusMixin, TestCaseWithFactory): |
| 457 | + """IBuildBase.handleStatus works with SPRecipe builds.""" |
| 458 | + |
| 459 | |
| 460 | def test_suite(): |
| 461 | return unittest.TestLoader().loadTestsFromName(__name__) |
| 462 | |
| 463 | === modified file 'lib/lp/soyuz/tests/test_binarypackagebuild.py' |
| 464 | --- lib/lp/soyuz/tests/test_binarypackagebuild.py 2010-06-07 20:21:02 +0000 |
| 465 | +++ lib/lp/soyuz/tests/test_binarypackagebuild.py 2010-06-08 16:04:27 +0000 |
| 466 | @@ -17,6 +17,8 @@ |
| 467 | from lp.buildmaster.interfaces.buildqueue import IBuildQueue |
| 468 | from lp.buildmaster.interfaces.packagebuild import IPackageBuild |
| 469 | from lp.buildmaster.model.buildqueue import BuildQueue |
| 470 | +from lp.buildmaster.tests.test_buildbase import ( |
| 471 | + TestGetUploadMethodsMixin, TestHandleStatusMixin) |
| 472 | from lp.soyuz.interfaces.binarypackagebuild import ( |
| 473 | IBinaryPackageBuild, IBinaryPackageBuildSet) |
| 474 | from lp.soyuz.interfaces.buildpackagejob import IBuildPackageJob |
| 475 | @@ -345,5 +347,26 @@ |
| 476 | self.assertIsNot(None, self.build.date_finished) |
| 477 | |
| 478 | |
| 479 | +class MakeBinaryPackageBuildMixin: |
| 480 | + """Provide the makeBuild method returning a queud build.""" |
| 481 | + |
| 482 | + def makeBuild(self): |
| 483 | + test_publisher = SoyuzTestPublisher() |
| 484 | + test_publisher.prepareBreezyAutotest() |
| 485 | + binaries = test_publisher.getPubBinaries() |
| 486 | + return binaries[0].binarypackagerelease.build |
| 487 | + |
| 488 | + |
| 489 | +class TestGetUploadMethodsForBinaryPackageBuild( |
| 490 | + MakeBinaryPackageBuildMixin, TestGetUploadMethodsMixin, |
| 491 | + TestCaseWithFactory): |
| 492 | + """IBuildBase.getUpload-related methods work with binary builds.""" |
| 493 | + |
| 494 | + |
| 495 | +class TestHandleStatusForBinaryPackageBuild( |
| 496 | + MakeBinaryPackageBuildMixin, TestHandleStatusMixin, TestCaseWithFactory): |
| 497 | + """IBuildBase.handleStatus works with binary builds.""" |
| 498 | + |
| 499 | + |
| 500 | def test_suite(): |
| 501 | return unittest.TestLoader().loadTestsFromName(__name__) |
| 502 | |
| 503 | === modified file 'lib/lp/testing/factory.py' |
| 504 | --- lib/lp/testing/factory.py 2010-05-30 04:06:48 +0000 |
| 505 | +++ lib/lp/testing/factory.py 2010-06-08 16:04:27 +0000 |
| 506 | @@ -1789,7 +1789,8 @@ |
| 507 | def makeSourcePackageRecipeBuild(self, sourcepackage=None, recipe=None, |
| 508 | requester=None, archive=None, |
| 509 | sourcename=None, distroseries=None, |
| 510 | - pocket=None): |
| 511 | + pocket=None, |
| 512 | + status=BuildStatus.NEEDSBUILD): |
| 513 | """Make a new SourcePackageRecipeBuild.""" |
| 514 | if recipe is None: |
| 515 | recipe = self.makeSourcePackageRecipe(name=sourcename) |
| 516 | @@ -1800,12 +1801,14 @@ |
| 517 | distribution=archive.distribution) |
| 518 | if requester is None: |
| 519 | requester = self.makePerson() |
| 520 | - return getUtility(ISourcePackageRecipeBuildSource).new( |
| 521 | + spr_build = getUtility(ISourcePackageRecipeBuildSource).new( |
| 522 | distroseries=distroseries, |
| 523 | recipe=recipe, |
| 524 | archive=archive, |
| 525 | requester=requester, |
| 526 | pocket=pocket) |
| 527 | + removeSecurityProxy(spr_build).buildstate = status |
| 528 | + return spr_build |
| 529 | |
| 530 | def makeSourcePackageRecipeBuildJob( |
| 531 | self, score=9876, virtualized=True, estimated_duration=64, |
