blob: 2d5fff308cc066f81c7ac0f74bf6411a7b864484 [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
Paul Belangerb67aba12013-05-13 19:22:14 -040077 repo.config_writer().set_value('user', 'email', 'user@example.com')
78 repo.config_writer().set_value('user', 'name', 'User Name')
79 repo.config_writer().write()
80
James E. Blair4886cc12012-07-18 15:39:41 -070081 fn = os.path.join(path, 'README')
82 f = open(fn, 'w')
83 f.write("test\n")
84 f.close()
85 repo.index.add([fn])
86 repo.index.commit('initial commit')
James E. Blairc6294a52012-08-17 10:19:48 -070087 master = repo.create_head('master')
James E. Blair4886cc12012-07-18 15:39:41 -070088 repo.create_tag('init')
89
James E. Blairc6294a52012-08-17 10:19:48 -070090 mp = repo.create_head('mp')
91 repo.head.reference = mp
92 f = open(fn, 'a')
93 f.write("test mp\n")
94 f.close()
95 repo.index.add([fn])
96 repo.index.commit('mp commit')
97
98 repo.head.reference = master
99 repo.head.reset(index=True, working_tree=True)
100 repo.git.clean('-x', '-f', '-d')
101
James E. Blair4886cc12012-07-18 15:39:41 -0700102
James E. Blair4886f282012-11-15 09:27:33 -0800103def add_fake_change_to_repo(project, branch, change_num, patchset, msg, fn,
104 large):
James E. Blair1dbd5082012-08-23 15:12:15 -0700105 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -0700106 repo = git.Repo(path)
107 ref = ChangeReference.create(repo, '1/%s/%s' % (change_num,
108 patchset),
109 'refs/tags/init')
110 repo.head.reference = ref
111 repo.head.reset(index=True, working_tree=True)
112 repo.git.clean('-x', '-f', '-d')
113
James E. Blair1dbd5082012-08-23 15:12:15 -0700114 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886f282012-11-15 09:27:33 -0800115 if not large:
116 fn = os.path.join(path, fn)
117 f = open(fn, 'w')
118 f.write("test %s %s %s\n" % (branch, change_num, patchset))
119 f.close()
120 repo.index.add([fn])
121 else:
122 for fni in range(100):
123 fn = os.path.join(path, str(fni))
124 f = open(fn, 'w')
125 for ci in range(4096):
126 f.write(random.choice(string.printable))
127 f.close()
128 repo.index.add([fn])
129
James E. Blairdaabed22012-08-15 15:38:57 -0700130 return repo.index.commit(msg)
James E. Blair4886cc12012-07-18 15:39:41 -0700131
132
133def ref_has_change(ref, change):
James E. Blair1dbd5082012-08-23 15:12:15 -0700134 path = os.path.join(GIT_ROOT, change.project)
James E. Blair4886cc12012-07-18 15:39:41 -0700135 repo = git.Repo(path)
136 for commit in repo.iter_commits(ref):
137 if commit.message.strip() == ('%s-1' % change.subject):
138 return True
139 return False
140
141
142def job_has_changes(*args):
143 job = args[0]
144 commits = args[1:]
145 project = job.parameters['ZUUL_PROJECT']
James E. Blair1dbd5082012-08-23 15:12:15 -0700146 path = os.path.join(GIT_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -0700147 repo = git.Repo(path)
148 ref = job.parameters['ZUUL_REF']
James E. Blair81515ad2012-10-01 18:29:08 -0700149 sha = job.parameters['ZUUL_COMMIT']
James E. Blair4886cc12012-07-18 15:39:41 -0700150 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
James E. Blair81515ad2012-10-01 18:29:08 -0700151 repo_shas = [c.hexsha for c in repo.iter_commits(ref)]
James E. Blair4886cc12012-07-18 15:39:41 -0700152 commit_messages = ['%s-1' % commit.subject for commit in commits]
James E. Blair4886cc12012-07-18 15:39:41 -0700153 for msg in commit_messages:
154 if msg not in repo_messages:
155 return False
James E. Blair81515ad2012-10-01 18:29:08 -0700156 if repo_shas[0] != sha:
157 return False
James E. Blair4886cc12012-07-18 15:39:41 -0700158 return True
159
160
James E. Blairb0fcae42012-07-17 11:12:10 -0700161class FakeChange(object):
James E. Blair8c803f82012-07-31 16:25:42 -0700162 categories = {'APRV': ('Approved', -1, 1),
163 'CRVW': ('Code-Review', -2, 2),
164 'VRFY': ('Verified', -2, 2)}
James E. Blairb0fcae42012-07-17 11:12:10 -0700165
James E. Blair8cc15a82012-08-01 11:17:57 -0700166 def __init__(self, gerrit, number, project, branch, subject, status='NEW'):
167 self.gerrit = gerrit
James E. Blaird466dc42012-07-31 10:42:56 -0700168 self.reported = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700169 self.queried = 0
James E. Blairb0fcae42012-07-17 11:12:10 -0700170 self.patchsets = []
James E. Blairb0fcae42012-07-17 11:12:10 -0700171 self.number = number
172 self.project = project
173 self.branch = branch
174 self.subject = subject
175 self.latest_patchset = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700176 self.depends_on_change = None
177 self.needed_by_changes = []
James E. Blair127bc182012-08-28 15:55:15 -0700178 self.fail_merge = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700179 self.data = {
180 'branch': branch,
181 'comments': [],
182 'commitMessage': subject,
183 'createdOn': time.time(),
James E. Blair8cc15a82012-08-01 11:17:57 -0700184 'id': 'I' + random_sha1(),
James E. Blairb0fcae42012-07-17 11:12:10 -0700185 'lastUpdated': time.time(),
186 'number': str(number),
187 'open': True,
188 'owner': {'email': 'user@example.com',
189 'name': 'User Name',
190 'username': 'username'},
191 'patchSets': self.patchsets,
192 'project': project,
193 'status': status,
194 'subject': subject,
James E. Blair8c803f82012-07-31 16:25:42 -0700195 'submitRecords': [],
James E. Blairb0fcae42012-07-17 11:12:10 -0700196 'url': 'https://hostname/%s' % number}
197
198 self.addPatchset()
James E. Blair8c803f82012-07-31 16:25:42 -0700199 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700200
James E. Blair70c71582013-03-06 08:50:50 -0800201 def addPatchset(self, files=[], large=False):
James E. Blairb0fcae42012-07-17 11:12:10 -0700202 self.latest_patchset += 1
James E. Blairdaabed22012-08-15 15:38:57 -0700203 if files:
204 fn = files[0]
205 else:
206 fn = '%s-%s' % (self.branch, self.number)
207 msg = self.subject + '-' + str(self.latest_patchset)
208 c = add_fake_change_to_repo(self.project, self.branch,
209 self.number, self.latest_patchset,
James E. Blair4886f282012-11-15 09:27:33 -0800210 msg, fn, large)
James E. Blair70c71582013-03-06 08:50:50 -0800211 ps_files = [{'file': '/COMMIT_MSG',
212 'type': 'ADDED'},
213 {'file': 'README',
214 'type': 'MODIFIED'}]
215 for f in files:
216 ps_files.append({'file': f, 'type': 'ADDED'})
James E. Blairb0fcae42012-07-17 11:12:10 -0700217 d = {'approvals': [],
218 'createdOn': time.time(),
James E. Blair70c71582013-03-06 08:50:50 -0800219 'files': ps_files,
James E. Blair8c803f82012-07-31 16:25:42 -0700220 'number': str(self.latest_patchset),
James E. Blairb0fcae42012-07-17 11:12:10 -0700221 'ref': 'refs/changes/1/%s/%s' % (self.number,
222 self.latest_patchset),
James E. Blairdaabed22012-08-15 15:38:57 -0700223 'revision': c.hexsha,
James E. Blairb0fcae42012-07-17 11:12:10 -0700224 'uploader': {'email': 'user@example.com',
225 'name': 'User name',
226 'username': 'user'}}
227 self.data['currentPatchSet'] = d
228 self.patchsets.append(d)
James E. Blair8c803f82012-07-31 16:25:42 -0700229 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700230
James E. Blaire0487072012-08-29 17:38:31 -0700231 def getPatchsetCreatedEvent(self, patchset):
232 event = {"type": "patchset-created",
233 "change": {"project": self.project,
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800234 "branch": self.branch,
235 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
236 "number": str(self.number),
237 "subject": self.subject,
238 "owner": {"name": "User Name"},
239 "url": "https://hostname/3"},
James E. Blaire0487072012-08-29 17:38:31 -0700240 "patchSet": self.patchsets[patchset - 1],
241 "uploader": {"name": "User Name"}}
242 return event
243
James E. Blairb0fcae42012-07-17 11:12:10 -0700244 def addApproval(self, category, value):
James E. Blair8c803f82012-07-31 16:25:42 -0700245 approval = {'description': self.categories[category][0],
246 'type': category,
247 'value': str(value)}
248 self.patchsets[-1]['approvals'].append(approval)
249 event = {'approvals': [approval],
James E. Blairb0fcae42012-07-17 11:12:10 -0700250 'author': {'email': 'user@example.com',
251 'name': 'User Name',
252 'username': 'username'},
253 'change': {'branch': self.branch,
254 'id': 'Iaa69c46accf97d0598111724a38250ae76a22c87',
255 'number': str(self.number),
256 'owner': {'email': 'user@example.com',
257 'name': 'User Name',
258 'username': 'username'},
259 'project': self.project,
260 'subject': self.subject,
261 'topic': 'master',
262 'url': 'https://hostname/459'},
263 'comment': '',
264 'patchSet': self.patchsets[-1],
265 'type': 'comment-added'}
James E. Blair8c803f82012-07-31 16:25:42 -0700266 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700267 return json.loads(json.dumps(event))
268
James E. Blair8c803f82012-07-31 16:25:42 -0700269 def getSubmitRecords(self):
270 status = {}
271 for cat in self.categories.keys():
272 status[cat] = 0
273
274 for a in self.patchsets[-1]['approvals']:
275 cur = status[a['type']]
276 cat_min, cat_max = self.categories[a['type']][1:]
277 new = int(a['value'])
278 if new == cat_min:
279 cur = new
280 elif abs(new) > abs(cur):
281 cur = new
282 status[a['type']] = cur
283
284 labels = []
285 ok = True
286 for typ, cat in self.categories.items():
287 cur = status[typ]
288 cat_min, cat_max = cat[1:]
289 if cur == cat_min:
290 value = 'REJECT'
291 ok = False
292 elif cur == cat_max:
293 value = 'OK'
294 else:
295 value = 'NEED'
296 ok = False
297 labels.append({'label': cat[0], 'status': value})
298 if ok:
299 return [{'status': 'OK'}]
300 return [{'status': 'NOT_READY',
301 'labels': labels}]
302
303 def setDependsOn(self, other, patchset):
304 self.depends_on_change = other
305 d = {'id': other.data['id'],
306 'number': other.data['number'],
307 'ref': other.patchsets[patchset - 1]['ref']
308 }
309 self.data['dependsOn'] = [d]
310
311 other.needed_by_changes.append(self)
312 needed = other.data.get('neededBy', [])
313 d = {'id': self.data['id'],
314 'number': self.data['number'],
315 'ref': self.patchsets[patchset - 1]['ref'],
316 'revision': self.patchsets[patchset - 1]['revision']
317 }
318 needed.append(d)
319 other.data['neededBy'] = needed
320
James E. Blairb0fcae42012-07-17 11:12:10 -0700321 def query(self):
James E. Blair8c803f82012-07-31 16:25:42 -0700322 self.queried += 1
323 d = self.data.get('dependsOn')
324 if d:
325 d = d[0]
326 if (self.depends_on_change.patchsets[-1]['ref'] == d['ref']):
327 d['isCurrentPatchSet'] = True
328 else:
329 d['isCurrentPatchSet'] = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700330 return json.loads(json.dumps(self.data))
331
332 def setMerged(self):
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800333 if (self.depends_on_change and
334 self.depends_on_change.data['status'] != 'MERGED'):
James E. Blaircaec0c52012-08-22 14:52:22 -0700335 return
James E. Blair127bc182012-08-28 15:55:15 -0700336 if self.fail_merge:
337 return
James E. Blairb0fcae42012-07-17 11:12:10 -0700338 self.data['status'] = 'MERGED'
339 self.open = False
James E. Blairdaabed22012-08-15 15:38:57 -0700340
James E. Blair1dbd5082012-08-23 15:12:15 -0700341 path = os.path.join(UPSTREAM_ROOT, self.project)
James E. Blairdaabed22012-08-15 15:38:57 -0700342 repo = git.Repo(path)
343 repo.heads[self.branch].commit = \
344 repo.commit(self.patchsets[-1]['revision'])
James E. Blairb0fcae42012-07-17 11:12:10 -0700345
James E. Blaird466dc42012-07-31 10:42:56 -0700346 def setReported(self):
347 self.reported += 1
348
James E. Blairb0fcae42012-07-17 11:12:10 -0700349
350class FakeGerrit(object):
351 def __init__(self, *args, **kw):
352 self.event_queue = Queue.Queue()
353 self.fixture_dir = os.path.join(FIXTURE_DIR, 'gerrit')
354 self.change_number = 0
355 self.changes = {}
356
357 def addFakeChange(self, project, branch, subject):
358 self.change_number += 1
James E. Blair8cc15a82012-08-01 11:17:57 -0700359 c = FakeChange(self, self.change_number, project, branch, subject)
James E. Blairb0fcae42012-07-17 11:12:10 -0700360 self.changes[self.change_number] = c
361 return c
362
363 def addEvent(self, data):
364 return self.event_queue.put(data)
365
366 def getEvent(self):
367 return self.event_queue.get()
368
369 def eventDone(self):
370 self.event_queue.task_done()
371
372 def review(self, project, changeid, message, action):
James E. Blaird466dc42012-07-31 10:42:56 -0700373 number, ps = changeid.split(',')
374 change = self.changes[int(number)]
James E. Blairb0fcae42012-07-17 11:12:10 -0700375 if 'submit' in action:
James E. Blairb0fcae42012-07-17 11:12:10 -0700376 change.setMerged()
James E. Blaird466dc42012-07-31 10:42:56 -0700377 if message:
378 change.setReported()
James E. Blairb0fcae42012-07-17 11:12:10 -0700379
380 def query(self, number):
381 change = self.changes[int(number)]
382 return change.query()
383
384 def startWatching(self, *args, **kw):
385 pass
386
387
388class FakeJenkinsEvent(object):
389 def __init__(self, name, number, parameters, phase, status=None):
Zhongyue Luo5d556072012-09-21 02:00:47 +0900390 data = {
391 'build': {
392 'full_url': 'https://server/job/%s/%s/' % (name, number),
393 'number': number,
394 'parameters': parameters,
395 'phase': phase,
396 'url': 'job/%s/%s/' % (name, number),
397 },
398 'name': name,
399 'url': 'job/%s/' % name,
400 }
James E. Blairb0fcae42012-07-17 11:12:10 -0700401 if status:
402 data['build']['status'] = status
403 self.body = json.dumps(data)
404
405
406class FakeJenkinsJob(threading.Thread):
407 log = logging.getLogger("zuul.test")
408
409 def __init__(self, jenkins, callback, name, number, parameters):
410 threading.Thread.__init__(self)
411 self.jenkins = jenkins
412 self.callback = callback
413 self.name = name
414 self.number = number
415 self.parameters = parameters
416 self.wait_condition = threading.Condition()
417 self.waiting = False
James E. Blaird466dc42012-07-31 10:42:56 -0700418 self.aborted = False
419 self.canceled = False
420 self.created = time.time()
James E. Blairb0fcae42012-07-17 11:12:10 -0700421
422 def release(self):
423 self.wait_condition.acquire()
424 self.wait_condition.notify()
425 self.waiting = False
426 self.log.debug("Job %s released" % (self.parameters['UUID']))
427 self.wait_condition.release()
428
429 def isWaiting(self):
430 self.wait_condition.acquire()
431 if self.waiting:
432 ret = True
433 else:
434 ret = False
435 self.wait_condition.release()
436 return ret
437
438 def _wait(self):
439 self.wait_condition.acquire()
440 self.waiting = True
441 self.log.debug("Job %s waiting" % (self.parameters['UUID']))
442 self.wait_condition.wait()
443 self.wait_condition.release()
444
445 def run(self):
446 self.jenkins.fakeEnqueue(self)
447 if self.jenkins.hold_jobs_in_queue:
448 self._wait()
449 self.jenkins.fakeDequeue(self)
James E. Blaird466dc42012-07-31 10:42:56 -0700450 if self.canceled:
451 self.jenkins.all_jobs.remove(self)
452 return
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800453 self.callback.jenkins_endpoint(FakeJenkinsEvent(self.name,
454 self.number,
455 self.parameters,
456 'STARTED'))
James E. Blairb0fcae42012-07-17 11:12:10 -0700457 if self.jenkins.hold_jobs_in_build:
458 self._wait()
459 self.log.debug("Job %s continuing" % (self.parameters['UUID']))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700460
461 result = 'SUCCESS'
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800462 if (('ZUUL_REF' in self.parameters) and
463 self.jenkins.fakeShouldFailTest(self.name,
464 self.parameters['ZUUL_REF'])):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700465 result = 'FAILURE'
James E. Blaird466dc42012-07-31 10:42:56 -0700466 if self.aborted:
467 result = 'ABORTED'
James E. Blairb02a3bb2012-07-30 17:49:55 -0700468
James E. Blair0018a6c2013-02-27 14:11:45 -0800469 changes = None
470 if 'ZUUL_CHANGE_IDS' in self.parameters:
471 changes = self.parameters['ZUUL_CHANGE_IDS']
472
James E. Blairb0fcae42012-07-17 11:12:10 -0700473 self.jenkins.fakeAddHistory(name=self.name, number=self.number,
James E. Blair0018a6c2013-02-27 14:11:45 -0800474 result=result, changes=changes)
James E. Blairff791972013-01-09 11:45:43 -0800475 self.jenkins.lock.acquire()
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800476 self.callback.jenkins_endpoint(FakeJenkinsEvent(self.name,
477 self.number,
478 self.parameters,
479 'COMPLETED',
480 result))
481 self.callback.jenkins_endpoint(FakeJenkinsEvent(self.name,
482 self.number,
483 self.parameters,
484 'FINISHED',
485 result))
James E. Blairb0fcae42012-07-17 11:12:10 -0700486 self.jenkins.all_jobs.remove(self)
James E. Blairff791972013-01-09 11:45:43 -0800487 self.jenkins.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700488
489
490class FakeJenkins(object):
491 log = logging.getLogger("zuul.test")
492
493 def __init__(self, *args, **kw):
494 self.queue = []
495 self.all_jobs = []
496 self.job_counter = {}
James E. Blaird466dc42012-07-31 10:42:56 -0700497 self.queue_counter = 0
James E. Blairb0fcae42012-07-17 11:12:10 -0700498 self.job_history = []
499 self.hold_jobs_in_queue = False
500 self.hold_jobs_in_build = False
James E. Blairb02a3bb2012-07-30 17:49:55 -0700501 self.fail_tests = {}
James E. Blair7ee88a22012-09-12 18:59:31 +0200502 self.nonexistent_jobs = []
James E. Blairff791972013-01-09 11:45:43 -0800503 self.lock = threading.Lock()
James E. Blairb0fcae42012-07-17 11:12:10 -0700504
505 def fakeEnqueue(self, job):
506 self.queue.append(job)
507
508 def fakeDequeue(self, job):
509 self.queue.remove(job)
510
James E. Blair0018a6c2013-02-27 14:11:45 -0800511 class FakeJobHistory(object):
512 def __init__(self, **kw):
513 self.__dict__.update(kw)
514
515 def __repr__(self):
516 return ("<Completed job, result: %s name: %s #%s changes: %s>" %
517 (self.result, self.name, self.number, self.changes))
518
James E. Blairb0fcae42012-07-17 11:12:10 -0700519 def fakeAddHistory(self, **kw):
James E. Blair0018a6c2013-02-27 14:11:45 -0800520 self.job_history.append(self.FakeJobHistory(**kw))
James E. Blairb0fcae42012-07-17 11:12:10 -0700521
522 def fakeRelease(self, regex=None):
523 all_jobs = self.all_jobs[:]
524 self.log.debug("releasing jobs %s (%s)" % (regex, len(self.all_jobs)))
525 for job in all_jobs:
526 if not regex or re.match(regex, job.name):
527 self.log.debug("releasing job %s" % (job.parameters['UUID']))
528 job.release()
529 else:
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800530 self.log.debug("not releasing job %s" %
531 (job.parameters['UUID']))
James E. Blairb0fcae42012-07-17 11:12:10 -0700532 self.log.debug("done releasing jobs %s (%s)" % (regex,
533 len(self.all_jobs)))
534
535 def fakeAllWaiting(self, regex=None):
James E. Blair4aa1ad62012-10-05 12:39:26 -0700536 all_jobs = self.all_jobs[:] + self.queue[:]
James E. Blairb0fcae42012-07-17 11:12:10 -0700537 for job in all_jobs:
538 self.log.debug("job %s %s" % (job.parameters['UUID'],
539 job.isWaiting()))
540 if not job.isWaiting():
541 return False
542 return True
543
James E. Blairb02a3bb2012-07-30 17:49:55 -0700544 def fakeAddFailTest(self, name, change):
545 l = self.fail_tests.get(name, [])
546 l.append(change)
547 self.fail_tests[name] = l
548
James E. Blair4886cc12012-07-18 15:39:41 -0700549 def fakeShouldFailTest(self, name, ref):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700550 l = self.fail_tests.get(name, [])
551 for change in l:
James E. Blair4886cc12012-07-18 15:39:41 -0700552 if ref_has_change(ref, change):
James E. Blairb02a3bb2012-07-30 17:49:55 -0700553 return True
554 return False
555
James E. Blairb0fcae42012-07-17 11:12:10 -0700556 def build_job(self, name, parameters):
James E. Blair7ee88a22012-09-12 18:59:31 +0200557 if name in self.nonexistent_jobs:
558 raise Exception("Job does not exist")
James E. Blairb0fcae42012-07-17 11:12:10 -0700559 count = self.job_counter.get(name, 0)
560 count += 1
561 self.job_counter[name] = count
James E. Blaird466dc42012-07-31 10:42:56 -0700562
563 queue_count = self.queue_counter
564 self.queue_counter += 1
James E. Blairb0fcae42012-07-17 11:12:10 -0700565 job = FakeJenkinsJob(self, self.callback, name, count, parameters)
James E. Blaird466dc42012-07-31 10:42:56 -0700566 job.queue_id = queue_count
567
James E. Blairb0fcae42012-07-17 11:12:10 -0700568 self.all_jobs.append(job)
569 job.start()
570
James E. Blaird466dc42012-07-31 10:42:56 -0700571 def stop_build(self, name, number):
572 for job in self.all_jobs:
573 if job.name == name and job.number == number:
574 job.aborted = True
575 job.release()
576 return
577
578 def cancel_queue(self, id):
579 for job in self.queue:
580 if job.queue_id == id:
581 job.canceled = True
582 job.release()
583 return
584
585 def get_queue_info(self):
586 items = []
James E. Blair1490eba2013-03-06 19:14:00 -0800587 for job in self.queue[:]:
588 self.log.debug("Queue info: %s %s" % (job.name,
589 job.parameters['UUID']))
James E. Blaird466dc42012-07-31 10:42:56 -0700590 paramstr = ''
591 paramlst = []
592 d = {'actions': [{'parameters': paramlst},
593 {'causes': [{'shortDescription':
594 'Started by user Jenkins',
595 'userId': 'jenkins',
596 'userName': 'Jenkins'}]}],
597 'blocked': False,
598 'buildable': True,
599 'buildableStartMilliseconds': (job.created * 1000) + 5,
600 'id': job.queue_id,
601 'inQueueSince': (job.created * 1000),
602 'params': paramstr,
603 'stuck': False,
604 'task': {'color': 'blue',
605 'name': job.name,
606 'url': 'https://server/job/%s/' % job.name},
607 'why': 'Waiting for next available executor'}
608 for k, v in job.parameters.items():
609 paramstr += "\n(StringParameterValue) %s='%s'" % (k, v)
610 pd = {'name': k, 'value': v}
611 paramlst.append(pd)
612 items.append(d)
613 return items
614
James E. Blairb0fcae42012-07-17 11:12:10 -0700615 def set_build_description(self, *args, **kw):
616 pass
617
618
619class FakeJenkinsCallback(zuul.launcher.jenkins.JenkinsCallback):
620 def start(self):
621 pass
622
623
James E. Blair8cc15a82012-08-01 11:17:57 -0700624class FakeURLOpener(object):
625 def __init__(self, fake_gerrit, url):
626 self.fake_gerrit = fake_gerrit
627 self.url = url
628
629 def read(self):
630 res = urlparse.urlparse(self.url)
631 path = res.path
632 project = '/'.join(path.split('/')[2:-2])
James E. Blair35956c52012-09-17 22:13:36 +0200633 ret = '001e# service=git-upload-pack\n'
634 ret += ('000000a31270149696713ba7e06f1beb760f20d359c4abed HEAD\x00'
635 'multi_ack thin-pack side-band side-band-64k ofs-delta '
636 'shallow no-progress include-tag multi_ack_detailed no-done\n')
James E. Blair1dbd5082012-08-23 15:12:15 -0700637 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blairdaabed22012-08-15 15:38:57 -0700638 repo = git.Repo(path)
639 for ref in repo.refs:
James E. Blair35956c52012-09-17 22:13:36 +0200640 r = ref.object.hexsha + ' ' + ref.path + '\n'
641 ret += '%04x%s' % (len(r) + 4, r)
642 ret += '0000'
James E. Blair8cc15a82012-08-01 11:17:57 -0700643 return ret
644
645
James E. Blair4886cc12012-07-18 15:39:41 -0700646class FakeGerritTrigger(zuul.trigger.gerrit.Gerrit):
647 def getGitUrl(self, project):
James E. Blair1dbd5082012-08-23 15:12:15 -0700648 return os.path.join(UPSTREAM_ROOT, project.name)
James E. Blair4886cc12012-07-18 15:39:41 -0700649
650
James E. Blair412e5582013-04-22 15:50:12 -0700651class FakeStatsd(threading.Thread):
652 def __init__(self):
653 threading.Thread.__init__(self)
654 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
655 self.sock.bind(('', 0))
656 self.port = self.sock.getsockname()[1]
657 self.wake_read, self.wake_write = os.pipe()
658 self.stats = []
659
660 def run(self):
661 while True:
Ori Livnehd75cc182013-05-02 18:44:46 -0700662 read_ready = select.select([self.sock, self.wake_read], [], [])[0]
663 for sock in read_ready:
664 if sock is self.sock:
James E. Blair412e5582013-04-22 15:50:12 -0700665 data = self.sock.recvfrom(1024)
666 if not data:
667 return
668 self.stats.append(data[0])
Ori Livnehd75cc182013-05-02 18:44:46 -0700669 else:
670 # wake_read
James E. Blair412e5582013-04-22 15:50:12 -0700671 return
672
673 def stop(self):
674 os.write(self.wake_write, '1\n')
675
676
James E. Blairb0fcae42012-07-17 11:12:10 -0700677class testScheduler(unittest.TestCase):
678 log = logging.getLogger("zuul.test")
679
680 def setUp(self):
James E. Blair1dbd5082012-08-23 15:12:15 -0700681 if os.path.exists(TEST_ROOT):
682 shutil.rmtree(TEST_ROOT)
683 os.makedirs(TEST_ROOT)
684 os.makedirs(UPSTREAM_ROOT)
685 os.makedirs(GIT_ROOT)
James E. Blair4886cc12012-07-18 15:39:41 -0700686
687 # For each project in config:
688 init_repo("org/project")
689 init_repo("org/project1")
690 init_repo("org/project2")
James E. Blair127bc182012-08-28 15:55:15 -0700691 init_repo("org/project3")
James E. Blair7f71c802012-08-22 13:04:32 -0700692 init_repo("org/one-job-project")
James E. Blair4ec821f2012-08-23 15:28:28 -0700693 init_repo("org/nonvoting-project")
Antoine Musso80edd5a2013-02-13 15:37:53 +0100694 init_repo("org/templated-project")
James E. Blairb0fcae42012-07-17 11:12:10 -0700695 self.config = CONFIG
James E. Blair412e5582013-04-22 15:50:12 -0700696
697 self.statsd = FakeStatsd()
698 os.environ['STATSD_HOST'] = 'localhost'
699 os.environ['STATSD_PORT'] = str(self.statsd.port)
700 self.statsd.start()
701 # the statsd client object is configured in the statsd module import
702 reload(statsd)
703 reload(zuul.scheduler)
704
James E. Blairb0fcae42012-07-17 11:12:10 -0700705 self.sched = zuul.scheduler.Scheduler()
706
707 def jenkinsFactory(*args, **kw):
708 self.fake_jenkins = FakeJenkins()
709 return self.fake_jenkins
710
711 def jenkinsCallbackFactory(*args, **kw):
712 self.fake_jenkins_callback = FakeJenkinsCallback(*args, **kw)
713 return self.fake_jenkins_callback
714
James E. Blair8cc15a82012-08-01 11:17:57 -0700715 def URLOpenerFactory(*args, **kw):
716 args = [self.fake_gerrit] + list(args)
717 return FakeURLOpener(*args, **kw)
718
James E. Blairb0fcae42012-07-17 11:12:10 -0700719 zuul.launcher.jenkins.ExtendedJenkins = jenkinsFactory
720 zuul.launcher.jenkins.JenkinsCallback = jenkinsCallbackFactory
James E. Blair8cc15a82012-08-01 11:17:57 -0700721 urllib2.urlopen = URLOpenerFactory
James E. Blairb0fcae42012-07-17 11:12:10 -0700722 self.jenkins = zuul.launcher.jenkins.Jenkins(self.config, self.sched)
723 self.fake_jenkins.callback = self.fake_jenkins_callback
724
725 zuul.lib.gerrit.Gerrit = FakeGerrit
726
James E. Blair4886cc12012-07-18 15:39:41 -0700727 self.gerrit = FakeGerritTrigger(self.config, self.sched)
James E. Blair8cc15a82012-08-01 11:17:57 -0700728 self.gerrit.replication_timeout = 1.5
729 self.gerrit.replication_retry_interval = 0.5
James E. Blairb0fcae42012-07-17 11:12:10 -0700730 self.fake_gerrit = self.gerrit.gerrit
731
732 self.sched.setLauncher(self.jenkins)
733 self.sched.setTrigger(self.gerrit)
734
735 self.sched.start()
736 self.sched.reconfigure(self.config)
737 self.sched.resume()
738
739 def tearDown(self):
740 self.jenkins.stop()
741 self.gerrit.stop()
742 self.sched.stop()
743 self.sched.join()
James E. Blair412e5582013-04-22 15:50:12 -0700744 self.statsd.stop()
745 self.statsd.join()
James E. Blair1dbd5082012-08-23 15:12:15 -0700746 #shutil.rmtree(TEST_ROOT)
James E. Blairb0fcae42012-07-17 11:12:10 -0700747
748 def waitUntilSettled(self):
749 self.log.debug("Waiting until settled...")
750 start = time.time()
751 while True:
752 if time.time() - start > 10:
753 print 'queue status:',
754 print self.sched.trigger_event_queue.empty(),
755 print self.sched.result_event_queue.empty(),
756 print self.fake_gerrit.event_queue.empty(),
757 raise Exception("Timeout waiting for Zuul to settle")
James E. Blairff791972013-01-09 11:45:43 -0800758 # Make sure our fake jenkins doesn't end any jobs
759 # (and therefore, emit events) while we're checking
760 self.fake_jenkins.lock.acquire()
761 # Join ensures that the queue is empty _and_ events have been
762 # processed
James E. Blairb0fcae42012-07-17 11:12:10 -0700763 self.fake_gerrit.event_queue.join()
James E. Blairff791972013-01-09 11:45:43 -0800764 self.sched.trigger_event_queue.join()
765 self.sched.result_event_queue.join()
James E. Blairb0fcae42012-07-17 11:12:10 -0700766 if (self.sched.trigger_event_queue.empty() and
767 self.sched.result_event_queue.empty() and
768 self.fake_gerrit.event_queue.empty() and
769 self.fake_jenkins.fakeAllWaiting()):
James E. Blairff791972013-01-09 11:45:43 -0800770 self.fake_jenkins.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700771 self.log.debug("...settled.")
772 return
James E. Blairff791972013-01-09 11:45:43 -0800773 self.fake_jenkins.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700774 self.sched.wake_event.wait(0.1)
775
James E. Blaird466dc42012-07-31 10:42:56 -0700776 def countJobResults(self, jobs, result):
James E. Blair0018a6c2013-02-27 14:11:45 -0800777 jobs = filter(lambda x: x.result == result, jobs)
James E. Blaird466dc42012-07-31 10:42:56 -0700778 return len(jobs)
779
James E. Blaire0487072012-08-29 17:38:31 -0700780 def assertEmptyQueues(self):
781 # Make sure there are no orphaned jobs
782 for pipeline in self.sched.pipelines.values():
783 for queue in pipeline.queues:
784 if len(queue.queue) != 0:
James E. Blairf62d4282012-12-31 17:01:50 -0800785 print 'pipeline %s queue %s contents %s' % (
786 pipeline.name, queue.name, queue.queue)
James E. Blaire0487072012-08-29 17:38:31 -0700787 assert len(queue.queue) == 0
788 if len(queue.severed_heads) != 0:
789 print 'heads', queue.severed_heads
790 assert len(queue.severed_heads) == 0
791
James E. Blair412e5582013-04-22 15:50:12 -0700792 def assertReportedStat(self, key, value=None):
793 start = time.time()
794 while time.time() < (start + 5):
795 for stat in self.statsd.stats:
796 k, v = stat.split(':')
797 if key == k:
798 if value is None:
799 return
800 if value == v:
801 return
802 time.sleep(0.1)
803
804 pprint.pprint(self.statsd.stats)
805 raise Exception("Key %s not found in reported stats" % key)
806
James E. Blairb0fcae42012-07-17 11:12:10 -0700807 def test_jobs_launched(self):
808 "Test that jobs are launched and a change is merged"
809 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -0700810 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700811 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
812 self.waitUntilSettled()
813 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -0800814 job_names = [x.name for x in jobs]
James E. Blairb0fcae42012-07-17 11:12:10 -0700815 assert 'project-merge' in job_names
816 assert 'project-test1' in job_names
817 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -0800818 assert jobs[0].result == 'SUCCESS'
819 assert jobs[1].result == 'SUCCESS'
820 assert jobs[2].result == 'SUCCESS'
James E. Blairb0fcae42012-07-17 11:12:10 -0700821 assert A.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700822 assert A.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700823 self.assertEmptyQueues()
James E. Blairb0fcae42012-07-17 11:12:10 -0700824
James E. Blair412e5582013-04-22 15:50:12 -0700825 self.assertReportedStat('gerrit.event.comment-added', '1|c')
826 self.assertReportedStat('zuul.pipeline.gate.current_changes', '1|g')
827 self.assertReportedStat('zuul.job.project-merge')
828 self.assertReportedStat('zuul.pipeline.gate.resident_time')
829 self.assertReportedStat('zuul.pipeline.gate.total_changes', '1|c')
830 self.assertReportedStat(
831 'zuul.pipeline.gate.org.project.resident_time')
832 self.assertReportedStat(
833 'zuul.pipeline.gate.org.project.total_changes', '1|c')
834
James E. Blairb0fcae42012-07-17 11:12:10 -0700835 def test_parallel_changes(self):
836 "Test that changes are tested in parallel and merged in series"
837 self.fake_jenkins.hold_jobs_in_build = True
838 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
839 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
840 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700841 A.addApproval('CRVW', 2)
842 B.addApproval('CRVW', 2)
843 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700844
845 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
846 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
847 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
848
849 self.waitUntilSettled()
850 jobs = self.fake_jenkins.all_jobs
851 assert len(jobs) == 1
852 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700853 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700854
855 self.fake_jenkins.fakeRelease('.*-merge')
856 self.waitUntilSettled()
857 assert len(jobs) == 3
858 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700859 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700860 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700861 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700862 assert jobs[2].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700863 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700864
865 self.fake_jenkins.fakeRelease('.*-merge')
866 self.waitUntilSettled()
867 assert len(jobs) == 5
868 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700869 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700870 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700871 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700872
873 assert jobs[2].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700874 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700875 assert jobs[3].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700876 assert job_has_changes(jobs[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700877
878 assert jobs[4].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700879 assert job_has_changes(jobs[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700880
881 self.fake_jenkins.fakeRelease('.*-merge')
882 self.waitUntilSettled()
883 assert len(jobs) == 6
884 assert jobs[0].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700885 assert job_has_changes(jobs[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700886 assert jobs[1].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700887 assert job_has_changes(jobs[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700888
889 assert jobs[2].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700890 assert job_has_changes(jobs[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700891 assert jobs[3].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700892 assert job_has_changes(jobs[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700893
894 assert jobs[4].name == 'project-test1'
James E. Blair4886cc12012-07-18 15:39:41 -0700895 assert job_has_changes(jobs[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700896 assert jobs[5].name == 'project-test2'
James E. Blair4886cc12012-07-18 15:39:41 -0700897 assert job_has_changes(jobs[5], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -0700898
899 self.fake_jenkins.hold_jobs_in_build = False
900 self.fake_jenkins.fakeRelease()
901 self.waitUntilSettled()
902 assert len(jobs) == 0
903
904 jobs = self.fake_jenkins.job_history
905 assert len(jobs) == 9
906 assert A.data['status'] == 'MERGED'
907 assert B.data['status'] == 'MERGED'
908 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700909 assert A.reported == 2
910 assert B.reported == 2
911 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700912 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700913
914 def test_failed_changes(self):
915 "Test that a change behind a failed change is retested"
916 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
917 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -0700918 A.addApproval('CRVW', 2)
919 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700920
921 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
922 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
923
James E. Blair4886cc12012-07-18 15:39:41 -0700924 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700925
926 self.waitUntilSettled()
927 jobs = self.fake_jenkins.job_history
928 assert len(jobs) > 6
929 assert A.data['status'] == 'NEW'
930 assert B.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700931 assert A.reported == 2
932 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700933 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700934
935 def test_independent_queues(self):
936 "Test that changes end up in the right queues"
937 self.fake_jenkins.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +0900938 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700939 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
940 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700941 A.addApproval('CRVW', 2)
942 B.addApproval('CRVW', 2)
943 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700944
945 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
946 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
947 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
948
949 jobs = self.fake_jenkins.all_jobs
950 self.waitUntilSettled()
951
952 # There should be one merge job at the head of each queue running
953 assert len(jobs) == 2
954 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700955 assert job_has_changes(jobs[0], A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700956 assert jobs[1].name == 'project1-merge'
James E. Blair4886cc12012-07-18 15:39:41 -0700957 assert job_has_changes(jobs[1], B)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700958
959 # Release the current merge jobs
960 self.fake_jenkins.fakeRelease('.*-merge')
961 self.waitUntilSettled()
962 # Release the merge job for project2 which is behind project1
963 self.fake_jenkins.fakeRelease('.*-merge')
964 self.waitUntilSettled()
965
966 # All the test jobs should be running:
967 # project1 (3) + project2 (3) + project (2) = 8
968 assert len(jobs) == 8
969
970 self.fake_jenkins.fakeRelease()
971 self.waitUntilSettled()
972 assert len(jobs) == 0
973
974 jobs = self.fake_jenkins.job_history
975 assert len(jobs) == 11
976 assert A.data['status'] == 'MERGED'
977 assert B.data['status'] == 'MERGED'
978 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700979 assert A.reported == 2
980 assert B.reported == 2
981 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700982 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -0700983
984 def test_failed_change_at_head(self):
985 "Test that if a change at the head fails, jobs behind it are canceled"
986 self.fake_jenkins.hold_jobs_in_build = True
987
988 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
989 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
990 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700991 A.addApproval('CRVW', 2)
992 B.addApproval('CRVW', 2)
993 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700994
James E. Blair4886cc12012-07-18 15:39:41 -0700995 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700996
997 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
998 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
999 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1000
1001 self.waitUntilSettled()
1002 jobs = self.fake_jenkins.all_jobs
1003 finished_jobs = self.fake_jenkins.job_history
1004
1005 assert len(jobs) == 1
1006 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -07001007 assert job_has_changes(jobs[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001008
1009 self.fake_jenkins.fakeRelease('.*-merge')
1010 self.waitUntilSettled()
1011 self.fake_jenkins.fakeRelease('.*-merge')
1012 self.waitUntilSettled()
1013 self.fake_jenkins.fakeRelease('.*-merge')
1014 self.waitUntilSettled()
1015
1016 assert len(jobs) == 6
1017 assert jobs[0].name == 'project-test1'
1018 assert jobs[1].name == 'project-test2'
1019 assert jobs[2].name == 'project-test1'
1020 assert jobs[3].name == 'project-test2'
1021 assert jobs[4].name == 'project-test1'
1022 assert jobs[5].name == 'project-test2'
1023
1024 jobs[0].release()
1025 self.waitUntilSettled()
1026
James E. Blairec590122012-08-22 15:19:31 -07001027 assert len(jobs) == 2 # project-test2, project-merge for B
James E. Blaird466dc42012-07-31 10:42:56 -07001028 assert self.countJobResults(finished_jobs, 'ABORTED') == 4
1029
1030 self.fake_jenkins.hold_jobs_in_build = False
1031 self.fake_jenkins.fakeRelease()
1032 self.waitUntilSettled()
1033
James E. Blair0018a6c2013-02-27 14:11:45 -08001034 for x in jobs:
1035 print x
1036 for x in finished_jobs:
1037 print x
1038
James E. Blaird466dc42012-07-31 10:42:56 -07001039 assert len(jobs) == 0
1040 assert len(finished_jobs) == 15
1041 assert A.data['status'] == 'NEW'
1042 assert B.data['status'] == 'MERGED'
1043 assert C.data['status'] == 'MERGED'
1044 assert A.reported == 2
1045 assert B.reported == 2
1046 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001047 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -07001048
1049 def test_failed_change_at_head_with_queue(self):
1050 "Test that if a change at the head fails, queued jobs are canceled"
1051 self.fake_jenkins.hold_jobs_in_queue = True
1052
1053 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1054 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1055 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001056 A.addApproval('CRVW', 2)
1057 B.addApproval('CRVW', 2)
1058 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001059
James E. Blair4886cc12012-07-18 15:39:41 -07001060 self.fake_jenkins.fakeAddFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001061
1062 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1063 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1064 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1065
1066 self.waitUntilSettled()
1067 jobs = self.fake_jenkins.all_jobs
1068 finished_jobs = self.fake_jenkins.job_history
1069 queue = self.fake_jenkins.queue
1070
1071 assert len(jobs) == 1
1072 assert len(queue) == 1
1073 assert jobs[0].name == 'project-merge'
James E. Blair4886cc12012-07-18 15:39:41 -07001074 assert job_has_changes(jobs[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001075
1076 self.fake_jenkins.fakeRelease('.*-merge')
1077 self.waitUntilSettled()
1078 self.fake_jenkins.fakeRelease('.*-merge')
1079 self.waitUntilSettled()
1080 self.fake_jenkins.fakeRelease('.*-merge')
1081 self.waitUntilSettled()
1082
1083 assert len(jobs) == 6
1084 assert len(queue) == 6
1085 assert jobs[0].name == 'project-test1'
1086 assert jobs[1].name == 'project-test2'
1087 assert jobs[2].name == 'project-test1'
1088 assert jobs[3].name == 'project-test2'
1089 assert jobs[4].name == 'project-test1'
1090 assert jobs[5].name == 'project-test2'
1091
1092 jobs[0].release()
1093 self.waitUntilSettled()
1094
James E. Blairec590122012-08-22 15:19:31 -07001095 assert len(jobs) == 2 # project-test2, project-merge for B
1096 assert len(queue) == 2
James E. Blaird466dc42012-07-31 10:42:56 -07001097 assert self.countJobResults(finished_jobs, 'ABORTED') == 0
1098
1099 self.fake_jenkins.hold_jobs_in_queue = False
1100 self.fake_jenkins.fakeRelease()
1101 self.waitUntilSettled()
1102
1103 assert len(jobs) == 0
1104 assert len(finished_jobs) == 11
1105 assert A.data['status'] == 'NEW'
1106 assert B.data['status'] == 'MERGED'
1107 assert C.data['status'] == 'MERGED'
1108 assert A.reported == 2
1109 assert B.reported == 2
1110 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001111 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001112
1113 def test_patch_order(self):
1114 "Test that dependent patches are tested in the right order"
1115 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1116 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1117 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1118 A.addApproval('CRVW', 2)
1119 B.addApproval('CRVW', 2)
1120 C.addApproval('CRVW', 2)
1121
1122 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
1123 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1124 M2.setMerged()
1125 M1.setMerged()
1126
1127 # C -> B -> A -> M1 -> M2
1128 # M2 is here to make sure it is never queried. If it is, it
1129 # means zuul is walking down the entire history of merged
1130 # changes.
1131
1132 C.setDependsOn(B, 1)
1133 B.setDependsOn(A, 1)
1134 A.setDependsOn(M1, 1)
1135 M1.setDependsOn(M2, 1)
1136
1137 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1138
1139 self.waitUntilSettled()
1140
1141 assert A.data['status'] == 'NEW'
1142 assert B.data['status'] == 'NEW'
1143 assert C.data['status'] == 'NEW'
1144
1145 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1146 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1147
1148 self.waitUntilSettled()
1149 assert M2.queried == 0
1150 assert A.data['status'] == 'MERGED'
1151 assert B.data['status'] == 'MERGED'
1152 assert C.data['status'] == 'MERGED'
1153 assert A.reported == 2
1154 assert B.reported == 2
1155 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001156 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001157
1158 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -07001159 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -07001160 # TODO: move to test_gerrit (this is a unit test!)
1161 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair4aea70c2012-07-26 14:23:24 -07001162 a = self.sched.trigger.getChange(1, 2)
1163 mgr = self.sched.pipelines['gate'].manager
1164 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001165
1166 A.addApproval('CRVW', 2)
James E. Blair4aea70c2012-07-26 14:23:24 -07001167 a = self.sched.trigger.getChange(1, 2)
1168 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001169
1170 A.addApproval('APRV', 1)
James E. Blair4aea70c2012-07-26 14:23:24 -07001171 a = self.sched.trigger.getChange(1, 2)
1172 assert self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blaire0487072012-08-29 17:38:31 -07001173 self.assertEmptyQueues()
James E. Blair4886cc12012-07-18 15:39:41 -07001174
1175 def test_build_configuration(self):
1176 "Test that zuul merges the right commits for testing"
1177 self.fake_jenkins.hold_jobs_in_queue = True
1178 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1179 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1180 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1181 A.addApproval('CRVW', 2)
1182 B.addApproval('CRVW', 2)
1183 C.addApproval('CRVW', 2)
1184 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1185 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1186 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1187 self.waitUntilSettled()
1188
1189 jobs = self.fake_jenkins.all_jobs
1190
1191 self.fake_jenkins.fakeRelease('.*-merge')
1192 self.waitUntilSettled()
1193 self.fake_jenkins.fakeRelease('.*-merge')
1194 self.waitUntilSettled()
1195 self.fake_jenkins.fakeRelease('.*-merge')
1196 self.waitUntilSettled()
James E. Blair1dbd5082012-08-23 15:12:15 -07001197
James E. Blair4886cc12012-07-18 15:39:41 -07001198 ref = jobs[-1].parameters['ZUUL_REF']
1199 self.fake_jenkins.hold_jobs_in_queue = False
1200 self.fake_jenkins.fakeRelease()
James E. Blair973721f2012-08-15 10:19:43 -07001201 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -07001202
James E. Blair1dbd5082012-08-23 15:12:15 -07001203 path = os.path.join(GIT_ROOT, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -07001204 repo = git.Repo(path)
1205 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1206 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -07001207 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
1208 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001209 self.assertEmptyQueues()
James E. Blair973721f2012-08-15 10:19:43 -07001210
1211 def test_build_configuration_conflict(self):
1212 "Test that merge conflicts are handled"
1213 self.fake_jenkins.hold_jobs_in_queue = True
1214 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1215 A.addPatchset(['conflict'])
1216 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1217 B.addPatchset(['conflict'])
1218 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1219 A.addApproval('CRVW', 2)
1220 B.addApproval('CRVW', 2)
1221 C.addApproval('CRVW', 2)
1222 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1223 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1224 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1225 self.waitUntilSettled()
1226
1227 jobs = self.fake_jenkins.all_jobs
1228
1229 self.fake_jenkins.fakeRelease('.*-merge')
1230 self.waitUntilSettled()
1231 self.fake_jenkins.fakeRelease('.*-merge')
1232 self.waitUntilSettled()
1233 self.fake_jenkins.fakeRelease('.*-merge')
1234 self.waitUntilSettled()
1235 ref = jobs[-1].parameters['ZUUL_REF']
1236 self.fake_jenkins.hold_jobs_in_queue = False
1237 self.fake_jenkins.fakeRelease()
1238 self.waitUntilSettled()
1239
1240 assert A.data['status'] == 'MERGED'
1241 assert B.data['status'] == 'NEW'
1242 assert C.data['status'] == 'MERGED'
1243 assert A.reported == 2
1244 assert B.reported == 2
1245 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001246 self.assertEmptyQueues()
James E. Blairdaabed22012-08-15 15:38:57 -07001247
1248 def test_post(self):
1249 "Test that post jobs run"
Zhongyue Luo5d556072012-09-21 02:00:47 +09001250 e = {
1251 "type": "ref-updated",
1252 "submitter": {
1253 "name": "User Name",
1254 },
1255 "refUpdate": {
1256 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1257 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1258 "refName": "master",
1259 "project": "org/project",
1260 }
1261 }
James E. Blairdaabed22012-08-15 15:38:57 -07001262 self.fake_gerrit.addEvent(e)
1263 self.waitUntilSettled()
1264
1265 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001266 job_names = [x.name for x in jobs]
James E. Blairdaabed22012-08-15 15:38:57 -07001267 assert len(jobs) == 1
1268 assert 'project-post' in job_names
James E. Blaire0487072012-08-29 17:38:31 -07001269 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001270
1271 def test_build_configuration_branch(self):
1272 "Test that the right commits are on alternate branches"
1273 self.fake_jenkins.hold_jobs_in_queue = True
1274 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1275 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1276 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1277 A.addApproval('CRVW', 2)
1278 B.addApproval('CRVW', 2)
1279 C.addApproval('CRVW', 2)
1280 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1281 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1282 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1283 self.waitUntilSettled()
1284
1285 jobs = self.fake_jenkins.all_jobs
1286
1287 self.fake_jenkins.fakeRelease('.*-merge')
1288 self.waitUntilSettled()
1289 self.fake_jenkins.fakeRelease('.*-merge')
1290 self.waitUntilSettled()
1291 self.fake_jenkins.fakeRelease('.*-merge')
1292 self.waitUntilSettled()
1293 ref = jobs[-1].parameters['ZUUL_REF']
1294 self.fake_jenkins.hold_jobs_in_queue = False
1295 self.fake_jenkins.fakeRelease()
1296 self.waitUntilSettled()
1297
James E. Blair1dbd5082012-08-23 15:12:15 -07001298 path = os.path.join(GIT_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001299 repo = git.Repo(path)
1300 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1301 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001302 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
1303 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001304 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001305
1306 def test_build_configuration_branch_interaction(self):
1307 "Test that switching between branches works"
1308 self.test_build_configuration()
1309 self.test_build_configuration_branch()
1310 # C has been merged, undo that
James E. Blair1dbd5082012-08-23 15:12:15 -07001311 path = os.path.join(UPSTREAM_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001312 repo = git.Repo(path)
1313 repo.heads.master.commit = repo.commit('init')
1314 self.test_build_configuration()
James E. Blaire0487072012-08-29 17:38:31 -07001315 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001316
1317 def test_build_configuration_multi_branch(self):
1318 "Test that dependent changes on multiple branches are merged"
1319 self.fake_jenkins.hold_jobs_in_queue = True
1320 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1321 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1322 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1323 A.addApproval('CRVW', 2)
1324 B.addApproval('CRVW', 2)
1325 C.addApproval('CRVW', 2)
1326 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1327 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1328 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1329 self.waitUntilSettled()
1330
1331 jobs = self.fake_jenkins.all_jobs
1332
1333 self.fake_jenkins.fakeRelease('.*-merge')
1334 self.waitUntilSettled()
1335 ref_mp = jobs[-1].parameters['ZUUL_REF']
1336 self.fake_jenkins.fakeRelease('.*-merge')
1337 self.waitUntilSettled()
1338 self.fake_jenkins.fakeRelease('.*-merge')
1339 self.waitUntilSettled()
1340 ref_master = jobs[-1].parameters['ZUUL_REF']
1341 self.fake_jenkins.hold_jobs_in_queue = False
1342 self.fake_jenkins.fakeRelease()
1343 self.waitUntilSettled()
1344
James E. Blair1dbd5082012-08-23 15:12:15 -07001345 path = os.path.join(GIT_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001346 repo = git.Repo(path)
1347
1348 repo_messages = [c.message.strip()
1349 for c in repo.iter_commits(ref_master)]
1350 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001351 correct_messages = ['initial commit', 'A-1', 'C-1']
1352 assert repo_messages == correct_messages
1353
1354 repo_messages = [c.message.strip()
1355 for c in repo.iter_commits(ref_mp)]
1356 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001357 correct_messages = ['initial commit', 'mp commit', 'B-1']
1358 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001359 self.assertEmptyQueues()
James E. Blair7f71c802012-08-22 13:04:32 -07001360
1361 def test_one_job_project(self):
1362 "Test that queueing works with one job"
1363 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1364 'master', 'A')
1365 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1366 'master', 'B')
1367 A.addApproval('CRVW', 2)
1368 B.addApproval('CRVW', 2)
1369 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1370 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1371 self.waitUntilSettled()
1372
1373 jobs = self.fake_jenkins.all_jobs
1374 finished_jobs = self.fake_jenkins.job_history
James E. Blair7f71c802012-08-22 13:04:32 -07001375
1376 assert A.data['status'] == 'MERGED'
1377 assert A.reported == 2
1378 assert B.data['status'] == 'MERGED'
1379 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001380 self.assertEmptyQueues()
James E. Blaircaec0c52012-08-22 14:52:22 -07001381
Antoine Musso80edd5a2013-02-13 15:37:53 +01001382 def test_job_from_templates_launched(self):
1383 "Test whether a job generated via a template can be launched"
1384 A = self.fake_gerrit.addFakeChange(
1385 'org/templated-project', 'master', 'A')
1386 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1387 self.waitUntilSettled()
1388 jobs = self.fake_jenkins.job_history
1389 job_names = [x.name for x in jobs]
1390
1391 assert 'project-test1' in job_names
1392 assert 'project-test2' in job_names
1393 assert jobs[0].result == 'SUCCESS'
1394 assert jobs[1].result == 'SUCCESS'
1395
James E. Blaircaec0c52012-08-22 14:52:22 -07001396 def test_dependent_changes_dequeue(self):
1397 "Test that dependent patches are not needlessly tested"
1398 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1399 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1400 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1401 A.addApproval('CRVW', 2)
1402 B.addApproval('CRVW', 2)
1403 C.addApproval('CRVW', 2)
1404
1405 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1406 M1.setMerged()
1407
1408 # C -> B -> A -> M1
1409
1410 C.setDependsOn(B, 1)
1411 B.setDependsOn(A, 1)
1412 A.setDependsOn(M1, 1)
1413
1414 self.fake_jenkins.fakeAddFailTest('project-merge', A)
1415
1416 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1417 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1418 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1419
1420 self.waitUntilSettled()
1421
1422 jobs = self.fake_jenkins.all_jobs
1423 finished_jobs = self.fake_jenkins.job_history
1424
James E. Blair127bc182012-08-28 15:55:15 -07001425 for x in jobs:
1426 print x
1427 for x in finished_jobs:
1428 print x
1429
James E. Blairec590122012-08-22 15:19:31 -07001430 assert A.data['status'] == 'NEW'
1431 assert A.reported == 2
1432 assert B.data['status'] == 'NEW'
1433 assert B.reported == 2
1434 assert C.data['status'] == 'NEW'
1435 assert C.reported == 2
1436 assert len(finished_jobs) == 1
James E. Blaire0487072012-08-29 17:38:31 -07001437 self.assertEmptyQueues()
James E. Blairec590122012-08-22 15:19:31 -07001438
1439 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001440 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001441 # If it's dequeued more than once, we should see extra
1442 # aborted jobs.
1443 self.fake_jenkins.hold_jobs_in_build = True
1444
1445 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1446 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1447 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1448 A.addApproval('CRVW', 2)
1449 B.addApproval('CRVW', 2)
1450 C.addApproval('CRVW', 2)
1451
1452 self.fake_jenkins.fakeAddFailTest('project1-test1', A)
1453 self.fake_jenkins.fakeAddFailTest('project1-test2', A)
1454 self.fake_jenkins.fakeAddFailTest('project1-project2-integration', A)
1455
1456 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1457 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1458 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1459
1460 self.waitUntilSettled()
1461 jobs = self.fake_jenkins.all_jobs
1462 finished_jobs = self.fake_jenkins.job_history
1463
1464 assert len(jobs) == 1
1465 assert jobs[0].name == 'project1-merge'
1466 assert job_has_changes(jobs[0], A)
1467
1468 self.fake_jenkins.fakeRelease('.*-merge')
1469 self.waitUntilSettled()
1470 self.fake_jenkins.fakeRelease('.*-merge')
1471 self.waitUntilSettled()
1472 self.fake_jenkins.fakeRelease('.*-merge')
1473 self.waitUntilSettled()
1474
1475 assert len(jobs) == 9
1476 assert jobs[0].name == 'project1-test1'
1477 assert jobs[1].name == 'project1-test2'
1478 assert jobs[2].name == 'project1-project2-integration'
1479 assert jobs[3].name == 'project1-test1'
1480 assert jobs[4].name == 'project1-test2'
1481 assert jobs[5].name == 'project1-project2-integration'
1482 assert jobs[6].name == 'project1-test1'
1483 assert jobs[7].name == 'project1-test2'
1484 assert jobs[8].name == 'project1-project2-integration'
1485
1486 jobs[0].release()
1487 self.waitUntilSettled()
1488
1489 assert len(jobs) == 3 # test2, integration, merge for B
1490 assert self.countJobResults(finished_jobs, 'ABORTED') == 6
1491
1492 self.fake_jenkins.hold_jobs_in_build = False
1493 self.fake_jenkins.fakeRelease()
1494 self.waitUntilSettled()
1495
1496 assert len(jobs) == 0
1497 assert len(finished_jobs) == 20
James E. Blaircaec0c52012-08-22 14:52:22 -07001498
1499 assert A.data['status'] == 'NEW'
James E. Blairec590122012-08-22 15:19:31 -07001500 assert B.data['status'] == 'MERGED'
1501 assert C.data['status'] == 'MERGED'
1502 assert A.reported == 2
1503 assert B.reported == 2
1504 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001505 self.assertEmptyQueues()
James E. Blair4ec821f2012-08-23 15:28:28 -07001506
1507 def test_nonvoting_job(self):
1508 "Test that non-voting jobs don't vote."
1509 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1510 'master', 'A')
1511 A.addApproval('CRVW', 2)
1512 self.fake_jenkins.fakeAddFailTest('nonvoting-project-test2', A)
1513 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1514
1515 self.waitUntilSettled()
1516 jobs = self.fake_jenkins.all_jobs
1517 finished_jobs = self.fake_jenkins.job_history
1518
1519 assert A.data['status'] == 'MERGED'
1520 assert A.reported == 2
James E. Blair0018a6c2013-02-27 14:11:45 -08001521 assert finished_jobs[0].result == 'SUCCESS'
1522 assert finished_jobs[1].result == 'SUCCESS'
1523 assert finished_jobs[2].result == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001524 self.assertEmptyQueues()
1525
1526 def test_check_queue_success(self):
1527 "Test successful check queue jobs."
1528 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1529 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1530
1531 self.waitUntilSettled()
1532 jobs = self.fake_jenkins.all_jobs
1533 finished_jobs = self.fake_jenkins.job_history
1534
1535 assert A.data['status'] == 'NEW'
1536 assert A.reported == 1
James E. Blair0018a6c2013-02-27 14:11:45 -08001537 assert finished_jobs[0].result == 'SUCCESS'
1538 assert finished_jobs[1].result == 'SUCCESS'
1539 assert finished_jobs[2].result == 'SUCCESS'
James E. Blaire0487072012-08-29 17:38:31 -07001540 self.assertEmptyQueues()
1541
1542 def test_check_queue_failure(self):
1543 "Test failed check queue jobs."
1544 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1545 self.fake_jenkins.fakeAddFailTest('project-test2', A)
1546 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1547
1548 self.waitUntilSettled()
1549 jobs = self.fake_jenkins.all_jobs
1550 finished_jobs = self.fake_jenkins.job_history
1551
1552 assert A.data['status'] == 'NEW'
1553 assert A.reported == 1
James E. Blair0018a6c2013-02-27 14:11:45 -08001554 assert finished_jobs[0].result == 'SUCCESS'
1555 assert finished_jobs[1].result == 'SUCCESS'
1556 assert finished_jobs[2].result == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001557 self.assertEmptyQueues()
James E. Blair127bc182012-08-28 15:55:15 -07001558
1559 def test_dependent_behind_dequeue(self):
1560 "test that dependent changes behind dequeued changes work"
1561 # This complicated test is a reproduction of a real life bug
1562 self.sched.reconfigure(self.config)
1563 self.fake_jenkins.hold_jobs_in_build = True
1564
1565 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1566 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1567 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1568 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1569 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1570 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1571 D.setDependsOn(C, 1)
1572 E.setDependsOn(D, 1)
1573 A.addApproval('CRVW', 2)
1574 B.addApproval('CRVW', 2)
1575 C.addApproval('CRVW', 2)
1576 D.addApproval('CRVW', 2)
1577 E.addApproval('CRVW', 2)
1578 F.addApproval('CRVW', 2)
1579
1580 A.fail_merge = True
1581 jobs = self.fake_jenkins.all_jobs
1582 finished_jobs = self.fake_jenkins.job_history
1583
1584 # Change object re-use in the gerrit trigger is hidden if
1585 # changes are added in quick succession; waiting makes it more
1586 # like real life.
1587 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1588 self.waitUntilSettled()
1589 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1590 self.waitUntilSettled()
1591
1592 self.fake_jenkins.fakeRelease('.*-merge')
1593 self.waitUntilSettled()
1594 self.fake_jenkins.fakeRelease('.*-merge')
1595 self.waitUntilSettled()
1596
1597 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1598 self.waitUntilSettled()
1599 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1600 self.waitUntilSettled()
1601 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1602 self.waitUntilSettled()
1603 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1604 self.waitUntilSettled()
1605
1606 self.fake_jenkins.fakeRelease('.*-merge')
1607 self.waitUntilSettled()
1608 self.fake_jenkins.fakeRelease('.*-merge')
1609 self.waitUntilSettled()
1610 self.fake_jenkins.fakeRelease('.*-merge')
1611 self.waitUntilSettled()
1612 self.fake_jenkins.fakeRelease('.*-merge')
1613 self.waitUntilSettled()
1614
James E. Blair4aa1ad62012-10-05 12:39:26 -07001615 for x in jobs:
1616 print x
James E. Blair127bc182012-08-28 15:55:15 -07001617 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001618
1619 # Grab pointers to the jobs we want to release before
1620 # releasing any, because list indexes may change as
1621 # the jobs complete.
1622 a, b, c = jobs[:3]
1623 a.release()
1624 b.release()
1625 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001626 self.waitUntilSettled()
1627
1628 self.fake_jenkins.hold_jobs_in_build = False
1629 self.fake_jenkins.fakeRelease()
1630 self.waitUntilSettled()
1631
1632 for x in jobs:
1633 print x
1634 for x in finished_jobs:
1635 print x
1636 print self.sched.formatStatusHTML()
1637
1638 assert A.data['status'] == 'NEW'
1639 assert B.data['status'] == 'MERGED'
1640 assert C.data['status'] == 'MERGED'
1641 assert D.data['status'] == 'MERGED'
1642 assert E.data['status'] == 'MERGED'
1643 assert F.data['status'] == 'MERGED'
1644
1645 assert A.reported == 2
1646 assert B.reported == 2
1647 assert C.reported == 2
1648 assert D.reported == 2
1649 assert E.reported == 2
1650 assert F.reported == 2
1651
James E. Blair127bc182012-08-28 15:55:15 -07001652 assert self.countJobResults(finished_jobs, 'ABORTED') == 15
1653 assert len(finished_jobs) == 44
James E. Blaire0487072012-08-29 17:38:31 -07001654 self.assertEmptyQueues()
James E. Blair05fed602012-09-07 12:45:24 -07001655
1656 def test_merger_repack(self):
1657 "Test that the merger works after a repack"
1658 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1659 A.addApproval('CRVW', 2)
1660 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1661 self.waitUntilSettled()
1662 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001663 job_names = [x.name for x in jobs]
James E. Blair05fed602012-09-07 12:45:24 -07001664 assert 'project-merge' in job_names
1665 assert 'project-test1' in job_names
1666 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001667 assert jobs[0].result == 'SUCCESS'
1668 assert jobs[1].result == 'SUCCESS'
1669 assert jobs[2].result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001670 assert A.data['status'] == 'MERGED'
1671 assert A.reported == 2
1672 self.assertEmptyQueues()
1673
1674 path = os.path.join(GIT_ROOT, "org/project")
1675 os.system('git --git-dir=%s/.git repack -afd' % path)
1676
1677 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1678 A.addApproval('CRVW', 2)
1679 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1680 self.waitUntilSettled()
1681 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001682 job_names = [x.name for x in jobs]
James E. Blair05fed602012-09-07 12:45:24 -07001683 assert 'project-merge' in job_names
1684 assert 'project-test1' in job_names
1685 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001686 assert jobs[0].result == 'SUCCESS'
1687 assert jobs[1].result == 'SUCCESS'
1688 assert jobs[2].result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001689 assert A.data['status'] == 'MERGED'
1690 assert A.reported == 2
1691 self.assertEmptyQueues()
James E. Blair7ee88a22012-09-12 18:59:31 +02001692
James E. Blair4886f282012-11-15 09:27:33 -08001693 def test_merger_repack_large_change(self):
1694 "Test that the merger works with large changes after a repack"
1695 # https://bugs.launchpad.net/zuul/+bug/1078946
1696 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1697 A.addPatchset(large=True)
1698 path = os.path.join(UPSTREAM_ROOT, "org/project1")
1699 os.system('git --git-dir=%s/.git repack -afd' % path)
1700 path = os.path.join(GIT_ROOT, "org/project1")
1701 os.system('git --git-dir=%s/.git repack -afd' % path)
1702
1703 A.addApproval('CRVW', 2)
1704 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1705 self.waitUntilSettled()
1706 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001707 job_names = [x.name for x in jobs]
James E. Blair4886f282012-11-15 09:27:33 -08001708 assert 'project1-merge' in job_names
1709 assert 'project1-test1' in job_names
1710 assert 'project1-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001711 assert jobs[0].result == 'SUCCESS'
1712 assert jobs[1].result == 'SUCCESS'
1713 assert jobs[2].result == 'SUCCESS'
James E. Blair4886f282012-11-15 09:27:33 -08001714 assert A.data['status'] == 'MERGED'
1715 assert A.reported == 2
1716 self.assertEmptyQueues()
1717
James E. Blair7ee88a22012-09-12 18:59:31 +02001718 def test_nonexistent_job(self):
1719 "Test launching a job that doesn't exist"
1720 self.fake_jenkins.nonexistent_jobs.append('project-merge')
1721 self.jenkins.launch_retry_timeout = 0.1
1722
1723 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1724 A.addApproval('CRVW', 2)
1725 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1726 # There may be a thread about to report a lost change
1727 while A.reported < 2:
1728 self.waitUntilSettled()
1729 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001730 job_names = [x.name for x in jobs]
James E. Blair7ee88a22012-09-12 18:59:31 +02001731 assert not job_names
1732 assert A.data['status'] == 'NEW'
1733 assert A.reported == 2
1734 self.assertEmptyQueues()
1735
1736 # Make sure things still work:
1737 self.fake_jenkins.nonexistent_jobs = []
1738 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1739 A.addApproval('CRVW', 2)
1740 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1741 self.waitUntilSettled()
1742 jobs = self.fake_jenkins.job_history
James E. Blair0018a6c2013-02-27 14:11:45 -08001743 job_names = [x.name for x in jobs]
James E. Blair7ee88a22012-09-12 18:59:31 +02001744 assert 'project-merge' in job_names
1745 assert 'project-test1' in job_names
1746 assert 'project-test2' in job_names
James E. Blair0018a6c2013-02-27 14:11:45 -08001747 assert jobs[0].result == 'SUCCESS'
1748 assert jobs[1].result == 'SUCCESS'
1749 assert jobs[2].result == 'SUCCESS'
James E. Blair7ee88a22012-09-12 18:59:31 +02001750 assert A.data['status'] == 'MERGED'
1751 assert A.reported == 2
1752 self.assertEmptyQueues()
James E. Blairf62d4282012-12-31 17:01:50 -08001753
1754 def test_single_nonexistent_post_job(self):
1755 "Test launching a single post job that doesn't exist"
1756 self.fake_jenkins.nonexistent_jobs.append('project-post')
1757 self.jenkins.launch_retry_timeout = 0.1
1758
1759 e = {
1760 "type": "ref-updated",
1761 "submitter": {
1762 "name": "User Name",
1763 },
1764 "refUpdate": {
1765 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1766 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1767 "refName": "master",
1768 "project": "org/project",
1769 }
1770 }
1771 self.fake_gerrit.addEvent(e)
1772 self.waitUntilSettled()
1773
1774 jobs = self.fake_jenkins.job_history
1775 assert len(jobs) == 0
1776 self.assertEmptyQueues()
James E. Blair2fa50962013-01-30 21:50:41 -08001777
1778 def test_new_patchset_dequeues_old(self):
1779 "Test that a new patchset causes the old to be dequeued"
1780 # D -> C (depends on B) -> B (depends on A) -> A -> M
1781 self.fake_jenkins.hold_jobs_in_build = True
1782
1783 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1784 M.setMerged()
1785
1786 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1787 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1788 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1789 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1790 A.addApproval('CRVW', 2)
1791 B.addApproval('CRVW', 2)
1792 C.addApproval('CRVW', 2)
1793 D.addApproval('CRVW', 2)
1794
1795 C.setDependsOn(B, 1)
1796 B.setDependsOn(A, 1)
1797 A.setDependsOn(M, 1)
1798
1799 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1800 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1801 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1802 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1803 self.waitUntilSettled()
1804
1805 B.addPatchset()
1806 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1807 self.waitUntilSettled()
1808
1809 self.fake_jenkins.hold_jobs_in_build = False
1810 self.fake_jenkins.fakeRelease()
1811 self.waitUntilSettled()
1812
1813 jobs = self.fake_jenkins.all_jobs
1814 finished_jobs = self.fake_jenkins.job_history
1815
1816 for x in jobs:
1817 print x
1818 for x in finished_jobs:
1819 print x
1820
1821 assert A.data['status'] == 'MERGED'
1822 assert A.reported == 2
1823 assert B.data['status'] == 'NEW'
1824 assert B.reported == 2
1825 assert C.data['status'] == 'NEW'
1826 assert C.reported == 2
1827 assert D.data['status'] == 'MERGED'
1828 assert D.reported == 2
1829 assert len(finished_jobs) == 9 # 3 each for A, B, D.
1830 self.assertEmptyQueues()
1831
1832 def test_new_patchset_dequeues_old_on_head(self):
1833 "Test that a new patchset causes the old to be dequeued (at head)"
1834 # D -> C (depends on B) -> B (depends on A) -> A -> M
1835 self.fake_jenkins.hold_jobs_in_build = True
1836
1837 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1838 M.setMerged()
1839 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1840 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1841 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1842 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1843 A.addApproval('CRVW', 2)
1844 B.addApproval('CRVW', 2)
1845 C.addApproval('CRVW', 2)
1846 D.addApproval('CRVW', 2)
1847
1848 C.setDependsOn(B, 1)
1849 B.setDependsOn(A, 1)
1850 A.setDependsOn(M, 1)
1851
1852 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1853 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1854 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1855 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1856 self.waitUntilSettled()
1857
1858 A.addPatchset()
1859 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1860 self.waitUntilSettled()
1861
1862 self.fake_jenkins.hold_jobs_in_build = False
1863 self.fake_jenkins.fakeRelease()
1864 self.waitUntilSettled()
1865
1866 jobs = self.fake_jenkins.all_jobs
1867 finished_jobs = self.fake_jenkins.job_history
1868
1869 for x in jobs:
1870 print x
1871 for x in finished_jobs:
1872 print x
1873
1874 assert A.data['status'] == 'NEW'
1875 assert A.reported == 2
1876 assert B.data['status'] == 'NEW'
1877 assert B.reported == 2
1878 assert C.data['status'] == 'NEW'
1879 assert C.reported == 2
1880 assert D.data['status'] == 'MERGED'
1881 assert D.reported == 2
1882 assert len(finished_jobs) == 7
1883 self.assertEmptyQueues()
1884
1885 def test_new_patchset_dequeues_old_without_dependents(self):
1886 "Test that a new patchset causes only the old to be dequeued"
1887 self.fake_jenkins.hold_jobs_in_build = True
1888
1889 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1890 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1891 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1892 A.addApproval('CRVW', 2)
1893 B.addApproval('CRVW', 2)
1894 C.addApproval('CRVW', 2)
1895
1896 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1897 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1898 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1899 self.waitUntilSettled()
1900
1901 B.addPatchset()
1902 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1903 self.waitUntilSettled()
1904
1905 self.fake_jenkins.hold_jobs_in_build = False
1906 self.fake_jenkins.fakeRelease()
1907 self.waitUntilSettled()
1908
1909 jobs = self.fake_jenkins.all_jobs
1910 finished_jobs = self.fake_jenkins.job_history
1911
1912 for x in jobs:
1913 print x
1914 for x in finished_jobs:
1915 print x
1916
1917 assert A.data['status'] == 'MERGED'
1918 assert A.reported == 2
1919 assert B.data['status'] == 'NEW'
1920 assert B.reported == 2
1921 assert C.data['status'] == 'MERGED'
1922 assert C.reported == 2
1923 assert len(finished_jobs) == 9
1924 self.assertEmptyQueues()
1925
1926 def test_new_patchset_dequeues_old_independent_queue(self):
1927 "Test that a new patchset causes the old to be dequeued (independent)"
1928 self.fake_jenkins.hold_jobs_in_build = True
1929
1930 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1931 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1932 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1933 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1934 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1935 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1936 self.waitUntilSettled()
1937
1938 B.addPatchset()
1939 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1940 self.waitUntilSettled()
1941
1942 self.fake_jenkins.hold_jobs_in_build = False
1943 self.fake_jenkins.fakeRelease()
1944 self.waitUntilSettled()
1945
1946 jobs = self.fake_jenkins.all_jobs
1947 finished_jobs = self.fake_jenkins.job_history
1948
1949 for x in jobs:
1950 print x
1951 for x in finished_jobs:
1952 print x
1953
1954 assert A.data['status'] == 'NEW'
1955 assert A.reported == 1
1956 assert B.data['status'] == 'NEW'
1957 assert B.reported == 1
1958 assert C.data['status'] == 'NEW'
1959 assert C.reported == 1
1960 assert len(finished_jobs) == 10
1961 assert self.countJobResults(finished_jobs, 'ABORTED') == 1
1962 self.assertEmptyQueues()
James E. Blair7d0dedc2013-02-21 17:26:09 -08001963
1964 def test_zuul_refs(self):
1965 "Test that zuul refs exist and have the right changes"
1966 self.fake_jenkins.hold_jobs_in_build = True
1967
1968 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
1969 M1.setMerged()
1970 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
1971 M2.setMerged()
1972
1973 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1974 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1975 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1976 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1977 A.addApproval('CRVW', 2)
1978 B.addApproval('CRVW', 2)
1979 C.addApproval('CRVW', 2)
1980 D.addApproval('CRVW', 2)
1981 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1982 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1983 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1984 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1985
1986 self.waitUntilSettled()
1987 self.fake_jenkins.fakeRelease('.*-merge')
1988 self.waitUntilSettled()
1989 self.fake_jenkins.fakeRelease('.*-merge')
1990 self.waitUntilSettled()
1991 self.fake_jenkins.fakeRelease('.*-merge')
1992 self.waitUntilSettled()
1993 self.fake_jenkins.fakeRelease('.*-merge')
1994 self.waitUntilSettled()
1995
1996 jobs = self.fake_jenkins.all_jobs
1997 finished_jobs = self.fake_jenkins.job_history
1998
1999 a_zref = b_zref = c_zref = d_zref = None
2000 for x in jobs:
2001 if x.parameters['ZUUL_CHANGE'] == '3':
2002 a_zref = x.parameters['ZUUL_REF']
2003 if x.parameters['ZUUL_CHANGE'] == '4':
2004 b_zref = x.parameters['ZUUL_REF']
2005 if x.parameters['ZUUL_CHANGE'] == '5':
2006 c_zref = x.parameters['ZUUL_REF']
2007 if x.parameters['ZUUL_CHANGE'] == '6':
2008 d_zref = x.parameters['ZUUL_REF']
2009
2010 # There are... four... refs.
2011 assert a_zref is not None
2012 assert b_zref is not None
2013 assert c_zref is not None
2014 assert d_zref is not None
2015
2016 # And they should all be different
2017 refs = set([a_zref, b_zref, c_zref, d_zref])
2018 assert len(refs) == 4
2019
2020 # a ref should have a, not b, and should not be in project2
2021 assert ref_has_change(a_zref, A)
2022 assert not ref_has_change(a_zref, B)
2023 assert not ref_has_change(a_zref, M2)
2024
2025 # b ref should have a and b, and should not be in project2
2026 assert ref_has_change(b_zref, A)
2027 assert ref_has_change(b_zref, B)
2028 assert not ref_has_change(b_zref, M2)
2029
2030 # c ref should have a and b in 1, c in 2
2031 assert ref_has_change(c_zref, A)
2032 assert ref_has_change(c_zref, B)
2033 assert ref_has_change(c_zref, C)
2034 assert not ref_has_change(c_zref, D)
2035
2036 # d ref should have a and b in 1, c and d in 2
2037 assert ref_has_change(d_zref, A)
2038 assert ref_has_change(d_zref, B)
2039 assert ref_has_change(d_zref, C)
2040 assert ref_has_change(d_zref, D)
2041
2042 self.fake_jenkins.hold_jobs_in_build = False
2043 self.fake_jenkins.fakeRelease()
2044 self.waitUntilSettled()
2045
2046 assert A.data['status'] == 'MERGED'
2047 assert A.reported == 2
2048 assert B.data['status'] == 'MERGED'
2049 assert B.reported == 2
2050 assert C.data['status'] == 'MERGED'
2051 assert C.reported == 2
2052 assert D.data['status'] == 'MERGED'
2053 assert D.reported == 2
2054 self.assertEmptyQueues()
James E. Blair70c71582013-03-06 08:50:50 -08002055
James E. Blair412e5582013-04-22 15:50:12 -07002056 def test_statsd(self):
2057 "Test each of the statsd methods used in the scheduler"
2058 import extras
2059 statsd = extras.try_import('statsd.statsd')
2060 statsd.incr('test-incr')
2061 statsd.timing('test-timing', 3)
2062 statsd.gauge('test-guage', 12)
2063 self.assertReportedStat('test-incr', '1|c')
2064 self.assertReportedStat('test-timing', '3|ms')
2065 self.assertReportedStat('test-guage', '12|g')
2066
James E. Blair70c71582013-03-06 08:50:50 -08002067 def test_file_jobs(self):
2068 "Test that file jobs run only when appropriate"
2069 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2070 A.addPatchset(['pip-requires'])
2071 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2072 A.addApproval('CRVW', 2)
2073 B.addApproval('CRVW', 2)
2074 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2075 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2076 self.waitUntilSettled()
2077
2078 jobs = self.fake_jenkins.all_jobs
2079 finished_jobs = self.fake_jenkins.job_history
2080
2081 testfile_jobs = [x for x in finished_jobs
2082 if x.name == 'project-testfile']
2083
2084 assert len(testfile_jobs) == 1
2085 assert testfile_jobs[0].changes == '1,2'
2086 assert A.data['status'] == 'MERGED'
2087 assert A.reported == 2
2088 assert B.data['status'] == 'MERGED'
2089 assert B.reported == 2
2090 self.assertEmptyQueues()
James E. Blair3c5e5b52013-04-26 11:17:03 -07002091
2092 def test_test_config(self):
2093 "Test that we can test the config"
2094 sched = zuul.scheduler.Scheduler()
2095 sched.testConfig(CONFIG.get('zuul', 'layout_config'))