def test_checkForNewBuilders(self): # Test that checkForNewBuilders() detects a new builder # The basic case, where no builders are added. builder_scanner = self._getScanner() self.assertEqual([], builder_scanner.checkForNewBuilders()) # Add two builders and ensure they're returned. new_builders = ["scooby", "lassie"] factory = LaunchpadObjectFactory() for builder_name in new_builders: factory.makeBuilder(name=builder_name) self.assertEqual(new_builders, builder_scanner.checkForNewBuilders())
def test_checkForNewBuilders(self): # Test that checkForNewBuilders() detects a new builder # The basic case, where no builders are added. builder_scanner = self._getScanner() self.assertEqual([], builder_scanner.checkForNewBuilders()) # Add two builders and ensure they're returned. new_builders = ["scooby", "lassie"] factory = LaunchpadObjectFactory() for builder_name in new_builders: factory.makeBuilder(name=builder_name) self.assertEqual( new_builders, builder_scanner.checkForNewBuilders())
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)
class TestBuildNotifications(TrialTestCase): layer = LaunchpadZopelessLayer def setUp(self): super(TestBuildNotifications, self).setUp() from lp.testing.factory import LaunchpadObjectFactory self.factory = LaunchpadObjectFactory() def prepareBehavior(self, fake_successful_upload=False): self.queue_record = self.factory.makeSourcePackageRecipeBuildJob() build = self.queue_record.specific_job.build build.updateStatus(BuildStatus.FULLYBUILT) 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.getBuildBehavior(self.queue_record, self.queue_record.builder, slave) def assertDeferredNotifyCount(self, status, behavior, expected_count): d = behavior.handleStatus(self.queue_record, status, {'filemap': {}}) def cb(result): self.assertEqual(expected_count, len(pop_notifications())) d.addCallback(cb) return d def test_handleStatus_PACKAGEFAIL(self): """Failing to build the package immediately sends a notification.""" return self.assertDeferredNotifyCount("PACKAGEFAIL", self.prepareBehavior(), 1) def test_handleStatus_OK(self): """Building the source package does _not_ immediately send mail. (The archive uploader mail send one later. """ return self.assertDeferredNotifyCount("OK", self.prepareBehavior(), 0) def test_handleStatus_OK_successful_upload(self): return self.assertDeferredNotifyCount("OK", self.prepareBehavior(True), 0)
class TestBuildNotifications(TrialTestCase): layer = LaunchpadZopelessLayer def setUp(self): super(TestBuildNotifications, self).setUp() from lp.testing.factory import LaunchpadObjectFactory self.factory = LaunchpadObjectFactory() def prepareBehavior(self, fake_successful_upload=False): self.queue_record = self.factory.makeSourcePackageRecipeBuildJob() build = self.queue_record.specific_job.build build.updateStatus(BuildStatus.FULLYBUILT) 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.getBuildBehavior(self.queue_record, self.queue_record.builder, slave) def assertDeferredNotifyCount(self, status, behavior, expected_count): d = behavior.handleStatus(self.queue_record, status, {"filemap": {}}) def cb(result): self.assertEqual(expected_count, len(pop_notifications())) d.addCallback(cb) return d def test_handleStatus_PACKAGEFAIL(self): """Failing to build the package immediately sends a notification.""" return self.assertDeferredNotifyCount("PACKAGEFAIL", self.prepareBehavior(), 1) def test_handleStatus_OK(self): """Building the source package does _not_ immediately send mail. (The archive uploader mail send one later. """ return self.assertDeferredNotifyCount("OK", self.prepareBehavior(), 0) def test_handleStatus_OK_successful_upload(self): return self.assertDeferredNotifyCount("OK", self.prepareBehavior(True), 0)
class TestHandleStatusMixin: """Tests for `IPackageBuild`s handleStatus method. This should be run with a Trial TestCase. """ layer = LaunchpadZopelessLayer def makeBuild(self): """Allow classes to override the build with which the test runs.""" raise NotImplementedError 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 assertResultCount(self, count, result): self.assertEqual( 1, len(os.listdir(os.path.join(self.upload_root, result)))) @defer.inlineCallbacks def test_handleStatus_OK_normal_file(self): # A filemap with plain filenames should not cause a problem. # The call to handleStatus will attempt to get the file from # the slave resulting in a URL error in this test case. with dbuser(config.builddmaster.dbuser): yield self.behaviour.handleStatus( self.build.buildqueue_record, 'OK', {'filemap': { 'myfile.py': 'test_file_hash' }}) self.assertEqual(BuildStatus.UPLOADING, self.build.status) self.assertResultCount(1, "incoming") @defer.inlineCallbacks def test_handleStatus_OK_absolute_filepath(self): # A filemap that tries to write to files outside of the upload # directory will not be collected. with ExpectedException( BuildDaemonError, "Build returned a file named u'/tmp/myfile.py'."): with dbuser(config.builddmaster.dbuser): yield self.behaviour.handleStatus( self.build.buildqueue_record, 'OK', {'filemap': { '/tmp/myfile.py': 'test_file_hash' }}) @defer.inlineCallbacks def test_handleStatus_OK_relative_filepath(self): # A filemap that tries to write to files outside of # the upload directory will not be collected. with ExpectedException(BuildDaemonError, "Build returned a file named u'../myfile.py'."): with dbuser(config.builddmaster.dbuser): yield self.behaviour.handleStatus( self.build.buildqueue_record, 'OK', {'filemap': { '../myfile.py': 'test_file_hash' }}) @defer.inlineCallbacks def test_handleStatus_OK_sets_build_log(self): # The build log is set during handleStatus. self.assertEqual(None, self.build.log) with dbuser(config.builddmaster.dbuser): yield self.behaviour.handleStatus( self.build.buildqueue_record, 'OK', {'filemap': { 'myfile.py': 'test_file_hash' }}) self.assertNotEqual(None, self.build.log) @defer.inlineCallbacks def _test_handleStatus_notifies(self, status): # An email notification is sent for a given build status if # notifications are allowed for that status. expected_notification = ( status in self.behaviour.ALLOWED_STATUS_NOTIFICATIONS) with dbuser(config.builddmaster.dbuser): yield self.behaviour.handleStatus(self.build.buildqueue_record, status, {}) if expected_notification: self.assertNotEqual(0, len(pop_notifications()), "Notifications received") else: self.assertEqual(0, len(pop_notifications()), "Notifications received") def test_handleStatus_DEPFAIL_notifies(self): return self._test_handleStatus_notifies("DEPFAIL") def test_handleStatus_CHROOTFAIL_notifies(self): return self._test_handleStatus_notifies("CHROOTFAIL") def test_handleStatus_PACKAGEFAIL_notifies(self): return self._test_handleStatus_notifies("PACKAGEFAIL") @defer.inlineCallbacks def test_handleStatus_ABORTED_cancels_cancelling(self): with dbuser(config.builddmaster.dbuser): self.build.updateStatus(BuildStatus.CANCELLING) yield self.behaviour.handleStatus(self.build.buildqueue_record, "ABORTED", {}) self.assertEqual(0, len(pop_notifications()), "Notifications received") self.assertEqual(BuildStatus.CANCELLED, self.build.status) @defer.inlineCallbacks def test_handleStatus_ABORTED_illegal_when_building(self): self.builder.vm_host = "fake_vm_host" self.behaviour = self.interactor.getBuildBehaviour( self.build.buildqueue_record, self.builder, self.slave) with dbuser(config.builddmaster.dbuser): self.build.updateStatus(BuildStatus.BUILDING) with ExpectedException( BuildDaemonError, "Build returned unexpected status: u'ABORTED'"): yield self.behaviour.handleStatus(self.build.buildqueue_record, "ABORTED", {}) @defer.inlineCallbacks def test_handleStatus_ABORTED_cancelling_sets_build_log(self): # If a build is intentionally cancelled, the build log is set. self.assertEqual(None, self.build.log) with dbuser(config.builddmaster.dbuser): self.build.updateStatus(BuildStatus.CANCELLING) yield self.behaviour.handleStatus(self.build.buildqueue_record, "ABORTED", {}) self.assertNotEqual(None, self.build.log) @defer.inlineCallbacks def test_date_finished_set(self): # The date finished is updated during handleStatus_OK. self.assertEqual(None, self.build.date_finished) with dbuser(config.builddmaster.dbuser): yield self.behaviour.handleStatus( self.build.buildqueue_record, 'OK', {'filemap': { 'myfile.py': 'test_file_hash' }}) self.assertNotEqual(None, self.build.date_finished) @defer.inlineCallbacks def test_givenback_collection(self): with ExpectedException( BuildDaemonError, "Build returned unexpected status: u'GIVENBACK'"): with dbuser(config.builddmaster.dbuser): yield self.behaviour.handleStatus(self.build.buildqueue_record, "GIVENBACK", {}) @defer.inlineCallbacks def test_builderfail_collection(self): with ExpectedException( BuildDaemonError, "Build returned unexpected status: u'BUILDERFAIL'"): with dbuser(config.builddmaster.dbuser): yield self.behaviour.handleStatus(self.build.buildqueue_record, "BUILDERFAIL", {}) @defer.inlineCallbacks def test_invalid_status_collection(self): with ExpectedException(BuildDaemonError, "Build returned unexpected status: u'BORKED'"): with dbuser(config.builddmaster.dbuser): yield self.behaviour.handleStatus(self.build.buildqueue_record, "BORKED", {})
class TestHandleStatusMixin: """Tests for `IPackageBuild`s handleStatus method. This should be run with a Trial TestCase. """ layer = LaunchpadZopelessLayer def makeBuild(self): """Allow classes to override the build with which the test runs.""" raise NotImplementedError 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.behavior = self.interactor.getBuildBehavior( 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 assertResultCount(self, count, result): self.assertEquals( 1, len(os.listdir(os.path.join(self.upload_root, result)))) def test_handleStatus_OK_normal_file(self): # A filemap with plain filenames should not cause a problem. # The call to handleStatus will attempt to get the file from # the slave resulting in a URL error in this test case. def got_status(ignored): self.assertEqual(BuildStatus.UPLOADING, self.build.status) self.assertResultCount(1, "incoming") d = self.behavior.handleStatus( self.build.buildqueue_record, 'OK', {'filemap': {'myfile.py': 'test_file_hash'}}) return d.addCallback(got_status) def test_handleStatus_OK_absolute_filepath(self): # A filemap that tries to write to files outside of # the upload directory will result in a failed upload. def got_status(ignored): self.assertEqual(BuildStatus.FAILEDTOUPLOAD, self.build.status) self.assertResultCount(0, "failed") self.assertIdentical(None, self.build.buildqueue_record) d = self.behavior.handleStatus( self.build.buildqueue_record, 'OK', {'filemap': {'/tmp/myfile.py': 'test_file_hash'}}) return d.addCallback(got_status) def test_handleStatus_OK_relative_filepath(self): # A filemap that tries to write to files outside of # the upload directory will result in a failed upload. def got_status(ignored): self.assertEqual(BuildStatus.FAILEDTOUPLOAD, self.build.status) self.assertResultCount(0, "failed") d = self.behavior.handleStatus( self.build.buildqueue_record, 'OK', {'filemap': {'../myfile.py': 'test_file_hash'}}) return d.addCallback(got_status) def test_handleStatus_OK_sets_build_log(self): # The build log is set during handleStatus. self.assertEqual(None, self.build.log) d = self.behavior.handleStatus( self.build.buildqueue_record, 'OK', {'filemap': {'myfile.py': 'test_file_hash'}}) def got_status(ignored): self.assertNotEqual(None, self.build.log) return d.addCallback(got_status) def _test_handleStatus_notifies(self, status): # An email notification is sent for a given build status if # notifications are allowed for that status. expected_notification = ( status in self.behavior.ALLOWED_STATUS_NOTIFICATIONS) def got_status(ignored): if expected_notification: self.failIf( len(pop_notifications()) == 0, "No notifications received") else: self.failIf( len(pop_notifications()) > 0, "Notifications received") d = self.behavior.handleStatus( self.build.buildqueue_record, status, {}) return d.addCallback(got_status) def test_handleStatus_DEPFAIL_notifies(self): return self._test_handleStatus_notifies("DEPFAIL") def test_handleStatus_CHROOTFAIL_notifies(self): return self._test_handleStatus_notifies("CHROOTFAIL") def test_handleStatus_PACKAGEFAIL_notifies(self): return self._test_handleStatus_notifies("PACKAGEFAIL") def test_handleStatus_ABORTED_cancels_cancelling(self): self.build.updateStatus(BuildStatus.CANCELLING) def got_status(ignored): self.assertEqual( 0, len(pop_notifications()), "Notifications received") self.assertEqual(BuildStatus.CANCELLED, self.build.status) d = self.behavior.handleStatus( self.build.buildqueue_record, "ABORTED", {}) return d.addCallback(got_status) def test_handleStatus_ABORTED_recovers_building(self): self.builder.vm_host = "fake_vm_host" self.behavior = self.interactor.getBuildBehavior( self.build.buildqueue_record, self.builder, self.slave) self.build.updateStatus(BuildStatus.BUILDING) def got_status(ignored): self.assertEqual( 0, len(pop_notifications()), "Notifications received") self.assertEqual(BuildStatus.NEEDSBUILD, self.build.status) self.assertEqual(1, self.builder.failure_count) self.assertEqual(1, self.build.failure_count) self.assertIn("clean", self.slave.call_log) d = self.behavior.handleStatus( self.build.buildqueue_record, "ABORTED", {}) return d.addCallback(got_status) @defer.inlineCallbacks def test_handleStatus_ABORTED_cancelling_sets_build_log(self): # If a build is intentionally cancelled, the build log is set. self.assertEqual(None, self.build.log) self.build.updateStatus(BuildStatus.CANCELLING) yield self.behavior.handleStatus( self.build.buildqueue_record, "ABORTED", {}) self.assertNotEqual(None, self.build.log) def test_date_finished_set(self): # The date finished is updated during handleStatus_OK. self.assertEqual(None, self.build.date_finished) d = self.behavior.handleStatus( self.build.buildqueue_record, 'OK', {'filemap': {'myfile.py': 'test_file_hash'}}) def got_status(ignored): self.assertNotEqual(None, self.build.date_finished) return d.addCallback(got_status)