diff options
-rw-r--r-- | tests/test_scheduler.py | 39 | ||||
-rw-r--r-- | zuul/launcher/jenkins.py | 13 | ||||
-rw-r--r-- | zuul/scheduler.py | 1 |
3 files changed, 50 insertions, 3 deletions
diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py index 568c85d57..cacf4a91e 100644 --- a/tests/test_scheduler.py +++ b/tests/test_scheduler.py @@ -460,6 +460,7 @@ class FakeJenkins(object): self.hold_jobs_in_queue = False self.hold_jobs_in_build = False self.fail_tests = {} + self.nonexistent_jobs = [] def fakeEnqueue(self, job): self.queue.append(job) @@ -505,6 +506,8 @@ class FakeJenkins(object): return False def build_job(self, name, parameters): + if name in self.nonexistent_jobs: + raise Exception("Job does not exist") count = self.job_counter.get(name, 0) count += 1 self.job_counter[name] = count @@ -1530,3 +1533,39 @@ class testScheduler(unittest.TestCase): assert A.data['status'] == 'MERGED' assert A.reported == 2 self.assertEmptyQueues() + + def test_nonexistent_job(self): + "Test launching a job that doesn't exist" + self.fake_jenkins.nonexistent_jobs.append('project-merge') + self.jenkins.launch_retry_timeout = 0.1 + + A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') + A.addApproval('CRVW', 2) + self.fake_gerrit.addEvent(A.addApproval('APRV', 1)) + # There may be a thread about to report a lost change + while A.reported < 2: + self.waitUntilSettled() + jobs = self.fake_jenkins.job_history + job_names = [x['name'] for x in jobs] + assert not job_names + assert A.data['status'] == 'NEW' + assert A.reported == 2 + self.assertEmptyQueues() + + # Make sure things still work: + self.fake_jenkins.nonexistent_jobs = [] + A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') + A.addApproval('CRVW', 2) + self.fake_gerrit.addEvent(A.addApproval('APRV', 1)) + self.waitUntilSettled() + jobs = self.fake_jenkins.job_history + job_names = [x['name'] for x in jobs] + assert 'project-merge' in job_names + assert 'project-test1' in job_names + assert 'project-test2' in job_names + assert jobs[0]['result'] == 'SUCCESS' + assert jobs[1]['result'] == 'SUCCESS' + assert jobs[2]['result'] == 'SUCCESS' + assert A.data['status'] == 'MERGED' + assert A.reported == 2 + self.assertEmptyQueues() diff --git a/zuul/launcher/jenkins.py b/zuul/launcher/jenkins.py index 19396ae51..6fd4ca410 100644 --- a/zuul/launcher/jenkins.py +++ b/zuul/launcher/jenkins.py @@ -190,6 +190,7 @@ class ExtendedJenkins(jenkins.Jenkins): class Jenkins(object): log = logging.getLogger("zuul.Jenkins") + launch_retry_timeout = 5 def __init__(self, config, sched): self.sched = sched @@ -267,7 +268,7 @@ class Jenkins(object): self.log.exception("Exception launching build %s for " "job %s for change %s (will retry):" % (build, job, change)) - time.sleep(5) + time.sleep(self.launch_retry_timeout) if errored: if launched: @@ -277,10 +278,16 @@ class Jenkins(object): "declaring lost" % build) # To keep the queue moving, declare this as a lost build # so that the change will get dropped. - self.onBuildCompleted(build.uuid, 'LOST', None, None) - + t = threading.Thread(target=self.declareBuildLost, + args=(build,)) + t.start() return build + def declareBuildLost(self, build): + # Call this from a new thread to invoke onBuildCompleted from + # a thread that has the queue lock. + self.onBuildCompleted(build.uuid, 'LOST', None, None) + def findBuildInQueue(self, build): for item in self.jenkins.get_queue_info(): if 'actions' not in item: diff --git a/zuul/scheduler.py b/zuul/scheduler.py index 4b205f1ab..329d0c42e 100644 --- a/zuul/scheduler.py +++ b/zuul/scheduler.py @@ -707,6 +707,7 @@ class BasePipelineManager(object): result = job.success_message elif result == 'FAILURE' and job.failure_message: result = job.failure_message + url = None if build.url: if pattern: url = pattern.format(change=changeish, |