blob: 385fda76da2f8a20de11e388a8d3d642a54f837f [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
Clark Boylan4ba48d92013-11-11 18:03:53 -080019import gc
James E. Blair8cc15a82012-08-01 11:17:57 -070020import hashlib
James E. Blairb0fcae42012-07-17 11:12:10 -070021import json
Monty Taylorbc758832013-06-17 17:22:42 -040022import logging
23import os
James E. Blairb0fcae42012-07-17 11:12:10 -070024import pprint
Monty Taylorbc758832013-06-17 17:22:42 -040025import Queue
26import random
James E. Blairb0fcae42012-07-17 11:12:10 -070027import re
James E. Blair412e5582013-04-22 15:50:12 -070028import select
James E. Blair4886cc12012-07-18 15:39:41 -070029import shutil
James E. Blair412e5582013-04-22 15:50:12 -070030import socket
James E. Blair4886f282012-11-15 09:27:33 -080031import string
Monty Taylorbc758832013-06-17 17:22:42 -040032import subprocess
Monty Taylorbc758832013-06-17 17:22:42 -040033import threading
34import time
James E. Blair1843a552013-07-03 14:19:52 -070035import urllib
Monty Taylorbc758832013-06-17 17:22:42 -040036import urllib2
37import urlparse
38
James E. Blair4886cc12012-07-18 15:39:41 -070039import git
James E. Blair1f4c2bb2013-04-26 08:40:46 -070040import gear
Monty Taylorbc758832013-06-17 17:22:42 -040041import fixtures
42import statsd
43import testtools
James E. Blairb0fcae42012-07-17 11:12:10 -070044
James E. Blairb0fcae42012-07-17 11:12:10 -070045import zuul.scheduler
James E. Blair1843a552013-07-03 14:19:52 -070046import zuul.webapp
James E. Blair1f4c2bb2013-04-26 08:40:46 -070047import zuul.launcher.gearman
Joshua Hesketh1879cf72013-08-19 14:13:15 +100048import zuul.reporter.gerrit
Joshua Hesketh5fea8672013-08-19 17:32:01 +100049import zuul.reporter.smtp
James E. Blairb0fcae42012-07-17 11:12:10 -070050import zuul.trigger.gerrit
James E. Blair63bb0ef2013-07-29 17:14:51 -070051import zuul.trigger.timer
James E. Blairb0fcae42012-07-17 11:12:10 -070052
53FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
54 'fixtures')
55CONFIG = ConfigParser.ConfigParser()
56CONFIG.read(os.path.join(FIXTURE_DIR, "zuul.conf"))
57
58CONFIG.set('zuul', 'layout_config',
59 os.path.join(FIXTURE_DIR, "layout.yaml"))
60
James E. Blair1f4c2bb2013-04-26 08:40:46 -070061logging.basicConfig(level=logging.DEBUG,
62 format='%(asctime)s %(name)-32s '
63 '%(levelname)-8s %(message)s')
James E. Blairb0fcae42012-07-17 11:12:10 -070064
65
Monty Taylorbc758832013-06-17 17:22:42 -040066def repack_repo(path):
67 output = subprocess.Popen(
68 ['git', '--git-dir=%s/.git' % path, 'repack', '-afd'],
69 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
70 out = output.communicate()
71 if output.returncode:
72 raise Exception("git repack returned %d" % output.returncode)
73 return out
74
75
James E. Blair8cc15a82012-08-01 11:17:57 -070076def random_sha1():
77 return hashlib.sha1(str(random.random())).hexdigest()
78
79
James E. Blair4886cc12012-07-18 15:39:41 -070080class ChangeReference(git.Reference):
81 _common_path_default = "refs/changes"
82 _points_to_commits_only = True
83
84
James E. Blairb0fcae42012-07-17 11:12:10 -070085class FakeChange(object):
James E. Blair8c803f82012-07-31 16:25:42 -070086 categories = {'APRV': ('Approved', -1, 1),
87 'CRVW': ('Code-Review', -2, 2),
88 'VRFY': ('Verified', -2, 2)}
James E. Blairb0fcae42012-07-17 11:12:10 -070089
Monty Taylorbc758832013-06-17 17:22:42 -040090 def __init__(self, gerrit, number, project, branch, subject,
91 status='NEW', upstream_root=None):
James E. Blair8cc15a82012-08-01 11:17:57 -070092 self.gerrit = gerrit
James E. Blaird466dc42012-07-31 10:42:56 -070093 self.reported = 0
James E. Blair8c803f82012-07-31 16:25:42 -070094 self.queried = 0
James E. Blairb0fcae42012-07-17 11:12:10 -070095 self.patchsets = []
James E. Blairb0fcae42012-07-17 11:12:10 -070096 self.number = number
97 self.project = project
98 self.branch = branch
99 self.subject = subject
100 self.latest_patchset = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700101 self.depends_on_change = None
102 self.needed_by_changes = []
James E. Blair127bc182012-08-28 15:55:15 -0700103 self.fail_merge = False
James E. Blair42f74822013-05-14 15:18:03 -0700104 self.messages = []
James E. Blairb0fcae42012-07-17 11:12:10 -0700105 self.data = {
106 'branch': branch,
107 'comments': [],
108 'commitMessage': subject,
109 'createdOn': time.time(),
James E. Blair8cc15a82012-08-01 11:17:57 -0700110 'id': 'I' + random_sha1(),
James E. Blairb0fcae42012-07-17 11:12:10 -0700111 'lastUpdated': time.time(),
112 'number': str(number),
113 'open': True,
114 'owner': {'email': 'user@example.com',
115 'name': 'User Name',
116 'username': 'username'},
117 'patchSets': self.patchsets,
118 'project': project,
119 'status': status,
120 'subject': subject,
James E. Blair8c803f82012-07-31 16:25:42 -0700121 'submitRecords': [],
James E. Blairb0fcae42012-07-17 11:12:10 -0700122 'url': 'https://hostname/%s' % number}
123
Monty Taylorbc758832013-06-17 17:22:42 -0400124 self.upstream_root = upstream_root
James E. Blairb0fcae42012-07-17 11:12:10 -0700125 self.addPatchset()
James E. Blair8c803f82012-07-31 16:25:42 -0700126 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700127
Monty Taylorbc758832013-06-17 17:22:42 -0400128 def add_fake_change_to_repo(self, msg, fn, large):
129 path = os.path.join(self.upstream_root, self.project)
130 repo = git.Repo(path)
131 ref = ChangeReference.create(repo, '1/%s/%s' % (self.number,
132 self.latest_patchset),
133 'refs/tags/init')
134 repo.head.reference = ref
135 repo.head.reset(index=True, working_tree=True)
136 repo.git.clean('-x', '-f', '-d')
137
138 path = os.path.join(self.upstream_root, self.project)
139 if not large:
140 fn = os.path.join(path, fn)
141 f = open(fn, 'w')
142 f.write("test %s %s %s\n" %
143 (self.branch, self.number, self.latest_patchset))
144 f.close()
145 repo.index.add([fn])
146 else:
147 for fni in range(100):
148 fn = os.path.join(path, str(fni))
149 f = open(fn, 'w')
150 for ci in range(4096):
151 f.write(random.choice(string.printable))
152 f.close()
153 repo.index.add([fn])
154
James E. Blair287c06d2013-07-24 10:39:30 -0700155 r = repo.index.commit(msg)
156 repo.head.reference = 'master'
157 repo.head.reset(index=True, working_tree=True)
158 repo.git.clean('-x', '-f', '-d')
159 return r
Monty Taylorbc758832013-06-17 17:22:42 -0400160
James E. Blair70c71582013-03-06 08:50:50 -0800161 def addPatchset(self, files=[], large=False):
James E. Blairb0fcae42012-07-17 11:12:10 -0700162 self.latest_patchset += 1
James E. Blairdaabed22012-08-15 15:38:57 -0700163 if files:
164 fn = files[0]
165 else:
166 fn = '%s-%s' % (self.branch, self.number)
167 msg = self.subject + '-' + str(self.latest_patchset)
Monty Taylorbc758832013-06-17 17:22:42 -0400168 c = self.add_fake_change_to_repo(msg, fn, large)
James E. Blair70c71582013-03-06 08:50:50 -0800169 ps_files = [{'file': '/COMMIT_MSG',
170 'type': 'ADDED'},
171 {'file': 'README',
172 'type': 'MODIFIED'}]
173 for f in files:
174 ps_files.append({'file': f, 'type': 'ADDED'})
James E. Blairb0fcae42012-07-17 11:12:10 -0700175 d = {'approvals': [],
176 'createdOn': time.time(),
James E. Blair70c71582013-03-06 08:50:50 -0800177 'files': ps_files,
James E. Blair8c803f82012-07-31 16:25:42 -0700178 'number': str(self.latest_patchset),
James E. Blairb0fcae42012-07-17 11:12:10 -0700179 'ref': 'refs/changes/1/%s/%s' % (self.number,
180 self.latest_patchset),
James E. Blairdaabed22012-08-15 15:38:57 -0700181 'revision': c.hexsha,
James E. Blairb0fcae42012-07-17 11:12:10 -0700182 'uploader': {'email': 'user@example.com',
183 'name': 'User name',
184 'username': 'user'}}
185 self.data['currentPatchSet'] = d
186 self.patchsets.append(d)
James E. Blair8c803f82012-07-31 16:25:42 -0700187 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700188
James E. Blaire0487072012-08-29 17:38:31 -0700189 def getPatchsetCreatedEvent(self, patchset):
190 event = {"type": "patchset-created",
191 "change": {"project": self.project,
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800192 "branch": self.branch,
193 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
194 "number": str(self.number),
195 "subject": self.subject,
196 "owner": {"name": "User Name"},
197 "url": "https://hostname/3"},
James E. Blaire0487072012-08-29 17:38:31 -0700198 "patchSet": self.patchsets[patchset - 1],
199 "uploader": {"name": "User Name"}}
200 return event
201
James E. Blair42f74822013-05-14 15:18:03 -0700202 def getChangeRestoredEvent(self):
203 event = {"type": "change-restored",
204 "change": {"project": self.project,
205 "branch": self.branch,
206 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
207 "number": str(self.number),
208 "subject": self.subject,
209 "owner": {"name": "User Name"},
210 "url": "https://hostname/3"},
211 "restorer": {"name": "User Name"},
212 "reason": ""}
213 return event
214
James E. Blairb0fcae42012-07-17 11:12:10 -0700215 def addApproval(self, category, value):
James E. Blair8c803f82012-07-31 16:25:42 -0700216 approval = {'description': self.categories[category][0],
217 'type': category,
218 'value': str(value)}
219 self.patchsets[-1]['approvals'].append(approval)
220 event = {'approvals': [approval],
James E. Blairb0fcae42012-07-17 11:12:10 -0700221 'author': {'email': 'user@example.com',
222 'name': 'User Name',
223 'username': 'username'},
224 'change': {'branch': self.branch,
225 'id': 'Iaa69c46accf97d0598111724a38250ae76a22c87',
226 'number': str(self.number),
227 'owner': {'email': 'user@example.com',
228 'name': 'User Name',
229 'username': 'username'},
230 'project': self.project,
231 'subject': self.subject,
232 'topic': 'master',
233 'url': 'https://hostname/459'},
234 'comment': '',
235 'patchSet': self.patchsets[-1],
236 'type': 'comment-added'}
James E. Blair8c803f82012-07-31 16:25:42 -0700237 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700238 return json.loads(json.dumps(event))
239
James E. Blair8c803f82012-07-31 16:25:42 -0700240 def getSubmitRecords(self):
241 status = {}
242 for cat in self.categories.keys():
243 status[cat] = 0
244
245 for a in self.patchsets[-1]['approvals']:
246 cur = status[a['type']]
247 cat_min, cat_max = self.categories[a['type']][1:]
248 new = int(a['value'])
249 if new == cat_min:
250 cur = new
251 elif abs(new) > abs(cur):
252 cur = new
253 status[a['type']] = cur
254
255 labels = []
256 ok = True
257 for typ, cat in self.categories.items():
258 cur = status[typ]
259 cat_min, cat_max = cat[1:]
260 if cur == cat_min:
261 value = 'REJECT'
262 ok = False
263 elif cur == cat_max:
264 value = 'OK'
265 else:
266 value = 'NEED'
267 ok = False
268 labels.append({'label': cat[0], 'status': value})
269 if ok:
270 return [{'status': 'OK'}]
271 return [{'status': 'NOT_READY',
272 'labels': labels}]
273
274 def setDependsOn(self, other, patchset):
275 self.depends_on_change = other
276 d = {'id': other.data['id'],
277 'number': other.data['number'],
278 'ref': other.patchsets[patchset - 1]['ref']
279 }
280 self.data['dependsOn'] = [d]
281
282 other.needed_by_changes.append(self)
283 needed = other.data.get('neededBy', [])
284 d = {'id': self.data['id'],
285 'number': self.data['number'],
286 'ref': self.patchsets[patchset - 1]['ref'],
287 'revision': self.patchsets[patchset - 1]['revision']
288 }
289 needed.append(d)
290 other.data['neededBy'] = needed
291
James E. Blairb0fcae42012-07-17 11:12:10 -0700292 def query(self):
James E. Blair8c803f82012-07-31 16:25:42 -0700293 self.queried += 1
294 d = self.data.get('dependsOn')
295 if d:
296 d = d[0]
297 if (self.depends_on_change.patchsets[-1]['ref'] == d['ref']):
298 d['isCurrentPatchSet'] = True
299 else:
300 d['isCurrentPatchSet'] = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700301 return json.loads(json.dumps(self.data))
302
303 def setMerged(self):
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800304 if (self.depends_on_change and
305 self.depends_on_change.data['status'] != 'MERGED'):
James E. Blaircaec0c52012-08-22 14:52:22 -0700306 return
James E. Blair127bc182012-08-28 15:55:15 -0700307 if self.fail_merge:
308 return
James E. Blairb0fcae42012-07-17 11:12:10 -0700309 self.data['status'] = 'MERGED'
310 self.open = False
James E. Blairdaabed22012-08-15 15:38:57 -0700311
Monty Taylorbc758832013-06-17 17:22:42 -0400312 path = os.path.join(self.upstream_root, self.project)
James E. Blairdaabed22012-08-15 15:38:57 -0700313 repo = git.Repo(path)
314 repo.heads[self.branch].commit = \
315 repo.commit(self.patchsets[-1]['revision'])
James E. Blairb0fcae42012-07-17 11:12:10 -0700316
James E. Blaird466dc42012-07-31 10:42:56 -0700317 def setReported(self):
318 self.reported += 1
319
James E. Blairb0fcae42012-07-17 11:12:10 -0700320
321class FakeGerrit(object):
322 def __init__(self, *args, **kw):
323 self.event_queue = Queue.Queue()
324 self.fixture_dir = os.path.join(FIXTURE_DIR, 'gerrit')
325 self.change_number = 0
326 self.changes = {}
327
328 def addFakeChange(self, project, branch, subject):
329 self.change_number += 1
Monty Taylorbc758832013-06-17 17:22:42 -0400330 c = FakeChange(self, self.change_number, project, branch, subject,
331 upstream_root=self.upstream_root)
James E. Blairb0fcae42012-07-17 11:12:10 -0700332 self.changes[self.change_number] = c
333 return c
334
335 def addEvent(self, data):
336 return self.event_queue.put(data)
337
338 def getEvent(self):
339 return self.event_queue.get()
340
341 def eventDone(self):
342 self.event_queue.task_done()
343
344 def review(self, project, changeid, message, action):
James E. Blaird466dc42012-07-31 10:42:56 -0700345 number, ps = changeid.split(',')
346 change = self.changes[int(number)]
James E. Blair42f74822013-05-14 15:18:03 -0700347 change.messages.append(message)
James E. Blairb0fcae42012-07-17 11:12:10 -0700348 if 'submit' in action:
James E. Blairb0fcae42012-07-17 11:12:10 -0700349 change.setMerged()
James E. Blaird466dc42012-07-31 10:42:56 -0700350 if message:
351 change.setReported()
James E. Blairb0fcae42012-07-17 11:12:10 -0700352
353 def query(self, number):
354 change = self.changes[int(number)]
355 return change.query()
356
357 def startWatching(self, *args, **kw):
358 pass
359
360
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700361class BuildHistory(object):
362 def __init__(self, **kw):
363 self.__dict__.update(kw)
James E. Blairb0fcae42012-07-17 11:12:10 -0700364
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700365 def __repr__(self):
366 return ("<Completed build, result: %s name: %s #%s changes: %s>" %
367 (self.result, self.name, self.number, self.changes))
James E. Blairb0fcae42012-07-17 11:12:10 -0700368
369
James E. Blair8cc15a82012-08-01 11:17:57 -0700370class FakeURLOpener(object):
Monty Taylorbc758832013-06-17 17:22:42 -0400371 def __init__(self, upstream_root, fake_gerrit, url):
372 self.upstream_root = upstream_root
James E. Blair8cc15a82012-08-01 11:17:57 -0700373 self.fake_gerrit = fake_gerrit
374 self.url = url
375
376 def read(self):
377 res = urlparse.urlparse(self.url)
378 path = res.path
379 project = '/'.join(path.split('/')[2:-2])
James E. Blair35956c52012-09-17 22:13:36 +0200380 ret = '001e# service=git-upload-pack\n'
381 ret += ('000000a31270149696713ba7e06f1beb760f20d359c4abed HEAD\x00'
382 'multi_ack thin-pack side-band side-band-64k ofs-delta '
383 'shallow no-progress include-tag multi_ack_detailed no-done\n')
Monty Taylorbc758832013-06-17 17:22:42 -0400384 path = os.path.join(self.upstream_root, project)
James E. Blairdaabed22012-08-15 15:38:57 -0700385 repo = git.Repo(path)
386 for ref in repo.refs:
James E. Blair35956c52012-09-17 22:13:36 +0200387 r = ref.object.hexsha + ' ' + ref.path + '\n'
388 ret += '%04x%s' % (len(r) + 4, r)
389 ret += '0000'
James E. Blair8cc15a82012-08-01 11:17:57 -0700390 return ret
391
392
James E. Blair4886cc12012-07-18 15:39:41 -0700393class FakeGerritTrigger(zuul.trigger.gerrit.Gerrit):
Joshua Hesketh1879cf72013-08-19 14:13:15 +1000394 name = 'gerrit'
395
Monty Taylorbc758832013-06-17 17:22:42 -0400396 def __init__(self, upstream_root, *args):
397 super(FakeGerritTrigger, self).__init__(*args)
398 self.upstream_root = upstream_root
399
James E. Blair4886cc12012-07-18 15:39:41 -0700400 def getGitUrl(self, project):
Monty Taylorbc758832013-06-17 17:22:42 -0400401 return os.path.join(self.upstream_root, project.name)
James E. Blair4886cc12012-07-18 15:39:41 -0700402
403
James E. Blair412e5582013-04-22 15:50:12 -0700404class FakeStatsd(threading.Thread):
405 def __init__(self):
406 threading.Thread.__init__(self)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400407 self.daemon = True
James E. Blair412e5582013-04-22 15:50:12 -0700408 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
409 self.sock.bind(('', 0))
410 self.port = self.sock.getsockname()[1]
411 self.wake_read, self.wake_write = os.pipe()
412 self.stats = []
413
414 def run(self):
415 while True:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700416 poll = select.poll()
417 poll.register(self.sock, select.POLLIN)
418 poll.register(self.wake_read, select.POLLIN)
419 ret = poll.poll()
420 for (fd, event) in ret:
421 if fd == self.sock.fileno():
James E. Blair412e5582013-04-22 15:50:12 -0700422 data = self.sock.recvfrom(1024)
423 if not data:
424 return
425 self.stats.append(data[0])
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700426 if fd == self.wake_read:
James E. Blair412e5582013-04-22 15:50:12 -0700427 return
428
429 def stop(self):
430 os.write(self.wake_write, '1\n')
431
432
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700433class FakeBuild(threading.Thread):
434 log = logging.getLogger("zuul.test")
435
436 def __init__(self, worker, job, number, node):
437 threading.Thread.__init__(self)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400438 self.daemon = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700439 self.worker = worker
440 self.job = job
441 self.name = job.name.split(':')[1]
442 self.number = number
443 self.node = node
444 self.parameters = json.loads(job.arguments)
445 self.unique = self.parameters['ZUUL_UUID']
446 self.wait_condition = threading.Condition()
447 self.waiting = False
448 self.aborted = False
449 self.created = time.time()
450 self.description = ''
James E. Blair4a28a882013-08-23 15:17:33 -0700451 self.run_error = False
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700452
453 def release(self):
454 self.wait_condition.acquire()
455 self.wait_condition.notify()
456 self.waiting = False
457 self.log.debug("Build %s released" % self.unique)
458 self.wait_condition.release()
459
460 def isWaiting(self):
461 self.wait_condition.acquire()
462 if self.waiting:
463 ret = True
464 else:
465 ret = False
466 self.wait_condition.release()
467 return ret
468
469 def _wait(self):
470 self.wait_condition.acquire()
471 self.waiting = True
472 self.log.debug("Build %s waiting" % self.unique)
473 self.wait_condition.wait()
474 self.wait_condition.release()
475
476 def run(self):
477 data = {
James E. Blair3c483cf2013-06-04 16:30:43 -0700478 'url': 'https://server/job/%s/%s/' % (self.name, self.number),
479 'name': self.name,
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700480 'number': self.number,
James E. Blair3c483cf2013-06-04 16:30:43 -0700481 'manager': self.worker.worker_id,
Paul Belangerec49b4c2013-07-20 20:32:20 -0400482 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700483
484 self.job.sendWorkData(json.dumps(data))
485 self.job.sendWorkStatus(0, 100)
486
487 if self.worker.hold_jobs_in_build:
488 self._wait()
489 self.log.debug("Build %s continuing" % self.unique)
490
491 self.worker.lock.acquire()
492
493 result = 'SUCCESS'
494 if (('ZUUL_REF' in self.parameters) and
495 self.worker.shouldFailTest(self.name,
496 self.parameters['ZUUL_REF'])):
497 result = 'FAILURE'
498 if self.aborted:
499 result = 'ABORTED'
500
James E. Blair4a28a882013-08-23 15:17:33 -0700501 if self.run_error:
502 work_fail = True
503 result = 'RUN_ERROR'
504 else:
505 data['result'] = result
506 work_fail = False
507
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700508 changes = None
509 if 'ZUUL_CHANGE_IDS' in self.parameters:
510 changes = self.parameters['ZUUL_CHANGE_IDS']
511
512 self.worker.build_history.append(
513 BuildHistory(name=self.name, number=self.number,
514 result=result, changes=changes, node=self.node,
James E. Blair64ed6f22013-07-10 14:07:23 -0700515 uuid=self.unique, description=self.description,
516 pipeline=self.parameters['ZUUL_PIPELINE'])
Paul Belangerec49b4c2013-07-20 20:32:20 -0400517 )
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700518
James E. Blair4a28a882013-08-23 15:17:33 -0700519 self.job.sendWorkData(json.dumps(data))
520 if work_fail:
521 self.job.sendWorkFail()
522 else:
523 self.job.sendWorkComplete(json.dumps(data))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700524 del self.worker.gearman_jobs[self.job.unique]
525 self.worker.running_builds.remove(self)
526 self.worker.lock.release()
527
528
529class FakeWorker(gear.Worker):
Monty Taylorbc758832013-06-17 17:22:42 -0400530 def __init__(self, worker_id, test):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700531 super(FakeWorker, self).__init__(worker_id)
532 self.gearman_jobs = {}
533 self.build_history = []
534 self.running_builds = []
535 self.build_counter = 0
536 self.fail_tests = {}
Monty Taylorbc758832013-06-17 17:22:42 -0400537 self.test = test
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700538
539 self.hold_jobs_in_build = False
540 self.lock = threading.Lock()
541 self.__work_thread = threading.Thread(target=self.work)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400542 self.__work_thread.daemon = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700543 self.__work_thread.start()
544
545 def handleJob(self, job):
546 parts = job.name.split(":")
547 cmd = parts[0]
548 name = parts[1]
549 if len(parts) > 2:
550 node = parts[2]
551 else:
552 node = None
553 if cmd == 'build':
554 self.handleBuild(job, name, node)
555 elif cmd == 'stop':
556 self.handleStop(job, name)
557 elif cmd == 'set_description':
558 self.handleSetDescription(job, name)
559
560 def handleBuild(self, job, name, node):
561 build = FakeBuild(self, job, self.build_counter, node)
562 job.build = build
563 self.gearman_jobs[job.unique] = job
564 self.build_counter += 1
565
566 self.running_builds.append(build)
567 build.start()
568
569 def handleStop(self, job, name):
570 self.log.debug("handle stop")
James E. Blair3c483cf2013-06-04 16:30:43 -0700571 parameters = json.loads(job.arguments)
572 name = parameters['name']
573 number = parameters['number']
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700574 for build in self.running_builds:
James E. Blair3c483cf2013-06-04 16:30:43 -0700575 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700576 build.aborted = True
577 build.release()
578 job.sendWorkComplete()
579 return
580 job.sendWorkFail()
581
582 def handleSetDescription(self, job, name):
583 self.log.debug("handle set description")
584 parameters = json.loads(job.arguments)
James E. Blair3c483cf2013-06-04 16:30:43 -0700585 name = parameters['name']
586 number = parameters['number']
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700587 descr = parameters['html_description']
588 for build in self.running_builds:
James E. Blair3c483cf2013-06-04 16:30:43 -0700589 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700590 build.description = descr
591 job.sendWorkComplete()
592 return
593 for build in self.build_history:
James E. Blair3c483cf2013-06-04 16:30:43 -0700594 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700595 build.description = descr
596 job.sendWorkComplete()
597 return
598 job.sendWorkFail()
599
600 def work(self):
601 while self.running:
602 try:
603 job = self.getJob()
604 except gear.InterruptedError:
605 continue
606 try:
607 self.handleJob(job)
608 except:
609 self.log.exception("Worker exception:")
610
611 def addFailTest(self, name, change):
612 l = self.fail_tests.get(name, [])
613 l.append(change)
614 self.fail_tests[name] = l
615
616 def shouldFailTest(self, name, ref):
617 l = self.fail_tests.get(name, [])
618 for change in l:
Monty Taylorbc758832013-06-17 17:22:42 -0400619 if self.test.ref_has_change(ref, change):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700620 return True
621 return False
622
623 def release(self, regex=None):
624 builds = self.running_builds[:]
625 self.log.debug("releasing build %s (%s)" % (regex,
James E. Blair78e31b32013-07-09 09:11:34 -0700626 len(self.running_builds)))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700627 for build in builds:
628 if not regex or re.match(regex, build.name):
629 self.log.debug("releasing build %s" %
630 (build.parameters['ZUUL_UUID']))
631 build.release()
632 else:
633 self.log.debug("not releasing build %s" %
634 (build.parameters['ZUUL_UUID']))
635 self.log.debug("done releasing builds %s (%s)" %
636 (regex, len(self.running_builds)))
637
638
639class FakeGearmanServer(gear.Server):
640 def __init__(self):
641 self.hold_jobs_in_queue = False
642 super(FakeGearmanServer, self).__init__(0)
643
644 def getJobForConnection(self, connection, peek=False):
James E. Blair701c5b42013-06-06 09:34:59 -0700645 for queue in [self.high_queue, self.normal_queue, self.low_queue]:
646 for job in queue:
647 if not hasattr(job, 'waiting'):
648 if job.name.startswith('build:'):
649 job.waiting = self.hold_jobs_in_queue
650 else:
651 job.waiting = False
652 if job.waiting:
653 continue
654 if job.name in connection.functions:
655 if not peek:
656 queue.remove(job)
James E. Blaire2819012013-06-28 17:17:26 -0400657 connection.related_jobs[job.handle] = job
658 job.worker_connection = connection
659 job.running = True
James E. Blair701c5b42013-06-06 09:34:59 -0700660 return job
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700661 return None
662
663 def release(self, regex=None):
664 released = False
James E. Blair701c5b42013-06-06 09:34:59 -0700665 qlen = (len(self.high_queue) + len(self.normal_queue) +
666 len(self.low_queue))
667 self.log.debug("releasing queued job %s (%s)" % (regex, qlen))
James E. Blairdda6c912013-07-29 14:12:12 -0700668 for job in self.getQueue():
669 cmd, name = job.name.split(':')
670 if cmd != 'build':
671 continue
672 if not regex or re.match(regex, name):
673 self.log.debug("releasing queued job %s" %
674 job.unique)
675 job.waiting = False
676 released = True
677 else:
678 self.log.debug("not releasing queued job %s" %
679 job.unique)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700680 if released:
681 self.wakeConnections()
James E. Blair701c5b42013-06-06 09:34:59 -0700682 qlen = (len(self.high_queue) + len(self.normal_queue) +
683 len(self.low_queue))
684 self.log.debug("done releasing queued jobs %s (%s)" % (regex, qlen))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700685
686
Joshua Hesketh5fea8672013-08-19 17:32:01 +1000687class FakeSMTP(object):
688 log = logging.getLogger('zuul.FakeSMTP')
689 messages = []
690
691 def __init__(self, server, port):
692 self.server = server
693 self.port = port
694
695 def sendmail(self, from_email, to_email, msg):
696 self.log.info("Sending email from %s, to %s, with msg %s" % (
697 from_email, to_email, msg))
698
699 headers = msg.split('\n\n', 1)[0]
700 body = msg.split('\n\n', 1)[1]
701
702 FakeSMTP.messages.append(dict(
703 from_email=from_email,
704 to_email=to_email,
705 msg=msg,
706 headers=headers,
707 body=body,
708 ))
709
710 return True
711
712 def quit(self):
713 return True
714
715
Monty Taylorbc758832013-06-17 17:22:42 -0400716class TestScheduler(testtools.TestCase):
James E. Blairb0fcae42012-07-17 11:12:10 -0700717 log = logging.getLogger("zuul.test")
718
719 def setUp(self):
Monty Taylorbc758832013-06-17 17:22:42 -0400720 super(TestScheduler, self).setUp()
721 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
722 try:
723 test_timeout = int(test_timeout)
724 except ValueError:
725 # If timeout value is invalid do not set a timeout.
726 test_timeout = 0
727 if test_timeout > 0:
728 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
729
730 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
731 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
732 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
733 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
734 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
735 os.environ.get('OS_STDERR_CAPTURE') == '1'):
736 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
737 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Monty Taylore6a6c402013-07-02 09:25:55 -0700738 if (os.environ.get('OS_LOG_CAPTURE') == 'True' or
739 os.environ.get('OS_LOG_CAPTURE') == '1'):
James E. Blaire2819012013-06-28 17:17:26 -0400740 self.useFixture(fixtures.FakeLogger(
741 level=logging.DEBUG,
742 format='%(asctime)s %(name)-32s '
743 '%(levelname)-8s %(message)s'))
Monty Taylor5a5a95c2013-07-03 13:39:14 -0700744 tmp_root = self.useFixture(fixtures.TempDir(
745 rootdir=os.environ.get("ZUUL_TEST_ROOT"))).path
Monty Taylorbc758832013-06-17 17:22:42 -0400746 self.test_root = os.path.join(tmp_root, "zuul-test")
747 self.upstream_root = os.path.join(self.test_root, "upstream")
748 self.git_root = os.path.join(self.test_root, "git")
749
750 CONFIG.set('zuul', 'git_dir', self.git_root)
751 if os.path.exists(self.test_root):
752 shutil.rmtree(self.test_root)
753 os.makedirs(self.test_root)
754 os.makedirs(self.upstream_root)
755 os.makedirs(self.git_root)
James E. Blair4886cc12012-07-18 15:39:41 -0700756
757 # For each project in config:
Monty Taylorbc758832013-06-17 17:22:42 -0400758 self.init_repo("org/project")
759 self.init_repo("org/project1")
760 self.init_repo("org/project2")
761 self.init_repo("org/project3")
762 self.init_repo("org/one-job-project")
763 self.init_repo("org/nonvoting-project")
764 self.init_repo("org/templated-project")
765 self.init_repo("org/node-project")
James E. Blair6736beb2013-07-11 15:18:15 -0700766 self.init_repo("org/conflict-project")
James E. Blair412e5582013-04-22 15:50:12 -0700767
768 self.statsd = FakeStatsd()
769 os.environ['STATSD_HOST'] = 'localhost'
770 os.environ['STATSD_PORT'] = str(self.statsd.port)
771 self.statsd.start()
772 # the statsd client object is configured in the statsd module import
773 reload(statsd)
774 reload(zuul.scheduler)
775
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700776 self.gearman_server = FakeGearmanServer()
777
778 self.config = ConfigParser.ConfigParser()
779 cfg = StringIO()
780 CONFIG.write(cfg)
781 cfg.seek(0)
782 self.config.readfp(cfg)
783 self.config.set('gearman', 'port', str(self.gearman_server.port))
784
Monty Taylorbc758832013-06-17 17:22:42 -0400785 self.worker = FakeWorker('fake_worker', self)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700786 self.worker.addServer('127.0.0.1', self.gearman_server.port)
787 self.gearman_server.worker = self.worker
788
James E. Blairb0fcae42012-07-17 11:12:10 -0700789 self.sched = zuul.scheduler.Scheduler()
790
James E. Blair8cc15a82012-08-01 11:17:57 -0700791 def URLOpenerFactory(*args, **kw):
792 args = [self.fake_gerrit] + list(args)
Monty Taylorbc758832013-06-17 17:22:42 -0400793 return FakeURLOpener(self.upstream_root, *args, **kw)
James E. Blair8cc15a82012-08-01 11:17:57 -0700794
James E. Blair8cc15a82012-08-01 11:17:57 -0700795 urllib2.urlopen = URLOpenerFactory
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700796 self.launcher = zuul.launcher.gearman.Gearman(self.config, self.sched)
James E. Blairb0fcae42012-07-17 11:12:10 -0700797
798 zuul.lib.gerrit.Gerrit = FakeGerrit
Joshua Hesketh5fea8672013-08-19 17:32:01 +1000799 self.useFixture(fixtures.MonkeyPatch('smtplib.SMTP', FakeSMTP))
James E. Blairb0fcae42012-07-17 11:12:10 -0700800
Monty Taylorbc758832013-06-17 17:22:42 -0400801 self.gerrit = FakeGerritTrigger(
802 self.upstream_root, self.config, self.sched)
James E. Blair8cc15a82012-08-01 11:17:57 -0700803 self.gerrit.replication_timeout = 1.5
804 self.gerrit.replication_retry_interval = 0.5
James E. Blairb0fcae42012-07-17 11:12:10 -0700805 self.fake_gerrit = self.gerrit.gerrit
Monty Taylorbc758832013-06-17 17:22:42 -0400806 self.fake_gerrit.upstream_root = self.upstream_root
James E. Blairb0fcae42012-07-17 11:12:10 -0700807
James E. Blair1843a552013-07-03 14:19:52 -0700808 self.webapp = zuul.webapp.WebApp(self.sched, port=0)
809
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700810 self.sched.setLauncher(self.launcher)
James E. Blair6c358e72013-07-29 17:06:47 -0700811 self.sched.registerTrigger(self.gerrit)
James E. Blair63bb0ef2013-07-29 17:14:51 -0700812 self.timer = zuul.trigger.timer.Timer(self.config, self.sched)
813 self.sched.registerTrigger(self.timer)
James E. Blairb0fcae42012-07-17 11:12:10 -0700814
Joshua Hesketh1879cf72013-08-19 14:13:15 +1000815 self.sched.registerReporter(
816 zuul.reporter.gerrit.Reporter(self.gerrit))
Joshua Hesketh5fea8672013-08-19 17:32:01 +1000817 self.smtp_reporter = zuul.reporter.smtp.Reporter(
818 self.config.get('smtp', 'default_from'),
819 self.config.get('smtp', 'default_to'),
820 self.config.get('smtp', 'server'))
821 self.sched.registerReporter(self.smtp_reporter)
Joshua Hesketh1879cf72013-08-19 14:13:15 +1000822
James E. Blairb0fcae42012-07-17 11:12:10 -0700823 self.sched.start()
824 self.sched.reconfigure(self.config)
825 self.sched.resume()
James E. Blair1843a552013-07-03 14:19:52 -0700826 self.webapp.start()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700827 self.launcher.gearman.waitForServer()
828 self.registerJobs()
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400829 self.builds = self.worker.running_builds
830 self.history = self.worker.build_history
James E. Blairb0fcae42012-07-17 11:12:10 -0700831
James E. Blairfee8d652013-06-07 08:57:52 -0700832 self.addCleanup(self.assertFinalState)
833 self.addCleanup(self.shutdown)
834
835 def assertFinalState(self):
836 # Make sure that the change cache is cleared
James E. Blair6c358e72013-07-29 17:06:47 -0700837 self.assertEqual(len(self.gerrit._change_cache.keys()), 0)
Clark Boylan4ba48d92013-11-11 18:03:53 -0800838 # Make sure that git.Repo objects have been garbage collected.
839 repos = []
840 gc.collect()
841 for obj in gc.get_objects():
842 if isinstance(obj, git.Repo):
843 repos.append(obj)
844 self.assertEqual(len(repos), 0)
James E. Blairfee8d652013-06-07 08:57:52 -0700845 self.assertEmptyQueues()
846
847 def shutdown(self):
848 self.log.debug("Shutting down after tests")
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700849 self.launcher.stop()
850 self.worker.shutdown()
851 self.gearman_server.shutdown()
James E. Blairb0fcae42012-07-17 11:12:10 -0700852 self.gerrit.stop()
James E. Blair63bb0ef2013-07-29 17:14:51 -0700853 self.timer.stop()
James E. Blairb0fcae42012-07-17 11:12:10 -0700854 self.sched.stop()
855 self.sched.join()
James E. Blair412e5582013-04-22 15:50:12 -0700856 self.statsd.stop()
857 self.statsd.join()
James E. Blair1843a552013-07-03 14:19:52 -0700858 self.webapp.stop()
859 self.webapp.join()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700860 threads = threading.enumerate()
861 if len(threads) > 1:
862 self.log.error("More than one thread is running: %s" % threads)
Monty Taylorbc758832013-06-17 17:22:42 -0400863 super(TestScheduler, self).tearDown()
864
865 def init_repo(self, project):
866 parts = project.split('/')
867 path = os.path.join(self.upstream_root, *parts[:-1])
868 if not os.path.exists(path):
869 os.makedirs(path)
870 path = os.path.join(self.upstream_root, project)
871 repo = git.Repo.init(path)
872
873 repo.config_writer().set_value('user', 'email', 'user@example.com')
874 repo.config_writer().set_value('user', 'name', 'User Name')
875 repo.config_writer().write()
876
877 fn = os.path.join(path, 'README')
878 f = open(fn, 'w')
879 f.write("test\n")
880 f.close()
881 repo.index.add([fn])
882 repo.index.commit('initial commit')
883 master = repo.create_head('master')
884 repo.create_tag('init')
885
886 mp = repo.create_head('mp')
887 repo.head.reference = mp
888 f = open(fn, 'a')
889 f.write("test mp\n")
890 f.close()
891 repo.index.add([fn])
892 repo.index.commit('mp commit')
893
894 repo.head.reference = master
895 repo.head.reset(index=True, working_tree=True)
896 repo.git.clean('-x', '-f', '-d')
897
898 def ref_has_change(self, ref, change):
899 path = os.path.join(self.git_root, change.project)
900 repo = git.Repo(path)
901 for commit in repo.iter_commits(ref):
902 if commit.message.strip() == ('%s-1' % change.subject):
903 return True
904 return False
905
906 def job_has_changes(self, *args):
907 job = args[0]
908 commits = args[1:]
909 if isinstance(job, FakeBuild):
910 parameters = job.parameters
911 else:
912 parameters = json.loads(job.arguments)
913 project = parameters['ZUUL_PROJECT']
914 path = os.path.join(self.git_root, project)
915 repo = git.Repo(path)
916 ref = parameters['ZUUL_REF']
917 sha = parameters['ZUUL_COMMIT']
918 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
919 repo_shas = [c.hexsha for c in repo.iter_commits(ref)]
920 commit_messages = ['%s-1' % commit.subject for commit in commits]
921 for msg in commit_messages:
922 if msg not in repo_messages:
923 return False
924 if repo_shas[0] != sha:
925 return False
926 return True
James E. Blairb0fcae42012-07-17 11:12:10 -0700927
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700928 def registerJobs(self):
929 count = 0
James E. Blaireff88162013-07-01 12:44:14 -0400930 for job in self.sched.layout.jobs.keys():
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700931 self.worker.registerFunction('build:' + job)
932 count += 1
933 self.worker.registerFunction('stop:' + self.worker.worker_id)
934 count += 1
935
936 while len(self.gearman_server.functions) < count:
937 time.sleep(0)
938
939 def release(self, job):
940 if isinstance(job, FakeBuild):
941 job.release()
942 else:
943 job.waiting = False
944 self.log.debug("Queued job %s released" % job.unique)
945 self.gearman_server.wakeConnections()
946
947 def getParameter(self, job, name):
948 if isinstance(job, FakeBuild):
949 return job.parameters[name]
950 else:
951 parameters = json.loads(job.arguments)
952 return parameters[name]
953
954 def resetGearmanServer(self):
955 self.worker.setFunctions([])
956 while True:
957 done = True
958 for connection in self.gearman_server.active_connections:
959 if connection.functions:
960 done = False
961 if done:
962 break
963 time.sleep(0)
964 self.gearman_server.functions = set()
965
966 def haveAllBuildsReported(self):
967 # See if Zuul is waiting on a meta job to complete
968 if self.launcher.meta_jobs:
969 return False
970 # Find out if every build that the worker has completed has been
971 # reported back to Zuul. If it hasn't then that means a Gearman
972 # event is still in transit and the system is not stable.
973 for build in self.worker.build_history:
974 zbuild = self.launcher.builds.get(build.uuid)
975 if not zbuild:
976 # It has already been reported
977 continue
978 # It hasn't been reported yet.
979 return False
980 # Make sure that none of the worker connections are in GRAB_WAIT
981 for connection in self.worker.active_connections:
982 if connection.state == 'GRAB_WAIT':
983 return False
984 return True
985
986 def areAllBuildsWaiting(self):
987 ret = True
988
989 builds = self.launcher.builds.values()
990 for build in builds:
991 client_job = None
992 for conn in self.launcher.gearman.active_connections:
993 for j in conn.related_jobs.values():
994 if j.unique == build.uuid:
995 client_job = j
996 break
997 if not client_job:
998 self.log.debug("%s is not known to the gearman client" %
999 build)
1000 ret = False
1001 continue
1002 if not client_job.handle:
1003 self.log.debug("%s has no handle" % client_job)
1004 ret = False
1005 continue
1006 server_job = self.gearman_server.jobs.get(client_job.handle)
1007 if not server_job:
1008 self.log.debug("%s is not known to the gearman server" %
1009 client_job)
1010 ret = False
1011 continue
1012 if not hasattr(server_job, 'waiting'):
1013 self.log.debug("%s is being enqueued" % server_job)
1014 ret = False
1015 continue
1016 if server_job.waiting:
1017 continue
1018 worker_job = self.worker.gearman_jobs.get(server_job.unique)
1019 if worker_job:
1020 if worker_job.build.isWaiting():
1021 continue
1022 else:
1023 self.log.debug("%s is running" % worker_job)
1024 ret = False
1025 else:
1026 self.log.debug("%s is unassigned" % server_job)
1027 ret = False
1028 return ret
1029
James E. Blairb0fcae42012-07-17 11:12:10 -07001030 def waitUntilSettled(self):
1031 self.log.debug("Waiting until settled...")
1032 start = time.time()
1033 while True:
1034 if time.time() - start > 10:
1035 print 'queue status:',
1036 print self.sched.trigger_event_queue.empty(),
1037 print self.sched.result_event_queue.empty(),
1038 print self.fake_gerrit.event_queue.empty(),
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001039 print self.areAllBuildsWaiting()
James E. Blairb0fcae42012-07-17 11:12:10 -07001040 raise Exception("Timeout waiting for Zuul to settle")
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001041 # Make sure no new events show up while we're checking
1042 self.worker.lock.acquire()
1043 # have all build states propogated to zuul?
1044 if self.haveAllBuildsReported():
1045 # Join ensures that the queue is empty _and_ events have been
1046 # processed
1047 self.fake_gerrit.event_queue.join()
1048 self.sched.trigger_event_queue.join()
1049 self.sched.result_event_queue.join()
1050 if (self.sched.trigger_event_queue.empty() and
1051 self.sched.result_event_queue.empty() and
1052 self.fake_gerrit.event_queue.empty() and
1053 self.areAllBuildsWaiting()):
1054 self.worker.lock.release()
1055 self.log.debug("...settled.")
1056 return
1057 self.worker.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -07001058 self.sched.wake_event.wait(0.1)
1059
James E. Blaird466dc42012-07-31 10:42:56 -07001060 def countJobResults(self, jobs, result):
James E. Blair0018a6c2013-02-27 14:11:45 -08001061 jobs = filter(lambda x: x.result == result, jobs)
James E. Blaird466dc42012-07-31 10:42:56 -07001062 return len(jobs)
1063
James E. Blair4ca985f2013-05-30 12:27:43 -07001064 def getJobFromHistory(self, name):
1065 history = self.worker.build_history
1066 for job in history:
1067 if job.name == name:
1068 return job
1069 raise Exception("Unable to find job %s in history" % name)
1070
James E. Blaire0487072012-08-29 17:38:31 -07001071 def assertEmptyQueues(self):
1072 # Make sure there are no orphaned jobs
James E. Blaireff88162013-07-01 12:44:14 -04001073 for pipeline in self.sched.layout.pipelines.values():
James E. Blaire0487072012-08-29 17:38:31 -07001074 for queue in pipeline.queues:
1075 if len(queue.queue) != 0:
James E. Blairf62d4282012-12-31 17:01:50 -08001076 print 'pipeline %s queue %s contents %s' % (
1077 pipeline.name, queue.name, queue.queue)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001078 self.assertEqual(len(queue.queue), 0)
James E. Blaire0487072012-08-29 17:38:31 -07001079
James E. Blair66eeebf2013-07-27 17:44:32 -07001080 def assertReportedStat(self, key, value=None, kind=None):
James E. Blair412e5582013-04-22 15:50:12 -07001081 start = time.time()
1082 while time.time() < (start + 5):
1083 for stat in self.statsd.stats:
James E. Blair66eeebf2013-07-27 17:44:32 -07001084 pprint.pprint(self.statsd.stats)
James E. Blair412e5582013-04-22 15:50:12 -07001085 k, v = stat.split(':')
1086 if key == k:
James E. Blair66eeebf2013-07-27 17:44:32 -07001087 if value is None and kind is None:
James E. Blair412e5582013-04-22 15:50:12 -07001088 return
James E. Blair66eeebf2013-07-27 17:44:32 -07001089 elif value:
1090 if value == v:
1091 return
1092 elif kind:
1093 if v.endswith('|' + kind):
1094 return
James E. Blair412e5582013-04-22 15:50:12 -07001095 time.sleep(0.1)
1096
1097 pprint.pprint(self.statsd.stats)
1098 raise Exception("Key %s not found in reported stats" % key)
1099
James E. Blairb0fcae42012-07-17 11:12:10 -07001100 def test_jobs_launched(self):
1101 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001102
James E. Blairb0fcae42012-07-17 11:12:10 -07001103 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -07001104 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001105 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1106 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001107 self.assertEqual(self.getJobFromHistory('project-merge').result,
1108 'SUCCESS')
1109 self.assertEqual(self.getJobFromHistory('project-test1').result,
1110 'SUCCESS')
1111 self.assertEqual(self.getJobFromHistory('project-test2').result,
1112 'SUCCESS')
1113 self.assertEqual(A.data['status'], 'MERGED')
1114 self.assertEqual(A.reported, 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001115
James E. Blair66eeebf2013-07-27 17:44:32 -07001116 self.assertReportedStat('gerrit.event.comment-added', value='1|c')
1117 self.assertReportedStat('zuul.pipeline.gate.current_changes',
1118 value='1|g')
1119 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
1120 kind='ms')
1121 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
1122 value='1|c')
1123 self.assertReportedStat('zuul.pipeline.gate.resident_time', kind='ms')
1124 self.assertReportedStat('zuul.pipeline.gate.total_changes',
1125 value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -07001126 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -07001127 'zuul.pipeline.gate.org.project.resident_time', kind='ms')
James E. Blair412e5582013-04-22 15:50:12 -07001128 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -07001129 'zuul.pipeline.gate.org.project.total_changes', value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -07001130
James E. Blair3cb10702013-08-24 08:56:03 -07001131 def test_initial_pipeline_gauges(self):
1132 "Test that each pipeline reported its length on start"
1133 pipeline_names = self.sched.layout.pipelines.keys()
1134 self.assertNotEqual(len(pipeline_names), 0)
1135 for name in pipeline_names:
1136 self.assertReportedStat('zuul.pipeline.%s.current_changes' % name,
1137 value='0|g')
1138
James E. Blair42f74822013-05-14 15:18:03 -07001139 def test_duplicate_pipelines(self):
1140 "Test that a change matching multiple pipelines works"
James E. Blair1b4d9722013-05-21 10:32:04 -07001141
James E. Blair42f74822013-05-14 15:18:03 -07001142 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1143 self.fake_gerrit.addEvent(A.getChangeRestoredEvent())
1144 self.waitUntilSettled()
James E. Blair42f74822013-05-14 15:18:03 -07001145
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001146 self.assertEqual(len(self.history), 2)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001147 self.history[0].name == 'project-test1'
1148 self.history[1].name == 'project-test1'
James E. Blair42f74822013-05-14 15:18:03 -07001149
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001150 self.assertEqual(len(A.messages), 2)
James E. Blair42f74822013-05-14 15:18:03 -07001151 if 'dup1/project-test1' in A.messages[0]:
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001152 self.assertIn('dup1/project-test1', A.messages[0])
1153 self.assertNotIn('dup2/project-test1', A.messages[0])
1154 self.assertNotIn('dup1/project-test1', A.messages[1])
1155 self.assertIn('dup2/project-test1', A.messages[1])
James E. Blair42f74822013-05-14 15:18:03 -07001156 else:
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001157 self.assertIn('dup1/project-test1', A.messages[1])
1158 self.assertNotIn('dup2/project-test1', A.messages[1])
1159 self.assertNotIn('dup1/project-test1', A.messages[0])
1160 self.assertIn('dup2/project-test1', A.messages[0])
James E. Blair42f74822013-05-14 15:18:03 -07001161
James E. Blairb0fcae42012-07-17 11:12:10 -07001162 def test_parallel_changes(self):
1163 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001164
1165 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -07001166 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1167 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1168 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001169 A.addApproval('CRVW', 2)
1170 B.addApproval('CRVW', 2)
1171 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001172
1173 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1174 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1175 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1176
1177 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001178 self.assertEqual(len(self.builds), 1)
1179 self.assertEqual(self.builds[0].name, 'project-merge')
1180 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairb0fcae42012-07-17 11:12:10 -07001181
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001182 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001183 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001184 self.assertEqual(len(self.builds), 3)
1185 self.assertEqual(self.builds[0].name, 'project-test1')
1186 self.assertTrue(self.job_has_changes(self.builds[0], A))
1187 self.assertEqual(self.builds[1].name, 'project-test2')
1188 self.assertTrue(self.job_has_changes(self.builds[1], A))
1189 self.assertEqual(self.builds[2].name, 'project-merge')
1190 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -07001191
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001192 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001193 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001194 self.assertEqual(len(self.builds), 5)
1195 self.assertEqual(self.builds[0].name, 'project-test1')
1196 self.assertTrue(self.job_has_changes(self.builds[0], A))
1197 self.assertEqual(self.builds[1].name, 'project-test2')
1198 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -07001199
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001200 self.assertEqual(self.builds[2].name, 'project-test1')
1201 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
1202 self.assertEqual(self.builds[3].name, 'project-test2')
1203 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -07001204
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001205 self.assertEqual(self.builds[4].name, 'project-merge')
1206 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -07001207
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001208 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001209 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001210 self.assertEqual(len(self.builds), 6)
1211 self.assertEqual(self.builds[0].name, 'project-test1')
1212 self.assertTrue(self.job_has_changes(self.builds[0], A))
1213 self.assertEqual(self.builds[1].name, 'project-test2')
1214 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -07001215
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001216 self.assertEqual(self.builds[2].name, 'project-test1')
1217 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
1218 self.assertEqual(self.builds[3].name, 'project-test2')
1219 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -07001220
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001221 self.assertEqual(self.builds[4].name, 'project-test1')
1222 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
1223 self.assertEqual(self.builds[5].name, 'project-test2')
1224 self.assertTrue(self.job_has_changes(self.builds[5], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -07001225
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001226 self.worker.hold_jobs_in_build = False
1227 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -07001228 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001229 self.assertEqual(len(self.builds), 0)
James E. Blairb0fcae42012-07-17 11:12:10 -07001230
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001231 self.assertEqual(len(self.history), 9)
1232 self.assertEqual(A.data['status'], 'MERGED')
1233 self.assertEqual(B.data['status'], 'MERGED')
1234 self.assertEqual(C.data['status'], 'MERGED')
1235 self.assertEqual(A.reported, 2)
1236 self.assertEqual(B.reported, 2)
1237 self.assertEqual(C.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001238
1239 def test_failed_changes(self):
1240 "Test that a change behind a failed change is retested"
James E. Blaire2819012013-06-28 17:17:26 -04001241 self.worker.hold_jobs_in_build = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001242
James E. Blairb02a3bb2012-07-30 17:49:55 -07001243 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1244 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -07001245 A.addApproval('CRVW', 2)
1246 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001247
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001248 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001249
James E. Blaire2819012013-06-28 17:17:26 -04001250 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1251 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
James E. Blairb02a3bb2012-07-30 17:49:55 -07001252 self.waitUntilSettled()
James E. Blaire2819012013-06-28 17:17:26 -04001253
1254 self.worker.release('.*-merge')
1255 self.waitUntilSettled()
1256
1257 self.worker.hold_jobs_in_build = False
1258 self.worker.release()
1259
1260 self.waitUntilSettled()
1261 # It's certain that the merge job for change 2 will run, but
1262 # the test1 and test2 jobs may or may not run.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001263 self.assertTrue(len(self.history) > 6)
1264 self.assertEqual(A.data['status'], 'NEW')
1265 self.assertEqual(B.data['status'], 'MERGED')
1266 self.assertEqual(A.reported, 2)
1267 self.assertEqual(B.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001268
1269 def test_independent_queues(self):
1270 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001271
1272 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +09001273 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001274 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1275 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001276 A.addApproval('CRVW', 2)
1277 B.addApproval('CRVW', 2)
1278 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001279
1280 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1281 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1282 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1283
James E. Blairb02a3bb2012-07-30 17:49:55 -07001284 self.waitUntilSettled()
1285
1286 # There should be one merge job at the head of each queue running
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001287 self.assertEqual(len(self.builds), 2)
1288 self.assertEqual(self.builds[0].name, 'project-merge')
1289 self.assertTrue(self.job_has_changes(self.builds[0], A))
1290 self.assertEqual(self.builds[1].name, 'project1-merge')
1291 self.assertTrue(self.job_has_changes(self.builds[1], B))
James E. Blairb02a3bb2012-07-30 17:49:55 -07001292
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001293 # Release the current merge builds
1294 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001295 self.waitUntilSettled()
1296 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001297 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001298 self.waitUntilSettled()
1299
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001300 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -07001301 # project1 (3) + project2 (3) + project (2) = 8
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001302 self.assertEqual(len(self.builds), 8)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001303
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001304 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001305 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001306 self.assertEqual(len(self.builds), 0)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001307
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001308 self.assertEqual(len(self.history), 11)
1309 self.assertEqual(A.data['status'], 'MERGED')
1310 self.assertEqual(B.data['status'], 'MERGED')
1311 self.assertEqual(C.data['status'], 'MERGED')
1312 self.assertEqual(A.reported, 2)
1313 self.assertEqual(B.reported, 2)
1314 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001315
1316 def test_failed_change_at_head(self):
1317 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -07001318
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001319 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -07001320 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1321 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1322 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001323 A.addApproval('CRVW', 2)
1324 B.addApproval('CRVW', 2)
1325 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001326
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001327 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001328
1329 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1330 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1331 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1332
1333 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -07001334
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001335 self.assertEqual(len(self.builds), 1)
1336 self.assertEqual(self.builds[0].name, 'project-merge')
1337 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -07001338
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001339 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001340 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001341 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001342 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001343 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001344 self.waitUntilSettled()
1345
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001346 self.assertEqual(len(self.builds), 6)
1347 self.assertEqual(self.builds[0].name, 'project-test1')
1348 self.assertEqual(self.builds[1].name, 'project-test2')
1349 self.assertEqual(self.builds[2].name, 'project-test1')
1350 self.assertEqual(self.builds[3].name, 'project-test2')
1351 self.assertEqual(self.builds[4].name, 'project-test1')
1352 self.assertEqual(self.builds[5].name, 'project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -07001353
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001354 self.release(self.builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001355 self.waitUntilSettled()
1356
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001357 # project-test2, project-merge for B
1358 self.assertEqual(len(self.builds), 2)
1359 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
James E. Blaird466dc42012-07-31 10:42:56 -07001360
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001361 self.worker.hold_jobs_in_build = False
1362 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001363 self.waitUntilSettled()
1364
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001365 self.assertEqual(len(self.builds), 0)
1366 self.assertEqual(len(self.history), 15)
1367 self.assertEqual(A.data['status'], 'NEW')
1368 self.assertEqual(B.data['status'], 'MERGED')
1369 self.assertEqual(C.data['status'], 'MERGED')
1370 self.assertEqual(A.reported, 2)
1371 self.assertEqual(B.reported, 2)
1372 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001373
James E. Blair0aac4872013-08-23 14:02:38 -07001374 def test_failed_change_in_middle(self):
1375 "Test a failed change in the middle of the queue"
1376
1377 self.worker.hold_jobs_in_build = True
1378 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1379 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1380 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1381 A.addApproval('CRVW', 2)
1382 B.addApproval('CRVW', 2)
1383 C.addApproval('CRVW', 2)
1384
1385 self.worker.addFailTest('project-test1', B)
1386
1387 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1388 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1389 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1390
1391 self.waitUntilSettled()
1392
1393 self.worker.release('.*-merge')
1394 self.waitUntilSettled()
1395 self.worker.release('.*-merge')
1396 self.waitUntilSettled()
1397 self.worker.release('.*-merge')
1398 self.waitUntilSettled()
1399
1400 self.assertEqual(len(self.builds), 6)
1401 self.assertEqual(self.builds[0].name, 'project-test1')
1402 self.assertEqual(self.builds[1].name, 'project-test2')
1403 self.assertEqual(self.builds[2].name, 'project-test1')
1404 self.assertEqual(self.builds[3].name, 'project-test2')
1405 self.assertEqual(self.builds[4].name, 'project-test1')
1406 self.assertEqual(self.builds[5].name, 'project-test2')
1407
1408 self.release(self.builds[2])
1409 self.waitUntilSettled()
1410
James E. Blair972e3c72013-08-29 12:04:55 -07001411 # project-test1 and project-test2 for A
1412 # project-test2 for B
1413 # project-merge for C (without B)
1414 self.assertEqual(len(self.builds), 4)
James E. Blair0aac4872013-08-23 14:02:38 -07001415 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 2)
1416
James E. Blair972e3c72013-08-29 12:04:55 -07001417 self.worker.release('.*-merge')
1418 self.waitUntilSettled()
1419
1420 # project-test1 and project-test2 for A
1421 # project-test2 for B
1422 # project-test1 and project-test2 for C
1423 self.assertEqual(len(self.builds), 5)
1424
James E. Blair0aac4872013-08-23 14:02:38 -07001425 items = self.sched.layout.pipelines['gate'].getAllItems()
1426 builds = items[0].current_build_set.getBuilds()
1427 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
1428 self.assertEqual(self.countJobResults(builds, None), 2)
1429 builds = items[1].current_build_set.getBuilds()
1430 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
1431 self.assertEqual(self.countJobResults(builds, 'FAILURE'), 1)
1432 self.assertEqual(self.countJobResults(builds, None), 1)
1433 builds = items[2].current_build_set.getBuilds()
1434 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
James E. Blair972e3c72013-08-29 12:04:55 -07001435 self.assertEqual(self.countJobResults(builds, None), 2)
James E. Blair0aac4872013-08-23 14:02:38 -07001436
1437 self.worker.hold_jobs_in_build = False
1438 self.worker.release()
1439 self.waitUntilSettled()
1440
1441 self.assertEqual(len(self.builds), 0)
1442 self.assertEqual(len(self.history), 12)
1443 self.assertEqual(A.data['status'], 'MERGED')
1444 self.assertEqual(B.data['status'], 'NEW')
1445 self.assertEqual(C.data['status'], 'MERGED')
1446 self.assertEqual(A.reported, 2)
1447 self.assertEqual(B.reported, 2)
1448 self.assertEqual(C.reported, 2)
1449
James E. Blaird466dc42012-07-31 10:42:56 -07001450 def test_failed_change_at_head_with_queue(self):
1451 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -07001452
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001453 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -07001454 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1455 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1456 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001457 A.addApproval('CRVW', 2)
1458 B.addApproval('CRVW', 2)
1459 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001460
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001461 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001462
1463 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1464 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1465 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1466
1467 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001468 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001469 self.assertEqual(len(self.builds), 0)
1470 self.assertEqual(len(queue), 1)
1471 self.assertEqual(queue[0].name, 'build:project-merge')
1472 self.assertTrue(self.job_has_changes(queue[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -07001473
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001474 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001475 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001476 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001477 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001478 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001479 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001480 queue = self.gearman_server.getQueue()
James E. Blaird466dc42012-07-31 10:42:56 -07001481
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001482 self.assertEqual(len(self.builds), 0)
1483 self.assertEqual(len(queue), 6)
1484 self.assertEqual(queue[0].name, 'build:project-test1')
1485 self.assertEqual(queue[1].name, 'build:project-test2')
1486 self.assertEqual(queue[2].name, 'build:project-test1')
1487 self.assertEqual(queue[3].name, 'build:project-test2')
1488 self.assertEqual(queue[4].name, 'build:project-test1')
1489 self.assertEqual(queue[5].name, 'build:project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -07001490
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001491 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001492 self.waitUntilSettled()
1493
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001494 self.assertEqual(len(self.builds), 0)
James E. Blair701c5b42013-06-06 09:34:59 -07001495 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001496 self.assertEqual(len(queue), 2) # project-test2, project-merge for B
1497 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 0)
James E. Blaird466dc42012-07-31 10:42:56 -07001498
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001499 self.gearman_server.hold_jobs_in_queue = False
1500 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001501 self.waitUntilSettled()
1502
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001503 self.assertEqual(len(self.builds), 0)
1504 self.assertEqual(len(self.history), 11)
1505 self.assertEqual(A.data['status'], 'NEW')
1506 self.assertEqual(B.data['status'], 'MERGED')
1507 self.assertEqual(C.data['status'], 'MERGED')
1508 self.assertEqual(A.reported, 2)
1509 self.assertEqual(B.reported, 2)
1510 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -07001511
James E. Blairfef71632013-09-23 11:15:47 -07001512 def test_two_failed_changes_at_head(self):
1513 "Test that changes are reparented correctly if 2 fail at head"
1514
1515 self.worker.hold_jobs_in_build = True
1516 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1517 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1518 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1519 A.addApproval('CRVW', 2)
1520 B.addApproval('CRVW', 2)
1521 C.addApproval('CRVW', 2)
1522
1523 self.worker.addFailTest('project-test1', A)
1524 self.worker.addFailTest('project-test1', B)
1525
1526 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1527 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1528 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1529 self.waitUntilSettled()
1530
1531 self.worker.release('.*-merge')
1532 self.waitUntilSettled()
1533 self.worker.release('.*-merge')
1534 self.waitUntilSettled()
1535 self.worker.release('.*-merge')
1536 self.waitUntilSettled()
1537
1538 self.assertEqual(len(self.builds), 6)
1539 self.assertEqual(self.builds[0].name, 'project-test1')
1540 self.assertEqual(self.builds[1].name, 'project-test2')
1541 self.assertEqual(self.builds[2].name, 'project-test1')
1542 self.assertEqual(self.builds[3].name, 'project-test2')
1543 self.assertEqual(self.builds[4].name, 'project-test1')
1544 self.assertEqual(self.builds[5].name, 'project-test2')
1545
1546 self.assertTrue(self.job_has_changes(self.builds[0], A))
1547 self.assertTrue(self.job_has_changes(self.builds[2], A))
1548 self.assertTrue(self.job_has_changes(self.builds[2], B))
1549 self.assertTrue(self.job_has_changes(self.builds[4], A))
1550 self.assertTrue(self.job_has_changes(self.builds[4], B))
1551 self.assertTrue(self.job_has_changes(self.builds[4], C))
1552
1553 # Fail change B first
1554 self.release(self.builds[2])
1555 self.waitUntilSettled()
1556
1557 # restart of C after B failure
1558 self.worker.release('.*-merge')
1559 self.waitUntilSettled()
1560
1561 self.assertEqual(len(self.builds), 5)
1562 self.assertEqual(self.builds[0].name, 'project-test1')
1563 self.assertEqual(self.builds[1].name, 'project-test2')
1564 self.assertEqual(self.builds[2].name, 'project-test2')
1565 self.assertEqual(self.builds[3].name, 'project-test1')
1566 self.assertEqual(self.builds[4].name, 'project-test2')
1567
1568 self.assertTrue(self.job_has_changes(self.builds[1], A))
1569 self.assertTrue(self.job_has_changes(self.builds[2], A))
1570 self.assertTrue(self.job_has_changes(self.builds[2], B))
1571 self.assertTrue(self.job_has_changes(self.builds[4], A))
1572 self.assertFalse(self.job_has_changes(self.builds[4], B))
1573 self.assertTrue(self.job_has_changes(self.builds[4], C))
1574
1575 # Finish running all passing jobs for change A
1576 self.release(self.builds[1])
1577 self.waitUntilSettled()
1578 # Fail and report change A
1579 self.release(self.builds[0])
1580 self.waitUntilSettled()
1581
1582 # restart of B,C after A failure
1583 self.worker.release('.*-merge')
1584 self.waitUntilSettled()
1585 self.worker.release('.*-merge')
1586 self.waitUntilSettled()
1587
1588 self.assertEqual(len(self.builds), 4)
1589 self.assertEqual(self.builds[0].name, 'project-test1') # B
1590 self.assertEqual(self.builds[1].name, 'project-test2') # B
1591 self.assertEqual(self.builds[2].name, 'project-test1') # C
1592 self.assertEqual(self.builds[3].name, 'project-test2') # C
1593
1594 self.assertFalse(self.job_has_changes(self.builds[1], A))
1595 self.assertTrue(self.job_has_changes(self.builds[1], B))
1596 self.assertFalse(self.job_has_changes(self.builds[1], C))
1597
1598 self.assertFalse(self.job_has_changes(self.builds[2], A))
1599 # After A failed and B and C restarted, B should be back in
1600 # C's tests because it has not failed yet.
1601 self.assertTrue(self.job_has_changes(self.builds[2], B))
1602 self.assertTrue(self.job_has_changes(self.builds[2], C))
1603
1604 self.worker.hold_jobs_in_build = False
1605 self.worker.release()
1606 self.waitUntilSettled()
1607
1608 self.assertEqual(len(self.builds), 0)
1609 self.assertEqual(len(self.history), 21)
1610 self.assertEqual(A.data['status'], 'NEW')
1611 self.assertEqual(B.data['status'], 'NEW')
1612 self.assertEqual(C.data['status'], 'MERGED')
1613 self.assertEqual(A.reported, 2)
1614 self.assertEqual(B.reported, 2)
1615 self.assertEqual(C.reported, 2)
1616
James E. Blair8c803f82012-07-31 16:25:42 -07001617 def test_patch_order(self):
1618 "Test that dependent patches are tested in the right order"
1619 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1620 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1621 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1622 A.addApproval('CRVW', 2)
1623 B.addApproval('CRVW', 2)
1624 C.addApproval('CRVW', 2)
1625
1626 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
1627 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1628 M2.setMerged()
1629 M1.setMerged()
1630
1631 # C -> B -> A -> M1 -> M2
1632 # M2 is here to make sure it is never queried. If it is, it
1633 # means zuul is walking down the entire history of merged
1634 # changes.
1635
1636 C.setDependsOn(B, 1)
1637 B.setDependsOn(A, 1)
1638 A.setDependsOn(M1, 1)
1639 M1.setDependsOn(M2, 1)
1640
1641 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1642
1643 self.waitUntilSettled()
1644
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001645 self.assertEqual(A.data['status'], 'NEW')
1646 self.assertEqual(B.data['status'], 'NEW')
1647 self.assertEqual(C.data['status'], 'NEW')
James E. Blair8c803f82012-07-31 16:25:42 -07001648
1649 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1650 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1651
1652 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001653 self.assertEqual(M2.queried, 0)
1654 self.assertEqual(A.data['status'], 'MERGED')
1655 self.assertEqual(B.data['status'], 'MERGED')
1656 self.assertEqual(C.data['status'], 'MERGED')
1657 self.assertEqual(A.reported, 2)
1658 self.assertEqual(B.reported, 2)
1659 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -07001660
James E. Blair0e933c52013-07-11 10:18:52 -07001661 def test_trigger_cache(self):
1662 "Test that the trigger cache operates correctly"
1663 self.worker.hold_jobs_in_build = True
1664
1665 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1666 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1667 X = self.fake_gerrit.addFakeChange('org/project', 'master', 'X')
1668 A.addApproval('CRVW', 2)
1669 B.addApproval('CRVW', 2)
1670
1671 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1672 M1.setMerged()
1673
1674 B.setDependsOn(A, 1)
1675 A.setDependsOn(M1, 1)
1676
1677 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1678 self.fake_gerrit.addEvent(X.getPatchsetCreatedEvent(1))
1679
1680 self.waitUntilSettled()
1681
1682 for build in self.builds:
1683 if build.parameters['ZUUL_PIPELINE'] == 'check':
1684 build.release()
1685 self.waitUntilSettled()
1686 for build in self.builds:
1687 if build.parameters['ZUUL_PIPELINE'] == 'check':
1688 build.release()
1689 self.waitUntilSettled()
1690
1691 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1692 self.waitUntilSettled()
1693
James E. Blair6c358e72013-07-29 17:06:47 -07001694 self.log.debug("len %s " % self.gerrit._change_cache.keys())
James E. Blair0e933c52013-07-11 10:18:52 -07001695 # there should still be changes in the cache
James E. Blair6c358e72013-07-29 17:06:47 -07001696 self.assertNotEqual(len(self.gerrit._change_cache.keys()), 0)
James E. Blair0e933c52013-07-11 10:18:52 -07001697
1698 self.worker.hold_jobs_in_build = False
1699 self.worker.release()
1700 self.waitUntilSettled()
1701
1702 self.assertEqual(A.data['status'], 'MERGED')
1703 self.assertEqual(B.data['status'], 'MERGED')
1704 self.assertEqual(A.queried, 2) # Initial and isMerged
1705 self.assertEqual(B.queried, 3) # Initial A, refresh from B, isMerged
1706
James E. Blair8c803f82012-07-31 16:25:42 -07001707 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -07001708 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -07001709 # TODO: move to test_gerrit (this is a unit test!)
1710 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair6c358e72013-07-29 17:06:47 -07001711 trigger = self.sched.layout.pipelines['gate'].trigger
1712 a = self.sched.triggers['gerrit'].getChange(1, 2)
James E. Blaireff88162013-07-01 12:44:14 -04001713 mgr = self.sched.layout.pipelines['gate'].manager
James E. Blair6c358e72013-07-29 17:06:47 -07001714 self.assertFalse(trigger.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -07001715
1716 A.addApproval('CRVW', 2)
James E. Blair6c358e72013-07-29 17:06:47 -07001717 a = trigger.getChange(1, 2, refresh=True)
1718 self.assertFalse(trigger.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -07001719
1720 A.addApproval('APRV', 1)
James E. Blair6c358e72013-07-29 17:06:47 -07001721 a = trigger.getChange(1, 2, refresh=True)
1722 self.assertTrue(trigger.canMerge(a, mgr.getSubmitAllowNeeds()))
1723 trigger.maintainCache([])
James E. Blair4886cc12012-07-18 15:39:41 -07001724
1725 def test_build_configuration(self):
1726 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001727
1728 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -07001729 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1730 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1731 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1732 A.addApproval('CRVW', 2)
1733 B.addApproval('CRVW', 2)
1734 C.addApproval('CRVW', 2)
1735 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1736 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1737 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1738 self.waitUntilSettled()
1739
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001740 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001741 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001742 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001743 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001744 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001745 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001746 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001747 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1748 self.gearman_server.hold_jobs_in_queue = False
1749 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001750 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -07001751
Monty Taylorbc758832013-06-17 17:22:42 -04001752 path = os.path.join(self.git_root, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -07001753 repo = git.Repo(path)
1754 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1755 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -07001756 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001757 self.assertEqual(repo_messages, correct_messages)
James E. Blair973721f2012-08-15 10:19:43 -07001758
1759 def test_build_configuration_conflict(self):
1760 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001761
1762 self.gearman_server.hold_jobs_in_queue = True
James E. Blair6736beb2013-07-11 15:18:15 -07001763 A = self.fake_gerrit.addFakeChange('org/conflict-project',
1764 'master', 'A')
James E. Blair973721f2012-08-15 10:19:43 -07001765 A.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -07001766 B = self.fake_gerrit.addFakeChange('org/conflict-project',
1767 'master', 'B')
James E. Blair973721f2012-08-15 10:19:43 -07001768 B.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -07001769 C = self.fake_gerrit.addFakeChange('org/conflict-project',
1770 'master', 'C')
James E. Blair973721f2012-08-15 10:19:43 -07001771 A.addApproval('CRVW', 2)
1772 B.addApproval('CRVW', 2)
1773 C.addApproval('CRVW', 2)
1774 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1775 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1776 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1777 self.waitUntilSettled()
1778
James E. Blair6736beb2013-07-11 15:18:15 -07001779 self.assertEqual(A.reported, 1)
1780 self.assertEqual(B.reported, 1)
1781 self.assertEqual(C.reported, 1)
1782
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001783 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001784 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001785 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001786 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001787 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001788 self.waitUntilSettled()
James E. Blair972e3c72013-08-29 12:04:55 -07001789
1790 self.assertEqual(len(self.history), 2) # A and C merge jobs
1791
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001792 self.gearman_server.hold_jobs_in_queue = False
1793 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001794 self.waitUntilSettled()
1795
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001796 self.assertEqual(A.data['status'], 'MERGED')
1797 self.assertEqual(B.data['status'], 'NEW')
1798 self.assertEqual(C.data['status'], 'MERGED')
1799 self.assertEqual(A.reported, 2)
1800 self.assertEqual(B.reported, 2)
1801 self.assertEqual(C.reported, 2)
James E. Blair972e3c72013-08-29 12:04:55 -07001802 self.assertEqual(len(self.history), 6)
James E. Blair6736beb2013-07-11 15:18:15 -07001803
James E. Blairdaabed22012-08-15 15:38:57 -07001804 def test_post(self):
1805 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001806
Zhongyue Luo5d556072012-09-21 02:00:47 +09001807 e = {
1808 "type": "ref-updated",
1809 "submitter": {
1810 "name": "User Name",
1811 },
1812 "refUpdate": {
1813 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1814 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1815 "refName": "master",
1816 "project": "org/project",
1817 }
1818 }
James E. Blairdaabed22012-08-15 15:38:57 -07001819 self.fake_gerrit.addEvent(e)
1820 self.waitUntilSettled()
1821
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001822 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001823 self.assertEqual(len(self.history), 1)
1824 self.assertIn('project-post', job_names)
James E. Blairc6294a52012-08-17 10:19:48 -07001825
1826 def test_build_configuration_branch(self):
1827 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001828
1829 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001830 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1831 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1832 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1833 A.addApproval('CRVW', 2)
1834 B.addApproval('CRVW', 2)
1835 C.addApproval('CRVW', 2)
1836 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1837 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1838 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1839 self.waitUntilSettled()
1840
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001841 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001842 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001843 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001844 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001845 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001846 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001847 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001848 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1849 self.gearman_server.hold_jobs_in_queue = False
1850 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001851 self.waitUntilSettled()
1852
Monty Taylorbc758832013-06-17 17:22:42 -04001853 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001854 repo = git.Repo(path)
1855 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1856 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001857 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001858 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -07001859
1860 def test_build_configuration_branch_interaction(self):
1861 "Test that switching between branches works"
1862 self.test_build_configuration()
1863 self.test_build_configuration_branch()
1864 # C has been merged, undo that
Monty Taylorbc758832013-06-17 17:22:42 -04001865 path = os.path.join(self.upstream_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001866 repo = git.Repo(path)
1867 repo.heads.master.commit = repo.commit('init')
1868 self.test_build_configuration()
1869
1870 def test_build_configuration_multi_branch(self):
1871 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001872
1873 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001874 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1875 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1876 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1877 A.addApproval('CRVW', 2)
1878 B.addApproval('CRVW', 2)
1879 C.addApproval('CRVW', 2)
1880 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1881 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1882 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1883 self.waitUntilSettled()
1884
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001885 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001886 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001887 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001888 job_B = None
1889 for job in queue:
1890 if 'project-merge' in job.name:
1891 job_B = job
1892 ref_B = self.getParameter(job_B, 'ZUUL_REF')
James E. Blairf750aa02013-07-15 14:11:24 -07001893 self.log.debug("Got Zuul ref for change B: %s" % ref_B)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001894 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001895 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001896 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001897 for job in queue:
1898 if 'project-merge' in job.name:
1899 job_C = job
1900 ref_C = self.getParameter(job_C, 'ZUUL_REF')
James E. Blairf750aa02013-07-15 14:11:24 -07001901 self.log.debug("Got Zuul ref for change C: %s" % ref_C)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001902 self.gearman_server.hold_jobs_in_queue = False
1903 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001904 self.waitUntilSettled()
1905
Monty Taylorbc758832013-06-17 17:22:42 -04001906 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001907 repo = git.Repo(path)
1908
1909 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001910 for c in repo.iter_commits(ref_C)]
James E. Blairc6294a52012-08-17 10:19:48 -07001911 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001912 correct_messages = ['initial commit', 'A-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001913 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -07001914
1915 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001916 for c in repo.iter_commits(ref_B)]
James E. Blairc6294a52012-08-17 10:19:48 -07001917 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001918 correct_messages = ['initial commit', 'mp commit', 'B-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001919 self.assertEqual(repo_messages, correct_messages)
James E. Blair7f71c802012-08-22 13:04:32 -07001920
1921 def test_one_job_project(self):
1922 "Test that queueing works with one job"
1923 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1924 'master', 'A')
1925 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1926 'master', 'B')
1927 A.addApproval('CRVW', 2)
1928 B.addApproval('CRVW', 2)
1929 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1930 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1931 self.waitUntilSettled()
1932
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001933 self.assertEqual(A.data['status'], 'MERGED')
1934 self.assertEqual(A.reported, 2)
1935 self.assertEqual(B.data['status'], 'MERGED')
1936 self.assertEqual(B.reported, 2)
James E. Blaircaec0c52012-08-22 14:52:22 -07001937
Antoine Musso80edd5a2013-02-13 15:37:53 +01001938 def test_job_from_templates_launched(self):
1939 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001940
Antoine Musso80edd5a2013-02-13 15:37:53 +01001941 A = self.fake_gerrit.addFakeChange(
1942 'org/templated-project', 'master', 'A')
1943 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1944 self.waitUntilSettled()
Antoine Musso80edd5a2013-02-13 15:37:53 +01001945
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001946 self.assertEqual(self.getJobFromHistory('project-test1').result,
1947 'SUCCESS')
1948 self.assertEqual(self.getJobFromHistory('project-test2').result,
1949 'SUCCESS')
Antoine Musso80edd5a2013-02-13 15:37:53 +01001950
James E. Blaircaec0c52012-08-22 14:52:22 -07001951 def test_dependent_changes_dequeue(self):
1952 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001953
James E. Blaircaec0c52012-08-22 14:52:22 -07001954 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1955 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1956 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1957 A.addApproval('CRVW', 2)
1958 B.addApproval('CRVW', 2)
1959 C.addApproval('CRVW', 2)
1960
1961 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1962 M1.setMerged()
1963
1964 # C -> B -> A -> M1
1965
1966 C.setDependsOn(B, 1)
1967 B.setDependsOn(A, 1)
1968 A.setDependsOn(M1, 1)
1969
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001970 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07001971
1972 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1973 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1974 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1975
1976 self.waitUntilSettled()
1977
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001978 self.assertEqual(A.data['status'], 'NEW')
1979 self.assertEqual(A.reported, 2)
1980 self.assertEqual(B.data['status'], 'NEW')
1981 self.assertEqual(B.reported, 2)
1982 self.assertEqual(C.data['status'], 'NEW')
1983 self.assertEqual(C.reported, 2)
1984 self.assertEqual(len(self.history), 1)
James E. Blairec590122012-08-22 15:19:31 -07001985
James E. Blair972e3c72013-08-29 12:04:55 -07001986 def test_failing_dependent_changes(self):
1987 "Test that failing dependent patches are taken out of stream"
1988 self.worker.hold_jobs_in_build = True
1989 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1990 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1991 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1992 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1993 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
1994 A.addApproval('CRVW', 2)
1995 B.addApproval('CRVW', 2)
1996 C.addApproval('CRVW', 2)
1997 D.addApproval('CRVW', 2)
1998 E.addApproval('CRVW', 2)
1999
2000 # E, D -> C -> B, A
2001
2002 D.setDependsOn(C, 1)
2003 C.setDependsOn(B, 1)
2004
2005 self.worker.addFailTest('project-test1', B)
2006
2007 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2008 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2009 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2010 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2011 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
2012
2013 self.waitUntilSettled()
2014 self.worker.release('.*-merge')
2015 self.waitUntilSettled()
2016 self.worker.release('.*-merge')
2017 self.waitUntilSettled()
2018 self.worker.release('.*-merge')
2019 self.waitUntilSettled()
2020 self.worker.release('.*-merge')
2021 self.waitUntilSettled()
2022 self.worker.release('.*-merge')
2023 self.waitUntilSettled()
2024
2025 self.worker.hold_jobs_in_build = False
2026 for build in self.builds:
2027 if build.parameters['ZUUL_CHANGE'] != '1':
2028 build.release()
2029 self.waitUntilSettled()
2030
2031 self.worker.release()
2032 self.waitUntilSettled()
2033
2034 self.assertEqual(A.data['status'], 'MERGED')
2035 self.assertEqual(A.reported, 2)
2036 self.assertEqual(B.data['status'], 'NEW')
2037 self.assertEqual(B.reported, 2)
2038 self.assertEqual(C.data['status'], 'NEW')
2039 self.assertEqual(C.reported, 2)
2040 self.assertEqual(D.data['status'], 'NEW')
2041 self.assertEqual(D.reported, 2)
2042 self.assertEqual(E.data['status'], 'MERGED')
2043 self.assertEqual(E.reported, 2)
2044 self.assertEqual(len(self.history), 18)
2045
James E. Blairec590122012-08-22 15:19:31 -07002046 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08002047 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07002048 # If it's dequeued more than once, we should see extra
2049 # aborted jobs.
James E. Blairec590122012-08-22 15:19:31 -07002050
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002051 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07002052 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2053 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2054 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
2055 A.addApproval('CRVW', 2)
2056 B.addApproval('CRVW', 2)
2057 C.addApproval('CRVW', 2)
2058
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002059 self.worker.addFailTest('project1-test1', A)
2060 self.worker.addFailTest('project1-test2', A)
2061 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07002062
2063 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2064 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2065 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2066
2067 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07002068
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002069 self.assertEqual(len(self.builds), 1)
2070 self.assertEqual(self.builds[0].name, 'project1-merge')
2071 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairec590122012-08-22 15:19:31 -07002072
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002073 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07002074 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002075 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07002076 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002077 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07002078 self.waitUntilSettled()
2079
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002080 self.assertEqual(len(self.builds), 9)
2081 self.assertEqual(self.builds[0].name, 'project1-test1')
2082 self.assertEqual(self.builds[1].name, 'project1-test2')
2083 self.assertEqual(self.builds[2].name, 'project1-project2-integration')
2084 self.assertEqual(self.builds[3].name, 'project1-test1')
2085 self.assertEqual(self.builds[4].name, 'project1-test2')
2086 self.assertEqual(self.builds[5].name, 'project1-project2-integration')
2087 self.assertEqual(self.builds[6].name, 'project1-test1')
2088 self.assertEqual(self.builds[7].name, 'project1-test2')
2089 self.assertEqual(self.builds[8].name, 'project1-project2-integration')
James E. Blairec590122012-08-22 15:19:31 -07002090
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002091 self.release(self.builds[0])
James E. Blairec590122012-08-22 15:19:31 -07002092 self.waitUntilSettled()
2093
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002094 self.assertEqual(len(self.builds), 3) # test2,integration, merge for B
2095 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 6)
James E. Blairec590122012-08-22 15:19:31 -07002096
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002097 self.worker.hold_jobs_in_build = False
2098 self.worker.release()
James E. Blairec590122012-08-22 15:19:31 -07002099 self.waitUntilSettled()
2100
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002101 self.assertEqual(len(self.builds), 0)
2102 self.assertEqual(len(self.history), 20)
James E. Blaircaec0c52012-08-22 14:52:22 -07002103
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002104 self.assertEqual(A.data['status'], 'NEW')
2105 self.assertEqual(B.data['status'], 'MERGED')
2106 self.assertEqual(C.data['status'], 'MERGED')
2107 self.assertEqual(A.reported, 2)
2108 self.assertEqual(B.reported, 2)
2109 self.assertEqual(C.reported, 2)
James E. Blair4ec821f2012-08-23 15:28:28 -07002110
2111 def test_nonvoting_job(self):
2112 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002113
James E. Blair4ec821f2012-08-23 15:28:28 -07002114 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
2115 'master', 'A')
2116 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002117 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07002118 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2119
2120 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07002121
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002122 self.assertEqual(A.data['status'], 'MERGED')
2123 self.assertEqual(A.reported, 2)
2124 self.assertEqual(
2125 self.getJobFromHistory('nonvoting-project-merge').result,
2126 'SUCCESS')
2127 self.assertEqual(
2128 self.getJobFromHistory('nonvoting-project-test1').result,
2129 'SUCCESS')
2130 self.assertEqual(
2131 self.getJobFromHistory('nonvoting-project-test2').result,
2132 'FAILURE')
James E. Blaire0487072012-08-29 17:38:31 -07002133
2134 def test_check_queue_success(self):
2135 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002136
James E. Blaire0487072012-08-29 17:38:31 -07002137 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2138 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2139
2140 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07002141
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002142 self.assertEqual(A.data['status'], 'NEW')
2143 self.assertEqual(A.reported, 1)
2144 self.assertEqual(self.getJobFromHistory('project-merge').result,
2145 'SUCCESS')
2146 self.assertEqual(self.getJobFromHistory('project-test1').result,
2147 'SUCCESS')
2148 self.assertEqual(self.getJobFromHistory('project-test2').result,
2149 'SUCCESS')
James E. Blaire0487072012-08-29 17:38:31 -07002150
2151 def test_check_queue_failure(self):
2152 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002153
James E. Blaire0487072012-08-29 17:38:31 -07002154 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002155 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07002156 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2157
2158 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07002159
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002160 self.assertEqual(A.data['status'], 'NEW')
2161 self.assertEqual(A.reported, 1)
2162 self.assertEqual(self.getJobFromHistory('project-merge').result,
James E. Blair78e31b32013-07-09 09:11:34 -07002163 'SUCCESS')
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002164 self.assertEqual(self.getJobFromHistory('project-test1').result,
2165 'SUCCESS')
2166 self.assertEqual(self.getJobFromHistory('project-test2').result,
2167 'FAILURE')
James E. Blair127bc182012-08-28 15:55:15 -07002168
2169 def test_dependent_behind_dequeue(self):
2170 "test that dependent changes behind dequeued changes work"
2171 # This complicated test is a reproduction of a real life bug
2172 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07002173
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002174 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07002175 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2176 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2177 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
2178 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
2179 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
2180 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
2181 D.setDependsOn(C, 1)
2182 E.setDependsOn(D, 1)
2183 A.addApproval('CRVW', 2)
2184 B.addApproval('CRVW', 2)
2185 C.addApproval('CRVW', 2)
2186 D.addApproval('CRVW', 2)
2187 E.addApproval('CRVW', 2)
2188 F.addApproval('CRVW', 2)
2189
2190 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07002191
2192 # Change object re-use in the gerrit trigger is hidden if
2193 # changes are added in quick succession; waiting makes it more
2194 # like real life.
2195 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2196 self.waitUntilSettled()
2197 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2198 self.waitUntilSettled()
2199
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002200 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002201 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002202 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002203 self.waitUntilSettled()
2204
2205 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2206 self.waitUntilSettled()
2207 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2208 self.waitUntilSettled()
2209 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
2210 self.waitUntilSettled()
2211 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
2212 self.waitUntilSettled()
2213
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002214 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002215 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002216 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002217 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002218 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002219 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002220 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002221 self.waitUntilSettled()
2222
2223 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07002224
2225 # Grab pointers to the jobs we want to release before
2226 # releasing any, because list indexes may change as
2227 # the jobs complete.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002228 a, b, c = self.builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07002229 a.release()
2230 b.release()
2231 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07002232 self.waitUntilSettled()
2233
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002234 self.worker.hold_jobs_in_build = False
2235 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07002236 self.waitUntilSettled()
2237
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002238 self.assertEqual(A.data['status'], 'NEW')
2239 self.assertEqual(B.data['status'], 'MERGED')
2240 self.assertEqual(C.data['status'], 'MERGED')
2241 self.assertEqual(D.data['status'], 'MERGED')
2242 self.assertEqual(E.data['status'], 'MERGED')
2243 self.assertEqual(F.data['status'], 'MERGED')
James E. Blair127bc182012-08-28 15:55:15 -07002244
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002245 self.assertEqual(A.reported, 2)
2246 self.assertEqual(B.reported, 2)
2247 self.assertEqual(C.reported, 2)
2248 self.assertEqual(D.reported, 2)
2249 self.assertEqual(E.reported, 2)
2250 self.assertEqual(F.reported, 2)
James E. Blair127bc182012-08-28 15:55:15 -07002251
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002252 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 15)
2253 self.assertEqual(len(self.history), 44)
James E. Blair05fed602012-09-07 12:45:24 -07002254
2255 def test_merger_repack(self):
2256 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002257
James E. Blair05fed602012-09-07 12:45:24 -07002258 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2259 A.addApproval('CRVW', 2)
2260 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2261 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002262 self.assertEqual(self.getJobFromHistory('project-merge').result,
2263 'SUCCESS')
2264 self.assertEqual(self.getJobFromHistory('project-test1').result,
2265 'SUCCESS')
2266 self.assertEqual(self.getJobFromHistory('project-test2').result,
2267 'SUCCESS')
2268 self.assertEqual(A.data['status'], 'MERGED')
2269 self.assertEqual(A.reported, 2)
James E. Blair05fed602012-09-07 12:45:24 -07002270 self.assertEmptyQueues()
James E. Blair4ca985f2013-05-30 12:27:43 -07002271 self.worker.build_history = []
James E. Blair05fed602012-09-07 12:45:24 -07002272
Monty Taylorbc758832013-06-17 17:22:42 -04002273 path = os.path.join(self.git_root, "org/project")
2274 print repack_repo(path)
James E. Blair05fed602012-09-07 12:45:24 -07002275
2276 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2277 A.addApproval('CRVW', 2)
2278 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2279 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002280 self.assertEqual(self.getJobFromHistory('project-merge').result,
2281 'SUCCESS')
2282 self.assertEqual(self.getJobFromHistory('project-test1').result,
2283 'SUCCESS')
2284 self.assertEqual(self.getJobFromHistory('project-test2').result,
2285 'SUCCESS')
2286 self.assertEqual(A.data['status'], 'MERGED')
2287 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02002288
James E. Blair4886f282012-11-15 09:27:33 -08002289 def test_merger_repack_large_change(self):
2290 "Test that the merger works with large changes after a repack"
2291 # https://bugs.launchpad.net/zuul/+bug/1078946
2292 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2293 A.addPatchset(large=True)
Monty Taylorbc758832013-06-17 17:22:42 -04002294 path = os.path.join(self.upstream_root, "org/project1")
2295 print repack_repo(path)
2296 path = os.path.join(self.git_root, "org/project1")
2297 print repack_repo(path)
James E. Blair4886f282012-11-15 09:27:33 -08002298
2299 A.addApproval('CRVW', 2)
2300 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2301 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002302 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2303 'SUCCESS')
2304 self.assertEqual(self.getJobFromHistory('project1-test1').result,
2305 'SUCCESS')
2306 self.assertEqual(self.getJobFromHistory('project1-test2').result,
2307 'SUCCESS')
2308 self.assertEqual(A.data['status'], 'MERGED')
2309 self.assertEqual(A.reported, 2)
James E. Blair4886f282012-11-15 09:27:33 -08002310
James E. Blair7ee88a22012-09-12 18:59:31 +02002311 def test_nonexistent_job(self):
2312 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002313 # Set to the state immediately after a restart
2314 self.resetGearmanServer()
2315 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02002316
2317 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2318 A.addApproval('CRVW', 2)
2319 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2320 # There may be a thread about to report a lost change
2321 while A.reported < 2:
2322 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002323 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002324 self.assertFalse(job_names)
2325 self.assertEqual(A.data['status'], 'NEW')
2326 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02002327 self.assertEmptyQueues()
2328
2329 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002330 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02002331 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2332 A.addApproval('CRVW', 2)
2333 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2334 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002335 self.assertEqual(self.getJobFromHistory('project-merge').result,
2336 'SUCCESS')
2337 self.assertEqual(self.getJobFromHistory('project-test1').result,
2338 'SUCCESS')
2339 self.assertEqual(self.getJobFromHistory('project-test2').result,
2340 'SUCCESS')
2341 self.assertEqual(A.data['status'], 'MERGED')
2342 self.assertEqual(A.reported, 2)
James E. Blairf62d4282012-12-31 17:01:50 -08002343
2344 def test_single_nonexistent_post_job(self):
2345 "Test launching a single post job that doesn't exist"
James E. Blairf62d4282012-12-31 17:01:50 -08002346 e = {
2347 "type": "ref-updated",
2348 "submitter": {
2349 "name": "User Name",
2350 },
2351 "refUpdate": {
2352 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
2353 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
2354 "refName": "master",
2355 "project": "org/project",
2356 }
2357 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002358 # Set to the state immediately after a restart
2359 self.resetGearmanServer()
2360 self.launcher.negative_function_cache_ttl = 0
2361
James E. Blairf62d4282012-12-31 17:01:50 -08002362 self.fake_gerrit.addEvent(e)
2363 self.waitUntilSettled()
2364
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002365 self.assertEqual(len(self.history), 0)
James E. Blair2fa50962013-01-30 21:50:41 -08002366
2367 def test_new_patchset_dequeues_old(self):
2368 "Test that a new patchset causes the old to be dequeued"
2369 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002370 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002371 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
2372 M.setMerged()
2373
2374 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2375 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2376 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2377 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
2378 A.addApproval('CRVW', 2)
2379 B.addApproval('CRVW', 2)
2380 C.addApproval('CRVW', 2)
2381 D.addApproval('CRVW', 2)
2382
2383 C.setDependsOn(B, 1)
2384 B.setDependsOn(A, 1)
2385 A.setDependsOn(M, 1)
2386
2387 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2388 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2389 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2390 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2391 self.waitUntilSettled()
2392
2393 B.addPatchset()
2394 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2395 self.waitUntilSettled()
2396
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002397 self.worker.hold_jobs_in_build = False
2398 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002399 self.waitUntilSettled()
2400
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002401 self.assertEqual(A.data['status'], 'MERGED')
2402 self.assertEqual(A.reported, 2)
2403 self.assertEqual(B.data['status'], 'NEW')
2404 self.assertEqual(B.reported, 2)
2405 self.assertEqual(C.data['status'], 'NEW')
2406 self.assertEqual(C.reported, 2)
2407 self.assertEqual(D.data['status'], 'MERGED')
2408 self.assertEqual(D.reported, 2)
2409 self.assertEqual(len(self.history), 9) # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08002410
2411 def test_new_patchset_dequeues_old_on_head(self):
2412 "Test that a new patchset causes the old to be dequeued (at head)"
2413 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002414 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002415 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
2416 M.setMerged()
2417 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2418 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2419 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2420 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
2421 A.addApproval('CRVW', 2)
2422 B.addApproval('CRVW', 2)
2423 C.addApproval('CRVW', 2)
2424 D.addApproval('CRVW', 2)
2425
2426 C.setDependsOn(B, 1)
2427 B.setDependsOn(A, 1)
2428 A.setDependsOn(M, 1)
2429
2430 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2431 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2432 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2433 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2434 self.waitUntilSettled()
2435
2436 A.addPatchset()
2437 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
2438 self.waitUntilSettled()
2439
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002440 self.worker.hold_jobs_in_build = False
2441 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002442 self.waitUntilSettled()
2443
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002444 self.assertEqual(A.data['status'], 'NEW')
2445 self.assertEqual(A.reported, 2)
2446 self.assertEqual(B.data['status'], 'NEW')
2447 self.assertEqual(B.reported, 2)
2448 self.assertEqual(C.data['status'], 'NEW')
2449 self.assertEqual(C.reported, 2)
2450 self.assertEqual(D.data['status'], 'MERGED')
2451 self.assertEqual(D.reported, 2)
2452 self.assertEqual(len(self.history), 7)
James E. Blair2fa50962013-01-30 21:50:41 -08002453
2454 def test_new_patchset_dequeues_old_without_dependents(self):
2455 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002456 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002457 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2458 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2459 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2460 A.addApproval('CRVW', 2)
2461 B.addApproval('CRVW', 2)
2462 C.addApproval('CRVW', 2)
2463
2464 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2465 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2466 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2467 self.waitUntilSettled()
2468
2469 B.addPatchset()
2470 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2471 self.waitUntilSettled()
2472
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002473 self.worker.hold_jobs_in_build = False
2474 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002475 self.waitUntilSettled()
2476
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002477 self.assertEqual(A.data['status'], 'MERGED')
2478 self.assertEqual(A.reported, 2)
2479 self.assertEqual(B.data['status'], 'NEW')
2480 self.assertEqual(B.reported, 2)
2481 self.assertEqual(C.data['status'], 'MERGED')
2482 self.assertEqual(C.reported, 2)
2483 self.assertEqual(len(self.history), 9)
James E. Blair2fa50962013-01-30 21:50:41 -08002484
2485 def test_new_patchset_dequeues_old_independent_queue(self):
2486 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002487 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002488 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2489 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2490 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2491 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2492 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2493 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2494 self.waitUntilSettled()
2495
2496 B.addPatchset()
2497 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2498 self.waitUntilSettled()
2499
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002500 self.worker.hold_jobs_in_build = False
2501 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002502 self.waitUntilSettled()
2503
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002504 self.assertEqual(A.data['status'], 'NEW')
2505 self.assertEqual(A.reported, 1)
2506 self.assertEqual(B.data['status'], 'NEW')
2507 self.assertEqual(B.reported, 1)
2508 self.assertEqual(C.data['status'], 'NEW')
2509 self.assertEqual(C.reported, 1)
2510 self.assertEqual(len(self.history), 10)
2511 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002512
2513 def test_zuul_refs(self):
2514 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002515 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08002516 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
2517 M1.setMerged()
2518 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
2519 M2.setMerged()
2520
2521 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2522 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2523 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
2524 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
2525 A.addApproval('CRVW', 2)
2526 B.addApproval('CRVW', 2)
2527 C.addApproval('CRVW', 2)
2528 D.addApproval('CRVW', 2)
2529 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2530 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2531 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2532 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2533
2534 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002535 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002536 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002537 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002538 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002539 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002540 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002541 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002542 self.waitUntilSettled()
2543
James E. Blair7d0dedc2013-02-21 17:26:09 -08002544 a_zref = b_zref = c_zref = d_zref = None
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002545 for x in self.builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08002546 if x.parameters['ZUUL_CHANGE'] == '3':
2547 a_zref = x.parameters['ZUUL_REF']
2548 if x.parameters['ZUUL_CHANGE'] == '4':
2549 b_zref = x.parameters['ZUUL_REF']
2550 if x.parameters['ZUUL_CHANGE'] == '5':
2551 c_zref = x.parameters['ZUUL_REF']
2552 if x.parameters['ZUUL_CHANGE'] == '6':
2553 d_zref = x.parameters['ZUUL_REF']
2554
2555 # There are... four... refs.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002556 self.assertIsNotNone(a_zref)
2557 self.assertIsNotNone(b_zref)
2558 self.assertIsNotNone(c_zref)
2559 self.assertIsNotNone(d_zref)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002560
2561 # And they should all be different
2562 refs = set([a_zref, b_zref, c_zref, d_zref])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002563 self.assertEqual(len(refs), 4)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002564
2565 # a ref should have a, not b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002566 self.assertTrue(self.ref_has_change(a_zref, A))
2567 self.assertFalse(self.ref_has_change(a_zref, B))
2568 self.assertFalse(self.ref_has_change(a_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002569
2570 # b ref should have a and b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002571 self.assertTrue(self.ref_has_change(b_zref, A))
2572 self.assertTrue(self.ref_has_change(b_zref, B))
2573 self.assertFalse(self.ref_has_change(b_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002574
2575 # c ref should have a and b in 1, c in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002576 self.assertTrue(self.ref_has_change(c_zref, A))
2577 self.assertTrue(self.ref_has_change(c_zref, B))
2578 self.assertTrue(self.ref_has_change(c_zref, C))
2579 self.assertFalse(self.ref_has_change(c_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002580
2581 # d ref should have a and b in 1, c and d in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002582 self.assertTrue(self.ref_has_change(d_zref, A))
2583 self.assertTrue(self.ref_has_change(d_zref, B))
2584 self.assertTrue(self.ref_has_change(d_zref, C))
2585 self.assertTrue(self.ref_has_change(d_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002586
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002587 self.worker.hold_jobs_in_build = False
2588 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002589 self.waitUntilSettled()
2590
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002591 self.assertEqual(A.data['status'], 'MERGED')
2592 self.assertEqual(A.reported, 2)
2593 self.assertEqual(B.data['status'], 'MERGED')
2594 self.assertEqual(B.reported, 2)
2595 self.assertEqual(C.data['status'], 'MERGED')
2596 self.assertEqual(C.reported, 2)
2597 self.assertEqual(D.data['status'], 'MERGED')
2598 self.assertEqual(D.reported, 2)
James E. Blair70c71582013-03-06 08:50:50 -08002599
James E. Blair4a28a882013-08-23 15:17:33 -07002600 def test_rerun_on_error(self):
2601 "Test that if a worker fails to run a job, it is run again"
2602 self.worker.hold_jobs_in_build = True
2603 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2604 A.addApproval('CRVW', 2)
2605 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2606 self.waitUntilSettled()
2607
2608 self.builds[0].run_error = True
2609 self.worker.hold_jobs_in_build = False
2610 self.worker.release()
2611 self.waitUntilSettled()
2612 self.assertEqual(self.countJobResults(self.history, 'RUN_ERROR'), 1)
2613 self.assertEqual(self.countJobResults(self.history, 'SUCCESS'), 3)
2614
James E. Blair412e5582013-04-22 15:50:12 -07002615 def test_statsd(self):
2616 "Test each of the statsd methods used in the scheduler"
2617 import extras
2618 statsd = extras.try_import('statsd.statsd')
2619 statsd.incr('test-incr')
2620 statsd.timing('test-timing', 3)
2621 statsd.gauge('test-guage', 12)
2622 self.assertReportedStat('test-incr', '1|c')
2623 self.assertReportedStat('test-timing', '3|ms')
2624 self.assertReportedStat('test-guage', '12|g')
2625
James E. Blair70c71582013-03-06 08:50:50 -08002626 def test_file_jobs(self):
2627 "Test that file jobs run only when appropriate"
2628 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2629 A.addPatchset(['pip-requires'])
2630 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2631 A.addApproval('CRVW', 2)
2632 B.addApproval('CRVW', 2)
2633 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2634 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2635 self.waitUntilSettled()
2636
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002637 testfile_jobs = [x for x in self.history
James E. Blair70c71582013-03-06 08:50:50 -08002638 if x.name == 'project-testfile']
2639
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002640 self.assertEqual(len(testfile_jobs), 1)
2641 self.assertEqual(testfile_jobs[0].changes, '1,2')
2642 self.assertEqual(A.data['status'], 'MERGED')
2643 self.assertEqual(A.reported, 2)
2644 self.assertEqual(B.data['status'], 'MERGED')
2645 self.assertEqual(B.reported, 2)
James E. Blair3c5e5b52013-04-26 11:17:03 -07002646
2647 def test_test_config(self):
2648 "Test that we can test the config"
2649 sched = zuul.scheduler.Scheduler()
James E. Blair6c358e72013-07-29 17:06:47 -07002650 sched.registerTrigger(None, 'gerrit')
James E. Blair63bb0ef2013-07-29 17:14:51 -07002651 sched.registerTrigger(None, 'timer')
James E. Blair3c5e5b52013-04-26 11:17:03 -07002652 sched.testConfig(CONFIG.get('zuul', 'layout_config'))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002653
2654 def test_build_description(self):
2655 "Test that build descriptions update"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002656 self.worker.registerFunction('set_description:' +
2657 self.worker.worker_id)
2658
2659 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2660 A.addApproval('CRVW', 2)
2661 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2662 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002663 desc = self.history[0].description
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002664 self.log.debug("Description: %s" % desc)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002665 self.assertTrue(re.search("Branch.*master", desc))
2666 self.assertTrue(re.search("Pipeline.*gate", desc))
2667 self.assertTrue(re.search("project-merge.*SUCCESS", desc))
2668 self.assertTrue(re.search("project-test1.*SUCCESS", desc))
2669 self.assertTrue(re.search("project-test2.*SUCCESS", desc))
2670 self.assertTrue(re.search("Reported result.*SUCCESS", desc))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002671
James E. Blair64ed6f22013-07-10 14:07:23 -07002672 def test_queue_precedence(self):
2673 "Test that queue precedence works"
2674
2675 self.gearman_server.hold_jobs_in_queue = True
James E. Blair8de58bd2013-07-18 16:23:33 -07002676 self.worker.hold_jobs_in_build = True
James E. Blair64ed6f22013-07-10 14:07:23 -07002677 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2678 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2679 A.addApproval('CRVW', 2)
2680 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2681
2682 self.waitUntilSettled()
2683 self.gearman_server.hold_jobs_in_queue = False
2684 self.gearman_server.release()
2685 self.waitUntilSettled()
2686
James E. Blair8de58bd2013-07-18 16:23:33 -07002687 # Run one build at a time to ensure non-race order:
2688 for x in range(6):
2689 self.release(self.builds[0])
2690 self.waitUntilSettled()
2691 self.worker.hold_jobs_in_build = False
2692 self.waitUntilSettled()
2693
James E. Blair64ed6f22013-07-10 14:07:23 -07002694 self.log.debug(self.history)
2695 self.assertEqual(self.history[0].pipeline, 'gate')
2696 self.assertEqual(self.history[1].pipeline, 'check')
2697 self.assertEqual(self.history[2].pipeline, 'gate')
2698 self.assertEqual(self.history[3].pipeline, 'gate')
2699 self.assertEqual(self.history[4].pipeline, 'check')
2700 self.assertEqual(self.history[5].pipeline, 'check')
2701
James E. Blair1843a552013-07-03 14:19:52 -07002702 def test_json_status(self):
2703 "Test that we can retrieve JSON status info"
2704 self.worker.hold_jobs_in_build = True
2705 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2706 A.addApproval('CRVW', 2)
2707 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2708 self.waitUntilSettled()
2709
2710 port = self.webapp.server.socket.getsockname()[1]
2711
2712 f = urllib.urlopen("http://localhost:%s/status.json" % port)
2713 data = f.read()
2714
2715 self.worker.hold_jobs_in_build = False
2716 self.worker.release()
2717 self.waitUntilSettled()
2718
2719 data = json.loads(data)
2720 status_jobs = set()
2721 for p in data['pipelines']:
2722 for q in p['change_queues']:
2723 for head in q['heads']:
2724 for change in head:
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002725 self.assertEqual(change['id'], '1,1')
James E. Blair1843a552013-07-03 14:19:52 -07002726 for job in change['jobs']:
2727 status_jobs.add(job['name'])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002728 self.assertIn('project-merge', status_jobs)
2729 self.assertIn('project-test1', status_jobs)
2730 self.assertIn('project-test2', status_jobs)
James E. Blair1843a552013-07-03 14:19:52 -07002731
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002732 def test_node_label(self):
2733 "Test that a job runs on a specific node label"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002734 self.worker.registerFunction('build:node-project-test1:debian')
2735
2736 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2737 A.addApproval('CRVW', 2)
2738 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2739 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07002740
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002741 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2742 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2743 'debian')
2744 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
James E. Blaircdccd972013-07-01 12:10:22 -07002745
2746 def test_live_reconfiguration(self):
2747 "Test that live reconfiguration works"
2748 self.worker.hold_jobs_in_build = True
2749 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2750 A.addApproval('CRVW', 2)
2751 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2752 self.waitUntilSettled()
2753
2754 self.sched.reconfigure(self.config)
2755
2756 self.worker.hold_jobs_in_build = False
2757 self.worker.release()
2758 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002759 self.assertEqual(self.getJobFromHistory('project-merge').result,
2760 'SUCCESS')
2761 self.assertEqual(self.getJobFromHistory('project-test1').result,
2762 'SUCCESS')
2763 self.assertEqual(self.getJobFromHistory('project-test2').result,
2764 'SUCCESS')
2765 self.assertEqual(A.data['status'], 'MERGED')
2766 self.assertEqual(A.reported, 2)
James E. Blair287c06d2013-07-24 10:39:30 -07002767
James E. Blaire712d9f2013-07-31 11:40:11 -07002768 def test_live_reconfiguration_functions(self):
2769 "Test live reconfiguration with a custom function"
2770 self.worker.registerFunction('build:node-project-test1:debian')
2771 self.worker.registerFunction('build:node-project-test1:wheezy')
2772 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2773 A.addApproval('CRVW', 2)
2774 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2775 self.waitUntilSettled()
2776
2777 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2778 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2779 'debian')
2780 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2781
2782 self.config.set('zuul', 'layout_config',
2783 'tests/fixtures/layout-live-'
2784 'reconfiguration-functions.yaml')
2785 self.sched.reconfigure(self.config)
2786 self.worker.build_history = []
2787
2788 B = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'B')
2789 B.addApproval('CRVW', 2)
2790 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2791 self.waitUntilSettled()
2792
2793 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2794 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2795 'wheezy')
2796 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2797
James E. Blair287c06d2013-07-24 10:39:30 -07002798 def test_delayed_repo_init(self):
2799 self.config.set('zuul', 'layout_config',
2800 'tests/fixtures/layout-delayed-repo-init.yaml')
2801 self.sched.reconfigure(self.config)
2802
2803 self.init_repo("org/new-project")
2804 A = self.fake_gerrit.addFakeChange('org/new-project', 'master', 'A')
2805
2806 A.addApproval('CRVW', 2)
2807 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2808 self.waitUntilSettled()
2809 self.assertEqual(self.getJobFromHistory('project-merge').result,
2810 'SUCCESS')
2811 self.assertEqual(self.getJobFromHistory('project-test1').result,
2812 'SUCCESS')
2813 self.assertEqual(self.getJobFromHistory('project-test2').result,
2814 'SUCCESS')
2815 self.assertEqual(A.data['status'], 'MERGED')
2816 self.assertEqual(A.reported, 2)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002817
Clark Boylan6dbbc482013-10-18 10:57:31 -07002818 def test_repo_deleted(self):
2819 self.config.set('zuul', 'layout_config',
2820 'tests/fixtures/layout-repo-deleted.yaml')
2821 self.sched.reconfigure(self.config)
2822
2823 self.init_repo("org/delete-project")
2824 A = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'A')
2825
2826 A.addApproval('CRVW', 2)
2827 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2828 self.waitUntilSettled()
2829 self.assertEqual(self.getJobFromHistory('project-merge').result,
2830 'SUCCESS')
2831 self.assertEqual(self.getJobFromHistory('project-test1').result,
2832 'SUCCESS')
2833 self.assertEqual(self.getJobFromHistory('project-test2').result,
2834 'SUCCESS')
2835 self.assertEqual(A.data['status'], 'MERGED')
2836 self.assertEqual(A.reported, 2)
2837
2838 # Delete org/new-project zuul repo. Should be recloned.
2839 shutil.rmtree(os.path.join(self.git_root, "org/delete-project"))
2840
2841 B = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'B')
2842
2843 B.addApproval('CRVW', 2)
2844 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2845 self.waitUntilSettled()
2846 self.assertEqual(self.getJobFromHistory('project-merge').result,
2847 'SUCCESS')
2848 self.assertEqual(self.getJobFromHistory('project-test1').result,
2849 'SUCCESS')
2850 self.assertEqual(self.getJobFromHistory('project-test2').result,
2851 'SUCCESS')
2852 self.assertEqual(B.data['status'], 'MERGED')
2853 self.assertEqual(B.reported, 2)
2854
James E. Blair63bb0ef2013-07-29 17:14:51 -07002855 def test_timer(self):
2856 "Test that a periodic job is triggered"
2857 self.worker.hold_jobs_in_build = True
2858 self.config.set('zuul', 'layout_config',
2859 'tests/fixtures/layout-timer.yaml')
2860 self.sched.reconfigure(self.config)
2861 self.registerJobs()
2862
2863 start = time.time()
2864 failed = True
2865 while ((time.time() - start) < 30):
2866 if len(self.builds) == 2:
2867 failed = False
2868 break
2869 else:
2870 time.sleep(1)
2871
2872 if failed:
2873 raise Exception("Expected jobs never ran")
2874
2875 self.waitUntilSettled()
2876 port = self.webapp.server.socket.getsockname()[1]
2877
2878 f = urllib.urlopen("http://localhost:%s/status.json" % port)
2879 data = f.read()
2880
2881 self.worker.hold_jobs_in_build = False
2882 self.worker.release()
2883 self.waitUntilSettled()
2884
2885 self.assertEqual(self.getJobFromHistory(
2886 'project-bitrot-stable-old').result, 'SUCCESS')
2887 self.assertEqual(self.getJobFromHistory(
2888 'project-bitrot-stable-older').result, 'SUCCESS')
2889
2890 data = json.loads(data)
2891 status_jobs = set()
2892 for p in data['pipelines']:
2893 for q in p['change_queues']:
2894 for head in q['heads']:
2895 for change in head:
Alex Gaynorddb9ef32013-09-16 21:04:58 -07002896 self.assertEqual(change['id'], None)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002897 for job in change['jobs']:
2898 status_jobs.add(job['name'])
2899 self.assertIn('project-bitrot-stable-old', status_jobs)
2900 self.assertIn('project-bitrot-stable-older', status_jobs)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002901
2902 def test_check_smtp_pool(self):
2903 self.config.set('zuul', 'layout_config',
2904 'tests/fixtures/layout-smtp.yaml')
2905 self.sched.reconfigure(self.config)
2906
2907 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2908 self.waitUntilSettled()
2909
2910 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2911 self.waitUntilSettled()
2912
2913 self.assertEqual(len(FakeSMTP.messages), 2)
2914
2915 # A.messages only holds what FakeGerrit places in it. Thus we
2916 # work on the knowledge of what the first message should be as
2917 # it is only configured to go to SMTP.
2918
2919 self.assertEqual('zuul@example.com',
2920 FakeSMTP.messages[0]['from_email'])
2921 self.assertEqual(['you@example.com'],
2922 FakeSMTP.messages[0]['to_email'])
2923 self.assertEqual('Starting check jobs.',
2924 FakeSMTP.messages[0]['body'])
2925
2926 self.assertEqual('zuul_from@example.com',
2927 FakeSMTP.messages[1]['from_email'])
2928 self.assertEqual(['alternative_me@example.com'],
2929 FakeSMTP.messages[1]['to_email'])
2930 self.assertEqual(A.messages[0],
2931 FakeSMTP.messages[1]['body'])