blob: 508af4249844c25831d90b9f5c124b300bb6524d [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. Blair412e5582013-04-22 15:50:12 -070031import select
32import statsd
James E. Blair4886cc12012-07-18 15:39:41 -070033import shutil
James E. Blair412e5582013-04-22 15:50:12 -070034import socket
James E. Blair4886f282012-11-15 09:27:33 -080035import string
James E. Blair4886cc12012-07-18 15:39:41 -070036import git
James E. Blairb0fcae42012-07-17 11:12:10 -070037
James E. Blairb0fcae42012-07-17 11:12:10 -070038import zuul.scheduler
39import zuul.launcher.jenkins
40import zuul.trigger.gerrit
41
42FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
43 'fixtures')
44CONFIG = ConfigParser.ConfigParser()
45CONFIG.read(os.path.join(FIXTURE_DIR, "zuul.conf"))
46
47CONFIG.set('zuul', 'layout_config',
48 os.path.join(FIXTURE_DIR, "layout.yaml"))
49
James E. Blair1dbd5082012-08-23 15:12:15 -070050TMP_ROOT = os.environ.get("ZUUL_TEST_ROOT", "/tmp")
51TEST_ROOT = os.path.join(TMP_ROOT, "zuul-test")
52UPSTREAM_ROOT = os.path.join(TEST_ROOT, "upstream")
53GIT_ROOT = os.path.join(TEST_ROOT, "git")
54
55CONFIG.set('zuul', 'git_dir', GIT_ROOT)
56
James E. Blairb0fcae42012-07-17 11:12:10 -070057logging.basicConfig(level=logging.DEBUG)
58
59
James E. Blair8cc15a82012-08-01 11:17:57 -070060def random_sha1():
61 return hashlib.sha1(str(random.random())).hexdigest()
62
63
James E. Blair4886cc12012-07-18 15:39:41 -070064class ChangeReference(git.Reference):
65 _common_path_default = "refs/changes"
66 _points_to_commits_only = True
67
68
69def init_repo(project):
70 parts = project.split('/')
James E. Blair1dbd5082012-08-23 15:12:15 -070071 path = os.path.join(UPSTREAM_ROOT, *parts[:-1])
James E. Blair4886cc12012-07-18 15:39:41 -070072 if not os.path.exists(path):
73 os.makedirs(path)
James E. Blair1dbd5082012-08-23 15:12:15 -070074 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -070075 repo = git.Repo.init(path)
76
77 fn = os.path.join(path, 'README')
78 f = open(fn, 'w')
79 f.write("test\n")
80 f.close()
81 repo.index.add([fn])
82 repo.index.commit('initial commit')
James E. Blairc6294a52012-08-17 10:19:48 -070083 master = repo.create_head('master')
James E. Blair4886cc12012-07-18 15:39:41 -070084 repo.create_tag('init')
85
James E. Blairc6294a52012-08-17 10:19:48 -070086 mp = repo.create_head('mp')
87 repo.head.reference = mp
88 f = open(fn, 'a')
89 f.write("test mp\n")
90 f.close()
91 repo.index.add([fn])
92 repo.index.commit('mp commit')
93
94 repo.head.reference = master
95 repo.head.reset(index=True, working_tree=True)
96 repo.git.clean('-x', '-f', '-d')
97
James E. Blair4886cc12012-07-18 15:39:41 -070098
James E. Blair4886f282012-11-15 09:27:33 -080099def add_fake_change_to_repo(project, branch, change_num, patchset, msg, fn,
100 large):
James E. Blair1dbd5082012-08-23 15:12:15 -0700101 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -0700102 repo = git.Repo(path)
103 ref = ChangeReference.create(repo, '1/%s/%s' % (change_num,
104 patchset),
105 'refs/tags/init')
106 repo.head.reference = ref
107 repo.head.reset(index=True, working_tree=True)
108 repo.git.clean('-x', '-f', '-d')
109
James E. Blair1dbd5082012-08-23 15:12:15 -0700110 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886f282012-11-15 09:27:33 -0800111 if not large:
112 fn = os.path.join(path, fn)
113 f = open(fn, 'w')
114 f.write("test %s %s %s\n" % (branch, change_num, patchset))
115 f.close()
116 repo.index.add([fn])
117 else:
118 for fni in range(100):
119 fn = os.path.join(path, str(fni))
120 f = open(fn, 'w')
121 for ci in range(4096):
122 f.write(random.choice(string.printable))
123 f.close()
124 repo.index.add([fn])
125
James E. Blairdaabed22012-08-15 15:38:57 -0700126 return repo.index.commit(msg)
James E. Blair4886cc12012-07-18 15:39:41 -0700127
128
129def ref_has_change(ref, change):
James E. Blair1dbd5082012-08-23 15:12:15 -0700130 path = os.path.join(GIT_ROOT, change.project)
James E. Blair4886cc12012-07-18 15:39:41 -0700131 repo = git.Repo(path)
132 for commit in repo.iter_commits(ref):
133 if commit.message.strip() == ('%s-1' % change.subject):
134 return True
135 return False
136
137
138def job_has_changes(*args):
139 job = args[0]
140 commits = args[1:]
141 project = job.parameters['ZUUL_PROJECT']
James E. Blair1dbd5082012-08-23 15:12:15 -0700142 path = os.path.join(GIT_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -0700143 repo = git.Repo(path)
144 ref = job.parameters['ZUUL_REF']
James E. Blair81515ad2012-10-01 18:29:08 -0700145 sha = job.parameters['ZUUL_COMMIT']
James E. Blair4886cc12012-07-18 15:39:41 -0700146 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
James E. Blair81515ad2012-10-01 18:29:08 -0700147 repo_shas = [c.hexsha for c in repo.iter_commits(ref)]
James E. Blair4886cc12012-07-18 15:39:41 -0700148 commit_messages = ['%s-1' % commit.subject for commit in commits]
James E. Blair4886cc12012-07-18 15:39:41 -0700149 for msg in commit_messages:
150 if msg not in repo_messages:
151 return False
James E. Blair81515ad2012-10-01 18:29:08 -0700152 if repo_shas[0] != sha:
153 return False
James E. Blair4886cc12012-07-18 15:39:41 -0700154 return True
155
156
James E. Blairb0fcae42012-07-17 11:12:10 -0700157class FakeChange(object):
James E. Blair8c803f82012-07-31 16:25:42 -0700158 categories = {'APRV': ('Approved', -1, 1),
159 'CRVW': ('Code-Review', -2, 2),
160 'VRFY': ('Verified', -2, 2)}
James E. Blairb0fcae42012-07-17 11:12:10 -0700161
James E. Blair8cc15a82012-08-01 11:17:57 -0700162 def __init__(self, gerrit, number, project, branch, subject, status='NEW'):
163 self.gerrit = gerrit
James E. Blaird466dc42012-07-31 10:42:56 -0700164 self.reported = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700165 self.queried = 0
James E. Blairb0fcae42012-07-17 11:12:10 -0700166 self.patchsets = []
James E. Blairb0fcae42012-07-17 11:12:10 -0700167 self.number = number
168 self.project = project
169 self.branch = branch
170 self.subject = subject
171 self.latest_patchset = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700172 self.depends_on_change = None
173 self.needed_by_changes = []
James E. Blair127bc182012-08-28 15:55:15 -0700174 self.fail_merge = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700175 self.data = {
176 'branch': branch,
177 'comments': [],
178 'commitMessage': subject,
179 'createdOn': time.time(),
James E. Blair8cc15a82012-08-01 11:17:57 -0700180 'id': 'I' + random_sha1(),
James E. Blairb0fcae42012-07-17 11:12:10 -0700181 'lastUpdated': time.time(),
182 'number': str(number),
183 'open': True,
184 'owner': {'email': 'user@example.com',
185 'name': 'User Name',
186 'username': 'username'},
187 'patchSets': self.patchsets,
188 'project': project,
189 'status': status,
190 'subject': subject,
James E. Blair8c803f82012-07-31 16:25:42 -0700191 'submitRecords': [],
James E. Blairb0fcae42012-07-17 11:12:10 -0700192 'url': 'https://hostname/%s' % number}
193
194 self.addPatchset()
James E. Blair8c803f82012-07-31 16:25:42 -0700195 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700196
James E. Blair70c71582013-03-06 08:50:50 -0800197 def addPatchset(self, files=[], large=False):
James E. Blairb0fcae42012-07-17 11:12:10 -0700198 self.latest_patchset += 1
James E. Blairdaabed22012-08-15 15:38:57 -0700199 if files:
200 fn = files[0]
201 else:
202 fn = '%s-%s' % (self.branch, self.number)
203 msg = self.subject + '-' + str(self.latest_patchset)
204 c = add_fake_change_to_repo(self.project, self.branch,
205 self.number, self.latest_patchset,
James E. Blair4886f282012-11-15 09:27:33 -0800206 msg, fn, large)
James E. Blair70c71582013-03-06 08:50:50 -0800207 ps_files = [{'file': '/COMMIT_MSG',
208 'type': 'ADDED'},
209 {'file': 'README',
210 'type': 'MODIFIED'}]
211 for f in files:
212 ps_files.append({'file': f, 'type': 'ADDED'})
James E. Blairb0fcae42012-07-17 11:12:10 -0700213 d = {'approvals': [],
214 'createdOn': time.time(),
James E. Blair70c71582013-03-06 08:50:50 -0800215 'files': ps_files,
James E. Blair8c803f82012-07-31 16:25:42 -0700216 'number': str(self.latest_patchset),
James E. Blairb0fcae42012-07-17 11:12:10 -0700217 'ref': 'refs/changes/1/%s/%s' % (self.number,
218 self.latest_patchset),
James E. Blairdaabed22012-08-15 15:38:57 -0700219 'revision': c.hexsha,
James E. Blairb0fcae42012-07-17 11:12:10 -0700220 'uploader': {'email': 'user@example.com',
221 'name': 'User name',
222 'username': 'user'}}
223 self.data['currentPatchSet'] = d
224 self.patchsets.append(d)
James E. Blair8c803f82012-07-31 16:25:42 -0700225 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700226
James E. Blaire0487072012-08-29 17:38:31 -0700227 def getPatchsetCreatedEvent(self, patchset):
228 event = {"type": "patchset-created",
229 "change": {"project": self.project,
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800230 "branch": self.branch,
231 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
232 "number": str(self.number),
233 "subject": self.subject,
234 "owner": {"name": "User Name"},
235 "url": "https://hostname/3"},
James E. Blaire0487072012-08-29 17:38:31 -0700236 "patchSet": self.patchsets[patchset - 1],
237 "uploader": {"name": "User Name"}}
238 return event
239
James E. Blairb0fcae42012-07-17 11:12:10 -0700240 def addApproval(self, category, value):
James E. Blair8c803f82012-07-31 16:25:42 -0700241 approval = {'description': self.categories[category][0],
242 'type': category,
243 'value': str(value)}
244 self.patchsets[-1]['approvals'].append(approval)
245 event = {'approvals': [approval],
James E. Blairb0fcae42012-07-17 11:12:10 -0700246 'author': {'email': 'user@example.com',
247 'name': 'User Name',
248 'username': 'username'},
249 'change': {'branch': self.branch,
250 'id': 'Iaa69c46accf97d0598111724a38250ae76a22c87',
251 'number': str(self.number),
252 'owner': {'email': 'user@example.com',
253 'name': 'User Name',
254 'username': 'username'},
255 'project': self.project,
256 'subject': self.subject,
257 'topic': 'master',
258 'url': 'https://hostname/459'},
259 'comment': '',
260 'patchSet': self.patchsets[-1],
261 'type': 'comment-added'}
James E. Blair8c803f82012-07-31 16:25:42 -0700262 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700263 return json.loads(json.dumps(event))
264
James E. Blair8c803f82012-07-31 16:25:42 -0700265 def getSubmitRecords(self):
266 status = {}
267 for cat in self.categories.keys():
268 status[cat] = 0
269
270 for a in self.patchsets[-1]['approvals']:
271 cur = status[a['type']]
272 cat_min, cat_max = self.categories[a['type']][1:]
273 new = int(a['value'])
274 if new == cat_min:
275 cur = new
276 elif abs(new) > abs(cur):
277 cur = new
278 status[a['type']] = cur
279
280 labels = []
281 ok = True
282 for typ, cat in self.categories.items():
283 cur = status[typ]
284 cat_min, cat_max = cat[1:]
285 if cur == cat_min:
286 value = 'REJECT'
287 ok = False
288 elif cur == cat_max:
289 value = 'OK'
290 else:
291 value = 'NEED'
292 ok = False
293 labels.append({'label': cat[0], 'status': value})
294 if ok:
295 return [{'status': 'OK'}]
296 return [{'status': 'NOT_READY',
297 'labels': labels}]
298
299 def setDependsOn(self, other, patchset):
300 self.depends_on_change = other
301 d = {'id': other.data['id'],
302 'number': other.data['number'],
303 'ref': other.patchsets[patchset - 1]['ref']
304 }
305 self.data['dependsOn'] = [d]
306
307 other.needed_by_changes.append(self)
308 needed = other.data.get('neededBy', [])
309 d = {'id': self.data['id'],
310 'number': self.data['number'],
311 'ref': self.patchsets[patchset - 1]['ref'],
312 'revision': self.patchsets[patchset - 1]['revision']
313 }
314 needed.append(d)
315 other.data['neededBy'] = needed
316
James E. Blairb0fcae42012-07-17 11:12:10 -0700317 def query(self):
James E. Blair8c803f82012-07-31 16:25:42 -0700318 self.queried += 1
319 d = self.data.get('dependsOn')
320 if d:
321 d = d[0]
322 if (self.depends_on_change.patchsets[-1]['ref'] == d['ref']):
323 d['isCurrentPatchSet'] = True
324 else:
325 d['isCurrentPatchSet'] = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700326 return json.loads(json.dumps(self.data))
327
328 def setMerged(self):
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800329 if (self.depends_on_change and
330 self.depends_on_change.data['status'] != 'MERGED'):
James E. Blaircaec0c52012-08-22 14:52:22 -0700331 return
James E. Blair127bc182012-08-28 15:55:15 -0700332 if self.fail_merge:
333 return
James E. Blairb0fcae42012-07-17 11:12:10 -0700334 self.data['status'] = 'MERGED'
335 self.open = False
James E. Blairdaabed22012-08-15 15:38:57 -0700336
James E. Blair1dbd5082012-08-23 15:12:15 -0700337 path = os.path.join(UPSTREAM_ROOT, self.project)
James E. Blairdaabed22012-08-15 15:38:57 -0700338 repo = git.Repo(path)
339 repo.heads[self.branch].commit = \
340 repo.commit(self.patchsets[-1]['revision'])
James E. Blairb0fcae42012-07-17 11:12:10 -0700341
James E. Blaird466dc42012-07-31 10:42:56 -0700342 def setReported(self):
343 self.reported += 1
344
James E. Blairb0fcae42012-07-17 11:12:10 -0700345
346class FakeGerrit(object):
347 def __init__(self, *args, **kw):
348 self.event_queue = Queue.Queue()
349 self.fixture_dir = os.path.join(FIXTURE_DIR, 'gerrit')
350 self.change_number = 0
351 self.changes = {}
352
353 def addFakeChange(self, project, branch, subject):
354 self.change_number += 1
James E. Blair8cc15a82012-08-01 11:17:57 -0700355 c = FakeChange(self, self.change_number, project, branch, subject)
James E. Blairb0fcae42012-07-17 11:12:10 -0700356 self.changes[self.change_number] = c
357 return c
358
359 def addEvent(self, data):
360 return self.event_queue.put(data)
361
362 def getEvent(self):
363 return self.event_queue.get()
364
365 def eventDone(self):
366 self.event_queue.task_done()
367
368 def review(self, project, changeid, message, action):
James E. Blaird466dc42012-07-31 10:42:56 -0700369 number, ps = changeid.split(',')
370 change = self.changes[int(number)]
James E. Blairb0fcae42012-07-17 11:12:10 -0700371 if 'submit' in action:
James E. Blairb0fcae42012-07-17 11:12:10 -0700372 change.setMerged()
James E. Blaird466dc42012-07-31 10:42:56 -0700373 if message:
374 change.setReported()
James E. Blairb0fcae42012-07-17 11:12:10 -0700375
376 def query(self, number):
377 change = self.changes[int(number)]
378 return change.query()
379
380 def startWatching(self, *args, **kw):
381 pass
382
383
384class FakeJenkinsEvent(object):
385 def __init__(self, name, number, parameters, phase, status=None):
Zhongyue Luo5d556072012-09-21 02:00:47 +0900386 data = {
387 'build': {
388 'full_url': 'https://server/job/%s/%s/' % (name, number),
389 'number': number,
390 'parameters': parameters,
391 'phase': phase,
392 'url': 'job/%s/%s/' % (name, number),
393 },
394 'name': name,
395 'url': 'job/%s/' % name,
396 }
James E. Blairb0fcae42012-07-17 11:12:10 -0700397 if status:
398 data['build']['status'] = status
399 self.body = json.dumps(data)
400
401
402class FakeJenkinsJob(threading.Thread):
403 log = logging.getLogger("zuul.test")
404
405 def __init__(self, jenkins, callback, name, number, parameters):
406 threading.Thread.__init__(self)
407 self.jenkins = jenkins
408 self.callback = callback
409 self.name = name
410 self.number = number
411 self.parameters = parameters
412 self.wait_condition = threading.Condition()
413 self.waiting = False
James E. Blaird466dc42012-07-31 10:42:56 -0700414 self.aborted = False
415 self.canceled = False
416 self.created = time.time()
James E. Blairb0fcae42012-07-17 11:12:10 -0700417
418 def release(self):
419 self.wait_condition.acquire()
420 self.wait_condition.notify()
421 self.waiting = False
422 self.log.debug("Job %s released" % (self.parameters['UUID']))
423 self.wait_condition.release()
424
425 def isWaiting(self):
426 self.wait_condition.acquire()
427 if self.waiting:
428 ret = True
429 else:
430 ret = False
431 self.wait_condition.release()
432 return ret
433
434 def _wait(self):
435 self.wait_condition.acquire()
436 self.waiting = True
437 self.log.debug("Job %s waiting" % (self.parameters['UUID']))
438 self.wait_condition.wait()
439 self.wait_condition.release()
440
441 def run(self):
442 self.jenkins.fakeEnqueue(self)
443 if self.jenkins.hold_jobs_in_queue:
444 self._wait()
445 self.jenkins.fakeDequeue(self)
James E. Blaird466dc42012-07-31 10:42:56 -0700446 if self.canceled:
447 self.jenkins.all_jobs.remove(self)
448 return
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800449 self.callback.jenkins_endpoint(FakeJenkinsEvent(self.name,
450 self.number,
451 self.parameters,
452 'STARTED'))
James E. Blairb0fcae42012-07-17 11:12:10 -0700453 if self.jenkins.hold_jobs_in_build:
454 self._wait()
455 self.log.debug("Job %s continuing" % (self.parameters['UUID']))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700456
457 result = 'SUCCESS'
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800458 if (('ZUUL_REF' in self.parameters) and
459 self.jenkins.fakeShouldFailTest(self.name,
460 self.parameters['ZUUL_REF'])):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700461 result = 'FAILURE'
James E. Blaird466dc42012-07-31 10:42:56 -0700462 if self.aborted:
463 result = 'ABORTED'
James E. Blairb02a3bb2012-07-30 17:49:55 -0700464
James E. Blair0018a6c2013-02-27 14:11:45 -0800465 changes = None
466 if 'ZUUL_CHANGE_IDS' in self.parameters:
467 changes = self.parameters['ZUUL_CHANGE_IDS']
468
James E. Blairb0fcae42012-07-17 11:12:10 -0700469 self.jenkins.fakeAddHistory(name=self.name, number=self.number,
James E. Blair0018a6c2013-02-27 14:11:45 -0800470 result=result, changes=changes)
James E. Blairff791972013-01-09 11:45:43 -0800471 self.jenkins.lock.acquire()
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800472 self.callback.jenkins_endpoint(FakeJenkinsEvent(self.name,
473 self.number,
474 self.parameters,
475 'COMPLETED',
476 result))
477 self.callback.jenkins_endpoint(FakeJenkinsEvent(self.name,
478 self.number,
479 self.parameters,
480 'FINISHED',
481 result))
James E. Blairb0fcae42012-07-17 11:12:10 -0700482 self.jenkins.all_jobs.remove(self)
James E. Blairff791972013-01-09 11:45:43 -0800483 self.jenkins.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700484
485
486class FakeJenkins(object):
487 log = logging.getLogger("zuul.test")
488
489 def __init__(self, *args, **kw):
490 self.queue = []
491 self.all_jobs = []
492 self.job_counter = {}
James E. Blaird466dc42012-07-31 10:42:56 -0700493 self.queue_counter = 0
James E. Blairb0fcae42012-07-17 11:12:10 -0700494 self.job_history = []
495 self.hold_jobs_in_queue = False
496 self.hold_jobs_in_build = False
James E. Blairb02a3bb2012-07-30 17:49:55 -0700497 self.fail_tests = {}
James E. Blair7ee88a22012-09-12 18:59:31 +0200498 self.nonexistent_jobs = []
James E. Blairff791972013-01-09 11:45:43 -0800499 self.lock = threading.Lock()
James E. Blairb0fcae42012-07-17 11:12:10 -0700500
501 def fakeEnqueue(self, job):
502 self.queue.append(job)
503
504 def fakeDequeue(self, job):
505 self.queue.remove(job)
506
James E. Blair0018a6c2013-02-27 14:11:45 -0800507 class FakeJobHistory(object):
508 def __init__(self, **kw):
509 self.__dict__.update(kw)
510
511 def __repr__(self):
512 return ("<Completed job, result: %s name: %s #%s changes: %s>" %
513 (self.result, self.name, self.number, self.changes))
514
James E. Blairb0fcae42012-07-17 11:12:10 -0700515 def fakeAddHistory(self, **kw):
James E. Blair0018a6c2013-02-27 14:11:45 -0800516 self.job_history.append(self.FakeJobHistory(**kw))
James E. Blairb0fcae42012-07-17 11:12:10 -0700517
518 def fakeRelease(self, regex=None):
519 all_jobs = self.all_jobs[:]
520 self.log.debug("releasing jobs %s (%s)" % (regex, len(self.all_jobs)))
521 for job in all_jobs:
522 if not regex or re.match(regex, job.name):
523 self.log.debug("releasing job %s" % (job.parameters['UUID']))
524 job.release()
525 else:
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800526 self.log.debug("not releasing job %s" %
527 (job.parameters['UUID']))
James E. Blairb0fcae42012-07-17 11:12:10 -0700528 self.log.debug("done releasing jobs %s (%s)" % (regex,
529 len(self.all_jobs)))
530
531 def fakeAllWaiting(self, regex=None):
James E. Blair4aa1ad62012-10-05 12:39:26 -0700532 all_jobs = self.all_jobs[:] + self.queue[:]
James E. Blairb0fcae42012-07-17 11:12:10 -0700533 for job in all_jobs:
534 self.log.debug("job %s %s" % (job.parameters['UUID'],
535 job.isWaiting()))
536 if not job.isWaiting():
537 return False
538 return True
539
James E. Blairb02a3bb2012-07-30 17:49:55 -0700540 def fakeAddFailTest(self, name, change):
541 l = self.fail_tests.get(name, [])
542 l.append(change)
543 self.fail_tests[name] = l
544
James E. Blair4886cc12012-07-18 15:39:41 -0700545 def fakeShouldFailTest(self, name, ref):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700546 l = self.fail_tests.get(name, [])
547 for change in l:
James E. Blair4886cc12012-07-18 15:39:41 -0700548 if ref_has_change(ref, change):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700549 return True
550 return False
551
James E. Blairb0fcae42012-07-17 11:12:10 -0700552 def build_job(self, name, parameters):
James E. Blair7ee88a22012-09-12 18:59:31 +0200553 if name in self.nonexistent_jobs:
554 raise Exception("Job does not exist")
James E. Blairb0fcae42012-07-17 11:12:10 -0700555 count = self.job_counter.get(name, 0)
556 count += 1
557 self.job_counter[name] = count
James E. Blaird466dc42012-07-31 10:42:56 -0700558
559 queue_count = self.queue_counter
560 self.queue_counter += 1
James E. Blairb0fcae42012-07-17 11:12:10 -0700561 job = FakeJenkinsJob(self, self.callback, name, count, parameters)
James E. Blaird466dc42012-07-31 10:42:56 -0700562 job.queue_id = queue_count
563
James E. Blairb0fcae42012-07-17 11:12:10 -0700564 self.all_jobs.append(job)
565 job.start()
566
James E. Blaird466dc42012-07-31 10:42:56 -0700567 def stop_build(self, name, number):
568 for job in self.all_jobs:
569 if job.name == name and job.number == number:
570 job.aborted = True
571 job.release()
572 return
573
574 def cancel_queue(self, id):
575 for job in self.queue:
576 if job.queue_id == id:
577 job.canceled = True
578 job.release()
579 return
580
581 def get_queue_info(self):
582 items = []
James E. Blair1490eba2013-03-06 19:14:00 -0800583 for job in self.queue[:]:
584 self.log.debug("Queue info: %s %s" % (job.name,
585 job.parameters['UUID']))
James E. Blaird466dc42012-07-31 10:42:56 -0700586 paramstr = ''
587 paramlst = []
588 d = {'actions': [{'parameters': paramlst},
589 {'causes': [{'shortDescription':
590 'Started by user Jenkins',
591 'userId': 'jenkins',
592 'userName': 'Jenkins'}]}],
593 'blocked': False,
594 'buildable': True,
595 'buildableStartMilliseconds': (job.created * 1000) + 5,
596 'id': job.queue_id,
597 'inQueueSince': (job.created * 1000),
598 'params': paramstr,
599 'stuck': False,
600 'task': {'color': 'blue',
601 'name': job.name,
602 'url': 'https://server/job/%s/' % job.name},
603 'why': 'Waiting for next available executor'}
604 for k, v in job.parameters.items():
605 paramstr += "\n(StringParameterValue) %s='%s'" % (k, v)
606 pd = {'name': k, 'value': v}
607 paramlst.append(pd)
608 items.append(d)
609 return items
610
James E. Blairb0fcae42012-07-17 11:12:10 -0700611 def set_build_description(self, *args, **kw):
612 pass
613
614
615class FakeJenkinsCallback(zuul.launcher.jenkins.JenkinsCallback):
616 def start(self):
617 pass
618
619
James E. Blair8cc15a82012-08-01 11:17:57 -0700620class FakeURLOpener(object):
621 def __init__(self, fake_gerrit, url):
622 self.fake_gerrit = fake_gerrit
623 self.url = url
624
625 def read(self):
626 res = urlparse.urlparse(self.url)
627 path = res.path
628 project = '/'.join(path.split('/')[2:-2])
James E. Blair35956c52012-09-17 22:13:36 +0200629 ret = '001e# service=git-upload-pack\n'
630 ret += ('000000a31270149696713ba7e06f1beb760f20d359c4abed HEAD\x00'
631 'multi_ack thin-pack side-band side-band-64k ofs-delta '
632 'shallow no-progress include-tag multi_ack_detailed no-done\n')
James E. Blair1dbd5082012-08-23 15:12:15 -0700633 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blairdaabed22012-08-15 15:38:57 -0700634 repo = git.Repo(path)
635 for ref in repo.refs:
James E. Blair35956c52012-09-17 22:13:36 +0200636 r = ref.object.hexsha + ' ' + ref.path + '\n'
637 ret += '%04x%s' % (len(r) + 4, r)
638 ret += '0000'
James E. Blair8cc15a82012-08-01 11:17:57 -0700639 return ret
640
641
James E. Blair4886cc12012-07-18 15:39:41 -0700642class FakeGerritTrigger(zuul.trigger.gerrit.Gerrit):
643 def getGitUrl(self, project):
James E. Blair1dbd5082012-08-23 15:12:15 -0700644 return os.path.join(UPSTREAM_ROOT, project.name)
James E. Blair4886cc12012-07-18 15:39:41 -0700645
646
James E. Blair412e5582013-04-22 15:50:12 -0700647class FakeStatsd(threading.Thread):
648 def __init__(self):
649 threading.Thread.__init__(self)
650 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
651 self.sock.bind(('', 0))
652 self.port = self.sock.getsockname()[1]
653 self.wake_read, self.wake_write = os.pipe()
654 self.stats = []
655
656 def run(self):
657 while True:
Ori Livnehd75cc182013-05-02 18:44:46 -0700658 read_ready = select.select([self.sock, self.wake_read], [], [])[0]
659 for sock in read_ready:
660 if sock is self.sock:
James E. Blair412e5582013-04-22 15:50:12 -0700661 data = self.sock.recvfrom(1024)
662 if not data:
663 return
664 self.stats.append(data[0])
Ori Livnehd75cc182013-05-02 18:44:46 -0700665 else:
666 # wake_read
James E. Blair412e5582013-04-22 15:50:12 -0700667 return
668
669 def stop(self):
670 os.write(self.wake_write, '1\n')
671
672
James E. Blairb0fcae42012-07-17 11:12:10 -0700673class testScheduler(unittest.TestCase):
674 log = logging.getLogger("zuul.test")
675
676 def setUp(self):
James E. Blair1dbd5082012-08-23 15:12:15 -0700677 if os.path.exists(TEST_ROOT):
678 shutil.rmtree(TEST_ROOT)
679 os.makedirs(TEST_ROOT)
680 os.makedirs(UPSTREAM_ROOT)
681 os.makedirs(GIT_ROOT)
James E. Blair4886cc12012-07-18 15:39:41 -0700682
683 # For each project in config:
684 init_repo("org/project")
685 init_repo("org/project1")
686 init_repo("org/project2")
James E. Blair127bc182012-08-28 15:55:15 -0700687 init_repo("org/project3")
James E. Blair7f71c802012-08-22 13:04:32 -0700688 init_repo("org/one-job-project")
James E. Blair4ec821f2012-08-23 15:28:28 -0700689 init_repo("org/nonvoting-project")
Antoine Musso80edd5a2013-02-13 15:37:53 +0100690 init_repo("org/templated-project")
James E. Blairb0fcae42012-07-17 11:12:10 -0700691 self.config = CONFIG
James E. Blair412e5582013-04-22 15:50:12 -0700692
693 self.statsd = FakeStatsd()
694 os.environ['STATSD_HOST'] = 'localhost'
695 os.environ['STATSD_PORT'] = str(self.statsd.port)
696 self.statsd.start()
697 # the statsd client object is configured in the statsd module import
698 reload(statsd)
699 reload(zuul.scheduler)
700
James E. Blairb0fcae42012-07-17 11:12:10 -0700701 self.sched = zuul.scheduler.Scheduler()
702
703 def jenkinsFactory(*args, **kw):
704 self.fake_jenkins = FakeJenkins()
705 return self.fake_jenkins
706
707 def jenkinsCallbackFactory(*args, **kw):
708 self.fake_jenkins_callback = FakeJenkinsCallback(*args, **kw)
709 return self.fake_jenkins_callback
710
James E. Blair8cc15a82012-08-01 11:17:57 -0700711 def URLOpenerFactory(*args, **kw):
712 args = [self.fake_gerrit] + list(args)
713 return FakeURLOpener(*args, **kw)
714
James E. Blairb0fcae42012-07-17 11:12:10 -0700715 zuul.launcher.jenkins.ExtendedJenkins = jenkinsFactory
716 zuul.launcher.jenkins.JenkinsCallback = jenkinsCallbackFactory
James E. Blair8cc15a82012-08-01 11:17:57 -0700717 urllib2.urlopen = URLOpenerFactory
James E. Blairb0fcae42012-07-17 11:12:10 -0700718 self.jenkins = zuul.launcher.jenkins.Jenkins(self.config, self.sched)
719 self.fake_jenkins.callback = self.fake_jenkins_callback
720
721 zuul.lib.gerrit.Gerrit = FakeGerrit
722
James E. Blair4886cc12012-07-18 15:39:41 -0700723 self.gerrit = FakeGerritTrigger(self.config, self.sched)
James E. Blair8cc15a82012-08-01 11:17:57 -0700724 self.gerrit.replication_timeout = 1.5
725 self.gerrit.replication_retry_interval = 0.5
James E. Blairb0fcae42012-07-17 11:12:10 -0700726 self.fake_gerrit = self.gerrit.gerrit
727
728 self.sched.setLauncher(self.jenkins)
729 self.sched.setTrigger(self.gerrit)
730
731 self.sched.start()
732 self.sched.reconfigure(self.config)
733 self.sched.resume()
734
735 def tearDown(self):
736 self.jenkins.stop()
737 self.gerrit.stop()
738 self.sched.stop()
739 self.sched.join()
James E. Blair412e5582013-04-22 15:50:12 -0700740 self.statsd.stop()
741 self.statsd.join()
James E. Blair1dbd5082012-08-23 15:12:15 -0700742 #shutil.rmtree(TEST_ROOT)
James E. Blairb0fcae42012-07-17 11:12:10 -0700743
744 def waitUntilSettled(self):
745 self.log.debug("Waiting until settled...")
746 start = time.time()
747 while True:
748 if time.time() - start > 10:
749 print 'queue status:',
750 print self.sched.trigger_event_queue.empty(),
751 print self.sched.result_event_queue.empty(),
752 print self.fake_gerrit.event_queue.empty(),
753 raise Exception("Timeout waiting for Zuul to settle")
James E. Blairff791972013-01-09 11:45:43 -0800754 # Make sure our fake jenkins doesn't end any jobs
755 # (and therefore, emit events) while we're checking
756 self.fake_jenkins.lock.acquire()
757 # Join ensures that the queue is empty _and_ events have been
758 # processed
James E. Blairb0fcae42012-07-17 11:12:10 -0700759 self.fake_gerrit.event_queue.join()
James E. Blairff791972013-01-09 11:45:43 -0800760 self.sched.trigger_event_queue.join()
761 self.sched.result_event_queue.join()
James E. Blairb0fcae42012-07-17 11:12:10 -0700762 if (self.sched.trigger_event_queue.empty() and
763 self.sched.result_event_queue.empty() and
764 self.fake_gerrit.event_queue.empty() and
765 self.fake_jenkins.fakeAllWaiting()):
James E. Blairff791972013-01-09 11:45:43 -0800766 self.fake_jenkins.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700767 self.log.debug("...settled.")
768 return
James E. Blairff791972013-01-09 11:45:43 -0800769 self.fake_jenkins.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700770 self.sched.wake_event.wait(0.1)
771
James E. Blaird466dc42012-07-31 10:42:56 -0700772 def countJobResults(self, jobs, result):
James E. Blair0018a6c2013-02-27 14:11:45 -0800773 jobs = filter(lambda x: x.result == result, jobs)
James E. Blaird466dc42012-07-31 10:42:56 -0700774 return len(jobs)
775
James E. Blaire0487072012-08-29 17:38:31 -0700776 def assertEmptyQueues(self):
777 # Make sure there are no orphaned jobs
778 for pipeline in self.sched.pipelines.values():
779 for queue in pipeline.queues:
780 if len(queue.queue) != 0:
James E. Blairf62d4282012-12-31 17:01:50 -0800781 print 'pipeline %s queue %s contents %s' % (
782 pipeline.name, queue.name, queue.queue)
James E. Blaire0487072012-08-29 17:38:31 -0700783 assert len(queue.queue) == 0
784 if len(queue.severed_heads) != 0:
785 print 'heads', queue.severed_heads
786 assert len(queue.severed_heads) == 0
787
James E. Blair412e5582013-04-22 15:50:12 -0700788 def assertReportedStat(self, key, value=None):
789 start = time.time()
790 while time.time() < (start + 5):
791 for stat in self.statsd.stats:
792 k, v = stat.split(':')
793 if key == k:
794 if value is None:
795 return
796 if value == v:
797 return
798 time.sleep(0.1)
799
800 pprint.pprint(self.statsd.stats)
801 raise Exception("Key %s not found in reported stats" % key)
802
James E. Blairb0fcae42012-07-17 11:12:10 -0700803 def test_jobs_launched(self):
804 "Test that jobs are launched and a change is merged"
805 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -0700806 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700807 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
808 self.waitUntilSettled()
809 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -0800810 job_names = [x.name for x in jobs]
James E. Blairb0fcae42012-07-17 11:12:10 -0700811 assert 'project-merge' in job_names
812 assert 'project-test1' in job_names
813 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -0800814 assert jobs[0].result == 'SUCCESS'
815 assert jobs[1].result == 'SUCCESS'
816 assert jobs[2].result == 'SUCCESS'
James E. Blairb0fcae42012-07-17 11:12:10 -0700817 assert A.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700818 assert A.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700819 self.assertEmptyQueues()
James E. Blairb0fcae42012-07-17 11:12:10 -0700820
James E. Blair412e5582013-04-22 15:50:12 -0700821 self.assertReportedStat('gerrit.event.comment-added', '1|c')
822 self.assertReportedStat('zuul.pipeline.gate.current_changes', '1|g')
823 self.assertReportedStat('zuul.job.project-merge')
824 self.assertReportedStat('zuul.pipeline.gate.resident_time')
825 self.assertReportedStat('zuul.pipeline.gate.total_changes', '1|c')
826 self.assertReportedStat(
827 'zuul.pipeline.gate.org.project.resident_time')
828 self.assertReportedStat(
829 'zuul.pipeline.gate.org.project.total_changes', '1|c')
830
James E. Blairb0fcae42012-07-17 11:12:10 -0700831 def test_parallel_changes(self):
832 "Test that changes are tested in parallel and merged in series"
833 self.fake_jenkins.hold_jobs_in_build = True
834 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
835 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
836 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700837 A.addApproval('CRVW', 2)
838 B.addApproval('CRVW', 2)
839 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700840
841 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
842 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
843 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
844
845 self.waitUntilSettled()
846 jobs = self.fake_jenkins.all_jobs
847 assert len(jobs) == 1
848 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700849 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700850
851 self.fake_jenkins.fakeRelease('.*-merge')
852 self.waitUntilSettled()
853 assert len(jobs) == 3
854 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700855 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700856 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700857 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700858 assert jobs[2].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700859 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700860
861 self.fake_jenkins.fakeRelease('.*-merge')
862 self.waitUntilSettled()
863 assert len(jobs) == 5
864 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700865 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700866 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700867 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700868
869 assert jobs[2].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700870 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700871 assert jobs[3].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700872 assert job_has_changes(jobs[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700873
874 assert jobs[4].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700875 assert job_has_changes(jobs[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700876
877 self.fake_jenkins.fakeRelease('.*-merge')
878 self.waitUntilSettled()
879 assert len(jobs) == 6
880 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700881 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700882 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700883 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700884
885 assert jobs[2].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700886 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700887 assert jobs[3].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700888 assert job_has_changes(jobs[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700889
890 assert jobs[4].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700891 assert job_has_changes(jobs[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700892 assert jobs[5].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700893 assert job_has_changes(jobs[5], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700894
895 self.fake_jenkins.hold_jobs_in_build = False
896 self.fake_jenkins.fakeRelease()
897 self.waitUntilSettled()
898 assert len(jobs) == 0
899
900 jobs = self.fake_jenkins.job_history
901 assert len(jobs) == 9
902 assert A.data['status'] == 'MERGED'
903 assert B.data['status'] == 'MERGED'
904 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700905 assert A.reported == 2
906 assert B.reported == 2
907 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700908 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700909
910 def test_failed_changes(self):
911 "Test that a change behind a failed change is retested"
912 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
913 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -0700914 A.addApproval('CRVW', 2)
915 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700916
917 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
918 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
919
James E. Blair4886cc12012-07-18 15:39:41 -0700920 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700921
922 self.waitUntilSettled()
923 jobs = self.fake_jenkins.job_history
924 assert len(jobs) > 6
925 assert A.data['status'] == 'NEW'
926 assert B.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700927 assert A.reported == 2
928 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700929 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700930
931 def test_independent_queues(self):
932 "Test that changes end up in the right queues"
933 self.fake_jenkins.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +0900934 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700935 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
936 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700937 A.addApproval('CRVW', 2)
938 B.addApproval('CRVW', 2)
939 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700940
941 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
942 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
943 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
944
945 jobs = self.fake_jenkins.all_jobs
946 self.waitUntilSettled()
947
948 # There should be one merge job at the head of each queue running
949 assert len(jobs) == 2
950 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700951 assert job_has_changes(jobs[0], A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700952 assert jobs[1].name == 'project1-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700953 assert job_has_changes(jobs[1], B)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700954
955 # Release the current merge jobs
956 self.fake_jenkins.fakeRelease('.*-merge')
957 self.waitUntilSettled()
958 # Release the merge job for project2 which is behind project1
959 self.fake_jenkins.fakeRelease('.*-merge')
960 self.waitUntilSettled()
961
962 # All the test jobs should be running:
963 # project1 (3) + project2 (3) + project (2) = 8
964 assert len(jobs) == 8
965
966 self.fake_jenkins.fakeRelease()
967 self.waitUntilSettled()
968 assert len(jobs) == 0
969
970 jobs = self.fake_jenkins.job_history
971 assert len(jobs) == 11
972 assert A.data['status'] == 'MERGED'
973 assert B.data['status'] == 'MERGED'
974 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700975 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(self):
981 "Test that if a change at the head fails, jobs behind it are canceled"
982 self.fake_jenkins.hold_jobs_in_build = 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
1001 assert len(jobs) == 1
1002 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -07001003 assert job_has_changes(jobs[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001004
1005 self.fake_jenkins.fakeRelease('.*-merge')
1006 self.waitUntilSettled()
1007 self.fake_jenkins.fakeRelease('.*-merge')
1008 self.waitUntilSettled()
1009 self.fake_jenkins.fakeRelease('.*-merge')
1010 self.waitUntilSettled()
1011
1012 assert len(jobs) == 6
1013 assert jobs[0].name == 'project-test1'
1014 assert jobs[1].name == 'project-test2'
1015 assert jobs[2].name == 'project-test1'
1016 assert jobs[3].name == 'project-test2'
1017 assert jobs[4].name == 'project-test1'
1018 assert jobs[5].name == 'project-test2'
1019
1020 jobs[0].release()
1021 self.waitUntilSettled()
1022
James E. Blairec590122012-08-22 15:19:31 -07001023 assert len(jobs) == 2 # project-test2, project-merge for B
James E. Blaird466dc42012-07-31 10:42:56 -07001024 assert self.countJobResults(finished_jobs, 'ABORTED') == 4
1025
1026 self.fake_jenkins.hold_jobs_in_build = False
1027 self.fake_jenkins.fakeRelease()
1028 self.waitUntilSettled()
1029
James E. Blair0018a6c2013-02-27 14:11:45 -08001030 for x in jobs:
1031 print x
1032 for x in finished_jobs:
1033 print x
1034
James E. Blaird466dc42012-07-31 10:42:56 -07001035 assert len(jobs) == 0
1036 assert len(finished_jobs) == 15
1037 assert A.data['status'] == 'NEW'
1038 assert B.data['status'] == 'MERGED'
1039 assert C.data['status'] == 'MERGED'
1040 assert A.reported == 2
1041 assert B.reported == 2
1042 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001043 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -07001044
1045 def test_failed_change_at_head_with_queue(self):
1046 "Test that if a change at the head fails, queued jobs are canceled"
1047 self.fake_jenkins.hold_jobs_in_queue = True
1048
1049 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1050 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1051 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001052 A.addApproval('CRVW', 2)
1053 B.addApproval('CRVW', 2)
1054 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001055
James E. Blair4886cc12012-07-18 15:39:41 -07001056 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001057
1058 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1059 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1060 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1061
1062 self.waitUntilSettled()
1063 jobs = self.fake_jenkins.all_jobs
1064 finished_jobs = self.fake_jenkins.job_history
1065 queue = self.fake_jenkins.queue
1066
1067 assert len(jobs) == 1
1068 assert len(queue) == 1
1069 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -07001070 assert job_has_changes(jobs[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001071
1072 self.fake_jenkins.fakeRelease('.*-merge')
1073 self.waitUntilSettled()
1074 self.fake_jenkins.fakeRelease('.*-merge')
1075 self.waitUntilSettled()
1076 self.fake_jenkins.fakeRelease('.*-merge')
1077 self.waitUntilSettled()
1078
1079 assert len(jobs) == 6
1080 assert len(queue) == 6
1081 assert jobs[0].name == 'project-test1'
1082 assert jobs[1].name == 'project-test2'
1083 assert jobs[2].name == 'project-test1'
1084 assert jobs[3].name == 'project-test2'
1085 assert jobs[4].name == 'project-test1'
1086 assert jobs[5].name == 'project-test2'
1087
1088 jobs[0].release()
1089 self.waitUntilSettled()
1090
James E. Blairec590122012-08-22 15:19:31 -07001091 assert len(jobs) == 2 # project-test2, project-merge for B
1092 assert len(queue) == 2
James E. Blaird466dc42012-07-31 10:42:56 -07001093 assert self.countJobResults(finished_jobs, 'ABORTED') == 0
1094
1095 self.fake_jenkins.hold_jobs_in_queue = False
1096 self.fake_jenkins.fakeRelease()
1097 self.waitUntilSettled()
1098
1099 assert len(jobs) == 0
1100 assert len(finished_jobs) == 11
1101 assert A.data['status'] == 'NEW'
1102 assert B.data['status'] == 'MERGED'
1103 assert C.data['status'] == 'MERGED'
1104 assert A.reported == 2
1105 assert B.reported == 2
1106 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001107 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001108
1109 def test_patch_order(self):
1110 "Test that dependent patches are tested in the right order"
1111 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1112 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1113 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1114 A.addApproval('CRVW', 2)
1115 B.addApproval('CRVW', 2)
1116 C.addApproval('CRVW', 2)
1117
1118 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
1119 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1120 M2.setMerged()
1121 M1.setMerged()
1122
1123 # C -> B -> A -> M1 -> M2
1124 # M2 is here to make sure it is never queried. If it is, it
1125 # means zuul is walking down the entire history of merged
1126 # changes.
1127
1128 C.setDependsOn(B, 1)
1129 B.setDependsOn(A, 1)
1130 A.setDependsOn(M1, 1)
1131 M1.setDependsOn(M2, 1)
1132
1133 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1134
1135 self.waitUntilSettled()
1136
1137 assert A.data['status'] == 'NEW'
1138 assert B.data['status'] == 'NEW'
1139 assert C.data['status'] == 'NEW'
1140
1141 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1142 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1143
1144 self.waitUntilSettled()
1145 assert M2.queried == 0
1146 assert A.data['status'] == 'MERGED'
1147 assert B.data['status'] == 'MERGED'
1148 assert C.data['status'] == 'MERGED'
1149 assert A.reported == 2
1150 assert B.reported == 2
1151 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001152 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001153
1154 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -07001155 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -07001156 # TODO: move to test_gerrit (this is a unit test!)
1157 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair4aea70c2012-07-26 14:23:24 -07001158 a = self.sched.trigger.getChange(1, 2)
1159 mgr = self.sched.pipelines['gate'].manager
1160 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001161
1162 A.addApproval('CRVW', 2)
James E. Blair4aea70c2012-07-26 14:23:24 -07001163 a = self.sched.trigger.getChange(1, 2)
1164 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001165
1166 A.addApproval('APRV', 1)
James E. Blair4aea70c2012-07-26 14:23:24 -07001167 a = self.sched.trigger.getChange(1, 2)
1168 assert self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blaire0487072012-08-29 17:38:31 -07001169 self.assertEmptyQueues()
James E. Blair4886cc12012-07-18 15:39:41 -07001170
1171 def test_build_configuration(self):
1172 "Test that zuul merges the right commits for testing"
1173 self.fake_jenkins.hold_jobs_in_queue = True
1174 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1175 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1176 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1177 A.addApproval('CRVW', 2)
1178 B.addApproval('CRVW', 2)
1179 C.addApproval('CRVW', 2)
1180 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1181 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1182 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1183 self.waitUntilSettled()
1184
1185 jobs = self.fake_jenkins.all_jobs
1186
1187 self.fake_jenkins.fakeRelease('.*-merge')
1188 self.waitUntilSettled()
1189 self.fake_jenkins.fakeRelease('.*-merge')
1190 self.waitUntilSettled()
1191 self.fake_jenkins.fakeRelease('.*-merge')
1192 self.waitUntilSettled()
James E. Blair1dbd5082012-08-23 15:12:15 -07001193
James E. Blair4886cc12012-07-18 15:39:41 -07001194 ref = jobs[-1].parameters['ZUUL_REF']
1195 self.fake_jenkins.hold_jobs_in_queue = False
1196 self.fake_jenkins.fakeRelease()
James E. Blair973721f2012-08-15 10:19:43 -07001197 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -07001198
James E. Blair1dbd5082012-08-23 15:12:15 -07001199 path = os.path.join(GIT_ROOT, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -07001200 repo = git.Repo(path)
1201 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1202 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -07001203 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
1204 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001205 self.assertEmptyQueues()
James E. Blair973721f2012-08-15 10:19:43 -07001206
1207 def test_build_configuration_conflict(self):
1208 "Test that merge conflicts are handled"
1209 self.fake_jenkins.hold_jobs_in_queue = True
1210 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1211 A.addPatchset(['conflict'])
1212 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1213 B.addPatchset(['conflict'])
1214 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1215 A.addApproval('CRVW', 2)
1216 B.addApproval('CRVW', 2)
1217 C.addApproval('CRVW', 2)
1218 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1219 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1220 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1221 self.waitUntilSettled()
1222
1223 jobs = self.fake_jenkins.all_jobs
1224
1225 self.fake_jenkins.fakeRelease('.*-merge')
1226 self.waitUntilSettled()
1227 self.fake_jenkins.fakeRelease('.*-merge')
1228 self.waitUntilSettled()
1229 self.fake_jenkins.fakeRelease('.*-merge')
1230 self.waitUntilSettled()
1231 ref = jobs[-1].parameters['ZUUL_REF']
1232 self.fake_jenkins.hold_jobs_in_queue = False
1233 self.fake_jenkins.fakeRelease()
1234 self.waitUntilSettled()
1235
1236 assert A.data['status'] == 'MERGED'
1237 assert B.data['status'] == 'NEW'
1238 assert C.data['status'] == 'MERGED'
1239 assert A.reported == 2
1240 assert B.reported == 2
1241 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001242 self.assertEmptyQueues()
James E. Blairdaabed22012-08-15 15:38:57 -07001243
1244 def test_post(self):
1245 "Test that post jobs run"
Zhongyue Luo5d556072012-09-21 02:00:47 +09001246 e = {
1247 "type": "ref-updated",
1248 "submitter": {
1249 "name": "User Name",
1250 },
1251 "refUpdate": {
1252 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1253 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1254 "refName": "master",
1255 "project": "org/project",
1256 }
1257 }
James E. Blairdaabed22012-08-15 15:38:57 -07001258 self.fake_gerrit.addEvent(e)
1259 self.waitUntilSettled()
1260
1261 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001262 job_names = [x.name for x in jobs]
James E. Blairdaabed22012-08-15 15:38:57 -07001263 assert len(jobs) == 1
1264 assert 'project-post' in job_names
James E. Blaire0487072012-08-29 17:38:31 -07001265 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001266
1267 def test_build_configuration_branch(self):
1268 "Test that the right commits are on alternate branches"
1269 self.fake_jenkins.hold_jobs_in_queue = True
1270 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1271 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1272 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1273 A.addApproval('CRVW', 2)
1274 B.addApproval('CRVW', 2)
1275 C.addApproval('CRVW', 2)
1276 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1277 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1278 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1279 self.waitUntilSettled()
1280
1281 jobs = self.fake_jenkins.all_jobs
1282
1283 self.fake_jenkins.fakeRelease('.*-merge')
1284 self.waitUntilSettled()
1285 self.fake_jenkins.fakeRelease('.*-merge')
1286 self.waitUntilSettled()
1287 self.fake_jenkins.fakeRelease('.*-merge')
1288 self.waitUntilSettled()
1289 ref = jobs[-1].parameters['ZUUL_REF']
1290 self.fake_jenkins.hold_jobs_in_queue = False
1291 self.fake_jenkins.fakeRelease()
1292 self.waitUntilSettled()
1293
James E. Blair1dbd5082012-08-23 15:12:15 -07001294 path = os.path.join(GIT_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001295 repo = git.Repo(path)
1296 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1297 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001298 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
1299 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001300 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001301
1302 def test_build_configuration_branch_interaction(self):
1303 "Test that switching between branches works"
1304 self.test_build_configuration()
1305 self.test_build_configuration_branch()
1306 # C has been merged, undo that
James E. Blair1dbd5082012-08-23 15:12:15 -07001307 path = os.path.join(UPSTREAM_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001308 repo = git.Repo(path)
1309 repo.heads.master.commit = repo.commit('init')
1310 self.test_build_configuration()
James E. Blaire0487072012-08-29 17:38:31 -07001311 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001312
1313 def test_build_configuration_multi_branch(self):
1314 "Test that dependent changes on multiple branches are merged"
1315 self.fake_jenkins.hold_jobs_in_queue = True
1316 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1317 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1318 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1319 A.addApproval('CRVW', 2)
1320 B.addApproval('CRVW', 2)
1321 C.addApproval('CRVW', 2)
1322 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1323 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1324 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1325 self.waitUntilSettled()
1326
1327 jobs = self.fake_jenkins.all_jobs
1328
1329 self.fake_jenkins.fakeRelease('.*-merge')
1330 self.waitUntilSettled()
1331 ref_mp = jobs[-1].parameters['ZUUL_REF']
1332 self.fake_jenkins.fakeRelease('.*-merge')
1333 self.waitUntilSettled()
1334 self.fake_jenkins.fakeRelease('.*-merge')
1335 self.waitUntilSettled()
1336 ref_master = jobs[-1].parameters['ZUUL_REF']
1337 self.fake_jenkins.hold_jobs_in_queue = False
1338 self.fake_jenkins.fakeRelease()
1339 self.waitUntilSettled()
1340
James E. Blair1dbd5082012-08-23 15:12:15 -07001341 path = os.path.join(GIT_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001342 repo = git.Repo(path)
1343
1344 repo_messages = [c.message.strip()
1345 for c in repo.iter_commits(ref_master)]
1346 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001347 correct_messages = ['initial commit', 'A-1', 'C-1']
1348 assert repo_messages == correct_messages
1349
1350 repo_messages = [c.message.strip()
1351 for c in repo.iter_commits(ref_mp)]
1352 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001353 correct_messages = ['initial commit', 'mp commit', 'B-1']
1354 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001355 self.assertEmptyQueues()
James E. Blair7f71c802012-08-22 13:04:32 -07001356
1357 def test_one_job_project(self):
1358 "Test that queueing works with one job"
1359 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1360 'master', 'A')
1361 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1362 'master', 'B')
1363 A.addApproval('CRVW', 2)
1364 B.addApproval('CRVW', 2)
1365 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1366 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1367 self.waitUntilSettled()
1368
1369 jobs = self.fake_jenkins.all_jobs
1370 finished_jobs = self.fake_jenkins.job_history
James E. Blair7f71c802012-08-22 13:04:32 -07001371
1372 assert A.data['status'] == 'MERGED'
1373 assert A.reported == 2
1374 assert B.data['status'] == 'MERGED'
1375 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001376 self.assertEmptyQueues()
James E. Blaircaec0c52012-08-22 14:52:22 -07001377
Antoine Musso80edd5a2013-02-13 15:37:53 +01001378 def test_job_from_templates_launched(self):
1379 "Test whether a job generated via a template can be launched"
1380 A = self.fake_gerrit.addFakeChange(
1381 'org/templated-project', 'master', 'A')
1382 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1383 self.waitUntilSettled()
1384 jobs = self.fake_jenkins.job_history
1385 job_names = [x.name for x in jobs]
1386
1387 assert 'project-test1' in job_names
1388 assert 'project-test2' in job_names
1389 assert jobs[0].result == 'SUCCESS'
1390 assert jobs[1].result == 'SUCCESS'
1391
James E. Blaircaec0c52012-08-22 14:52:22 -07001392 def test_dependent_changes_dequeue(self):
1393 "Test that dependent patches are not needlessly tested"
1394 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1395 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1396 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1397 A.addApproval('CRVW', 2)
1398 B.addApproval('CRVW', 2)
1399 C.addApproval('CRVW', 2)
1400
1401 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1402 M1.setMerged()
1403
1404 # C -> B -> A -> M1
1405
1406 C.setDependsOn(B, 1)
1407 B.setDependsOn(A, 1)
1408 A.setDependsOn(M1, 1)
1409
1410 self.fake_jenkins.fakeAddFailTest('project-merge', A)
1411
1412 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1413 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1414 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1415
1416 self.waitUntilSettled()
1417
1418 jobs = self.fake_jenkins.all_jobs
1419 finished_jobs = self.fake_jenkins.job_history
1420
James E. Blair127bc182012-08-28 15:55:15 -07001421 for x in jobs:
1422 print x
1423 for x in finished_jobs:
1424 print x
1425
James E. Blairec590122012-08-22 15:19:31 -07001426 assert A.data['status'] == 'NEW'
1427 assert A.reported == 2
1428 assert B.data['status'] == 'NEW'
1429 assert B.reported == 2
1430 assert C.data['status'] == 'NEW'
1431 assert C.reported == 2
1432 assert len(finished_jobs) == 1
James E. Blaire0487072012-08-29 17:38:31 -07001433 self.assertEmptyQueues()
James E. Blairec590122012-08-22 15:19:31 -07001434
1435 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001436 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001437 # If it's dequeued more than once, we should see extra
1438 # aborted jobs.
1439 self.fake_jenkins.hold_jobs_in_build = True
1440
1441 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1442 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1443 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1444 A.addApproval('CRVW', 2)
1445 B.addApproval('CRVW', 2)
1446 C.addApproval('CRVW', 2)
1447
1448 self.fake_jenkins.fakeAddFailTest('project1-test1', A)
1449 self.fake_jenkins.fakeAddFailTest('project1-test2', A)
1450 self.fake_jenkins.fakeAddFailTest('project1-project2-integration', A)
1451
1452 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1453 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1454 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1455
1456 self.waitUntilSettled()
1457 jobs = self.fake_jenkins.all_jobs
1458 finished_jobs = self.fake_jenkins.job_history
1459
1460 assert len(jobs) == 1
1461 assert jobs[0].name == 'project1-merge'
1462 assert job_has_changes(jobs[0], A)
1463
1464 self.fake_jenkins.fakeRelease('.*-merge')
1465 self.waitUntilSettled()
1466 self.fake_jenkins.fakeRelease('.*-merge')
1467 self.waitUntilSettled()
1468 self.fake_jenkins.fakeRelease('.*-merge')
1469 self.waitUntilSettled()
1470
1471 assert len(jobs) == 9
1472 assert jobs[0].name == 'project1-test1'
1473 assert jobs[1].name == 'project1-test2'
1474 assert jobs[2].name == 'project1-project2-integration'
1475 assert jobs[3].name == 'project1-test1'
1476 assert jobs[4].name == 'project1-test2'
1477 assert jobs[5].name == 'project1-project2-integration'
1478 assert jobs[6].name == 'project1-test1'
1479 assert jobs[7].name == 'project1-test2'
1480 assert jobs[8].name == 'project1-project2-integration'
1481
1482 jobs[0].release()
1483 self.waitUntilSettled()
1484
1485 assert len(jobs) == 3 # test2, integration, merge for B
1486 assert self.countJobResults(finished_jobs, 'ABORTED') == 6
1487
1488 self.fake_jenkins.hold_jobs_in_build = False
1489 self.fake_jenkins.fakeRelease()
1490 self.waitUntilSettled()
1491
1492 assert len(jobs) == 0
1493 assert len(finished_jobs) == 20
James E. Blaircaec0c52012-08-22 14:52:22 -07001494
1495 assert A.data['status'] == 'NEW'
James E. Blairec590122012-08-22 15:19:31 -07001496 assert B.data['status'] == 'MERGED'
1497 assert C.data['status'] == 'MERGED'
1498 assert A.reported == 2
1499 assert B.reported == 2
1500 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001501 self.assertEmptyQueues()
James E. Blair4ec821f2012-08-23 15:28:28 -07001502
1503 def test_nonvoting_job(self):
1504 "Test that non-voting jobs don't vote."
1505 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1506 'master', 'A')
1507 A.addApproval('CRVW', 2)
1508 self.fake_jenkins.fakeAddFailTest('nonvoting-project-test2', A)
1509 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1510
1511 self.waitUntilSettled()
1512 jobs = self.fake_jenkins.all_jobs
1513 finished_jobs = self.fake_jenkins.job_history
1514
1515 assert A.data['status'] == 'MERGED'
1516 assert A.reported == 2
James E. Blair0018a6c2013-02-27 14:11:45 -08001517 assert finished_jobs[0].result == 'SUCCESS'
1518 assert finished_jobs[1].result == 'SUCCESS'
1519 assert finished_jobs[2].result == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001520 self.assertEmptyQueues()
1521
1522 def test_check_queue_success(self):
1523 "Test successful check queue jobs."
1524 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1525 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1526
1527 self.waitUntilSettled()
1528 jobs = self.fake_jenkins.all_jobs
1529 finished_jobs = self.fake_jenkins.job_history
1530
1531 assert A.data['status'] == 'NEW'
1532 assert A.reported == 1
James E. Blair0018a6c2013-02-27 14:11:45 -08001533 assert finished_jobs[0].result == 'SUCCESS'
1534 assert finished_jobs[1].result == 'SUCCESS'
1535 assert finished_jobs[2].result == 'SUCCESS'
James E. Blaire0487072012-08-29 17:38:31 -07001536 self.assertEmptyQueues()
1537
1538 def test_check_queue_failure(self):
1539 "Test failed check queue jobs."
1540 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1541 self.fake_jenkins.fakeAddFailTest('project-test2', A)
1542 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1543
1544 self.waitUntilSettled()
1545 jobs = self.fake_jenkins.all_jobs
1546 finished_jobs = self.fake_jenkins.job_history
1547
1548 assert A.data['status'] == 'NEW'
1549 assert A.reported == 1
James E. Blair0018a6c2013-02-27 14:11:45 -08001550 assert finished_jobs[0].result == 'SUCCESS'
1551 assert finished_jobs[1].result == 'SUCCESS'
1552 assert finished_jobs[2].result == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001553 self.assertEmptyQueues()
James E. Blair127bc182012-08-28 15:55:15 -07001554
1555 def test_dependent_behind_dequeue(self):
1556 "test that dependent changes behind dequeued changes work"
1557 # This complicated test is a reproduction of a real life bug
1558 self.sched.reconfigure(self.config)
1559 self.fake_jenkins.hold_jobs_in_build = True
1560
1561 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1562 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1563 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1564 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1565 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1566 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1567 D.setDependsOn(C, 1)
1568 E.setDependsOn(D, 1)
1569 A.addApproval('CRVW', 2)
1570 B.addApproval('CRVW', 2)
1571 C.addApproval('CRVW', 2)
1572 D.addApproval('CRVW', 2)
1573 E.addApproval('CRVW', 2)
1574 F.addApproval('CRVW', 2)
1575
1576 A.fail_merge = True
1577 jobs = self.fake_jenkins.all_jobs
1578 finished_jobs = self.fake_jenkins.job_history
1579
1580 # Change object re-use in the gerrit trigger is hidden if
1581 # changes are added in quick succession; waiting makes it more
1582 # like real life.
1583 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1584 self.waitUntilSettled()
1585 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1586 self.waitUntilSettled()
1587
1588 self.fake_jenkins.fakeRelease('.*-merge')
1589 self.waitUntilSettled()
1590 self.fake_jenkins.fakeRelease('.*-merge')
1591 self.waitUntilSettled()
1592
1593 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1594 self.waitUntilSettled()
1595 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1596 self.waitUntilSettled()
1597 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1598 self.waitUntilSettled()
1599 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1600 self.waitUntilSettled()
1601
1602 self.fake_jenkins.fakeRelease('.*-merge')
1603 self.waitUntilSettled()
1604 self.fake_jenkins.fakeRelease('.*-merge')
1605 self.waitUntilSettled()
1606 self.fake_jenkins.fakeRelease('.*-merge')
1607 self.waitUntilSettled()
1608 self.fake_jenkins.fakeRelease('.*-merge')
1609 self.waitUntilSettled()
1610
James E. Blair4aa1ad62012-10-05 12:39:26 -07001611 for x in jobs:
1612 print x
James E. Blair127bc182012-08-28 15:55:15 -07001613 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001614
1615 # Grab pointers to the jobs we want to release before
1616 # releasing any, because list indexes may change as
1617 # the jobs complete.
1618 a, b, c = jobs[:3]
1619 a.release()
1620 b.release()
1621 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001622 self.waitUntilSettled()
1623
1624 self.fake_jenkins.hold_jobs_in_build = False
1625 self.fake_jenkins.fakeRelease()
1626 self.waitUntilSettled()
1627
1628 for x in jobs:
1629 print x
1630 for x in finished_jobs:
1631 print x
1632 print self.sched.formatStatusHTML()
1633
1634 assert A.data['status'] == 'NEW'
1635 assert B.data['status'] == 'MERGED'
1636 assert C.data['status'] == 'MERGED'
1637 assert D.data['status'] == 'MERGED'
1638 assert E.data['status'] == 'MERGED'
1639 assert F.data['status'] == 'MERGED'
1640
1641 assert A.reported == 2
1642 assert B.reported == 2
1643 assert C.reported == 2
1644 assert D.reported == 2
1645 assert E.reported == 2
1646 assert F.reported == 2
1647
James E. Blair127bc182012-08-28 15:55:15 -07001648 assert self.countJobResults(finished_jobs, 'ABORTED') == 15
1649 assert len(finished_jobs) == 44
James E. Blaire0487072012-08-29 17:38:31 -07001650 self.assertEmptyQueues()
James E. Blair05fed602012-09-07 12:45:24 -07001651
1652 def test_merger_repack(self):
1653 "Test that the merger works after a repack"
1654 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1655 A.addApproval('CRVW', 2)
1656 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1657 self.waitUntilSettled()
1658 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001659 job_names = [x.name for x in jobs]
James E. Blair05fed602012-09-07 12:45:24 -07001660 assert 'project-merge' in job_names
1661 assert 'project-test1' in job_names
1662 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001663 assert jobs[0].result == 'SUCCESS'
1664 assert jobs[1].result == 'SUCCESS'
1665 assert jobs[2].result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001666 assert A.data['status'] == 'MERGED'
1667 assert A.reported == 2
1668 self.assertEmptyQueues()
1669
1670 path = os.path.join(GIT_ROOT, "org/project")
1671 os.system('git --git-dir=%s/.git repack -afd' % path)
1672
1673 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1674 A.addApproval('CRVW', 2)
1675 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1676 self.waitUntilSettled()
1677 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001678 job_names = [x.name for x in jobs]
James E. Blair05fed602012-09-07 12:45:24 -07001679 assert 'project-merge' in job_names
1680 assert 'project-test1' in job_names
1681 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001682 assert jobs[0].result == 'SUCCESS'
1683 assert jobs[1].result == 'SUCCESS'
1684 assert jobs[2].result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001685 assert A.data['status'] == 'MERGED'
1686 assert A.reported == 2
1687 self.assertEmptyQueues()
James E. Blair7ee88a22012-09-12 18:59:31 +02001688
James E. Blair4886f282012-11-15 09:27:33 -08001689 def test_merger_repack_large_change(self):
1690 "Test that the merger works with large changes after a repack"
1691 # https://bugs.launchpad.net/zuul/+bug/1078946
1692 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1693 A.addPatchset(large=True)
1694 path = os.path.join(UPSTREAM_ROOT, "org/project1")
1695 os.system('git --git-dir=%s/.git repack -afd' % path)
1696 path = os.path.join(GIT_ROOT, "org/project1")
1697 os.system('git --git-dir=%s/.git repack -afd' % path)
1698
1699 A.addApproval('CRVW', 2)
1700 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1701 self.waitUntilSettled()
1702 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001703 job_names = [x.name for x in jobs]
James E. Blair4886f282012-11-15 09:27:33 -08001704 assert 'project1-merge' in job_names
1705 assert 'project1-test1' in job_names
1706 assert 'project1-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001707 assert jobs[0].result == 'SUCCESS'
1708 assert jobs[1].result == 'SUCCESS'
1709 assert jobs[2].result == 'SUCCESS'
James E. Blair4886f282012-11-15 09:27:33 -08001710 assert A.data['status'] == 'MERGED'
1711 assert A.reported == 2
1712 self.assertEmptyQueues()
1713
James E. Blair7ee88a22012-09-12 18:59:31 +02001714 def test_nonexistent_job(self):
1715 "Test launching a job that doesn't exist"
1716 self.fake_jenkins.nonexistent_jobs.append('project-merge')
1717 self.jenkins.launch_retry_timeout = 0.1
1718
1719 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1720 A.addApproval('CRVW', 2)
1721 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1722 # There may be a thread about to report a lost change
1723 while A.reported < 2:
1724 self.waitUntilSettled()
1725 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001726 job_names = [x.name for x in jobs]
James E. Blair7ee88a22012-09-12 18:59:31 +02001727 assert not job_names
1728 assert A.data['status'] == 'NEW'
1729 assert A.reported == 2
1730 self.assertEmptyQueues()
1731
1732 # Make sure things still work:
1733 self.fake_jenkins.nonexistent_jobs = []
1734 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1735 A.addApproval('CRVW', 2)
1736 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1737 self.waitUntilSettled()
1738 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001739 job_names = [x.name for x in jobs]
James E. Blair7ee88a22012-09-12 18:59:31 +02001740 assert 'project-merge' in job_names
1741 assert 'project-test1' in job_names
1742 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001743 assert jobs[0].result == 'SUCCESS'
1744 assert jobs[1].result == 'SUCCESS'
1745 assert jobs[2].result == 'SUCCESS'
James E. Blair7ee88a22012-09-12 18:59:31 +02001746 assert A.data['status'] == 'MERGED'
1747 assert A.reported == 2
1748 self.assertEmptyQueues()
James E. Blairf62d4282012-12-31 17:01:50 -08001749
1750 def test_single_nonexistent_post_job(self):
1751 "Test launching a single post job that doesn't exist"
1752 self.fake_jenkins.nonexistent_jobs.append('project-post')
1753 self.jenkins.launch_retry_timeout = 0.1
1754
1755 e = {
1756 "type": "ref-updated",
1757 "submitter": {
1758 "name": "User Name",
1759 },
1760 "refUpdate": {
1761 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1762 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1763 "refName": "master",
1764 "project": "org/project",
1765 }
1766 }
1767 self.fake_gerrit.addEvent(e)
1768 self.waitUntilSettled()
1769
1770 jobs = self.fake_jenkins.job_history
1771 assert len(jobs) == 0
1772 self.assertEmptyQueues()
James E. Blair2fa50962013-01-30 21:50:41 -08001773
1774 def test_new_patchset_dequeues_old(self):
1775 "Test that a new patchset causes the old to be dequeued"
1776 # D -> C (depends on B) -> B (depends on A) -> A -> M
1777 self.fake_jenkins.hold_jobs_in_build = True
1778
1779 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1780 M.setMerged()
1781
1782 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1783 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1784 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1785 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1786 A.addApproval('CRVW', 2)
1787 B.addApproval('CRVW', 2)
1788 C.addApproval('CRVW', 2)
1789 D.addApproval('CRVW', 2)
1790
1791 C.setDependsOn(B, 1)
1792 B.setDependsOn(A, 1)
1793 A.setDependsOn(M, 1)
1794
1795 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1796 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1797 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1798 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1799 self.waitUntilSettled()
1800
1801 B.addPatchset()
1802 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1803 self.waitUntilSettled()
1804
1805 self.fake_jenkins.hold_jobs_in_build = False
1806 self.fake_jenkins.fakeRelease()
1807 self.waitUntilSettled()
1808
1809 jobs = self.fake_jenkins.all_jobs
1810 finished_jobs = self.fake_jenkins.job_history
1811
1812 for x in jobs:
1813 print x
1814 for x in finished_jobs:
1815 print x
1816
1817 assert A.data['status'] == 'MERGED'
1818 assert A.reported == 2
1819 assert B.data['status'] == 'NEW'
1820 assert B.reported == 2
1821 assert C.data['status'] == 'NEW'
1822 assert C.reported == 2
1823 assert D.data['status'] == 'MERGED'
1824 assert D.reported == 2
1825 assert len(finished_jobs) == 9 # 3 each for A, B, D.
1826 self.assertEmptyQueues()
1827
1828 def test_new_patchset_dequeues_old_on_head(self):
1829 "Test that a new patchset causes the old to be dequeued (at head)"
1830 # D -> C (depends on B) -> B (depends on A) -> A -> M
1831 self.fake_jenkins.hold_jobs_in_build = True
1832
1833 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1834 M.setMerged()
1835 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1836 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1837 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1838 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1839 A.addApproval('CRVW', 2)
1840 B.addApproval('CRVW', 2)
1841 C.addApproval('CRVW', 2)
1842 D.addApproval('CRVW', 2)
1843
1844 C.setDependsOn(B, 1)
1845 B.setDependsOn(A, 1)
1846 A.setDependsOn(M, 1)
1847
1848 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1849 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1850 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1851 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1852 self.waitUntilSettled()
1853
1854 A.addPatchset()
1855 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1856 self.waitUntilSettled()
1857
1858 self.fake_jenkins.hold_jobs_in_build = False
1859 self.fake_jenkins.fakeRelease()
1860 self.waitUntilSettled()
1861
1862 jobs = self.fake_jenkins.all_jobs
1863 finished_jobs = self.fake_jenkins.job_history
1864
1865 for x in jobs:
1866 print x
1867 for x in finished_jobs:
1868 print x
1869
1870 assert A.data['status'] == 'NEW'
1871 assert A.reported == 2
1872 assert B.data['status'] == 'NEW'
1873 assert B.reported == 2
1874 assert C.data['status'] == 'NEW'
1875 assert C.reported == 2
1876 assert D.data['status'] == 'MERGED'
1877 assert D.reported == 2
1878 assert len(finished_jobs) == 7
1879 self.assertEmptyQueues()
1880
1881 def test_new_patchset_dequeues_old_without_dependents(self):
1882 "Test that a new patchset causes only the old to be dequeued"
1883 self.fake_jenkins.hold_jobs_in_build = True
1884
1885 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1886 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1887 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1888 A.addApproval('CRVW', 2)
1889 B.addApproval('CRVW', 2)
1890 C.addApproval('CRVW', 2)
1891
1892 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1893 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1894 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1895 self.waitUntilSettled()
1896
1897 B.addPatchset()
1898 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1899 self.waitUntilSettled()
1900
1901 self.fake_jenkins.hold_jobs_in_build = False
1902 self.fake_jenkins.fakeRelease()
1903 self.waitUntilSettled()
1904
1905 jobs = self.fake_jenkins.all_jobs
1906 finished_jobs = self.fake_jenkins.job_history
1907
1908 for x in jobs:
1909 print x
1910 for x in finished_jobs:
1911 print x
1912
1913 assert A.data['status'] == 'MERGED'
1914 assert A.reported == 2
1915 assert B.data['status'] == 'NEW'
1916 assert B.reported == 2
1917 assert C.data['status'] == 'MERGED'
1918 assert C.reported == 2
1919 assert len(finished_jobs) == 9
1920 self.assertEmptyQueues()
1921
1922 def test_new_patchset_dequeues_old_independent_queue(self):
1923 "Test that a new patchset causes the old to be dequeued (independent)"
1924 self.fake_jenkins.hold_jobs_in_build = True
1925
1926 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1927 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1928 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1929 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1930 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1931 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1932 self.waitUntilSettled()
1933
1934 B.addPatchset()
1935 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1936 self.waitUntilSettled()
1937
1938 self.fake_jenkins.hold_jobs_in_build = False
1939 self.fake_jenkins.fakeRelease()
1940 self.waitUntilSettled()
1941
1942 jobs = self.fake_jenkins.all_jobs
1943 finished_jobs = self.fake_jenkins.job_history
1944
1945 for x in jobs:
1946 print x
1947 for x in finished_jobs:
1948 print x
1949
1950 assert A.data['status'] == 'NEW'
1951 assert A.reported == 1
1952 assert B.data['status'] == 'NEW'
1953 assert B.reported == 1
1954 assert C.data['status'] == 'NEW'
1955 assert C.reported == 1
1956 assert len(finished_jobs) == 10
1957 assert self.countJobResults(finished_jobs, 'ABORTED') == 1
1958 self.assertEmptyQueues()
James E. Blair7d0dedc2013-02-21 17:26:09 -08001959
1960 def test_zuul_refs(self):
1961 "Test that zuul refs exist and have the right changes"
1962 self.fake_jenkins.hold_jobs_in_build = True
1963
1964 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
1965 M1.setMerged()
1966 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
1967 M2.setMerged()
1968
1969 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1970 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1971 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1972 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1973 A.addApproval('CRVW', 2)
1974 B.addApproval('CRVW', 2)
1975 C.addApproval('CRVW', 2)
1976 D.addApproval('CRVW', 2)
1977 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1978 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1979 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1980 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1981
1982 self.waitUntilSettled()
1983 self.fake_jenkins.fakeRelease('.*-merge')
1984 self.waitUntilSettled()
1985 self.fake_jenkins.fakeRelease('.*-merge')
1986 self.waitUntilSettled()
1987 self.fake_jenkins.fakeRelease('.*-merge')
1988 self.waitUntilSettled()
1989 self.fake_jenkins.fakeRelease('.*-merge')
1990 self.waitUntilSettled()
1991
1992 jobs = self.fake_jenkins.all_jobs
1993 finished_jobs = self.fake_jenkins.job_history
1994
1995 a_zref = b_zref = c_zref = d_zref = None
1996 for x in jobs:
1997 if x.parameters['ZUUL_CHANGE'] == '3':
1998 a_zref = x.parameters['ZUUL_REF']
1999 if x.parameters['ZUUL_CHANGE'] == '4':
2000 b_zref = x.parameters['ZUUL_REF']
2001 if x.parameters['ZUUL_CHANGE'] == '5':
2002 c_zref = x.parameters['ZUUL_REF']
2003 if x.parameters['ZUUL_CHANGE'] == '6':
2004 d_zref = x.parameters['ZUUL_REF']
2005
2006 # There are... four... refs.
2007 assert a_zref is not None
2008 assert b_zref is not None
2009 assert c_zref is not None
2010 assert d_zref is not None
2011
2012 # And they should all be different
2013 refs = set([a_zref, b_zref, c_zref, d_zref])
2014 assert len(refs) == 4
2015
2016 # a ref should have a, not b, and should not be in project2
2017 assert ref_has_change(a_zref, A)
2018 assert not ref_has_change(a_zref, B)
2019 assert not ref_has_change(a_zref, M2)
2020
2021 # b ref should have a and b, and should not be in project2
2022 assert ref_has_change(b_zref, A)
2023 assert ref_has_change(b_zref, B)
2024 assert not ref_has_change(b_zref, M2)
2025
2026 # c ref should have a and b in 1, c in 2
2027 assert ref_has_change(c_zref, A)
2028 assert ref_has_change(c_zref, B)
2029 assert ref_has_change(c_zref, C)
2030 assert not ref_has_change(c_zref, D)
2031
2032 # d ref should have a and b in 1, c and d in 2
2033 assert ref_has_change(d_zref, A)
2034 assert ref_has_change(d_zref, B)
2035 assert ref_has_change(d_zref, C)
2036 assert ref_has_change(d_zref, D)
2037
2038 self.fake_jenkins.hold_jobs_in_build = False
2039 self.fake_jenkins.fakeRelease()
2040 self.waitUntilSettled()
2041
2042 assert A.data['status'] == 'MERGED'
2043 assert A.reported == 2
2044 assert B.data['status'] == 'MERGED'
2045 assert B.reported == 2
2046 assert C.data['status'] == 'MERGED'
2047 assert C.reported == 2
2048 assert D.data['status'] == 'MERGED'
2049 assert D.reported == 2
2050 self.assertEmptyQueues()
James E. Blair70c71582013-03-06 08:50:50 -08002051
James E. Blair412e5582013-04-22 15:50:12 -07002052 def test_statsd(self):
2053 "Test each of the statsd methods used in the scheduler"
2054 import extras
2055 statsd = extras.try_import('statsd.statsd')
2056 statsd.incr('test-incr')
2057 statsd.timing('test-timing', 3)
2058 statsd.gauge('test-guage', 12)
2059 self.assertReportedStat('test-incr', '1|c')
2060 self.assertReportedStat('test-timing', '3|ms')
2061 self.assertReportedStat('test-guage', '12|g')
2062
James E. Blair70c71582013-03-06 08:50:50 -08002063 def test_file_jobs(self):
2064 "Test that file jobs run only when appropriate"
2065 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2066 A.addPatchset(['pip-requires'])
2067 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2068 A.addApproval('CRVW', 2)
2069 B.addApproval('CRVW', 2)
2070 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2071 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2072 self.waitUntilSettled()
2073
2074 jobs = self.fake_jenkins.all_jobs
2075 finished_jobs = self.fake_jenkins.job_history
2076
2077 testfile_jobs = [x for x in finished_jobs
2078 if x.name == 'project-testfile']
2079
2080 assert len(testfile_jobs) == 1
2081 assert testfile_jobs[0].changes == '1,2'
2082 assert A.data['status'] == 'MERGED'
2083 assert A.reported == 2
2084 assert B.data['status'] == 'MERGED'
2085 assert B.reported == 2
2086 self.assertEmptyQueues()
James E. Blair3c5e5b52013-04-26 11:17:03 -07002087
2088 def test_test_config(self):
2089 "Test that we can test the config"
2090 sched = zuul.scheduler.Scheduler()
2091 sched.testConfig(CONFIG.get('zuul', 'layout_config'))