blob: 5fc221aefe1595b0f642291fa9e9a6a4dcd2f900 [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
James E. Blair4886f282012-11-15 09:27:33 -080032import string
James E. Blair4886cc12012-07-18 15:39:41 -070033import git
James E. Blairb0fcae42012-07-17 11:12:10 -070034
35import zuul
36import zuul.scheduler
37import zuul.launcher.jenkins
38import zuul.trigger.gerrit
39
40FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
41 'fixtures')
42CONFIG = ConfigParser.ConfigParser()
43CONFIG.read(os.path.join(FIXTURE_DIR, "zuul.conf"))
44
45CONFIG.set('zuul', 'layout_config',
46 os.path.join(FIXTURE_DIR, "layout.yaml"))
47
James E. Blair1dbd5082012-08-23 15:12:15 -070048TMP_ROOT = os.environ.get("ZUUL_TEST_ROOT", "/tmp")
49TEST_ROOT = os.path.join(TMP_ROOT, "zuul-test")
50UPSTREAM_ROOT = os.path.join(TEST_ROOT, "upstream")
51GIT_ROOT = os.path.join(TEST_ROOT, "git")
52
53CONFIG.set('zuul', 'git_dir', GIT_ROOT)
54
James E. Blairb0fcae42012-07-17 11:12:10 -070055logging.basicConfig(level=logging.DEBUG)
56
57
James E. Blair8cc15a82012-08-01 11:17:57 -070058def random_sha1():
59 return hashlib.sha1(str(random.random())).hexdigest()
60
61
James E. Blair4886cc12012-07-18 15:39:41 -070062class ChangeReference(git.Reference):
63 _common_path_default = "refs/changes"
64 _points_to_commits_only = True
65
66
67def init_repo(project):
68 parts = project.split('/')
James E. Blair1dbd5082012-08-23 15:12:15 -070069 path = os.path.join(UPSTREAM_ROOT, *parts[:-1])
James E. Blair4886cc12012-07-18 15:39:41 -070070 if not os.path.exists(path):
71 os.makedirs(path)
James E. Blair1dbd5082012-08-23 15:12:15 -070072 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -070073 repo = git.Repo.init(path)
74
75 fn = os.path.join(path, 'README')
76 f = open(fn, 'w')
77 f.write("test\n")
78 f.close()
79 repo.index.add([fn])
80 repo.index.commit('initial commit')
James E. Blairc6294a52012-08-17 10:19:48 -070081 master = repo.create_head('master')
James E. Blair4886cc12012-07-18 15:39:41 -070082 repo.create_tag('init')
83
James E. Blairc6294a52012-08-17 10:19:48 -070084 mp = repo.create_head('mp')
85 repo.head.reference = mp
86 f = open(fn, 'a')
87 f.write("test mp\n")
88 f.close()
89 repo.index.add([fn])
90 repo.index.commit('mp commit')
91
92 repo.head.reference = master
93 repo.head.reset(index=True, working_tree=True)
94 repo.git.clean('-x', '-f', '-d')
95
James E. Blair4886cc12012-07-18 15:39:41 -070096
James E. Blair4886f282012-11-15 09:27:33 -080097def add_fake_change_to_repo(project, branch, change_num, patchset, msg, fn,
98 large):
James E. Blair1dbd5082012-08-23 15:12:15 -070099 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -0700100 repo = git.Repo(path)
101 ref = ChangeReference.create(repo, '1/%s/%s' % (change_num,
102 patchset),
103 'refs/tags/init')
104 repo.head.reference = ref
105 repo.head.reset(index=True, working_tree=True)
106 repo.git.clean('-x', '-f', '-d')
107
James E. Blair1dbd5082012-08-23 15:12:15 -0700108 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886f282012-11-15 09:27:33 -0800109 if not large:
110 fn = os.path.join(path, fn)
111 f = open(fn, 'w')
112 f.write("test %s %s %s\n" % (branch, change_num, patchset))
113 f.close()
114 repo.index.add([fn])
115 else:
116 for fni in range(100):
117 fn = os.path.join(path, str(fni))
118 f = open(fn, 'w')
119 for ci in range(4096):
120 f.write(random.choice(string.printable))
121 f.close()
122 repo.index.add([fn])
123
James E. Blairdaabed22012-08-15 15:38:57 -0700124 return repo.index.commit(msg)
James E. Blair4886cc12012-07-18 15:39:41 -0700125
126
127def ref_has_change(ref, change):
James E. Blair1dbd5082012-08-23 15:12:15 -0700128 path = os.path.join(GIT_ROOT, change.project)
James E. Blair4886cc12012-07-18 15:39:41 -0700129 repo = git.Repo(path)
130 for commit in repo.iter_commits(ref):
131 if commit.message.strip() == ('%s-1' % change.subject):
132 return True
133 return False
134
135
136def job_has_changes(*args):
137 job = args[0]
138 commits = args[1:]
139 project = job.parameters['ZUUL_PROJECT']
James E. Blair1dbd5082012-08-23 15:12:15 -0700140 path = os.path.join(GIT_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -0700141 repo = git.Repo(path)
142 ref = job.parameters['ZUUL_REF']
James E. Blair81515ad2012-10-01 18:29:08 -0700143 sha = job.parameters['ZUUL_COMMIT']
James E. Blair4886cc12012-07-18 15:39:41 -0700144 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
James E. Blair81515ad2012-10-01 18:29:08 -0700145 repo_shas = [c.hexsha for c in repo.iter_commits(ref)]
James E. Blair4886cc12012-07-18 15:39:41 -0700146 commit_messages = ['%s-1' % commit.subject for commit in commits]
James E. Blair4886cc12012-07-18 15:39:41 -0700147 for msg in commit_messages:
148 if msg not in repo_messages:
149 return False
James E. Blair81515ad2012-10-01 18:29:08 -0700150 if repo_shas[0] != sha:
151 return False
James E. Blair4886cc12012-07-18 15:39:41 -0700152 return True
153
154
James E. Blairb0fcae42012-07-17 11:12:10 -0700155class FakeChange(object):
James E. Blair8c803f82012-07-31 16:25:42 -0700156 categories = {'APRV': ('Approved', -1, 1),
157 'CRVW': ('Code-Review', -2, 2),
158 'VRFY': ('Verified', -2, 2)}
James E. Blairb0fcae42012-07-17 11:12:10 -0700159
James E. Blair8cc15a82012-08-01 11:17:57 -0700160 def __init__(self, gerrit, number, project, branch, subject, status='NEW'):
161 self.gerrit = gerrit
James E. Blaird466dc42012-07-31 10:42:56 -0700162 self.reported = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700163 self.queried = 0
James E. Blairb0fcae42012-07-17 11:12:10 -0700164 self.patchsets = []
James E. Blairb0fcae42012-07-17 11:12:10 -0700165 self.number = number
166 self.project = project
167 self.branch = branch
168 self.subject = subject
169 self.latest_patchset = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700170 self.depends_on_change = None
171 self.needed_by_changes = []
James E. Blair127bc182012-08-28 15:55:15 -0700172 self.fail_merge = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700173 self.data = {
174 'branch': branch,
175 'comments': [],
176 'commitMessage': subject,
177 'createdOn': time.time(),
James E. Blair8cc15a82012-08-01 11:17:57 -0700178 'id': 'I' + random_sha1(),
James E. Blairb0fcae42012-07-17 11:12:10 -0700179 'lastUpdated': time.time(),
180 'number': str(number),
181 'open': True,
182 'owner': {'email': 'user@example.com',
183 'name': 'User Name',
184 'username': 'username'},
185 'patchSets': self.patchsets,
186 'project': project,
187 'status': status,
188 'subject': subject,
James E. Blair8c803f82012-07-31 16:25:42 -0700189 'submitRecords': [],
James E. Blairb0fcae42012-07-17 11:12:10 -0700190 'url': 'https://hostname/%s' % number}
191
192 self.addPatchset()
James E. Blair8c803f82012-07-31 16:25:42 -0700193 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700194
James E. Blair70c71582013-03-06 08:50:50 -0800195 def addPatchset(self, files=[], large=False):
James E. Blairb0fcae42012-07-17 11:12:10 -0700196 self.latest_patchset += 1
James E. Blairdaabed22012-08-15 15:38:57 -0700197 if files:
198 fn = files[0]
199 else:
200 fn = '%s-%s' % (self.branch, self.number)
201 msg = self.subject + '-' + str(self.latest_patchset)
202 c = add_fake_change_to_repo(self.project, self.branch,
203 self.number, self.latest_patchset,
James E. Blair4886f282012-11-15 09:27:33 -0800204 msg, fn, large)
James E. Blair70c71582013-03-06 08:50:50 -0800205 ps_files = [{'file': '/COMMIT_MSG',
206 'type': 'ADDED'},
207 {'file': 'README',
208 'type': 'MODIFIED'}]
209 for f in files:
210 ps_files.append({'file': f, 'type': 'ADDED'})
James E. Blairb0fcae42012-07-17 11:12:10 -0700211 d = {'approvals': [],
212 'createdOn': time.time(),
James E. Blair70c71582013-03-06 08:50:50 -0800213 'files': ps_files,
James E. Blair8c803f82012-07-31 16:25:42 -0700214 'number': str(self.latest_patchset),
James E. Blairb0fcae42012-07-17 11:12:10 -0700215 'ref': 'refs/changes/1/%s/%s' % (self.number,
216 self.latest_patchset),
James E. Blairdaabed22012-08-15 15:38:57 -0700217 'revision': c.hexsha,
James E. Blairb0fcae42012-07-17 11:12:10 -0700218 'uploader': {'email': 'user@example.com',
219 'name': 'User name',
220 'username': 'user'}}
221 self.data['currentPatchSet'] = d
222 self.patchsets.append(d)
James E. Blair8c803f82012-07-31 16:25:42 -0700223 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700224
James E. Blaire0487072012-08-29 17:38:31 -0700225 def getPatchsetCreatedEvent(self, patchset):
226 event = {"type": "patchset-created",
227 "change": {"project": self.project,
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800228 "branch": self.branch,
229 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
230 "number": str(self.number),
231 "subject": self.subject,
232 "owner": {"name": "User Name"},
233 "url": "https://hostname/3"},
James E. Blaire0487072012-08-29 17:38:31 -0700234 "patchSet": self.patchsets[patchset - 1],
235 "uploader": {"name": "User Name"}}
236 return event
237
James E. Blairb0fcae42012-07-17 11:12:10 -0700238 def addApproval(self, category, value):
James E. Blair8c803f82012-07-31 16:25:42 -0700239 approval = {'description': self.categories[category][0],
240 'type': category,
241 'value': str(value)}
242 self.patchsets[-1]['approvals'].append(approval)
243 event = {'approvals': [approval],
James E. Blairb0fcae42012-07-17 11:12:10 -0700244 'author': {'email': 'user@example.com',
245 'name': 'User Name',
246 'username': 'username'},
247 'change': {'branch': self.branch,
248 'id': 'Iaa69c46accf97d0598111724a38250ae76a22c87',
249 'number': str(self.number),
250 'owner': {'email': 'user@example.com',
251 'name': 'User Name',
252 'username': 'username'},
253 'project': self.project,
254 'subject': self.subject,
255 'topic': 'master',
256 'url': 'https://hostname/459'},
257 'comment': '',
258 'patchSet': self.patchsets[-1],
259 'type': 'comment-added'}
James E. Blair8c803f82012-07-31 16:25:42 -0700260 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700261 return json.loads(json.dumps(event))
262
James E. Blair8c803f82012-07-31 16:25:42 -0700263 def getSubmitRecords(self):
264 status = {}
265 for cat in self.categories.keys():
266 status[cat] = 0
267
268 for a in self.patchsets[-1]['approvals']:
269 cur = status[a['type']]
270 cat_min, cat_max = self.categories[a['type']][1:]
271 new = int(a['value'])
272 if new == cat_min:
273 cur = new
274 elif abs(new) > abs(cur):
275 cur = new
276 status[a['type']] = cur
277
278 labels = []
279 ok = True
280 for typ, cat in self.categories.items():
281 cur = status[typ]
282 cat_min, cat_max = cat[1:]
283 if cur == cat_min:
284 value = 'REJECT'
285 ok = False
286 elif cur == cat_max:
287 value = 'OK'
288 else:
289 value = 'NEED'
290 ok = False
291 labels.append({'label': cat[0], 'status': value})
292 if ok:
293 return [{'status': 'OK'}]
294 return [{'status': 'NOT_READY',
295 'labels': labels}]
296
297 def setDependsOn(self, other, patchset):
298 self.depends_on_change = other
299 d = {'id': other.data['id'],
300 'number': other.data['number'],
301 'ref': other.patchsets[patchset - 1]['ref']
302 }
303 self.data['dependsOn'] = [d]
304
305 other.needed_by_changes.append(self)
306 needed = other.data.get('neededBy', [])
307 d = {'id': self.data['id'],
308 'number': self.data['number'],
309 'ref': self.patchsets[patchset - 1]['ref'],
310 'revision': self.patchsets[patchset - 1]['revision']
311 }
312 needed.append(d)
313 other.data['neededBy'] = needed
314
James E. Blairb0fcae42012-07-17 11:12:10 -0700315 def query(self):
James E. Blair8c803f82012-07-31 16:25:42 -0700316 self.queried += 1
317 d = self.data.get('dependsOn')
318 if d:
319 d = d[0]
320 if (self.depends_on_change.patchsets[-1]['ref'] == d['ref']):
321 d['isCurrentPatchSet'] = True
322 else:
323 d['isCurrentPatchSet'] = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700324 return json.loads(json.dumps(self.data))
325
326 def setMerged(self):
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800327 if (self.depends_on_change and
328 self.depends_on_change.data['status'] != 'MERGED'):
James E. Blaircaec0c52012-08-22 14:52:22 -0700329 return
James E. Blair127bc182012-08-28 15:55:15 -0700330 if self.fail_merge:
331 return
James E. Blairb0fcae42012-07-17 11:12:10 -0700332 self.data['status'] = 'MERGED'
333 self.open = False
James E. Blairdaabed22012-08-15 15:38:57 -0700334
James E. Blair1dbd5082012-08-23 15:12:15 -0700335 path = os.path.join(UPSTREAM_ROOT, self.project)
James E. Blairdaabed22012-08-15 15:38:57 -0700336 repo = git.Repo(path)
337 repo.heads[self.branch].commit = \
338 repo.commit(self.patchsets[-1]['revision'])
James E. Blairb0fcae42012-07-17 11:12:10 -0700339
James E. Blaird466dc42012-07-31 10:42:56 -0700340 def setReported(self):
341 self.reported += 1
342
James E. Blairb0fcae42012-07-17 11:12:10 -0700343
344class FakeGerrit(object):
345 def __init__(self, *args, **kw):
346 self.event_queue = Queue.Queue()
347 self.fixture_dir = os.path.join(FIXTURE_DIR, 'gerrit')
348 self.change_number = 0
349 self.changes = {}
350
351 def addFakeChange(self, project, branch, subject):
352 self.change_number += 1
James E. Blair8cc15a82012-08-01 11:17:57 -0700353 c = FakeChange(self, self.change_number, project, branch, subject)
James E. Blairb0fcae42012-07-17 11:12:10 -0700354 self.changes[self.change_number] = c
355 return c
356
357 def addEvent(self, data):
358 return self.event_queue.put(data)
359
360 def getEvent(self):
361 return self.event_queue.get()
362
363 def eventDone(self):
364 self.event_queue.task_done()
365
366 def review(self, project, changeid, message, action):
James E. Blaird466dc42012-07-31 10:42:56 -0700367 number, ps = changeid.split(',')
368 change = self.changes[int(number)]
James E. Blairb0fcae42012-07-17 11:12:10 -0700369 if 'submit' in action:
James E. Blairb0fcae42012-07-17 11:12:10 -0700370 change.setMerged()
James E. Blaird466dc42012-07-31 10:42:56 -0700371 if message:
372 change.setReported()
James E. Blairb0fcae42012-07-17 11:12:10 -0700373
374 def query(self, number):
375 change = self.changes[int(number)]
376 return change.query()
377
378 def startWatching(self, *args, **kw):
379 pass
380
381
382class FakeJenkinsEvent(object):
383 def __init__(self, name, number, parameters, phase, status=None):
Zhongyue Luo5d556072012-09-21 02:00:47 +0900384 data = {
385 'build': {
386 'full_url': 'https://server/job/%s/%s/' % (name, number),
387 'number': number,
388 'parameters': parameters,
389 'phase': phase,
390 'url': 'job/%s/%s/' % (name, number),
391 },
392 'name': name,
393 'url': 'job/%s/' % name,
394 }
James E. Blairb0fcae42012-07-17 11:12:10 -0700395 if status:
396 data['build']['status'] = status
397 self.body = json.dumps(data)
398
399
400class FakeJenkinsJob(threading.Thread):
401 log = logging.getLogger("zuul.test")
402
403 def __init__(self, jenkins, callback, name, number, parameters):
404 threading.Thread.__init__(self)
405 self.jenkins = jenkins
406 self.callback = callback
407 self.name = name
408 self.number = number
409 self.parameters = parameters
410 self.wait_condition = threading.Condition()
411 self.waiting = False
James E. Blaird466dc42012-07-31 10:42:56 -0700412 self.aborted = False
413 self.canceled = False
414 self.created = time.time()
James E. Blairb0fcae42012-07-17 11:12:10 -0700415
416 def release(self):
417 self.wait_condition.acquire()
418 self.wait_condition.notify()
419 self.waiting = False
420 self.log.debug("Job %s released" % (self.parameters['UUID']))
421 self.wait_condition.release()
422
423 def isWaiting(self):
424 self.wait_condition.acquire()
425 if self.waiting:
426 ret = True
427 else:
428 ret = False
429 self.wait_condition.release()
430 return ret
431
432 def _wait(self):
433 self.wait_condition.acquire()
434 self.waiting = True
435 self.log.debug("Job %s waiting" % (self.parameters['UUID']))
436 self.wait_condition.wait()
437 self.wait_condition.release()
438
439 def run(self):
440 self.jenkins.fakeEnqueue(self)
441 if self.jenkins.hold_jobs_in_queue:
442 self._wait()
443 self.jenkins.fakeDequeue(self)
James E. Blaird466dc42012-07-31 10:42:56 -0700444 if self.canceled:
445 self.jenkins.all_jobs.remove(self)
446 return
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800447 self.callback.jenkins_endpoint(FakeJenkinsEvent(self.name,
448 self.number,
449 self.parameters,
450 'STARTED'))
James E. Blairb0fcae42012-07-17 11:12:10 -0700451 if self.jenkins.hold_jobs_in_build:
452 self._wait()
453 self.log.debug("Job %s continuing" % (self.parameters['UUID']))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700454
455 result = 'SUCCESS'
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800456 if (('ZUUL_REF' in self.parameters) and
457 self.jenkins.fakeShouldFailTest(self.name,
458 self.parameters['ZUUL_REF'])):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700459 result = 'FAILURE'
James E. Blaird466dc42012-07-31 10:42:56 -0700460 if self.aborted:
461 result = 'ABORTED'
James E. Blairb02a3bb2012-07-30 17:49:55 -0700462
James E. Blair0018a6c2013-02-27 14:11:45 -0800463 changes = None
464 if 'ZUUL_CHANGE_IDS' in self.parameters:
465 changes = self.parameters['ZUUL_CHANGE_IDS']
466
James E. Blairb0fcae42012-07-17 11:12:10 -0700467 self.jenkins.fakeAddHistory(name=self.name, number=self.number,
James E. Blair0018a6c2013-02-27 14:11:45 -0800468 result=result, changes=changes)
James E. Blairff791972013-01-09 11:45:43 -0800469 self.jenkins.lock.acquire()
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800470 self.callback.jenkins_endpoint(FakeJenkinsEvent(self.name,
471 self.number,
472 self.parameters,
473 'COMPLETED',
474 result))
475 self.callback.jenkins_endpoint(FakeJenkinsEvent(self.name,
476 self.number,
477 self.parameters,
478 'FINISHED',
479 result))
James E. Blairb0fcae42012-07-17 11:12:10 -0700480 self.jenkins.all_jobs.remove(self)
James E. Blairff791972013-01-09 11:45:43 -0800481 self.jenkins.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700482
483
484class FakeJenkins(object):
485 log = logging.getLogger("zuul.test")
486
487 def __init__(self, *args, **kw):
488 self.queue = []
489 self.all_jobs = []
490 self.job_counter = {}
James E. Blaird466dc42012-07-31 10:42:56 -0700491 self.queue_counter = 0
James E. Blairb0fcae42012-07-17 11:12:10 -0700492 self.job_history = []
493 self.hold_jobs_in_queue = False
494 self.hold_jobs_in_build = False
James E. Blairb02a3bb2012-07-30 17:49:55 -0700495 self.fail_tests = {}
James E. Blair7ee88a22012-09-12 18:59:31 +0200496 self.nonexistent_jobs = []
James E. Blairff791972013-01-09 11:45:43 -0800497 self.lock = threading.Lock()
James E. Blairb0fcae42012-07-17 11:12:10 -0700498
499 def fakeEnqueue(self, job):
500 self.queue.append(job)
501
502 def fakeDequeue(self, job):
503 self.queue.remove(job)
504
James E. Blair0018a6c2013-02-27 14:11:45 -0800505 class FakeJobHistory(object):
506 def __init__(self, **kw):
507 self.__dict__.update(kw)
508
509 def __repr__(self):
510 return ("<Completed job, result: %s name: %s #%s changes: %s>" %
511 (self.result, self.name, self.number, self.changes))
512
James E. Blairb0fcae42012-07-17 11:12:10 -0700513 def fakeAddHistory(self, **kw):
James E. Blair0018a6c2013-02-27 14:11:45 -0800514 self.job_history.append(self.FakeJobHistory(**kw))
James E. Blairb0fcae42012-07-17 11:12:10 -0700515
516 def fakeRelease(self, regex=None):
517 all_jobs = self.all_jobs[:]
518 self.log.debug("releasing jobs %s (%s)" % (regex, len(self.all_jobs)))
519 for job in all_jobs:
520 if not regex or re.match(regex, job.name):
521 self.log.debug("releasing job %s" % (job.parameters['UUID']))
522 job.release()
523 else:
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800524 self.log.debug("not releasing job %s" %
525 (job.parameters['UUID']))
James E. Blairb0fcae42012-07-17 11:12:10 -0700526 self.log.debug("done releasing jobs %s (%s)" % (regex,
527 len(self.all_jobs)))
528
529 def fakeAllWaiting(self, regex=None):
James E. Blair4aa1ad62012-10-05 12:39:26 -0700530 all_jobs = self.all_jobs[:] + self.queue[:]
James E. Blairb0fcae42012-07-17 11:12:10 -0700531 for job in all_jobs:
532 self.log.debug("job %s %s" % (job.parameters['UUID'],
533 job.isWaiting()))
534 if not job.isWaiting():
535 return False
536 return True
537
James E. Blairb02a3bb2012-07-30 17:49:55 -0700538 def fakeAddFailTest(self, name, change):
539 l = self.fail_tests.get(name, [])
540 l.append(change)
541 self.fail_tests[name] = l
542
James E. Blair4886cc12012-07-18 15:39:41 -0700543 def fakeShouldFailTest(self, name, ref):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700544 l = self.fail_tests.get(name, [])
545 for change in l:
James E. Blair4886cc12012-07-18 15:39:41 -0700546 if ref_has_change(ref, change):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700547 return True
548 return False
549
James E. Blairb0fcae42012-07-17 11:12:10 -0700550 def build_job(self, name, parameters):
James E. Blair7ee88a22012-09-12 18:59:31 +0200551 if name in self.nonexistent_jobs:
552 raise Exception("Job does not exist")
James E. Blairb0fcae42012-07-17 11:12:10 -0700553 count = self.job_counter.get(name, 0)
554 count += 1
555 self.job_counter[name] = count
James E. Blaird466dc42012-07-31 10:42:56 -0700556
557 queue_count = self.queue_counter
558 self.queue_counter += 1
James E. Blairb0fcae42012-07-17 11:12:10 -0700559 job = FakeJenkinsJob(self, self.callback, name, count, parameters)
James E. Blaird466dc42012-07-31 10:42:56 -0700560 job.queue_id = queue_count
561
James E. Blairb0fcae42012-07-17 11:12:10 -0700562 self.all_jobs.append(job)
563 job.start()
564
James E. Blaird466dc42012-07-31 10:42:56 -0700565 def stop_build(self, name, number):
566 for job in self.all_jobs:
567 if job.name == name and job.number == number:
568 job.aborted = True
569 job.release()
570 return
571
572 def cancel_queue(self, id):
573 for job in self.queue:
574 if job.queue_id == id:
575 job.canceled = True
576 job.release()
577 return
578
579 def get_queue_info(self):
580 items = []
James E. Blair1490eba2013-03-06 19:14:00 -0800581 for job in self.queue[:]:
582 self.log.debug("Queue info: %s %s" % (job.name,
583 job.parameters['UUID']))
James E. Blaird466dc42012-07-31 10:42:56 -0700584 paramstr = ''
585 paramlst = []
586 d = {'actions': [{'parameters': paramlst},
587 {'causes': [{'shortDescription':
588 'Started by user Jenkins',
589 'userId': 'jenkins',
590 'userName': 'Jenkins'}]}],
591 'blocked': False,
592 'buildable': True,
593 'buildableStartMilliseconds': (job.created * 1000) + 5,
594 'id': job.queue_id,
595 'inQueueSince': (job.created * 1000),
596 'params': paramstr,
597 'stuck': False,
598 'task': {'color': 'blue',
599 'name': job.name,
600 'url': 'https://server/job/%s/' % job.name},
601 'why': 'Waiting for next available executor'}
602 for k, v in job.parameters.items():
603 paramstr += "\n(StringParameterValue) %s='%s'" % (k, v)
604 pd = {'name': k, 'value': v}
605 paramlst.append(pd)
606 items.append(d)
607 return items
608
James E. Blairb0fcae42012-07-17 11:12:10 -0700609 def set_build_description(self, *args, **kw):
610 pass
611
612
613class FakeJenkinsCallback(zuul.launcher.jenkins.JenkinsCallback):
614 def start(self):
615 pass
616
617
James E. Blair8cc15a82012-08-01 11:17:57 -0700618class FakeURLOpener(object):
619 def __init__(self, fake_gerrit, url):
620 self.fake_gerrit = fake_gerrit
621 self.url = url
622
623 def read(self):
624 res = urlparse.urlparse(self.url)
625 path = res.path
626 project = '/'.join(path.split('/')[2:-2])
James E. Blair35956c52012-09-17 22:13:36 +0200627 ret = '001e# service=git-upload-pack\n'
628 ret += ('000000a31270149696713ba7e06f1beb760f20d359c4abed HEAD\x00'
629 'multi_ack thin-pack side-band side-band-64k ofs-delta '
630 'shallow no-progress include-tag multi_ack_detailed no-done\n')
James E. Blair1dbd5082012-08-23 15:12:15 -0700631 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blairdaabed22012-08-15 15:38:57 -0700632 repo = git.Repo(path)
633 for ref in repo.refs:
James E. Blair35956c52012-09-17 22:13:36 +0200634 r = ref.object.hexsha + ' ' + ref.path + '\n'
635 ret += '%04x%s' % (len(r) + 4, r)
636 ret += '0000'
James E. Blair8cc15a82012-08-01 11:17:57 -0700637 return ret
638
639
James E. Blair4886cc12012-07-18 15:39:41 -0700640class FakeGerritTrigger(zuul.trigger.gerrit.Gerrit):
641 def getGitUrl(self, project):
James E. Blair1dbd5082012-08-23 15:12:15 -0700642 return os.path.join(UPSTREAM_ROOT, project.name)
James E. Blair4886cc12012-07-18 15:39:41 -0700643
644
James E. Blairb0fcae42012-07-17 11:12:10 -0700645class testScheduler(unittest.TestCase):
646 log = logging.getLogger("zuul.test")
647
648 def setUp(self):
James E. Blair1dbd5082012-08-23 15:12:15 -0700649 if os.path.exists(TEST_ROOT):
650 shutil.rmtree(TEST_ROOT)
651 os.makedirs(TEST_ROOT)
652 os.makedirs(UPSTREAM_ROOT)
653 os.makedirs(GIT_ROOT)
James E. Blair4886cc12012-07-18 15:39:41 -0700654
655 # For each project in config:
656 init_repo("org/project")
657 init_repo("org/project1")
658 init_repo("org/project2")
James E. Blair127bc182012-08-28 15:55:15 -0700659 init_repo("org/project3")
James E. Blair7f71c802012-08-22 13:04:32 -0700660 init_repo("org/one-job-project")
James E. Blair4ec821f2012-08-23 15:28:28 -0700661 init_repo("org/nonvoting-project")
James E. Blairb0fcae42012-07-17 11:12:10 -0700662 self.config = CONFIG
663 self.sched = zuul.scheduler.Scheduler()
664
665 def jenkinsFactory(*args, **kw):
666 self.fake_jenkins = FakeJenkins()
667 return self.fake_jenkins
668
669 def jenkinsCallbackFactory(*args, **kw):
670 self.fake_jenkins_callback = FakeJenkinsCallback(*args, **kw)
671 return self.fake_jenkins_callback
672
James E. Blair8cc15a82012-08-01 11:17:57 -0700673 def URLOpenerFactory(*args, **kw):
674 args = [self.fake_gerrit] + list(args)
675 return FakeURLOpener(*args, **kw)
676
James E. Blairb0fcae42012-07-17 11:12:10 -0700677 zuul.launcher.jenkins.ExtendedJenkins = jenkinsFactory
678 zuul.launcher.jenkins.JenkinsCallback = jenkinsCallbackFactory
James E. Blair8cc15a82012-08-01 11:17:57 -0700679 urllib2.urlopen = URLOpenerFactory
James E. Blairb0fcae42012-07-17 11:12:10 -0700680 self.jenkins = zuul.launcher.jenkins.Jenkins(self.config, self.sched)
681 self.fake_jenkins.callback = self.fake_jenkins_callback
682
683 zuul.lib.gerrit.Gerrit = FakeGerrit
684
James E. Blair4886cc12012-07-18 15:39:41 -0700685 self.gerrit = FakeGerritTrigger(self.config, self.sched)
James E. Blair8cc15a82012-08-01 11:17:57 -0700686 self.gerrit.replication_timeout = 1.5
687 self.gerrit.replication_retry_interval = 0.5
James E. Blairb0fcae42012-07-17 11:12:10 -0700688 self.fake_gerrit = self.gerrit.gerrit
689
690 self.sched.setLauncher(self.jenkins)
691 self.sched.setTrigger(self.gerrit)
692
693 self.sched.start()
694 self.sched.reconfigure(self.config)
695 self.sched.resume()
696
697 def tearDown(self):
698 self.jenkins.stop()
699 self.gerrit.stop()
700 self.sched.stop()
701 self.sched.join()
James E. Blair1dbd5082012-08-23 15:12:15 -0700702 #shutil.rmtree(TEST_ROOT)
James E. Blairb0fcae42012-07-17 11:12:10 -0700703
704 def waitUntilSettled(self):
705 self.log.debug("Waiting until settled...")
706 start = time.time()
707 while True:
708 if time.time() - start > 10:
709 print 'queue status:',
710 print self.sched.trigger_event_queue.empty(),
711 print self.sched.result_event_queue.empty(),
712 print self.fake_gerrit.event_queue.empty(),
713 raise Exception("Timeout waiting for Zuul to settle")
James E. Blairff791972013-01-09 11:45:43 -0800714 # Make sure our fake jenkins doesn't end any jobs
715 # (and therefore, emit events) while we're checking
716 self.fake_jenkins.lock.acquire()
717 # Join ensures that the queue is empty _and_ events have been
718 # processed
James E. Blairb0fcae42012-07-17 11:12:10 -0700719 self.fake_gerrit.event_queue.join()
James E. Blairff791972013-01-09 11:45:43 -0800720 self.sched.trigger_event_queue.join()
721 self.sched.result_event_queue.join()
James E. Blairb0fcae42012-07-17 11:12:10 -0700722 if (self.sched.trigger_event_queue.empty() and
723 self.sched.result_event_queue.empty() and
724 self.fake_gerrit.event_queue.empty() and
725 self.fake_jenkins.fakeAllWaiting()):
James E. Blairff791972013-01-09 11:45:43 -0800726 self.fake_jenkins.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700727 self.log.debug("...settled.")
728 return
James E. Blairff791972013-01-09 11:45:43 -0800729 self.fake_jenkins.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700730 self.sched.wake_event.wait(0.1)
731
James E. Blaird466dc42012-07-31 10:42:56 -0700732 def countJobResults(self, jobs, result):
James E. Blair0018a6c2013-02-27 14:11:45 -0800733 jobs = filter(lambda x: x.result == result, jobs)
James E. Blaird466dc42012-07-31 10:42:56 -0700734 return len(jobs)
735
James E. Blaire0487072012-08-29 17:38:31 -0700736 def assertEmptyQueues(self):
737 # Make sure there are no orphaned jobs
738 for pipeline in self.sched.pipelines.values():
739 for queue in pipeline.queues:
740 if len(queue.queue) != 0:
James E. Blairf62d4282012-12-31 17:01:50 -0800741 print 'pipeline %s queue %s contents %s' % (
742 pipeline.name, queue.name, queue.queue)
James E. Blaire0487072012-08-29 17:38:31 -0700743 assert len(queue.queue) == 0
744 if len(queue.severed_heads) != 0:
745 print 'heads', queue.severed_heads
746 assert len(queue.severed_heads) == 0
747
James E. Blairb0fcae42012-07-17 11:12:10 -0700748 def test_jobs_launched(self):
749 "Test that jobs are launched and a change is merged"
750 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -0700751 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700752 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
753 self.waitUntilSettled()
754 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -0800755 job_names = [x.name for x in jobs]
James E. Blairb0fcae42012-07-17 11:12:10 -0700756 assert 'project-merge' in job_names
757 assert 'project-test1' in job_names
758 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -0800759 assert jobs[0].result == 'SUCCESS'
760 assert jobs[1].result == 'SUCCESS'
761 assert jobs[2].result == 'SUCCESS'
James E. Blairb0fcae42012-07-17 11:12:10 -0700762 assert A.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700763 assert A.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700764 self.assertEmptyQueues()
James E. Blairb0fcae42012-07-17 11:12:10 -0700765
766 def test_parallel_changes(self):
767 "Test that changes are tested in parallel and merged in series"
768 self.fake_jenkins.hold_jobs_in_build = True
769 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
770 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
771 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700772 A.addApproval('CRVW', 2)
773 B.addApproval('CRVW', 2)
774 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700775
776 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
777 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
778 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
779
780 self.waitUntilSettled()
781 jobs = self.fake_jenkins.all_jobs
782 assert len(jobs) == 1
783 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700784 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700785
786 self.fake_jenkins.fakeRelease('.*-merge')
787 self.waitUntilSettled()
788 assert len(jobs) == 3
789 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700790 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700791 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700792 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700793 assert jobs[2].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700794 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700795
796 self.fake_jenkins.fakeRelease('.*-merge')
797 self.waitUntilSettled()
798 assert len(jobs) == 5
799 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700800 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700801 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700802 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700803
804 assert jobs[2].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700805 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700806 assert jobs[3].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700807 assert job_has_changes(jobs[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700808
809 assert jobs[4].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700810 assert job_has_changes(jobs[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700811
812 self.fake_jenkins.fakeRelease('.*-merge')
813 self.waitUntilSettled()
814 assert len(jobs) == 6
815 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700816 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700817 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700818 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700819
820 assert jobs[2].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700821 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700822 assert jobs[3].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700823 assert job_has_changes(jobs[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700824
825 assert jobs[4].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700826 assert job_has_changes(jobs[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700827 assert jobs[5].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700828 assert job_has_changes(jobs[5], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700829
830 self.fake_jenkins.hold_jobs_in_build = False
831 self.fake_jenkins.fakeRelease()
832 self.waitUntilSettled()
833 assert len(jobs) == 0
834
835 jobs = self.fake_jenkins.job_history
836 assert len(jobs) == 9
837 assert A.data['status'] == 'MERGED'
838 assert B.data['status'] == 'MERGED'
839 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700840 assert A.reported == 2
841 assert B.reported == 2
842 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700843 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700844
845 def test_failed_changes(self):
846 "Test that a change behind a failed change is retested"
847 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
848 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -0700849 A.addApproval('CRVW', 2)
850 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700851
852 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
853 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
854
James E. Blair4886cc12012-07-18 15:39:41 -0700855 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700856
857 self.waitUntilSettled()
858 jobs = self.fake_jenkins.job_history
859 assert len(jobs) > 6
860 assert A.data['status'] == 'NEW'
861 assert B.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700862 assert A.reported == 2
863 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700864 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700865
866 def test_independent_queues(self):
867 "Test that changes end up in the right queues"
868 self.fake_jenkins.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +0900869 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700870 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
871 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700872 A.addApproval('CRVW', 2)
873 B.addApproval('CRVW', 2)
874 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700875
876 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
877 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
878 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
879
880 jobs = self.fake_jenkins.all_jobs
881 self.waitUntilSettled()
882
883 # There should be one merge job at the head of each queue running
884 assert len(jobs) == 2
885 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700886 assert job_has_changes(jobs[0], A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700887 assert jobs[1].name == 'project1-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700888 assert job_has_changes(jobs[1], B)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700889
890 # Release the current merge jobs
891 self.fake_jenkins.fakeRelease('.*-merge')
892 self.waitUntilSettled()
893 # Release the merge job for project2 which is behind project1
894 self.fake_jenkins.fakeRelease('.*-merge')
895 self.waitUntilSettled()
896
897 # All the test jobs should be running:
898 # project1 (3) + project2 (3) + project (2) = 8
899 assert len(jobs) == 8
900
901 self.fake_jenkins.fakeRelease()
902 self.waitUntilSettled()
903 assert len(jobs) == 0
904
905 jobs = self.fake_jenkins.job_history
906 assert len(jobs) == 11
907 assert A.data['status'] == 'MERGED'
908 assert B.data['status'] == 'MERGED'
909 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700910 assert A.reported == 2
911 assert B.reported == 2
912 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700913 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -0700914
915 def test_failed_change_at_head(self):
916 "Test that if a change at the head fails, jobs behind it are canceled"
917 self.fake_jenkins.hold_jobs_in_build = True
918
919 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
920 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
921 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700922 A.addApproval('CRVW', 2)
923 B.addApproval('CRVW', 2)
924 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700925
James E. Blair4886cc12012-07-18 15:39:41 -0700926 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700927
928 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
929 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
930 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
931
932 self.waitUntilSettled()
933 jobs = self.fake_jenkins.all_jobs
934 finished_jobs = self.fake_jenkins.job_history
935
936 assert len(jobs) == 1
937 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700938 assert job_has_changes(jobs[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -0700939
940 self.fake_jenkins.fakeRelease('.*-merge')
941 self.waitUntilSettled()
942 self.fake_jenkins.fakeRelease('.*-merge')
943 self.waitUntilSettled()
944 self.fake_jenkins.fakeRelease('.*-merge')
945 self.waitUntilSettled()
946
947 assert len(jobs) == 6
948 assert jobs[0].name == 'project-test1'
949 assert jobs[1].name == 'project-test2'
950 assert jobs[2].name == 'project-test1'
951 assert jobs[3].name == 'project-test2'
952 assert jobs[4].name == 'project-test1'
953 assert jobs[5].name == 'project-test2'
954
955 jobs[0].release()
956 self.waitUntilSettled()
957
James E. Blairec590122012-08-22 15:19:31 -0700958 assert len(jobs) == 2 # project-test2, project-merge for B
James E. Blaird466dc42012-07-31 10:42:56 -0700959 assert self.countJobResults(finished_jobs, 'ABORTED') == 4
960
961 self.fake_jenkins.hold_jobs_in_build = False
962 self.fake_jenkins.fakeRelease()
963 self.waitUntilSettled()
964
James E. Blair0018a6c2013-02-27 14:11:45 -0800965 for x in jobs:
966 print x
967 for x in finished_jobs:
968 print x
969
James E. Blaird466dc42012-07-31 10:42:56 -0700970 assert len(jobs) == 0
971 assert len(finished_jobs) == 15
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. Blaird466dc42012-07-31 10:42:56 -0700979
980 def test_failed_change_at_head_with_queue(self):
981 "Test that if a change at the head fails, queued jobs are canceled"
982 self.fake_jenkins.hold_jobs_in_queue = True
983
984 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
985 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
986 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700987 A.addApproval('CRVW', 2)
988 B.addApproval('CRVW', 2)
989 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700990
James E. Blair4886cc12012-07-18 15:39:41 -0700991 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700992
993 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
994 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
995 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
996
997 self.waitUntilSettled()
998 jobs = self.fake_jenkins.all_jobs
999 finished_jobs = self.fake_jenkins.job_history
1000 queue = self.fake_jenkins.queue
1001
1002 assert len(jobs) == 1
1003 assert len(queue) == 1
1004 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -07001005 assert job_has_changes(jobs[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001006
1007 self.fake_jenkins.fakeRelease('.*-merge')
1008 self.waitUntilSettled()
1009 self.fake_jenkins.fakeRelease('.*-merge')
1010 self.waitUntilSettled()
1011 self.fake_jenkins.fakeRelease('.*-merge')
1012 self.waitUntilSettled()
1013
1014 assert len(jobs) == 6
1015 assert len(queue) == 6
1016 assert jobs[0].name == 'project-test1'
1017 assert jobs[1].name == 'project-test2'
1018 assert jobs[2].name == 'project-test1'
1019 assert jobs[3].name == 'project-test2'
1020 assert jobs[4].name == 'project-test1'
1021 assert jobs[5].name == 'project-test2'
1022
1023 jobs[0].release()
1024 self.waitUntilSettled()
1025
James E. Blairec590122012-08-22 15:19:31 -07001026 assert len(jobs) == 2 # project-test2, project-merge for B
1027 assert len(queue) == 2
James E. Blaird466dc42012-07-31 10:42:56 -07001028 assert self.countJobResults(finished_jobs, 'ABORTED') == 0
1029
1030 self.fake_jenkins.hold_jobs_in_queue = False
1031 self.fake_jenkins.fakeRelease()
1032 self.waitUntilSettled()
1033
1034 assert len(jobs) == 0
1035 assert len(finished_jobs) == 11
1036 assert A.data['status'] == 'NEW'
1037 assert B.data['status'] == 'MERGED'
1038 assert C.data['status'] == 'MERGED'
1039 assert A.reported == 2
1040 assert B.reported == 2
1041 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001042 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001043
1044 def test_patch_order(self):
1045 "Test that dependent patches are tested in the right order"
1046 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1047 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1048 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1049 A.addApproval('CRVW', 2)
1050 B.addApproval('CRVW', 2)
1051 C.addApproval('CRVW', 2)
1052
1053 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
1054 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1055 M2.setMerged()
1056 M1.setMerged()
1057
1058 # C -> B -> A -> M1 -> M2
1059 # M2 is here to make sure it is never queried. If it is, it
1060 # means zuul is walking down the entire history of merged
1061 # changes.
1062
1063 C.setDependsOn(B, 1)
1064 B.setDependsOn(A, 1)
1065 A.setDependsOn(M1, 1)
1066 M1.setDependsOn(M2, 1)
1067
1068 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1069
1070 self.waitUntilSettled()
1071
1072 assert A.data['status'] == 'NEW'
1073 assert B.data['status'] == 'NEW'
1074 assert C.data['status'] == 'NEW'
1075
1076 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1077 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1078
1079 self.waitUntilSettled()
1080 assert M2.queried == 0
1081 assert A.data['status'] == 'MERGED'
1082 assert B.data['status'] == 'MERGED'
1083 assert C.data['status'] == 'MERGED'
1084 assert A.reported == 2
1085 assert B.reported == 2
1086 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001087 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001088
1089 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -07001090 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -07001091 # TODO: move to test_gerrit (this is a unit test!)
1092 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair4aea70c2012-07-26 14:23:24 -07001093 a = self.sched.trigger.getChange(1, 2)
1094 mgr = self.sched.pipelines['gate'].manager
1095 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001096
1097 A.addApproval('CRVW', 2)
James E. Blair4aea70c2012-07-26 14:23:24 -07001098 a = self.sched.trigger.getChange(1, 2)
1099 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001100
1101 A.addApproval('APRV', 1)
James E. Blair4aea70c2012-07-26 14:23:24 -07001102 a = self.sched.trigger.getChange(1, 2)
1103 assert self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blaire0487072012-08-29 17:38:31 -07001104 self.assertEmptyQueues()
James E. Blair4886cc12012-07-18 15:39:41 -07001105
1106 def test_build_configuration(self):
1107 "Test that zuul merges the right commits for testing"
1108 self.fake_jenkins.hold_jobs_in_queue = True
1109 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1110 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1111 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1112 A.addApproval('CRVW', 2)
1113 B.addApproval('CRVW', 2)
1114 C.addApproval('CRVW', 2)
1115 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1116 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1117 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1118 self.waitUntilSettled()
1119
1120 jobs = self.fake_jenkins.all_jobs
1121
1122 self.fake_jenkins.fakeRelease('.*-merge')
1123 self.waitUntilSettled()
1124 self.fake_jenkins.fakeRelease('.*-merge')
1125 self.waitUntilSettled()
1126 self.fake_jenkins.fakeRelease('.*-merge')
1127 self.waitUntilSettled()
James E. Blair1dbd5082012-08-23 15:12:15 -07001128
James E. Blair4886cc12012-07-18 15:39:41 -07001129 ref = jobs[-1].parameters['ZUUL_REF']
1130 self.fake_jenkins.hold_jobs_in_queue = False
1131 self.fake_jenkins.fakeRelease()
James E. Blair973721f2012-08-15 10:19:43 -07001132 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -07001133
James E. Blair1dbd5082012-08-23 15:12:15 -07001134 path = os.path.join(GIT_ROOT, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -07001135 repo = git.Repo(path)
1136 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1137 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -07001138 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
1139 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001140 self.assertEmptyQueues()
James E. Blair973721f2012-08-15 10:19:43 -07001141
1142 def test_build_configuration_conflict(self):
1143 "Test that merge conflicts are handled"
1144 self.fake_jenkins.hold_jobs_in_queue = True
1145 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1146 A.addPatchset(['conflict'])
1147 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1148 B.addPatchset(['conflict'])
1149 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1150 A.addApproval('CRVW', 2)
1151 B.addApproval('CRVW', 2)
1152 C.addApproval('CRVW', 2)
1153 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1154 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1155 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1156 self.waitUntilSettled()
1157
1158 jobs = self.fake_jenkins.all_jobs
1159
1160 self.fake_jenkins.fakeRelease('.*-merge')
1161 self.waitUntilSettled()
1162 self.fake_jenkins.fakeRelease('.*-merge')
1163 self.waitUntilSettled()
1164 self.fake_jenkins.fakeRelease('.*-merge')
1165 self.waitUntilSettled()
1166 ref = jobs[-1].parameters['ZUUL_REF']
1167 self.fake_jenkins.hold_jobs_in_queue = False
1168 self.fake_jenkins.fakeRelease()
1169 self.waitUntilSettled()
1170
1171 assert A.data['status'] == 'MERGED'
1172 assert B.data['status'] == 'NEW'
1173 assert C.data['status'] == 'MERGED'
1174 assert A.reported == 2
1175 assert B.reported == 2
1176 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001177 self.assertEmptyQueues()
James E. Blairdaabed22012-08-15 15:38:57 -07001178
1179 def test_post(self):
1180 "Test that post jobs run"
Zhongyue Luo5d556072012-09-21 02:00:47 +09001181 e = {
1182 "type": "ref-updated",
1183 "submitter": {
1184 "name": "User Name",
1185 },
1186 "refUpdate": {
1187 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1188 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1189 "refName": "master",
1190 "project": "org/project",
1191 }
1192 }
James E. Blairdaabed22012-08-15 15:38:57 -07001193 self.fake_gerrit.addEvent(e)
1194 self.waitUntilSettled()
1195
1196 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001197 job_names = [x.name for x in jobs]
James E. Blairdaabed22012-08-15 15:38:57 -07001198 assert len(jobs) == 1
1199 assert 'project-post' in job_names
James E. Blaire0487072012-08-29 17:38:31 -07001200 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001201
1202 def test_build_configuration_branch(self):
1203 "Test that the right commits are on alternate branches"
1204 self.fake_jenkins.hold_jobs_in_queue = True
1205 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1206 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1207 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1208 A.addApproval('CRVW', 2)
1209 B.addApproval('CRVW', 2)
1210 C.addApproval('CRVW', 2)
1211 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1212 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1213 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1214 self.waitUntilSettled()
1215
1216 jobs = self.fake_jenkins.all_jobs
1217
1218 self.fake_jenkins.fakeRelease('.*-merge')
1219 self.waitUntilSettled()
1220 self.fake_jenkins.fakeRelease('.*-merge')
1221 self.waitUntilSettled()
1222 self.fake_jenkins.fakeRelease('.*-merge')
1223 self.waitUntilSettled()
1224 ref = jobs[-1].parameters['ZUUL_REF']
1225 self.fake_jenkins.hold_jobs_in_queue = False
1226 self.fake_jenkins.fakeRelease()
1227 self.waitUntilSettled()
1228
James E. Blair1dbd5082012-08-23 15:12:15 -07001229 path = os.path.join(GIT_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001230 repo = git.Repo(path)
1231 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1232 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001233 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
1234 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001235 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001236
1237 def test_build_configuration_branch_interaction(self):
1238 "Test that switching between branches works"
1239 self.test_build_configuration()
1240 self.test_build_configuration_branch()
1241 # C has been merged, undo that
James E. Blair1dbd5082012-08-23 15:12:15 -07001242 path = os.path.join(UPSTREAM_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001243 repo = git.Repo(path)
1244 repo.heads.master.commit = repo.commit('init')
1245 self.test_build_configuration()
James E. Blaire0487072012-08-29 17:38:31 -07001246 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001247
1248 def test_build_configuration_multi_branch(self):
1249 "Test that dependent changes on multiple branches are merged"
1250 self.fake_jenkins.hold_jobs_in_queue = True
1251 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1252 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1253 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1254 A.addApproval('CRVW', 2)
1255 B.addApproval('CRVW', 2)
1256 C.addApproval('CRVW', 2)
1257 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1258 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1259 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1260 self.waitUntilSettled()
1261
1262 jobs = self.fake_jenkins.all_jobs
1263
1264 self.fake_jenkins.fakeRelease('.*-merge')
1265 self.waitUntilSettled()
1266 ref_mp = jobs[-1].parameters['ZUUL_REF']
1267 self.fake_jenkins.fakeRelease('.*-merge')
1268 self.waitUntilSettled()
1269 self.fake_jenkins.fakeRelease('.*-merge')
1270 self.waitUntilSettled()
1271 ref_master = jobs[-1].parameters['ZUUL_REF']
1272 self.fake_jenkins.hold_jobs_in_queue = False
1273 self.fake_jenkins.fakeRelease()
1274 self.waitUntilSettled()
1275
James E. Blair1dbd5082012-08-23 15:12:15 -07001276 path = os.path.join(GIT_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001277 repo = git.Repo(path)
1278
1279 repo_messages = [c.message.strip()
1280 for c in repo.iter_commits(ref_master)]
1281 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001282 correct_messages = ['initial commit', 'A-1', 'C-1']
1283 assert repo_messages == correct_messages
1284
1285 repo_messages = [c.message.strip()
1286 for c in repo.iter_commits(ref_mp)]
1287 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001288 correct_messages = ['initial commit', 'mp commit', 'B-1']
1289 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001290 self.assertEmptyQueues()
James E. Blair7f71c802012-08-22 13:04:32 -07001291
1292 def test_one_job_project(self):
1293 "Test that queueing works with one job"
1294 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1295 'master', 'A')
1296 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1297 'master', 'B')
1298 A.addApproval('CRVW', 2)
1299 B.addApproval('CRVW', 2)
1300 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1301 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1302 self.waitUntilSettled()
1303
1304 jobs = self.fake_jenkins.all_jobs
1305 finished_jobs = self.fake_jenkins.job_history
James E. Blair7f71c802012-08-22 13:04:32 -07001306
1307 assert A.data['status'] == 'MERGED'
1308 assert A.reported == 2
1309 assert B.data['status'] == 'MERGED'
1310 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001311 self.assertEmptyQueues()
James E. Blaircaec0c52012-08-22 14:52:22 -07001312
1313 def test_dependent_changes_dequeue(self):
1314 "Test that dependent patches are not needlessly tested"
1315 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1316 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1317 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1318 A.addApproval('CRVW', 2)
1319 B.addApproval('CRVW', 2)
1320 C.addApproval('CRVW', 2)
1321
1322 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1323 M1.setMerged()
1324
1325 # C -> B -> A -> M1
1326
1327 C.setDependsOn(B, 1)
1328 B.setDependsOn(A, 1)
1329 A.setDependsOn(M1, 1)
1330
1331 self.fake_jenkins.fakeAddFailTest('project-merge', A)
1332
1333 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1334 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1335 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1336
1337 self.waitUntilSettled()
1338
1339 jobs = self.fake_jenkins.all_jobs
1340 finished_jobs = self.fake_jenkins.job_history
1341
James E. Blair127bc182012-08-28 15:55:15 -07001342 for x in jobs:
1343 print x
1344 for x in finished_jobs:
1345 print x
1346
James E. Blairec590122012-08-22 15:19:31 -07001347 assert A.data['status'] == 'NEW'
1348 assert A.reported == 2
1349 assert B.data['status'] == 'NEW'
1350 assert B.reported == 2
1351 assert C.data['status'] == 'NEW'
1352 assert C.reported == 2
1353 assert len(finished_jobs) == 1
James E. Blaire0487072012-08-29 17:38:31 -07001354 self.assertEmptyQueues()
James E. Blairec590122012-08-22 15:19:31 -07001355
1356 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001357 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001358 # If it's dequeued more than once, we should see extra
1359 # aborted jobs.
1360 self.fake_jenkins.hold_jobs_in_build = True
1361
1362 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1363 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1364 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1365 A.addApproval('CRVW', 2)
1366 B.addApproval('CRVW', 2)
1367 C.addApproval('CRVW', 2)
1368
1369 self.fake_jenkins.fakeAddFailTest('project1-test1', A)
1370 self.fake_jenkins.fakeAddFailTest('project1-test2', A)
1371 self.fake_jenkins.fakeAddFailTest('project1-project2-integration', A)
1372
1373 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1374 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1375 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1376
1377 self.waitUntilSettled()
1378 jobs = self.fake_jenkins.all_jobs
1379 finished_jobs = self.fake_jenkins.job_history
1380
1381 assert len(jobs) == 1
1382 assert jobs[0].name == 'project1-merge'
1383 assert job_has_changes(jobs[0], A)
1384
1385 self.fake_jenkins.fakeRelease('.*-merge')
1386 self.waitUntilSettled()
1387 self.fake_jenkins.fakeRelease('.*-merge')
1388 self.waitUntilSettled()
1389 self.fake_jenkins.fakeRelease('.*-merge')
1390 self.waitUntilSettled()
1391
1392 assert len(jobs) == 9
1393 assert jobs[0].name == 'project1-test1'
1394 assert jobs[1].name == 'project1-test2'
1395 assert jobs[2].name == 'project1-project2-integration'
1396 assert jobs[3].name == 'project1-test1'
1397 assert jobs[4].name == 'project1-test2'
1398 assert jobs[5].name == 'project1-project2-integration'
1399 assert jobs[6].name == 'project1-test1'
1400 assert jobs[7].name == 'project1-test2'
1401 assert jobs[8].name == 'project1-project2-integration'
1402
1403 jobs[0].release()
1404 self.waitUntilSettled()
1405
1406 assert len(jobs) == 3 # test2, integration, merge for B
1407 assert self.countJobResults(finished_jobs, 'ABORTED') == 6
1408
1409 self.fake_jenkins.hold_jobs_in_build = False
1410 self.fake_jenkins.fakeRelease()
1411 self.waitUntilSettled()
1412
1413 assert len(jobs) == 0
1414 assert len(finished_jobs) == 20
James E. Blaircaec0c52012-08-22 14:52:22 -07001415
1416 assert A.data['status'] == 'NEW'
James E. Blairec590122012-08-22 15:19:31 -07001417 assert B.data['status'] == 'MERGED'
1418 assert C.data['status'] == 'MERGED'
1419 assert A.reported == 2
1420 assert B.reported == 2
1421 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001422 self.assertEmptyQueues()
James E. Blair4ec821f2012-08-23 15:28:28 -07001423
1424 def test_nonvoting_job(self):
1425 "Test that non-voting jobs don't vote."
1426 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1427 'master', 'A')
1428 A.addApproval('CRVW', 2)
1429 self.fake_jenkins.fakeAddFailTest('nonvoting-project-test2', A)
1430 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1431
1432 self.waitUntilSettled()
1433 jobs = self.fake_jenkins.all_jobs
1434 finished_jobs = self.fake_jenkins.job_history
1435
1436 assert A.data['status'] == 'MERGED'
1437 assert A.reported == 2
James E. Blair0018a6c2013-02-27 14:11:45 -08001438 assert finished_jobs[0].result == 'SUCCESS'
1439 assert finished_jobs[1].result == 'SUCCESS'
1440 assert finished_jobs[2].result == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001441 self.assertEmptyQueues()
1442
1443 def test_check_queue_success(self):
1444 "Test successful check queue jobs."
1445 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1446 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1447
1448 self.waitUntilSettled()
1449 jobs = self.fake_jenkins.all_jobs
1450 finished_jobs = self.fake_jenkins.job_history
1451
1452 assert A.data['status'] == 'NEW'
1453 assert A.reported == 1
James E. Blair0018a6c2013-02-27 14:11:45 -08001454 assert finished_jobs[0].result == 'SUCCESS'
1455 assert finished_jobs[1].result == 'SUCCESS'
1456 assert finished_jobs[2].result == 'SUCCESS'
James E. Blaire0487072012-08-29 17:38:31 -07001457 self.assertEmptyQueues()
1458
1459 def test_check_queue_failure(self):
1460 "Test failed check queue jobs."
1461 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1462 self.fake_jenkins.fakeAddFailTest('project-test2', A)
1463 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1464
1465 self.waitUntilSettled()
1466 jobs = self.fake_jenkins.all_jobs
1467 finished_jobs = self.fake_jenkins.job_history
1468
1469 assert A.data['status'] == 'NEW'
1470 assert A.reported == 1
James E. Blair0018a6c2013-02-27 14:11:45 -08001471 assert finished_jobs[0].result == 'SUCCESS'
1472 assert finished_jobs[1].result == 'SUCCESS'
1473 assert finished_jobs[2].result == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001474 self.assertEmptyQueues()
James E. Blair127bc182012-08-28 15:55:15 -07001475
1476 def test_dependent_behind_dequeue(self):
1477 "test that dependent changes behind dequeued changes work"
1478 # This complicated test is a reproduction of a real life bug
1479 self.sched.reconfigure(self.config)
1480 self.fake_jenkins.hold_jobs_in_build = True
1481
1482 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1483 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1484 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1485 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1486 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1487 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1488 D.setDependsOn(C, 1)
1489 E.setDependsOn(D, 1)
1490 A.addApproval('CRVW', 2)
1491 B.addApproval('CRVW', 2)
1492 C.addApproval('CRVW', 2)
1493 D.addApproval('CRVW', 2)
1494 E.addApproval('CRVW', 2)
1495 F.addApproval('CRVW', 2)
1496
1497 A.fail_merge = True
1498 jobs = self.fake_jenkins.all_jobs
1499 finished_jobs = self.fake_jenkins.job_history
1500
1501 # Change object re-use in the gerrit trigger is hidden if
1502 # changes are added in quick succession; waiting makes it more
1503 # like real life.
1504 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1505 self.waitUntilSettled()
1506 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1507 self.waitUntilSettled()
1508
1509 self.fake_jenkins.fakeRelease('.*-merge')
1510 self.waitUntilSettled()
1511 self.fake_jenkins.fakeRelease('.*-merge')
1512 self.waitUntilSettled()
1513
1514 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1515 self.waitUntilSettled()
1516 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1517 self.waitUntilSettled()
1518 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1519 self.waitUntilSettled()
1520 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1521 self.waitUntilSettled()
1522
1523 self.fake_jenkins.fakeRelease('.*-merge')
1524 self.waitUntilSettled()
1525 self.fake_jenkins.fakeRelease('.*-merge')
1526 self.waitUntilSettled()
1527 self.fake_jenkins.fakeRelease('.*-merge')
1528 self.waitUntilSettled()
1529 self.fake_jenkins.fakeRelease('.*-merge')
1530 self.waitUntilSettled()
1531
James E. Blair4aa1ad62012-10-05 12:39:26 -07001532 for x in jobs:
1533 print x
James E. Blair127bc182012-08-28 15:55:15 -07001534 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001535
1536 # Grab pointers to the jobs we want to release before
1537 # releasing any, because list indexes may change as
1538 # the jobs complete.
1539 a, b, c = jobs[:3]
1540 a.release()
1541 b.release()
1542 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001543 self.waitUntilSettled()
1544
1545 self.fake_jenkins.hold_jobs_in_build = False
1546 self.fake_jenkins.fakeRelease()
1547 self.waitUntilSettled()
1548
1549 for x in jobs:
1550 print x
1551 for x in finished_jobs:
1552 print x
1553 print self.sched.formatStatusHTML()
1554
1555 assert A.data['status'] == 'NEW'
1556 assert B.data['status'] == 'MERGED'
1557 assert C.data['status'] == 'MERGED'
1558 assert D.data['status'] == 'MERGED'
1559 assert E.data['status'] == 'MERGED'
1560 assert F.data['status'] == 'MERGED'
1561
1562 assert A.reported == 2
1563 assert B.reported == 2
1564 assert C.reported == 2
1565 assert D.reported == 2
1566 assert E.reported == 2
1567 assert F.reported == 2
1568
James E. Blair127bc182012-08-28 15:55:15 -07001569 assert self.countJobResults(finished_jobs, 'ABORTED') == 15
1570 assert len(finished_jobs) == 44
James E. Blaire0487072012-08-29 17:38:31 -07001571 self.assertEmptyQueues()
James E. Blair05fed602012-09-07 12:45:24 -07001572
1573 def test_merger_repack(self):
1574 "Test that the merger works after a repack"
1575 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1576 A.addApproval('CRVW', 2)
1577 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1578 self.waitUntilSettled()
1579 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001580 job_names = [x.name for x in jobs]
James E. Blair05fed602012-09-07 12:45:24 -07001581 assert 'project-merge' in job_names
1582 assert 'project-test1' in job_names
1583 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001584 assert jobs[0].result == 'SUCCESS'
1585 assert jobs[1].result == 'SUCCESS'
1586 assert jobs[2].result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001587 assert A.data['status'] == 'MERGED'
1588 assert A.reported == 2
1589 self.assertEmptyQueues()
1590
1591 path = os.path.join(GIT_ROOT, "org/project")
1592 os.system('git --git-dir=%s/.git repack -afd' % path)
1593
1594 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1595 A.addApproval('CRVW', 2)
1596 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1597 self.waitUntilSettled()
1598 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001599 job_names = [x.name for x in jobs]
James E. Blair05fed602012-09-07 12:45:24 -07001600 assert 'project-merge' in job_names
1601 assert 'project-test1' in job_names
1602 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001603 assert jobs[0].result == 'SUCCESS'
1604 assert jobs[1].result == 'SUCCESS'
1605 assert jobs[2].result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001606 assert A.data['status'] == 'MERGED'
1607 assert A.reported == 2
1608 self.assertEmptyQueues()
James E. Blair7ee88a22012-09-12 18:59:31 +02001609
James E. Blair4886f282012-11-15 09:27:33 -08001610 def test_merger_repack_large_change(self):
1611 "Test that the merger works with large changes after a repack"
1612 # https://bugs.launchpad.net/zuul/+bug/1078946
1613 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1614 A.addPatchset(large=True)
1615 path = os.path.join(UPSTREAM_ROOT, "org/project1")
1616 os.system('git --git-dir=%s/.git repack -afd' % path)
1617 path = os.path.join(GIT_ROOT, "org/project1")
1618 os.system('git --git-dir=%s/.git repack -afd' % path)
1619
1620 A.addApproval('CRVW', 2)
1621 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1622 self.waitUntilSettled()
1623 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001624 job_names = [x.name for x in jobs]
James E. Blair4886f282012-11-15 09:27:33 -08001625 assert 'project1-merge' in job_names
1626 assert 'project1-test1' in job_names
1627 assert 'project1-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001628 assert jobs[0].result == 'SUCCESS'
1629 assert jobs[1].result == 'SUCCESS'
1630 assert jobs[2].result == 'SUCCESS'
James E. Blair4886f282012-11-15 09:27:33 -08001631 assert A.data['status'] == 'MERGED'
1632 assert A.reported == 2
1633 self.assertEmptyQueues()
1634
James E. Blair7ee88a22012-09-12 18:59:31 +02001635 def test_nonexistent_job(self):
1636 "Test launching a job that doesn't exist"
1637 self.fake_jenkins.nonexistent_jobs.append('project-merge')
1638 self.jenkins.launch_retry_timeout = 0.1
1639
1640 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1641 A.addApproval('CRVW', 2)
1642 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1643 # There may be a thread about to report a lost change
1644 while A.reported < 2:
1645 self.waitUntilSettled()
1646 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001647 job_names = [x.name for x in jobs]
James E. Blair7ee88a22012-09-12 18:59:31 +02001648 assert not job_names
1649 assert A.data['status'] == 'NEW'
1650 assert A.reported == 2
1651 self.assertEmptyQueues()
1652
1653 # Make sure things still work:
1654 self.fake_jenkins.nonexistent_jobs = []
1655 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1656 A.addApproval('CRVW', 2)
1657 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1658 self.waitUntilSettled()
1659 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001660 job_names = [x.name for x in jobs]
James E. Blair7ee88a22012-09-12 18:59:31 +02001661 assert 'project-merge' in job_names
1662 assert 'project-test1' in job_names
1663 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001664 assert jobs[0].result == 'SUCCESS'
1665 assert jobs[1].result == 'SUCCESS'
1666 assert jobs[2].result == 'SUCCESS'
James E. Blair7ee88a22012-09-12 18:59:31 +02001667 assert A.data['status'] == 'MERGED'
1668 assert A.reported == 2
1669 self.assertEmptyQueues()
James E. Blairf62d4282012-12-31 17:01:50 -08001670
1671 def test_single_nonexistent_post_job(self):
1672 "Test launching a single post job that doesn't exist"
1673 self.fake_jenkins.nonexistent_jobs.append('project-post')
1674 self.jenkins.launch_retry_timeout = 0.1
1675
1676 e = {
1677 "type": "ref-updated",
1678 "submitter": {
1679 "name": "User Name",
1680 },
1681 "refUpdate": {
1682 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1683 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1684 "refName": "master",
1685 "project": "org/project",
1686 }
1687 }
1688 self.fake_gerrit.addEvent(e)
1689 self.waitUntilSettled()
1690
1691 jobs = self.fake_jenkins.job_history
1692 assert len(jobs) == 0
1693 self.assertEmptyQueues()
James E. Blair2fa50962013-01-30 21:50:41 -08001694
1695 def test_new_patchset_dequeues_old(self):
1696 "Test that a new patchset causes the old to be dequeued"
1697 # D -> C (depends on B) -> B (depends on A) -> A -> M
1698 self.fake_jenkins.hold_jobs_in_build = True
1699
1700 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1701 M.setMerged()
1702
1703 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1704 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1705 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1706 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1707 A.addApproval('CRVW', 2)
1708 B.addApproval('CRVW', 2)
1709 C.addApproval('CRVW', 2)
1710 D.addApproval('CRVW', 2)
1711
1712 C.setDependsOn(B, 1)
1713 B.setDependsOn(A, 1)
1714 A.setDependsOn(M, 1)
1715
1716 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1717 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1718 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1719 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1720 self.waitUntilSettled()
1721
1722 B.addPatchset()
1723 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1724 self.waitUntilSettled()
1725
1726 self.fake_jenkins.hold_jobs_in_build = False
1727 self.fake_jenkins.fakeRelease()
1728 self.waitUntilSettled()
1729
1730 jobs = self.fake_jenkins.all_jobs
1731 finished_jobs = self.fake_jenkins.job_history
1732
1733 for x in jobs:
1734 print x
1735 for x in finished_jobs:
1736 print x
1737
1738 assert A.data['status'] == 'MERGED'
1739 assert A.reported == 2
1740 assert B.data['status'] == 'NEW'
1741 assert B.reported == 2
1742 assert C.data['status'] == 'NEW'
1743 assert C.reported == 2
1744 assert D.data['status'] == 'MERGED'
1745 assert D.reported == 2
1746 assert len(finished_jobs) == 9 # 3 each for A, B, D.
1747 self.assertEmptyQueues()
1748
1749 def test_new_patchset_dequeues_old_on_head(self):
1750 "Test that a new patchset causes the old to be dequeued (at head)"
1751 # D -> C (depends on B) -> B (depends on A) -> A -> M
1752 self.fake_jenkins.hold_jobs_in_build = True
1753
1754 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1755 M.setMerged()
1756 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1757 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1758 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1759 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1760 A.addApproval('CRVW', 2)
1761 B.addApproval('CRVW', 2)
1762 C.addApproval('CRVW', 2)
1763 D.addApproval('CRVW', 2)
1764
1765 C.setDependsOn(B, 1)
1766 B.setDependsOn(A, 1)
1767 A.setDependsOn(M, 1)
1768
1769 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1770 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1771 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1772 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1773 self.waitUntilSettled()
1774
1775 A.addPatchset()
1776 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1777 self.waitUntilSettled()
1778
1779 self.fake_jenkins.hold_jobs_in_build = False
1780 self.fake_jenkins.fakeRelease()
1781 self.waitUntilSettled()
1782
1783 jobs = self.fake_jenkins.all_jobs
1784 finished_jobs = self.fake_jenkins.job_history
1785
1786 for x in jobs:
1787 print x
1788 for x in finished_jobs:
1789 print x
1790
1791 assert A.data['status'] == 'NEW'
1792 assert A.reported == 2
1793 assert B.data['status'] == 'NEW'
1794 assert B.reported == 2
1795 assert C.data['status'] == 'NEW'
1796 assert C.reported == 2
1797 assert D.data['status'] == 'MERGED'
1798 assert D.reported == 2
1799 assert len(finished_jobs) == 7
1800 self.assertEmptyQueues()
1801
1802 def test_new_patchset_dequeues_old_without_dependents(self):
1803 "Test that a new patchset causes only the old to be dequeued"
1804 self.fake_jenkins.hold_jobs_in_build = True
1805
1806 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1807 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1808 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1809 A.addApproval('CRVW', 2)
1810 B.addApproval('CRVW', 2)
1811 C.addApproval('CRVW', 2)
1812
1813 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1814 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1815 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1816 self.waitUntilSettled()
1817
1818 B.addPatchset()
1819 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1820 self.waitUntilSettled()
1821
1822 self.fake_jenkins.hold_jobs_in_build = False
1823 self.fake_jenkins.fakeRelease()
1824 self.waitUntilSettled()
1825
1826 jobs = self.fake_jenkins.all_jobs
1827 finished_jobs = self.fake_jenkins.job_history
1828
1829 for x in jobs:
1830 print x
1831 for x in finished_jobs:
1832 print x
1833
1834 assert A.data['status'] == 'MERGED'
1835 assert A.reported == 2
1836 assert B.data['status'] == 'NEW'
1837 assert B.reported == 2
1838 assert C.data['status'] == 'MERGED'
1839 assert C.reported == 2
1840 assert len(finished_jobs) == 9
1841 self.assertEmptyQueues()
1842
1843 def test_new_patchset_dequeues_old_independent_queue(self):
1844 "Test that a new patchset causes the old to be dequeued (independent)"
1845 self.fake_jenkins.hold_jobs_in_build = True
1846
1847 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1848 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1849 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1850 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1851 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1852 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1853 self.waitUntilSettled()
1854
1855 B.addPatchset()
1856 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1857 self.waitUntilSettled()
1858
1859 self.fake_jenkins.hold_jobs_in_build = False
1860 self.fake_jenkins.fakeRelease()
1861 self.waitUntilSettled()
1862
1863 jobs = self.fake_jenkins.all_jobs
1864 finished_jobs = self.fake_jenkins.job_history
1865
1866 for x in jobs:
1867 print x
1868 for x in finished_jobs:
1869 print x
1870
1871 assert A.data['status'] == 'NEW'
1872 assert A.reported == 1
1873 assert B.data['status'] == 'NEW'
1874 assert B.reported == 1
1875 assert C.data['status'] == 'NEW'
1876 assert C.reported == 1
1877 assert len(finished_jobs) == 10
1878 assert self.countJobResults(finished_jobs, 'ABORTED') == 1
1879 self.assertEmptyQueues()
James E. Blair7d0dedc2013-02-21 17:26:09 -08001880
1881 def test_zuul_refs(self):
1882 "Test that zuul refs exist and have the right changes"
1883 self.fake_jenkins.hold_jobs_in_build = True
1884
1885 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
1886 M1.setMerged()
1887 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
1888 M2.setMerged()
1889
1890 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1891 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1892 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1893 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1894 A.addApproval('CRVW', 2)
1895 B.addApproval('CRVW', 2)
1896 C.addApproval('CRVW', 2)
1897 D.addApproval('CRVW', 2)
1898 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1899 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1900 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1901 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1902
1903 self.waitUntilSettled()
1904 self.fake_jenkins.fakeRelease('.*-merge')
1905 self.waitUntilSettled()
1906 self.fake_jenkins.fakeRelease('.*-merge')
1907 self.waitUntilSettled()
1908 self.fake_jenkins.fakeRelease('.*-merge')
1909 self.waitUntilSettled()
1910 self.fake_jenkins.fakeRelease('.*-merge')
1911 self.waitUntilSettled()
1912
1913 jobs = self.fake_jenkins.all_jobs
1914 finished_jobs = self.fake_jenkins.job_history
1915
1916 a_zref = b_zref = c_zref = d_zref = None
1917 for x in jobs:
1918 if x.parameters['ZUUL_CHANGE'] == '3':
1919 a_zref = x.parameters['ZUUL_REF']
1920 if x.parameters['ZUUL_CHANGE'] == '4':
1921 b_zref = x.parameters['ZUUL_REF']
1922 if x.parameters['ZUUL_CHANGE'] == '5':
1923 c_zref = x.parameters['ZUUL_REF']
1924 if x.parameters['ZUUL_CHANGE'] == '6':
1925 d_zref = x.parameters['ZUUL_REF']
1926
1927 # There are... four... refs.
1928 assert a_zref is not None
1929 assert b_zref is not None
1930 assert c_zref is not None
1931 assert d_zref is not None
1932
1933 # And they should all be different
1934 refs = set([a_zref, b_zref, c_zref, d_zref])
1935 assert len(refs) == 4
1936
1937 # a ref should have a, not b, and should not be in project2
1938 assert ref_has_change(a_zref, A)
1939 assert not ref_has_change(a_zref, B)
1940 assert not ref_has_change(a_zref, M2)
1941
1942 # b ref should have a and b, and should not be in project2
1943 assert ref_has_change(b_zref, A)
1944 assert ref_has_change(b_zref, B)
1945 assert not ref_has_change(b_zref, M2)
1946
1947 # c ref should have a and b in 1, c in 2
1948 assert ref_has_change(c_zref, A)
1949 assert ref_has_change(c_zref, B)
1950 assert ref_has_change(c_zref, C)
1951 assert not ref_has_change(c_zref, D)
1952
1953 # d ref should have a and b in 1, c and d in 2
1954 assert ref_has_change(d_zref, A)
1955 assert ref_has_change(d_zref, B)
1956 assert ref_has_change(d_zref, C)
1957 assert ref_has_change(d_zref, D)
1958
1959 self.fake_jenkins.hold_jobs_in_build = False
1960 self.fake_jenkins.fakeRelease()
1961 self.waitUntilSettled()
1962
1963 assert A.data['status'] == 'MERGED'
1964 assert A.reported == 2
1965 assert B.data['status'] == 'MERGED'
1966 assert B.reported == 2
1967 assert C.data['status'] == 'MERGED'
1968 assert C.reported == 2
1969 assert D.data['status'] == 'MERGED'
1970 assert D.reported == 2
1971 self.assertEmptyQueues()
James E. Blair70c71582013-03-06 08:50:50 -08001972
1973 def test_file_jobs(self):
1974 "Test that file jobs run only when appropriate"
1975 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1976 A.addPatchset(['pip-requires'])
1977 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1978 A.addApproval('CRVW', 2)
1979 B.addApproval('CRVW', 2)
1980 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1981 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1982 self.waitUntilSettled()
1983
1984 jobs = self.fake_jenkins.all_jobs
1985 finished_jobs = self.fake_jenkins.job_history
1986
1987 testfile_jobs = [x for x in finished_jobs
1988 if x.name == 'project-testfile']
1989
1990 assert len(testfile_jobs) == 1
1991 assert testfile_jobs[0].changes == '1,2'
1992 assert A.data['status'] == 'MERGED'
1993 assert A.reported == 2
1994 assert B.data['status'] == 'MERGED'
1995 assert B.reported == 2
1996 self.assertEmptyQueues()