def setUp(self): super(TestHandleStatusMixin, self).setUp() self.factory = LaunchpadObjectFactory() self.build = self.makeBuild() # For the moment, we require a builder for the build so that # handleStatus_OK can get a reference to the slave. self.builder = self.factory.makeBuilder() self.build.buildqueue_record.markAsBuilding(self.builder) self.slave = WaitingSlave('BuildStatus.OK') self.slave.valid_file_hashes.append('test_file_hash') self.interactor = BuilderInteractor() self.behaviour = self.interactor.getBuildBehaviour( self.build.buildqueue_record, self.builder, self.slave) # We overwrite the buildmaster root to use a temp directory. tempdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, tempdir) self.upload_root = tempdir tmp_builddmaster_root = """ [builddmaster] root: %s """ % self.upload_root config.push('tmp_builddmaster_root', tmp_builddmaster_root) # We stub out our builds getUploaderCommand() method so # we can check whether it was called as well as # verifySuccessfulUpload(). removeSecurityProxy( self.build).verifySuccessfulUpload = FakeMethod(result=True)
def test_recover_waiting_slave_with_good_id(self): # rescueIfLost does not attempt to abort or clean a builder that is # WAITING. waiting_slave = WaitingSlave(build_id='trivial') lost = yield BuilderInteractor.rescueIfLost( extract_vitals_from_db(MockBuilder()), waiting_slave, 'trivial') self.assertFalse(lost) self.assertEqual(['status'], waiting_slave.call_log)
def test_chrootfail_collection(self): # There was a chroot problem for this build. def got_update(ignored): self.assertBuildProperties(self.build) self.assertEqual(BuildStatus.CHROOTWAIT, self.build.status) d = self.updateBuild(self.candidate, WaitingSlave('BuildStatus.CHROOTFAIL')) return d.addCallback(got_update)
def test_uploading_collection(self): # After a successful build, the status should be UPLOADING. def got_update(ignored): self.assertEqual(self.build.status, BuildStatus.UPLOADING) # We do not store any upload log information when the binary # upload processing succeeded. self.assertIs(None, self.build.upload_log) d = self.updateBuild(self.candidate, WaitingSlave('BuildStatus.OK')) return d.addCallback(got_update)
def test_packagefail_collection(self): # When a package fails to build, make sure the builder notes are # stored and the build status is set as failed. def got_update(ignored): self.assertBuildProperties(self.build) self.assertEqual(BuildStatus.FAILEDTOBUILD, self.build.status) d = self.updateBuild(self.candidate, WaitingSlave('BuildStatus.PACKAGEFAIL')) return d.addCallback(got_update)
def test_recover_waiting_slave_with_bad_id(self): # If a slave is WAITING with a build for us to get, and the build # cookie cannot be verified, which means we don't recognize the build, # then rescueBuilderIfLost should attempt to abort it, so that the # builder is reset for a new build, and the corrupt build is # discarded. waiting_slave = WaitingSlave(build_id='non-trivial') lost = yield BuilderInteractor.rescueIfLost( extract_vitals_from_db(MockBuilder()), waiting_slave, 'trivial') self.assertTrue(lost) self.assertEqual(['status', 'clean'], waiting_slave.call_log)
def test_depwait_collection(self): # Package build was left in dependency wait. DEPENDENCIES = 'baz (>= 1.0.1)' def got_update(ignored): self.assertBuildProperties(self.build) self.assertEqual(BuildStatus.MANUALDEPWAIT, self.build.status) self.assertEqual(DEPENDENCIES, self.build.dependencies) d = self.updateBuild(self.candidate, WaitingSlave('BuildStatus.DEPFAIL', DEPENDENCIES)) return d.addCallback(got_update)
def test_collection_for_deleted_source(self): # If we collected a build for a superseded/deleted source then # the build should get marked superseded as the build results # get discarded. spr = removeSecurityProxy(self.build.source_package_release) pub = self.build.current_source_publication pub.requestDeletion(spr.creator) def got_update(ignored): self.assertEqual(BuildStatus.SUPERSEDED, self.build.status) d = self.updateBuild(self.candidate, WaitingSlave('BuildStatus.OK')) return d.addCallback(got_update)
def test_givenback_collection(self): score = self.candidate.lastscore def got_update(ignored): self.assertIs(None, self.candidate.builder) self.assertIs(None, self.candidate.date_started) self.assertEqual(score, self.candidate.lastscore) self.assertEqual(BuildStatus.NEEDSBUILD, self.build.status) job = self.candidate.specific_job.job self.assertEqual(JobStatus.WAITING, job.status) d = self.updateBuild(self.candidate, WaitingSlave('BuildStatus.GIVENBACK')) return d.addCallback(got_update)
def test_builderfail_collection(self): # The builder failed after we dispatched the build. def got_update(ignored): self.assertEqual( "Builder returned BUILDERFAIL when asked for its status", self.builder.failnotes) self.assertIs(None, self.candidate.builder) self.assertEqual(BuildStatus.NEEDSBUILD, self.build.status) job = self.candidate.specific_job.job self.assertEqual(JobStatus.WAITING, job.status) d = self.updateBuild(self.candidate, WaitingSlave('BuildStatus.BUILDERFAIL')) return d.addCallback(got_update)
def makeBehaviour(self, branch=None, use_fake_chroot=True, **kwargs): """Create a TranslationTemplatesBuildBehaviour. Anything that might communicate with build slaves and such (which we can't really do here) is mocked up. """ build = self.factory.makeTranslationTemplatesBuild(branch=branch) behaviour = IBuildFarmJobBehaviour(build) slave = WaitingSlave(**kwargs) behaviour.setBuilder(self.factory.makeBuilder(), slave) if use_fake_chroot: behaviour.distro_arch_series.addOrUpdateChroot( self.factory.makeLibraryFileAlias(db_only=True)) self.layer.txn.commit() return behaviour
def test_log_file_collection(self): self.build.updateStatus(BuildStatus.FULLYBUILT) old_tmps = sorted(os.listdir('/tmp')) slave = WaitingSlave('BuildStatus.OK') def got_log(logfile_lfa_id): # Grabbing logs should not leave new files in /tmp (bug #172798) logfile_lfa = getUtility(ILibraryFileAliasSet)[logfile_lfa_id] new_tmps = sorted(os.listdir('/tmp')) self.assertEqual(old_tmps, new_tmps) # The new librarian file is stored compressed with a .gz # extension and text/plain file type for easy viewing in # browsers, as it decompresses and displays the file inline. self.assertTrue( logfile_lfa.filename.endswith('_FULLYBUILT.txt.gz')) self.assertEqual('text/plain', logfile_lfa.mimetype) self.layer.txn.commit() # LibrarianFileAlias does not implement tell() or seek(), which # are required by gzip.open(), so we need to read the file out # of the librarian first. fd, fname = tempfile.mkstemp() self.addCleanup(os.remove, fname) tmp = os.fdopen(fd, 'wb') tmp.write(logfile_lfa.read()) tmp.close() uncompressed_file = gzip.open(fname).read() # Now make a temp filename that getFile() can write to. fd, tmp_orig_file_name = tempfile.mkstemp() self.addCleanup(os.remove, tmp_orig_file_name) # Check that the original file from the slave matches the # uncompressed file in the librarian. def got_orig_log(ignored): orig_file_content = open(tmp_orig_file_name).read() self.assertEqual(orig_file_content, uncompressed_file) d = removeSecurityProxy(slave).getFile('buildlog', tmp_orig_file_name) return d.addCallback(got_orig_log) behaviour = IBuildFarmJobBehaviour(self.build) behaviour.setBuilder(self.builder, slave) d = behaviour.getLogFromSlave(self.build.buildqueue_record) return d.addCallback(got_log)
def makeBehavior(self, branch=None, use_fake_chroot=True): """Create a TranslationTemplatesBuildBehavior. Anything that might communicate with build slaves and such (which we can't really do here) is mocked up. """ specific_job = self.factory.makeTranslationTemplatesBuildJob( branch=branch) behavior = IBuildFarmJobBehavior(specific_job) slave = WaitingSlave() behavior.setBuilder(self.factory.makeBuilder(), slave) if use_fake_chroot: lf = self.factory.makeLibraryFileAlias() self.layer.txn.commit() behavior._getChroot = lambda: lf return behavior
def prepareBehaviour(self, fake_successful_upload=False): self.queue_record = ( self.factory.makeSourcePackageRecipeBuild().queueBuild()) build = self.queue_record.specific_build if fake_successful_upload: removeSecurityProxy(build).verifySuccessfulUpload = FakeMethod( result=True) # We overwrite the buildmaster root to use a temp directory. tempdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, tempdir) self.upload_root = tempdir tmp_builddmaster_root = """ [builddmaster] root: %s """ % self.upload_root config.push('tmp_builddmaster_root', tmp_builddmaster_root) self.addCleanup(config.pop, 'tmp_builddmaster_root') self.queue_record.builder = self.factory.makeBuilder() slave = WaitingSlave('BuildStatus.OK') return BuilderInteractor.getBuildBehaviour( self.queue_record, self.queue_record.builder, slave)
def test_status_waiting_slave(self): self.assertStatus(WaitingSlave(), builder_status='BuilderStatus.WAITING', build_status='BuildStatus.OK', build_id=True, filemap={})
def test_nonvirtual_waiting(self): # A WAITING non-virtual slave just needs clean() called. yield self.assertCleanCalls( MockBuilder(virtualized=False, clean_status=BuilderCleanStatus.DIRTY), WaitingSlave(), ['status', 'clean'], True)