def test_run_all(self): """The job can be run under the JobRunner successfully.""" job = make_runnable_incremental_diff_job(self) with dbuser("merge-proposal-jobs"): runner = JobRunner([job]) runner.runAll() self.assertEqual([job], runner.completed_jobs)
def test_runAll_mails_user_errors(self): """User errors should be mailed out without oopsing. User errors are identified by the RunnableJob.user_error_types attribute. They do not cause an oops to be recorded, and their error messages are mailed to interested parties verbatim. """ job_1, job_2 = self.makeTwoJobs() class ExampleError(Exception): pass def raiseError(): raise ExampleError('Fake exception. Foobar, I say!') job_1.run = raiseError job_1.user_error_types = (ExampleError,) job_1.error_recipients = ['*****@*****.**'] runner = JobRunner([job_1, job_2]) runner.runAll() self.assertEqual([], self.oopses) notifications = pop_notifications() self.assertEqual(1, len(notifications)) body = notifications[0].get_payload(decode=True) self.assertEqual( 'Launchpad encountered an error during the following operation:' ' appending a string to a list. Fake exception. Foobar, I say!', body) self.assertEqual( 'Launchpad error while appending a string to a list', notifications[0]['subject'])
def test_runAll_mails_user_errors(self): """User errors should be mailed out without oopsing. User errors are identified by the RunnableJob.user_error_types attribute. They do not cause an oops to be recorded, and their error messages are mailed to interested parties verbatim. """ job_1, job_2 = self.makeTwoJobs() class ExampleError(Exception): pass def raiseError(): raise ExampleError('Fake exception. Foobar, I say!') job_1.run = raiseError job_1.user_error_types = (ExampleError, ) job_1.error_recipients = ['*****@*****.**'] runner = JobRunner([job_1, job_2]) runner.runAll() self.assertEqual([], self.oopses) notifications = pop_notifications() self.assertEqual(1, len(notifications)) body = notifications[0].get_payload(decode=True) self.assertEqual( 'Launchpad encountered an error during the following operation:' ' appending a string to a list. Fake exception. Foobar, I say!', body) self.assertEqual('Launchpad error while appending a string to a list', notifications[0]['subject'])
def test_runAll_skips_lease_failures(self): """Ensure runAll skips jobs whose leases can't be acquired.""" job_1, job_2 = self.makeTwoJobs() job_2.job.acquireLease() runner = JobRunner([job_1, job_2]) runner.runAll() self.assertEqual(JobStatus.COMPLETED, job_1.job.status) self.assertEqual(JobStatus.WAITING, job_2.job.status) self.assertEqual([job_1], runner.completed_jobs) self.assertEqual([job_2], runner.incomplete_jobs) self.assertEqual([], self.oopses)
def test_runAll(self): """Ensure runAll works in the normal case.""" job_1, job_2 = self.makeTwoJobs() runner = JobRunner([job_1, job_2]) runner.runAll() self.assertEqual(JobStatus.COMPLETED, job_1.job.status) self.assertEqual(JobStatus.COMPLETED, job_2.job.status) msg1 = NullJob.JOB_COMPLETIONS.pop() msg2 = NullJob.JOB_COMPLETIONS.pop() self.assertEqual(msg1, "job 2") self.assertEqual(msg2, "job 1") self.assertEqual([job_1, job_2], runner.completed_jobs)
def runJob(self, job): with dbuser("webhookrunner"): runner = JobRunner([job]) runner.runAll() job.lease_expires = None if len(runner.completed_jobs) == 1 and not runner.incomplete_jobs: return True if len(runner.incomplete_jobs) == 1 and not runner.completed_jobs: return False if not runner.incomplete_jobs and not runner.completed_jobs: return None raise Exception("Unexpected jobs.")
def test_oops_messages_used_when_handling(self): """Oops messages should appear even when exceptions are handled.""" job_1, job_2 = self.makeTwoJobs() def handleError(): reporter = errorlog.globalErrorUtility try: raise ValueError('Fake exception. Foobar, I say!') except ValueError: reporter.raising(sys.exc_info()) job_1.run = handleError runner = JobRunner([job_1, job_2]) runner.runAll() oops = self.oopses[-1] self.assertEqual(["{'foo': 'bar'}"], oops['req_vars'].values())
def test_runAll_aborts_transaction_on_error(self): """runAll should abort the transaction on oops.""" class DBAlterJob(NullJob): def __init__(self): super(DBAlterJob, self).__init__('') def run(self): self.job.log = 'hello' raise ValueError job = DBAlterJob() runner = JobRunner([job]) runner.runAll() # If the transaction was committed, job.log == 'hello'. If it was # aborted, it is None. self.assertIs(None, job.job.log)
def test_runAll_reports_oopses(self): """When an error is encountered, report an oops and continue.""" job_1, job_2 = self.makeTwoJobs() def raiseError(): # Ensure that jobs which call transaction.abort work, too. transaction.abort() raise Exception('Fake exception. Foobar, I say!') job_1.run = raiseError runner = JobRunner([job_1, job_2]) runner.runAll() self.assertEqual([], pop_notifications()) self.assertEqual([job_2], runner.completed_jobs) self.assertEqual([job_1], runner.incomplete_jobs) self.assertEqual(JobStatus.FAILED, job_1.job.status) self.assertEqual(JobStatus.COMPLETED, job_2.job.status) oops = self.oopses[-1] self.assertIn('Fake exception. Foobar, I say!', oops['tb_text']) self.assertEqual(["{'foo': 'bar'}"], oops['req_vars'].values())
def test_runAll_mails_oopses(self): """Email interested parties about OOPses.""" job_1, job_2 = self.makeTwoJobs() def raiseError(): # Ensure that jobs which call transaction.abort work, too. transaction.abort() raise Exception('Fake exception. Foobar, I say!') job_1.run = raiseError job_1.oops_recipients = ['*****@*****.**'] runner = JobRunner([job_1, job_2]) runner.runAll() (notification,) = pop_notifications() oops = self.oopses[-1] self.assertIn( 'Launchpad encountered an internal error during the following' ' operation: appending a string to a list. It was logged with id' ' %s. Sorry for the inconvenience.' % oops['id'], notification.get_payload(decode=True)) self.assertNotIn('Fake exception. Foobar, I say!', notification.get_payload(decode=True)) self.assertEqual('Launchpad internal error', notification['subject'])
def test_runAll_mails_oopses(self): """Email interested parties about OOPses.""" job_1, job_2 = self.makeTwoJobs() def raiseError(): # Ensure that jobs which call transaction.abort work, too. transaction.abort() raise Exception('Fake exception. Foobar, I say!') job_1.run = raiseError job_1.oops_recipients = ['*****@*****.**'] runner = JobRunner([job_1, job_2]) runner.runAll() (notification, ) = pop_notifications() oops = self.oopses[-1] self.assertIn( 'Launchpad encountered an internal error during the following' ' operation: appending a string to a list. It was logged with id' ' %s. Sorry for the inconvenience.' % oops['id'], notification.get_payload(decode=True)) self.assertNotIn('Fake exception. Foobar, I say!', notification.get_payload(decode=True)) self.assertEqual('Launchpad internal error', notification['subject'])