blob: 66fbd4e913ea89b3e8c2065e3fc12683ff31b9ce [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)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400396 self.daemon = True
James E. Blair412e5582013-04-22 15:50:12 -0700397 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
398 self.sock.bind(('', 0))
399 self.port = self.sock.getsockname()[1]
400 self.wake_read, self.wake_write = os.pipe()
401 self.stats = []
402
403 def run(self):
404 while True:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700405 poll = select.poll()
406 poll.register(self.sock, select.POLLIN)
407 poll.register(self.wake_read, select.POLLIN)
408 ret = poll.poll()
409 for (fd, event) in ret:
410 if fd == self.sock.fileno():
James E. Blair412e5582013-04-22 15:50:12 -0700411 data = self.sock.recvfrom(1024)
412 if not data:
413 return
414 self.stats.append(data[0])
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700415 if fd == self.wake_read:
James E. Blair412e5582013-04-22 15:50:12 -0700416 return
417
418 def stop(self):
419 os.write(self.wake_write, '1\n')
420
421
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700422class FakeBuild(threading.Thread):
423 log = logging.getLogger("zuul.test")
424
425 def __init__(self, worker, job, number, node):
426 threading.Thread.__init__(self)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400427 self.daemon = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700428 self.worker = worker
429 self.job = job
430 self.name = job.name.split(':')[1]
431 self.number = number
432 self.node = node
433 self.parameters = json.loads(job.arguments)
434 self.unique = self.parameters['ZUUL_UUID']
435 self.wait_condition = threading.Condition()
436 self.waiting = False
437 self.aborted = False
438 self.created = time.time()
439 self.description = ''
440
441 def release(self):
442 self.wait_condition.acquire()
443 self.wait_condition.notify()
444 self.waiting = False
445 self.log.debug("Build %s released" % self.unique)
446 self.wait_condition.release()
447
448 def isWaiting(self):
449 self.wait_condition.acquire()
450 if self.waiting:
451 ret = True
452 else:
453 ret = False
454 self.wait_condition.release()
455 return ret
456
457 def _wait(self):
458 self.wait_condition.acquire()
459 self.waiting = True
460 self.log.debug("Build %s waiting" % self.unique)
461 self.wait_condition.wait()
462 self.wait_condition.release()
463
464 def run(self):
465 data = {
James E. Blair3c483cf2013-06-04 16:30:43 -0700466 'url': 'https://server/job/%s/%s/' % (self.name, self.number),
467 'name': self.name,
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700468 'number': self.number,
James E. Blair3c483cf2013-06-04 16:30:43 -0700469 'manager': self.worker.worker_id,
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700470 }
471
472 self.job.sendWorkData(json.dumps(data))
473 self.job.sendWorkStatus(0, 100)
474
475 if self.worker.hold_jobs_in_build:
476 self._wait()
477 self.log.debug("Build %s continuing" % self.unique)
478
479 self.worker.lock.acquire()
480
481 result = 'SUCCESS'
482 if (('ZUUL_REF' in self.parameters) and
483 self.worker.shouldFailTest(self.name,
484 self.parameters['ZUUL_REF'])):
485 result = 'FAILURE'
486 if self.aborted:
487 result = 'ABORTED'
488
489 data = {'result': result}
490 changes = None
491 if 'ZUUL_CHANGE_IDS' in self.parameters:
492 changes = self.parameters['ZUUL_CHANGE_IDS']
493
494 self.worker.build_history.append(
495 BuildHistory(name=self.name, number=self.number,
496 result=result, changes=changes, node=self.node,
497 uuid=self.unique, description=self.description)
498 )
499
500 self.job.sendWorkComplete(json.dumps(data))
501 del self.worker.gearman_jobs[self.job.unique]
502 self.worker.running_builds.remove(self)
503 self.worker.lock.release()
504
505
506class FakeWorker(gear.Worker):
Monty Taylorbc758832013-06-17 17:22:42 -0400507 def __init__(self, worker_id, test):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700508 super(FakeWorker, self).__init__(worker_id)
509 self.gearman_jobs = {}
510 self.build_history = []
511 self.running_builds = []
512 self.build_counter = 0
513 self.fail_tests = {}
Monty Taylorbc758832013-06-17 17:22:42 -0400514 self.test = test
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700515
516 self.hold_jobs_in_build = False
517 self.lock = threading.Lock()
518 self.__work_thread = threading.Thread(target=self.work)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400519 self.__work_thread.daemon = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700520 self.__work_thread.start()
521
522 def handleJob(self, job):
523 parts = job.name.split(":")
524 cmd = parts[0]
525 name = parts[1]
526 if len(parts) > 2:
527 node = parts[2]
528 else:
529 node = None
530 if cmd == 'build':
531 self.handleBuild(job, name, node)
532 elif cmd == 'stop':
533 self.handleStop(job, name)
534 elif cmd == 'set_description':
535 self.handleSetDescription(job, name)
536
537 def handleBuild(self, job, name, node):
538 build = FakeBuild(self, job, self.build_counter, node)
539 job.build = build
540 self.gearman_jobs[job.unique] = job
541 self.build_counter += 1
542
543 self.running_builds.append(build)
544 build.start()
545
546 def handleStop(self, job, name):
547 self.log.debug("handle stop")
James E. Blair3c483cf2013-06-04 16:30:43 -0700548 parameters = json.loads(job.arguments)
549 name = parameters['name']
550 number = parameters['number']
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700551 for build in self.running_builds:
James E. Blair3c483cf2013-06-04 16:30:43 -0700552 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700553 build.aborted = True
554 build.release()
555 job.sendWorkComplete()
556 return
557 job.sendWorkFail()
558
559 def handleSetDescription(self, job, name):
560 self.log.debug("handle set description")
561 parameters = json.loads(job.arguments)
James E. Blair3c483cf2013-06-04 16:30:43 -0700562 name = parameters['name']
563 number = parameters['number']
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700564 descr = parameters['html_description']
565 for build in self.running_builds:
James E. Blair3c483cf2013-06-04 16:30:43 -0700566 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700567 build.description = descr
568 job.sendWorkComplete()
569 return
570 for build in self.build_history:
James E. Blair3c483cf2013-06-04 16:30:43 -0700571 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700572 build.description = descr
573 job.sendWorkComplete()
574 return
575 job.sendWorkFail()
576
577 def work(self):
578 while self.running:
579 try:
580 job = self.getJob()
581 except gear.InterruptedError:
582 continue
583 try:
584 self.handleJob(job)
585 except:
586 self.log.exception("Worker exception:")
587
588 def addFailTest(self, name, change):
589 l = self.fail_tests.get(name, [])
590 l.append(change)
591 self.fail_tests[name] = l
592
593 def shouldFailTest(self, name, ref):
594 l = self.fail_tests.get(name, [])
595 for change in l:
Monty Taylorbc758832013-06-17 17:22:42 -0400596 if self.test.ref_has_change(ref, change):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700597 return True
598 return False
599
600 def release(self, regex=None):
601 builds = self.running_builds[:]
602 self.log.debug("releasing build %s (%s)" % (regex,
603 len(self.running_builds)))
604 for build in builds:
605 if not regex or re.match(regex, build.name):
606 self.log.debug("releasing build %s" %
607 (build.parameters['ZUUL_UUID']))
608 build.release()
609 else:
610 self.log.debug("not releasing build %s" %
611 (build.parameters['ZUUL_UUID']))
612 self.log.debug("done releasing builds %s (%s)" %
613 (regex, len(self.running_builds)))
614
615
616class FakeGearmanServer(gear.Server):
617 def __init__(self):
618 self.hold_jobs_in_queue = False
619 super(FakeGearmanServer, self).__init__(0)
620
621 def getJobForConnection(self, connection, peek=False):
James E. Blair701c5b42013-06-06 09:34:59 -0700622 for queue in [self.high_queue, self.normal_queue, self.low_queue]:
623 for job in queue:
624 if not hasattr(job, 'waiting'):
625 if job.name.startswith('build:'):
626 job.waiting = self.hold_jobs_in_queue
627 else:
628 job.waiting = False
629 if job.waiting:
630 continue
631 if job.name in connection.functions:
632 if not peek:
633 queue.remove(job)
James E. Blaire2819012013-06-28 17:17:26 -0400634 connection.related_jobs[job.handle] = job
635 job.worker_connection = connection
636 job.running = True
James E. Blair701c5b42013-06-06 09:34:59 -0700637 return job
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700638 return None
639
640 def release(self, regex=None):
641 released = False
James E. Blair701c5b42013-06-06 09:34:59 -0700642 qlen = (len(self.high_queue) + len(self.normal_queue) +
643 len(self.low_queue))
644 self.log.debug("releasing queued job %s (%s)" % (regex, qlen))
645 for queue in [self.high_queue, self.normal_queue, self.low_queue]:
646 queue = queue[:]
647 for job in queue:
648 cmd, name = job.name.split(':')
649 if cmd != 'build':
650 continue
651 if not regex or re.match(regex, name):
652 self.log.debug("releasing queued job %s" %
653 job.unique)
654 job.waiting = False
655 released = True
656 else:
657 self.log.debug("not releasing queued job %s" %
658 job.unique)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700659 if released:
660 self.wakeConnections()
James E. Blair701c5b42013-06-06 09:34:59 -0700661 qlen = (len(self.high_queue) + len(self.normal_queue) +
662 len(self.low_queue))
663 self.log.debug("done releasing queued jobs %s (%s)" % (regex, qlen))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700664
665
Monty Taylorbc758832013-06-17 17:22:42 -0400666class TestScheduler(testtools.TestCase):
James E. Blairb0fcae42012-07-17 11:12:10 -0700667 log = logging.getLogger("zuul.test")
668
669 def setUp(self):
Monty Taylorbc758832013-06-17 17:22:42 -0400670 super(TestScheduler, self).setUp()
671 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
672 try:
673 test_timeout = int(test_timeout)
674 except ValueError:
675 # If timeout value is invalid do not set a timeout.
676 test_timeout = 0
677 if test_timeout > 0:
678 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
679
680 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
681 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
682 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
683 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
684 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
685 os.environ.get('OS_STDERR_CAPTURE') == '1'):
686 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
687 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
688 self.useFixture(fixtures.NestedTempfile())
Monty Taylore6a6c402013-07-02 09:25:55 -0700689 if (os.environ.get('OS_LOG_CAPTURE') == 'True' or
690 os.environ.get('OS_LOG_CAPTURE') == '1'):
James E. Blaire2819012013-06-28 17:17:26 -0400691 self.useFixture(fixtures.FakeLogger(
692 level=logging.DEBUG,
693 format='%(asctime)s %(name)-32s '
694 '%(levelname)-8s %(message)s'))
695 tmp_root = tempfile.mkdtemp(dir=os.environ.get("ZUUL_TEST_ROOT",
696 '/tmp'))
Monty Taylorbc758832013-06-17 17:22:42 -0400697 self.test_root = os.path.join(tmp_root, "zuul-test")
698 self.upstream_root = os.path.join(self.test_root, "upstream")
699 self.git_root = os.path.join(self.test_root, "git")
700
701 CONFIG.set('zuul', 'git_dir', self.git_root)
702 if os.path.exists(self.test_root):
703 shutil.rmtree(self.test_root)
704 os.makedirs(self.test_root)
705 os.makedirs(self.upstream_root)
706 os.makedirs(self.git_root)
James E. Blair4886cc12012-07-18 15:39:41 -0700707
708 # For each project in config:
Monty Taylorbc758832013-06-17 17:22:42 -0400709 self.init_repo("org/project")
710 self.init_repo("org/project1")
711 self.init_repo("org/project2")
712 self.init_repo("org/project3")
713 self.init_repo("org/one-job-project")
714 self.init_repo("org/nonvoting-project")
715 self.init_repo("org/templated-project")
716 self.init_repo("org/node-project")
James E. Blair412e5582013-04-22 15:50:12 -0700717
718 self.statsd = FakeStatsd()
719 os.environ['STATSD_HOST'] = 'localhost'
720 os.environ['STATSD_PORT'] = str(self.statsd.port)
721 self.statsd.start()
722 # the statsd client object is configured in the statsd module import
723 reload(statsd)
724 reload(zuul.scheduler)
725
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700726 self.gearman_server = FakeGearmanServer()
727
728 self.config = ConfigParser.ConfigParser()
729 cfg = StringIO()
730 CONFIG.write(cfg)
731 cfg.seek(0)
732 self.config.readfp(cfg)
733 self.config.set('gearman', 'port', str(self.gearman_server.port))
734
Monty Taylorbc758832013-06-17 17:22:42 -0400735 self.worker = FakeWorker('fake_worker', self)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700736 self.worker.addServer('127.0.0.1', self.gearman_server.port)
737 self.gearman_server.worker = self.worker
738
James E. Blairb0fcae42012-07-17 11:12:10 -0700739 self.sched = zuul.scheduler.Scheduler()
740
James E. Blair8cc15a82012-08-01 11:17:57 -0700741 def URLOpenerFactory(*args, **kw):
742 args = [self.fake_gerrit] + list(args)
Monty Taylorbc758832013-06-17 17:22:42 -0400743 return FakeURLOpener(self.upstream_root, *args, **kw)
James E. Blair8cc15a82012-08-01 11:17:57 -0700744
James E. Blair8cc15a82012-08-01 11:17:57 -0700745 urllib2.urlopen = URLOpenerFactory
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700746 self.launcher = zuul.launcher.gearman.Gearman(self.config, self.sched)
James E. Blairb0fcae42012-07-17 11:12:10 -0700747
748 zuul.lib.gerrit.Gerrit = FakeGerrit
749
Monty Taylorbc758832013-06-17 17:22:42 -0400750 self.gerrit = FakeGerritTrigger(
751 self.upstream_root, self.config, self.sched)
James E. Blair8cc15a82012-08-01 11:17:57 -0700752 self.gerrit.replication_timeout = 1.5
753 self.gerrit.replication_retry_interval = 0.5
James E. Blairb0fcae42012-07-17 11:12:10 -0700754 self.fake_gerrit = self.gerrit.gerrit
Monty Taylorbc758832013-06-17 17:22:42 -0400755 self.fake_gerrit.upstream_root = self.upstream_root
James E. Blairb0fcae42012-07-17 11:12:10 -0700756
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700757 self.sched.setLauncher(self.launcher)
James E. Blairb0fcae42012-07-17 11:12:10 -0700758 self.sched.setTrigger(self.gerrit)
759
760 self.sched.start()
761 self.sched.reconfigure(self.config)
762 self.sched.resume()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700763 self.launcher.gearman.waitForServer()
764 self.registerJobs()
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400765 self.builds = self.worker.running_builds
766 self.history = self.worker.build_history
James E. Blairb0fcae42012-07-17 11:12:10 -0700767
768 def tearDown(self):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700769 self.launcher.stop()
770 self.worker.shutdown()
771 self.gearman_server.shutdown()
James E. Blairb0fcae42012-07-17 11:12:10 -0700772 self.gerrit.stop()
773 self.sched.stop()
774 self.sched.join()
James E. Blair412e5582013-04-22 15:50:12 -0700775 self.statsd.stop()
776 self.statsd.join()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700777 threads = threading.enumerate()
778 if len(threads) > 1:
779 self.log.error("More than one thread is running: %s" % threads)
Monty Taylorbc758832013-06-17 17:22:42 -0400780 super(TestScheduler, self).tearDown()
781
782 def init_repo(self, project):
783 parts = project.split('/')
784 path = os.path.join(self.upstream_root, *parts[:-1])
785 if not os.path.exists(path):
786 os.makedirs(path)
787 path = os.path.join(self.upstream_root, project)
788 repo = git.Repo.init(path)
789
790 repo.config_writer().set_value('user', 'email', 'user@example.com')
791 repo.config_writer().set_value('user', 'name', 'User Name')
792 repo.config_writer().write()
793
794 fn = os.path.join(path, 'README')
795 f = open(fn, 'w')
796 f.write("test\n")
797 f.close()
798 repo.index.add([fn])
799 repo.index.commit('initial commit')
800 master = repo.create_head('master')
801 repo.create_tag('init')
802
803 mp = repo.create_head('mp')
804 repo.head.reference = mp
805 f = open(fn, 'a')
806 f.write("test mp\n")
807 f.close()
808 repo.index.add([fn])
809 repo.index.commit('mp commit')
810
811 repo.head.reference = master
812 repo.head.reset(index=True, working_tree=True)
813 repo.git.clean('-x', '-f', '-d')
814
815 def ref_has_change(self, ref, change):
816 path = os.path.join(self.git_root, change.project)
817 repo = git.Repo(path)
818 for commit in repo.iter_commits(ref):
819 if commit.message.strip() == ('%s-1' % change.subject):
820 return True
821 return False
822
823 def job_has_changes(self, *args):
824 job = args[0]
825 commits = args[1:]
826 if isinstance(job, FakeBuild):
827 parameters = job.parameters
828 else:
829 parameters = json.loads(job.arguments)
830 project = parameters['ZUUL_PROJECT']
831 path = os.path.join(self.git_root, project)
832 repo = git.Repo(path)
833 ref = parameters['ZUUL_REF']
834 sha = parameters['ZUUL_COMMIT']
835 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
836 repo_shas = [c.hexsha for c in repo.iter_commits(ref)]
837 commit_messages = ['%s-1' % commit.subject for commit in commits]
838 for msg in commit_messages:
839 if msg not in repo_messages:
840 return False
841 if repo_shas[0] != sha:
842 return False
843 return True
James E. Blairb0fcae42012-07-17 11:12:10 -0700844
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700845 def registerJobs(self):
846 count = 0
847 for job in self.sched.jobs.keys():
848 self.worker.registerFunction('build:' + job)
849 count += 1
850 self.worker.registerFunction('stop:' + self.worker.worker_id)
851 count += 1
852
853 while len(self.gearman_server.functions) < count:
854 time.sleep(0)
855
856 def release(self, job):
857 if isinstance(job, FakeBuild):
858 job.release()
859 else:
860 job.waiting = False
861 self.log.debug("Queued job %s released" % job.unique)
862 self.gearman_server.wakeConnections()
863
864 def getParameter(self, job, name):
865 if isinstance(job, FakeBuild):
866 return job.parameters[name]
867 else:
868 parameters = json.loads(job.arguments)
869 return parameters[name]
870
871 def resetGearmanServer(self):
872 self.worker.setFunctions([])
873 while True:
874 done = True
875 for connection in self.gearman_server.active_connections:
876 if connection.functions:
877 done = False
878 if done:
879 break
880 time.sleep(0)
881 self.gearman_server.functions = set()
882
883 def haveAllBuildsReported(self):
884 # See if Zuul is waiting on a meta job to complete
885 if self.launcher.meta_jobs:
886 return False
887 # Find out if every build that the worker has completed has been
888 # reported back to Zuul. If it hasn't then that means a Gearman
889 # event is still in transit and the system is not stable.
890 for build in self.worker.build_history:
891 zbuild = self.launcher.builds.get(build.uuid)
892 if not zbuild:
893 # It has already been reported
894 continue
895 # It hasn't been reported yet.
896 return False
897 # Make sure that none of the worker connections are in GRAB_WAIT
898 for connection in self.worker.active_connections:
899 if connection.state == 'GRAB_WAIT':
900 return False
901 return True
902
903 def areAllBuildsWaiting(self):
904 ret = True
905
906 builds = self.launcher.builds.values()
907 for build in builds:
908 client_job = None
909 for conn in self.launcher.gearman.active_connections:
910 for j in conn.related_jobs.values():
911 if j.unique == build.uuid:
912 client_job = j
913 break
914 if not client_job:
915 self.log.debug("%s is not known to the gearman client" %
916 build)
917 ret = False
918 continue
919 if not client_job.handle:
920 self.log.debug("%s has no handle" % client_job)
921 ret = False
922 continue
923 server_job = self.gearman_server.jobs.get(client_job.handle)
924 if not server_job:
925 self.log.debug("%s is not known to the gearman server" %
926 client_job)
927 ret = False
928 continue
929 if not hasattr(server_job, 'waiting'):
930 self.log.debug("%s is being enqueued" % server_job)
931 ret = False
932 continue
933 if server_job.waiting:
934 continue
935 worker_job = self.worker.gearman_jobs.get(server_job.unique)
936 if worker_job:
937 if worker_job.build.isWaiting():
938 continue
939 else:
940 self.log.debug("%s is running" % worker_job)
941 ret = False
942 else:
943 self.log.debug("%s is unassigned" % server_job)
944 ret = False
945 return ret
946
James E. Blairb0fcae42012-07-17 11:12:10 -0700947 def waitUntilSettled(self):
948 self.log.debug("Waiting until settled...")
949 start = time.time()
950 while True:
951 if time.time() - start > 10:
952 print 'queue status:',
953 print self.sched.trigger_event_queue.empty(),
954 print self.sched.result_event_queue.empty(),
955 print self.fake_gerrit.event_queue.empty(),
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700956 print self.areAllBuildsWaiting()
James E. Blairb0fcae42012-07-17 11:12:10 -0700957 raise Exception("Timeout waiting for Zuul to settle")
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700958 # Make sure no new events show up while we're checking
959 self.worker.lock.acquire()
960 # have all build states propogated to zuul?
961 if self.haveAllBuildsReported():
962 # Join ensures that the queue is empty _and_ events have been
963 # processed
964 self.fake_gerrit.event_queue.join()
965 self.sched.trigger_event_queue.join()
966 self.sched.result_event_queue.join()
967 if (self.sched.trigger_event_queue.empty() and
968 self.sched.result_event_queue.empty() and
969 self.fake_gerrit.event_queue.empty() and
970 self.areAllBuildsWaiting()):
971 self.worker.lock.release()
972 self.log.debug("...settled.")
973 return
974 self.worker.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700975 self.sched.wake_event.wait(0.1)
976
James E. Blaird466dc42012-07-31 10:42:56 -0700977 def countJobResults(self, jobs, result):
James E. Blair0018a6c2013-02-27 14:11:45 -0800978 jobs = filter(lambda x: x.result == result, jobs)
James E. Blaird466dc42012-07-31 10:42:56 -0700979 return len(jobs)
980
James E. Blair4ca985f2013-05-30 12:27:43 -0700981 def getJobFromHistory(self, name):
982 history = self.worker.build_history
983 for job in history:
984 if job.name == name:
985 return job
986 raise Exception("Unable to find job %s in history" % name)
987
James E. Blaire0487072012-08-29 17:38:31 -0700988 def assertEmptyQueues(self):
989 # Make sure there are no orphaned jobs
990 for pipeline in self.sched.pipelines.values():
991 for queue in pipeline.queues:
992 if len(queue.queue) != 0:
James E. Blairf62d4282012-12-31 17:01:50 -0800993 print 'pipeline %s queue %s contents %s' % (
994 pipeline.name, queue.name, queue.queue)
James E. Blaire0487072012-08-29 17:38:31 -0700995 assert len(queue.queue) == 0
996 if len(queue.severed_heads) != 0:
997 print 'heads', queue.severed_heads
998 assert len(queue.severed_heads) == 0
999
James E. Blair412e5582013-04-22 15:50:12 -07001000 def assertReportedStat(self, key, value=None):
1001 start = time.time()
1002 while time.time() < (start + 5):
1003 for stat in self.statsd.stats:
1004 k, v = stat.split(':')
1005 if key == k:
1006 if value is None:
1007 return
1008 if value == v:
1009 return
1010 time.sleep(0.1)
1011
1012 pprint.pprint(self.statsd.stats)
1013 raise Exception("Key %s not found in reported stats" % key)
1014
James E. Blairb0fcae42012-07-17 11:12:10 -07001015 def test_jobs_launched(self):
1016 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001017
James E. Blairb0fcae42012-07-17 11:12:10 -07001018 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -07001019 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001020 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1021 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07001022 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1023 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1024 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
James E. Blairb0fcae42012-07-17 11:12:10 -07001025 assert A.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001026 assert A.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001027 self.assertEmptyQueues()
James E. Blairb0fcae42012-07-17 11:12:10 -07001028
James E. Blair412e5582013-04-22 15:50:12 -07001029 self.assertReportedStat('gerrit.event.comment-added', '1|c')
1030 self.assertReportedStat('zuul.pipeline.gate.current_changes', '1|g')
1031 self.assertReportedStat('zuul.job.project-merge')
1032 self.assertReportedStat('zuul.pipeline.gate.resident_time')
1033 self.assertReportedStat('zuul.pipeline.gate.total_changes', '1|c')
1034 self.assertReportedStat(
1035 'zuul.pipeline.gate.org.project.resident_time')
1036 self.assertReportedStat(
1037 'zuul.pipeline.gate.org.project.total_changes', '1|c')
1038
James E. Blair42f74822013-05-14 15:18:03 -07001039 def test_duplicate_pipelines(self):
1040 "Test that a change matching multiple pipelines works"
James E. Blair1b4d9722013-05-21 10:32:04 -07001041
James E. Blair42f74822013-05-14 15:18:03 -07001042 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1043 self.fake_gerrit.addEvent(A.getChangeRestoredEvent())
1044 self.waitUntilSettled()
James E. Blair42f74822013-05-14 15:18:03 -07001045
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001046 print self.builds
James E. Blair42f74822013-05-14 15:18:03 -07001047 print A.messages
1048
1049 self.assertEmptyQueues()
1050
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001051 assert len(self.history) == 2
1052 self.history[0].name == 'project-test1'
1053 self.history[1].name == 'project-test1'
James E. Blair42f74822013-05-14 15:18:03 -07001054
1055 assert len(A.messages) == 2
1056 if 'dup1/project-test1' in A.messages[0]:
1057 assert 'dup1/project-test1' in A.messages[0]
1058 assert 'dup2/project-test1' not in A.messages[0]
1059 assert 'dup1/project-test1' not in A.messages[1]
1060 assert 'dup2/project-test1' in A.messages[1]
1061 else:
1062 assert 'dup1/project-test1' in A.messages[1]
1063 assert 'dup2/project-test1' not in A.messages[1]
1064 assert 'dup1/project-test1' not in A.messages[0]
1065 assert 'dup2/project-test1' in A.messages[0]
1066
James E. Blairb0fcae42012-07-17 11:12:10 -07001067 def test_parallel_changes(self):
1068 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001069
1070 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -07001071 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1072 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1073 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001074 A.addApproval('CRVW', 2)
1075 B.addApproval('CRVW', 2)
1076 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001077
1078 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1079 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1080 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1081
1082 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001083 assert len(self.builds) == 1
1084 assert self.builds[0].name == 'project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001085 assert self.job_has_changes(self.builds[0], A)
James E. Blairb0fcae42012-07-17 11:12:10 -07001086
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001087 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001088 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001089 assert len(self.builds) == 3
1090 assert self.builds[0].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001091 assert self.job_has_changes(self.builds[0], A)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001092 assert self.builds[1].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001093 assert self.job_has_changes(self.builds[1], A)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001094 assert self.builds[2].name == 'project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001095 assert self.job_has_changes(self.builds[2], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -07001096
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001097 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001098 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001099 assert len(self.builds) == 5
1100 assert self.builds[0].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001101 assert self.job_has_changes(self.builds[0], A)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001102 assert self.builds[1].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001103 assert self.job_has_changes(self.builds[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -07001104
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001105 assert self.builds[2].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001106 assert self.job_has_changes(self.builds[2], A, B)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001107 assert self.builds[3].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001108 assert self.job_has_changes(self.builds[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -07001109
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001110 assert self.builds[4].name == 'project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001111 assert self.job_has_changes(self.builds[4], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -07001112
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001113 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001114 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001115 assert len(self.builds) == 6
1116 assert self.builds[0].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001117 assert self.job_has_changes(self.builds[0], A)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001118 assert self.builds[1].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001119 assert self.job_has_changes(self.builds[1], A)
James E. Blairb0fcae42012-07-17 11:12:10 -07001120
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001121 assert self.builds[2].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001122 assert self.job_has_changes(self.builds[2], A, B)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001123 assert self.builds[3].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001124 assert self.job_has_changes(self.builds[3], A, B)
James E. Blairb0fcae42012-07-17 11:12:10 -07001125
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001126 assert self.builds[4].name == 'project-test1'
Monty Taylorbc758832013-06-17 17:22:42 -04001127 assert self.job_has_changes(self.builds[4], A, B, C)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001128 assert self.builds[5].name == 'project-test2'
Monty Taylorbc758832013-06-17 17:22:42 -04001129 assert self.job_has_changes(self.builds[5], A, B, C)
James E. Blairb0fcae42012-07-17 11:12:10 -07001130
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001131 self.worker.hold_jobs_in_build = False
1132 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -07001133 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001134 assert len(self.builds) == 0
James E. Blairb0fcae42012-07-17 11:12:10 -07001135
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001136 assert len(self.history) == 9
James E. Blairb0fcae42012-07-17 11:12:10 -07001137 assert A.data['status'] == 'MERGED'
1138 assert B.data['status'] == 'MERGED'
1139 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001140 assert A.reported == 2
1141 assert B.reported == 2
1142 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001143 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001144
1145 def test_failed_changes(self):
1146 "Test that a change behind a failed change is retested"
James E. Blaire2819012013-06-28 17:17:26 -04001147 self.worker.hold_jobs_in_build = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001148
James E. Blairb02a3bb2012-07-30 17:49:55 -07001149 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1150 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -07001151 A.addApproval('CRVW', 2)
1152 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001153
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001154 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001155
James E. Blaire2819012013-06-28 17:17:26 -04001156 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1157 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
James E. Blairb02a3bb2012-07-30 17:49:55 -07001158 self.waitUntilSettled()
James E. Blaire2819012013-06-28 17:17:26 -04001159
1160 self.worker.release('.*-merge')
1161 self.waitUntilSettled()
1162
1163 self.worker.hold_jobs_in_build = False
1164 self.worker.release()
1165
1166 self.waitUntilSettled()
1167 # It's certain that the merge job for change 2 will run, but
1168 # the test1 and test2 jobs may or may not run.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001169 assert len(self.history) > 6
James E. Blairb02a3bb2012-07-30 17:49:55 -07001170 assert A.data['status'] == 'NEW'
1171 assert B.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001172 assert A.reported == 2
1173 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001174 self.assertEmptyQueues()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001175
1176 def test_independent_queues(self):
1177 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001178
1179 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +09001180 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001181 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1182 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001183 A.addApproval('CRVW', 2)
1184 B.addApproval('CRVW', 2)
1185 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001186
1187 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1188 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1189 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1190
James E. Blairb02a3bb2012-07-30 17:49:55 -07001191 self.waitUntilSettled()
1192
1193 # There should be one merge job at the head of each queue running
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001194 assert len(self.builds) == 2
1195 assert self.builds[0].name == 'project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001196 assert self.job_has_changes(self.builds[0], A)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001197 assert self.builds[1].name == 'project1-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001198 assert self.job_has_changes(self.builds[1], B)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001199
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001200 # Release the current merge builds
1201 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001202 self.waitUntilSettled()
1203 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001204 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001205 self.waitUntilSettled()
1206
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001207 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -07001208 # project1 (3) + project2 (3) + project (2) = 8
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001209 assert len(self.builds) == 8
James E. Blairb02a3bb2012-07-30 17:49:55 -07001210
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001211 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001212 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001213 assert len(self.builds) == 0
James E. Blairb02a3bb2012-07-30 17:49:55 -07001214
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001215 assert len(self.history) == 11
James E. Blairb02a3bb2012-07-30 17:49:55 -07001216 assert A.data['status'] == 'MERGED'
1217 assert B.data['status'] == 'MERGED'
1218 assert C.data['status'] == 'MERGED'
James E. Blaird466dc42012-07-31 10:42:56 -07001219 assert A.reported == 2
1220 assert B.reported == 2
1221 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001222 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -07001223
1224 def test_failed_change_at_head(self):
1225 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -07001226
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001227 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -07001228 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1229 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1230 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001231 A.addApproval('CRVW', 2)
1232 B.addApproval('CRVW', 2)
1233 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001234
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001235 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001236
1237 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1238 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1239 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1240
1241 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -07001242
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001243 assert len(self.builds) == 1
1244 assert self.builds[0].name == 'project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001245 assert self.job_has_changes(self.builds[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001246
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001247 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001248 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001249 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001250 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001251 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001252 self.waitUntilSettled()
1253
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001254 assert len(self.builds) == 6
1255 assert self.builds[0].name == 'project-test1'
1256 assert self.builds[1].name == 'project-test2'
1257 assert self.builds[2].name == 'project-test1'
1258 assert self.builds[3].name == 'project-test2'
1259 assert self.builds[4].name == 'project-test1'
1260 assert self.builds[5].name == 'project-test2'
James E. Blaird466dc42012-07-31 10:42:56 -07001261
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001262 self.release(self.builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001263 self.waitUntilSettled()
1264
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001265 assert len(self.builds) == 2 # project-test2, project-merge for B
1266 assert self.countJobResults(self.history, 'ABORTED') == 4
James E. Blaird466dc42012-07-31 10:42:56 -07001267
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001268 self.worker.hold_jobs_in_build = False
1269 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001270 self.waitUntilSettled()
1271
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001272 assert len(self.builds) == 0
1273 assert len(self.history) == 15
James E. Blaird466dc42012-07-31 10:42:56 -07001274 assert A.data['status'] == 'NEW'
1275 assert B.data['status'] == 'MERGED'
1276 assert C.data['status'] == 'MERGED'
1277 assert A.reported == 2
1278 assert B.reported == 2
1279 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001280 self.assertEmptyQueues()
James E. Blaird466dc42012-07-31 10:42:56 -07001281
1282 def test_failed_change_at_head_with_queue(self):
1283 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -07001284
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001285 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -07001286 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1287 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1288 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001289 A.addApproval('CRVW', 2)
1290 B.addApproval('CRVW', 2)
1291 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001292
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001293 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001294
1295 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1296 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1297 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1298
1299 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001300 queue = self.gearman_server.getQueue()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001301 assert len(self.builds) == 0
James E. Blaird466dc42012-07-31 10:42:56 -07001302 assert len(queue) == 1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001303 assert queue[0].name == 'build:project-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001304 assert self.job_has_changes(queue[0], A)
James E. Blaird466dc42012-07-31 10:42:56 -07001305
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001306 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001307 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001308 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001309 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001310 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001311 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001312 queue = self.gearman_server.getQueue()
James E. Blaird466dc42012-07-31 10:42:56 -07001313
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001314 assert len(self.builds) == 0
James E. Blaird466dc42012-07-31 10:42:56 -07001315 assert len(queue) == 6
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001316 assert queue[0].name == 'build:project-test1'
1317 assert queue[1].name == 'build:project-test2'
1318 assert queue[2].name == 'build:project-test1'
1319 assert queue[3].name == 'build:project-test2'
1320 assert queue[4].name == 'build:project-test1'
1321 assert queue[5].name == 'build:project-test2'
James E. Blaird466dc42012-07-31 10:42:56 -07001322
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001323 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001324 self.waitUntilSettled()
1325
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001326 assert len(self.builds) == 0
James E. Blair701c5b42013-06-06 09:34:59 -07001327 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001328 assert len(queue) == 2 # project-test2, project-merge for B
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001329 assert self.countJobResults(self.history, 'ABORTED') == 0
James E. Blaird466dc42012-07-31 10:42:56 -07001330
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001331 self.gearman_server.hold_jobs_in_queue = False
1332 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001333 self.waitUntilSettled()
1334
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001335 assert len(self.builds) == 0
1336 assert len(self.history) == 11
James E. Blaird466dc42012-07-31 10:42:56 -07001337 assert A.data['status'] == 'NEW'
1338 assert B.data['status'] == 'MERGED'
1339 assert C.data['status'] == 'MERGED'
1340 assert A.reported == 2
1341 assert B.reported == 2
1342 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001343 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001344
1345 def test_patch_order(self):
1346 "Test that dependent patches are tested in the right order"
1347 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1348 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1349 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1350 A.addApproval('CRVW', 2)
1351 B.addApproval('CRVW', 2)
1352 C.addApproval('CRVW', 2)
1353
1354 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
1355 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1356 M2.setMerged()
1357 M1.setMerged()
1358
1359 # C -> B -> A -> M1 -> M2
1360 # M2 is here to make sure it is never queried. If it is, it
1361 # means zuul is walking down the entire history of merged
1362 # changes.
1363
1364 C.setDependsOn(B, 1)
1365 B.setDependsOn(A, 1)
1366 A.setDependsOn(M1, 1)
1367 M1.setDependsOn(M2, 1)
1368
1369 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1370
1371 self.waitUntilSettled()
1372
1373 assert A.data['status'] == 'NEW'
1374 assert B.data['status'] == 'NEW'
1375 assert C.data['status'] == 'NEW'
1376
1377 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1378 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1379
1380 self.waitUntilSettled()
1381 assert M2.queried == 0
1382 assert A.data['status'] == 'MERGED'
1383 assert B.data['status'] == 'MERGED'
1384 assert C.data['status'] == 'MERGED'
1385 assert A.reported == 2
1386 assert B.reported == 2
1387 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001388 self.assertEmptyQueues()
James E. Blair8c803f82012-07-31 16:25:42 -07001389
1390 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -07001391 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -07001392 # TODO: move to test_gerrit (this is a unit test!)
1393 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair4aea70c2012-07-26 14:23:24 -07001394 a = self.sched.trigger.getChange(1, 2)
1395 mgr = self.sched.pipelines['gate'].manager
1396 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001397
1398 A.addApproval('CRVW', 2)
James E. Blair4aea70c2012-07-26 14:23:24 -07001399 a = self.sched.trigger.getChange(1, 2)
1400 assert not self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blair8c803f82012-07-31 16:25:42 -07001401
1402 A.addApproval('APRV', 1)
James E. Blair4aea70c2012-07-26 14:23:24 -07001403 a = self.sched.trigger.getChange(1, 2)
1404 assert self.sched.trigger.canMerge(a, mgr.getSubmitAllowNeeds())
James E. Blaire0487072012-08-29 17:38:31 -07001405 self.assertEmptyQueues()
James E. Blair4886cc12012-07-18 15:39:41 -07001406
1407 def test_build_configuration(self):
1408 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001409
1410 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -07001411 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1412 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1413 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1414 A.addApproval('CRVW', 2)
1415 B.addApproval('CRVW', 2)
1416 C.addApproval('CRVW', 2)
1417 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1418 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1419 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1420 self.waitUntilSettled()
1421
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001422 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001423 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001424 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001425 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001426 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001427 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001428 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001429 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1430 self.gearman_server.hold_jobs_in_queue = False
1431 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001432 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -07001433
Monty Taylorbc758832013-06-17 17:22:42 -04001434 path = os.path.join(self.git_root, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -07001435 repo = git.Repo(path)
1436 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1437 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -07001438 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
1439 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001440 self.assertEmptyQueues()
James E. Blair973721f2012-08-15 10:19:43 -07001441
1442 def test_build_configuration_conflict(self):
1443 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001444
1445 self.gearman_server.hold_jobs_in_queue = True
James E. Blair973721f2012-08-15 10:19:43 -07001446 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1447 A.addPatchset(['conflict'])
1448 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1449 B.addPatchset(['conflict'])
1450 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1451 A.addApproval('CRVW', 2)
1452 B.addApproval('CRVW', 2)
1453 C.addApproval('CRVW', 2)
1454 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1455 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1456 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1457 self.waitUntilSettled()
1458
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001459 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001460 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001461 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001462 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001463 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001464 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001465 queue = self.gearman_server.getQueue()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001466 self.getParameter(queue[-1], 'ZUUL_REF')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001467 self.gearman_server.hold_jobs_in_queue = False
1468 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001469 self.waitUntilSettled()
1470
1471 assert A.data['status'] == 'MERGED'
1472 assert B.data['status'] == 'NEW'
1473 assert C.data['status'] == 'MERGED'
1474 assert A.reported == 2
1475 assert B.reported == 2
1476 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001477 self.assertEmptyQueues()
James E. Blairdaabed22012-08-15 15:38:57 -07001478
1479 def test_post(self):
1480 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001481
Zhongyue Luo5d556072012-09-21 02:00:47 +09001482 e = {
1483 "type": "ref-updated",
1484 "submitter": {
1485 "name": "User Name",
1486 },
1487 "refUpdate": {
1488 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1489 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1490 "refName": "master",
1491 "project": "org/project",
1492 }
1493 }
James E. Blairdaabed22012-08-15 15:38:57 -07001494 self.fake_gerrit.addEvent(e)
1495 self.waitUntilSettled()
1496
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001497 job_names = [x.name for x in self.history]
1498 assert len(self.history) == 1
James E. Blairdaabed22012-08-15 15:38:57 -07001499 assert 'project-post' in job_names
James E. Blaire0487072012-08-29 17:38:31 -07001500 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001501
1502 def test_build_configuration_branch(self):
1503 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001504
1505 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001506 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1507 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1508 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1509 A.addApproval('CRVW', 2)
1510 B.addApproval('CRVW', 2)
1511 C.addApproval('CRVW', 2)
1512 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1513 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1514 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1515 self.waitUntilSettled()
1516
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001517 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001518 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001519 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001520 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001521 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001522 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001523 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001524 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1525 self.gearman_server.hold_jobs_in_queue = False
1526 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001527 self.waitUntilSettled()
1528
Monty Taylorbc758832013-06-17 17:22:42 -04001529 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001530 repo = git.Repo(path)
1531 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1532 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001533 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
1534 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001535 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001536
1537 def test_build_configuration_branch_interaction(self):
1538 "Test that switching between branches works"
1539 self.test_build_configuration()
1540 self.test_build_configuration_branch()
1541 # C has been merged, undo that
Monty Taylorbc758832013-06-17 17:22:42 -04001542 path = os.path.join(self.upstream_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001543 repo = git.Repo(path)
1544 repo.heads.master.commit = repo.commit('init')
1545 self.test_build_configuration()
James E. Blaire0487072012-08-29 17:38:31 -07001546 self.assertEmptyQueues()
James E. Blairc6294a52012-08-17 10:19:48 -07001547
1548 def test_build_configuration_multi_branch(self):
1549 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001550
1551 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001552 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1553 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1554 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1555 A.addApproval('CRVW', 2)
1556 B.addApproval('CRVW', 2)
1557 C.addApproval('CRVW', 2)
1558 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1559 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1560 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1561 self.waitUntilSettled()
1562
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001563 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001564 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001565 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001566 ref_mp = self.getParameter(queue[-1], 'ZUUL_REF')
1567 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001568 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001569 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001570 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001571 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001572 ref_master = self.getParameter(queue[-1], 'ZUUL_REF')
1573 self.gearman_server.hold_jobs_in_queue = False
1574 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001575 self.waitUntilSettled()
1576
Monty Taylorbc758832013-06-17 17:22:42 -04001577 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001578 repo = git.Repo(path)
1579
1580 repo_messages = [c.message.strip()
1581 for c in repo.iter_commits(ref_master)]
1582 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001583 correct_messages = ['initial commit', 'A-1', 'C-1']
1584 assert repo_messages == correct_messages
1585
1586 repo_messages = [c.message.strip()
1587 for c in repo.iter_commits(ref_mp)]
1588 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001589 correct_messages = ['initial commit', 'mp commit', 'B-1']
1590 assert repo_messages == correct_messages
James E. Blaire0487072012-08-29 17:38:31 -07001591 self.assertEmptyQueues()
James E. Blair7f71c802012-08-22 13:04:32 -07001592
1593 def test_one_job_project(self):
1594 "Test that queueing works with one job"
1595 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1596 'master', 'A')
1597 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1598 'master', 'B')
1599 A.addApproval('CRVW', 2)
1600 B.addApproval('CRVW', 2)
1601 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1602 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1603 self.waitUntilSettled()
1604
James E. Blair7f71c802012-08-22 13:04:32 -07001605 assert A.data['status'] == 'MERGED'
1606 assert A.reported == 2
1607 assert B.data['status'] == 'MERGED'
1608 assert B.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001609 self.assertEmptyQueues()
James E. Blaircaec0c52012-08-22 14:52:22 -07001610
Antoine Musso80edd5a2013-02-13 15:37:53 +01001611 def test_job_from_templates_launched(self):
1612 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001613
Antoine Musso80edd5a2013-02-13 15:37:53 +01001614 A = self.fake_gerrit.addFakeChange(
1615 'org/templated-project', 'master', 'A')
1616 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1617 self.waitUntilSettled()
Antoine Musso80edd5a2013-02-13 15:37:53 +01001618
James E. Blair4ca985f2013-05-30 12:27:43 -07001619 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1620 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
Antoine Musso80edd5a2013-02-13 15:37:53 +01001621
James E. Blaircaec0c52012-08-22 14:52:22 -07001622 def test_dependent_changes_dequeue(self):
1623 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001624
James E. Blaircaec0c52012-08-22 14:52:22 -07001625 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1626 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1627 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1628 A.addApproval('CRVW', 2)
1629 B.addApproval('CRVW', 2)
1630 C.addApproval('CRVW', 2)
1631
1632 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1633 M1.setMerged()
1634
1635 # C -> B -> A -> M1
1636
1637 C.setDependsOn(B, 1)
1638 B.setDependsOn(A, 1)
1639 A.setDependsOn(M1, 1)
1640
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001641 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07001642
1643 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1644 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1645 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1646
1647 self.waitUntilSettled()
1648
James E. Blairec590122012-08-22 15:19:31 -07001649 assert A.data['status'] == 'NEW'
1650 assert A.reported == 2
1651 assert B.data['status'] == 'NEW'
1652 assert B.reported == 2
1653 assert C.data['status'] == 'NEW'
1654 assert C.reported == 2
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001655 assert len(self.history) == 1
James E. Blaire0487072012-08-29 17:38:31 -07001656 self.assertEmptyQueues()
James E. Blairec590122012-08-22 15:19:31 -07001657
1658 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001659 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001660 # If it's dequeued more than once, we should see extra
1661 # aborted jobs.
James E. Blairec590122012-08-22 15:19:31 -07001662
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001663 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07001664 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1665 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1666 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1667 A.addApproval('CRVW', 2)
1668 B.addApproval('CRVW', 2)
1669 C.addApproval('CRVW', 2)
1670
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001671 self.worker.addFailTest('project1-test1', A)
1672 self.worker.addFailTest('project1-test2', A)
1673 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07001674
1675 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1676 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1677 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1678
1679 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07001680
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001681 assert len(self.builds) == 1
1682 assert self.builds[0].name == 'project1-merge'
Monty Taylorbc758832013-06-17 17:22:42 -04001683 assert self.job_has_changes(self.builds[0], A)
James E. Blairec590122012-08-22 15:19:31 -07001684
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001685 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001686 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001687 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001688 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001689 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001690 self.waitUntilSettled()
1691
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001692 assert len(self.builds) == 9
1693 assert self.builds[0].name == 'project1-test1'
1694 assert self.builds[1].name == 'project1-test2'
1695 assert self.builds[2].name == 'project1-project2-integration'
1696 assert self.builds[3].name == 'project1-test1'
1697 assert self.builds[4].name == 'project1-test2'
1698 assert self.builds[5].name == 'project1-project2-integration'
1699 assert self.builds[6].name == 'project1-test1'
1700 assert self.builds[7].name == 'project1-test2'
1701 assert self.builds[8].name == 'project1-project2-integration'
James E. Blairec590122012-08-22 15:19:31 -07001702
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001703 self.release(self.builds[0])
James E. Blairec590122012-08-22 15:19:31 -07001704 self.waitUntilSettled()
1705
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001706 assert len(self.builds) == 3 # test2, integration, merge for B
1707 assert self.countJobResults(self.history, 'ABORTED') == 6
James E. Blairec590122012-08-22 15:19:31 -07001708
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001709 self.worker.hold_jobs_in_build = False
1710 self.worker.release()
James E. Blairec590122012-08-22 15:19:31 -07001711 self.waitUntilSettled()
1712
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001713 assert len(self.builds) == 0
1714 assert len(self.history) == 20
James E. Blaircaec0c52012-08-22 14:52:22 -07001715
1716 assert A.data['status'] == 'NEW'
James E. Blairec590122012-08-22 15:19:31 -07001717 assert B.data['status'] == 'MERGED'
1718 assert C.data['status'] == 'MERGED'
1719 assert A.reported == 2
1720 assert B.reported == 2
1721 assert C.reported == 2
James E. Blaire0487072012-08-29 17:38:31 -07001722 self.assertEmptyQueues()
James E. Blair4ec821f2012-08-23 15:28:28 -07001723
1724 def test_nonvoting_job(self):
1725 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001726
James E. Blair4ec821f2012-08-23 15:28:28 -07001727 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1728 'master', 'A')
1729 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001730 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07001731 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1732
1733 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07001734
1735 assert A.data['status'] == 'MERGED'
1736 assert A.reported == 2
James E. Blair4ca985f2013-05-30 12:27:43 -07001737 assert (self.getJobFromHistory('nonvoting-project-merge').result ==
1738 'SUCCESS')
1739 assert (self.getJobFromHistory('nonvoting-project-test1').result ==
1740 'SUCCESS')
1741 assert (self.getJobFromHistory('nonvoting-project-test2').result ==
1742 'FAILURE')
James E. Blaire0487072012-08-29 17:38:31 -07001743 self.assertEmptyQueues()
1744
1745 def test_check_queue_success(self):
1746 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001747
James E. Blaire0487072012-08-29 17:38:31 -07001748 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1749 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1750
1751 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001752
1753 assert A.data['status'] == 'NEW'
1754 assert A.reported == 1
James E. Blair4ca985f2013-05-30 12:27:43 -07001755 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1756 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1757 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
James E. Blaire0487072012-08-29 17:38:31 -07001758 self.assertEmptyQueues()
1759
1760 def test_check_queue_failure(self):
1761 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001762
James E. Blaire0487072012-08-29 17:38:31 -07001763 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001764 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07001765 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1766
1767 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001768
1769 assert A.data['status'] == 'NEW'
1770 assert A.reported == 1
James E. Blair4ca985f2013-05-30 12:27:43 -07001771 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1772 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1773 assert self.getJobFromHistory('project-test2').result == 'FAILURE'
James E. Blaire0487072012-08-29 17:38:31 -07001774 self.assertEmptyQueues()
James E. Blair127bc182012-08-28 15:55:15 -07001775
1776 def test_dependent_behind_dequeue(self):
1777 "test that dependent changes behind dequeued changes work"
1778 # This complicated test is a reproduction of a real life bug
1779 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07001780
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001781 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07001782 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1783 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1784 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1785 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1786 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1787 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1788 D.setDependsOn(C, 1)
1789 E.setDependsOn(D, 1)
1790 A.addApproval('CRVW', 2)
1791 B.addApproval('CRVW', 2)
1792 C.addApproval('CRVW', 2)
1793 D.addApproval('CRVW', 2)
1794 E.addApproval('CRVW', 2)
1795 F.addApproval('CRVW', 2)
1796
1797 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07001798
1799 # Change object re-use in the gerrit trigger is hidden if
1800 # changes are added in quick succession; waiting makes it more
1801 # like real life.
1802 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1803 self.waitUntilSettled()
1804 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1805 self.waitUntilSettled()
1806
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001807 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001808 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001809 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001810 self.waitUntilSettled()
1811
1812 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1813 self.waitUntilSettled()
1814 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1815 self.waitUntilSettled()
1816 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1817 self.waitUntilSettled()
1818 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1819 self.waitUntilSettled()
1820
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001821 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001822 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001823 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001824 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001825 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001826 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001827 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001828 self.waitUntilSettled()
1829
1830 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001831
1832 # Grab pointers to the jobs we want to release before
1833 # releasing any, because list indexes may change as
1834 # the jobs complete.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001835 a, b, c = self.builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07001836 a.release()
1837 b.release()
1838 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001839 self.waitUntilSettled()
1840
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001841 self.worker.hold_jobs_in_build = False
1842 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07001843 self.waitUntilSettled()
1844
James E. Blair127bc182012-08-28 15:55:15 -07001845 assert A.data['status'] == 'NEW'
1846 assert B.data['status'] == 'MERGED'
1847 assert C.data['status'] == 'MERGED'
1848 assert D.data['status'] == 'MERGED'
1849 assert E.data['status'] == 'MERGED'
1850 assert F.data['status'] == 'MERGED'
1851
1852 assert A.reported == 2
1853 assert B.reported == 2
1854 assert C.reported == 2
1855 assert D.reported == 2
1856 assert E.reported == 2
1857 assert F.reported == 2
1858
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001859 assert self.countJobResults(self.history, 'ABORTED') == 15
1860 assert len(self.history) == 44
James E. Blaire0487072012-08-29 17:38:31 -07001861 self.assertEmptyQueues()
James E. Blair05fed602012-09-07 12:45:24 -07001862
1863 def test_merger_repack(self):
1864 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001865
James E. Blair05fed602012-09-07 12:45:24 -07001866 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1867 A.addApproval('CRVW', 2)
1868 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1869 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07001870 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1871 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1872 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001873 assert A.data['status'] == 'MERGED'
1874 assert A.reported == 2
1875 self.assertEmptyQueues()
James E. Blair4ca985f2013-05-30 12:27:43 -07001876 self.worker.build_history = []
James E. Blair05fed602012-09-07 12:45:24 -07001877
Monty Taylorbc758832013-06-17 17:22:42 -04001878 path = os.path.join(self.git_root, "org/project")
1879 print repack_repo(path)
James E. Blair05fed602012-09-07 12:45:24 -07001880
1881 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1882 A.addApproval('CRVW', 2)
1883 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1884 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07001885 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1886 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1887 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
James E. Blair05fed602012-09-07 12:45:24 -07001888 assert A.data['status'] == 'MERGED'
1889 assert A.reported == 2
1890 self.assertEmptyQueues()
James E. Blair7ee88a22012-09-12 18:59:31 +02001891
James E. Blair4886f282012-11-15 09:27:33 -08001892 def test_merger_repack_large_change(self):
1893 "Test that the merger works with large changes after a repack"
1894 # https://bugs.launchpad.net/zuul/+bug/1078946
1895 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1896 A.addPatchset(large=True)
Monty Taylorbc758832013-06-17 17:22:42 -04001897 path = os.path.join(self.upstream_root, "org/project1")
1898 print repack_repo(path)
1899 path = os.path.join(self.git_root, "org/project1")
1900 print repack_repo(path)
James E. Blair4886f282012-11-15 09:27:33 -08001901
1902 A.addApproval('CRVW', 2)
1903 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1904 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07001905 assert self.getJobFromHistory('project1-merge').result == 'SUCCESS'
1906 assert self.getJobFromHistory('project1-test1').result == 'SUCCESS'
1907 assert self.getJobFromHistory('project1-test2').result == 'SUCCESS'
James E. Blair4886f282012-11-15 09:27:33 -08001908 assert A.data['status'] == 'MERGED'
1909 assert A.reported == 2
1910 self.assertEmptyQueues()
1911
James E. Blair7ee88a22012-09-12 18:59:31 +02001912 def test_nonexistent_job(self):
1913 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001914 # Set to the state immediately after a restart
1915 self.resetGearmanServer()
1916 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02001917
1918 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1919 A.addApproval('CRVW', 2)
1920 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1921 # There may be a thread about to report a lost change
1922 while A.reported < 2:
1923 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001924 job_names = [x.name for x in self.history]
James E. Blair7ee88a22012-09-12 18:59:31 +02001925 assert not job_names
1926 assert A.data['status'] == 'NEW'
1927 assert A.reported == 2
1928 self.assertEmptyQueues()
1929
1930 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001931 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02001932 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1933 A.addApproval('CRVW', 2)
1934 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1935 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07001936 assert self.getJobFromHistory('project-merge').result == 'SUCCESS'
1937 assert self.getJobFromHistory('project-test1').result == 'SUCCESS'
1938 assert self.getJobFromHistory('project-test2').result == 'SUCCESS'
James E. Blair7ee88a22012-09-12 18:59:31 +02001939 assert A.data['status'] == 'MERGED'
1940 assert A.reported == 2
1941 self.assertEmptyQueues()
James E. Blairf62d4282012-12-31 17:01:50 -08001942
1943 def test_single_nonexistent_post_job(self):
1944 "Test launching a single post job that doesn't exist"
James E. Blairf62d4282012-12-31 17:01:50 -08001945 e = {
1946 "type": "ref-updated",
1947 "submitter": {
1948 "name": "User Name",
1949 },
1950 "refUpdate": {
1951 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1952 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1953 "refName": "master",
1954 "project": "org/project",
1955 }
1956 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001957 # Set to the state immediately after a restart
1958 self.resetGearmanServer()
1959 self.launcher.negative_function_cache_ttl = 0
1960
James E. Blairf62d4282012-12-31 17:01:50 -08001961 self.fake_gerrit.addEvent(e)
1962 self.waitUntilSettled()
1963
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001964 assert len(self.history) == 0
James E. Blairf62d4282012-12-31 17:01:50 -08001965 self.assertEmptyQueues()
James E. Blair2fa50962013-01-30 21:50:41 -08001966
1967 def test_new_patchset_dequeues_old(self):
1968 "Test that a new patchset causes the old to be dequeued"
1969 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001970 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001971 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1972 M.setMerged()
1973
1974 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1975 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1976 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1977 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1978 A.addApproval('CRVW', 2)
1979 B.addApproval('CRVW', 2)
1980 C.addApproval('CRVW', 2)
1981 D.addApproval('CRVW', 2)
1982
1983 C.setDependsOn(B, 1)
1984 B.setDependsOn(A, 1)
1985 A.setDependsOn(M, 1)
1986
1987 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1988 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1989 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1990 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1991 self.waitUntilSettled()
1992
1993 B.addPatchset()
1994 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1995 self.waitUntilSettled()
1996
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001997 self.worker.hold_jobs_in_build = False
1998 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001999 self.waitUntilSettled()
2000
James E. Blair2fa50962013-01-30 21:50:41 -08002001 assert A.data['status'] == 'MERGED'
2002 assert A.reported == 2
2003 assert B.data['status'] == 'NEW'
2004 assert B.reported == 2
2005 assert C.data['status'] == 'NEW'
2006 assert C.reported == 2
2007 assert D.data['status'] == 'MERGED'
2008 assert D.reported == 2
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002009 assert len(self.history) == 9 # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08002010 self.assertEmptyQueues()
2011
2012 def test_new_patchset_dequeues_old_on_head(self):
2013 "Test that a new patchset causes the old to be dequeued (at head)"
2014 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002015 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002016 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
2017 M.setMerged()
2018 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2019 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2020 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2021 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
2022 A.addApproval('CRVW', 2)
2023 B.addApproval('CRVW', 2)
2024 C.addApproval('CRVW', 2)
2025 D.addApproval('CRVW', 2)
2026
2027 C.setDependsOn(B, 1)
2028 B.setDependsOn(A, 1)
2029 A.setDependsOn(M, 1)
2030
2031 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2032 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2033 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2034 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2035 self.waitUntilSettled()
2036
2037 A.addPatchset()
2038 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
2039 self.waitUntilSettled()
2040
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002041 self.worker.hold_jobs_in_build = False
2042 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002043 self.waitUntilSettled()
2044
James E. Blair2fa50962013-01-30 21:50:41 -08002045 assert A.data['status'] == 'NEW'
2046 assert A.reported == 2
2047 assert B.data['status'] == 'NEW'
2048 assert B.reported == 2
2049 assert C.data['status'] == 'NEW'
2050 assert C.reported == 2
2051 assert D.data['status'] == 'MERGED'
2052 assert D.reported == 2
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002053 assert len(self.history) == 7
James E. Blair2fa50962013-01-30 21:50:41 -08002054 self.assertEmptyQueues()
2055
2056 def test_new_patchset_dequeues_old_without_dependents(self):
2057 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002058 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002059 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2060 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2061 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2062 A.addApproval('CRVW', 2)
2063 B.addApproval('CRVW', 2)
2064 C.addApproval('CRVW', 2)
2065
2066 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2067 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2068 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2069 self.waitUntilSettled()
2070
2071 B.addPatchset()
2072 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2073 self.waitUntilSettled()
2074
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002075 self.worker.hold_jobs_in_build = False
2076 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002077 self.waitUntilSettled()
2078
James E. Blair2fa50962013-01-30 21:50:41 -08002079 assert A.data['status'] == 'MERGED'
2080 assert A.reported == 2
2081 assert B.data['status'] == 'NEW'
2082 assert B.reported == 2
2083 assert C.data['status'] == 'MERGED'
2084 assert C.reported == 2
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002085 assert len(self.history) == 9
James E. Blair2fa50962013-01-30 21:50:41 -08002086 self.assertEmptyQueues()
2087
2088 def test_new_patchset_dequeues_old_independent_queue(self):
2089 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002090 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002091 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2092 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2093 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2094 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2095 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2096 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2097 self.waitUntilSettled()
2098
2099 B.addPatchset()
2100 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2101 self.waitUntilSettled()
2102
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002103 self.worker.hold_jobs_in_build = False
2104 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002105 self.waitUntilSettled()
2106
James E. Blair2fa50962013-01-30 21:50:41 -08002107 assert A.data['status'] == 'NEW'
2108 assert A.reported == 1
2109 assert B.data['status'] == 'NEW'
2110 assert B.reported == 1
2111 assert C.data['status'] == 'NEW'
2112 assert C.reported == 1
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002113 assert len(self.history) == 10
2114 assert self.countJobResults(self.history, 'ABORTED') == 1
James E. Blair2fa50962013-01-30 21:50:41 -08002115 self.assertEmptyQueues()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002116
2117 def test_zuul_refs(self):
2118 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002119 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08002120 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
2121 M1.setMerged()
2122 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
2123 M2.setMerged()
2124
2125 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2126 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2127 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
2128 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
2129 A.addApproval('CRVW', 2)
2130 B.addApproval('CRVW', 2)
2131 C.addApproval('CRVW', 2)
2132 D.addApproval('CRVW', 2)
2133 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2134 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2135 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2136 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2137
2138 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002139 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002140 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002141 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002142 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002143 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002144 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002145 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002146 self.waitUntilSettled()
2147
James E. Blair7d0dedc2013-02-21 17:26:09 -08002148 a_zref = b_zref = c_zref = d_zref = None
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002149 for x in self.builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08002150 if x.parameters['ZUUL_CHANGE'] == '3':
2151 a_zref = x.parameters['ZUUL_REF']
2152 if x.parameters['ZUUL_CHANGE'] == '4':
2153 b_zref = x.parameters['ZUUL_REF']
2154 if x.parameters['ZUUL_CHANGE'] == '5':
2155 c_zref = x.parameters['ZUUL_REF']
2156 if x.parameters['ZUUL_CHANGE'] == '6':
2157 d_zref = x.parameters['ZUUL_REF']
2158
2159 # There are... four... refs.
2160 assert a_zref is not None
2161 assert b_zref is not None
2162 assert c_zref is not None
2163 assert d_zref is not None
2164
2165 # And they should all be different
2166 refs = set([a_zref, b_zref, c_zref, d_zref])
2167 assert len(refs) == 4
2168
2169 # a ref should have a, not b, and should not be in project2
Monty Taylorbc758832013-06-17 17:22:42 -04002170 assert self.ref_has_change(a_zref, A)
2171 assert not self.ref_has_change(a_zref, B)
2172 assert not self.ref_has_change(a_zref, M2)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002173
2174 # b ref should have a and b, and should not be in project2
Monty Taylorbc758832013-06-17 17:22:42 -04002175 assert self.ref_has_change(b_zref, A)
2176 assert self.ref_has_change(b_zref, B)
2177 assert not self.ref_has_change(b_zref, M2)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002178
2179 # c ref should have a and b in 1, c in 2
Monty Taylorbc758832013-06-17 17:22:42 -04002180 assert self.ref_has_change(c_zref, A)
2181 assert self.ref_has_change(c_zref, B)
2182 assert self.ref_has_change(c_zref, C)
2183 assert not self.ref_has_change(c_zref, D)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002184
2185 # d ref should have a and b in 1, c and d in 2
Monty Taylorbc758832013-06-17 17:22:42 -04002186 assert self.ref_has_change(d_zref, A)
2187 assert self.ref_has_change(d_zref, B)
2188 assert self.ref_has_change(d_zref, C)
2189 assert self.ref_has_change(d_zref, D)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002190
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002191 self.worker.hold_jobs_in_build = False
2192 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002193 self.waitUntilSettled()
2194
2195 assert A.data['status'] == 'MERGED'
2196 assert A.reported == 2
2197 assert B.data['status'] == 'MERGED'
2198 assert B.reported == 2
2199 assert C.data['status'] == 'MERGED'
2200 assert C.reported == 2
2201 assert D.data['status'] == 'MERGED'
2202 assert D.reported == 2
2203 self.assertEmptyQueues()
James E. Blair70c71582013-03-06 08:50:50 -08002204
James E. Blair412e5582013-04-22 15:50:12 -07002205 def test_statsd(self):
2206 "Test each of the statsd methods used in the scheduler"
2207 import extras
2208 statsd = extras.try_import('statsd.statsd')
2209 statsd.incr('test-incr')
2210 statsd.timing('test-timing', 3)
2211 statsd.gauge('test-guage', 12)
2212 self.assertReportedStat('test-incr', '1|c')
2213 self.assertReportedStat('test-timing', '3|ms')
2214 self.assertReportedStat('test-guage', '12|g')
2215
James E. Blair70c71582013-03-06 08:50:50 -08002216 def test_file_jobs(self):
2217 "Test that file jobs run only when appropriate"
2218 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2219 A.addPatchset(['pip-requires'])
2220 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2221 A.addApproval('CRVW', 2)
2222 B.addApproval('CRVW', 2)
2223 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2224 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2225 self.waitUntilSettled()
2226
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002227 testfile_jobs = [x for x in self.history
James E. Blair70c71582013-03-06 08:50:50 -08002228 if x.name == 'project-testfile']
2229
2230 assert len(testfile_jobs) == 1
2231 assert testfile_jobs[0].changes == '1,2'
2232 assert A.data['status'] == 'MERGED'
2233 assert A.reported == 2
2234 assert B.data['status'] == 'MERGED'
2235 assert B.reported == 2
2236 self.assertEmptyQueues()
James E. Blair3c5e5b52013-04-26 11:17:03 -07002237
2238 def test_test_config(self):
2239 "Test that we can test the config"
2240 sched = zuul.scheduler.Scheduler()
2241 sched.testConfig(CONFIG.get('zuul', 'layout_config'))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002242
2243 def test_build_description(self):
2244 "Test that build descriptions update"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002245 self.worker.registerFunction('set_description:' +
2246 self.worker.worker_id)
2247
2248 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2249 A.addApproval('CRVW', 2)
2250 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2251 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002252 desc = self.history[0].description
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002253 self.log.debug("Description: %s" % desc)
2254 assert re.search("Branch.*master", desc)
2255 assert re.search("Pipeline.*gate", desc)
2256 assert re.search("project-merge.*SUCCESS", desc)
2257 assert re.search("project-test1.*SUCCESS", desc)
2258 assert re.search("project-test2.*SUCCESS", desc)
2259 assert re.search("Reported result.*SUCCESS", desc)
2260
2261 def test_node_label(self):
2262 "Test that a job runs on a specific node label"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002263 self.worker.registerFunction('build:node-project-test1:debian')
2264
2265 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2266 A.addApproval('CRVW', 2)
2267 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2268 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07002269
2270 assert self.getJobFromHistory('node-project-merge').node is None
2271 assert self.getJobFromHistory('node-project-test1').node == 'debian'
2272 assert self.getJobFromHistory('node-project-test2').node is None