blob: 568c85d57b25630845e69f2d549f03e207905f4c [file] [log] [blame]
James E. Blairb0fcae42012-07-17 11:12:10 -07001#!/usr/bin/env python
2
3# Copyright 2012 Hewlett-Packard Development Company, L.P.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17import unittest
18import ConfigParser
19import os
20import Queue
James E. Blair8cc15a82012-08-01 11:17:57 -070021import hashlib
James E. Blairb0fcae42012-07-17 11:12:10 -070022import logging
James E. Blair8cc15a82012-08-01 11:17:57 -070023import random
James E. Blairb0fcae42012-07-17 11:12:10 -070024import json
25import threading
26import time
27import pprint
28import re
James E. Blair8cc15a82012-08-01 11:17:57 -070029import urllib2
30import urlparse
James E. Blair4886cc12012-07-18 15:39:41 -070031import shutil
32import git
James E. Blairb0fcae42012-07-17 11:12:10 -070033
34import zuul
35import zuul.scheduler
36import zuul.launcher.jenkins
37import zuul.trigger.gerrit
38
39FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
40 'fixtures')
41CONFIG = ConfigParser.ConfigParser()
42CONFIG.read(os.path.join(FIXTURE_DIR, "zuul.conf"))
43
44CONFIG.set('zuul', 'layout_config',
45 os.path.join(FIXTURE_DIR, "layout.yaml"))
46
James E. Blair1dbd5082012-08-23 15:12:15 -070047TMP_ROOT = os.environ.get("ZUUL_TEST_ROOT", "/tmp")
48TEST_ROOT = os.path.join(TMP_ROOT, "zuul-test")
49UPSTREAM_ROOT = os.path.join(TEST_ROOT, "upstream")
50GIT_ROOT = os.path.join(TEST_ROOT, "git")
51
52CONFIG.set('zuul', 'git_dir', GIT_ROOT)
53
James E. Blairb0fcae42012-07-17 11:12:10 -070054logging.basicConfig(level=logging.DEBUG)
55
56
James E. Blair8cc15a82012-08-01 11:17:57 -070057def random_sha1():
58 return hashlib.sha1(str(random.random())).hexdigest()
59
60
James E. Blair4886cc12012-07-18 15:39:41 -070061class ChangeReference(git.Reference):
62 _common_path_default = "refs/changes"
63 _points_to_commits_only = True
64
65
66def init_repo(project):
67 parts = project.split('/')
James E. Blair1dbd5082012-08-23 15:12:15 -070068 path = os.path.join(UPSTREAM_ROOT, *parts[:-1])
James E. Blair4886cc12012-07-18 15:39:41 -070069 if not os.path.exists(path):
70 os.makedirs(path)
James E. Blair1dbd5082012-08-23 15:12:15 -070071 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -070072 repo = git.Repo.init(path)
73
74 fn = os.path.join(path, 'README')
75 f = open(fn, 'w')
76 f.write("test\n")
77 f.close()
78 repo.index.add([fn])
79 repo.index.commit('initial commit')
James E. Blairc6294a52012-08-17 10:19:48 -070080 master = repo.create_head('master')
James E. Blair4886cc12012-07-18 15:39:41 -070081 repo.create_tag('init')
82
James E. Blairc6294a52012-08-17 10:19:48 -070083 mp = repo.create_head('mp')
84 repo.head.reference = mp
85 f = open(fn, 'a')
86 f.write("test mp\n")
87 f.close()
88 repo.index.add([fn])
89 repo.index.commit('mp commit')
90
91 repo.head.reference = master
92 repo.head.reset(index=True, working_tree=True)
93 repo.git.clean('-x', '-f', '-d')
94
James E. Blair4886cc12012-07-18 15:39:41 -070095
James E. Blair973721f2012-08-15 10:19:43 -070096def add_fake_change_to_repo(project, branch, change_num, patchset, msg, fn):
James E. Blair1dbd5082012-08-23 15:12:15 -070097 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -070098 repo = git.Repo(path)
99 ref = ChangeReference.create(repo, '1/%s/%s' % (change_num,
100 patchset),
101 'refs/tags/init')
102 repo.head.reference = ref
103 repo.head.reset(index=True, working_tree=True)
104 repo.git.clean('-x', '-f', '-d')
105
James E. Blair1dbd5082012-08-23 15:12:15 -0700106 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair973721f2012-08-15 10:19:43 -0700107 fn = os.path.join(path, fn)
James E. Blair4886cc12012-07-18 15:39:41 -0700108 f = open(fn, 'w')
James E. Blair973721f2012-08-15 10:19:43 -0700109 f.write("test %s %s %s\n" % (branch, change_num, patchset))
James E. Blair4886cc12012-07-18 15:39:41 -0700110 f.close()
111 repo.index.add([fn])
James E. Blairdaabed22012-08-15 15:38:57 -0700112 return repo.index.commit(msg)
James E. Blair4886cc12012-07-18 15:39:41 -0700113
114
115def ref_has_change(ref, change):
James E. Blair1dbd5082012-08-23 15:12:15 -0700116 path = os.path.join(GIT_ROOT, change.project)
James E. Blair4886cc12012-07-18 15:39:41 -0700117 repo = git.Repo(path)
118 for commit in repo.iter_commits(ref):
119 if commit.message.strip() == ('%s-1' % change.subject):
120 return True
121 return False
122
123
124def job_has_changes(*args):
125 job = args[0]
126 commits = args[1:]
127 project = job.parameters['ZUUL_PROJECT']
James E. Blair1dbd5082012-08-23 15:12:15 -0700128 path = os.path.join(GIT_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -0700129 repo = git.Repo(path)
130 ref = job.parameters['ZUUL_REF']
131 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
132 commit_messages = ['%s-1' % commit.subject for commit in commits]
James E. Blair4886cc12012-07-18 15:39:41 -0700133 for msg in commit_messages:
134 if msg not in repo_messages:
135 return False
136 return True
137
138
James E. Blairb0fcae42012-07-17 11:12:10 -0700139class FakeChange(object):
James E. Blair8c803f82012-07-31 16:25:42 -0700140 categories = {'APRV': ('Approved', -1, 1),
141 'CRVW': ('Code-Review', -2, 2),
142 'VRFY': ('Verified', -2, 2)}
James E. Blairb0fcae42012-07-17 11:12:10 -0700143
James E. Blair8cc15a82012-08-01 11:17:57 -0700144 def __init__(self, gerrit, number, project, branch, subject, status='NEW'):
145 self.gerrit = gerrit
James E. Blaird466dc42012-07-31 10:42:56 -0700146 self.reported = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700147 self.queried = 0
James E. Blairb0fcae42012-07-17 11:12:10 -0700148 self.patchsets = []
James E. Blairb0fcae42012-07-17 11:12:10 -0700149 self.number = number
150 self.project = project
151 self.branch = branch
152 self.subject = subject
153 self.latest_patchset = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700154 self.depends_on_change = None
155 self.needed_by_changes = []
James E. Blair127bc182012-08-28 15:55:15 -0700156 self.fail_merge = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700157 self.data = {
158 'branch': branch,
159 'comments': [],
160 'commitMessage': subject,
161 'createdOn': time.time(),
James E. Blair8cc15a82012-08-01 11:17:57 -0700162 'id': 'I' + random_sha1(),
James E. Blairb0fcae42012-07-17 11:12:10 -0700163 'lastUpdated': time.time(),
164 'number': str(number),
165 'open': True,
166 'owner': {'email': 'user@example.com',
167 'name': 'User Name',
168 'username': 'username'},
169 'patchSets': self.patchsets,
170 'project': project,
171 'status': status,
172 'subject': subject,
James E. Blair8c803f82012-07-31 16:25:42 -0700173 'submitRecords': [],
James E. Blairb0fcae42012-07-17 11:12:10 -0700174 'url': 'https://hostname/%s' % number}
175
176 self.addPatchset()
James E. Blair8c803f82012-07-31 16:25:42 -0700177 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700178
179 def addPatchset(self, files=None):
180 self.latest_patchset += 1
James E. Blairdaabed22012-08-15 15:38:57 -0700181 if files:
182 fn = files[0]
183 else:
184 fn = '%s-%s' % (self.branch, self.number)
185 msg = self.subject + '-' + str(self.latest_patchset)
186 c = add_fake_change_to_repo(self.project, self.branch,
187 self.number, self.latest_patchset,
188 msg, fn)
James E. Blairb0fcae42012-07-17 11:12:10 -0700189 d = {'approvals': [],
190 'createdOn': time.time(),
191 'files': [{'file': '/COMMIT_MSG',
192 'type': 'ADDED'},
193 {'file': 'README',
194 'type': 'MODIFIED'}],
James E. Blair8c803f82012-07-31 16:25:42 -0700195 'number': str(self.latest_patchset),
James E. Blairb0fcae42012-07-17 11:12:10 -0700196 'ref': 'refs/changes/1/%s/%s' % (self.number,
197 self.latest_patchset),
James E. Blairdaabed22012-08-15 15:38:57 -0700198 'revision': c.hexsha,
James E. Blairb0fcae42012-07-17 11:12:10 -0700199 'uploader': {'email': 'user@example.com',
200 'name': 'User name',
201 'username': 'user'}}
202 self.data['currentPatchSet'] = d
203 self.patchsets.append(d)
James E. Blair8c803f82012-07-31 16:25:42 -0700204 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700205
James E. Blaire0487072012-08-29 17:38:31 -0700206 def getPatchsetCreatedEvent(self, patchset):
207 event = {"type": "patchset-created",
208 "change": {"project": self.project,
209 "branch": self.branch,
210 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
211 "number": str(self.number),
212 "subject": self.subject,
213 "owner": {"name": "User Name"},
214 "url": "https://hostname/3"},
215 "patchSet": self.patchsets[patchset - 1],
216 "uploader": {"name": "User Name"}}
217 return event
218
James E. Blairb0fcae42012-07-17 11:12:10 -0700219 def addApproval(self, category, value):
James E. Blair8c803f82012-07-31 16:25:42 -0700220 approval = {'description': self.categories[category][0],
221 'type': category,
222 'value': str(value)}
223 self.patchsets[-1]['approvals'].append(approval)
224 event = {'approvals': [approval],
James E. Blairb0fcae42012-07-17 11:12:10 -0700225 'author': {'email': 'user@example.com',
226 'name': 'User Name',
227 'username': 'username'},
228 'change': {'branch': self.branch,
229 'id': 'Iaa69c46accf97d0598111724a38250ae76a22c87',
230 'number': str(self.number),
231 'owner': {'email': 'user@example.com',
232 'name': 'User Name',
233 'username': 'username'},
234 'project': self.project,
235 'subject': self.subject,
236 'topic': 'master',
237 'url': 'https://hostname/459'},
238 'comment': '',
239 'patchSet': self.patchsets[-1],
240 'type': 'comment-added'}
James E. Blair8c803f82012-07-31 16:25:42 -0700241 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700242 return json.loads(json.dumps(event))
243
James E. Blair8c803f82012-07-31 16:25:42 -0700244 def getSubmitRecords(self):
245 status = {}
246 for cat in self.categories.keys():
247 status[cat] = 0
248
249 for a in self.patchsets[-1]['approvals']:
250 cur = status[a['type']]
251 cat_min, cat_max = self.categories[a['type']][1:]
252 new = int(a['value'])
253 if new == cat_min:
254 cur = new
255 elif abs(new) > abs(cur):
256 cur = new
257 status[a['type']] = cur
258
259 labels = []
260 ok = True
261 for typ, cat in self.categories.items():
262 cur = status[typ]
263 cat_min, cat_max = cat[1:]
264 if cur == cat_min:
265 value = 'REJECT'
266 ok = False
267 elif cur == cat_max:
268 value = 'OK'
269 else:
270 value = 'NEED'
271 ok = False
272 labels.append({'label': cat[0], 'status': value})
273 if ok:
274 return [{'status': 'OK'}]
275 return [{'status': 'NOT_READY',
276 'labels': labels}]
277
278 def setDependsOn(self, other, patchset):
279 self.depends_on_change = other
280 d = {'id': other.data['id'],
281 'number': other.data['number'],
282 'ref': other.patchsets[patchset - 1]['ref']
283 }
284 self.data['dependsOn'] = [d]
285
286 other.needed_by_changes.append(self)
287 needed = other.data.get('neededBy', [])
288 d = {'id': self.data['id'],
289 'number': self.data['number'],
290 'ref': self.patchsets[patchset - 1]['ref'],
291 'revision': self.patchsets[patchset - 1]['revision']
292 }
293 needed.append(d)
294 other.data['neededBy'] = needed
295
James E. Blairb0fcae42012-07-17 11:12:10 -0700296 def query(self):
James E. Blair8c803f82012-07-31 16:25:42 -0700297 self.queried += 1
298 d = self.data.get('dependsOn')
299 if d:
300 d = d[0]
301 if (self.depends_on_change.patchsets[-1]['ref'] == d['ref']):
302 d['isCurrentPatchSet'] = True
303 else:
304 d['isCurrentPatchSet'] = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700305 return json.loads(json.dumps(self.data))
306
307 def setMerged(self):
James E. Blaircaec0c52012-08-22 14:52:22 -0700308 if (self.depends_on_change
309 and self.depends_on_change.data['status'] != 'MERGED'):
310 return
James E. Blair127bc182012-08-28 15:55:15 -0700311 if self.fail_merge:
312 return
James E. Blairb0fcae42012-07-17 11:12:10 -0700313 self.data['status'] = 'MERGED'
314 self.open = False
James E. Blairdaabed22012-08-15 15:38:57 -0700315
James E. Blair1dbd5082012-08-23 15:12:15 -0700316 path = os.path.join(UPSTREAM_ROOT, self.project)
James E. Blairdaabed22012-08-15 15:38:57 -0700317 repo = git.Repo(path)
318 repo.heads[self.branch].commit = \
319 repo.commit(self.patchsets[-1]['revision'])
James E. Blairb0fcae42012-07-17 11:12:10 -0700320
James E. Blaird466dc42012-07-31 10:42:56 -0700321 def setReported(self):
322 self.reported += 1
323
James E. Blairb0fcae42012-07-17 11:12:10 -0700324
325class FakeGerrit(object):
326 def __init__(self, *args, **kw):
327 self.event_queue = Queue.Queue()
328 self.fixture_dir = os.path.join(FIXTURE_DIR, 'gerrit')
329 self.change_number = 0
330 self.changes = {}
331
332 def addFakeChange(self, project, branch, subject):
333 self.change_number += 1
James E. Blair8cc15a82012-08-01 11:17:57 -0700334 c = FakeChange(self, self.change_number, project, branch, subject)
James E. Blairb0fcae42012-07-17 11:12:10 -0700335 self.changes[self.change_number] = c
336 return c
337
338 def addEvent(self, data):
339 return self.event_queue.put(data)
340
341 def getEvent(self):
342 return self.event_queue.get()
343
344 def eventDone(self):
345 self.event_queue.task_done()
346
347 def review(self, project, changeid, message, action):
James E. Blaird466dc42012-07-31 10:42:56 -0700348 number, ps = changeid.split(',')
349 change = self.changes[int(number)]
James E. Blairb0fcae42012-07-17 11:12:10 -0700350 if 'submit' in action:
James E. Blairb0fcae42012-07-17 11:12:10 -0700351 change.setMerged()
James E. Blaird466dc42012-07-31 10:42:56 -0700352 if message:
353 change.setReported()
James E. Blairb0fcae42012-07-17 11:12:10 -0700354
355 def query(self, number):
356 change = self.changes[int(number)]
357 return change.query()
358
359 def startWatching(self, *args, **kw):
360 pass
361
362
363class FakeJenkinsEvent(object):
364 def __init__(self, name, number, parameters, phase, status=None):
365 data = {'build':
366 {'full_url': 'https://server/job/%s/%s/' % (name, number),
367 'number': number,
368 'parameters': parameters,
369 'phase': phase,
370 'url': 'job/%s/%s/' % (name, number)},
371 'name': name,
372 'url': 'job/%s/' % name}
373 if status:
374 data['build']['status'] = status
375 self.body = json.dumps(data)
376
377
378class FakeJenkinsJob(threading.Thread):
379 log = logging.getLogger("zuul.test")
380
381 def __init__(self, jenkins, callback, name, number, parameters):
382 threading.Thread.__init__(self)
383 self.jenkins = jenkins
384 self.callback = callback
385 self.name = name
386 self.number = number
387 self.parameters = parameters
388 self.wait_condition = threading.Condition()
389 self.waiting = False
James E. Blaird466dc42012-07-31 10:42:56 -0700390 self.aborted = False
391 self.canceled = False
392 self.created = time.time()
James E. Blairb0fcae42012-07-17 11:12:10 -0700393
394 def release(self):
395 self.wait_condition.acquire()
396 self.wait_condition.notify()
397 self.waiting = False
398 self.log.debug("Job %s released" % (self.parameters['UUID']))
399 self.wait_condition.release()
400
401 def isWaiting(self):
402 self.wait_condition.acquire()
403 if self.waiting:
404 ret = True
405 else:
406 ret = False
407 self.wait_condition.release()
408 return ret
409
410 def _wait(self):
411 self.wait_condition.acquire()
412 self.waiting = True
413 self.log.debug("Job %s waiting" % (self.parameters['UUID']))
414 self.wait_condition.wait()
415 self.wait_condition.release()
416
417 def run(self):
418 self.jenkins.fakeEnqueue(self)
419 if self.jenkins.hold_jobs_in_queue:
420 self._wait()
421 self.jenkins.fakeDequeue(self)
James E. Blaird466dc42012-07-31 10:42:56 -0700422 if self.canceled:
423 self.jenkins.all_jobs.remove(self)
424 return
James E. Blairb0fcae42012-07-17 11:12:10 -0700425 self.callback.jenkins_endpoint(FakeJenkinsEvent(
426 self.name, self.number, self.parameters,
427 'STARTED'))
428 if self.jenkins.hold_jobs_in_build:
429 self._wait()
430 self.log.debug("Job %s continuing" % (self.parameters['UUID']))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700431
432 result = 'SUCCESS'
James E. Blairdaabed22012-08-15 15:38:57 -0700433 if ('ZUUL_REF' in self.parameters) and self.jenkins.fakeShouldFailTest(
James E. Blairb02a3bb2012-07-30 17:49:55 -0700434 self.name,
James E. Blair4886cc12012-07-18 15:39:41 -0700435 self.parameters['ZUUL_REF']):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700436 result = 'FAILURE'
James E. Blaird466dc42012-07-31 10:42:56 -0700437 if self.aborted:
438 result = 'ABORTED'
James E. Blairb02a3bb2012-07-30 17:49:55 -0700439
James E. Blairb0fcae42012-07-17 11:12:10 -0700440 self.jenkins.fakeAddHistory(name=self.name, number=self.number,
James E. Blairb02a3bb2012-07-30 17:49:55 -0700441 result=result)
James E. Blairb0fcae42012-07-17 11:12:10 -0700442 self.callback.jenkins_endpoint(FakeJenkinsEvent(
443 self.name, self.number, self.parameters,
James E. Blairb02a3bb2012-07-30 17:49:55 -0700444 'COMPLETED', result))
James E. Blairb0fcae42012-07-17 11:12:10 -0700445 self.callback.jenkins_endpoint(FakeJenkinsEvent(
446 self.name, self.number, self.parameters,
James E. Blairb02a3bb2012-07-30 17:49:55 -0700447 'FINISHED', result))
James E. Blairb0fcae42012-07-17 11:12:10 -0700448 self.jenkins.all_jobs.remove(self)
449
450
451class FakeJenkins(object):
452 log = logging.getLogger("zuul.test")
453
454 def __init__(self, *args, **kw):
455 self.queue = []
456 self.all_jobs = []
457 self.job_counter = {}
James E. Blaird466dc42012-07-31 10:42:56 -0700458 self.queue_counter = 0
James E. Blairb0fcae42012-07-17 11:12:10 -0700459 self.job_history = []
460 self.hold_jobs_in_queue = False
461 self.hold_jobs_in_build = False
James E. Blairb02a3bb2012-07-30 17:49:55 -0700462 self.fail_tests = {}
James E. Blairb0fcae42012-07-17 11:12:10 -0700463
464 def fakeEnqueue(self, job):
465 self.queue.append(job)
466
467 def fakeDequeue(self, job):
468 self.queue.remove(job)
469
470 def fakeAddHistory(self, **kw):
471 self.job_history.append(kw)
472
473 def fakeRelease(self, regex=None):
474 all_jobs = self.all_jobs[:]
475 self.log.debug("releasing jobs %s (%s)" % (regex, len(self.all_jobs)))
476 for job in all_jobs:
477 if not regex or re.match(regex, job.name):
478 self.log.debug("releasing job %s" % (job.parameters['UUID']))
479 job.release()
480 else:
481 self.log.debug("not releasing job %s" % (
482 job.parameters['UUID']))
483 self.log.debug("done releasing jobs %s (%s)" % (regex,
484 len(self.all_jobs)))
485
486 def fakeAllWaiting(self, regex=None):
487 all_jobs = self.all_jobs[:]
488 for job in all_jobs:
489 self.log.debug("job %s %s" % (job.parameters['UUID'],
490 job.isWaiting()))
491 if not job.isWaiting():
492 return False
493 return True
494
James E. Blairb02a3bb2012-07-30 17:49:55 -0700495 def fakeAddFailTest(self, name, change):
496 l = self.fail_tests.get(name, [])
497 l.append(change)
498 self.fail_tests[name] = l
499
James E. Blair4886cc12012-07-18 15:39:41 -0700500 def fakeShouldFailTest(self, name, ref):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700501 l = self.fail_tests.get(name, [])
502 for change in l:
James E. Blair4886cc12012-07-18 15:39:41 -0700503 if ref_has_change(ref, change):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700504 return True
505 return False
506
James E. Blairb0fcae42012-07-17 11:12:10 -0700507 def build_job(self, name, parameters):
508 count = self.job_counter.get(name, 0)
509 count += 1
510 self.job_counter[name] = count
James E. Blaird466dc42012-07-31 10:42:56 -0700511
512 queue_count = self.queue_counter
513 self.queue_counter += 1
James E. Blairb0fcae42012-07-17 11:12:10 -0700514 job = FakeJenkinsJob(self, self.callback, name, count, parameters)
James E. Blaird466dc42012-07-31 10:42:56 -0700515 job.queue_id = queue_count
516
James E. Blairb0fcae42012-07-17 11:12:10 -0700517 self.all_jobs.append(job)
518 job.start()
519
James E. Blaird466dc42012-07-31 10:42:56 -0700520 def stop_build(self, name, number):
521 for job in self.all_jobs:
522 if job.name == name and job.number == number:
523 job.aborted = True
524 job.release()
525 return
526
527 def cancel_queue(self, id):
528 for job in self.queue:
529 if job.queue_id == id:
530 job.canceled = True
531 job.release()
532 return
533
534 def get_queue_info(self):
535 items = []
536 for job in self.queue:
537 paramstr = ''
538 paramlst = []
539 d = {'actions': [{'parameters': paramlst},
540 {'causes': [{'shortDescription':
541 'Started by user Jenkins',
542 'userId': 'jenkins',
543 'userName': 'Jenkins'}]}],
544 'blocked': False,
545 'buildable': True,
546 'buildableStartMilliseconds': (job.created * 1000) + 5,
547 'id': job.queue_id,
548 'inQueueSince': (job.created * 1000),
549 'params': paramstr,
550 'stuck': False,
551 'task': {'color': 'blue',
552 'name': job.name,
553 'url': 'https://server/job/%s/' % job.name},
554 'why': 'Waiting for next available executor'}
555 for k, v in job.parameters.items():
556 paramstr += "\n(StringParameterValue) %s='%s'" % (k, v)
557 pd = {'name': k, 'value': v}
558 paramlst.append(pd)
559 items.append(d)
560 return items
561
James E. Blairb0fcae42012-07-17 11:12:10 -0700562 def set_build_description(self, *args, **kw):
563 pass
564
565
566class FakeJenkinsCallback(zuul.launcher.jenkins.JenkinsCallback):
567 def start(self):
568 pass
569
570
James E. Blair8cc15a82012-08-01 11:17:57 -0700571class FakeURLOpener(object):
572 def __init__(self, fake_gerrit, url):
573 self.fake_gerrit = fake_gerrit
574 self.url = url
575
576 def read(self):
577 res = urlparse.urlparse(self.url)
578 path = res.path
579 project = '/'.join(path.split('/')[2:-2])
James E. Blair8cc15a82012-08-01 11:17:57 -0700580 ret = ''
James E. Blair1dbd5082012-08-23 15:12:15 -0700581 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blairdaabed22012-08-15 15:38:57 -0700582 repo = git.Repo(path)
583 for ref in repo.refs:
584 ret += ref.object.hexsha + '\t' + ref.path + '\n'
James E. Blair8cc15a82012-08-01 11:17:57 -0700585 return ret
586
587
James E. Blair4886cc12012-07-18 15:39:41 -0700588class FakeGerritTrigger(zuul.trigger.gerrit.Gerrit):
589 def getGitUrl(self, project):
James E. Blair1dbd5082012-08-23 15:12:15 -0700590 return os.path.join(UPSTREAM_ROOT, project.name)
James E. Blair4886cc12012-07-18 15:39:41 -0700591
592
James E. Blairb0fcae42012-07-17 11:12:10 -0700593class testScheduler(unittest.TestCase):
594 log = logging.getLogger("zuul.test")
595
596 def setUp(self):
James E. Blair1dbd5082012-08-23 15:12:15 -0700597 if os.path.exists(TEST_ROOT):
598 shutil.rmtree(TEST_ROOT)
599 os.makedirs(TEST_ROOT)
600 os.makedirs(UPSTREAM_ROOT)
601 os.makedirs(GIT_ROOT)
James E. Blair4886cc12012-07-18 15:39:41 -0700602
603 # For each project in config:
604 init_repo("org/project")
605 init_repo("org/project1")
606 init_repo("org/project2")
James E. Blair127bc182012-08-28 15:55:15 -0700607 init_repo("org/project3")
James E. Blair7f71c802012-08-22 13:04:32 -0700608 init_repo("org/one-job-project")
James E. Blair4ec821f2012-08-23 15:28:28 -0700609 init_repo("org/nonvoting-project")
James E. Blairb0fcae42012-07-17 11:12:10 -0700610 self.config = CONFIG
611 self.sched = zuul.scheduler.Scheduler()
612
613 def jenkinsFactory(*args, **kw):
614 self.fake_jenkins = FakeJenkins()
615 return self.fake_jenkins
616
617 def jenkinsCallbackFactory(*args, **kw):
618 self.fake_jenkins_callback = FakeJenkinsCallback(*args, **kw)
619 return self.fake_jenkins_callback
620
James E. Blair8cc15a82012-08-01 11:17:57 -0700621 def URLOpenerFactory(*args, **kw):
622 args = [self.fake_gerrit] + list(args)
623 return FakeURLOpener(*args, **kw)
624
James E. Blairb0fcae42012-07-17 11:12:10 -0700625 zuul.launcher.jenkins.ExtendedJenkins = jenkinsFactory
626 zuul.launcher.jenkins.JenkinsCallback = jenkinsCallbackFactory
James E. Blair8cc15a82012-08-01 11:17:57 -0700627 urllib2.urlopen = URLOpenerFactory
James E. Blairb0fcae42012-07-17 11:12:10 -0700628 self.jenkins = zuul.launcher.jenkins.Jenkins(self.config, self.sched)
629 self.fake_jenkins.callback = self.fake_jenkins_callback
630
631 zuul.lib.gerrit.Gerrit = FakeGerrit
632
James E. Blair4886cc12012-07-18 15:39:41 -0700633 self.gerrit = FakeGerritTrigger(self.config, self.sched)
James E. Blair8cc15a82012-08-01 11:17:57 -0700634 self.gerrit.replication_timeout = 1.5
635 self.gerrit.replication_retry_interval = 0.5
James E. Blairb0fcae42012-07-17 11:12:10 -0700636 self.fake_gerrit = self.gerrit.gerrit
637
638 self.sched.setLauncher(self.jenkins)
639 self.sched.setTrigger(self.gerrit)
640
641 self.sched.start()
642 self.sched.reconfigure(self.config)
643 self.sched.resume()
644
645 def tearDown(self):
646 self.jenkins.stop()
647 self.gerrit.stop()
648 self.sched.stop()
649 self.sched.join()
James E. Blair1dbd5082012-08-23 15:12:15 -0700650 #shutil.rmtree(TEST_ROOT)
James E. Blairb0fcae42012-07-17 11:12:10 -0700651
652 def waitUntilSettled(self):
653 self.log.debug("Waiting until settled...")
654 start = time.time()
655 while True:
656 if time.time() - start > 10:
657 print 'queue status:',
658 print self.sched.trigger_event_queue.empty(),
659 print self.sched.result_event_queue.empty(),
660 print self.fake_gerrit.event_queue.empty(),
661 raise Exception("Timeout waiting for Zuul to settle")
662 self.fake_gerrit.event_queue.join()
663 self.sched.queue_lock.acquire()
664 if (self.sched.trigger_event_queue.empty() and
665 self.sched.result_event_queue.empty() and
666 self.fake_gerrit.event_queue.empty() and
667 self.fake_jenkins.fakeAllWaiting()):
668 self.sched.queue_lock.release()
669 self.log.debug("...settled.")
670 return
671 self.sched.queue_lock.release()
672 self.sched.wake_event.wait(0.1)
673
James E. Blaird466dc42012-07-31 10:42:56 -0700674 def countJobResults(self, jobs, result):
675 jobs = filter(lambda x: x['result'] == result, jobs)
676 return len(jobs)
677
James E. Blaire0487072012-08-29 17:38:31 -0700678 def assertEmptyQueues(self):
679 # Make sure there are no orphaned jobs
680 for pipeline in self.sched.pipelines.values():
681 for queue in pipeline.queues:
682 if len(queue.queue) != 0:
683 print 'queue', queue.queue
684 assert len(queue.queue) == 0
685 if len(queue.severed_heads) != 0:
686 print 'heads', queue.severed_heads
687 assert len(queue.severed_heads) == 0
688
James E. Blairb0fcae42012-07-17 11:12:10 -0700689 def test_jobs_launched(self):
690 "Test that jobs are launched and a change is merged"
691 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -0700692 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700693 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
694 self.waitUntilSettled()
695 jobs = self.fake_jenkins.job_history
696 job_names = [x['name'] for x in jobs]
697 assert 'project-merge' in job_names
698 assert 'project-test1' in job_names
699 assert 'project-test2' in job_names
700 assert jobs[0]['result'] == 'SUCCESS'
701 assert jobs[1]['result'] == 'SUCCESS'
702 assert jobs[2]['result'] == 'SUCCESS'
703 assert A.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700704 assert A.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700705 self.assertEmptyQueues()
James E. Blairb0fcae42012-07-17 11:12:10 -0700706
707 def test_parallel_changes(self):
708 "Test that changes are tested in parallel and merged in series"
709 self.fake_jenkins.hold_jobs_in_build = True
710 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
711 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
712 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700713 A.addApproval('CRVW', 2)
714 B.addApproval('CRVW', 2)
715 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700716
717 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
718 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
719 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
720
721 self.waitUntilSettled()
722 jobs = self.fake_jenkins.all_jobs
723 assert len(jobs) == 1
724 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700725 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700726
727 self.fake_jenkins.fakeRelease('.*-merge')
728 self.waitUntilSettled()
729 assert len(jobs) == 3
730 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700731 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700732 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700733 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700734 assert jobs[2].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700735 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700736
737 self.fake_jenkins.fakeRelease('.*-merge')
738 self.waitUntilSettled()
739 assert len(jobs) == 5
740 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700741 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700742 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700743 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700744
745 assert jobs[2].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700746 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700747 assert jobs[3].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700748 assert job_has_changes(jobs[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700749
750 assert jobs[4].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700751 assert job_has_changes(jobs[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700752
753 self.fake_jenkins.fakeRelease('.*-merge')
754 self.waitUntilSettled()
755 assert len(jobs) == 6
756 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700757 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700758 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700759 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700760
761 assert jobs[2].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700762 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700763 assert jobs[3].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700764 assert job_has_changes(jobs[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700765
766 assert jobs[4].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700767 assert job_has_changes(jobs[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700768 assert jobs[5].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700769 assert job_has_changes(jobs[5], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700770
771 self.fake_jenkins.hold_jobs_in_build = False
772 self.fake_jenkins.fakeRelease()
773 self.waitUntilSettled()
774 assert len(jobs) == 0
775
776 jobs = self.fake_jenkins.job_history
777 assert len(jobs) == 9
778 assert A.data['status'] == 'MERGED'
779 assert B.data['status'] == 'MERGED'
780 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700781 assert A.reported == 2
782 assert B.reported == 2
783 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700784 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700785
786 def test_failed_changes(self):
787 "Test that a change behind a failed change is retested"
788 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
789 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -0700790 A.addApproval('CRVW', 2)
791 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700792
793 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
794 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
795
James E. Blair4886cc12012-07-18 15:39:41 -0700796 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700797
798 self.waitUntilSettled()
799 jobs = self.fake_jenkins.job_history
800 assert len(jobs) > 6
801 assert A.data['status'] == 'NEW'
802 assert B.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700803 assert A.reported == 2
804 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700805 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700806
807 def test_independent_queues(self):
808 "Test that changes end up in the right queues"
809 self.fake_jenkins.hold_jobs_in_build = True
810 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
811 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
812 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700813 A.addApproval('CRVW', 2)
814 B.addApproval('CRVW', 2)
815 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700816
817 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
818 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
819 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
820
821 jobs = self.fake_jenkins.all_jobs
822 self.waitUntilSettled()
823
824 # There should be one merge job at the head of each queue running
825 assert len(jobs) == 2
826 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700827 assert job_has_changes(jobs[0], A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700828 assert jobs[1].name == 'project1-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700829 assert job_has_changes(jobs[1], B)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700830
831 # Release the current merge jobs
832 self.fake_jenkins.fakeRelease('.*-merge')
833 self.waitUntilSettled()
834 # Release the merge job for project2 which is behind project1
835 self.fake_jenkins.fakeRelease('.*-merge')
836 self.waitUntilSettled()
837
838 # All the test jobs should be running:
839 # project1 (3) + project2 (3) + project (2) = 8
840 assert len(jobs) == 8
841
842 self.fake_jenkins.fakeRelease()
843 self.waitUntilSettled()
844 assert len(jobs) == 0
845
846 jobs = self.fake_jenkins.job_history
847 assert len(jobs) == 11
848 assert A.data['status'] == 'MERGED'
849 assert B.data['status'] == 'MERGED'
850 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700851 assert A.reported == 2
852 assert B.reported == 2
853 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700854 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -0700855
856 def test_failed_change_at_head(self):
857 "Test that if a change at the head fails, jobs behind it are canceled"
858 self.fake_jenkins.hold_jobs_in_build = True
859
860 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
861 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
862 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700863 A.addApproval('CRVW', 2)
864 B.addApproval('CRVW', 2)
865 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700866
James E. Blair4886cc12012-07-18 15:39:41 -0700867 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700868
869 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
870 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
871 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
872
873 self.waitUntilSettled()
874 jobs = self.fake_jenkins.all_jobs
875 finished_jobs = self.fake_jenkins.job_history
876
877 assert len(jobs) == 1
878 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700879 assert job_has_changes(jobs[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -0700880
881 self.fake_jenkins.fakeRelease('.*-merge')
882 self.waitUntilSettled()
883 self.fake_jenkins.fakeRelease('.*-merge')
884 self.waitUntilSettled()
885 self.fake_jenkins.fakeRelease('.*-merge')
886 self.waitUntilSettled()
887
888 assert len(jobs) == 6
889 assert jobs[0].name == 'project-test1'
890 assert jobs[1].name == 'project-test2'
891 assert jobs[2].name == 'project-test1'
892 assert jobs[3].name == 'project-test2'
893 assert jobs[4].name == 'project-test1'
894 assert jobs[5].name == 'project-test2'
895
896 jobs[0].release()
897 self.waitUntilSettled()
898
James E. Blairec590122012-08-22 15:19:31 -0700899 assert len(jobs) == 2 # project-test2, project-merge for B
James E. Blaird466dc42012-07-31 10:42:56 -0700900 assert self.countJobResults(finished_jobs, 'ABORTED') == 4
901
902 self.fake_jenkins.hold_jobs_in_build = False
903 self.fake_jenkins.fakeRelease()
904 self.waitUntilSettled()
905
906 assert len(jobs) == 0
907 assert len(finished_jobs) == 15
908 assert A.data['status'] == 'NEW'
909 assert B.data['status'] == 'MERGED'
910 assert C.data['status'] == 'MERGED'
911 assert A.reported == 2
912 assert B.reported == 2
913 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700914 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -0700915
916 def test_failed_change_at_head_with_queue(self):
917 "Test that if a change at the head fails, queued jobs are canceled"
918 self.fake_jenkins.hold_jobs_in_queue = True
919
920 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
921 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
922 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700923 A.addApproval('CRVW', 2)
924 B.addApproval('CRVW', 2)
925 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700926
James E. Blair4886cc12012-07-18 15:39:41 -0700927 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700928
929 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
930 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
931 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
932
933 self.waitUntilSettled()
934 jobs = self.fake_jenkins.all_jobs
935 finished_jobs = self.fake_jenkins.job_history
936 queue = self.fake_jenkins.queue
937
938 assert len(jobs) == 1
939 assert len(queue) == 1
940 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700941 assert job_has_changes(jobs[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -0700942
943 self.fake_jenkins.fakeRelease('.*-merge')
944 self.waitUntilSettled()
945 self.fake_jenkins.fakeRelease('.*-merge')
946 self.waitUntilSettled()
947 self.fake_jenkins.fakeRelease('.*-merge')
948 self.waitUntilSettled()
949
950 assert len(jobs) == 6
951 assert len(queue) == 6
952 assert jobs[0].name == 'project-test1'
953 assert jobs[1].name == 'project-test2'
954 assert jobs[2].name == 'project-test1'
955 assert jobs[3].name == 'project-test2'
956 assert jobs[4].name == 'project-test1'
957 assert jobs[5].name == 'project-test2'
958
959 jobs[0].release()
960 self.waitUntilSettled()
961
James E. Blairec590122012-08-22 15:19:31 -0700962 assert len(jobs) == 2 # project-test2, project-merge for B
963 assert len(queue) == 2
James E. Blaird466dc42012-07-31 10:42:56 -0700964 assert self.countJobResults(finished_jobs, 'ABORTED') == 0
965
966 self.fake_jenkins.hold_jobs_in_queue = False
967 self.fake_jenkins.fakeRelease()
968 self.waitUntilSettled()
969
970 assert len(jobs) == 0
971 assert len(finished_jobs) == 11
972 assert A.data['status'] == 'NEW'
973 assert B.data['status'] == 'MERGED'
974 assert C.data['status'] == 'MERGED'
975 assert A.reported == 2
976 assert B.reported == 2
977 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700978 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -0700979
980 def test_patch_order(self):
981 "Test that dependent patches are tested in the right order"
982 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
983 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
984 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
985 A.addApproval('CRVW', 2)
986 B.addApproval('CRVW', 2)
987 C.addApproval('CRVW', 2)
988
989 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
990 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
991 M2.setMerged()
992 M1.setMerged()
993
994 # C -> B -> A -> M1 -> M2
995 # M2 is here to make sure it is never queried. If it is, it
996 # means zuul is walking down the entire history of merged
997 # changes.
998
999 C.setDependsOn(B, 1)
1000 B.setDependsOn(A, 1)
1001 A.setDependsOn(M1, 1)
1002 M1.setDependsOn(M2, 1)
1003
1004 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1005
1006 self.waitUntilSettled()
1007
1008 assert A.data['status'] == 'NEW'
1009 assert B.data['status'] == 'NEW'
1010 assert C.data['status'] == 'NEW'
1011
1012 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1013 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1014
1015 self.waitUntilSettled()
1016 assert M2.queried == 0
1017 assert A.data['status'] == 'MERGED'
1018 assert B.data['status'] == 'MERGED'
1019 assert C.data['status'] == 'MERGED'
1020 assert A.reported == 2
1021 assert B.reported == 2
1022 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001023 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001024
1025 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -07001026 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -07001027 # TODO: move to test_gerrit (this is a unit test!)
1028 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair4aea70c2012-07-26 14:23:24 -07001029 a = self.sched.trigger.getChange(1, 2)
1030 mgr = self.sched.pipelines['gate'].manager
1031 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001032
1033 A.addApproval('CRVW', 2)
James E. Blair4aea70c2012-07-26 14:23:24 -07001034 a = self.sched.trigger.getChange(1, 2)
1035 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001036
1037 A.addApproval('APRV', 1)
James E. Blair4aea70c2012-07-26 14:23:24 -07001038 a = self.sched.trigger.getChange(1, 2)
1039 assert self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blaire0487072012-08-29 17:38:31 -07001040 self.assertEmptyQueues()
James E. Blair4886cc12012-07-18 15:39:41 -07001041
1042 def test_build_configuration(self):
1043 "Test that zuul merges the right commits for testing"
1044 self.fake_jenkins.hold_jobs_in_queue = True
1045 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1046 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1047 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1048 A.addApproval('CRVW', 2)
1049 B.addApproval('CRVW', 2)
1050 C.addApproval('CRVW', 2)
1051 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1052 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1053 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1054 self.waitUntilSettled()
1055
1056 jobs = self.fake_jenkins.all_jobs
1057
1058 self.fake_jenkins.fakeRelease('.*-merge')
1059 self.waitUntilSettled()
1060 self.fake_jenkins.fakeRelease('.*-merge')
1061 self.waitUntilSettled()
1062 self.fake_jenkins.fakeRelease('.*-merge')
1063 self.waitUntilSettled()
James E. Blair1dbd5082012-08-23 15:12:15 -07001064
James E. Blair4886cc12012-07-18 15:39:41 -07001065 ref = jobs[-1].parameters['ZUUL_REF']
1066 self.fake_jenkins.hold_jobs_in_queue = False
1067 self.fake_jenkins.fakeRelease()
James E. Blair973721f2012-08-15 10:19:43 -07001068 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -07001069
James E. Blair1dbd5082012-08-23 15:12:15 -07001070 path = os.path.join(GIT_ROOT, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -07001071 repo = git.Repo(path)
1072 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1073 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -07001074 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
1075 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001076 self.assertEmptyQueues()
James E. Blair973721f2012-08-15 10:19:43 -07001077
1078 def test_build_configuration_conflict(self):
1079 "Test that merge conflicts are handled"
1080 self.fake_jenkins.hold_jobs_in_queue = True
1081 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1082 A.addPatchset(['conflict'])
1083 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1084 B.addPatchset(['conflict'])
1085 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1086 A.addApproval('CRVW', 2)
1087 B.addApproval('CRVW', 2)
1088 C.addApproval('CRVW', 2)
1089 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1090 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1091 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1092 self.waitUntilSettled()
1093
1094 jobs = self.fake_jenkins.all_jobs
1095
1096 self.fake_jenkins.fakeRelease('.*-merge')
1097 self.waitUntilSettled()
1098 self.fake_jenkins.fakeRelease('.*-merge')
1099 self.waitUntilSettled()
1100 self.fake_jenkins.fakeRelease('.*-merge')
1101 self.waitUntilSettled()
1102 ref = jobs[-1].parameters['ZUUL_REF']
1103 self.fake_jenkins.hold_jobs_in_queue = False
1104 self.fake_jenkins.fakeRelease()
1105 self.waitUntilSettled()
1106
1107 assert A.data['status'] == 'MERGED'
1108 assert B.data['status'] == 'NEW'
1109 assert C.data['status'] == 'MERGED'
1110 assert A.reported == 2
1111 assert B.reported == 2
1112 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001113 self.assertEmptyQueues()
James E. Blairdaabed22012-08-15 15:38:57 -07001114
1115 def test_post(self):
1116 "Test that post jobs run"
1117 e = {"type": "ref-updated",
1118 "submitter": {"name": "User Name"},
1119 "refUpdate": {"oldRev":
1120 "90f173846e3af9154517b88543ffbd1691f31366",
1121 "newRev":
1122 "d479a0bfcb34da57a31adb2a595c0cf687812543",
1123 "refName": "master", "project": "org/project"}}
1124 self.fake_gerrit.addEvent(e)
1125 self.waitUntilSettled()
1126
1127 jobs = self.fake_jenkins.job_history
1128 job_names = [x['name'] for x in jobs]
1129 assert len(jobs) == 1
1130 assert 'project-post' in job_names
James E. Blaire0487072012-08-29 17:38:31 -07001131 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001132
1133 def test_build_configuration_branch(self):
1134 "Test that the right commits are on alternate branches"
1135 self.fake_jenkins.hold_jobs_in_queue = True
1136 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1137 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1138 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1139 A.addApproval('CRVW', 2)
1140 B.addApproval('CRVW', 2)
1141 C.addApproval('CRVW', 2)
1142 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1143 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1144 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1145 self.waitUntilSettled()
1146
1147 jobs = self.fake_jenkins.all_jobs
1148
1149 self.fake_jenkins.fakeRelease('.*-merge')
1150 self.waitUntilSettled()
1151 self.fake_jenkins.fakeRelease('.*-merge')
1152 self.waitUntilSettled()
1153 self.fake_jenkins.fakeRelease('.*-merge')
1154 self.waitUntilSettled()
1155 ref = jobs[-1].parameters['ZUUL_REF']
1156 self.fake_jenkins.hold_jobs_in_queue = False
1157 self.fake_jenkins.fakeRelease()
1158 self.waitUntilSettled()
1159
James E. Blair1dbd5082012-08-23 15:12:15 -07001160 path = os.path.join(GIT_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001161 repo = git.Repo(path)
1162 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1163 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001164 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
1165 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001166 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001167
1168 def test_build_configuration_branch_interaction(self):
1169 "Test that switching between branches works"
1170 self.test_build_configuration()
1171 self.test_build_configuration_branch()
1172 # C has been merged, undo that
James E. Blair1dbd5082012-08-23 15:12:15 -07001173 path = os.path.join(UPSTREAM_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001174 repo = git.Repo(path)
1175 repo.heads.master.commit = repo.commit('init')
1176 self.test_build_configuration()
James E. Blaire0487072012-08-29 17:38:31 -07001177 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001178
1179 def test_build_configuration_multi_branch(self):
1180 "Test that dependent changes on multiple branches are merged"
1181 self.fake_jenkins.hold_jobs_in_queue = True
1182 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1183 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1184 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1185 A.addApproval('CRVW', 2)
1186 B.addApproval('CRVW', 2)
1187 C.addApproval('CRVW', 2)
1188 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1189 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1190 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1191 self.waitUntilSettled()
1192
1193 jobs = self.fake_jenkins.all_jobs
1194
1195 self.fake_jenkins.fakeRelease('.*-merge')
1196 self.waitUntilSettled()
1197 ref_mp = jobs[-1].parameters['ZUUL_REF']
1198 self.fake_jenkins.fakeRelease('.*-merge')
1199 self.waitUntilSettled()
1200 self.fake_jenkins.fakeRelease('.*-merge')
1201 self.waitUntilSettled()
1202 ref_master = jobs[-1].parameters['ZUUL_REF']
1203 self.fake_jenkins.hold_jobs_in_queue = False
1204 self.fake_jenkins.fakeRelease()
1205 self.waitUntilSettled()
1206
James E. Blair1dbd5082012-08-23 15:12:15 -07001207 path = os.path.join(GIT_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001208 repo = git.Repo(path)
1209
1210 repo_messages = [c.message.strip()
1211 for c in repo.iter_commits(ref_master)]
1212 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001213 correct_messages = ['initial commit', 'A-1', 'C-1']
1214 assert repo_messages == correct_messages
1215
1216 repo_messages = [c.message.strip()
1217 for c in repo.iter_commits(ref_mp)]
1218 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001219 correct_messages = ['initial commit', 'mp commit', 'B-1']
1220 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001221 self.assertEmptyQueues()
James E. Blair7f71c802012-08-22 13:04:32 -07001222
1223 def test_one_job_project(self):
1224 "Test that queueing works with one job"
1225 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1226 'master', 'A')
1227 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1228 'master', 'B')
1229 A.addApproval('CRVW', 2)
1230 B.addApproval('CRVW', 2)
1231 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1232 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1233 self.waitUntilSettled()
1234
1235 jobs = self.fake_jenkins.all_jobs
1236 finished_jobs = self.fake_jenkins.job_history
James E. Blair7f71c802012-08-22 13:04:32 -07001237
1238 assert A.data['status'] == 'MERGED'
1239 assert A.reported == 2
1240 assert B.data['status'] == 'MERGED'
1241 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001242 self.assertEmptyQueues()
James E. Blaircaec0c52012-08-22 14:52:22 -07001243
1244 def test_dependent_changes_dequeue(self):
1245 "Test that dependent patches are not needlessly tested"
1246 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1247 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1248 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1249 A.addApproval('CRVW', 2)
1250 B.addApproval('CRVW', 2)
1251 C.addApproval('CRVW', 2)
1252
1253 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1254 M1.setMerged()
1255
1256 # C -> B -> A -> M1
1257
1258 C.setDependsOn(B, 1)
1259 B.setDependsOn(A, 1)
1260 A.setDependsOn(M1, 1)
1261
1262 self.fake_jenkins.fakeAddFailTest('project-merge', A)
1263
1264 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1265 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1266 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1267
1268 self.waitUntilSettled()
1269
1270 jobs = self.fake_jenkins.all_jobs
1271 finished_jobs = self.fake_jenkins.job_history
1272
James E. Blair127bc182012-08-28 15:55:15 -07001273 for x in jobs:
1274 print x
1275 for x in finished_jobs:
1276 print x
1277
James E. Blairec590122012-08-22 15:19:31 -07001278 assert A.data['status'] == 'NEW'
1279 assert A.reported == 2
1280 assert B.data['status'] == 'NEW'
1281 assert B.reported == 2
1282 assert C.data['status'] == 'NEW'
1283 assert C.reported == 2
1284 assert len(finished_jobs) == 1
James E. Blaire0487072012-08-29 17:38:31 -07001285 self.assertEmptyQueues()
James E. Blairec590122012-08-22 15:19:31 -07001286
1287 def test_head_is_dequeued_once(self):
1288 "Test that if a change at the head fails it is dequeud only once"
1289 # If it's dequeued more than once, we should see extra
1290 # aborted jobs.
1291 self.fake_jenkins.hold_jobs_in_build = True
1292
1293 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1294 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1295 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1296 A.addApproval('CRVW', 2)
1297 B.addApproval('CRVW', 2)
1298 C.addApproval('CRVW', 2)
1299
1300 self.fake_jenkins.fakeAddFailTest('project1-test1', A)
1301 self.fake_jenkins.fakeAddFailTest('project1-test2', A)
1302 self.fake_jenkins.fakeAddFailTest('project1-project2-integration', A)
1303
1304 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1305 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1306 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1307
1308 self.waitUntilSettled()
1309 jobs = self.fake_jenkins.all_jobs
1310 finished_jobs = self.fake_jenkins.job_history
1311
1312 assert len(jobs) == 1
1313 assert jobs[0].name == 'project1-merge'
1314 assert job_has_changes(jobs[0], A)
1315
1316 self.fake_jenkins.fakeRelease('.*-merge')
1317 self.waitUntilSettled()
1318 self.fake_jenkins.fakeRelease('.*-merge')
1319 self.waitUntilSettled()
1320 self.fake_jenkins.fakeRelease('.*-merge')
1321 self.waitUntilSettled()
1322
1323 assert len(jobs) == 9
1324 assert jobs[0].name == 'project1-test1'
1325 assert jobs[1].name == 'project1-test2'
1326 assert jobs[2].name == 'project1-project2-integration'
1327 assert jobs[3].name == 'project1-test1'
1328 assert jobs[4].name == 'project1-test2'
1329 assert jobs[5].name == 'project1-project2-integration'
1330 assert jobs[6].name == 'project1-test1'
1331 assert jobs[7].name == 'project1-test2'
1332 assert jobs[8].name == 'project1-project2-integration'
1333
1334 jobs[0].release()
1335 self.waitUntilSettled()
1336
1337 assert len(jobs) == 3 # test2, integration, merge for B
1338 assert self.countJobResults(finished_jobs, 'ABORTED') == 6
1339
1340 self.fake_jenkins.hold_jobs_in_build = False
1341 self.fake_jenkins.fakeRelease()
1342 self.waitUntilSettled()
1343
1344 assert len(jobs) == 0
1345 assert len(finished_jobs) == 20
James E. Blaircaec0c52012-08-22 14:52:22 -07001346
1347 assert A.data['status'] == 'NEW'
James E. Blairec590122012-08-22 15:19:31 -07001348 assert B.data['status'] == 'MERGED'
1349 assert C.data['status'] == 'MERGED'
1350 assert A.reported == 2
1351 assert B.reported == 2
1352 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001353 self.assertEmptyQueues()
James E. Blair4ec821f2012-08-23 15:28:28 -07001354
1355 def test_nonvoting_job(self):
1356 "Test that non-voting jobs don't vote."
1357 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1358 'master', 'A')
1359 A.addApproval('CRVW', 2)
1360 self.fake_jenkins.fakeAddFailTest('nonvoting-project-test2', A)
1361 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1362
1363 self.waitUntilSettled()
1364 jobs = self.fake_jenkins.all_jobs
1365 finished_jobs = self.fake_jenkins.job_history
1366
1367 assert A.data['status'] == 'MERGED'
1368 assert A.reported == 2
1369 assert finished_jobs[0]['result'] == 'SUCCESS'
1370 assert finished_jobs[1]['result'] == 'SUCCESS'
1371 assert finished_jobs[2]['result'] == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001372 self.assertEmptyQueues()
1373
1374 def test_check_queue_success(self):
1375 "Test successful check queue jobs."
1376 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1377 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1378
1379 self.waitUntilSettled()
1380 jobs = self.fake_jenkins.all_jobs
1381 finished_jobs = self.fake_jenkins.job_history
1382
1383 assert A.data['status'] == 'NEW'
1384 assert A.reported == 1
1385 assert finished_jobs[0]['result'] == 'SUCCESS'
1386 assert finished_jobs[1]['result'] == 'SUCCESS'
1387 assert finished_jobs[2]['result'] == 'SUCCESS'
1388 self.assertEmptyQueues()
1389
1390 def test_check_queue_failure(self):
1391 "Test failed check queue jobs."
1392 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1393 self.fake_jenkins.fakeAddFailTest('project-test2', A)
1394 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1395
1396 self.waitUntilSettled()
1397 jobs = self.fake_jenkins.all_jobs
1398 finished_jobs = self.fake_jenkins.job_history
1399
1400 assert A.data['status'] == 'NEW'
1401 assert A.reported == 1
1402 assert finished_jobs[0]['result'] == 'SUCCESS'
1403 assert finished_jobs[1]['result'] == 'SUCCESS'
1404 assert finished_jobs[2]['result'] == 'FAILURE'
1405 self.assertEmptyQueues()
James E. Blair127bc182012-08-28 15:55:15 -07001406
1407 def test_dependent_behind_dequeue(self):
1408 "test that dependent changes behind dequeued changes work"
1409 # This complicated test is a reproduction of a real life bug
1410 self.sched.reconfigure(self.config)
1411 self.fake_jenkins.hold_jobs_in_build = True
1412
1413 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1414 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1415 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1416 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1417 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1418 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1419 D.setDependsOn(C, 1)
1420 E.setDependsOn(D, 1)
1421 A.addApproval('CRVW', 2)
1422 B.addApproval('CRVW', 2)
1423 C.addApproval('CRVW', 2)
1424 D.addApproval('CRVW', 2)
1425 E.addApproval('CRVW', 2)
1426 F.addApproval('CRVW', 2)
1427
1428 A.fail_merge = True
1429 jobs = self.fake_jenkins.all_jobs
1430 finished_jobs = self.fake_jenkins.job_history
1431
1432 # Change object re-use in the gerrit trigger is hidden if
1433 # changes are added in quick succession; waiting makes it more
1434 # like real life.
1435 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1436 self.waitUntilSettled()
1437 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1438 self.waitUntilSettled()
1439
1440 self.fake_jenkins.fakeRelease('.*-merge')
1441 self.waitUntilSettled()
1442 self.fake_jenkins.fakeRelease('.*-merge')
1443 self.waitUntilSettled()
1444
1445 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1446 self.waitUntilSettled()
1447 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1448 self.waitUntilSettled()
1449 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1450 self.waitUntilSettled()
1451 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1452 self.waitUntilSettled()
1453
1454 self.fake_jenkins.fakeRelease('.*-merge')
1455 self.waitUntilSettled()
1456 self.fake_jenkins.fakeRelease('.*-merge')
1457 self.waitUntilSettled()
1458 self.fake_jenkins.fakeRelease('.*-merge')
1459 self.waitUntilSettled()
1460 self.fake_jenkins.fakeRelease('.*-merge')
1461 self.waitUntilSettled()
1462
1463 # all jobs running
1464 jobs[0].release()
1465 jobs[1].release()
1466 jobs[2].release()
1467 self.waitUntilSettled()
1468
1469 self.fake_jenkins.hold_jobs_in_build = False
1470 self.fake_jenkins.fakeRelease()
1471 self.waitUntilSettled()
1472
1473 for x in jobs:
1474 print x
1475 for x in finished_jobs:
1476 print x
1477 print self.sched.formatStatusHTML()
1478
1479 assert A.data['status'] == 'NEW'
1480 assert B.data['status'] == 'MERGED'
1481 assert C.data['status'] == 'MERGED'
1482 assert D.data['status'] == 'MERGED'
1483 assert E.data['status'] == 'MERGED'
1484 assert F.data['status'] == 'MERGED'
1485
1486 assert A.reported == 2
1487 assert B.reported == 2
1488 assert C.reported == 2
1489 assert D.reported == 2
1490 assert E.reported == 2
1491 assert F.reported == 2
1492
James E. Blair127bc182012-08-28 15:55:15 -07001493 assert self.countJobResults(finished_jobs, 'ABORTED') == 15
1494 assert len(finished_jobs) == 44
James E. Blaire0487072012-08-29 17:38:31 -07001495 self.assertEmptyQueues()
James E. Blair05fed602012-09-07 12:45:24 -07001496
1497 def test_merger_repack(self):
1498 "Test that the merger works after a repack"
1499 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1500 A.addApproval('CRVW', 2)
1501 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1502 self.waitUntilSettled()
1503 jobs = self.fake_jenkins.job_history
1504 job_names = [x['name'] for x in jobs]
1505 assert 'project-merge' in job_names
1506 assert 'project-test1' in job_names
1507 assert 'project-test2' in job_names
1508 assert jobs[0]['result'] == 'SUCCESS'
1509 assert jobs[1]['result'] == 'SUCCESS'
1510 assert jobs[2]['result'] == 'SUCCESS'
1511 assert A.data['status'] == 'MERGED'
1512 assert A.reported == 2
1513 self.assertEmptyQueues()
1514
1515 path = os.path.join(GIT_ROOT, "org/project")
1516 os.system('git --git-dir=%s/.git repack -afd' % path)
1517
1518 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1519 A.addApproval('CRVW', 2)
1520 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1521 self.waitUntilSettled()
1522 jobs = self.fake_jenkins.job_history
1523 job_names = [x['name'] for x in jobs]
1524 assert 'project-merge' in job_names
1525 assert 'project-test1' in job_names
1526 assert 'project-test2' in job_names
1527 assert jobs[0]['result'] == 'SUCCESS'
1528 assert jobs[1]['result'] == 'SUCCESS'
1529 assert jobs[2]['result'] == 'SUCCESS'
1530 assert A.data['status'] == 'MERGED'
1531 assert A.reported == 2
1532 self.assertEmptyQueues()