def test_fail_to_resume_slave_resets_job(self): # If an attempt to resume and dispatch a slave fails, it should # reset the job via job.reset() # Make a slave with a failing resume() method. slave = OkSlave() slave.resume = lambda: deferLater( reactor, 0, defer.fail, Failure(('out', 'err', 1))) # Reset sampledata builder. builder = removeSecurityProxy( getUtility(IBuilderSet)[BOB_THE_BUILDER_NAME]) self._resetBuilder(builder) self.assertEqual(0, builder.failure_count) self.patch(BuilderSlave, 'makeBuilderSlave', FakeMethod(slave)) builder.vm_host = "fake_vm_host" scanner = self._getScanner() # Get the next job that will be dispatched. job = removeSecurityProxy(builder._findBuildCandidate()) job.virtualized = True builder.virtualized = True transaction.commit() yield scanner.singleCycle() # The failure_count will have been incremented on the builder, we # can check that to see that a dispatch attempt did indeed occur. self.assertEqual(1, builder.failure_count) # There should also be no builder set on the job. self.assertIsNone(job.builder) build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job) self.assertEqual(build.status, BuildStatus.NEEDSBUILD)
def test_fail_to_resume_slave_resets_job(self): # If an attempt to resume and dispatch a slave fails, it should # reset the job via job.reset() # Make a slave with a failing resume() method. slave = OkSlave() slave.resume = lambda: deferLater(reactor, 0, defer.fail, Failure(('out', 'err', 1))) # Reset sampledata builder. builder = removeSecurityProxy( getUtility(IBuilderSet)[BOB_THE_BUILDER_NAME]) self._resetBuilder(builder) self.assertEqual(0, builder.failure_count) self.patch(BuilderSlave, 'makeBuilderSlave', FakeMethod(slave)) builder.vm_host = "fake_vm_host" scanner = self._getScanner() # Get the next job that will be dispatched. job = removeSecurityProxy(builder._findBuildCandidate()) job.virtualized = True builder.virtualized = True transaction.commit() yield scanner.singleCycle() # The failure_count will have been incremented on the builder, we # can check that to see that a dispatch attempt did indeed occur. self.assertEqual(1, builder.failure_count) # There should also be no builder set on the job. self.assertIsNone(job.builder) build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job) self.assertEqual(build.status, BuildStatus.NEEDSBUILD)
def test_dispatchBuildToSlave(self): # Ensure dispatchBuildToSlave will make the right calls to the slave job = self.makeJob() test_publisher = SoyuzTestPublisher() test_publisher.addFakeChroots(job.build.distroseries) slave = OkSlave() builder = MockBuilder("bob-de-bouwer") builder.processor = getUtility(IProcessorSet).getByName('386') job.setBuilder(builder, slave) logger = BufferLogger() d = defer.maybeDeferred(job.dispatchBuildToSlave, "someid", logger) def check_dispatch(ignored): self.assertThat( logger.getLogBuffer(), StartsWith( dedent("""\ INFO Sending chroot file for recipe build to bob-de-bouwer INFO Initiating build 1-someid on http://fake:0000 """))) self.assertEquals(["ensurepresent", "build"], [call[0] for call in slave.call_log]) build_args = slave.call_log[1][1:] self.assertEquals(build_args[0], job.getBuildCookie()) self.assertEquals(build_args[1], "sourcepackagerecipe") self.assertEquals(build_args[3], []) distroarchseries = job.build.distroseries.architectures[0] self.assertEqual(build_args[4], job._extraBuildArgs(distroarchseries)) return d.addCallback(check_dispatch)
def setUp(self): TestCaseWithFactory.setUp(self) self.builder = self.factory.makeBuilder() self.build = self.factory.makeSourcePackageRecipeBuild() self.buildqueue = self.build.queueBuild() self.buildqueue.markAsBuilding(self.builder) self.slave = OkSlave()
def test_virtual_ppa_dispatch(self): # Make sure the builder slave gets reset before a build is # dispatched to it. archive = self.factory.makeArchive(virtualized=True) slave = OkSlave() builder = self.factory.makeBuilder(virtualized=True, vm_host="foohost") vitals = extract_vitals_from_db(builder) build = self.factory.makeBinaryPackageBuild(builder=builder, archive=archive) lf = self.factory.makeLibraryFileAlias() transaction.commit() build.distro_arch_series.addOrUpdateChroot(lf) bq = build.queueBuild() bq.markAsBuilding(builder) interactor = BuilderInteractor() d = interactor._startBuild( bq, vitals, builder, slave, interactor.getBuildBehavior(bq, builder, slave), BufferLogger()) def check_build(ignored): # We expect the first call to the slave to be a resume call, # followed by the rest of the usual calls we expect. expected_resume_call = slave.call_log.pop(0) self.assertEqual('resume', expected_resume_call) self.assertExpectedInteraction(ignored, slave.call_log, builder, build, lf, archive, ArchivePurpose.PPA) return d.addCallback(check_build)
def test_non_virtual_ppa_dispatch_with_primary_ancestry(self): # If there is a primary component override, it is honoured for # non-virtual PPA builds too. archive = self.factory.makeArchive(virtualized=False) slave = OkSlave() builder = self.factory.makeBuilder(virtualized=False) builder.setCleanStatus(BuilderCleanStatus.CLEAN) vitals = extract_vitals_from_db(builder) build = self.factory.makeBinaryPackageBuild(builder=builder, archive=archive) self.factory.makeSourcePackagePublishingHistory( distroseries=build.distro_series, archive=archive.distribution.main_archive, sourcepackagename=build.source_package_release.sourcepackagename, component='main') lf = self.factory.makeLibraryFileAlias() transaction.commit() build.distro_arch_series.addOrUpdateChroot(lf) bq = build.queueBuild() bq.markAsBuilding(builder) interactor = BuilderInteractor() yield interactor._startBuild( bq, vitals, builder, slave, interactor.getBuildBehaviour(bq, builder, slave), BufferLogger()) yield self.assertExpectedInteraction(slave.call_log, builder, build, lf, archive, ArchivePurpose.PRIMARY, 'main')
def test_non_virtual_ppa_dispatch(self): # When the BinaryPackageBuildBehaviour dispatches PPA builds to # non-virtual builders, it stores the chroot on the server and # requests a binary package build, lying to say that the archive # purpose is "PRIMARY" because this ensures that the package mangling # tools will run over the built packages. archive = self.factory.makeArchive(virtualized=False) slave = OkSlave() builder = self.factory.makeBuilder(virtualized=False) builder.setCleanStatus(BuilderCleanStatus.CLEAN) vitals = extract_vitals_from_db(builder) build = self.factory.makeBinaryPackageBuild(builder=builder, archive=archive) lf = self.factory.makeLibraryFileAlias() transaction.commit() build.distro_arch_series.addOrUpdateChroot(lf) bq = build.queueBuild() bq.markAsBuilding(builder) interactor = BuilderInteractor() yield interactor._startBuild( bq, vitals, builder, slave, interactor.getBuildBehaviour(bq, builder, slave), BufferLogger()) yield self.assertExpectedInteraction(slave.call_log, builder, build, lf, archive, ArchivePurpose.PRIMARY, 'universe')
def test_private_source_dispatch(self): archive = self.factory.makeArchive(private=True) slave = OkSlave() builder = self.factory.makeBuilder() builder.setCleanStatus(BuilderCleanStatus.CLEAN) vitals = extract_vitals_from_db(builder) build = self.factory.makeBinaryPackageBuild(builder=builder, archive=archive) sprf = build.source_package_release.addFile( self.factory.makeLibraryFileAlias(db_only=True), filetype=SourcePackageFileType.ORIG_TARBALL) sprf_url = ( 'http://private-ppa.launchpad.dev/%s/%s/ubuntu/pool/%s/%s' % (archive.owner.name, archive.name, poolify(build.source_package_release.sourcepackagename.name, 'main'), sprf.libraryfile.filename)) lf = self.factory.makeLibraryFileAlias() transaction.commit() build.distro_arch_series.addOrUpdateChroot(lf) bq = build.queueBuild() bq.markAsBuilding(builder) interactor = BuilderInteractor() yield interactor._startBuild( bq, vitals, builder, slave, interactor.getBuildBehaviour(bq, builder, slave), BufferLogger()) yield self.assertExpectedInteraction( slave.call_log, builder, build, lf, archive, ArchivePurpose.PPA, extra_uploads=[(sprf_url, 'buildd', 'sekrit')], filemap_names=[sprf.libraryfile.filename])
def test_recover_ok_slave(self): # An idle slave that's meant to be idle is not rescued. slave = OkSlave() lost = yield BuilderInteractor.rescueIfLost( extract_vitals_from_db(MockBuilder()), slave, None) self.assertFalse(lost) self.assertEqual([], slave.call_log)
def test_verifyBuildRequest_no_chroot(self): # verifyBuildRequest raises when the DAS has no chroot. job = self.makeJob() builder = MockBuilder() job.setBuilder(builder, OkSlave()) logger = BufferLogger() e = self.assertRaises(CannotBuild, job.verifyBuildRequest, logger) self.assertIn("Missing chroot", str(e))
def test_scan_with_nothing_to_dispatch(self): factory = LaunchpadObjectFactory() builder = factory.makeBuilder() self.patch(BuilderSlave, 'makeBuilderSlave', FakeMethod(OkSlave())) transaction.commit() scanner = self._getScanner(builder_name=builder.name) d = scanner.scan() return d.addCallback(self._checkNoDispatch, builder)
def test_verifyBuildRequest_valid(self): # VerifyBuildRequest won't raise any exceptions when called with a # valid builder set. job = self.makeJob() builder = MockBuilder("bob-de-bouwer") job.setBuilder(builder, OkSlave()) logger = BufferLogger() job.verifyBuildRequest(logger) self.assertEquals("", logger.getLogBuffer())
def test_verifyBuildRequest_bad_pocket(self): # verifyBuildRequest will raise if a bad pocket is proposed. build = self.factory.makeSourcePackageRecipeBuild( pocket=PackagePublishingPocket.SECURITY) job = IBuildFarmJobBehaviour(build) job.setBuilder(MockBuilder("bob-de-bouwer"), OkSlave()) e = self.assertRaises( AssertionError, job.verifyBuildRequest, BufferLogger()) self.assertIn('invalid pocket due to the series status of', str(e))
def test_findAndStartJob_dirties_slave(self): # findAndStartJob marks its builder DIRTY before dispatching. builder, build = self._setupBinaryBuildAndBuilder() candidate = build.queueBuild() removeSecurityProxy(builder)._findBuildCandidate = FakeMethod( result=candidate) vitals = extract_vitals_from_db(builder) yield BuilderInteractor.findAndStartJob(vitals, builder, OkSlave()) self.assertEqual(BuilderCleanStatus.DIRTY, builder.clean_status)
def test_virtual_1_1(self): # Virtual builders using protocol 1.1 get reset, and once the # trigger completes we're happy that it's clean. builder = MockBuilder(virtualized=True, clean_status=BuilderCleanStatus.DIRTY, vm_host='lol', vm_reset_protocol=BuilderResetProtocol.PROTO_1_1) yield self.assertCleanCalls(builder, OkSlave(), ['resume', 'echo'], True)
def test_recover_idle_slave(self): # An idle slave is not rescued, even if it's not meant to be # idle. SlaveScanner.scan() will clean up the DB side, because # we still report that it's lost. slave = OkSlave() lost = yield BuilderInteractor.rescueIfLost( extract_vitals_from_db(MockBuilder()), slave, 'trivial') self.assertTrue(lost) self.assertEqual([], slave.call_log)
def test_virtual_2_0_dirty(self): # Virtual builders using protocol 2.0 get reset and set to # CLEANING. It's then up to the non-Launchpad reset code to set # the builder back to CLEAN using the webservice. builder = MockBuilder(virtualized=True, clean_status=BuilderCleanStatus.DIRTY, vm_host='lol', vm_reset_protocol=BuilderResetProtocol.PROTO_2_0) yield self.assertCleanCalls(builder, OkSlave(), ['resume'], False) self.assertEqual(BuilderCleanStatus.CLEANING, builder.clean_status)
def test_dispatchBuildToSlave(self): behaviour = self.makeBehaviour(FakeDistroArchSeries()) builder = MockBuilder() slave = OkSlave() logger = BufferLogger() behaviour.setBuilder(builder, slave) yield behaviour.dispatchBuildToSlave(logger) self.assertDispatched(slave, logger, 'chroot-fooix-bar-y86.tar.gz', 'chroot')
def test_virtual_2_0_cleaning(self): # Virtual builders using protocol 2.0 only get touched when # they're DIRTY. Once they're cleaning, they're not our problem # until they return to CLEAN, so we ignore them. builder = MockBuilder(virtualized=True, clean_status=BuilderCleanStatus.CLEANING, vm_host='lol', vm_reset_protocol=BuilderResetProtocol.PROTO_2_0) yield self.assertCleanCalls(builder, OkSlave(), [], False) self.assertEqual(BuilderCleanStatus.CLEANING, builder.clean_status)
def test_verifyBuildRequest_non_virtual(self): # verifyBuildRequest will raise if a non-virtual builder is proposed. job = self.makeJob() builder = MockBuilder('non-virtual builder') builder.virtualized = False job.setBuilder(builder, OkSlave()) logger = BufferLogger() e = self.assertRaises(AssertionError, job.verifyBuildRequest, logger) self.assertEqual( 'Attempt to build virtual item on a non-virtual builder.', str(e))
def test_findAndStartJob_requires_clean_slave(self): # findAndStartJob ensures that its slave starts CLEAN. builder, build = self._setupBinaryBuildAndBuilder() builder.setCleanStatus(BuilderCleanStatus.DIRTY) candidate = build.queueBuild() removeSecurityProxy(builder)._findBuildCandidate = FakeMethod( result=candidate) vitals = extract_vitals_from_db(builder) with ExpectedException(BuildDaemonIsolationError, "Attempted to start build on a dirty slave."): yield BuilderInteractor.findAndStartJob(vitals, builder, OkSlave())
def test_dispatchBuildToSlave_nochroot(self): # dispatchBuildToSlave will fail when there is not chroot tarball # available for the distroseries to build for. job = self.makeJob() #test_publisher = SoyuzTestPublisher() builder = MockBuilder("bob-de-bouwer") builder.processor = getUtility(IProcessorSet).getByName('386') job.setBuilder(builder, OkSlave()) logger = BufferLogger() d = defer.maybeDeferred(job.dispatchBuildToSlave, "someid", logger) return assert_fails_with(d, CannotBuild)
def test_scan_with_not_ok_builder(self): # Reset sampledata builder. builder = getUtility(IBuilderSet)[BOB_THE_BUILDER_NAME] self._resetBuilder(builder) self.patch(BuilderSlave, 'makeBuilderSlave', FakeMethod(OkSlave())) builder.builderok = False transaction.commit() scanner = self._getScanner() yield scanner.scan() # Because the builder is not ok, we can't use _checkNoDispatch. self.assertIsNone(builder.currentjob)
def test_scan_with_manual_builder(self): # Reset sampledata builder. builder = getUtility(IBuilderSet)[BOB_THE_BUILDER_NAME] self._resetBuilder(builder) self.patch(BuilderSlave, 'makeBuilderSlave', FakeMethod(OkSlave())) builder.manual = True transaction.commit() scanner = self._getScanner() d = scanner.scan() d.addCallback(self._checkNoDispatch, builder) return d
def test_dispatchBuildToSlave_falls_back_to_chroot(self): job = self.makeJob(allow_internet=False) builder = MockBuilder() builder.processor = job.build.processor slave = OkSlave() job.setBuilder(builder, slave) chroot_lfa = self.factory.makeLibraryFileAlias(db_only=True) job.build.distro_arch_series.addOrUpdateChroot( chroot_lfa, image_type=BuildBaseImageType.CHROOT) yield job.dispatchBuildToSlave(DevNullLogger()) self.assertEqual(('ensurepresent', chroot_lfa.http_url, '', ''), slave.call_log[0])
def test_verifyBuildRequest_archive_disabled(self): archive = self.factory.makeArchive(enabled=False, displayname="Disabled Archive") job = self.makeJob(archive=archive) lfa = self.factory.makeLibraryFileAlias() transaction.commit() job.build.distro_arch_series.addOrUpdateChroot(lfa) builder = MockBuilder() job.setBuilder(builder, OkSlave()) logger = BufferLogger() e = self.assertRaises(ArchiveDisabled, job.verifyBuildRequest, logger) self.assertEqual("Disabled Archive is disabled.", str(e))
def test_verifyBuildRequest_valid(self): # verifyBuildRequest doesn't raise any exceptions when called with a # valid builder set. job = self.makeJob() lfa = self.factory.makeLibraryFileAlias() transaction.commit() job.build.distro_arch_series.addOrUpdateChroot(lfa) builder = MockBuilder() job.setBuilder(builder, OkSlave()) logger = BufferLogger() job.verifyBuildRequest(logger) self.assertEqual("", logger.getLogBuffer())
def test_virtual_no_protocol(self): # Virtual builders fail to clean unless vm_reset_protocol is # set. builder = MockBuilder(virtualized=True, clean_status=BuilderCleanStatus.DIRTY, vm_host='lol') builder.vm_reset_protocol = None with ExpectedException(CannotResumeHost, "Invalid vm_reset_protocol: None"): yield BuilderInteractor.cleanSlave( extract_vitals_from_db(builder), OkSlave(), MockBuilderFactory(builder, None))
def test_findAndStartJob_returns_candidate(self): # findAndStartJob finds the next queued job using _findBuildCandidate. # We don't care about the type of build at all. builder, build = self._setupRecipeBuildAndBuilder() candidate = build.queueBuild() # _findBuildCandidate is tested elsewhere, we just make sure that # findAndStartJob delegates to it. removeSecurityProxy(builder)._findBuildCandidate = FakeMethod( result=candidate) vitals = extract_vitals_from_db(builder) d = BuilderInteractor.findAndStartJob(vitals, builder, OkSlave()) return d.addCallback(self.assertEqual, candidate)
def test_verifyBuildRequest_archive_private_owners_match(self): archive = self.factory.makeArchive(private=True) job = self.makeJob(archive=archive, registrant=archive.owner, owner=archive.owner) lfa = self.factory.makeLibraryFileAlias() transaction.commit() job.build.distro_arch_series.addOrUpdateChroot(lfa) builder = MockBuilder() job.setBuilder(builder, OkSlave()) logger = BufferLogger() job.verifyBuildRequest(logger) self.assertEqual("", logger.getLogBuffer())
def test_verifyBuildRequest_virtual_mismatch(self): # verifyBuildRequest raises on an attempt to build a virtualized # build on a non-virtual builder. job = self.makeJob() lfa = self.factory.makeLibraryFileAlias() transaction.commit() job.build.distro_arch_series.addOrUpdateChroot(lfa) builder = MockBuilder(virtualized=False) job.setBuilder(builder, OkSlave()) logger = BufferLogger() e = self.assertRaises(AssertionError, job.verifyBuildRequest, logger) self.assertEqual( "Attempt to build virtual item on a non-virtual builder.", str(e))