blob: 4d3351e3112c072f8b884095a6da04f6ef096982 [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. Blair1f4c2bb2013-04-26 08:40:46 -070036from cStringIO import StringIO
James E. Blair4886cc12012-07-18 15:39:41 -070037import git
James E. Blair1f4c2bb2013-04-26 08:40:46 -070038import gear
James E. Blairb0fcae42012-07-17 11:12:10 -070039
James E. Blairb0fcae42012-07-17 11:12:10 -070040import zuul.scheduler
James E. Blair1f4c2bb2013-04-26 08:40:46 -070041import zuul.launcher.gearman
James E. Blairb0fcae42012-07-17 11:12:10 -070042import zuul.trigger.gerrit
43
44FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
45 'fixtures')
46CONFIG = ConfigParser.ConfigParser()
47CONFIG.read(os.path.join(FIXTURE_DIR, "zuul.conf"))
48
49CONFIG.set('zuul', 'layout_config',
50 os.path.join(FIXTURE_DIR, "layout.yaml"))
51
James E. Blair1dbd5082012-08-23 15:12:15 -070052TMP_ROOT = os.environ.get("ZUUL_TEST_ROOT", "/tmp")
53TEST_ROOT = os.path.join(TMP_ROOT, "zuul-test")
54UPSTREAM_ROOT = os.path.join(TEST_ROOT, "upstream")
55GIT_ROOT = os.path.join(TEST_ROOT, "git")
56
57CONFIG.set('zuul', 'git_dir', GIT_ROOT)
58
James E. Blair1f4c2bb2013-04-26 08:40:46 -070059logging.basicConfig(level=logging.DEBUG,
60 format='%(asctime)s %(name)-32s '
61 '%(levelname)-8s %(message)s')
James E. Blairb0fcae42012-07-17 11:12:10 -070062
63
James E. Blair8cc15a82012-08-01 11:17:57 -070064def random_sha1():
65 return hashlib.sha1(str(random.random())).hexdigest()
66
67
James E. Blair4886cc12012-07-18 15:39:41 -070068class ChangeReference(git.Reference):
69 _common_path_default = "refs/changes"
70 _points_to_commits_only = True
71
72
73def init_repo(project):
74 parts = project.split('/')
James E. Blair1dbd5082012-08-23 15:12:15 -070075 path = os.path.join(UPSTREAM_ROOT, *parts[:-1])
James E. Blair4886cc12012-07-18 15:39:41 -070076 if not os.path.exists(path):
77 os.makedirs(path)
James E. Blair1dbd5082012-08-23 15:12:15 -070078 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -070079 repo = git.Repo.init(path)
80
81 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:]
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700145 if isinstance(job, FakeBuild):
146 parameters = job.parameters
147 else:
148 parameters = json.loads(job.arguments)
149 project = parameters['ZUUL_PROJECT']
James E. Blair1dbd5082012-08-23 15:12:15 -0700150 path = os.path.join(GIT_ROOT, project)
James E. Blair4886cc12012-07-18 15:39:41 -0700151 repo = git.Repo(path)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700152 ref = parameters['ZUUL_REF']
153 sha = parameters['ZUUL_COMMIT']
James E. Blair4886cc12012-07-18 15:39:41 -0700154 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
James E. Blair81515ad2012-10-01 18:29:08 -0700155 repo_shas = [c.hexsha for c in repo.iter_commits(ref)]
James E. Blair4886cc12012-07-18 15:39:41 -0700156 commit_messages = ['%s-1' % commit.subject for commit in commits]
James E. Blair4886cc12012-07-18 15:39:41 -0700157 for msg in commit_messages:
158 if msg not in repo_messages:
159 return False
James E. Blair81515ad2012-10-01 18:29:08 -0700160 if repo_shas[0] != sha:
161 return False
James E. Blair4886cc12012-07-18 15:39:41 -0700162 return True
163
164
James E. Blairb0fcae42012-07-17 11:12:10 -0700165class FakeChange(object):
James E. Blair8c803f82012-07-31 16:25:42 -0700166 categories = {'APRV': ('Approved', -1, 1),
167 'CRVW': ('Code-Review', -2, 2),
168 'VRFY': ('Verified', -2, 2)}
James E. Blairb0fcae42012-07-17 11:12:10 -0700169
James E. Blair8cc15a82012-08-01 11:17:57 -0700170 def __init__(self, gerrit, number, project, branch, subject, status='NEW'):
171 self.gerrit = gerrit
James E. Blaird466dc42012-07-31 10:42:56 -0700172 self.reported = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700173 self.queried = 0
James E. Blairb0fcae42012-07-17 11:12:10 -0700174 self.patchsets = []
James E. Blairb0fcae42012-07-17 11:12:10 -0700175 self.number = number
176 self.project = project
177 self.branch = branch
178 self.subject = subject
179 self.latest_patchset = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700180 self.depends_on_change = None
181 self.needed_by_changes = []
James E. Blair127bc182012-08-28 15:55:15 -0700182 self.fail_merge = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700183 self.data = {
184 'branch': branch,
185 'comments': [],
186 'commitMessage': subject,
187 'createdOn': time.time(),
James E. Blair8cc15a82012-08-01 11:17:57 -0700188 'id': 'I' + random_sha1(),
James E. Blairb0fcae42012-07-17 11:12:10 -0700189 'lastUpdated': time.time(),
190 'number': str(number),
191 'open': True,
192 'owner': {'email': 'user@example.com',
193 'name': 'User Name',
194 'username': 'username'},
195 'patchSets': self.patchsets,
196 'project': project,
197 'status': status,
198 'subject': subject,
James E. Blair8c803f82012-07-31 16:25:42 -0700199 'submitRecords': [],
James E. Blairb0fcae42012-07-17 11:12:10 -0700200 'url': 'https://hostname/%s' % number}
201
202 self.addPatchset()
James E. Blair8c803f82012-07-31 16:25:42 -0700203 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700204
James E. Blair70c71582013-03-06 08:50:50 -0800205 def addPatchset(self, files=[], large=False):
James E. Blairb0fcae42012-07-17 11:12:10 -0700206 self.latest_patchset += 1
James E. Blairdaabed22012-08-15 15:38:57 -0700207 if files:
208 fn = files[0]
209 else:
210 fn = '%s-%s' % (self.branch, self.number)
211 msg = self.subject + '-' + str(self.latest_patchset)
212 c = add_fake_change_to_repo(self.project, self.branch,
213 self.number, self.latest_patchset,
James E. Blair4886f282012-11-15 09:27:33 -0800214 msg, fn, large)
James E. Blair70c71582013-03-06 08:50:50 -0800215 ps_files = [{'file': '/COMMIT_MSG',
216 'type': 'ADDED'},
217 {'file': 'README',
218 'type': 'MODIFIED'}]
219 for f in files:
220 ps_files.append({'file': f, 'type': 'ADDED'})
James E. Blairb0fcae42012-07-17 11:12:10 -0700221 d = {'approvals': [],
222 'createdOn': time.time(),
James E. Blair70c71582013-03-06 08:50:50 -0800223 'files': ps_files,
James E. Blair8c803f82012-07-31 16:25:42 -0700224 'number': str(self.latest_patchset),
James E. Blairb0fcae42012-07-17 11:12:10 -0700225 'ref': 'refs/changes/1/%s/%s' % (self.number,
226 self.latest_patchset),
James E. Blairdaabed22012-08-15 15:38:57 -0700227 'revision': c.hexsha,
James E. Blairb0fcae42012-07-17 11:12:10 -0700228 'uploader': {'email': 'user@example.com',
229 'name': 'User name',
230 'username': 'user'}}
231 self.data['currentPatchSet'] = d
232 self.patchsets.append(d)
James E. Blair8c803f82012-07-31 16:25:42 -0700233 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700234
James E. Blaire0487072012-08-29 17:38:31 -0700235 def getPatchsetCreatedEvent(self, patchset):
236 event = {"type": "patchset-created",
237 "change": {"project": self.project,
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800238 "branch": self.branch,
239 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
240 "number": str(self.number),
241 "subject": self.subject,
242 "owner": {"name": "User Name"},
243 "url": "https://hostname/3"},
James E. Blaire0487072012-08-29 17:38:31 -0700244 "patchSet": self.patchsets[patchset - 1],
245 "uploader": {"name": "User Name"}}
246 return event
247
James E. Blairb0fcae42012-07-17 11:12:10 -0700248 def addApproval(self, category, value):
James E. Blair8c803f82012-07-31 16:25:42 -0700249 approval = {'description': self.categories[category][0],
250 'type': category,
251 'value': str(value)}
252 self.patchsets[-1]['approvals'].append(approval)
253 event = {'approvals': [approval],
James E. Blairb0fcae42012-07-17 11:12:10 -0700254 'author': {'email': 'user@example.com',
255 'name': 'User Name',
256 'username': 'username'},
257 'change': {'branch': self.branch,
258 'id': 'Iaa69c46accf97d0598111724a38250ae76a22c87',
259 'number': str(self.number),
260 'owner': {'email': 'user@example.com',
261 'name': 'User Name',
262 'username': 'username'},
263 'project': self.project,
264 'subject': self.subject,
265 'topic': 'master',
266 'url': 'https://hostname/459'},
267 'comment': '',
268 'patchSet': self.patchsets[-1],
269 'type': 'comment-added'}
James E. Blair8c803f82012-07-31 16:25:42 -0700270 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700271 return json.loads(json.dumps(event))
272
James E. Blair8c803f82012-07-31 16:25:42 -0700273 def getSubmitRecords(self):
274 status = {}
275 for cat in self.categories.keys():
276 status[cat] = 0
277
278 for a in self.patchsets[-1]['approvals']:
279 cur = status[a['type']]
280 cat_min, cat_max = self.categories[a['type']][1:]
281 new = int(a['value'])
282 if new == cat_min:
283 cur = new
284 elif abs(new) > abs(cur):
285 cur = new
286 status[a['type']] = cur
287
288 labels = []
289 ok = True
290 for typ, cat in self.categories.items():
291 cur = status[typ]
292 cat_min, cat_max = cat[1:]
293 if cur == cat_min:
294 value = 'REJECT'
295 ok = False
296 elif cur == cat_max:
297 value = 'OK'
298 else:
299 value = 'NEED'
300 ok = False
301 labels.append({'label': cat[0], 'status': value})
302 if ok:
303 return [{'status': 'OK'}]
304 return [{'status': 'NOT_READY',
305 'labels': labels}]
306
307 def setDependsOn(self, other, patchset):
308 self.depends_on_change = other
309 d = {'id': other.data['id'],
310 'number': other.data['number'],
311 'ref': other.patchsets[patchset - 1]['ref']
312 }
313 self.data['dependsOn'] = [d]
314
315 other.needed_by_changes.append(self)
316 needed = other.data.get('neededBy', [])
317 d = {'id': self.data['id'],
318 'number': self.data['number'],
319 'ref': self.patchsets[patchset - 1]['ref'],
320 'revision': self.patchsets[patchset - 1]['revision']
321 }
322 needed.append(d)
323 other.data['neededBy'] = needed
324
James E. Blairb0fcae42012-07-17 11:12:10 -0700325 def query(self):
James E. Blair8c803f82012-07-31 16:25:42 -0700326 self.queried += 1
327 d = self.data.get('dependsOn')
328 if d:
329 d = d[0]
330 if (self.depends_on_change.patchsets[-1]['ref'] == d['ref']):
331 d['isCurrentPatchSet'] = True
332 else:
333 d['isCurrentPatchSet'] = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700334 return json.loads(json.dumps(self.data))
335
336 def setMerged(self):
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800337 if (self.depends_on_change and
338 self.depends_on_change.data['status'] != 'MERGED'):
James E. Blaircaec0c52012-08-22 14:52:22 -0700339 return
James E. Blair127bc182012-08-28 15:55:15 -0700340 if self.fail_merge:
341 return
James E. Blairb0fcae42012-07-17 11:12:10 -0700342 self.data['status'] = 'MERGED'
343 self.open = False
James E. Blairdaabed22012-08-15 15:38:57 -0700344
James E. Blair1dbd5082012-08-23 15:12:15 -0700345 path = os.path.join(UPSTREAM_ROOT, self.project)
James E. Blairdaabed22012-08-15 15:38:57 -0700346 repo = git.Repo(path)
347 repo.heads[self.branch].commit = \
348 repo.commit(self.patchsets[-1]['revision'])
James E. Blairb0fcae42012-07-17 11:12:10 -0700349
James E. Blaird466dc42012-07-31 10:42:56 -0700350 def setReported(self):
351 self.reported += 1
352
James E. Blairb0fcae42012-07-17 11:12:10 -0700353
354class FakeGerrit(object):
355 def __init__(self, *args, **kw):
356 self.event_queue = Queue.Queue()
357 self.fixture_dir = os.path.join(FIXTURE_DIR, 'gerrit')
358 self.change_number = 0
359 self.changes = {}
360
361 def addFakeChange(self, project, branch, subject):
362 self.change_number += 1
James E. Blair8cc15a82012-08-01 11:17:57 -0700363 c = FakeChange(self, self.change_number, project, branch, subject)
James E. Blairb0fcae42012-07-17 11:12:10 -0700364 self.changes[self.change_number] = c
365 return c
366
367 def addEvent(self, data):
368 return self.event_queue.put(data)
369
370 def getEvent(self):
371 return self.event_queue.get()
372
373 def eventDone(self):
374 self.event_queue.task_done()
375
376 def review(self, project, changeid, message, action):
James E. Blaird466dc42012-07-31 10:42:56 -0700377 number, ps = changeid.split(',')
378 change = self.changes[int(number)]
James E. Blairb0fcae42012-07-17 11:12:10 -0700379 if 'submit' in action:
James E. Blairb0fcae42012-07-17 11:12:10 -0700380 change.setMerged()
James E. Blaird466dc42012-07-31 10:42:56 -0700381 if message:
382 change.setReported()
James E. Blairb0fcae42012-07-17 11:12:10 -0700383
384 def query(self, number):
385 change = self.changes[int(number)]
386 return change.query()
387
388 def startWatching(self, *args, **kw):
389 pass
390
391
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700392class BuildHistory(object):
393 def __init__(self, **kw):
394 self.__dict__.update(kw)
James E. Blairb0fcae42012-07-17 11:12:10 -0700395
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700396 def __repr__(self):
397 return ("<Completed build, result: %s name: %s #%s changes: %s>" %
398 (self.result, self.name, self.number, self.changes))
James E. Blairb0fcae42012-07-17 11:12:10 -0700399
400
James E. Blair8cc15a82012-08-01 11:17:57 -0700401class FakeURLOpener(object):
402 def __init__(self, fake_gerrit, url):
403 self.fake_gerrit = fake_gerrit
404 self.url = url
405
406 def read(self):
407 res = urlparse.urlparse(self.url)
408 path = res.path
409 project = '/'.join(path.split('/')[2:-2])
James E. Blair35956c52012-09-17 22:13:36 +0200410 ret = '001e# service=git-upload-pack\n'
411 ret += ('000000a31270149696713ba7e06f1beb760f20d359c4abed HEAD\x00'
412 'multi_ack thin-pack side-band side-band-64k ofs-delta '
413 'shallow no-progress include-tag multi_ack_detailed no-done\n')
James E. Blair1dbd5082012-08-23 15:12:15 -0700414 path = os.path.join(UPSTREAM_ROOT, project)
James E. Blairdaabed22012-08-15 15:38:57 -0700415 repo = git.Repo(path)
416 for ref in repo.refs:
James E. Blair35956c52012-09-17 22:13:36 +0200417 r = ref.object.hexsha + ' ' + ref.path + '\n'
418 ret += '%04x%s' % (len(r) + 4, r)
419 ret += '0000'
James E. Blair8cc15a82012-08-01 11:17:57 -0700420 return ret
421
422
James E. Blair4886cc12012-07-18 15:39:41 -0700423class FakeGerritTrigger(zuul.trigger.gerrit.Gerrit):
424 def getGitUrl(self, project):
James E. Blair1dbd5082012-08-23 15:12:15 -0700425 return os.path.join(UPSTREAM_ROOT, project.name)
James E. Blair4886cc12012-07-18 15:39:41 -0700426
427
James E. Blair412e5582013-04-22 15:50:12 -0700428class FakeStatsd(threading.Thread):
429 def __init__(self):
430 threading.Thread.__init__(self)
431 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
432 self.sock.bind(('', 0))
433 self.port = self.sock.getsockname()[1]
434 self.wake_read, self.wake_write = os.pipe()
435 self.stats = []
436
437 def run(self):
438 while True:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700439 poll = select.poll()
440 poll.register(self.sock, select.POLLIN)
441 poll.register(self.wake_read, select.POLLIN)
442 ret = poll.poll()
443 for (fd, event) in ret:
444 if fd == self.sock.fileno():
James E. Blair412e5582013-04-22 15:50:12 -0700445 data = self.sock.recvfrom(1024)
446 if not data:
447 return
448 self.stats.append(data[0])
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700449 if fd == self.wake_read:
James E. Blair412e5582013-04-22 15:50:12 -0700450 return
451
452 def stop(self):
453 os.write(self.wake_write, '1\n')
454
455
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700456class FakeBuild(threading.Thread):
457 log = logging.getLogger("zuul.test")
458
459 def __init__(self, worker, job, number, node):
460 threading.Thread.__init__(self)
461 self.worker = worker
462 self.job = job
463 self.name = job.name.split(':')[1]
464 self.number = number
465 self.node = node
466 self.parameters = json.loads(job.arguments)
467 self.unique = self.parameters['ZUUL_UUID']
468 self.wait_condition = threading.Condition()
469 self.waiting = False
470 self.aborted = False
471 self.created = time.time()
472 self.description = ''
473
474 def release(self):
475 self.wait_condition.acquire()
476 self.wait_condition.notify()
477 self.waiting = False
478 self.log.debug("Build %s released" % self.unique)
479 self.wait_condition.release()
480
481 def isWaiting(self):
482 self.wait_condition.acquire()
483 if self.waiting:
484 ret = True
485 else:
486 ret = False
487 self.wait_condition.release()
488 return ret
489
490 def _wait(self):
491 self.wait_condition.acquire()
492 self.waiting = True
493 self.log.debug("Build %s waiting" % self.unique)
494 self.wait_condition.wait()
495 self.wait_condition.release()
496
497 def run(self):
498 data = {
499 'full_url': 'https://server/job/%s/%s/' % (self.name, self.number),
500 'number': self.number,
501 'master': self.worker.worker_id,
502 }
503
504 self.job.sendWorkData(json.dumps(data))
505 self.job.sendWorkStatus(0, 100)
506
507 if self.worker.hold_jobs_in_build:
508 self._wait()
509 self.log.debug("Build %s continuing" % self.unique)
510
511 self.worker.lock.acquire()
512
513 result = 'SUCCESS'
514 if (('ZUUL_REF' in self.parameters) and
515 self.worker.shouldFailTest(self.name,
516 self.parameters['ZUUL_REF'])):
517 result = 'FAILURE'
518 if self.aborted:
519 result = 'ABORTED'
520
521 data = {'result': result}
522 changes = None
523 if 'ZUUL_CHANGE_IDS' in self.parameters:
524 changes = self.parameters['ZUUL_CHANGE_IDS']
525
526 self.worker.build_history.append(
527 BuildHistory(name=self.name, number=self.number,
528 result=result, changes=changes, node=self.node,
529 uuid=self.unique, description=self.description)
530 )
531
532 self.job.sendWorkComplete(json.dumps(data))
533 del self.worker.gearman_jobs[self.job.unique]
534 self.worker.running_builds.remove(self)
535 self.worker.lock.release()
536
537
538class FakeWorker(gear.Worker):
539 def __init__(self, worker_id):
540 super(FakeWorker, self).__init__(worker_id)
541 self.gearman_jobs = {}
542 self.build_history = []
543 self.running_builds = []
544 self.build_counter = 0
545 self.fail_tests = {}
546
547 self.hold_jobs_in_build = False
548 self.lock = threading.Lock()
549 self.__work_thread = threading.Thread(target=self.work)
550 self.__work_thread.start()
551
552 def handleJob(self, job):
553 parts = job.name.split(":")
554 cmd = parts[0]
555 name = parts[1]
556 if len(parts) > 2:
557 node = parts[2]
558 else:
559 node = None
560 if cmd == 'build':
561 self.handleBuild(job, name, node)
562 elif cmd == 'stop':
563 self.handleStop(job, name)
564 elif cmd == 'set_description':
565 self.handleSetDescription(job, name)
566
567 def handleBuild(self, job, name, node):
568 build = FakeBuild(self, job, self.build_counter, node)
569 job.build = build
570 self.gearman_jobs[job.unique] = job
571 self.build_counter += 1
572
573 self.running_builds.append(build)
574 build.start()
575
576 def handleStop(self, job, name):
577 self.log.debug("handle stop")
578 unique = job.arguments
579 for build in self.running_builds:
580 if build.unique == unique:
581 build.aborted = True
582 build.release()
583 job.sendWorkComplete()
584 return
585 job.sendWorkFail()
586
587 def handleSetDescription(self, job, name):
588 self.log.debug("handle set description")
589 parameters = json.loads(job.arguments)
590 unique = parameters['unique_id']
591 descr = parameters['html_description']
592 for build in self.running_builds:
593 if build.unique == unique:
594 build.description = descr
595 job.sendWorkComplete()
596 return
597 for build in self.build_history:
598 if build.uuid == unique:
599 build.description = descr
600 job.sendWorkComplete()
601 return
602 job.sendWorkFail()
603
604 def work(self):
605 while self.running:
606 try:
607 job = self.getJob()
608 except gear.InterruptedError:
609 continue
610 try:
611 self.handleJob(job)
612 except:
613 self.log.exception("Worker exception:")
614
615 def addFailTest(self, name, change):
616 l = self.fail_tests.get(name, [])
617 l.append(change)
618 self.fail_tests[name] = l
619
620 def shouldFailTest(self, name, ref):
621 l = self.fail_tests.get(name, [])
622 for change in l:
623 if ref_has_change(ref, change):
624 return True
625 return False
626
627 def release(self, regex=None):
628 builds = self.running_builds[:]
629 self.log.debug("releasing build %s (%s)" % (regex,
630 len(self.running_builds)))
631 for build in builds:
632 if not regex or re.match(regex, build.name):
633 self.log.debug("releasing build %s" %
634 (build.parameters['ZUUL_UUID']))
635 build.release()
636 else:
637 self.log.debug("not releasing build %s" %
638 (build.parameters['ZUUL_UUID']))
639 self.log.debug("done releasing builds %s (%s)" %
640 (regex, len(self.running_builds)))
641
642
643class FakeGearmanServer(gear.Server):
644 def __init__(self):
645 self.hold_jobs_in_queue = False
646 super(FakeGearmanServer, self).__init__(0)
647
648 def getJobForConnection(self, connection, peek=False):
649 for job in self.queue:
650 if not hasattr(job, 'waiting'):
651 if job.name.startswith('build:'):
652 job.waiting = self.hold_jobs_in_queue
653 else:
654 job.waiting = False
655 if job.waiting:
656 continue
657 if job.name in connection.functions:
658 if not peek:
659 self.queue.remove(job)
660 return job
661 return None
662
663 def release(self, regex=None):
664 released = False
665 queue = self.queue[:]
666 self.log.debug("releasing queued job %s (%s)" % (regex,
667 len(self.queue)))
668 for job in queue:
669 cmd, name = job.name.split(':')
670 if cmd != 'build':
671 continue
672 if not regex or re.match(regex, name):
673 self.log.debug("releasing queued job %s" %
674 job.unique)
675 job.waiting = False
676 released = True
677 else:
678 self.log.debug("not releasing queued job %s" %
679 job.unique)
680 if released:
681 self.wakeConnections()
682 self.log.debug("done releasing queued jobs %s (%s)" %
683 (regex, len(self.queue)))
684
685
James E. Blairb0fcae42012-07-17 11:12:10 -0700686class testScheduler(unittest.TestCase):
687 log = logging.getLogger("zuul.test")
688
689 def setUp(self):
James E. Blair1dbd5082012-08-23 15:12:15 -0700690 if os.path.exists(TEST_ROOT):
691 shutil.rmtree(TEST_ROOT)
692 os.makedirs(TEST_ROOT)
693 os.makedirs(UPSTREAM_ROOT)
694 os.makedirs(GIT_ROOT)
James E. Blair4886cc12012-07-18 15:39:41 -0700695
696 # For each project in config:
697 init_repo("org/project")
698 init_repo("org/project1")
699 init_repo("org/project2")
James E. Blair127bc182012-08-28 15:55:15 -0700700 init_repo("org/project3")
James E. Blair7f71c802012-08-22 13:04:32 -0700701 init_repo("org/one-job-project")
James E. Blair4ec821f2012-08-23 15:28:28 -0700702 init_repo("org/nonvoting-project")
Antoine Musso80edd5a2013-02-13 15:37:53 +0100703 init_repo("org/templated-project")
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700704 init_repo("org/node-project")
James E. Blair412e5582013-04-22 15:50:12 -0700705
706 self.statsd = FakeStatsd()
707 os.environ['STATSD_HOST'] = 'localhost'
708 os.environ['STATSD_PORT'] = str(self.statsd.port)
709 self.statsd.start()
710 # the statsd client object is configured in the statsd module import
711 reload(statsd)
712 reload(zuul.scheduler)
713
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700714 self.gearman_server = FakeGearmanServer()
715
716 self.config = ConfigParser.ConfigParser()
717 cfg = StringIO()
718 CONFIG.write(cfg)
719 cfg.seek(0)
720 self.config.readfp(cfg)
721 self.config.set('gearman', 'port', str(self.gearman_server.port))
722
723 self.worker = FakeWorker('fake_worker')
724 self.worker.addServer('127.0.0.1', self.gearman_server.port)
725 self.gearman_server.worker = self.worker
726
James E. Blairb0fcae42012-07-17 11:12:10 -0700727 self.sched = zuul.scheduler.Scheduler()
728
James E. Blair8cc15a82012-08-01 11:17:57 -0700729 def URLOpenerFactory(*args, **kw):
730 args = [self.fake_gerrit] + list(args)
731 return FakeURLOpener(*args, **kw)
732
James E. Blair8cc15a82012-08-01 11:17:57 -0700733 urllib2.urlopen = URLOpenerFactory
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700734 self.launcher = zuul.launcher.gearman.Gearman(self.config, self.sched)
James E. Blairb0fcae42012-07-17 11:12:10 -0700735
736 zuul.lib.gerrit.Gerrit = FakeGerrit
737
James E. Blair4886cc12012-07-18 15:39:41 -0700738 self.gerrit = FakeGerritTrigger(self.config, self.sched)
James E. Blair8cc15a82012-08-01 11:17:57 -0700739 self.gerrit.replication_timeout = 1.5
740 self.gerrit.replication_retry_interval = 0.5
James E. Blairb0fcae42012-07-17 11:12:10 -0700741 self.fake_gerrit = self.gerrit.gerrit
742
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700743 self.sched.setLauncher(self.launcher)
James E. Blairb0fcae42012-07-17 11:12:10 -0700744 self.sched.setTrigger(self.gerrit)
745
746 self.sched.start()
747 self.sched.reconfigure(self.config)
748 self.sched.resume()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700749 self.launcher.gearman.waitForServer()
750 self.registerJobs()
James E. Blairb0fcae42012-07-17 11:12:10 -0700751
752 def tearDown(self):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700753 self.launcher.stop()
754 self.worker.shutdown()
755 self.gearman_server.shutdown()
James E. Blairb0fcae42012-07-17 11:12:10 -0700756 self.gerrit.stop()
757 self.sched.stop()
758 self.sched.join()
James E. Blair412e5582013-04-22 15:50:12 -0700759 self.statsd.stop()
760 self.statsd.join()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700761 threads = threading.enumerate()
762 if len(threads) > 1:
763 self.log.error("More than one thread is running: %s" % threads)
James E. Blair1dbd5082012-08-23 15:12:15 -0700764 #shutil.rmtree(TEST_ROOT)
James E. Blairb0fcae42012-07-17 11:12:10 -0700765
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700766 def registerJobs(self):
767 count = 0
768 for job in self.sched.jobs.keys():
769 self.worker.registerFunction('build:' + job)
770 count += 1
771 self.worker.registerFunction('stop:' + self.worker.worker_id)
772 count += 1
773
774 while len(self.gearman_server.functions) < count:
775 time.sleep(0)
776
777 def release(self, job):
778 if isinstance(job, FakeBuild):
779 job.release()
780 else:
781 job.waiting = False
782 self.log.debug("Queued job %s released" % job.unique)
783 self.gearman_server.wakeConnections()
784
785 def getParameter(self, job, name):
786 if isinstance(job, FakeBuild):
787 return job.parameters[name]
788 else:
789 parameters = json.loads(job.arguments)
790 return parameters[name]
791
792 def resetGearmanServer(self):
793 self.worker.setFunctions([])
794 while True:
795 done = True
796 for connection in self.gearman_server.active_connections:
797 if connection.functions:
798 done = False
799 if done:
800 break
801 time.sleep(0)
802 self.gearman_server.functions = set()
803
804 def haveAllBuildsReported(self):
805 # See if Zuul is waiting on a meta job to complete
806 if self.launcher.meta_jobs:
807 return False
808 # Find out if every build that the worker has completed has been
809 # reported back to Zuul. If it hasn't then that means a Gearman
810 # event is still in transit and the system is not stable.
811 for build in self.worker.build_history:
812 zbuild = self.launcher.builds.get(build.uuid)
813 if not zbuild:
814 # It has already been reported
815 continue
816 # It hasn't been reported yet.
817 return False
818 # Make sure that none of the worker connections are in GRAB_WAIT
819 for connection in self.worker.active_connections:
820 if connection.state == 'GRAB_WAIT':
821 return False
822 return True
823
824 def areAllBuildsWaiting(self):
825 ret = True
826
827 builds = self.launcher.builds.values()
828 for build in builds:
829 client_job = None
830 for conn in self.launcher.gearman.active_connections:
831 for j in conn.related_jobs.values():
832 if j.unique == build.uuid:
833 client_job = j
834 break
835 if not client_job:
836 self.log.debug("%s is not known to the gearman client" %
837 build)
838 ret = False
839 continue
840 if not client_job.handle:
841 self.log.debug("%s has no handle" % client_job)
842 ret = False
843 continue
844 server_job = self.gearman_server.jobs.get(client_job.handle)
845 if not server_job:
846 self.log.debug("%s is not known to the gearman server" %
847 client_job)
848 ret = False
849 continue
850 if not hasattr(server_job, 'waiting'):
851 self.log.debug("%s is being enqueued" % server_job)
852 ret = False
853 continue
854 if server_job.waiting:
855 continue
856 worker_job = self.worker.gearman_jobs.get(server_job.unique)
857 if worker_job:
858 if worker_job.build.isWaiting():
859 continue
860 else:
861 self.log.debug("%s is running" % worker_job)
862 ret = False
863 else:
864 self.log.debug("%s is unassigned" % server_job)
865 ret = False
866 return ret
867
James E. Blairb0fcae42012-07-17 11:12:10 -0700868 def waitUntilSettled(self):
869 self.log.debug("Waiting until settled...")
870 start = time.time()
871 while True:
872 if time.time() - start > 10:
873 print 'queue status:',
874 print self.sched.trigger_event_queue.empty(),
875 print self.sched.result_event_queue.empty(),
876 print self.fake_gerrit.event_queue.empty(),
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700877 print self.areAllBuildsWaiting()
James E. Blairb0fcae42012-07-17 11:12:10 -0700878 raise Exception("Timeout waiting for Zuul to settle")
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700879 # Make sure no new events show up while we're checking
880 self.worker.lock.acquire()
881 # have all build states propogated to zuul?
882 if self.haveAllBuildsReported():
883 # Join ensures that the queue is empty _and_ events have been
884 # processed
885 self.fake_gerrit.event_queue.join()
886 self.sched.trigger_event_queue.join()
887 self.sched.result_event_queue.join()
888 if (self.sched.trigger_event_queue.empty() and
889 self.sched.result_event_queue.empty() and
890 self.fake_gerrit.event_queue.empty() and
891 self.areAllBuildsWaiting()):
892 self.worker.lock.release()
893 self.log.debug("...settled.")
894 return
895 self.worker.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700896 self.sched.wake_event.wait(0.1)
897
James E. Blaird466dc42012-07-31 10:42:56 -0700898 def countJobResults(self, jobs, result):
James E. Blair0018a6c2013-02-27 14:11:45 -0800899 jobs = filter(lambda x: x.result == result, jobs)
James E. Blaird466dc42012-07-31 10:42:56 -0700900 return len(jobs)
901
James E. Blaire0487072012-08-29 17:38:31 -0700902 def assertEmptyQueues(self):
903 # Make sure there are no orphaned jobs
904 for pipeline in self.sched.pipelines.values():
905 for queue in pipeline.queues:
906 if len(queue.queue) != 0:
James E. Blairf62d4282012-12-31 17:01:50 -0800907 print 'pipeline %s queue %s contents %s' % (
908 pipeline.name, queue.name, queue.queue)
James E. Blaire0487072012-08-29 17:38:31 -0700909 assert len(queue.queue) == 0
910 if len(queue.severed_heads) != 0:
911 print 'heads', queue.severed_heads
912 assert len(queue.severed_heads) == 0
913
James E. Blair412e5582013-04-22 15:50:12 -0700914 def assertReportedStat(self, key, value=None):
915 start = time.time()
916 while time.time() < (start + 5):
917 for stat in self.statsd.stats:
918 k, v = stat.split(':')
919 if key == k:
920 if value is None:
921 return
922 if value == v:
923 return
924 time.sleep(0.1)
925
926 pprint.pprint(self.statsd.stats)
927 raise Exception("Key %s not found in reported stats" % key)
928
James E. Blairb0fcae42012-07-17 11:12:10 -0700929 def test_jobs_launched(self):
930 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700931 builds = self.worker.running_builds
932 history = self.worker.build_history
933
James E. Blairb0fcae42012-07-17 11:12:10 -0700934 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -0700935 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700936 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
937 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700938 job_names = [x.name for x in history]
James E. Blairb0fcae42012-07-17 11:12:10 -0700939 assert 'project-merge' in job_names
940 assert 'project-test1' in job_names
941 assert 'project-test2' in job_names
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700942 assert history[0].result == 'SUCCESS'
943 assert history[1].result == 'SUCCESS'
944 assert history[2].result == 'SUCCESS'
James E. Blairb0fcae42012-07-17 11:12:10 -0700945 assert A.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -0700946 assert A.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -0700947 self.assertEmptyQueues()
James E. Blairb0fcae42012-07-17 11:12:10 -0700948
James E. Blair412e5582013-04-22 15:50:12 -0700949 self.assertReportedStat('gerrit.event.comment-added', '1|c')
950 self.assertReportedStat('zuul.pipeline.gate.current_changes', '1|g')
951 self.assertReportedStat('zuul.job.project-merge')
952 self.assertReportedStat('zuul.pipeline.gate.resident_time')
953 self.assertReportedStat('zuul.pipeline.gate.total_changes', '1|c')
954 self.assertReportedStat(
955 'zuul.pipeline.gate.org.project.resident_time')
956 self.assertReportedStat(
957 'zuul.pipeline.gate.org.project.total_changes', '1|c')
958
James E. Blairb0fcae42012-07-17 11:12:10 -0700959 def test_parallel_changes(self):
960 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700961 builds = self.worker.running_builds
962 history = self.worker.build_history
963
964 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -0700965 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
966 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
967 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700968 A.addApproval('CRVW', 2)
969 B.addApproval('CRVW', 2)
970 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700971
972 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
973 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
974 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
975
976 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700977 assert len(builds) == 1
978 assert builds[0].name == 'project-merge'
979 assert job_has_changes(builds[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700980
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700981 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700982 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700983 assert len(builds) == 3
984 assert builds[0].name == 'project-test1'
985 assert job_has_changes(builds[0], A)
986 assert builds[1].name == 'project-test2'
987 assert job_has_changes(builds[1], A)
988 assert builds[2].name == 'project-merge'
989 assert job_has_changes(builds[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -0700990
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700991 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700992 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700993 assert len(builds) == 5
994 assert builds[0].name == 'project-test1'
995 assert job_has_changes(builds[0], A)
996 assert builds[1].name == 'project-test2'
997 assert job_has_changes(builds[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -0700998
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700999 assert builds[2].name == 'project-test1'
1000 assert job_has_changes(builds[2], A, B)
1001 assert builds[3].name == 'project-test2'
1002 assert job_has_changes(builds[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -07001003
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001004 assert builds[4].name == 'project-merge'
1005 assert job_has_changes(builds[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -07001006
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001007 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001008 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001009 assert len(builds) == 6
1010 assert builds[0].name == 'project-test1'
1011 assert job_has_changes(builds[0], A)
1012 assert builds[1].name == 'project-test2'
1013 assert job_has_changes(builds[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -07001014
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001015 assert builds[2].name == 'project-test1'
1016 assert job_has_changes(builds[2], A, B)
1017 assert builds[3].name == 'project-test2'
1018 assert job_has_changes(builds[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -07001019
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001020 assert builds[4].name == 'project-test1'
1021 assert job_has_changes(builds[4], A, B, C)
1022 assert builds[5].name == 'project-test2'
1023 assert job_has_changes(builds[5], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -07001024
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001025 self.worker.hold_jobs_in_build = False
1026 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -07001027 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001028 assert len(builds) == 0
James E. Blairb0fcae42012-07-17 11:12:10 -07001029
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001030 assert len(history) == 9
James E. Blairb0fcae42012-07-17 11:12:10 -07001031 assert A.data['status'] == 'MERGED'
1032 assert B.data['status'] == 'MERGED'
1033 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001034 assert A.reported == 2
1035 assert B.reported == 2
1036 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001037 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001038
1039 def test_failed_changes(self):
1040 "Test that a change behind a failed change is retested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001041 builds = self.worker.running_builds
1042 history = self.worker.build_history
1043
James E. Blairb02a3bb2012-07-30 17:49:55 -07001044 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1045 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -07001046 A.addApproval('CRVW', 2)
1047 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001048
1049 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1050 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1051
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001052 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001053
1054 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001055 assert len(history) > 6
James E. Blairb02a3bb2012-07-30 17:49:55 -07001056 assert A.data['status'] == 'NEW'
1057 assert B.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001058 assert A.reported == 2
1059 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001060 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001061
1062 def test_independent_queues(self):
1063 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001064 builds = self.worker.running_builds
1065 history = self.worker.build_history
1066
1067 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +09001068 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001069 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1070 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001071 A.addApproval('CRVW', 2)
1072 B.addApproval('CRVW', 2)
1073 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001074
1075 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1076 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1077 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1078
James E. Blairb02a3bb2012-07-30 17:49:55 -07001079 self.waitUntilSettled()
1080
1081 # There should be one merge job at the head of each queue running
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001082 assert len(builds) == 2
1083 assert builds[0].name == 'project-merge'
1084 assert job_has_changes(builds[0], A)
1085 assert builds[1].name == 'project1-merge'
1086 assert job_has_changes(builds[1], B)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001087
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001088 # Release the current merge builds
1089 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001090 self.waitUntilSettled()
1091 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001092 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001093 self.waitUntilSettled()
1094
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001095 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -07001096 # project1 (3) + project2 (3) + project (2) = 8
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001097 assert len(builds) == 8
James E. Blairb02a3bb2012-07-30 17:49:55 -07001098
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001099 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001100 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001101 assert len(builds) == 0
James E. Blairb02a3bb2012-07-30 17:49:55 -07001102
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001103 assert len(history) == 11
James E. Blairb02a3bb2012-07-30 17:49:55 -07001104 assert A.data['status'] == 'MERGED'
1105 assert B.data['status'] == 'MERGED'
1106 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001107 assert A.reported == 2
1108 assert B.reported == 2
1109 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001110 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -07001111
1112 def test_failed_change_at_head(self):
1113 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001114 builds = self.worker.running_builds
1115 history = self.worker.build_history
James E. Blaird466dc42012-07-31 10:42:56 -07001116
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001117 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -07001118 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1119 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1120 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001121 A.addApproval('CRVW', 2)
1122 B.addApproval('CRVW', 2)
1123 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001124
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001125 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001126
1127 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1128 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1129 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1130
1131 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -07001132
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001133 assert len(builds) == 1
1134 assert builds[0].name == 'project-merge'
1135 assert job_has_changes(builds[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001136
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001137 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001138 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001139 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001140 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001141 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001142 self.waitUntilSettled()
1143
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001144 assert len(builds) == 6
1145 assert builds[0].name == 'project-test1'
1146 assert builds[1].name == 'project-test2'
1147 assert builds[2].name == 'project-test1'
1148 assert builds[3].name == 'project-test2'
1149 assert builds[4].name == 'project-test1'
1150 assert builds[5].name == 'project-test2'
James E. Blaird466dc42012-07-31 10:42:56 -07001151
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001152 self.release(builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001153 self.waitUntilSettled()
1154
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001155 assert len(builds) == 2 # project-test2, project-merge for B
1156 assert self.countJobResults(history, 'ABORTED') == 4
James E. Blaird466dc42012-07-31 10:42:56 -07001157
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001158 self.worker.hold_jobs_in_build = False
1159 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001160 self.waitUntilSettled()
1161
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001162 assert len(builds) == 0
1163 assert len(history) == 15
James E. Blaird466dc42012-07-31 10:42:56 -07001164 assert A.data['status'] == 'NEW'
1165 assert B.data['status'] == 'MERGED'
1166 assert C.data['status'] == 'MERGED'
1167 assert A.reported == 2
1168 assert B.reported == 2
1169 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001170 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -07001171
1172 def test_failed_change_at_head_with_queue(self):
1173 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001174 builds = self.worker.running_builds
1175 history = self.worker.build_history
1176 queue = self.gearman_server.queue
James E. Blaird466dc42012-07-31 10:42:56 -07001177
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001178 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -07001179 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1180 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1181 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001182 A.addApproval('CRVW', 2)
1183 B.addApproval('CRVW', 2)
1184 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001185
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001186 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001187
1188 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1189 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1190 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1191
1192 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001193 assert len(builds) == 0
James E. Blaird466dc42012-07-31 10:42:56 -07001194 assert len(queue) == 1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001195 assert queue[0].name == 'build:project-merge'
1196 assert job_has_changes(queue[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001197
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001198 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001199 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001200 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001201 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001202 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001203 self.waitUntilSettled()
1204
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001205 assert len(builds) == 0
James E. Blaird466dc42012-07-31 10:42:56 -07001206 assert len(queue) == 6
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001207 assert queue[0].name == 'build:project-test1'
1208 assert queue[1].name == 'build:project-test2'
1209 assert queue[2].name == 'build:project-test1'
1210 assert queue[3].name == 'build:project-test2'
1211 assert queue[4].name == 'build:project-test1'
1212 assert queue[5].name == 'build:project-test2'
James E. Blaird466dc42012-07-31 10:42:56 -07001213
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001214 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001215 self.waitUntilSettled()
1216
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001217 assert len(builds) == 0
1218 assert len(queue) == 2 # project-test2, project-merge for B
1219 assert self.countJobResults(history, 'ABORTED') == 0
James E. Blaird466dc42012-07-31 10:42:56 -07001220
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001221 self.gearman_server.hold_jobs_in_queue = False
1222 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001223 self.waitUntilSettled()
1224
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001225 assert len(builds) == 0
1226 assert len(history) == 11
James E. Blaird466dc42012-07-31 10:42:56 -07001227 assert A.data['status'] == 'NEW'
1228 assert B.data['status'] == 'MERGED'
1229 assert C.data['status'] == 'MERGED'
1230 assert A.reported == 2
1231 assert B.reported == 2
1232 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001233 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001234
1235 def test_patch_order(self):
1236 "Test that dependent patches are tested in the right order"
1237 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1238 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1239 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1240 A.addApproval('CRVW', 2)
1241 B.addApproval('CRVW', 2)
1242 C.addApproval('CRVW', 2)
1243
1244 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
1245 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1246 M2.setMerged()
1247 M1.setMerged()
1248
1249 # C -> B -> A -> M1 -> M2
1250 # M2 is here to make sure it is never queried. If it is, it
1251 # means zuul is walking down the entire history of merged
1252 # changes.
1253
1254 C.setDependsOn(B, 1)
1255 B.setDependsOn(A, 1)
1256 A.setDependsOn(M1, 1)
1257 M1.setDependsOn(M2, 1)
1258
1259 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1260
1261 self.waitUntilSettled()
1262
1263 assert A.data['status'] == 'NEW'
1264 assert B.data['status'] == 'NEW'
1265 assert C.data['status'] == 'NEW'
1266
1267 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1268 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1269
1270 self.waitUntilSettled()
1271 assert M2.queried == 0
1272 assert A.data['status'] == 'MERGED'
1273 assert B.data['status'] == 'MERGED'
1274 assert C.data['status'] == 'MERGED'
1275 assert A.reported == 2
1276 assert B.reported == 2
1277 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001278 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001279
1280 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -07001281 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -07001282 # TODO: move to test_gerrit (this is a unit test!)
1283 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair4aea70c2012-07-26 14:23:24 -07001284 a = self.sched.trigger.getChange(1, 2)
1285 mgr = self.sched.pipelines['gate'].manager
1286 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001287
1288 A.addApproval('CRVW', 2)
James E. Blair4aea70c2012-07-26 14:23:24 -07001289 a = self.sched.trigger.getChange(1, 2)
1290 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001291
1292 A.addApproval('APRV', 1)
James E. Blair4aea70c2012-07-26 14:23:24 -07001293 a = self.sched.trigger.getChange(1, 2)
1294 assert self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blaire0487072012-08-29 17:38:31 -07001295 self.assertEmptyQueues()
James E. Blair4886cc12012-07-18 15:39:41 -07001296
1297 def test_build_configuration(self):
1298 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001299 builds = self.worker.running_builds
1300 history = self.worker.build_history
1301 queue = self.gearman_server.queue
1302
1303 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -07001304 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1305 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1306 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1307 A.addApproval('CRVW', 2)
1308 B.addApproval('CRVW', 2)
1309 C.addApproval('CRVW', 2)
1310 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1311 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1312 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1313 self.waitUntilSettled()
1314
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001315 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001316 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001317 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001318 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001319 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001320 self.waitUntilSettled()
James E. Blair1dbd5082012-08-23 15:12:15 -07001321
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001322 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1323 self.gearman_server.hold_jobs_in_queue = False
1324 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001325 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -07001326
James E. Blair1dbd5082012-08-23 15:12:15 -07001327 path = os.path.join(GIT_ROOT, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -07001328 repo = git.Repo(path)
1329 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1330 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -07001331 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
1332 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001333 self.assertEmptyQueues()
James E. Blair973721f2012-08-15 10:19:43 -07001334
1335 def test_build_configuration_conflict(self):
1336 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001337 builds = self.worker.running_builds
1338 history = self.worker.build_history
1339 queue = self.gearman_server.queue
1340
1341 self.gearman_server.hold_jobs_in_queue = True
James E. Blair973721f2012-08-15 10:19:43 -07001342 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1343 A.addPatchset(['conflict'])
1344 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1345 B.addPatchset(['conflict'])
1346 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1347 A.addApproval('CRVW', 2)
1348 B.addApproval('CRVW', 2)
1349 C.addApproval('CRVW', 2)
1350 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1351 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1352 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1353 self.waitUntilSettled()
1354
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001355 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001356 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001357 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001358 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001359 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001360 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001361 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1362 self.gearman_server.hold_jobs_in_queue = False
1363 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001364 self.waitUntilSettled()
1365
1366 assert A.data['status'] == 'MERGED'
1367 assert B.data['status'] == 'NEW'
1368 assert C.data['status'] == 'MERGED'
1369 assert A.reported == 2
1370 assert B.reported == 2
1371 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001372 self.assertEmptyQueues()
James E. Blairdaabed22012-08-15 15:38:57 -07001373
1374 def test_post(self):
1375 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001376 builds = self.worker.running_builds
1377 history = self.worker.build_history
1378
Zhongyue Luo5d556072012-09-21 02:00:47 +09001379 e = {
1380 "type": "ref-updated",
1381 "submitter": {
1382 "name": "User Name",
1383 },
1384 "refUpdate": {
1385 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1386 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1387 "refName": "master",
1388 "project": "org/project",
1389 }
1390 }
James E. Blairdaabed22012-08-15 15:38:57 -07001391 self.fake_gerrit.addEvent(e)
1392 self.waitUntilSettled()
1393
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001394 job_names = [x.name for x in history]
1395 assert len(history) == 1
James E. Blairdaabed22012-08-15 15:38:57 -07001396 assert 'project-post' in job_names
James E. Blaire0487072012-08-29 17:38:31 -07001397 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001398
1399 def test_build_configuration_branch(self):
1400 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001401 builds = self.worker.running_builds
1402 history = self.worker.build_history
1403 queue = self.gearman_server.queue
1404
1405 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001406 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1407 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1408 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1409 A.addApproval('CRVW', 2)
1410 B.addApproval('CRVW', 2)
1411 C.addApproval('CRVW', 2)
1412 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1413 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1414 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1415 self.waitUntilSettled()
1416
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001417 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001418 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001419 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001420 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001421 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001422 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001423 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1424 self.gearman_server.hold_jobs_in_queue = False
1425 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001426 self.waitUntilSettled()
1427
James E. Blair1dbd5082012-08-23 15:12:15 -07001428 path = os.path.join(GIT_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001429 repo = git.Repo(path)
1430 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1431 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001432 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
1433 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001434 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001435
1436 def test_build_configuration_branch_interaction(self):
1437 "Test that switching between branches works"
1438 self.test_build_configuration()
1439 self.test_build_configuration_branch()
1440 # C has been merged, undo that
James E. Blair1dbd5082012-08-23 15:12:15 -07001441 path = os.path.join(UPSTREAM_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001442 repo = git.Repo(path)
1443 repo.heads.master.commit = repo.commit('init')
1444 self.test_build_configuration()
James E. Blaire0487072012-08-29 17:38:31 -07001445 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001446
1447 def test_build_configuration_multi_branch(self):
1448 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001449 builds = self.worker.running_builds
1450 history = self.worker.build_history
1451 queue = self.gearman_server.queue
1452
1453 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001454 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1455 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1456 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1457 A.addApproval('CRVW', 2)
1458 B.addApproval('CRVW', 2)
1459 C.addApproval('CRVW', 2)
1460 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1461 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1462 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1463 self.waitUntilSettled()
1464
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001465 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001466 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001467 ref_mp = self.getParameter(queue[-1], 'ZUUL_REF')
1468 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001469 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001470 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001471 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001472 ref_master = self.getParameter(queue[-1], 'ZUUL_REF')
1473 self.gearman_server.hold_jobs_in_queue = False
1474 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001475 self.waitUntilSettled()
1476
James E. Blair1dbd5082012-08-23 15:12:15 -07001477 path = os.path.join(GIT_ROOT, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001478 repo = git.Repo(path)
1479
1480 repo_messages = [c.message.strip()
1481 for c in repo.iter_commits(ref_master)]
1482 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001483 correct_messages = ['initial commit', 'A-1', 'C-1']
1484 assert repo_messages == correct_messages
1485
1486 repo_messages = [c.message.strip()
1487 for c in repo.iter_commits(ref_mp)]
1488 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001489 correct_messages = ['initial commit', 'mp commit', 'B-1']
1490 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001491 self.assertEmptyQueues()
James E. Blair7f71c802012-08-22 13:04:32 -07001492
1493 def test_one_job_project(self):
1494 "Test that queueing works with one job"
1495 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1496 'master', 'A')
1497 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1498 'master', 'B')
1499 A.addApproval('CRVW', 2)
1500 B.addApproval('CRVW', 2)
1501 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1502 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1503 self.waitUntilSettled()
1504
James E. Blair7f71c802012-08-22 13:04:32 -07001505 assert A.data['status'] == 'MERGED'
1506 assert A.reported == 2
1507 assert B.data['status'] == 'MERGED'
1508 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001509 self.assertEmptyQueues()
James E. Blaircaec0c52012-08-22 14:52:22 -07001510
Antoine Musso80edd5a2013-02-13 15:37:53 +01001511 def test_job_from_templates_launched(self):
1512 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001513 builds = self.worker.running_builds
1514 history = self.worker.build_history
1515
Antoine Musso80edd5a2013-02-13 15:37:53 +01001516 A = self.fake_gerrit.addFakeChange(
1517 'org/templated-project', 'master', 'A')
1518 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1519 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001520 job_names = [x.name for x in history]
Antoine Musso80edd5a2013-02-13 15:37:53 +01001521
1522 assert 'project-test1' in job_names
1523 assert 'project-test2' in job_names
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001524 assert history[0].result == 'SUCCESS'
1525 assert history[1].result == 'SUCCESS'
Antoine Musso80edd5a2013-02-13 15:37:53 +01001526
James E. Blaircaec0c52012-08-22 14:52:22 -07001527 def test_dependent_changes_dequeue(self):
1528 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001529 builds = self.worker.running_builds
1530 history = self.worker.build_history
1531
James E. Blaircaec0c52012-08-22 14:52:22 -07001532 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1533 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1534 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1535 A.addApproval('CRVW', 2)
1536 B.addApproval('CRVW', 2)
1537 C.addApproval('CRVW', 2)
1538
1539 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1540 M1.setMerged()
1541
1542 # C -> B -> A -> M1
1543
1544 C.setDependsOn(B, 1)
1545 B.setDependsOn(A, 1)
1546 A.setDependsOn(M1, 1)
1547
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001548 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07001549
1550 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1551 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1552 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1553
1554 self.waitUntilSettled()
1555
James E. Blairec590122012-08-22 15:19:31 -07001556 assert A.data['status'] == 'NEW'
1557 assert A.reported == 2
1558 assert B.data['status'] == 'NEW'
1559 assert B.reported == 2
1560 assert C.data['status'] == 'NEW'
1561 assert C.reported == 2
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001562 assert len(history) == 1
James E. Blaire0487072012-08-29 17:38:31 -07001563 self.assertEmptyQueues()
James E. Blairec590122012-08-22 15:19:31 -07001564
1565 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001566 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001567 # If it's dequeued more than once, we should see extra
1568 # aborted jobs.
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001569 builds = self.worker.running_builds
1570 history = self.worker.build_history
James E. Blairec590122012-08-22 15:19:31 -07001571
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001572 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07001573 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1574 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1575 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1576 A.addApproval('CRVW', 2)
1577 B.addApproval('CRVW', 2)
1578 C.addApproval('CRVW', 2)
1579
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001580 self.worker.addFailTest('project1-test1', A)
1581 self.worker.addFailTest('project1-test2', A)
1582 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07001583
1584 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1585 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1586 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1587
1588 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07001589
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001590 assert len(builds) == 1
1591 assert builds[0].name == 'project1-merge'
1592 assert job_has_changes(builds[0], A)
James E. Blairec590122012-08-22 15:19:31 -07001593
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001594 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001595 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001596 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001597 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001598 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001599 self.waitUntilSettled()
1600
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001601 assert len(builds) == 9
1602 assert builds[0].name == 'project1-test1'
1603 assert builds[1].name == 'project1-test2'
1604 assert builds[2].name == 'project1-project2-integration'
1605 assert builds[3].name == 'project1-test1'
1606 assert builds[4].name == 'project1-test2'
1607 assert builds[5].name == 'project1-project2-integration'
1608 assert builds[6].name == 'project1-test1'
1609 assert builds[7].name == 'project1-test2'
1610 assert builds[8].name == 'project1-project2-integration'
James E. Blairec590122012-08-22 15:19:31 -07001611
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001612 self.release(builds[0])
James E. Blairec590122012-08-22 15:19:31 -07001613 self.waitUntilSettled()
1614
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001615 assert len(builds) == 3 # test2, integration, merge for B
1616 assert self.countJobResults(history, 'ABORTED') == 6
James E. Blairec590122012-08-22 15:19:31 -07001617
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001618 self.worker.hold_jobs_in_build = False
1619 self.worker.release()
James E. Blairec590122012-08-22 15:19:31 -07001620 self.waitUntilSettled()
1621
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001622 assert len(builds) == 0
1623 assert len(history) == 20
James E. Blaircaec0c52012-08-22 14:52:22 -07001624
1625 assert A.data['status'] == 'NEW'
James E. Blairec590122012-08-22 15:19:31 -07001626 assert B.data['status'] == 'MERGED'
1627 assert C.data['status'] == 'MERGED'
1628 assert A.reported == 2
1629 assert B.reported == 2
1630 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001631 self.assertEmptyQueues()
James E. Blair4ec821f2012-08-23 15:28:28 -07001632
1633 def test_nonvoting_job(self):
1634 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001635 builds = self.worker.running_builds
1636 history = self.worker.build_history
1637
James E. Blair4ec821f2012-08-23 15:28:28 -07001638 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1639 'master', 'A')
1640 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001641 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07001642 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1643
1644 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07001645
1646 assert A.data['status'] == 'MERGED'
1647 assert A.reported == 2
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001648 assert history[0].result == 'SUCCESS'
1649 assert history[1].result == 'SUCCESS'
1650 assert history[2].result == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001651 self.assertEmptyQueues()
1652
1653 def test_check_queue_success(self):
1654 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001655 builds = self.worker.running_builds
1656 history = self.worker.build_history
1657
James E. Blaire0487072012-08-29 17:38:31 -07001658 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1659 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1660
1661 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001662
1663 assert A.data['status'] == 'NEW'
1664 assert A.reported == 1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001665 assert history[0].result == 'SUCCESS'
1666 assert history[1].result == 'SUCCESS'
1667 assert history[2].result == 'SUCCESS'
James E. Blaire0487072012-08-29 17:38:31 -07001668 self.assertEmptyQueues()
1669
1670 def test_check_queue_failure(self):
1671 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001672 builds = self.worker.running_builds
1673 history = self.worker.build_history
1674
James E. Blaire0487072012-08-29 17:38:31 -07001675 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001676 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07001677 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1678
1679 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001680
1681 assert A.data['status'] == 'NEW'
1682 assert A.reported == 1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001683 assert history[0].result == 'SUCCESS'
1684 assert history[1].result == 'SUCCESS'
1685 assert history[2].result == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001686 self.assertEmptyQueues()
James E. Blair127bc182012-08-28 15:55:15 -07001687
1688 def test_dependent_behind_dequeue(self):
1689 "test that dependent changes behind dequeued changes work"
1690 # This complicated test is a reproduction of a real life bug
1691 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07001692
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001693 builds = self.worker.running_builds
1694 history = self.worker.build_history
1695
1696 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07001697 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1698 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1699 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1700 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1701 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1702 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1703 D.setDependsOn(C, 1)
1704 E.setDependsOn(D, 1)
1705 A.addApproval('CRVW', 2)
1706 B.addApproval('CRVW', 2)
1707 C.addApproval('CRVW', 2)
1708 D.addApproval('CRVW', 2)
1709 E.addApproval('CRVW', 2)
1710 F.addApproval('CRVW', 2)
1711
1712 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07001713
1714 # Change object re-use in the gerrit trigger is hidden if
1715 # changes are added in quick succession; waiting makes it more
1716 # like real life.
1717 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1718 self.waitUntilSettled()
1719 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1720 self.waitUntilSettled()
1721
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001722 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001723 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001724 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001725 self.waitUntilSettled()
1726
1727 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1728 self.waitUntilSettled()
1729 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1730 self.waitUntilSettled()
1731 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1732 self.waitUntilSettled()
1733 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1734 self.waitUntilSettled()
1735
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001736 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001737 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001738 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001739 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001740 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001741 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001742 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001743 self.waitUntilSettled()
1744
1745 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001746
1747 # Grab pointers to the jobs we want to release before
1748 # releasing any, because list indexes may change as
1749 # the jobs complete.
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001750 a, b, c = builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07001751 a.release()
1752 b.release()
1753 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001754 self.waitUntilSettled()
1755
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001756 self.worker.hold_jobs_in_build = False
1757 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07001758 self.waitUntilSettled()
1759
James E. Blair127bc182012-08-28 15:55:15 -07001760 assert A.data['status'] == 'NEW'
1761 assert B.data['status'] == 'MERGED'
1762 assert C.data['status'] == 'MERGED'
1763 assert D.data['status'] == 'MERGED'
1764 assert E.data['status'] == 'MERGED'
1765 assert F.data['status'] == 'MERGED'
1766
1767 assert A.reported == 2
1768 assert B.reported == 2
1769 assert C.reported == 2
1770 assert D.reported == 2
1771 assert E.reported == 2
1772 assert F.reported == 2
1773
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001774 assert self.countJobResults(history, 'ABORTED') == 15
1775 assert len(history) == 44
James E. Blaire0487072012-08-29 17:38:31 -07001776 self.assertEmptyQueues()
James E. Blair05fed602012-09-07 12:45:24 -07001777
1778 def test_merger_repack(self):
1779 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001780 builds = self.worker.running_builds
1781 history = self.worker.build_history
1782
James E. Blair05fed602012-09-07 12:45:24 -07001783 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1784 A.addApproval('CRVW', 2)
1785 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1786 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001787 job_names = [x.name for x in history]
James E. Blair05fed602012-09-07 12:45:24 -07001788 assert 'project-merge' in job_names
1789 assert 'project-test1' in job_names
1790 assert 'project-test2' in job_names
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001791 assert history[0].result == 'SUCCESS'
1792 assert history[1].result == 'SUCCESS'
1793 assert history[2].result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001794 assert A.data['status'] == 'MERGED'
1795 assert A.reported == 2
1796 self.assertEmptyQueues()
1797
1798 path = os.path.join(GIT_ROOT, "org/project")
1799 os.system('git --git-dir=%s/.git repack -afd' % path)
1800
1801 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1802 A.addApproval('CRVW', 2)
1803 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1804 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001805 job_names = [x.name for x in history]
James E. Blair05fed602012-09-07 12:45:24 -07001806 assert 'project-merge' in job_names
1807 assert 'project-test1' in job_names
1808 assert 'project-test2' in job_names
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001809 assert history[0].result == 'SUCCESS'
1810 assert history[1].result == 'SUCCESS'
1811 assert history[2].result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001812 assert A.data['status'] == 'MERGED'
1813 assert A.reported == 2
1814 self.assertEmptyQueues()
James E. Blair7ee88a22012-09-12 18:59:31 +02001815
James E. Blair4886f282012-11-15 09:27:33 -08001816 def test_merger_repack_large_change(self):
1817 "Test that the merger works with large changes after a repack"
1818 # https://bugs.launchpad.net/zuul/+bug/1078946
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001819 builds = self.worker.running_builds
1820 history = self.worker.build_history
1821
James E. Blair4886f282012-11-15 09:27:33 -08001822 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1823 A.addPatchset(large=True)
1824 path = os.path.join(UPSTREAM_ROOT, "org/project1")
1825 os.system('git --git-dir=%s/.git repack -afd' % path)
1826 path = os.path.join(GIT_ROOT, "org/project1")
1827 os.system('git --git-dir=%s/.git repack -afd' % path)
1828
1829 A.addApproval('CRVW', 2)
1830 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1831 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001832 job_names = [x.name for x in history]
James E. Blair4886f282012-11-15 09:27:33 -08001833 assert 'project1-merge' in job_names
1834 assert 'project1-test1' in job_names
1835 assert 'project1-test2' in job_names
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001836 assert history[0].result == 'SUCCESS'
1837 assert history[1].result == 'SUCCESS'
1838 assert history[2].result == 'SUCCESS'
James E. Blair4886f282012-11-15 09:27:33 -08001839 assert A.data['status'] == 'MERGED'
1840 assert A.reported == 2
1841 self.assertEmptyQueues()
1842
James E. Blair7ee88a22012-09-12 18:59:31 +02001843 def test_nonexistent_job(self):
1844 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001845 builds = self.worker.running_builds
1846 history = self.worker.build_history
1847
1848 # Set to the state immediately after a restart
1849 self.resetGearmanServer()
1850 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02001851
1852 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1853 A.addApproval('CRVW', 2)
1854 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1855 # There may be a thread about to report a lost change
1856 while A.reported < 2:
1857 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001858 job_names = [x.name for x in history]
James E. Blair7ee88a22012-09-12 18:59:31 +02001859 assert not job_names
1860 assert A.data['status'] == 'NEW'
1861 assert A.reported == 2
1862 self.assertEmptyQueues()
1863
1864 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001865 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02001866 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1867 A.addApproval('CRVW', 2)
1868 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1869 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001870 job_names = [x.name for x in history]
James E. Blair7ee88a22012-09-12 18:59:31 +02001871 assert 'project-merge' in job_names
1872 assert 'project-test1' in job_names
1873 assert 'project-test2' in job_names
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001874 assert history[0].result == 'SUCCESS'
1875 assert history[1].result == 'SUCCESS'
1876 assert history[2].result == 'SUCCESS'
James E. Blair7ee88a22012-09-12 18:59:31 +02001877 assert A.data['status'] == 'MERGED'
1878 assert A.reported == 2
1879 self.assertEmptyQueues()
James E. Blairf62d4282012-12-31 17:01:50 -08001880
1881 def test_single_nonexistent_post_job(self):
1882 "Test launching a single post job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001883 builds = self.worker.running_builds
1884 history = self.worker.build_history
James E. Blairf62d4282012-12-31 17:01:50 -08001885
1886 e = {
1887 "type": "ref-updated",
1888 "submitter": {
1889 "name": "User Name",
1890 },
1891 "refUpdate": {
1892 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1893 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1894 "refName": "master",
1895 "project": "org/project",
1896 }
1897 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001898 # Set to the state immediately after a restart
1899 self.resetGearmanServer()
1900 self.launcher.negative_function_cache_ttl = 0
1901
James E. Blairf62d4282012-12-31 17:01:50 -08001902 self.fake_gerrit.addEvent(e)
1903 self.waitUntilSettled()
1904
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001905 assert len(history) == 0
James E. Blairf62d4282012-12-31 17:01:50 -08001906 self.assertEmptyQueues()
James E. Blair2fa50962013-01-30 21:50:41 -08001907
1908 def test_new_patchset_dequeues_old(self):
1909 "Test that a new patchset causes the old to be dequeued"
1910 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001911 builds = self.worker.running_builds
1912 history = self.worker.build_history
James E. Blair2fa50962013-01-30 21:50:41 -08001913
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001914 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001915 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1916 M.setMerged()
1917
1918 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1919 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1920 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1921 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1922 A.addApproval('CRVW', 2)
1923 B.addApproval('CRVW', 2)
1924 C.addApproval('CRVW', 2)
1925 D.addApproval('CRVW', 2)
1926
1927 C.setDependsOn(B, 1)
1928 B.setDependsOn(A, 1)
1929 A.setDependsOn(M, 1)
1930
1931 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1932 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1933 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1934 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1935 self.waitUntilSettled()
1936
1937 B.addPatchset()
1938 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1939 self.waitUntilSettled()
1940
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001941 self.worker.hold_jobs_in_build = False
1942 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001943 self.waitUntilSettled()
1944
James E. Blair2fa50962013-01-30 21:50:41 -08001945 assert A.data['status'] == 'MERGED'
1946 assert A.reported == 2
1947 assert B.data['status'] == 'NEW'
1948 assert B.reported == 2
1949 assert C.data['status'] == 'NEW'
1950 assert C.reported == 2
1951 assert D.data['status'] == 'MERGED'
1952 assert D.reported == 2
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001953 assert len(history) == 9 # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08001954 self.assertEmptyQueues()
1955
1956 def test_new_patchset_dequeues_old_on_head(self):
1957 "Test that a new patchset causes the old to be dequeued (at head)"
1958 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001959 builds = self.worker.running_builds
1960 history = self.worker.build_history
James E. Blair2fa50962013-01-30 21:50:41 -08001961
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001962 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001963 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1964 M.setMerged()
1965 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1966 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1967 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1968 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1969 A.addApproval('CRVW', 2)
1970 B.addApproval('CRVW', 2)
1971 C.addApproval('CRVW', 2)
1972 D.addApproval('CRVW', 2)
1973
1974 C.setDependsOn(B, 1)
1975 B.setDependsOn(A, 1)
1976 A.setDependsOn(M, 1)
1977
1978 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1979 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1980 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1981 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1982 self.waitUntilSettled()
1983
1984 A.addPatchset()
1985 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1986 self.waitUntilSettled()
1987
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001988 self.worker.hold_jobs_in_build = False
1989 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001990 self.waitUntilSettled()
1991
James E. Blair2fa50962013-01-30 21:50:41 -08001992 assert A.data['status'] == 'NEW'
1993 assert A.reported == 2
1994 assert B.data['status'] == 'NEW'
1995 assert B.reported == 2
1996 assert C.data['status'] == 'NEW'
1997 assert C.reported == 2
1998 assert D.data['status'] == 'MERGED'
1999 assert D.reported == 2
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002000 assert len(history) == 7
James E. Blair2fa50962013-01-30 21:50:41 -08002001 self.assertEmptyQueues()
2002
2003 def test_new_patchset_dequeues_old_without_dependents(self):
2004 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002005 builds = self.worker.running_builds
2006 history = self.worker.build_history
James E. Blair2fa50962013-01-30 21:50:41 -08002007
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002008 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002009 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2010 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2011 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2012 A.addApproval('CRVW', 2)
2013 B.addApproval('CRVW', 2)
2014 C.addApproval('CRVW', 2)
2015
2016 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2017 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2018 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2019 self.waitUntilSettled()
2020
2021 B.addPatchset()
2022 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2023 self.waitUntilSettled()
2024
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002025 self.worker.hold_jobs_in_build = False
2026 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002027 self.waitUntilSettled()
2028
James E. Blair2fa50962013-01-30 21:50:41 -08002029 assert A.data['status'] == 'MERGED'
2030 assert A.reported == 2
2031 assert B.data['status'] == 'NEW'
2032 assert B.reported == 2
2033 assert C.data['status'] == 'MERGED'
2034 assert C.reported == 2
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002035 assert len(history) == 9
James E. Blair2fa50962013-01-30 21:50:41 -08002036 self.assertEmptyQueues()
2037
2038 def test_new_patchset_dequeues_old_independent_queue(self):
2039 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002040 builds = self.worker.running_builds
2041 history = self.worker.build_history
James E. Blair2fa50962013-01-30 21:50:41 -08002042
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002043 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002044 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2045 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2046 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2047 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2048 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2049 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2050 self.waitUntilSettled()
2051
2052 B.addPatchset()
2053 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2054 self.waitUntilSettled()
2055
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002056 self.worker.hold_jobs_in_build = False
2057 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002058 self.waitUntilSettled()
2059
James E. Blair2fa50962013-01-30 21:50:41 -08002060 assert A.data['status'] == 'NEW'
2061 assert A.reported == 1
2062 assert B.data['status'] == 'NEW'
2063 assert B.reported == 1
2064 assert C.data['status'] == 'NEW'
2065 assert C.reported == 1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002066 assert len(history) == 10
2067 assert self.countJobResults(history, 'ABORTED') == 1
James E. Blair2fa50962013-01-30 21:50:41 -08002068 self.assertEmptyQueues()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002069
2070 def test_zuul_refs(self):
2071 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002072 builds = self.worker.running_builds
2073 history = self.worker.build_history
James E. Blair7d0dedc2013-02-21 17:26:09 -08002074
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002075 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08002076 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
2077 M1.setMerged()
2078 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
2079 M2.setMerged()
2080
2081 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2082 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2083 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
2084 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
2085 A.addApproval('CRVW', 2)
2086 B.addApproval('CRVW', 2)
2087 C.addApproval('CRVW', 2)
2088 D.addApproval('CRVW', 2)
2089 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2090 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2091 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2092 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2093
2094 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002095 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002096 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002097 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002098 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002099 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002100 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002101 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002102 self.waitUntilSettled()
2103
James E. Blair7d0dedc2013-02-21 17:26:09 -08002104 a_zref = b_zref = c_zref = d_zref = None
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002105 for x in builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08002106 if x.parameters['ZUUL_CHANGE'] == '3':
2107 a_zref = x.parameters['ZUUL_REF']
2108 if x.parameters['ZUUL_CHANGE'] == '4':
2109 b_zref = x.parameters['ZUUL_REF']
2110 if x.parameters['ZUUL_CHANGE'] == '5':
2111 c_zref = x.parameters['ZUUL_REF']
2112 if x.parameters['ZUUL_CHANGE'] == '6':
2113 d_zref = x.parameters['ZUUL_REF']
2114
2115 # There are... four... refs.
2116 assert a_zref is not None
2117 assert b_zref is not None
2118 assert c_zref is not None
2119 assert d_zref is not None
2120
2121 # And they should all be different
2122 refs = set([a_zref, b_zref, c_zref, d_zref])
2123 assert len(refs) == 4
2124
2125 # a ref should have a, not b, and should not be in project2
2126 assert ref_has_change(a_zref, A)
2127 assert not ref_has_change(a_zref, B)
2128 assert not ref_has_change(a_zref, M2)
2129
2130 # b ref should have a and b, and should not be in project2
2131 assert ref_has_change(b_zref, A)
2132 assert ref_has_change(b_zref, B)
2133 assert not ref_has_change(b_zref, M2)
2134
2135 # c ref should have a and b in 1, c in 2
2136 assert ref_has_change(c_zref, A)
2137 assert ref_has_change(c_zref, B)
2138 assert ref_has_change(c_zref, C)
2139 assert not ref_has_change(c_zref, D)
2140
2141 # d ref should have a and b in 1, c and d in 2
2142 assert ref_has_change(d_zref, A)
2143 assert ref_has_change(d_zref, B)
2144 assert ref_has_change(d_zref, C)
2145 assert ref_has_change(d_zref, D)
2146
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002147 self.worker.hold_jobs_in_build = False
2148 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002149 self.waitUntilSettled()
2150
2151 assert A.data['status'] == 'MERGED'
2152 assert A.reported == 2
2153 assert B.data['status'] == 'MERGED'
2154 assert B.reported == 2
2155 assert C.data['status'] == 'MERGED'
2156 assert C.reported == 2
2157 assert D.data['status'] == 'MERGED'
2158 assert D.reported == 2
2159 self.assertEmptyQueues()
James E. Blair70c71582013-03-06 08:50:50 -08002160
James E. Blair412e5582013-04-22 15:50:12 -07002161 def test_statsd(self):
2162 "Test each of the statsd methods used in the scheduler"
2163 import extras
2164 statsd = extras.try_import('statsd.statsd')
2165 statsd.incr('test-incr')
2166 statsd.timing('test-timing', 3)
2167 statsd.gauge('test-guage', 12)
2168 self.assertReportedStat('test-incr', '1|c')
2169 self.assertReportedStat('test-timing', '3|ms')
2170 self.assertReportedStat('test-guage', '12|g')
2171
James E. Blair70c71582013-03-06 08:50:50 -08002172 def test_file_jobs(self):
2173 "Test that file jobs run only when appropriate"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002174 builds = self.worker.running_builds
2175 history = self.worker.build_history
2176
James E. Blair70c71582013-03-06 08:50:50 -08002177 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2178 A.addPatchset(['pip-requires'])
2179 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2180 A.addApproval('CRVW', 2)
2181 B.addApproval('CRVW', 2)
2182 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2183 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2184 self.waitUntilSettled()
2185
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002186 testfile_jobs = [x for x in history
James E. Blair70c71582013-03-06 08:50:50 -08002187 if x.name == 'project-testfile']
2188
2189 assert len(testfile_jobs) == 1
2190 assert testfile_jobs[0].changes == '1,2'
2191 assert A.data['status'] == 'MERGED'
2192 assert A.reported == 2
2193 assert B.data['status'] == 'MERGED'
2194 assert B.reported == 2
2195 self.assertEmptyQueues()
James E. Blair3c5e5b52013-04-26 11:17:03 -07002196
2197 def test_test_config(self):
2198 "Test that we can test the config"
2199 sched = zuul.scheduler.Scheduler()
2200 sched.testConfig(CONFIG.get('zuul', 'layout_config'))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002201
2202 def test_build_description(self):
2203 "Test that build descriptions update"
2204 builds = self.worker.running_builds
2205 history = self.worker.build_history
2206
2207 self.worker.registerFunction('set_description:' +
2208 self.worker.worker_id)
2209
2210 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2211 A.addApproval('CRVW', 2)
2212 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2213 self.waitUntilSettled()
2214 desc = history[0].description
2215 self.log.debug("Description: %s" % desc)
2216 assert re.search("Branch.*master", desc)
2217 assert re.search("Pipeline.*gate", desc)
2218 assert re.search("project-merge.*SUCCESS", desc)
2219 assert re.search("project-test1.*SUCCESS", desc)
2220 assert re.search("project-test2.*SUCCESS", desc)
2221 assert re.search("Reported result.*SUCCESS", desc)
2222
2223 def test_node_label(self):
2224 "Test that a job runs on a specific node label"
2225 builds = self.worker.running_builds
2226 history = self.worker.build_history
2227
2228 self.worker.registerFunction('build:node-project-test1:debian')
2229
2230 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2231 A.addApproval('CRVW', 2)
2232 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2233 self.waitUntilSettled()
2234 assert history[0].node is None
2235 assert history[1].node == 'debian'
2236 assert history[2].node is None