blob: da9b4318a469d2e3c8008e2a298539a688f27e0a [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
James E. Blairb0fcae42012-07-17 11:12:10 -070017import ConfigParser
Monty Taylorbc758832013-06-17 17:22:42 -040018from cStringIO import StringIO
James E. Blair8cc15a82012-08-01 11:17:57 -070019import hashlib
James E. Blairb0fcae42012-07-17 11:12:10 -070020import json
Monty Taylorbc758832013-06-17 17:22:42 -040021import logging
22import os
James E. Blairb0fcae42012-07-17 11:12:10 -070023import pprint
Monty Taylorbc758832013-06-17 17:22:42 -040024import Queue
25import random
James E. Blairb0fcae42012-07-17 11:12:10 -070026import re
James E. Blair412e5582013-04-22 15:50:12 -070027import select
James E. Blair4886cc12012-07-18 15:39:41 -070028import shutil
James E. Blair412e5582013-04-22 15:50:12 -070029import socket
James E. Blair4886f282012-11-15 09:27:33 -080030import string
Monty Taylorbc758832013-06-17 17:22:42 -040031import subprocess
32import tempfile
33import threading
34import time
35import urllib2
36import urlparse
37
James E. Blair4886cc12012-07-18 15:39:41 -070038import git
James E. Blair1f4c2bb2013-04-26 08:40:46 -070039import gear
Monty Taylorbc758832013-06-17 17:22:42 -040040import fixtures
41import statsd
42import testtools
James E. Blairb0fcae42012-07-17 11:12:10 -070043
James E. Blairb0fcae42012-07-17 11:12:10 -070044import zuul.scheduler
James E. Blair1f4c2bb2013-04-26 08:40:46 -070045import zuul.launcher.gearman
James E. Blairb0fcae42012-07-17 11:12:10 -070046import zuul.trigger.gerrit
47
48FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
49 'fixtures')
50CONFIG = ConfigParser.ConfigParser()
51CONFIG.read(os.path.join(FIXTURE_DIR, "zuul.conf"))
52
53CONFIG.set('zuul', 'layout_config',
54 os.path.join(FIXTURE_DIR, "layout.yaml"))
55
James E. Blair1f4c2bb2013-04-26 08:40:46 -070056logging.basicConfig(level=logging.DEBUG,
57 format='%(asctime)s %(name)-32s '
58 '%(levelname)-8s %(message)s')
James E. Blairb0fcae42012-07-17 11:12:10 -070059
60
Monty Taylorbc758832013-06-17 17:22:42 -040061def repack_repo(path):
62 output = subprocess.Popen(
63 ['git', '--git-dir=%s/.git' % path, 'repack', '-afd'],
64 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
65 out = output.communicate()
66 if output.returncode:
67 raise Exception("git repack returned %d" % output.returncode)
68 return out
69
70
James E. Blair8cc15a82012-08-01 11:17:57 -070071def random_sha1():
72 return hashlib.sha1(str(random.random())).hexdigest()
73
74
James E. Blair4886cc12012-07-18 15:39:41 -070075class ChangeReference(git.Reference):
76 _common_path_default = "refs/changes"
77 _points_to_commits_only = True
78
79
James E. Blairb0fcae42012-07-17 11:12:10 -070080class FakeChange(object):
James E. Blair8c803f82012-07-31 16:25:42 -070081 categories = {'APRV': ('Approved', -1, 1),
82 'CRVW': ('Code-Review', -2, 2),
83 'VRFY': ('Verified', -2, 2)}
James E. Blairb0fcae42012-07-17 11:12:10 -070084
Monty Taylorbc758832013-06-17 17:22:42 -040085 def __init__(self, gerrit, number, project, branch, subject,
86 status='NEW', upstream_root=None):
James E. Blair8cc15a82012-08-01 11:17:57 -070087 self.gerrit = gerrit
James E. Blaird466dc42012-07-31 10:42:56 -070088 self.reported = 0
James E. Blair8c803f82012-07-31 16:25:42 -070089 self.queried = 0
James E. Blairb0fcae42012-07-17 11:12:10 -070090 self.patchsets = []
James E. Blairb0fcae42012-07-17 11:12:10 -070091 self.number = number
92 self.project = project
93 self.branch = branch
94 self.subject = subject
95 self.latest_patchset = 0
James E. Blair8c803f82012-07-31 16:25:42 -070096 self.depends_on_change = None
97 self.needed_by_changes = []
James E. Blair127bc182012-08-28 15:55:15 -070098 self.fail_merge = False
James E. Blair42f74822013-05-14 15:18:03 -070099 self.messages = []
James E. Blairb0fcae42012-07-17 11:12:10 -0700100 self.data = {
101 'branch': branch,
102 'comments': [],
103 'commitMessage': subject,
104 'createdOn': time.time(),
James E. Blair8cc15a82012-08-01 11:17:57 -0700105 'id': 'I' + random_sha1(),
James E. Blairb0fcae42012-07-17 11:12:10 -0700106 'lastUpdated': time.time(),
107 'number': str(number),
108 'open': True,
109 'owner': {'email': 'user@example.com',
110 'name': 'User Name',
111 'username': 'username'},
112 'patchSets': self.patchsets,
113 'project': project,
114 'status': status,
115 'subject': subject,
James E. Blair8c803f82012-07-31 16:25:42 -0700116 'submitRecords': [],
James E. Blairb0fcae42012-07-17 11:12:10 -0700117 'url': 'https://hostname/%s' % number}
118
Monty Taylorbc758832013-06-17 17:22:42 -0400119 self.upstream_root = upstream_root
James E. Blairb0fcae42012-07-17 11:12:10 -0700120 self.addPatchset()
James E. Blair8c803f82012-07-31 16:25:42 -0700121 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700122
Monty Taylorbc758832013-06-17 17:22:42 -0400123 def add_fake_change_to_repo(self, msg, fn, large):
124 path = os.path.join(self.upstream_root, self.project)
125 repo = git.Repo(path)
126 ref = ChangeReference.create(repo, '1/%s/%s' % (self.number,
127 self.latest_patchset),
128 'refs/tags/init')
129 repo.head.reference = ref
130 repo.head.reset(index=True, working_tree=True)
131 repo.git.clean('-x', '-f', '-d')
132
133 path = os.path.join(self.upstream_root, self.project)
134 if not large:
135 fn = os.path.join(path, fn)
136 f = open(fn, 'w')
137 f.write("test %s %s %s\n" %
138 (self.branch, self.number, self.latest_patchset))
139 f.close()
140 repo.index.add([fn])
141 else:
142 for fni in range(100):
143 fn = os.path.join(path, str(fni))
144 f = open(fn, 'w')
145 for ci in range(4096):
146 f.write(random.choice(string.printable))
147 f.close()
148 repo.index.add([fn])
149
150 return repo.index.commit(msg)
151
James E. Blair70c71582013-03-06 08:50:50 -0800152 def addPatchset(self, files=[], large=False):
James E. Blairb0fcae42012-07-17 11:12:10 -0700153 self.latest_patchset += 1
James E. Blairdaabed22012-08-15 15:38:57 -0700154 if files:
155 fn = files[0]
156 else:
157 fn = '%s-%s' % (self.branch, self.number)
158 msg = self.subject + '-' + str(self.latest_patchset)
Monty Taylorbc758832013-06-17 17:22:42 -0400159 c = self.add_fake_change_to_repo(msg, fn, large)
James E. Blair70c71582013-03-06 08:50:50 -0800160 ps_files = [{'file': '/COMMIT_MSG',
161 'type': 'ADDED'},
162 {'file': 'README',
163 'type': 'MODIFIED'}]
164 for f in files:
165 ps_files.append({'file': f, 'type': 'ADDED'})
James E. Blairb0fcae42012-07-17 11:12:10 -0700166 d = {'approvals': [],
167 'createdOn': time.time(),
James E. Blair70c71582013-03-06 08:50:50 -0800168 'files': ps_files,
James E. Blair8c803f82012-07-31 16:25:42 -0700169 'number': str(self.latest_patchset),
James E. Blairb0fcae42012-07-17 11:12:10 -0700170 'ref': 'refs/changes/1/%s/%s' % (self.number,
171 self.latest_patchset),
James E. Blairdaabed22012-08-15 15:38:57 -0700172 'revision': c.hexsha,
James E. Blairb0fcae42012-07-17 11:12:10 -0700173 'uploader': {'email': 'user@example.com',
174 'name': 'User name',
175 'username': 'user'}}
176 self.data['currentPatchSet'] = d
177 self.patchsets.append(d)
James E. Blair8c803f82012-07-31 16:25:42 -0700178 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700179
James E. Blaire0487072012-08-29 17:38:31 -0700180 def getPatchsetCreatedEvent(self, patchset):
181 event = {"type": "patchset-created",
182 "change": {"project": self.project,
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800183 "branch": self.branch,
184 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
185 "number": str(self.number),
186 "subject": self.subject,
187 "owner": {"name": "User Name"},
188 "url": "https://hostname/3"},
James E. Blaire0487072012-08-29 17:38:31 -0700189 "patchSet": self.patchsets[patchset - 1],
190 "uploader": {"name": "User Name"}}
191 return event
192
James E. Blair42f74822013-05-14 15:18:03 -0700193 def getChangeRestoredEvent(self):
194 event = {"type": "change-restored",
195 "change": {"project": self.project,
196 "branch": self.branch,
197 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
198 "number": str(self.number),
199 "subject": self.subject,
200 "owner": {"name": "User Name"},
201 "url": "https://hostname/3"},
202 "restorer": {"name": "User Name"},
203 "reason": ""}
204 return event
205
James E. Blairb0fcae42012-07-17 11:12:10 -0700206 def addApproval(self, category, value):
James E. Blair8c803f82012-07-31 16:25:42 -0700207 approval = {'description': self.categories[category][0],
208 'type': category,
209 'value': str(value)}
210 self.patchsets[-1]['approvals'].append(approval)
211 event = {'approvals': [approval],
James E. Blairb0fcae42012-07-17 11:12:10 -0700212 'author': {'email': 'user@example.com',
213 'name': 'User Name',
214 'username': 'username'},
215 'change': {'branch': self.branch,
216 'id': 'Iaa69c46accf97d0598111724a38250ae76a22c87',
217 'number': str(self.number),
218 'owner': {'email': 'user@example.com',
219 'name': 'User Name',
220 'username': 'username'},
221 'project': self.project,
222 'subject': self.subject,
223 'topic': 'master',
224 'url': 'https://hostname/459'},
225 'comment': '',
226 'patchSet': self.patchsets[-1],
227 'type': 'comment-added'}
James E. Blair8c803f82012-07-31 16:25:42 -0700228 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700229 return json.loads(json.dumps(event))
230
James E. Blair8c803f82012-07-31 16:25:42 -0700231 def getSubmitRecords(self):
232 status = {}
233 for cat in self.categories.keys():
234 status[cat] = 0
235
236 for a in self.patchsets[-1]['approvals']:
237 cur = status[a['type']]
238 cat_min, cat_max = self.categories[a['type']][1:]
239 new = int(a['value'])
240 if new == cat_min:
241 cur = new
242 elif abs(new) > abs(cur):
243 cur = new
244 status[a['type']] = cur
245
246 labels = []
247 ok = True
248 for typ, cat in self.categories.items():
249 cur = status[typ]
250 cat_min, cat_max = cat[1:]
251 if cur == cat_min:
252 value = 'REJECT'
253 ok = False
254 elif cur == cat_max:
255 value = 'OK'
256 else:
257 value = 'NEED'
258 ok = False
259 labels.append({'label': cat[0], 'status': value})
260 if ok:
261 return [{'status': 'OK'}]
262 return [{'status': 'NOT_READY',
263 'labels': labels}]
264
265 def setDependsOn(self, other, patchset):
266 self.depends_on_change = other
267 d = {'id': other.data['id'],
268 'number': other.data['number'],
269 'ref': other.patchsets[patchset - 1]['ref']
270 }
271 self.data['dependsOn'] = [d]
272
273 other.needed_by_changes.append(self)
274 needed = other.data.get('neededBy', [])
275 d = {'id': self.data['id'],
276 'number': self.data['number'],
277 'ref': self.patchsets[patchset - 1]['ref'],
278 'revision': self.patchsets[patchset - 1]['revision']
279 }
280 needed.append(d)
281 other.data['neededBy'] = needed
282
James E. Blairb0fcae42012-07-17 11:12:10 -0700283 def query(self):
James E. Blair8c803f82012-07-31 16:25:42 -0700284 self.queried += 1
285 d = self.data.get('dependsOn')
286 if d:
287 d = d[0]
288 if (self.depends_on_change.patchsets[-1]['ref'] == d['ref']):
289 d['isCurrentPatchSet'] = True
290 else:
291 d['isCurrentPatchSet'] = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700292 return json.loads(json.dumps(self.data))
293
294 def setMerged(self):
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800295 if (self.depends_on_change and
296 self.depends_on_change.data['status'] != 'MERGED'):
James E. Blaircaec0c52012-08-22 14:52:22 -0700297 return
James E. Blair127bc182012-08-28 15:55:15 -0700298 if self.fail_merge:
299 return
James E. Blairb0fcae42012-07-17 11:12:10 -0700300 self.data['status'] = 'MERGED'
301 self.open = False
James E. Blairdaabed22012-08-15 15:38:57 -0700302
Monty Taylorbc758832013-06-17 17:22:42 -0400303 path = os.path.join(self.upstream_root, self.project)
James E. Blairdaabed22012-08-15 15:38:57 -0700304 repo = git.Repo(path)
305 repo.heads[self.branch].commit = \
306 repo.commit(self.patchsets[-1]['revision'])
James E. Blairb0fcae42012-07-17 11:12:10 -0700307
James E. Blaird466dc42012-07-31 10:42:56 -0700308 def setReported(self):
309 self.reported += 1
310
James E. Blairb0fcae42012-07-17 11:12:10 -0700311
312class FakeGerrit(object):
313 def __init__(self, *args, **kw):
314 self.event_queue = Queue.Queue()
315 self.fixture_dir = os.path.join(FIXTURE_DIR, 'gerrit')
316 self.change_number = 0
317 self.changes = {}
318
319 def addFakeChange(self, project, branch, subject):
320 self.change_number += 1
Monty Taylorbc758832013-06-17 17:22:42 -0400321 c = FakeChange(self, self.change_number, project, branch, subject,
322 upstream_root=self.upstream_root)
James E. Blairb0fcae42012-07-17 11:12:10 -0700323 self.changes[self.change_number] = c
324 return c
325
326 def addEvent(self, data):
327 return self.event_queue.put(data)
328
329 def getEvent(self):
330 return self.event_queue.get()
331
332 def eventDone(self):
333 self.event_queue.task_done()
334
335 def review(self, project, changeid, message, action):
James E. Blaird466dc42012-07-31 10:42:56 -0700336 number, ps = changeid.split(',')
337 change = self.changes[int(number)]
James E. Blair42f74822013-05-14 15:18:03 -0700338 change.messages.append(message)
James E. Blairb0fcae42012-07-17 11:12:10 -0700339 if 'submit' in action:
James E. Blairb0fcae42012-07-17 11:12:10 -0700340 change.setMerged()
James E. Blaird466dc42012-07-31 10:42:56 -0700341 if message:
342 change.setReported()
James E. Blairb0fcae42012-07-17 11:12:10 -0700343
344 def query(self, number):
345 change = self.changes[int(number)]
346 return change.query()
347
348 def startWatching(self, *args, **kw):
349 pass
350
351
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700352class BuildHistory(object):
353 def __init__(self, **kw):
354 self.__dict__.update(kw)
James E. Blairb0fcae42012-07-17 11:12:10 -0700355
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700356 def __repr__(self):
357 return ("<Completed build, result: %s name: %s #%s changes: %s>" %
358 (self.result, self.name, self.number, self.changes))
James E. Blairb0fcae42012-07-17 11:12:10 -0700359
360
James E. Blair8cc15a82012-08-01 11:17:57 -0700361class FakeURLOpener(object):
Monty Taylorbc758832013-06-17 17:22:42 -0400362 def __init__(self, upstream_root, fake_gerrit, url):
363 self.upstream_root = upstream_root
James E. Blair8cc15a82012-08-01 11:17:57 -0700364 self.fake_gerrit = fake_gerrit
365 self.url = url
366
367 def read(self):
368 res = urlparse.urlparse(self.url)
369 path = res.path
370 project = '/'.join(path.split('/')[2:-2])
James E. Blair35956c52012-09-17 22:13:36 +0200371 ret = '001e# service=git-upload-pack\n'
372 ret += ('000000a31270149696713ba7e06f1beb760f20d359c4abed HEAD\x00'
373 'multi_ack thin-pack side-band side-band-64k ofs-delta '
374 'shallow no-progress include-tag multi_ack_detailed no-done\n')
Monty Taylorbc758832013-06-17 17:22:42 -0400375 path = os.path.join(self.upstream_root, project)
James E. Blairdaabed22012-08-15 15:38:57 -0700376 repo = git.Repo(path)
377 for ref in repo.refs:
James E. Blair35956c52012-09-17 22:13:36 +0200378 r = ref.object.hexsha + ' ' + ref.path + '\n'
379 ret += '%04x%s' % (len(r) + 4, r)
380 ret += '0000'
James E. Blair8cc15a82012-08-01 11:17:57 -0700381 return ret
382
383
James E. Blair4886cc12012-07-18 15:39:41 -0700384class FakeGerritTrigger(zuul.trigger.gerrit.Gerrit):
Monty Taylorbc758832013-06-17 17:22:42 -0400385 def __init__(self, upstream_root, *args):
386 super(FakeGerritTrigger, self).__init__(*args)
387 self.upstream_root = upstream_root
388
James E. Blair4886cc12012-07-18 15:39:41 -0700389 def getGitUrl(self, project):
Monty Taylorbc758832013-06-17 17:22:42 -0400390 return os.path.join(self.upstream_root, project.name)
James E. Blair4886cc12012-07-18 15:39:41 -0700391
392
James E. Blair412e5582013-04-22 15:50:12 -0700393class FakeStatsd(threading.Thread):
394 def __init__(self):
395 threading.Thread.__init__(self)
396 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
397 self.sock.bind(('', 0))
398 self.port = self.sock.getsockname()[1]
399 self.wake_read, self.wake_write = os.pipe()
400 self.stats = []
401
402 def run(self):
403 while True:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700404 poll = select.poll()
405 poll.register(self.sock, select.POLLIN)
406 poll.register(self.wake_read, select.POLLIN)
407 ret = poll.poll()
408 for (fd, event) in ret:
409 if fd == self.sock.fileno():
James E. Blair412e5582013-04-22 15:50:12 -0700410 data = self.sock.recvfrom(1024)
411 if not data:
412 return
413 self.stats.append(data[0])
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700414 if fd == self.wake_read:
James E. Blair412e5582013-04-22 15:50:12 -0700415 return
416
417 def stop(self):
418 os.write(self.wake_write, '1\n')
419
420
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700421class FakeBuild(threading.Thread):
422 log = logging.getLogger("zuul.test")
423
424 def __init__(self, worker, job, number, node):
425 threading.Thread.__init__(self)
426 self.worker = worker
427 self.job = job
428 self.name = job.name.split(':')[1]
429 self.number = number
430 self.node = node
431 self.parameters = json.loads(job.arguments)
432 self.unique = self.parameters['ZUUL_UUID']
433 self.wait_condition = threading.Condition()
434 self.waiting = False
435 self.aborted = False
436 self.created = time.time()
437 self.description = ''
438
439 def release(self):
440 self.wait_condition.acquire()
441 self.wait_condition.notify()
442 self.waiting = False
443 self.log.debug("Build %s released" % self.unique)
444 self.wait_condition.release()
445
446 def isWaiting(self):
447 self.wait_condition.acquire()
448 if self.waiting:
449 ret = True
450 else:
451 ret = False
452 self.wait_condition.release()
453 return ret
454
455 def _wait(self):
456 self.wait_condition.acquire()
457 self.waiting = True
458 self.log.debug("Build %s waiting" % self.unique)
459 self.wait_condition.wait()
460 self.wait_condition.release()
461
462 def run(self):
463 data = {
James E. Blair3c483cf2013-06-04 16:30:43 -0700464 'url': 'https://server/job/%s/%s/' % (self.name, self.number),
465 'name': self.name,
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700466 'number': self.number,
James E. Blair3c483cf2013-06-04 16:30:43 -0700467 'manager': self.worker.worker_id,
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700468 }
469
470 self.job.sendWorkData(json.dumps(data))
471 self.job.sendWorkStatus(0, 100)
472
473 if self.worker.hold_jobs_in_build:
474 self._wait()
475 self.log.debug("Build %s continuing" % self.unique)
476
477 self.worker.lock.acquire()
478
479 result = 'SUCCESS'
480 if (('ZUUL_REF' in self.parameters) and
481 self.worker.shouldFailTest(self.name,
482 self.parameters['ZUUL_REF'])):
483 result = 'FAILURE'
484 if self.aborted:
485 result = 'ABORTED'
486
487 data = {'result': result}
488 changes = None
489 if 'ZUUL_CHANGE_IDS' in self.parameters:
490 changes = self.parameters['ZUUL_CHANGE_IDS']
491
492 self.worker.build_history.append(
493 BuildHistory(name=self.name, number=self.number,
494 result=result, changes=changes, node=self.node,
495 uuid=self.unique, description=self.description)
496 )
497
498 self.job.sendWorkComplete(json.dumps(data))
499 del self.worker.gearman_jobs[self.job.unique]
500 self.worker.running_builds.remove(self)
501 self.worker.lock.release()
502
503
504class FakeWorker(gear.Worker):
Monty Taylorbc758832013-06-17 17:22:42 -0400505 def __init__(self, worker_id, test):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700506 super(FakeWorker, self).__init__(worker_id)
507 self.gearman_jobs = {}
508 self.build_history = []
509 self.running_builds = []
510 self.build_counter = 0
511 self.fail_tests = {}
Monty Taylorbc758832013-06-17 17:22:42 -0400512 self.test = test
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700513
514 self.hold_jobs_in_build = False
515 self.lock = threading.Lock()
516 self.__work_thread = threading.Thread(target=self.work)
517 self.__work_thread.start()
518
519 def handleJob(self, job):
520 parts = job.name.split(":")
521 cmd = parts[0]
522 name = parts[1]
523 if len(parts) > 2:
524 node = parts[2]
525 else:
526 node = None
527 if cmd == 'build':
528 self.handleBuild(job, name, node)
529 elif cmd == 'stop':
530 self.handleStop(job, name)
531 elif cmd == 'set_description':
532 self.handleSetDescription(job, name)
533
534 def handleBuild(self, job, name, node):
535 build = FakeBuild(self, job, self.build_counter, node)
536 job.build = build
537 self.gearman_jobs[job.unique] = job
538 self.build_counter += 1
539
540 self.running_builds.append(build)
541 build.start()
542
543 def handleStop(self, job, name):
544 self.log.debug("handle stop")
James E. Blair3c483cf2013-06-04 16:30:43 -0700545 parameters = json.loads(job.arguments)
546 name = parameters['name']
547 number = parameters['number']
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700548 for build in self.running_builds:
James E. Blair3c483cf2013-06-04 16:30:43 -0700549 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700550 build.aborted = True
551 build.release()
552 job.sendWorkComplete()
553 return
554 job.sendWorkFail()
555
556 def handleSetDescription(self, job, name):
557 self.log.debug("handle set description")
558 parameters = json.loads(job.arguments)
James E. Blair3c483cf2013-06-04 16:30:43 -0700559 name = parameters['name']
560 number = parameters['number']
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700561 descr = parameters['html_description']
562 for build in self.running_builds:
James E. Blair3c483cf2013-06-04 16:30:43 -0700563 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700564 build.description = descr
565 job.sendWorkComplete()
566 return
567 for build in self.build_history:
James E. Blair3c483cf2013-06-04 16:30:43 -0700568 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700569 build.description = descr
570 job.sendWorkComplete()
571 return
572 job.sendWorkFail()
573
574 def work(self):
575 while self.running:
576 try:
577 job = self.getJob()
578 except gear.InterruptedError:
579 continue
580 try:
581 self.handleJob(job)
582 except:
583 self.log.exception("Worker exception:")
584
585 def addFailTest(self, name, change):
586 l = self.fail_tests.get(name, [])
587 l.append(change)
588 self.fail_tests[name] = l
589
590 def shouldFailTest(self, name, ref):
591 l = self.fail_tests.get(name, [])
592 for change in l:
Monty Taylorbc758832013-06-17 17:22:42 -0400593 if self.test.ref_has_change(ref, change):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700594 return True
595 return False
596
597 def release(self, regex=None):
598 builds = self.running_builds[:]
599 self.log.debug("releasing build %s (%s)" % (regex,
600 len(self.running_builds)))
601 for build in builds:
602 if not regex or re.match(regex, build.name):
603 self.log.debug("releasing build %s" %
604 (build.parameters['ZUUL_UUID']))
605 build.release()
606 else:
607 self.log.debug("not releasing build %s" %
608 (build.parameters['ZUUL_UUID']))
609 self.log.debug("done releasing builds %s (%s)" %
610 (regex, len(self.running_builds)))
611
612
613class FakeGearmanServer(gear.Server):
614 def __init__(self):
615 self.hold_jobs_in_queue = False
616 super(FakeGearmanServer, self).__init__(0)
617
618 def getJobForConnection(self, connection, peek=False):
James E. Blair701c5b42013-06-06 09:34:59 -0700619 for queue in [self.high_queue, self.normal_queue, self.low_queue]:
620 for job in queue:
621 if not hasattr(job, 'waiting'):
622 if job.name.startswith('build:'):
623 job.waiting = self.hold_jobs_in_queue
624 else:
625 job.waiting = False
626 if job.waiting:
627 continue
628 if job.name in connection.functions:
629 if not peek:
630 queue.remove(job)
631 return job
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700632 return None
633
634 def release(self, regex=None):
635 released = False
James E. Blair701c5b42013-06-06 09:34:59 -0700636 qlen = (len(self.high_queue) + len(self.normal_queue) +
637 len(self.low_queue))
638 self.log.debug("releasing queued job %s (%s)" % (regex, qlen))
639 for queue in [self.high_queue, self.normal_queue, self.low_queue]:
640 queue = queue[:]
641 for job in queue:
642 cmd, name = job.name.split(':')
643 if cmd != 'build':
644 continue
645 if not regex or re.match(regex, name):
646 self.log.debug("releasing queued job %s" %
647 job.unique)
648 job.waiting = False
649 released = True
650 else:
651 self.log.debug("not releasing queued job %s" %
652 job.unique)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700653 if released:
654 self.wakeConnections()
James E. Blair701c5b42013-06-06 09:34:59 -0700655 qlen = (len(self.high_queue) + len(self.normal_queue) +
656 len(self.low_queue))
657 self.log.debug("done releasing queued jobs %s (%s)" % (regex, qlen))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700658
659
Monty Taylorbc758832013-06-17 17:22:42 -0400660class TestScheduler(testtools.TestCase):
James E. Blairb0fcae42012-07-17 11:12:10 -0700661 log = logging.getLogger("zuul.test")
662
663 def setUp(self):
Monty Taylorbc758832013-06-17 17:22:42 -0400664 super(TestScheduler, self).setUp()
665 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
666 try:
667 test_timeout = int(test_timeout)
668 except ValueError:
669 # If timeout value is invalid do not set a timeout.
670 test_timeout = 0
671 if test_timeout > 0:
672 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
673
674 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
675 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
676 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
677 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
678 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
679 os.environ.get('OS_STDERR_CAPTURE') == '1'):
680 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
681 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
682 self.useFixture(fixtures.NestedTempfile())
683 self.log_fixture = self.useFixture(fixtures.FakeLogger())
684
685 tmp_root = os.environ.get("ZUUL_TEST_ROOT", tempfile.mkdtemp())
686 self.test_root = os.path.join(tmp_root, "zuul-test")
687 self.upstream_root = os.path.join(self.test_root, "upstream")
688 self.git_root = os.path.join(self.test_root, "git")
689
690 CONFIG.set('zuul', 'git_dir', self.git_root)
691 if os.path.exists(self.test_root):
692 shutil.rmtree(self.test_root)
693 os.makedirs(self.test_root)
694 os.makedirs(self.upstream_root)
695 os.makedirs(self.git_root)
James E. Blair4886cc12012-07-18 15:39:41 -0700696
697 # For each project in config:
Monty Taylorbc758832013-06-17 17:22:42 -0400698 self.init_repo("org/project")
699 self.init_repo("org/project1")
700 self.init_repo("org/project2")
701 self.init_repo("org/project3")
702 self.init_repo("org/one-job-project")
703 self.init_repo("org/nonvoting-project")
704 self.init_repo("org/templated-project")
705 self.init_repo("org/node-project")
James E. Blair412e5582013-04-22 15:50:12 -0700706
707 self.statsd = FakeStatsd()
708 os.environ['STATSD_HOST'] = 'localhost'
709 os.environ['STATSD_PORT'] = str(self.statsd.port)
710 self.statsd.start()
711 # the statsd client object is configured in the statsd module import
712 reload(statsd)
713 reload(zuul.scheduler)
714
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700715 self.gearman_server = FakeGearmanServer()
716
717 self.config = ConfigParser.ConfigParser()
718 cfg = StringIO()
719 CONFIG.write(cfg)
720 cfg.seek(0)
721 self.config.readfp(cfg)
722 self.config.set('gearman', 'port', str(self.gearman_server.port))
723
Monty Taylorbc758832013-06-17 17:22:42 -0400724 self.worker = FakeWorker('fake_worker', self)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700725 self.worker.addServer('127.0.0.1', self.gearman_server.port)
726 self.gearman_server.worker = self.worker
727
James E. Blairb0fcae42012-07-17 11:12:10 -0700728 self.sched = zuul.scheduler.Scheduler()
729
James E. Blair8cc15a82012-08-01 11:17:57 -0700730 def URLOpenerFactory(*args, **kw):
731 args = [self.fake_gerrit] + list(args)
Monty Taylorbc758832013-06-17 17:22:42 -0400732 return FakeURLOpener(self.upstream_root, *args, **kw)
James E. Blair8cc15a82012-08-01 11:17:57 -0700733
James E. Blair8cc15a82012-08-01 11:17:57 -0700734 urllib2.urlopen = URLOpenerFactory
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700735 self.launcher = zuul.launcher.gearman.Gearman(self.config, self.sched)
James E. Blairb0fcae42012-07-17 11:12:10 -0700736
737 zuul.lib.gerrit.Gerrit = FakeGerrit
738
Monty Taylorbc758832013-06-17 17:22:42 -0400739 self.gerrit = FakeGerritTrigger(
740 self.upstream_root, self.config, self.sched)
James E. Blair8cc15a82012-08-01 11:17:57 -0700741 self.gerrit.replication_timeout = 1.5
742 self.gerrit.replication_retry_interval = 0.5
James E. Blairb0fcae42012-07-17 11:12:10 -0700743 self.fake_gerrit = self.gerrit.gerrit
Monty Taylorbc758832013-06-17 17:22:42 -0400744 self.fake_gerrit.upstream_root = self.upstream_root
James E. Blairb0fcae42012-07-17 11:12:10 -0700745
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700746 self.sched.setLauncher(self.launcher)
James E. Blairb0fcae42012-07-17 11:12:10 -0700747 self.sched.setTrigger(self.gerrit)
748
749 self.sched.start()
750 self.sched.reconfigure(self.config)
751 self.sched.resume()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700752 self.launcher.gearman.waitForServer()
753 self.registerJobs()
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400754 self.builds = self.worker.running_builds
755 self.history = self.worker.build_history
James E. Blairb0fcae42012-07-17 11:12:10 -0700756
757 def tearDown(self):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700758 self.launcher.stop()
759 self.worker.shutdown()
760 self.gearman_server.shutdown()
James E. Blairb0fcae42012-07-17 11:12:10 -0700761 self.gerrit.stop()
762 self.sched.stop()
763 self.sched.join()
James E. Blair412e5582013-04-22 15:50:12 -0700764 self.statsd.stop()
765 self.statsd.join()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700766 threads = threading.enumerate()
767 if len(threads) > 1:
768 self.log.error("More than one thread is running: %s" % threads)
Monty Taylorbc758832013-06-17 17:22:42 -0400769 super(TestScheduler, self).tearDown()
770
771 def init_repo(self, project):
772 parts = project.split('/')
773 path = os.path.join(self.upstream_root, *parts[:-1])
774 if not os.path.exists(path):
775 os.makedirs(path)
776 path = os.path.join(self.upstream_root, project)
777 repo = git.Repo.init(path)
778
779 repo.config_writer().set_value('user', 'email', 'user@example.com')
780 repo.config_writer().set_value('user', 'name', 'User Name')
781 repo.config_writer().write()
782
783 fn = os.path.join(path, 'README')
784 f = open(fn, 'w')
785 f.write("test\n")
786 f.close()
787 repo.index.add([fn])
788 repo.index.commit('initial commit')
789 master = repo.create_head('master')
790 repo.create_tag('init')
791
792 mp = repo.create_head('mp')
793 repo.head.reference = mp
794 f = open(fn, 'a')
795 f.write("test mp\n")
796 f.close()
797 repo.index.add([fn])
798 repo.index.commit('mp commit')
799
800 repo.head.reference = master
801 repo.head.reset(index=True, working_tree=True)
802 repo.git.clean('-x', '-f', '-d')
803
804 def ref_has_change(self, ref, change):
805 path = os.path.join(self.git_root, change.project)
806 repo = git.Repo(path)
807 for commit in repo.iter_commits(ref):
808 if commit.message.strip() == ('%s-1' % change.subject):
809 return True
810 return False
811
812 def job_has_changes(self, *args):
813 job = args[0]
814 commits = args[1:]
815 if isinstance(job, FakeBuild):
816 parameters = job.parameters
817 else:
818 parameters = json.loads(job.arguments)
819 project = parameters['ZUUL_PROJECT']
820 path = os.path.join(self.git_root, project)
821 repo = git.Repo(path)
822 ref = parameters['ZUUL_REF']
823 sha = parameters['ZUUL_COMMIT']
824 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
825 repo_shas = [c.hexsha for c in repo.iter_commits(ref)]
826 commit_messages = ['%s-1' % commit.subject for commit in commits]
827 for msg in commit_messages:
828 if msg not in repo_messages:
829 return False
830 if repo_shas[0] != sha:
831 return False
832 return True
James E. Blairb0fcae42012-07-17 11:12:10 -0700833
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700834 def registerJobs(self):
835 count = 0
836 for job in self.sched.jobs.keys():
837 self.worker.registerFunction('build:' + job)
838 count += 1
839 self.worker.registerFunction('stop:' + self.worker.worker_id)
840 count += 1
841
842 while len(self.gearman_server.functions) < count:
843 time.sleep(0)
844
845 def release(self, job):
846 if isinstance(job, FakeBuild):
847 job.release()
848 else:
849 job.waiting = False
850 self.log.debug("Queued job %s released" % job.unique)
851 self.gearman_server.wakeConnections()
852
853 def getParameter(self, job, name):
854 if isinstance(job, FakeBuild):
855 return job.parameters[name]
856 else:
857 parameters = json.loads(job.arguments)
858 return parameters[name]
859
860 def resetGearmanServer(self):
861 self.worker.setFunctions([])
862 while True:
863 done = True
864 for connection in self.gearman_server.active_connections:
865 if connection.functions:
866 done = False
867 if done:
868 break
869 time.sleep(0)
870 self.gearman_server.functions = set()
871
872 def haveAllBuildsReported(self):
873 # See if Zuul is waiting on a meta job to complete
874 if self.launcher.meta_jobs:
875 return False
876 # Find out if every build that the worker has completed has been
877 # reported back to Zuul. If it hasn't then that means a Gearman
878 # event is still in transit and the system is not stable.
879 for build in self.worker.build_history:
880 zbuild = self.launcher.builds.get(build.uuid)
881 if not zbuild:
882 # It has already been reported
883 continue
884 # It hasn't been reported yet.
885 return False
886 # Make sure that none of the worker connections are in GRAB_WAIT
887 for connection in self.worker.active_connections:
888 if connection.state == 'GRAB_WAIT':
889 return False
890 return True
891
892 def areAllBuildsWaiting(self):
893 ret = True
894
895 builds = self.launcher.builds.values()
896 for build in builds:
897 client_job = None
898 for conn in self.launcher.gearman.active_connections:
899 for j in conn.related_jobs.values():
900 if j.unique == build.uuid:
901 client_job = j
902 break
903 if not client_job:
904 self.log.debug("%s is not known to the gearman client" %
905 build)
906 ret = False
907 continue
908 if not client_job.handle:
909 self.log.debug("%s has no handle" % client_job)
910 ret = False
911 continue
912 server_job = self.gearman_server.jobs.get(client_job.handle)
913 if not server_job:
914 self.log.debug("%s is not known to the gearman server" %
915 client_job)
916 ret = False
917 continue
918 if not hasattr(server_job, 'waiting'):
919 self.log.debug("%s is being enqueued" % server_job)
920 ret = False
921 continue
922 if server_job.waiting:
923 continue
924 worker_job = self.worker.gearman_jobs.get(server_job.unique)
925 if worker_job:
926 if worker_job.build.isWaiting():
927 continue
928 else:
929 self.log.debug("%s is running" % worker_job)
930 ret = False
931 else:
932 self.log.debug("%s is unassigned" % server_job)
933 ret = False
934 return ret
935
James E. Blairb0fcae42012-07-17 11:12:10 -0700936 def waitUntilSettled(self):
937 self.log.debug("Waiting until settled...")
938 start = time.time()
939 while True:
940 if time.time() - start > 10:
941 print 'queue status:',
942 print self.sched.trigger_event_queue.empty(),
943 print self.sched.result_event_queue.empty(),
944 print self.fake_gerrit.event_queue.empty(),
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700945 print self.areAllBuildsWaiting()
James E. Blairb0fcae42012-07-17 11:12:10 -0700946 raise Exception("Timeout waiting for Zuul to settle")
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700947 # Make sure no new events show up while we're checking
948 self.worker.lock.acquire()
949 # have all build states propogated to zuul?
950 if self.haveAllBuildsReported():
951 # Join ensures that the queue is empty _and_ events have been
952 # processed
953 self.fake_gerrit.event_queue.join()
954 self.sched.trigger_event_queue.join()
955 self.sched.result_event_queue.join()
956 if (self.sched.trigger_event_queue.empty() and
957 self.sched.result_event_queue.empty() and
958 self.fake_gerrit.event_queue.empty() and
959 self.areAllBuildsWaiting()):
960 self.worker.lock.release()
961 self.log.debug("...settled.")
962 return
963 self.worker.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700964 self.sched.wake_event.wait(0.1)
965
James E. Blaird466dc42012-07-31 10:42:56 -0700966 def countJobResults(self, jobs, result):
James E. Blair0018a6c2013-02-27 14:11:45 -0800967 jobs = filter(lambda x: x.result == result, jobs)
James E. Blaird466dc42012-07-31 10:42:56 -0700968 return len(jobs)
969
James E. Blair4ca985f2013-05-30 12:27:43 -0700970 def getJobFromHistory(self, name):
971 history = self.worker.build_history
972 for job in history:
973 if job.name == name:
974 return job
975 raise Exception("Unable to find job %s in history" % name)
976
James E. Blaire0487072012-08-29 17:38:31 -0700977 def assertEmptyQueues(self):
978 # Make sure there are no orphaned jobs
979 for pipeline in self.sched.pipelines.values():
980 for queue in pipeline.queues:
981 if len(queue.queue) != 0:
James E. Blairf62d4282012-12-31 17:01:50 -0800982 print 'pipeline %s queue %s contents %s' % (
983 pipeline.name, queue.name, queue.queue)
James E. Blaire0487072012-08-29 17:38:31 -0700984 assert len(queue.queue) == 0
985 if len(queue.severed_heads) != 0:
986 print 'heads', queue.severed_heads
987 assert len(queue.severed_heads) == 0
988
James E. Blair412e5582013-04-22 15:50:12 -0700989 def assertReportedStat(self, key, value=None):
990 start = time.time()
991 while time.time() < (start + 5):
992 for stat in self.statsd.stats:
993 k, v = stat.split(':')
994 if key == k:
995 if value is None:
996 return
997 if value == v:
998 return
999 time.sleep(0.1)
1000
1001 pprint.pprint(self.statsd.stats)
1002 raise Exception("Key %s not found in reported stats" % key)
1003
James E. Blairb0fcae42012-07-17 11:12:10 -07001004 def test_jobs_launched(self):
1005 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001006
James E. Blairb0fcae42012-07-17 11:12:10 -07001007 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -07001008 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001009 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1010 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07001011 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1012 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1013 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
James E. Blairb0fcae42012-07-17 11:12:10 -07001014 assert A.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001015 assert A.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001016 self.assertEmptyQueues()
James E. Blairb0fcae42012-07-17 11:12:10 -07001017
James E. Blair412e5582013-04-22 15:50:12 -07001018 self.assertReportedStat('gerrit.event.comment-added', '1|c')
1019 self.assertReportedStat('zuul.pipeline.gate.current_changes', '1|g')
1020 self.assertReportedStat('zuul.job.project-merge')
1021 self.assertReportedStat('zuul.pipeline.gate.resident_time')
1022 self.assertReportedStat('zuul.pipeline.gate.total_changes', '1|c')
1023 self.assertReportedStat(
1024 'zuul.pipeline.gate.org.project.resident_time')
1025 self.assertReportedStat(
1026 'zuul.pipeline.gate.org.project.total_changes', '1|c')
1027
James E. Blair42f74822013-05-14 15:18:03 -07001028 def test_duplicate_pipelines(self):
1029 "Test that a change matching multiple pipelines works"
James E. Blair1b4d9722013-05-21 10:32:04 -07001030
James E. Blair42f74822013-05-14 15:18:03 -07001031 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1032 self.fake_gerrit.addEvent(A.getChangeRestoredEvent())
1033 self.waitUntilSettled()
James E. Blair42f74822013-05-14 15:18:03 -07001034
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001035 print self.builds
James E. Blair42f74822013-05-14 15:18:03 -07001036 print A.messages
1037
1038 self.assertEmptyQueues()
1039
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001040 assert len(self.history) == 2
1041 self.history[0].name == 'project-test1'
1042 self.history[1].name == 'project-test1'
James E. Blair42f74822013-05-14 15:18:03 -07001043
1044 assert len(A.messages) == 2
1045 if 'dup1/project-test1' in A.messages[0]:
1046 assert 'dup1/project-test1' in A.messages[0]
1047 assert 'dup2/project-test1' not in A.messages[0]
1048 assert 'dup1/project-test1' not in A.messages[1]
1049 assert 'dup2/project-test1' in A.messages[1]
1050 else:
1051 assert 'dup1/project-test1' in A.messages[1]
1052 assert 'dup2/project-test1' not in A.messages[1]
1053 assert 'dup1/project-test1' not in A.messages[0]
1054 assert 'dup2/project-test1' in A.messages[0]
1055
James E. Blairb0fcae42012-07-17 11:12:10 -07001056 def test_parallel_changes(self):
1057 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001058
1059 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -07001060 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1061 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1062 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001063 A.addApproval('CRVW', 2)
1064 B.addApproval('CRVW', 2)
1065 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001066
1067 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1068 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1069 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1070
1071 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001072 assert len(self.builds) == 1
1073 assert self.builds[0].name == 'project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001074 assert self.job_has_changes(self.builds[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -07001075
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001076 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001077 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001078 assert len(self.builds) == 3
1079 assert self.builds[0].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001080 assert self.job_has_changes(self.builds[0], A)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001081 assert self.builds[1].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001082 assert self.job_has_changes(self.builds[1], A)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001083 assert self.builds[2].name == 'project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001084 assert self.job_has_changes(self.builds[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -07001085
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001086 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001087 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001088 assert len(self.builds) == 5
1089 assert self.builds[0].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001090 assert self.job_has_changes(self.builds[0], A)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001091 assert self.builds[1].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001092 assert self.job_has_changes(self.builds[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -07001093
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001094 assert self.builds[2].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001095 assert self.job_has_changes(self.builds[2], A, B)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001096 assert self.builds[3].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001097 assert self.job_has_changes(self.builds[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -07001098
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001099 assert self.builds[4].name == 'project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001100 assert self.job_has_changes(self.builds[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -07001101
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001102 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001103 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001104 assert len(self.builds) == 6
1105 assert self.builds[0].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001106 assert self.job_has_changes(self.builds[0], A)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001107 assert self.builds[1].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001108 assert self.job_has_changes(self.builds[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -07001109
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001110 assert self.builds[2].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001111 assert self.job_has_changes(self.builds[2], A, B)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001112 assert self.builds[3].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001113 assert self.job_has_changes(self.builds[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -07001114
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001115 assert self.builds[4].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001116 assert self.job_has_changes(self.builds[4], A, B, C)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001117 assert self.builds[5].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001118 assert self.job_has_changes(self.builds[5], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -07001119
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001120 self.worker.hold_jobs_in_build = False
1121 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -07001122 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001123 assert len(self.builds) == 0
James E. Blairb0fcae42012-07-17 11:12:10 -07001124
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001125 assert len(self.history) == 9
James E. Blairb0fcae42012-07-17 11:12:10 -07001126 assert A.data['status'] == 'MERGED'
1127 assert B.data['status'] == 'MERGED'
1128 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001129 assert A.reported == 2
1130 assert B.reported == 2
1131 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001132 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001133
1134 def test_failed_changes(self):
1135 "Test that a change behind a failed change is retested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001136
James E. Blairb02a3bb2012-07-30 17:49:55 -07001137 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1138 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -07001139 A.addApproval('CRVW', 2)
1140 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001141
1142 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1143 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1144
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001145 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001146
1147 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001148 assert len(self.history) > 6
James E. Blairb02a3bb2012-07-30 17:49:55 -07001149 assert A.data['status'] == 'NEW'
1150 assert B.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001151 assert A.reported == 2
1152 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001153 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001154
1155 def test_independent_queues(self):
1156 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001157
1158 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +09001159 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001160 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1161 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001162 A.addApproval('CRVW', 2)
1163 B.addApproval('CRVW', 2)
1164 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001165
1166 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1167 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1168 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1169
James E. Blairb02a3bb2012-07-30 17:49:55 -07001170 self.waitUntilSettled()
1171
1172 # There should be one merge job at the head of each queue running
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001173 assert len(self.builds) == 2
1174 assert self.builds[0].name == 'project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001175 assert self.job_has_changes(self.builds[0], A)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001176 assert self.builds[1].name == 'project1-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001177 assert self.job_has_changes(self.builds[1], B)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001178
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001179 # Release the current merge builds
1180 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001181 self.waitUntilSettled()
1182 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001183 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001184 self.waitUntilSettled()
1185
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001186 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -07001187 # project1 (3) + project2 (3) + project (2) = 8
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001188 assert len(self.builds) == 8
James E. Blairb02a3bb2012-07-30 17:49:55 -07001189
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001190 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001191 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001192 assert len(self.builds) == 0
James E. Blairb02a3bb2012-07-30 17:49:55 -07001193
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001194 assert len(self.history) == 11
James E. Blairb02a3bb2012-07-30 17:49:55 -07001195 assert A.data['status'] == 'MERGED'
1196 assert B.data['status'] == 'MERGED'
1197 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001198 assert A.reported == 2
1199 assert B.reported == 2
1200 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001201 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -07001202
1203 def test_failed_change_at_head(self):
1204 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -07001205
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001206 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -07001207 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1208 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1209 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001210 A.addApproval('CRVW', 2)
1211 B.addApproval('CRVW', 2)
1212 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001213
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001214 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001215
1216 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1217 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1218 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1219
1220 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -07001221
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001222 assert len(self.builds) == 1
1223 assert self.builds[0].name == 'project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001224 assert self.job_has_changes(self.builds[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001225
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001226 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001227 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001228 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001229 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001230 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001231 self.waitUntilSettled()
1232
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001233 assert len(self.builds) == 6
1234 assert self.builds[0].name == 'project-test1'
1235 assert self.builds[1].name == 'project-test2'
1236 assert self.builds[2].name == 'project-test1'
1237 assert self.builds[3].name == 'project-test2'
1238 assert self.builds[4].name == 'project-test1'
1239 assert self.builds[5].name == 'project-test2'
James E. Blaird466dc42012-07-31 10:42:56 -07001240
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001241 self.release(self.builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001242 self.waitUntilSettled()
1243
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001244 assert len(self.builds) == 2 # project-test2, project-merge for B
1245 assert self.countJobResults(self.history, 'ABORTED') == 4
James E. Blaird466dc42012-07-31 10:42:56 -07001246
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001247 self.worker.hold_jobs_in_build = False
1248 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001249 self.waitUntilSettled()
1250
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001251 assert len(self.builds) == 0
1252 assert len(self.history) == 15
James E. Blaird466dc42012-07-31 10:42:56 -07001253 assert A.data['status'] == 'NEW'
1254 assert B.data['status'] == 'MERGED'
1255 assert C.data['status'] == 'MERGED'
1256 assert A.reported == 2
1257 assert B.reported == 2
1258 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001259 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -07001260
1261 def test_failed_change_at_head_with_queue(self):
1262 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -07001263
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001264 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -07001265 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1266 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1267 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001268 A.addApproval('CRVW', 2)
1269 B.addApproval('CRVW', 2)
1270 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001271
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001272 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001273
1274 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1275 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1276 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1277
1278 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001279 queue = self.gearman_server.getQueue()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001280 assert len(self.builds) == 0
James E. Blaird466dc42012-07-31 10:42:56 -07001281 assert len(queue) == 1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001282 assert queue[0].name == 'build:project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001283 assert self.job_has_changes(queue[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001284
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001285 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001286 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001287 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001288 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001289 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001290 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001291 queue = self.gearman_server.getQueue()
James E. Blaird466dc42012-07-31 10:42:56 -07001292
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001293 assert len(self.builds) == 0
James E. Blaird466dc42012-07-31 10:42:56 -07001294 assert len(queue) == 6
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001295 assert queue[0].name == 'build:project-test1'
1296 assert queue[1].name == 'build:project-test2'
1297 assert queue[2].name == 'build:project-test1'
1298 assert queue[3].name == 'build:project-test2'
1299 assert queue[4].name == 'build:project-test1'
1300 assert queue[5].name == 'build:project-test2'
James E. Blaird466dc42012-07-31 10:42:56 -07001301
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001302 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001303 self.waitUntilSettled()
1304
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001305 assert len(self.builds) == 0
James E. Blair701c5b42013-06-06 09:34:59 -07001306 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001307 assert len(queue) == 2 # project-test2, project-merge for B
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001308 assert self.countJobResults(self.history, 'ABORTED') == 0
James E. Blaird466dc42012-07-31 10:42:56 -07001309
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001310 self.gearman_server.hold_jobs_in_queue = False
1311 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001312 self.waitUntilSettled()
1313
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001314 assert len(self.builds) == 0
1315 assert len(self.history) == 11
James E. Blaird466dc42012-07-31 10:42:56 -07001316 assert A.data['status'] == 'NEW'
1317 assert B.data['status'] == 'MERGED'
1318 assert C.data['status'] == 'MERGED'
1319 assert A.reported == 2
1320 assert B.reported == 2
1321 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001322 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001323
1324 def test_patch_order(self):
1325 "Test that dependent patches are tested in the right order"
1326 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1327 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1328 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1329 A.addApproval('CRVW', 2)
1330 B.addApproval('CRVW', 2)
1331 C.addApproval('CRVW', 2)
1332
1333 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
1334 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1335 M2.setMerged()
1336 M1.setMerged()
1337
1338 # C -> B -> A -> M1 -> M2
1339 # M2 is here to make sure it is never queried. If it is, it
1340 # means zuul is walking down the entire history of merged
1341 # changes.
1342
1343 C.setDependsOn(B, 1)
1344 B.setDependsOn(A, 1)
1345 A.setDependsOn(M1, 1)
1346 M1.setDependsOn(M2, 1)
1347
1348 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1349
1350 self.waitUntilSettled()
1351
1352 assert A.data['status'] == 'NEW'
1353 assert B.data['status'] == 'NEW'
1354 assert C.data['status'] == 'NEW'
1355
1356 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1357 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1358
1359 self.waitUntilSettled()
1360 assert M2.queried == 0
1361 assert A.data['status'] == 'MERGED'
1362 assert B.data['status'] == 'MERGED'
1363 assert C.data['status'] == 'MERGED'
1364 assert A.reported == 2
1365 assert B.reported == 2
1366 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001367 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001368
1369 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -07001370 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -07001371 # TODO: move to test_gerrit (this is a unit test!)
1372 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair4aea70c2012-07-26 14:23:24 -07001373 a = self.sched.trigger.getChange(1, 2)
1374 mgr = self.sched.pipelines['gate'].manager
1375 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001376
1377 A.addApproval('CRVW', 2)
James E. Blair4aea70c2012-07-26 14:23:24 -07001378 a = self.sched.trigger.getChange(1, 2)
1379 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001380
1381 A.addApproval('APRV', 1)
James E. Blair4aea70c2012-07-26 14:23:24 -07001382 a = self.sched.trigger.getChange(1, 2)
1383 assert self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blaire0487072012-08-29 17:38:31 -07001384 self.assertEmptyQueues()
James E. Blair4886cc12012-07-18 15:39:41 -07001385
1386 def test_build_configuration(self):
1387 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001388
1389 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -07001390 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1391 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1392 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1393 A.addApproval('CRVW', 2)
1394 B.addApproval('CRVW', 2)
1395 C.addApproval('CRVW', 2)
1396 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1397 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1398 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1399 self.waitUntilSettled()
1400
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001401 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001402 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001403 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001404 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001405 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001406 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001407 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001408 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1409 self.gearman_server.hold_jobs_in_queue = False
1410 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001411 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -07001412
Monty Taylorbc758832013-06-17 17:22:42 -04001413 path = os.path.join(self.git_root, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -07001414 repo = git.Repo(path)
1415 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1416 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -07001417 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
1418 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001419 self.assertEmptyQueues()
James E. Blair973721f2012-08-15 10:19:43 -07001420
1421 def test_build_configuration_conflict(self):
1422 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001423
1424 self.gearman_server.hold_jobs_in_queue = True
James E. Blair973721f2012-08-15 10:19:43 -07001425 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1426 A.addPatchset(['conflict'])
1427 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1428 B.addPatchset(['conflict'])
1429 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1430 A.addApproval('CRVW', 2)
1431 B.addApproval('CRVW', 2)
1432 C.addApproval('CRVW', 2)
1433 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1434 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1435 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1436 self.waitUntilSettled()
1437
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001438 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001439 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001440 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001441 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001442 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001443 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001444 queue = self.gearman_server.getQueue()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001445 self.getParameter(queue[-1], 'ZUUL_REF')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001446 self.gearman_server.hold_jobs_in_queue = False
1447 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001448 self.waitUntilSettled()
1449
1450 assert A.data['status'] == 'MERGED'
1451 assert B.data['status'] == 'NEW'
1452 assert C.data['status'] == 'MERGED'
1453 assert A.reported == 2
1454 assert B.reported == 2
1455 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001456 self.assertEmptyQueues()
James E. Blairdaabed22012-08-15 15:38:57 -07001457
1458 def test_post(self):
1459 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001460
Zhongyue Luo5d556072012-09-21 02:00:47 +09001461 e = {
1462 "type": "ref-updated",
1463 "submitter": {
1464 "name": "User Name",
1465 },
1466 "refUpdate": {
1467 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1468 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1469 "refName": "master",
1470 "project": "org/project",
1471 }
1472 }
James E. Blairdaabed22012-08-15 15:38:57 -07001473 self.fake_gerrit.addEvent(e)
1474 self.waitUntilSettled()
1475
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001476 job_names = [x.name for x in self.history]
1477 assert len(self.history) == 1
James E. Blairdaabed22012-08-15 15:38:57 -07001478 assert 'project-post' in job_names
James E. Blaire0487072012-08-29 17:38:31 -07001479 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001480
1481 def test_build_configuration_branch(self):
1482 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001483
1484 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001485 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1486 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1487 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1488 A.addApproval('CRVW', 2)
1489 B.addApproval('CRVW', 2)
1490 C.addApproval('CRVW', 2)
1491 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1492 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1493 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1494 self.waitUntilSettled()
1495
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001496 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001497 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001498 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001499 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001500 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001501 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001502 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001503 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1504 self.gearman_server.hold_jobs_in_queue = False
1505 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001506 self.waitUntilSettled()
1507
Monty Taylorbc758832013-06-17 17:22:42 -04001508 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001509 repo = git.Repo(path)
1510 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1511 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001512 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
1513 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001514 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001515
1516 def test_build_configuration_branch_interaction(self):
1517 "Test that switching between branches works"
1518 self.test_build_configuration()
1519 self.test_build_configuration_branch()
1520 # C has been merged, undo that
Monty Taylorbc758832013-06-17 17:22:42 -04001521 path = os.path.join(self.upstream_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001522 repo = git.Repo(path)
1523 repo.heads.master.commit = repo.commit('init')
1524 self.test_build_configuration()
James E. Blaire0487072012-08-29 17:38:31 -07001525 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001526
1527 def test_build_configuration_multi_branch(self):
1528 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001529
1530 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001531 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1532 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1533 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1534 A.addApproval('CRVW', 2)
1535 B.addApproval('CRVW', 2)
1536 C.addApproval('CRVW', 2)
1537 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1538 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1539 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1540 self.waitUntilSettled()
1541
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001542 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001543 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001544 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001545 ref_mp = self.getParameter(queue[-1], 'ZUUL_REF')
1546 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001547 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001548 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001549 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001550 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001551 ref_master = self.getParameter(queue[-1], 'ZUUL_REF')
1552 self.gearman_server.hold_jobs_in_queue = False
1553 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001554 self.waitUntilSettled()
1555
Monty Taylorbc758832013-06-17 17:22:42 -04001556 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001557 repo = git.Repo(path)
1558
1559 repo_messages = [c.message.strip()
1560 for c in repo.iter_commits(ref_master)]
1561 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001562 correct_messages = ['initial commit', 'A-1', 'C-1']
1563 assert repo_messages == correct_messages
1564
1565 repo_messages = [c.message.strip()
1566 for c in repo.iter_commits(ref_mp)]
1567 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001568 correct_messages = ['initial commit', 'mp commit', 'B-1']
1569 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001570 self.assertEmptyQueues()
James E. Blair7f71c802012-08-22 13:04:32 -07001571
1572 def test_one_job_project(self):
1573 "Test that queueing works with one job"
1574 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1575 'master', 'A')
1576 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1577 'master', 'B')
1578 A.addApproval('CRVW', 2)
1579 B.addApproval('CRVW', 2)
1580 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1581 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1582 self.waitUntilSettled()
1583
James E. Blair7f71c802012-08-22 13:04:32 -07001584 assert A.data['status'] == 'MERGED'
1585 assert A.reported == 2
1586 assert B.data['status'] == 'MERGED'
1587 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001588 self.assertEmptyQueues()
James E. Blaircaec0c52012-08-22 14:52:22 -07001589
Antoine Musso80edd5a2013-02-13 15:37:53 +01001590 def test_job_from_templates_launched(self):
1591 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001592
Antoine Musso80edd5a2013-02-13 15:37:53 +01001593 A = self.fake_gerrit.addFakeChange(
1594 'org/templated-project', 'master', 'A')
1595 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1596 self.waitUntilSettled()
Antoine Musso80edd5a2013-02-13 15:37:53 +01001597
James E. Blair4ca985f2013-05-30 12:27:43 -07001598 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1599 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
Antoine Musso80edd5a2013-02-13 15:37:53 +01001600
James E. Blaircaec0c52012-08-22 14:52:22 -07001601 def test_dependent_changes_dequeue(self):
1602 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001603
James E. Blaircaec0c52012-08-22 14:52:22 -07001604 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1605 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1606 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1607 A.addApproval('CRVW', 2)
1608 B.addApproval('CRVW', 2)
1609 C.addApproval('CRVW', 2)
1610
1611 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1612 M1.setMerged()
1613
1614 # C -> B -> A -> M1
1615
1616 C.setDependsOn(B, 1)
1617 B.setDependsOn(A, 1)
1618 A.setDependsOn(M1, 1)
1619
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001620 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07001621
1622 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1623 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1624 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1625
1626 self.waitUntilSettled()
1627
James E. Blairec590122012-08-22 15:19:31 -07001628 assert A.data['status'] == 'NEW'
1629 assert A.reported == 2
1630 assert B.data['status'] == 'NEW'
1631 assert B.reported == 2
1632 assert C.data['status'] == 'NEW'
1633 assert C.reported == 2
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001634 assert len(self.history) == 1
James E. Blaire0487072012-08-29 17:38:31 -07001635 self.assertEmptyQueues()
James E. Blairec590122012-08-22 15:19:31 -07001636
1637 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001638 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001639 # If it's dequeued more than once, we should see extra
1640 # aborted jobs.
James E. Blairec590122012-08-22 15:19:31 -07001641
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001642 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07001643 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1644 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1645 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1646 A.addApproval('CRVW', 2)
1647 B.addApproval('CRVW', 2)
1648 C.addApproval('CRVW', 2)
1649
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001650 self.worker.addFailTest('project1-test1', A)
1651 self.worker.addFailTest('project1-test2', A)
1652 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07001653
1654 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1655 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1656 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1657
1658 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07001659
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001660 assert len(self.builds) == 1
1661 assert self.builds[0].name == 'project1-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001662 assert self.job_has_changes(self.builds[0], A)
James E. Blairec590122012-08-22 15:19:31 -07001663
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001664 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001665 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001666 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001667 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001668 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001669 self.waitUntilSettled()
1670
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001671 assert len(self.builds) == 9
1672 assert self.builds[0].name == 'project1-test1'
1673 assert self.builds[1].name == 'project1-test2'
1674 assert self.builds[2].name == 'project1-project2-integration'
1675 assert self.builds[3].name == 'project1-test1'
1676 assert self.builds[4].name == 'project1-test2'
1677 assert self.builds[5].name == 'project1-project2-integration'
1678 assert self.builds[6].name == 'project1-test1'
1679 assert self.builds[7].name == 'project1-test2'
1680 assert self.builds[8].name == 'project1-project2-integration'
James E. Blairec590122012-08-22 15:19:31 -07001681
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001682 self.release(self.builds[0])
James E. Blairec590122012-08-22 15:19:31 -07001683 self.waitUntilSettled()
1684
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001685 assert len(self.builds) == 3 # test2, integration, merge for B
1686 assert self.countJobResults(self.history, 'ABORTED') == 6
James E. Blairec590122012-08-22 15:19:31 -07001687
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001688 self.worker.hold_jobs_in_build = False
1689 self.worker.release()
James E. Blairec590122012-08-22 15:19:31 -07001690 self.waitUntilSettled()
1691
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001692 assert len(self.builds) == 0
1693 assert len(self.history) == 20
James E. Blaircaec0c52012-08-22 14:52:22 -07001694
1695 assert A.data['status'] == 'NEW'
James E. Blairec590122012-08-22 15:19:31 -07001696 assert B.data['status'] == 'MERGED'
1697 assert C.data['status'] == 'MERGED'
1698 assert A.reported == 2
1699 assert B.reported == 2
1700 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001701 self.assertEmptyQueues()
James E. Blair4ec821f2012-08-23 15:28:28 -07001702
1703 def test_nonvoting_job(self):
1704 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001705
James E. Blair4ec821f2012-08-23 15:28:28 -07001706 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1707 'master', 'A')
1708 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001709 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07001710 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1711
1712 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07001713
1714 assert A.data['status'] == 'MERGED'
1715 assert A.reported == 2
James E. Blair4ca985f2013-05-30 12:27:43 -07001716 assert (self.getJobFromHistory('nonvoting-project-merge').result ==
1717 'SUCCESS')
1718 assert (self.getJobFromHistory('nonvoting-project-test1').result ==
1719 'SUCCESS')
1720 assert (self.getJobFromHistory('nonvoting-project-test2').result ==
1721 'FAILURE')
James E. Blaire0487072012-08-29 17:38:31 -07001722 self.assertEmptyQueues()
1723
1724 def test_check_queue_success(self):
1725 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001726
James E. Blaire0487072012-08-29 17:38:31 -07001727 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1728 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1729
1730 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001731
1732 assert A.data['status'] == 'NEW'
1733 assert A.reported == 1
James E. Blair4ca985f2013-05-30 12:27:43 -07001734 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1735 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1736 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
James E. Blaire0487072012-08-29 17:38:31 -07001737 self.assertEmptyQueues()
1738
1739 def test_check_queue_failure(self):
1740 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001741
James E. Blaire0487072012-08-29 17:38:31 -07001742 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001743 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07001744 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1745
1746 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001747
1748 assert A.data['status'] == 'NEW'
1749 assert A.reported == 1
James E. Blair4ca985f2013-05-30 12:27:43 -07001750 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1751 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1752 assert self.getJobFromHistory('project-test2').result == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001753 self.assertEmptyQueues()
James E. Blair127bc182012-08-28 15:55:15 -07001754
1755 def test_dependent_behind_dequeue(self):
1756 "test that dependent changes behind dequeued changes work"
1757 # This complicated test is a reproduction of a real life bug
1758 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07001759
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001760 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07001761 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1762 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1763 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1764 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1765 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1766 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1767 D.setDependsOn(C, 1)
1768 E.setDependsOn(D, 1)
1769 A.addApproval('CRVW', 2)
1770 B.addApproval('CRVW', 2)
1771 C.addApproval('CRVW', 2)
1772 D.addApproval('CRVW', 2)
1773 E.addApproval('CRVW', 2)
1774 F.addApproval('CRVW', 2)
1775
1776 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07001777
1778 # Change object re-use in the gerrit trigger is hidden if
1779 # changes are added in quick succession; waiting makes it more
1780 # like real life.
1781 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1782 self.waitUntilSettled()
1783 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1784 self.waitUntilSettled()
1785
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001786 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001787 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001788 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001789 self.waitUntilSettled()
1790
1791 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1792 self.waitUntilSettled()
1793 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1794 self.waitUntilSettled()
1795 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1796 self.waitUntilSettled()
1797 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1798 self.waitUntilSettled()
1799
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001800 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001801 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001802 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001803 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001804 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001805 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001806 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001807 self.waitUntilSettled()
1808
1809 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001810
1811 # Grab pointers to the jobs we want to release before
1812 # releasing any, because list indexes may change as
1813 # the jobs complete.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001814 a, b, c = self.builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07001815 a.release()
1816 b.release()
1817 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001818 self.waitUntilSettled()
1819
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001820 self.worker.hold_jobs_in_build = False
1821 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07001822 self.waitUntilSettled()
1823
James E. Blair127bc182012-08-28 15:55:15 -07001824 assert A.data['status'] == 'NEW'
1825 assert B.data['status'] == 'MERGED'
1826 assert C.data['status'] == 'MERGED'
1827 assert D.data['status'] == 'MERGED'
1828 assert E.data['status'] == 'MERGED'
1829 assert F.data['status'] == 'MERGED'
1830
1831 assert A.reported == 2
1832 assert B.reported == 2
1833 assert C.reported == 2
1834 assert D.reported == 2
1835 assert E.reported == 2
1836 assert F.reported == 2
1837
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001838 assert self.countJobResults(self.history, 'ABORTED') == 15
1839 assert len(self.history) == 44
James E. Blaire0487072012-08-29 17:38:31 -07001840 self.assertEmptyQueues()
James E. Blair05fed602012-09-07 12:45:24 -07001841
1842 def test_merger_repack(self):
1843 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001844
James E. Blair05fed602012-09-07 12:45:24 -07001845 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1846 A.addApproval('CRVW', 2)
1847 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1848 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07001849 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1850 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1851 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001852 assert A.data['status'] == 'MERGED'
1853 assert A.reported == 2
1854 self.assertEmptyQueues()
James E. Blair4ca985f2013-05-30 12:27:43 -07001855 self.worker.build_history = []
James E. Blair05fed602012-09-07 12:45:24 -07001856
Monty Taylorbc758832013-06-17 17:22:42 -04001857 path = os.path.join(self.git_root, "org/project")
1858 print repack_repo(path)
James E. Blair05fed602012-09-07 12:45:24 -07001859
1860 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1861 A.addApproval('CRVW', 2)
1862 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1863 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07001864 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1865 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1866 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001867 assert A.data['status'] == 'MERGED'
1868 assert A.reported == 2
1869 self.assertEmptyQueues()
James E. Blair7ee88a22012-09-12 18:59:31 +02001870
James E. Blair4886f282012-11-15 09:27:33 -08001871 def test_merger_repack_large_change(self):
1872 "Test that the merger works with large changes after a repack"
1873 # https://bugs.launchpad.net/zuul/+bug/1078946
1874 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1875 A.addPatchset(large=True)
Monty Taylorbc758832013-06-17 17:22:42 -04001876 path = os.path.join(self.upstream_root, "org/project1")
1877 print repack_repo(path)
1878 path = os.path.join(self.git_root, "org/project1")
1879 print repack_repo(path)
James E. Blair4886f282012-11-15 09:27:33 -08001880
1881 A.addApproval('CRVW', 2)
1882 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1883 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07001884 assert self.getJobFromHistory('project1-merge').result == 'SUCCESS'
1885 assert self.getJobFromHistory('project1-test1').result == 'SUCCESS'
1886 assert self.getJobFromHistory('project1-test2').result == 'SUCCESS'
James E. Blair4886f282012-11-15 09:27:33 -08001887 assert A.data['status'] == 'MERGED'
1888 assert A.reported == 2
1889 self.assertEmptyQueues()
1890
James E. Blair7ee88a22012-09-12 18:59:31 +02001891 def test_nonexistent_job(self):
1892 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001893 # Set to the state immediately after a restart
1894 self.resetGearmanServer()
1895 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02001896
1897 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1898 A.addApproval('CRVW', 2)
1899 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1900 # There may be a thread about to report a lost change
1901 while A.reported < 2:
1902 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001903 job_names = [x.name for x in self.history]
James E. Blair7ee88a22012-09-12 18:59:31 +02001904 assert not job_names
1905 assert A.data['status'] == 'NEW'
1906 assert A.reported == 2
1907 self.assertEmptyQueues()
1908
1909 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001910 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02001911 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1912 A.addApproval('CRVW', 2)
1913 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1914 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07001915 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1916 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1917 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
James E. Blair7ee88a22012-09-12 18:59:31 +02001918 assert A.data['status'] == 'MERGED'
1919 assert A.reported == 2
1920 self.assertEmptyQueues()
James E. Blairf62d4282012-12-31 17:01:50 -08001921
1922 def test_single_nonexistent_post_job(self):
1923 "Test launching a single post job that doesn't exist"
James E. Blairf62d4282012-12-31 17:01:50 -08001924 e = {
1925 "type": "ref-updated",
1926 "submitter": {
1927 "name": "User Name",
1928 },
1929 "refUpdate": {
1930 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1931 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1932 "refName": "master",
1933 "project": "org/project",
1934 }
1935 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001936 # Set to the state immediately after a restart
1937 self.resetGearmanServer()
1938 self.launcher.negative_function_cache_ttl = 0
1939
James E. Blairf62d4282012-12-31 17:01:50 -08001940 self.fake_gerrit.addEvent(e)
1941 self.waitUntilSettled()
1942
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001943 assert len(self.history) == 0
James E. Blairf62d4282012-12-31 17:01:50 -08001944 self.assertEmptyQueues()
James E. Blair2fa50962013-01-30 21:50:41 -08001945
1946 def test_new_patchset_dequeues_old(self):
1947 "Test that a new patchset causes the old to be dequeued"
1948 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001949 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001950 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1951 M.setMerged()
1952
1953 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1954 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1955 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1956 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1957 A.addApproval('CRVW', 2)
1958 B.addApproval('CRVW', 2)
1959 C.addApproval('CRVW', 2)
1960 D.addApproval('CRVW', 2)
1961
1962 C.setDependsOn(B, 1)
1963 B.setDependsOn(A, 1)
1964 A.setDependsOn(M, 1)
1965
1966 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1967 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1968 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1969 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1970 self.waitUntilSettled()
1971
1972 B.addPatchset()
1973 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1974 self.waitUntilSettled()
1975
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001976 self.worker.hold_jobs_in_build = False
1977 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001978 self.waitUntilSettled()
1979
James E. Blair2fa50962013-01-30 21:50:41 -08001980 assert A.data['status'] == 'MERGED'
1981 assert A.reported == 2
1982 assert B.data['status'] == 'NEW'
1983 assert B.reported == 2
1984 assert C.data['status'] == 'NEW'
1985 assert C.reported == 2
1986 assert D.data['status'] == 'MERGED'
1987 assert D.reported == 2
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001988 assert len(self.history) == 9 # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08001989 self.assertEmptyQueues()
1990
1991 def test_new_patchset_dequeues_old_on_head(self):
1992 "Test that a new patchset causes the old to be dequeued (at head)"
1993 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001994 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001995 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1996 M.setMerged()
1997 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1998 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1999 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2000 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
2001 A.addApproval('CRVW', 2)
2002 B.addApproval('CRVW', 2)
2003 C.addApproval('CRVW', 2)
2004 D.addApproval('CRVW', 2)
2005
2006 C.setDependsOn(B, 1)
2007 B.setDependsOn(A, 1)
2008 A.setDependsOn(M, 1)
2009
2010 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2011 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2012 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2013 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2014 self.waitUntilSettled()
2015
2016 A.addPatchset()
2017 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
2018 self.waitUntilSettled()
2019
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002020 self.worker.hold_jobs_in_build = False
2021 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002022 self.waitUntilSettled()
2023
James E. Blair2fa50962013-01-30 21:50:41 -08002024 assert A.data['status'] == 'NEW'
2025 assert A.reported == 2
2026 assert B.data['status'] == 'NEW'
2027 assert B.reported == 2
2028 assert C.data['status'] == 'NEW'
2029 assert C.reported == 2
2030 assert D.data['status'] == 'MERGED'
2031 assert D.reported == 2
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002032 assert len(self.history) == 7
James E. Blair2fa50962013-01-30 21:50:41 -08002033 self.assertEmptyQueues()
2034
2035 def test_new_patchset_dequeues_old_without_dependents(self):
2036 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002037 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002038 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2039 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2040 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2041 A.addApproval('CRVW', 2)
2042 B.addApproval('CRVW', 2)
2043 C.addApproval('CRVW', 2)
2044
2045 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2046 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2047 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2048 self.waitUntilSettled()
2049
2050 B.addPatchset()
2051 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2052 self.waitUntilSettled()
2053
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002054 self.worker.hold_jobs_in_build = False
2055 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002056 self.waitUntilSettled()
2057
James E. Blair2fa50962013-01-30 21:50:41 -08002058 assert A.data['status'] == 'MERGED'
2059 assert A.reported == 2
2060 assert B.data['status'] == 'NEW'
2061 assert B.reported == 2
2062 assert C.data['status'] == 'MERGED'
2063 assert C.reported == 2
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002064 assert len(self.history) == 9
James E. Blair2fa50962013-01-30 21:50:41 -08002065 self.assertEmptyQueues()
2066
2067 def test_new_patchset_dequeues_old_independent_queue(self):
2068 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002069 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002070 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2071 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2072 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2073 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2074 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2075 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2076 self.waitUntilSettled()
2077
2078 B.addPatchset()
2079 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2080 self.waitUntilSettled()
2081
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002082 self.worker.hold_jobs_in_build = False
2083 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002084 self.waitUntilSettled()
2085
James E. Blair2fa50962013-01-30 21:50:41 -08002086 assert A.data['status'] == 'NEW'
2087 assert A.reported == 1
2088 assert B.data['status'] == 'NEW'
2089 assert B.reported == 1
2090 assert C.data['status'] == 'NEW'
2091 assert C.reported == 1
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002092 assert len(self.history) == 10
2093 assert self.countJobResults(self.history, 'ABORTED') == 1
James E. Blair2fa50962013-01-30 21:50:41 -08002094 self.assertEmptyQueues()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002095
2096 def test_zuul_refs(self):
2097 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002098 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08002099 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
2100 M1.setMerged()
2101 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
2102 M2.setMerged()
2103
2104 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2105 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2106 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
2107 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
2108 A.addApproval('CRVW', 2)
2109 B.addApproval('CRVW', 2)
2110 C.addApproval('CRVW', 2)
2111 D.addApproval('CRVW', 2)
2112 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2113 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2114 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2115 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2116
2117 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002118 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002119 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002120 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002121 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002122 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002123 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002124 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002125 self.waitUntilSettled()
2126
James E. Blair7d0dedc2013-02-21 17:26:09 -08002127 a_zref = b_zref = c_zref = d_zref = None
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002128 for x in self.builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08002129 if x.parameters['ZUUL_CHANGE'] == '3':
2130 a_zref = x.parameters['ZUUL_REF']
2131 if x.parameters['ZUUL_CHANGE'] == '4':
2132 b_zref = x.parameters['ZUUL_REF']
2133 if x.parameters['ZUUL_CHANGE'] == '5':
2134 c_zref = x.parameters['ZUUL_REF']
2135 if x.parameters['ZUUL_CHANGE'] == '6':
2136 d_zref = x.parameters['ZUUL_REF']
2137
2138 # There are... four... refs.
2139 assert a_zref is not None
2140 assert b_zref is not None
2141 assert c_zref is not None
2142 assert d_zref is not None
2143
2144 # And they should all be different
2145 refs = set([a_zref, b_zref, c_zref, d_zref])
2146 assert len(refs) == 4
2147
2148 # a ref should have a, not b, and should not be in project2
Monty Taylorbc758832013-06-17 17:22:42 -04002149 assert self.ref_has_change(a_zref, A)
2150 assert not self.ref_has_change(a_zref, B)
2151 assert not self.ref_has_change(a_zref, M2)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002152
2153 # b ref should have a and b, and should not be in project2
Monty Taylorbc758832013-06-17 17:22:42 -04002154 assert self.ref_has_change(b_zref, A)
2155 assert self.ref_has_change(b_zref, B)
2156 assert not self.ref_has_change(b_zref, M2)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002157
2158 # c ref should have a and b in 1, c in 2
Monty Taylorbc758832013-06-17 17:22:42 -04002159 assert self.ref_has_change(c_zref, A)
2160 assert self.ref_has_change(c_zref, B)
2161 assert self.ref_has_change(c_zref, C)
2162 assert not self.ref_has_change(c_zref, D)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002163
2164 # d ref should have a and b in 1, c and d in 2
Monty Taylorbc758832013-06-17 17:22:42 -04002165 assert self.ref_has_change(d_zref, A)
2166 assert self.ref_has_change(d_zref, B)
2167 assert self.ref_has_change(d_zref, C)
2168 assert self.ref_has_change(d_zref, D)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002169
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002170 self.worker.hold_jobs_in_build = False
2171 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002172 self.waitUntilSettled()
2173
2174 assert A.data['status'] == 'MERGED'
2175 assert A.reported == 2
2176 assert B.data['status'] == 'MERGED'
2177 assert B.reported == 2
2178 assert C.data['status'] == 'MERGED'
2179 assert C.reported == 2
2180 assert D.data['status'] == 'MERGED'
2181 assert D.reported == 2
2182 self.assertEmptyQueues()
James E. Blair70c71582013-03-06 08:50:50 -08002183
James E. Blair412e5582013-04-22 15:50:12 -07002184 def test_statsd(self):
2185 "Test each of the statsd methods used in the scheduler"
2186 import extras
2187 statsd = extras.try_import('statsd.statsd')
2188 statsd.incr('test-incr')
2189 statsd.timing('test-timing', 3)
2190 statsd.gauge('test-guage', 12)
2191 self.assertReportedStat('test-incr', '1|c')
2192 self.assertReportedStat('test-timing', '3|ms')
2193 self.assertReportedStat('test-guage', '12|g')
2194
James E. Blair70c71582013-03-06 08:50:50 -08002195 def test_file_jobs(self):
2196 "Test that file jobs run only when appropriate"
2197 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2198 A.addPatchset(['pip-requires'])
2199 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2200 A.addApproval('CRVW', 2)
2201 B.addApproval('CRVW', 2)
2202 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2203 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2204 self.waitUntilSettled()
2205
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002206 testfile_jobs = [x for x in self.history
James E. Blair70c71582013-03-06 08:50:50 -08002207 if x.name == 'project-testfile']
2208
2209 assert len(testfile_jobs) == 1
2210 assert testfile_jobs[0].changes == '1,2'
2211 assert A.data['status'] == 'MERGED'
2212 assert A.reported == 2
2213 assert B.data['status'] == 'MERGED'
2214 assert B.reported == 2
2215 self.assertEmptyQueues()
James E. Blair3c5e5b52013-04-26 11:17:03 -07002216
2217 def test_test_config(self):
2218 "Test that we can test the config"
2219 sched = zuul.scheduler.Scheduler()
2220 sched.testConfig(CONFIG.get('zuul', 'layout_config'))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002221
2222 def test_build_description(self):
2223 "Test that build descriptions update"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002224 self.worker.registerFunction('set_description:' +
2225 self.worker.worker_id)
2226
2227 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2228 A.addApproval('CRVW', 2)
2229 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2230 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002231 desc = self.history[0].description
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002232 self.log.debug("Description: %s" % desc)
2233 assert re.search("Branch.*master", desc)
2234 assert re.search("Pipeline.*gate", desc)
2235 assert re.search("project-merge.*SUCCESS", desc)
2236 assert re.search("project-test1.*SUCCESS", desc)
2237 assert re.search("project-test2.*SUCCESS", desc)
2238 assert re.search("Reported result.*SUCCESS", desc)
2239
2240 def test_node_label(self):
2241 "Test that a job runs on a specific node label"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002242 self.worker.registerFunction('build:node-project-test1:debian')
2243
2244 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2245 A.addApproval('CRVW', 2)
2246 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2247 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07002248
2249 assert self.getJobFromHistory('node-project-merge').node is None
2250 assert self.getJobFromHistory('node-project-test1').node == 'debian'
2251 assert self.getJobFromHistory('node-project-test2').node is None