blob: 3d3602ee5b0022ebae9c9bd364aa0a72557ee10f [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. Blairad28e912013-11-27 10:43:22 -080047import zuul.rpclistener
48import zuul.rpcclient
James E. Blair1f4c2bb2013-04-26 08:40:46 -070049import zuul.launcher.gearman
Joshua Hesketh1879cf72013-08-19 14:13:15 +100050import zuul.reporter.gerrit
Joshua Hesketh5fea8672013-08-19 17:32:01 +100051import zuul.reporter.smtp
James E. Blairb0fcae42012-07-17 11:12:10 -070052import zuul.trigger.gerrit
James E. Blair63bb0ef2013-07-29 17:14:51 -070053import zuul.trigger.timer
James E. Blairb0fcae42012-07-17 11:12:10 -070054
55FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
56 'fixtures')
57CONFIG = ConfigParser.ConfigParser()
58CONFIG.read(os.path.join(FIXTURE_DIR, "zuul.conf"))
59
60CONFIG.set('zuul', 'layout_config',
61 os.path.join(FIXTURE_DIR, "layout.yaml"))
62
James E. Blair1f4c2bb2013-04-26 08:40:46 -070063logging.basicConfig(level=logging.DEBUG,
64 format='%(asctime)s %(name)-32s '
65 '%(levelname)-8s %(message)s')
James E. Blairb0fcae42012-07-17 11:12:10 -070066
67
Monty Taylorbc758832013-06-17 17:22:42 -040068def repack_repo(path):
James E. Blairac2c3242014-01-24 13:38:51 -080069 cmd = ['git', '--git-dir=%s/.git' % path, 'repack', '-afd']
70 output = subprocess.Popen(cmd, close_fds=True,
71 stdout=subprocess.PIPE,
72 stderr=subprocess.PIPE)
Monty Taylorbc758832013-06-17 17:22:42 -040073 out = output.communicate()
74 if output.returncode:
75 raise Exception("git repack returned %d" % output.returncode)
76 return out
77
78
James E. Blair8cc15a82012-08-01 11:17:57 -070079def random_sha1():
80 return hashlib.sha1(str(random.random())).hexdigest()
81
82
James E. Blair4886cc12012-07-18 15:39:41 -070083class ChangeReference(git.Reference):
84 _common_path_default = "refs/changes"
85 _points_to_commits_only = True
86
87
James E. Blairb0fcae42012-07-17 11:12:10 -070088class FakeChange(object):
James E. Blair8c803f82012-07-31 16:25:42 -070089 categories = {'APRV': ('Approved', -1, 1),
90 'CRVW': ('Code-Review', -2, 2),
91 'VRFY': ('Verified', -2, 2)}
James E. Blairb0fcae42012-07-17 11:12:10 -070092
Monty Taylorbc758832013-06-17 17:22:42 -040093 def __init__(self, gerrit, number, project, branch, subject,
94 status='NEW', upstream_root=None):
James E. Blair8cc15a82012-08-01 11:17:57 -070095 self.gerrit = gerrit
James E. Blaird466dc42012-07-31 10:42:56 -070096 self.reported = 0
James E. Blair8c803f82012-07-31 16:25:42 -070097 self.queried = 0
James E. Blairb0fcae42012-07-17 11:12:10 -070098 self.patchsets = []
James E. Blairb0fcae42012-07-17 11:12:10 -070099 self.number = number
100 self.project = project
101 self.branch = branch
102 self.subject = subject
103 self.latest_patchset = 0
James E. Blair8c803f82012-07-31 16:25:42 -0700104 self.depends_on_change = None
105 self.needed_by_changes = []
James E. Blair127bc182012-08-28 15:55:15 -0700106 self.fail_merge = False
James E. Blair42f74822013-05-14 15:18:03 -0700107 self.messages = []
James E. Blairb0fcae42012-07-17 11:12:10 -0700108 self.data = {
109 'branch': branch,
110 'comments': [],
111 'commitMessage': subject,
112 'createdOn': time.time(),
James E. Blair8cc15a82012-08-01 11:17:57 -0700113 'id': 'I' + random_sha1(),
James E. Blairb0fcae42012-07-17 11:12:10 -0700114 'lastUpdated': time.time(),
115 'number': str(number),
116 'open': True,
117 'owner': {'email': 'user@example.com',
118 'name': 'User Name',
119 'username': 'username'},
120 'patchSets': self.patchsets,
121 'project': project,
122 'status': status,
123 'subject': subject,
James E. Blair8c803f82012-07-31 16:25:42 -0700124 'submitRecords': [],
James E. Blairb0fcae42012-07-17 11:12:10 -0700125 'url': 'https://hostname/%s' % number}
126
Monty Taylorbc758832013-06-17 17:22:42 -0400127 self.upstream_root = upstream_root
James E. Blairb0fcae42012-07-17 11:12:10 -0700128 self.addPatchset()
James E. Blair8c803f82012-07-31 16:25:42 -0700129 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700130
Monty Taylorbc758832013-06-17 17:22:42 -0400131 def add_fake_change_to_repo(self, msg, fn, large):
132 path = os.path.join(self.upstream_root, self.project)
133 repo = git.Repo(path)
134 ref = ChangeReference.create(repo, '1/%s/%s' % (self.number,
135 self.latest_patchset),
136 'refs/tags/init')
137 repo.head.reference = ref
138 repo.head.reset(index=True, working_tree=True)
139 repo.git.clean('-x', '-f', '-d')
140
141 path = os.path.join(self.upstream_root, self.project)
142 if not large:
143 fn = os.path.join(path, fn)
144 f = open(fn, 'w')
145 f.write("test %s %s %s\n" %
146 (self.branch, self.number, self.latest_patchset))
147 f.close()
148 repo.index.add([fn])
149 else:
150 for fni in range(100):
151 fn = os.path.join(path, str(fni))
152 f = open(fn, 'w')
153 for ci in range(4096):
154 f.write(random.choice(string.printable))
155 f.close()
156 repo.index.add([fn])
157
James E. Blair287c06d2013-07-24 10:39:30 -0700158 r = repo.index.commit(msg)
159 repo.head.reference = 'master'
160 repo.head.reset(index=True, working_tree=True)
161 repo.git.clean('-x', '-f', '-d')
James E. Blairac2c3242014-01-24 13:38:51 -0800162 repo.heads['master'].checkout()
James E. Blair287c06d2013-07-24 10:39:30 -0700163 return r
Monty Taylorbc758832013-06-17 17:22:42 -0400164
James E. Blair70c71582013-03-06 08:50:50 -0800165 def addPatchset(self, files=[], large=False):
James E. Blairb0fcae42012-07-17 11:12:10 -0700166 self.latest_patchset += 1
James E. Blairdaabed22012-08-15 15:38:57 -0700167 if files:
168 fn = files[0]
169 else:
170 fn = '%s-%s' % (self.branch, self.number)
171 msg = self.subject + '-' + str(self.latest_patchset)
Monty Taylorbc758832013-06-17 17:22:42 -0400172 c = self.add_fake_change_to_repo(msg, fn, large)
James E. Blair70c71582013-03-06 08:50:50 -0800173 ps_files = [{'file': '/COMMIT_MSG',
174 'type': 'ADDED'},
175 {'file': 'README',
176 'type': 'MODIFIED'}]
177 for f in files:
178 ps_files.append({'file': f, 'type': 'ADDED'})
James E. Blairb0fcae42012-07-17 11:12:10 -0700179 d = {'approvals': [],
180 'createdOn': time.time(),
James E. Blair70c71582013-03-06 08:50:50 -0800181 'files': ps_files,
James E. Blair8c803f82012-07-31 16:25:42 -0700182 'number': str(self.latest_patchset),
James E. Blairb0fcae42012-07-17 11:12:10 -0700183 'ref': 'refs/changes/1/%s/%s' % (self.number,
184 self.latest_patchset),
James E. Blairdaabed22012-08-15 15:38:57 -0700185 'revision': c.hexsha,
James E. Blairb0fcae42012-07-17 11:12:10 -0700186 'uploader': {'email': 'user@example.com',
187 'name': 'User name',
188 'username': 'user'}}
189 self.data['currentPatchSet'] = d
190 self.patchsets.append(d)
James E. Blair8c803f82012-07-31 16:25:42 -0700191 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700192
James E. Blaire0487072012-08-29 17:38:31 -0700193 def getPatchsetCreatedEvent(self, patchset):
194 event = {"type": "patchset-created",
195 "change": {"project": self.project,
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800196 "branch": self.branch,
197 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
198 "number": str(self.number),
199 "subject": self.subject,
200 "owner": {"name": "User Name"},
201 "url": "https://hostname/3"},
James E. Blaire0487072012-08-29 17:38:31 -0700202 "patchSet": self.patchsets[patchset - 1],
203 "uploader": {"name": "User Name"}}
204 return event
205
James E. Blair42f74822013-05-14 15:18:03 -0700206 def getChangeRestoredEvent(self):
207 event = {"type": "change-restored",
208 "change": {"project": self.project,
209 "branch": self.branch,
210 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
211 "number": str(self.number),
212 "subject": self.subject,
213 "owner": {"name": "User Name"},
214 "url": "https://hostname/3"},
215 "restorer": {"name": "User Name"},
216 "reason": ""}
217 return event
218
James E. Blairc053d022014-01-22 14:57:33 -0800219 def addApproval(self, category, value, username='jenkins',
220 granted_on=None):
221 if not granted_on:
222 granted_on = time.time()
James E. Blair8c803f82012-07-31 16:25:42 -0700223 approval = {'description': self.categories[category][0],
224 'type': category,
James E. Blairc053d022014-01-22 14:57:33 -0800225 'value': str(value),
James E. Blair64ff4ef2014-01-24 13:50:23 -0800226 'by': {
227 'username': username,
228 'email': username + '@example.com',
229 },
James E. Blairc053d022014-01-22 14:57:33 -0800230 'grantedOn': int(granted_on)}
231 for i, x in enumerate(self.patchsets[-1]['approvals'][:]):
James E. Blair64ff4ef2014-01-24 13:50:23 -0800232 if x['by']['username'] == username and x['type'] == category:
James E. Blairc053d022014-01-22 14:57:33 -0800233 del self.patchsets[-1]['approvals'][i]
James E. Blair8c803f82012-07-31 16:25:42 -0700234 self.patchsets[-1]['approvals'].append(approval)
235 event = {'approvals': [approval],
James E. Blairb0fcae42012-07-17 11:12:10 -0700236 'author': {'email': 'user@example.com',
237 'name': 'User Name',
238 'username': 'username'},
239 'change': {'branch': self.branch,
240 'id': 'Iaa69c46accf97d0598111724a38250ae76a22c87',
241 'number': str(self.number),
242 'owner': {'email': 'user@example.com',
243 'name': 'User Name',
244 'username': 'username'},
245 'project': self.project,
246 'subject': self.subject,
247 'topic': 'master',
248 'url': 'https://hostname/459'},
249 'comment': '',
250 'patchSet': self.patchsets[-1],
251 'type': 'comment-added'}
James E. Blair8c803f82012-07-31 16:25:42 -0700252 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700253 return json.loads(json.dumps(event))
254
James E. Blair8c803f82012-07-31 16:25:42 -0700255 def getSubmitRecords(self):
256 status = {}
257 for cat in self.categories.keys():
258 status[cat] = 0
259
260 for a in self.patchsets[-1]['approvals']:
261 cur = status[a['type']]
262 cat_min, cat_max = self.categories[a['type']][1:]
263 new = int(a['value'])
264 if new == cat_min:
265 cur = new
266 elif abs(new) > abs(cur):
267 cur = new
268 status[a['type']] = cur
269
270 labels = []
271 ok = True
272 for typ, cat in self.categories.items():
273 cur = status[typ]
274 cat_min, cat_max = cat[1:]
275 if cur == cat_min:
276 value = 'REJECT'
277 ok = False
278 elif cur == cat_max:
279 value = 'OK'
280 else:
281 value = 'NEED'
282 ok = False
283 labels.append({'label': cat[0], 'status': value})
284 if ok:
285 return [{'status': 'OK'}]
286 return [{'status': 'NOT_READY',
287 'labels': labels}]
288
289 def setDependsOn(self, other, patchset):
290 self.depends_on_change = other
291 d = {'id': other.data['id'],
292 'number': other.data['number'],
293 'ref': other.patchsets[patchset - 1]['ref']
294 }
295 self.data['dependsOn'] = [d]
296
297 other.needed_by_changes.append(self)
298 needed = other.data.get('neededBy', [])
299 d = {'id': self.data['id'],
300 'number': self.data['number'],
301 'ref': self.patchsets[patchset - 1]['ref'],
302 'revision': self.patchsets[patchset - 1]['revision']
303 }
304 needed.append(d)
305 other.data['neededBy'] = needed
306
James E. Blairb0fcae42012-07-17 11:12:10 -0700307 def query(self):
James E. Blair8c803f82012-07-31 16:25:42 -0700308 self.queried += 1
309 d = self.data.get('dependsOn')
310 if d:
311 d = d[0]
312 if (self.depends_on_change.patchsets[-1]['ref'] == d['ref']):
313 d['isCurrentPatchSet'] = True
314 else:
315 d['isCurrentPatchSet'] = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700316 return json.loads(json.dumps(self.data))
317
318 def setMerged(self):
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800319 if (self.depends_on_change and
320 self.depends_on_change.data['status'] != 'MERGED'):
James E. Blaircaec0c52012-08-22 14:52:22 -0700321 return
James E. Blair127bc182012-08-28 15:55:15 -0700322 if self.fail_merge:
323 return
James E. Blairb0fcae42012-07-17 11:12:10 -0700324 self.data['status'] = 'MERGED'
325 self.open = False
James E. Blairdaabed22012-08-15 15:38:57 -0700326
Monty Taylorbc758832013-06-17 17:22:42 -0400327 path = os.path.join(self.upstream_root, self.project)
James E. Blairdaabed22012-08-15 15:38:57 -0700328 repo = git.Repo(path)
329 repo.heads[self.branch].commit = \
330 repo.commit(self.patchsets[-1]['revision'])
James E. Blairb0fcae42012-07-17 11:12:10 -0700331
James E. Blaird466dc42012-07-31 10:42:56 -0700332 def setReported(self):
333 self.reported += 1
334
James E. Blairb0fcae42012-07-17 11:12:10 -0700335
336class FakeGerrit(object):
337 def __init__(self, *args, **kw):
338 self.event_queue = Queue.Queue()
339 self.fixture_dir = os.path.join(FIXTURE_DIR, 'gerrit')
340 self.change_number = 0
341 self.changes = {}
342
343 def addFakeChange(self, project, branch, subject):
344 self.change_number += 1
Monty Taylorbc758832013-06-17 17:22:42 -0400345 c = FakeChange(self, self.change_number, project, branch, subject,
346 upstream_root=self.upstream_root)
James E. Blairb0fcae42012-07-17 11:12:10 -0700347 self.changes[self.change_number] = c
348 return c
349
350 def addEvent(self, data):
351 return self.event_queue.put(data)
352
353 def getEvent(self):
354 return self.event_queue.get()
355
356 def eventDone(self):
357 self.event_queue.task_done()
358
359 def review(self, project, changeid, message, action):
James E. Blaird466dc42012-07-31 10:42:56 -0700360 number, ps = changeid.split(',')
361 change = self.changes[int(number)]
James E. Blair42f74822013-05-14 15:18:03 -0700362 change.messages.append(message)
James E. Blairb0fcae42012-07-17 11:12:10 -0700363 if 'submit' in action:
James E. Blairb0fcae42012-07-17 11:12:10 -0700364 change.setMerged()
James E. Blaird466dc42012-07-31 10:42:56 -0700365 if message:
366 change.setReported()
James E. Blairb0fcae42012-07-17 11:12:10 -0700367
368 def query(self, number):
James E. Blairad28e912013-11-27 10:43:22 -0800369 change = self.changes.get(int(number))
370 if change:
371 return change.query()
372 return {}
James E. Blairb0fcae42012-07-17 11:12:10 -0700373
374 def startWatching(self, *args, **kw):
375 pass
376
377
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700378class BuildHistory(object):
379 def __init__(self, **kw):
380 self.__dict__.update(kw)
James E. Blairb0fcae42012-07-17 11:12:10 -0700381
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700382 def __repr__(self):
383 return ("<Completed build, result: %s name: %s #%s changes: %s>" %
384 (self.result, self.name, self.number, self.changes))
James E. Blairb0fcae42012-07-17 11:12:10 -0700385
386
James E. Blair8cc15a82012-08-01 11:17:57 -0700387class FakeURLOpener(object):
Monty Taylorbc758832013-06-17 17:22:42 -0400388 def __init__(self, upstream_root, fake_gerrit, url):
389 self.upstream_root = upstream_root
James E. Blair8cc15a82012-08-01 11:17:57 -0700390 self.fake_gerrit = fake_gerrit
391 self.url = url
392
393 def read(self):
394 res = urlparse.urlparse(self.url)
395 path = res.path
396 project = '/'.join(path.split('/')[2:-2])
James E. Blair35956c52012-09-17 22:13:36 +0200397 ret = '001e# service=git-upload-pack\n'
398 ret += ('000000a31270149696713ba7e06f1beb760f20d359c4abed HEAD\x00'
399 'multi_ack thin-pack side-band side-band-64k ofs-delta '
400 'shallow no-progress include-tag multi_ack_detailed no-done\n')
Monty Taylorbc758832013-06-17 17:22:42 -0400401 path = os.path.join(self.upstream_root, project)
James E. Blairdaabed22012-08-15 15:38:57 -0700402 repo = git.Repo(path)
403 for ref in repo.refs:
James E. Blair35956c52012-09-17 22:13:36 +0200404 r = ref.object.hexsha + ' ' + ref.path + '\n'
405 ret += '%04x%s' % (len(r) + 4, r)
406 ret += '0000'
James E. Blair8cc15a82012-08-01 11:17:57 -0700407 return ret
408
409
James E. Blair4886cc12012-07-18 15:39:41 -0700410class FakeGerritTrigger(zuul.trigger.gerrit.Gerrit):
Joshua Hesketh1879cf72013-08-19 14:13:15 +1000411 name = 'gerrit'
412
Monty Taylorbc758832013-06-17 17:22:42 -0400413 def __init__(self, upstream_root, *args):
414 super(FakeGerritTrigger, self).__init__(*args)
415 self.upstream_root = upstream_root
416
James E. Blair4886cc12012-07-18 15:39:41 -0700417 def getGitUrl(self, project):
Monty Taylorbc758832013-06-17 17:22:42 -0400418 return os.path.join(self.upstream_root, project.name)
James E. Blair4886cc12012-07-18 15:39:41 -0700419
420
James E. Blair412e5582013-04-22 15:50:12 -0700421class FakeStatsd(threading.Thread):
422 def __init__(self):
423 threading.Thread.__init__(self)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400424 self.daemon = True
James E. Blair412e5582013-04-22 15:50:12 -0700425 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
426 self.sock.bind(('', 0))
427 self.port = self.sock.getsockname()[1]
428 self.wake_read, self.wake_write = os.pipe()
429 self.stats = []
430
431 def run(self):
432 while True:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700433 poll = select.poll()
434 poll.register(self.sock, select.POLLIN)
435 poll.register(self.wake_read, select.POLLIN)
436 ret = poll.poll()
437 for (fd, event) in ret:
438 if fd == self.sock.fileno():
James E. Blair412e5582013-04-22 15:50:12 -0700439 data = self.sock.recvfrom(1024)
440 if not data:
441 return
442 self.stats.append(data[0])
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700443 if fd == self.wake_read:
James E. Blair412e5582013-04-22 15:50:12 -0700444 return
445
446 def stop(self):
447 os.write(self.wake_write, '1\n')
448
449
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700450class FakeBuild(threading.Thread):
451 log = logging.getLogger("zuul.test")
452
453 def __init__(self, worker, job, number, node):
454 threading.Thread.__init__(self)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400455 self.daemon = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700456 self.worker = worker
457 self.job = job
458 self.name = job.name.split(':')[1]
459 self.number = number
460 self.node = node
461 self.parameters = json.loads(job.arguments)
462 self.unique = self.parameters['ZUUL_UUID']
463 self.wait_condition = threading.Condition()
464 self.waiting = False
465 self.aborted = False
466 self.created = time.time()
467 self.description = ''
James E. Blair4a28a882013-08-23 15:17:33 -0700468 self.run_error = False
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700469
470 def release(self):
471 self.wait_condition.acquire()
472 self.wait_condition.notify()
473 self.waiting = False
474 self.log.debug("Build %s released" % self.unique)
475 self.wait_condition.release()
476
477 def isWaiting(self):
478 self.wait_condition.acquire()
479 if self.waiting:
480 ret = True
481 else:
482 ret = False
483 self.wait_condition.release()
484 return ret
485
486 def _wait(self):
487 self.wait_condition.acquire()
488 self.waiting = True
489 self.log.debug("Build %s waiting" % self.unique)
490 self.wait_condition.wait()
491 self.wait_condition.release()
492
493 def run(self):
494 data = {
James E. Blair3c483cf2013-06-04 16:30:43 -0700495 'url': 'https://server/job/%s/%s/' % (self.name, self.number),
496 'name': self.name,
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700497 'number': self.number,
James E. Blair3c483cf2013-06-04 16:30:43 -0700498 'manager': self.worker.worker_id,
Paul Belangerec49b4c2013-07-20 20:32:20 -0400499 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700500
501 self.job.sendWorkData(json.dumps(data))
502 self.job.sendWorkStatus(0, 100)
503
504 if self.worker.hold_jobs_in_build:
505 self._wait()
506 self.log.debug("Build %s continuing" % self.unique)
507
508 self.worker.lock.acquire()
509
510 result = 'SUCCESS'
511 if (('ZUUL_REF' in self.parameters) and
512 self.worker.shouldFailTest(self.name,
513 self.parameters['ZUUL_REF'])):
514 result = 'FAILURE'
515 if self.aborted:
516 result = 'ABORTED'
517
James E. Blair4a28a882013-08-23 15:17:33 -0700518 if self.run_error:
519 work_fail = True
520 result = 'RUN_ERROR'
521 else:
522 data['result'] = result
523 work_fail = False
524
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700525 changes = None
526 if 'ZUUL_CHANGE_IDS' in self.parameters:
527 changes = self.parameters['ZUUL_CHANGE_IDS']
528
529 self.worker.build_history.append(
530 BuildHistory(name=self.name, number=self.number,
531 result=result, changes=changes, node=self.node,
James E. Blair64ed6f22013-07-10 14:07:23 -0700532 uuid=self.unique, description=self.description,
533 pipeline=self.parameters['ZUUL_PIPELINE'])
Paul Belangerec49b4c2013-07-20 20:32:20 -0400534 )
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700535
James E. Blair4a28a882013-08-23 15:17:33 -0700536 self.job.sendWorkData(json.dumps(data))
537 if work_fail:
538 self.job.sendWorkFail()
539 else:
540 self.job.sendWorkComplete(json.dumps(data))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700541 del self.worker.gearman_jobs[self.job.unique]
542 self.worker.running_builds.remove(self)
543 self.worker.lock.release()
544
545
546class FakeWorker(gear.Worker):
Monty Taylorbc758832013-06-17 17:22:42 -0400547 def __init__(self, worker_id, test):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700548 super(FakeWorker, self).__init__(worker_id)
549 self.gearman_jobs = {}
550 self.build_history = []
551 self.running_builds = []
552 self.build_counter = 0
553 self.fail_tests = {}
Monty Taylorbc758832013-06-17 17:22:42 -0400554 self.test = test
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700555
556 self.hold_jobs_in_build = False
557 self.lock = threading.Lock()
558 self.__work_thread = threading.Thread(target=self.work)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400559 self.__work_thread.daemon = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700560 self.__work_thread.start()
561
562 def handleJob(self, job):
563 parts = job.name.split(":")
564 cmd = parts[0]
565 name = parts[1]
566 if len(parts) > 2:
567 node = parts[2]
568 else:
569 node = None
570 if cmd == 'build':
571 self.handleBuild(job, name, node)
572 elif cmd == 'stop':
573 self.handleStop(job, name)
574 elif cmd == 'set_description':
575 self.handleSetDescription(job, name)
576
577 def handleBuild(self, job, name, node):
578 build = FakeBuild(self, job, self.build_counter, node)
579 job.build = build
580 self.gearman_jobs[job.unique] = job
581 self.build_counter += 1
582
583 self.running_builds.append(build)
584 build.start()
585
586 def handleStop(self, job, name):
587 self.log.debug("handle stop")
James E. Blair3c483cf2013-06-04 16:30:43 -0700588 parameters = json.loads(job.arguments)
589 name = parameters['name']
590 number = parameters['number']
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700591 for build in self.running_builds:
James E. Blair3c483cf2013-06-04 16:30:43 -0700592 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700593 build.aborted = True
594 build.release()
595 job.sendWorkComplete()
596 return
597 job.sendWorkFail()
598
599 def handleSetDescription(self, job, name):
600 self.log.debug("handle set description")
601 parameters = json.loads(job.arguments)
James E. Blair3c483cf2013-06-04 16:30:43 -0700602 name = parameters['name']
603 number = parameters['number']
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700604 descr = parameters['html_description']
605 for build in self.running_builds:
James E. Blair3c483cf2013-06-04 16:30:43 -0700606 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700607 build.description = descr
608 job.sendWorkComplete()
609 return
610 for build in self.build_history:
James E. Blair3c483cf2013-06-04 16:30:43 -0700611 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700612 build.description = descr
613 job.sendWorkComplete()
614 return
615 job.sendWorkFail()
616
617 def work(self):
618 while self.running:
619 try:
620 job = self.getJob()
621 except gear.InterruptedError:
622 continue
623 try:
624 self.handleJob(job)
625 except:
626 self.log.exception("Worker exception:")
627
628 def addFailTest(self, name, change):
629 l = self.fail_tests.get(name, [])
630 l.append(change)
631 self.fail_tests[name] = l
632
633 def shouldFailTest(self, name, ref):
634 l = self.fail_tests.get(name, [])
635 for change in l:
Monty Taylorbc758832013-06-17 17:22:42 -0400636 if self.test.ref_has_change(ref, change):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700637 return True
638 return False
639
640 def release(self, regex=None):
641 builds = self.running_builds[:]
642 self.log.debug("releasing build %s (%s)" % (regex,
James E. Blair78e31b32013-07-09 09:11:34 -0700643 len(self.running_builds)))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700644 for build in builds:
645 if not regex or re.match(regex, build.name):
646 self.log.debug("releasing build %s" %
647 (build.parameters['ZUUL_UUID']))
648 build.release()
649 else:
650 self.log.debug("not releasing build %s" %
651 (build.parameters['ZUUL_UUID']))
652 self.log.debug("done releasing builds %s (%s)" %
653 (regex, len(self.running_builds)))
654
655
656class FakeGearmanServer(gear.Server):
657 def __init__(self):
658 self.hold_jobs_in_queue = False
659 super(FakeGearmanServer, self).__init__(0)
660
661 def getJobForConnection(self, connection, peek=False):
James E. Blair701c5b42013-06-06 09:34:59 -0700662 for queue in [self.high_queue, self.normal_queue, self.low_queue]:
663 for job in queue:
664 if not hasattr(job, 'waiting'):
665 if job.name.startswith('build:'):
666 job.waiting = self.hold_jobs_in_queue
667 else:
668 job.waiting = False
669 if job.waiting:
670 continue
671 if job.name in connection.functions:
672 if not peek:
673 queue.remove(job)
James E. Blaire2819012013-06-28 17:17:26 -0400674 connection.related_jobs[job.handle] = job
675 job.worker_connection = connection
676 job.running = True
James E. Blair701c5b42013-06-06 09:34:59 -0700677 return job
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700678 return None
679
680 def release(self, regex=None):
681 released = False
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("releasing queued job %s (%s)" % (regex, qlen))
James E. Blairdda6c912013-07-29 14:12:12 -0700685 for job in self.getQueue():
686 cmd, name = job.name.split(':')
687 if cmd != 'build':
688 continue
689 if not regex or re.match(regex, name):
690 self.log.debug("releasing queued job %s" %
691 job.unique)
692 job.waiting = False
693 released = True
694 else:
695 self.log.debug("not releasing queued job %s" %
696 job.unique)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700697 if released:
698 self.wakeConnections()
James E. Blair701c5b42013-06-06 09:34:59 -0700699 qlen = (len(self.high_queue) + len(self.normal_queue) +
700 len(self.low_queue))
701 self.log.debug("done releasing queued jobs %s (%s)" % (regex, qlen))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700702
703
Joshua Hesketh5fea8672013-08-19 17:32:01 +1000704class FakeSMTP(object):
705 log = logging.getLogger('zuul.FakeSMTP')
Joshua Hesketh5fea8672013-08-19 17:32:01 +1000706
James E. Blairff80a2f2013-12-27 13:24:06 -0800707 def __init__(self, messages, server, port):
Joshua Hesketh5fea8672013-08-19 17:32:01 +1000708 self.server = server
709 self.port = port
James E. Blairff80a2f2013-12-27 13:24:06 -0800710 self.messages = messages
Joshua Hesketh5fea8672013-08-19 17:32:01 +1000711
712 def sendmail(self, from_email, to_email, msg):
713 self.log.info("Sending email from %s, to %s, with msg %s" % (
714 from_email, to_email, msg))
715
716 headers = msg.split('\n\n', 1)[0]
717 body = msg.split('\n\n', 1)[1]
718
James E. Blairff80a2f2013-12-27 13:24:06 -0800719 self.messages.append(dict(
Joshua Hesketh5fea8672013-08-19 17:32:01 +1000720 from_email=from_email,
721 to_email=to_email,
722 msg=msg,
723 headers=headers,
724 body=body,
725 ))
726
727 return True
728
729 def quit(self):
730 return True
731
732
Monty Taylorbc758832013-06-17 17:22:42 -0400733class TestScheduler(testtools.TestCase):
James E. Blairb0fcae42012-07-17 11:12:10 -0700734 log = logging.getLogger("zuul.test")
735
736 def setUp(self):
Monty Taylorbc758832013-06-17 17:22:42 -0400737 super(TestScheduler, self).setUp()
738 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
739 try:
740 test_timeout = int(test_timeout)
741 except ValueError:
742 # If timeout value is invalid do not set a timeout.
743 test_timeout = 0
744 if test_timeout > 0:
James E. Blairff80a2f2013-12-27 13:24:06 -0800745 self.useFixture(fixtures.Timeout(test_timeout, gentle=False))
Monty Taylorbc758832013-06-17 17:22:42 -0400746
747 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
748 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
749 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
750 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
751 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
752 os.environ.get('OS_STDERR_CAPTURE') == '1'):
753 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
754 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Monty Taylore6a6c402013-07-02 09:25:55 -0700755 if (os.environ.get('OS_LOG_CAPTURE') == 'True' or
756 os.environ.get('OS_LOG_CAPTURE') == '1'):
James E. Blaire2819012013-06-28 17:17:26 -0400757 self.useFixture(fixtures.FakeLogger(
758 level=logging.DEBUG,
759 format='%(asctime)s %(name)-32s '
760 '%(levelname)-8s %(message)s'))
Monty Taylor5a5a95c2013-07-03 13:39:14 -0700761 tmp_root = self.useFixture(fixtures.TempDir(
762 rootdir=os.environ.get("ZUUL_TEST_ROOT"))).path
Monty Taylorbc758832013-06-17 17:22:42 -0400763 self.test_root = os.path.join(tmp_root, "zuul-test")
764 self.upstream_root = os.path.join(self.test_root, "upstream")
765 self.git_root = os.path.join(self.test_root, "git")
766
767 CONFIG.set('zuul', 'git_dir', self.git_root)
768 if os.path.exists(self.test_root):
769 shutil.rmtree(self.test_root)
770 os.makedirs(self.test_root)
771 os.makedirs(self.upstream_root)
772 os.makedirs(self.git_root)
James E. Blair4886cc12012-07-18 15:39:41 -0700773
774 # For each project in config:
Monty Taylorbc758832013-06-17 17:22:42 -0400775 self.init_repo("org/project")
776 self.init_repo("org/project1")
777 self.init_repo("org/project2")
778 self.init_repo("org/project3")
779 self.init_repo("org/one-job-project")
780 self.init_repo("org/nonvoting-project")
781 self.init_repo("org/templated-project")
James E. Blair3e98c022013-12-16 15:25:38 -0800782 self.init_repo("org/layered-project")
Monty Taylorbc758832013-06-17 17:22:42 -0400783 self.init_repo("org/node-project")
James E. Blair6736beb2013-07-11 15:18:15 -0700784 self.init_repo("org/conflict-project")
James E. Blair412e5582013-04-22 15:50:12 -0700785
786 self.statsd = FakeStatsd()
787 os.environ['STATSD_HOST'] = 'localhost'
788 os.environ['STATSD_PORT'] = str(self.statsd.port)
789 self.statsd.start()
790 # the statsd client object is configured in the statsd module import
791 reload(statsd)
792 reload(zuul.scheduler)
793
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700794 self.gearman_server = FakeGearmanServer()
795
796 self.config = ConfigParser.ConfigParser()
797 cfg = StringIO()
798 CONFIG.write(cfg)
799 cfg.seek(0)
800 self.config.readfp(cfg)
801 self.config.set('gearman', 'port', str(self.gearman_server.port))
802
Monty Taylorbc758832013-06-17 17:22:42 -0400803 self.worker = FakeWorker('fake_worker', self)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700804 self.worker.addServer('127.0.0.1', self.gearman_server.port)
805 self.gearman_server.worker = self.worker
806
James E. Blairb0fcae42012-07-17 11:12:10 -0700807 self.sched = zuul.scheduler.Scheduler()
808
James E. Blair8cc15a82012-08-01 11:17:57 -0700809 def URLOpenerFactory(*args, **kw):
810 args = [self.fake_gerrit] + list(args)
Monty Taylorbc758832013-06-17 17:22:42 -0400811 return FakeURLOpener(self.upstream_root, *args, **kw)
James E. Blair8cc15a82012-08-01 11:17:57 -0700812
James E. Blair8cc15a82012-08-01 11:17:57 -0700813 urllib2.urlopen = URLOpenerFactory
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700814 self.launcher = zuul.launcher.gearman.Gearman(self.config, self.sched)
James E. Blairb0fcae42012-07-17 11:12:10 -0700815
James E. Blairff80a2f2013-12-27 13:24:06 -0800816 self.smtp_messages = []
817
818 def FakeSMTPFactory(*args, **kw):
819 args = [self.smtp_messages] + list(args)
820 return FakeSMTP(*args, **kw)
821
James E. Blairb0fcae42012-07-17 11:12:10 -0700822 zuul.lib.gerrit.Gerrit = FakeGerrit
James E. Blairff80a2f2013-12-27 13:24:06 -0800823 self.useFixture(fixtures.MonkeyPatch('smtplib.SMTP', FakeSMTPFactory))
James E. Blairb0fcae42012-07-17 11:12:10 -0700824
Monty Taylorbc758832013-06-17 17:22:42 -0400825 self.gerrit = FakeGerritTrigger(
826 self.upstream_root, self.config, self.sched)
James E. Blair8cc15a82012-08-01 11:17:57 -0700827 self.gerrit.replication_timeout = 1.5
828 self.gerrit.replication_retry_interval = 0.5
James E. Blairb0fcae42012-07-17 11:12:10 -0700829 self.fake_gerrit = self.gerrit.gerrit
Monty Taylorbc758832013-06-17 17:22:42 -0400830 self.fake_gerrit.upstream_root = self.upstream_root
James E. Blairb0fcae42012-07-17 11:12:10 -0700831
James E. Blair1843a552013-07-03 14:19:52 -0700832 self.webapp = zuul.webapp.WebApp(self.sched, port=0)
James E. Blairad28e912013-11-27 10:43:22 -0800833 self.rpc = zuul.rpclistener.RPCListener(self.config, self.sched)
James E. Blair1843a552013-07-03 14:19:52 -0700834
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700835 self.sched.setLauncher(self.launcher)
James E. Blair6c358e72013-07-29 17:06:47 -0700836 self.sched.registerTrigger(self.gerrit)
James E. Blair63bb0ef2013-07-29 17:14:51 -0700837 self.timer = zuul.trigger.timer.Timer(self.config, self.sched)
838 self.sched.registerTrigger(self.timer)
James E. Blairb0fcae42012-07-17 11:12:10 -0700839
Joshua Hesketh1879cf72013-08-19 14:13:15 +1000840 self.sched.registerReporter(
841 zuul.reporter.gerrit.Reporter(self.gerrit))
Joshua Hesketh5fea8672013-08-19 17:32:01 +1000842 self.smtp_reporter = zuul.reporter.smtp.Reporter(
843 self.config.get('smtp', 'default_from'),
844 self.config.get('smtp', 'default_to'),
845 self.config.get('smtp', 'server'))
846 self.sched.registerReporter(self.smtp_reporter)
Joshua Hesketh1879cf72013-08-19 14:13:15 +1000847
James E. Blairb0fcae42012-07-17 11:12:10 -0700848 self.sched.start()
849 self.sched.reconfigure(self.config)
850 self.sched.resume()
James E. Blair1843a552013-07-03 14:19:52 -0700851 self.webapp.start()
James E. Blairad28e912013-11-27 10:43:22 -0800852 self.rpc.start()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700853 self.launcher.gearman.waitForServer()
854 self.registerJobs()
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400855 self.builds = self.worker.running_builds
856 self.history = self.worker.build_history
James E. Blairb0fcae42012-07-17 11:12:10 -0700857
James E. Blairfee8d652013-06-07 08:57:52 -0700858 self.addCleanup(self.assertFinalState)
859 self.addCleanup(self.shutdown)
860
861 def assertFinalState(self):
862 # Make sure that the change cache is cleared
James E. Blair6c358e72013-07-29 17:06:47 -0700863 self.assertEqual(len(self.gerrit._change_cache.keys()), 0)
Clark Boylan4ba48d92013-11-11 18:03:53 -0800864 # Make sure that git.Repo objects have been garbage collected.
865 repos = []
866 gc.collect()
867 for obj in gc.get_objects():
868 if isinstance(obj, git.Repo):
869 repos.append(obj)
870 self.assertEqual(len(repos), 0)
James E. Blairfee8d652013-06-07 08:57:52 -0700871 self.assertEmptyQueues()
872
873 def shutdown(self):
874 self.log.debug("Shutting down after tests")
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700875 self.launcher.stop()
876 self.worker.shutdown()
877 self.gearman_server.shutdown()
James E. Blairb0fcae42012-07-17 11:12:10 -0700878 self.gerrit.stop()
James E. Blair63bb0ef2013-07-29 17:14:51 -0700879 self.timer.stop()
James E. Blairb0fcae42012-07-17 11:12:10 -0700880 self.sched.stop()
881 self.sched.join()
James E. Blair412e5582013-04-22 15:50:12 -0700882 self.statsd.stop()
883 self.statsd.join()
James E. Blair1843a552013-07-03 14:19:52 -0700884 self.webapp.stop()
885 self.webapp.join()
James E. Blairad28e912013-11-27 10:43:22 -0800886 self.rpc.stop()
887 self.rpc.join()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700888 threads = threading.enumerate()
889 if len(threads) > 1:
890 self.log.error("More than one thread is running: %s" % threads)
Monty Taylorbc758832013-06-17 17:22:42 -0400891 super(TestScheduler, self).tearDown()
892
893 def init_repo(self, project):
894 parts = project.split('/')
895 path = os.path.join(self.upstream_root, *parts[:-1])
896 if not os.path.exists(path):
897 os.makedirs(path)
898 path = os.path.join(self.upstream_root, project)
899 repo = git.Repo.init(path)
900
901 repo.config_writer().set_value('user', 'email', 'user@example.com')
902 repo.config_writer().set_value('user', 'name', 'User Name')
903 repo.config_writer().write()
904
905 fn = os.path.join(path, 'README')
906 f = open(fn, 'w')
907 f.write("test\n")
908 f.close()
909 repo.index.add([fn])
910 repo.index.commit('initial commit')
911 master = repo.create_head('master')
912 repo.create_tag('init')
913
914 mp = repo.create_head('mp')
915 repo.head.reference = mp
916 f = open(fn, 'a')
917 f.write("test mp\n")
918 f.close()
919 repo.index.add([fn])
920 repo.index.commit('mp commit')
921
922 repo.head.reference = master
923 repo.head.reset(index=True, working_tree=True)
924 repo.git.clean('-x', '-f', '-d')
925
926 def ref_has_change(self, ref, change):
927 path = os.path.join(self.git_root, change.project)
928 repo = git.Repo(path)
929 for commit in repo.iter_commits(ref):
930 if commit.message.strip() == ('%s-1' % change.subject):
931 return True
932 return False
933
934 def job_has_changes(self, *args):
935 job = args[0]
936 commits = args[1:]
937 if isinstance(job, FakeBuild):
938 parameters = job.parameters
939 else:
940 parameters = json.loads(job.arguments)
941 project = parameters['ZUUL_PROJECT']
942 path = os.path.join(self.git_root, project)
943 repo = git.Repo(path)
944 ref = parameters['ZUUL_REF']
945 sha = parameters['ZUUL_COMMIT']
946 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
947 repo_shas = [c.hexsha for c in repo.iter_commits(ref)]
948 commit_messages = ['%s-1' % commit.subject for commit in commits]
James E. Blairac2c3242014-01-24 13:38:51 -0800949 self.log.debug("Checking if job %s has changes; commit_messages %s;"
950 " repo_messages %s; sha %s" % (job, commit_messages,
951 repo_messages, sha))
Monty Taylorbc758832013-06-17 17:22:42 -0400952 for msg in commit_messages:
953 if msg not in repo_messages:
James E. Blairac2c3242014-01-24 13:38:51 -0800954 self.log.debug(" messages do not match")
Monty Taylorbc758832013-06-17 17:22:42 -0400955 return False
956 if repo_shas[0] != sha:
James E. Blairac2c3242014-01-24 13:38:51 -0800957 self.log.debug(" sha does not match")
Monty Taylorbc758832013-06-17 17:22:42 -0400958 return False
James E. Blairac2c3242014-01-24 13:38:51 -0800959 self.log.debug(" OK")
Monty Taylorbc758832013-06-17 17:22:42 -0400960 return True
James E. Blairb0fcae42012-07-17 11:12:10 -0700961
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700962 def registerJobs(self):
963 count = 0
James E. Blaireff88162013-07-01 12:44:14 -0400964 for job in self.sched.layout.jobs.keys():
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700965 self.worker.registerFunction('build:' + job)
966 count += 1
967 self.worker.registerFunction('stop:' + self.worker.worker_id)
968 count += 1
969
970 while len(self.gearman_server.functions) < count:
971 time.sleep(0)
972
973 def release(self, job):
974 if isinstance(job, FakeBuild):
975 job.release()
976 else:
977 job.waiting = False
978 self.log.debug("Queued job %s released" % job.unique)
979 self.gearman_server.wakeConnections()
980
981 def getParameter(self, job, name):
982 if isinstance(job, FakeBuild):
983 return job.parameters[name]
984 else:
985 parameters = json.loads(job.arguments)
986 return parameters[name]
987
988 def resetGearmanServer(self):
989 self.worker.setFunctions([])
990 while True:
991 done = True
992 for connection in self.gearman_server.active_connections:
James E. Blairad28e912013-11-27 10:43:22 -0800993 if (connection.functions and
994 connection.client_id != 'Zuul RPC Listener'):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700995 done = False
996 if done:
997 break
998 time.sleep(0)
999 self.gearman_server.functions = set()
James E. Blairad28e912013-11-27 10:43:22 -08001000 self.rpc.register()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001001
1002 def haveAllBuildsReported(self):
1003 # See if Zuul is waiting on a meta job to complete
1004 if self.launcher.meta_jobs:
1005 return False
1006 # Find out if every build that the worker has completed has been
1007 # reported back to Zuul. If it hasn't then that means a Gearman
1008 # event is still in transit and the system is not stable.
1009 for build in self.worker.build_history:
1010 zbuild = self.launcher.builds.get(build.uuid)
1011 if not zbuild:
1012 # It has already been reported
1013 continue
1014 # It hasn't been reported yet.
1015 return False
1016 # Make sure that none of the worker connections are in GRAB_WAIT
1017 for connection in self.worker.active_connections:
1018 if connection.state == 'GRAB_WAIT':
1019 return False
1020 return True
1021
1022 def areAllBuildsWaiting(self):
1023 ret = True
1024
1025 builds = self.launcher.builds.values()
1026 for build in builds:
1027 client_job = None
1028 for conn in self.launcher.gearman.active_connections:
1029 for j in conn.related_jobs.values():
1030 if j.unique == build.uuid:
1031 client_job = j
1032 break
1033 if not client_job:
1034 self.log.debug("%s is not known to the gearman client" %
1035 build)
1036 ret = False
1037 continue
1038 if not client_job.handle:
1039 self.log.debug("%s has no handle" % client_job)
1040 ret = False
1041 continue
1042 server_job = self.gearman_server.jobs.get(client_job.handle)
1043 if not server_job:
1044 self.log.debug("%s is not known to the gearman server" %
1045 client_job)
1046 ret = False
1047 continue
1048 if not hasattr(server_job, 'waiting'):
1049 self.log.debug("%s is being enqueued" % server_job)
1050 ret = False
1051 continue
1052 if server_job.waiting:
1053 continue
1054 worker_job = self.worker.gearman_jobs.get(server_job.unique)
1055 if worker_job:
1056 if worker_job.build.isWaiting():
1057 continue
1058 else:
1059 self.log.debug("%s is running" % worker_job)
1060 ret = False
1061 else:
1062 self.log.debug("%s is unassigned" % server_job)
1063 ret = False
1064 return ret
1065
James E. Blairb0fcae42012-07-17 11:12:10 -07001066 def waitUntilSettled(self):
1067 self.log.debug("Waiting until settled...")
1068 start = time.time()
1069 while True:
1070 if time.time() - start > 10:
1071 print 'queue status:',
1072 print self.sched.trigger_event_queue.empty(),
1073 print self.sched.result_event_queue.empty(),
1074 print self.fake_gerrit.event_queue.empty(),
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001075 print self.areAllBuildsWaiting()
James E. Blairb0fcae42012-07-17 11:12:10 -07001076 raise Exception("Timeout waiting for Zuul to settle")
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001077 # Make sure no new events show up while we're checking
1078 self.worker.lock.acquire()
1079 # have all build states propogated to zuul?
1080 if self.haveAllBuildsReported():
1081 # Join ensures that the queue is empty _and_ events have been
1082 # processed
1083 self.fake_gerrit.event_queue.join()
1084 self.sched.trigger_event_queue.join()
1085 self.sched.result_event_queue.join()
1086 if (self.sched.trigger_event_queue.empty() and
1087 self.sched.result_event_queue.empty() and
1088 self.fake_gerrit.event_queue.empty() and
1089 self.areAllBuildsWaiting()):
1090 self.worker.lock.release()
1091 self.log.debug("...settled.")
1092 return
1093 self.worker.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -07001094 self.sched.wake_event.wait(0.1)
1095
James E. Blaird466dc42012-07-31 10:42:56 -07001096 def countJobResults(self, jobs, result):
James E. Blair0018a6c2013-02-27 14:11:45 -08001097 jobs = filter(lambda x: x.result == result, jobs)
James E. Blaird466dc42012-07-31 10:42:56 -07001098 return len(jobs)
1099
James E. Blair4ca985f2013-05-30 12:27:43 -07001100 def getJobFromHistory(self, name):
1101 history = self.worker.build_history
1102 for job in history:
1103 if job.name == name:
1104 return job
1105 raise Exception("Unable to find job %s in history" % name)
1106
James E. Blaire0487072012-08-29 17:38:31 -07001107 def assertEmptyQueues(self):
1108 # Make sure there are no orphaned jobs
James E. Blaireff88162013-07-01 12:44:14 -04001109 for pipeline in self.sched.layout.pipelines.values():
James E. Blaire0487072012-08-29 17:38:31 -07001110 for queue in pipeline.queues:
1111 if len(queue.queue) != 0:
James E. Blairf62d4282012-12-31 17:01:50 -08001112 print 'pipeline %s queue %s contents %s' % (
1113 pipeline.name, queue.name, queue.queue)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001114 self.assertEqual(len(queue.queue), 0)
James E. Blaire0487072012-08-29 17:38:31 -07001115
James E. Blair66eeebf2013-07-27 17:44:32 -07001116 def assertReportedStat(self, key, value=None, kind=None):
James E. Blair412e5582013-04-22 15:50:12 -07001117 start = time.time()
1118 while time.time() < (start + 5):
1119 for stat in self.statsd.stats:
James E. Blair66eeebf2013-07-27 17:44:32 -07001120 pprint.pprint(self.statsd.stats)
James E. Blair412e5582013-04-22 15:50:12 -07001121 k, v = stat.split(':')
1122 if key == k:
James E. Blair66eeebf2013-07-27 17:44:32 -07001123 if value is None and kind is None:
James E. Blair412e5582013-04-22 15:50:12 -07001124 return
James E. Blair66eeebf2013-07-27 17:44:32 -07001125 elif value:
1126 if value == v:
1127 return
1128 elif kind:
1129 if v.endswith('|' + kind):
1130 return
James E. Blair412e5582013-04-22 15:50:12 -07001131 time.sleep(0.1)
1132
1133 pprint.pprint(self.statsd.stats)
1134 raise Exception("Key %s not found in reported stats" % key)
1135
James E. Blairb0fcae42012-07-17 11:12:10 -07001136 def test_jobs_launched(self):
1137 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001138
James E. Blairb0fcae42012-07-17 11:12:10 -07001139 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -07001140 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001141 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1142 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001143 self.assertEqual(self.getJobFromHistory('project-merge').result,
1144 'SUCCESS')
1145 self.assertEqual(self.getJobFromHistory('project-test1').result,
1146 'SUCCESS')
1147 self.assertEqual(self.getJobFromHistory('project-test2').result,
1148 'SUCCESS')
1149 self.assertEqual(A.data['status'], 'MERGED')
1150 self.assertEqual(A.reported, 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001151
James E. Blair66eeebf2013-07-27 17:44:32 -07001152 self.assertReportedStat('gerrit.event.comment-added', value='1|c')
1153 self.assertReportedStat('zuul.pipeline.gate.current_changes',
1154 value='1|g')
1155 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
1156 kind='ms')
1157 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
1158 value='1|c')
1159 self.assertReportedStat('zuul.pipeline.gate.resident_time', kind='ms')
1160 self.assertReportedStat('zuul.pipeline.gate.total_changes',
1161 value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -07001162 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -07001163 'zuul.pipeline.gate.org.project.resident_time', kind='ms')
James E. Blair412e5582013-04-22 15:50:12 -07001164 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -07001165 'zuul.pipeline.gate.org.project.total_changes', value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -07001166
James E. Blair3cb10702013-08-24 08:56:03 -07001167 def test_initial_pipeline_gauges(self):
1168 "Test that each pipeline reported its length on start"
1169 pipeline_names = self.sched.layout.pipelines.keys()
1170 self.assertNotEqual(len(pipeline_names), 0)
1171 for name in pipeline_names:
1172 self.assertReportedStat('zuul.pipeline.%s.current_changes' % name,
1173 value='0|g')
1174
James E. Blair42f74822013-05-14 15:18:03 -07001175 def test_duplicate_pipelines(self):
1176 "Test that a change matching multiple pipelines works"
James E. Blair1b4d9722013-05-21 10:32:04 -07001177
James E. Blair42f74822013-05-14 15:18:03 -07001178 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1179 self.fake_gerrit.addEvent(A.getChangeRestoredEvent())
1180 self.waitUntilSettled()
James E. Blair42f74822013-05-14 15:18:03 -07001181
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001182 self.assertEqual(len(self.history), 2)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001183 self.history[0].name == 'project-test1'
1184 self.history[1].name == 'project-test1'
James E. Blair42f74822013-05-14 15:18:03 -07001185
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001186 self.assertEqual(len(A.messages), 2)
James E. Blair42f74822013-05-14 15:18:03 -07001187 if 'dup1/project-test1' in A.messages[0]:
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001188 self.assertIn('dup1/project-test1', A.messages[0])
1189 self.assertNotIn('dup2/project-test1', A.messages[0])
1190 self.assertNotIn('dup1/project-test1', A.messages[1])
1191 self.assertIn('dup2/project-test1', A.messages[1])
James E. Blair42f74822013-05-14 15:18:03 -07001192 else:
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001193 self.assertIn('dup1/project-test1', A.messages[1])
1194 self.assertNotIn('dup2/project-test1', A.messages[1])
1195 self.assertNotIn('dup1/project-test1', A.messages[0])
1196 self.assertIn('dup2/project-test1', A.messages[0])
James E. Blair42f74822013-05-14 15:18:03 -07001197
James E. Blairb0fcae42012-07-17 11:12:10 -07001198 def test_parallel_changes(self):
1199 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001200
1201 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -07001202 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1203 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1204 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001205 A.addApproval('CRVW', 2)
1206 B.addApproval('CRVW', 2)
1207 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001208
1209 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1210 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1211 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1212
1213 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001214 self.assertEqual(len(self.builds), 1)
1215 self.assertEqual(self.builds[0].name, 'project-merge')
1216 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairb0fcae42012-07-17 11:12:10 -07001217
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001218 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001219 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001220 self.assertEqual(len(self.builds), 3)
1221 self.assertEqual(self.builds[0].name, 'project-test1')
1222 self.assertTrue(self.job_has_changes(self.builds[0], A))
1223 self.assertEqual(self.builds[1].name, 'project-test2')
1224 self.assertTrue(self.job_has_changes(self.builds[1], A))
1225 self.assertEqual(self.builds[2].name, 'project-merge')
1226 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -07001227
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001228 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001229 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001230 self.assertEqual(len(self.builds), 5)
1231 self.assertEqual(self.builds[0].name, 'project-test1')
1232 self.assertTrue(self.job_has_changes(self.builds[0], A))
1233 self.assertEqual(self.builds[1].name, 'project-test2')
1234 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -07001235
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001236 self.assertEqual(self.builds[2].name, 'project-test1')
1237 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
1238 self.assertEqual(self.builds[3].name, 'project-test2')
1239 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -07001240
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001241 self.assertEqual(self.builds[4].name, 'project-merge')
1242 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -07001243
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001244 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001245 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001246 self.assertEqual(len(self.builds), 6)
1247 self.assertEqual(self.builds[0].name, 'project-test1')
1248 self.assertTrue(self.job_has_changes(self.builds[0], A))
1249 self.assertEqual(self.builds[1].name, 'project-test2')
1250 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -07001251
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001252 self.assertEqual(self.builds[2].name, 'project-test1')
1253 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
1254 self.assertEqual(self.builds[3].name, 'project-test2')
1255 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -07001256
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001257 self.assertEqual(self.builds[4].name, 'project-test1')
1258 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
1259 self.assertEqual(self.builds[5].name, 'project-test2')
1260 self.assertTrue(self.job_has_changes(self.builds[5], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -07001261
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001262 self.worker.hold_jobs_in_build = False
1263 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -07001264 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001265 self.assertEqual(len(self.builds), 0)
James E. Blairb0fcae42012-07-17 11:12:10 -07001266
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001267 self.assertEqual(len(self.history), 9)
1268 self.assertEqual(A.data['status'], 'MERGED')
1269 self.assertEqual(B.data['status'], 'MERGED')
1270 self.assertEqual(C.data['status'], 'MERGED')
1271 self.assertEqual(A.reported, 2)
1272 self.assertEqual(B.reported, 2)
1273 self.assertEqual(C.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001274
1275 def test_failed_changes(self):
1276 "Test that a change behind a failed change is retested"
James E. Blaire2819012013-06-28 17:17:26 -04001277 self.worker.hold_jobs_in_build = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001278
James E. Blairb02a3bb2012-07-30 17:49:55 -07001279 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1280 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -07001281 A.addApproval('CRVW', 2)
1282 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001283
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001284 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001285
James E. Blaire2819012013-06-28 17:17:26 -04001286 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1287 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
James E. Blairb02a3bb2012-07-30 17:49:55 -07001288 self.waitUntilSettled()
James E. Blaire2819012013-06-28 17:17:26 -04001289
1290 self.worker.release('.*-merge')
1291 self.waitUntilSettled()
1292
1293 self.worker.hold_jobs_in_build = False
1294 self.worker.release()
1295
1296 self.waitUntilSettled()
1297 # It's certain that the merge job for change 2 will run, but
1298 # the test1 and test2 jobs may or may not run.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001299 self.assertTrue(len(self.history) > 6)
1300 self.assertEqual(A.data['status'], 'NEW')
1301 self.assertEqual(B.data['status'], 'MERGED')
1302 self.assertEqual(A.reported, 2)
1303 self.assertEqual(B.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001304
1305 def test_independent_queues(self):
1306 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001307
1308 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +09001309 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001310 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1311 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001312 A.addApproval('CRVW', 2)
1313 B.addApproval('CRVW', 2)
1314 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001315
1316 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1317 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1318 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1319
James E. Blairb02a3bb2012-07-30 17:49:55 -07001320 self.waitUntilSettled()
1321
1322 # There should be one merge job at the head of each queue running
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001323 self.assertEqual(len(self.builds), 2)
1324 self.assertEqual(self.builds[0].name, 'project-merge')
1325 self.assertTrue(self.job_has_changes(self.builds[0], A))
1326 self.assertEqual(self.builds[1].name, 'project1-merge')
1327 self.assertTrue(self.job_has_changes(self.builds[1], B))
James E. Blairb02a3bb2012-07-30 17:49:55 -07001328
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001329 # Release the current merge builds
1330 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001331 self.waitUntilSettled()
1332 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001333 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001334 self.waitUntilSettled()
1335
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001336 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -07001337 # project1 (3) + project2 (3) + project (2) = 8
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001338 self.assertEqual(len(self.builds), 8)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001339
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001340 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001341 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001342 self.assertEqual(len(self.builds), 0)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001343
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001344 self.assertEqual(len(self.history), 11)
1345 self.assertEqual(A.data['status'], 'MERGED')
1346 self.assertEqual(B.data['status'], 'MERGED')
1347 self.assertEqual(C.data['status'], 'MERGED')
1348 self.assertEqual(A.reported, 2)
1349 self.assertEqual(B.reported, 2)
1350 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001351
1352 def test_failed_change_at_head(self):
1353 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -07001354
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001355 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -07001356 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1357 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1358 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001359 A.addApproval('CRVW', 2)
1360 B.addApproval('CRVW', 2)
1361 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001362
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001363 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001364
1365 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1366 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1367 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1368
1369 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -07001370
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001371 self.assertEqual(len(self.builds), 1)
1372 self.assertEqual(self.builds[0].name, 'project-merge')
1373 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -07001374
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001375 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001376 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001377 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001378 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001379 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001380 self.waitUntilSettled()
1381
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001382 self.assertEqual(len(self.builds), 6)
1383 self.assertEqual(self.builds[0].name, 'project-test1')
1384 self.assertEqual(self.builds[1].name, 'project-test2')
1385 self.assertEqual(self.builds[2].name, 'project-test1')
1386 self.assertEqual(self.builds[3].name, 'project-test2')
1387 self.assertEqual(self.builds[4].name, 'project-test1')
1388 self.assertEqual(self.builds[5].name, 'project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -07001389
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001390 self.release(self.builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001391 self.waitUntilSettled()
1392
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001393 # project-test2, project-merge for B
1394 self.assertEqual(len(self.builds), 2)
1395 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
James E. Blaird466dc42012-07-31 10:42:56 -07001396
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001397 self.worker.hold_jobs_in_build = False
1398 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001399 self.waitUntilSettled()
1400
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001401 self.assertEqual(len(self.builds), 0)
1402 self.assertEqual(len(self.history), 15)
1403 self.assertEqual(A.data['status'], 'NEW')
1404 self.assertEqual(B.data['status'], 'MERGED')
1405 self.assertEqual(C.data['status'], 'MERGED')
1406 self.assertEqual(A.reported, 2)
1407 self.assertEqual(B.reported, 2)
1408 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001409
James E. Blair0aac4872013-08-23 14:02:38 -07001410 def test_failed_change_in_middle(self):
1411 "Test a failed change in the middle of the queue"
1412
1413 self.worker.hold_jobs_in_build = True
1414 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1415 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1416 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1417 A.addApproval('CRVW', 2)
1418 B.addApproval('CRVW', 2)
1419 C.addApproval('CRVW', 2)
1420
1421 self.worker.addFailTest('project-test1', B)
1422
1423 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1424 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1425 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1426
1427 self.waitUntilSettled()
1428
1429 self.worker.release('.*-merge')
1430 self.waitUntilSettled()
1431 self.worker.release('.*-merge')
1432 self.waitUntilSettled()
1433 self.worker.release('.*-merge')
1434 self.waitUntilSettled()
1435
1436 self.assertEqual(len(self.builds), 6)
1437 self.assertEqual(self.builds[0].name, 'project-test1')
1438 self.assertEqual(self.builds[1].name, 'project-test2')
1439 self.assertEqual(self.builds[2].name, 'project-test1')
1440 self.assertEqual(self.builds[3].name, 'project-test2')
1441 self.assertEqual(self.builds[4].name, 'project-test1')
1442 self.assertEqual(self.builds[5].name, 'project-test2')
1443
1444 self.release(self.builds[2])
1445 self.waitUntilSettled()
1446
James E. Blair972e3c72013-08-29 12:04:55 -07001447 # project-test1 and project-test2 for A
1448 # project-test2 for B
1449 # project-merge for C (without B)
1450 self.assertEqual(len(self.builds), 4)
James E. Blair0aac4872013-08-23 14:02:38 -07001451 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 2)
1452
James E. Blair972e3c72013-08-29 12:04:55 -07001453 self.worker.release('.*-merge')
1454 self.waitUntilSettled()
1455
1456 # project-test1 and project-test2 for A
1457 # project-test2 for B
1458 # project-test1 and project-test2 for C
1459 self.assertEqual(len(self.builds), 5)
1460
James E. Blair0aac4872013-08-23 14:02:38 -07001461 items = self.sched.layout.pipelines['gate'].getAllItems()
1462 builds = items[0].current_build_set.getBuilds()
1463 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
1464 self.assertEqual(self.countJobResults(builds, None), 2)
1465 builds = items[1].current_build_set.getBuilds()
1466 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
1467 self.assertEqual(self.countJobResults(builds, 'FAILURE'), 1)
1468 self.assertEqual(self.countJobResults(builds, None), 1)
1469 builds = items[2].current_build_set.getBuilds()
1470 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
James E. Blair972e3c72013-08-29 12:04:55 -07001471 self.assertEqual(self.countJobResults(builds, None), 2)
James E. Blair0aac4872013-08-23 14:02:38 -07001472
1473 self.worker.hold_jobs_in_build = False
1474 self.worker.release()
1475 self.waitUntilSettled()
1476
1477 self.assertEqual(len(self.builds), 0)
1478 self.assertEqual(len(self.history), 12)
1479 self.assertEqual(A.data['status'], 'MERGED')
1480 self.assertEqual(B.data['status'], 'NEW')
1481 self.assertEqual(C.data['status'], 'MERGED')
1482 self.assertEqual(A.reported, 2)
1483 self.assertEqual(B.reported, 2)
1484 self.assertEqual(C.reported, 2)
1485
James E. Blaird466dc42012-07-31 10:42:56 -07001486 def test_failed_change_at_head_with_queue(self):
1487 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -07001488
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001489 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -07001490 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1491 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1492 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001493 A.addApproval('CRVW', 2)
1494 B.addApproval('CRVW', 2)
1495 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001496
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001497 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001498
1499 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1500 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1501 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1502
1503 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001504 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001505 self.assertEqual(len(self.builds), 0)
1506 self.assertEqual(len(queue), 1)
1507 self.assertEqual(queue[0].name, 'build:project-merge')
1508 self.assertTrue(self.job_has_changes(queue[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -07001509
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001510 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001511 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001512 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001513 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001514 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001515 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001516 queue = self.gearman_server.getQueue()
James E. Blaird466dc42012-07-31 10:42:56 -07001517
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001518 self.assertEqual(len(self.builds), 0)
1519 self.assertEqual(len(queue), 6)
1520 self.assertEqual(queue[0].name, 'build:project-test1')
1521 self.assertEqual(queue[1].name, 'build:project-test2')
1522 self.assertEqual(queue[2].name, 'build:project-test1')
1523 self.assertEqual(queue[3].name, 'build:project-test2')
1524 self.assertEqual(queue[4].name, 'build:project-test1')
1525 self.assertEqual(queue[5].name, 'build:project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -07001526
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001527 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001528 self.waitUntilSettled()
1529
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001530 self.assertEqual(len(self.builds), 0)
James E. Blair701c5b42013-06-06 09:34:59 -07001531 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001532 self.assertEqual(len(queue), 2) # project-test2, project-merge for B
1533 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 0)
James E. Blaird466dc42012-07-31 10:42:56 -07001534
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001535 self.gearman_server.hold_jobs_in_queue = False
1536 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001537 self.waitUntilSettled()
1538
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001539 self.assertEqual(len(self.builds), 0)
1540 self.assertEqual(len(self.history), 11)
1541 self.assertEqual(A.data['status'], 'NEW')
1542 self.assertEqual(B.data['status'], 'MERGED')
1543 self.assertEqual(C.data['status'], 'MERGED')
1544 self.assertEqual(A.reported, 2)
1545 self.assertEqual(B.reported, 2)
1546 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -07001547
James E. Blairfef71632013-09-23 11:15:47 -07001548 def test_two_failed_changes_at_head(self):
1549 "Test that changes are reparented correctly if 2 fail at head"
1550
1551 self.worker.hold_jobs_in_build = True
1552 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1553 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1554 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1555 A.addApproval('CRVW', 2)
1556 B.addApproval('CRVW', 2)
1557 C.addApproval('CRVW', 2)
1558
1559 self.worker.addFailTest('project-test1', A)
1560 self.worker.addFailTest('project-test1', B)
1561
1562 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1563 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1564 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1565 self.waitUntilSettled()
1566
1567 self.worker.release('.*-merge')
1568 self.waitUntilSettled()
1569 self.worker.release('.*-merge')
1570 self.waitUntilSettled()
1571 self.worker.release('.*-merge')
1572 self.waitUntilSettled()
1573
1574 self.assertEqual(len(self.builds), 6)
1575 self.assertEqual(self.builds[0].name, 'project-test1')
1576 self.assertEqual(self.builds[1].name, 'project-test2')
1577 self.assertEqual(self.builds[2].name, 'project-test1')
1578 self.assertEqual(self.builds[3].name, 'project-test2')
1579 self.assertEqual(self.builds[4].name, 'project-test1')
1580 self.assertEqual(self.builds[5].name, 'project-test2')
1581
1582 self.assertTrue(self.job_has_changes(self.builds[0], A))
1583 self.assertTrue(self.job_has_changes(self.builds[2], A))
1584 self.assertTrue(self.job_has_changes(self.builds[2], B))
1585 self.assertTrue(self.job_has_changes(self.builds[4], A))
1586 self.assertTrue(self.job_has_changes(self.builds[4], B))
1587 self.assertTrue(self.job_has_changes(self.builds[4], C))
1588
1589 # Fail change B first
1590 self.release(self.builds[2])
1591 self.waitUntilSettled()
1592
1593 # restart of C after B failure
1594 self.worker.release('.*-merge')
1595 self.waitUntilSettled()
1596
1597 self.assertEqual(len(self.builds), 5)
1598 self.assertEqual(self.builds[0].name, 'project-test1')
1599 self.assertEqual(self.builds[1].name, 'project-test2')
1600 self.assertEqual(self.builds[2].name, 'project-test2')
1601 self.assertEqual(self.builds[3].name, 'project-test1')
1602 self.assertEqual(self.builds[4].name, 'project-test2')
1603
1604 self.assertTrue(self.job_has_changes(self.builds[1], A))
1605 self.assertTrue(self.job_has_changes(self.builds[2], A))
1606 self.assertTrue(self.job_has_changes(self.builds[2], B))
1607 self.assertTrue(self.job_has_changes(self.builds[4], A))
1608 self.assertFalse(self.job_has_changes(self.builds[4], B))
1609 self.assertTrue(self.job_has_changes(self.builds[4], C))
1610
1611 # Finish running all passing jobs for change A
1612 self.release(self.builds[1])
1613 self.waitUntilSettled()
1614 # Fail and report change A
1615 self.release(self.builds[0])
1616 self.waitUntilSettled()
1617
1618 # restart of B,C after A failure
1619 self.worker.release('.*-merge')
1620 self.waitUntilSettled()
1621 self.worker.release('.*-merge')
1622 self.waitUntilSettled()
1623
1624 self.assertEqual(len(self.builds), 4)
1625 self.assertEqual(self.builds[0].name, 'project-test1') # B
1626 self.assertEqual(self.builds[1].name, 'project-test2') # B
1627 self.assertEqual(self.builds[2].name, 'project-test1') # C
1628 self.assertEqual(self.builds[3].name, 'project-test2') # C
1629
1630 self.assertFalse(self.job_has_changes(self.builds[1], A))
1631 self.assertTrue(self.job_has_changes(self.builds[1], B))
1632 self.assertFalse(self.job_has_changes(self.builds[1], C))
1633
1634 self.assertFalse(self.job_has_changes(self.builds[2], A))
1635 # After A failed and B and C restarted, B should be back in
1636 # C's tests because it has not failed yet.
1637 self.assertTrue(self.job_has_changes(self.builds[2], B))
1638 self.assertTrue(self.job_has_changes(self.builds[2], C))
1639
1640 self.worker.hold_jobs_in_build = False
1641 self.worker.release()
1642 self.waitUntilSettled()
1643
1644 self.assertEqual(len(self.builds), 0)
1645 self.assertEqual(len(self.history), 21)
1646 self.assertEqual(A.data['status'], 'NEW')
1647 self.assertEqual(B.data['status'], 'NEW')
1648 self.assertEqual(C.data['status'], 'MERGED')
1649 self.assertEqual(A.reported, 2)
1650 self.assertEqual(B.reported, 2)
1651 self.assertEqual(C.reported, 2)
1652
James E. Blair8c803f82012-07-31 16:25:42 -07001653 def test_patch_order(self):
1654 "Test that dependent patches are tested in the right order"
1655 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1656 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1657 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1658 A.addApproval('CRVW', 2)
1659 B.addApproval('CRVW', 2)
1660 C.addApproval('CRVW', 2)
1661
1662 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
1663 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1664 M2.setMerged()
1665 M1.setMerged()
1666
1667 # C -> B -> A -> M1 -> M2
1668 # M2 is here to make sure it is never queried. If it is, it
1669 # means zuul is walking down the entire history of merged
1670 # changes.
1671
1672 C.setDependsOn(B, 1)
1673 B.setDependsOn(A, 1)
1674 A.setDependsOn(M1, 1)
1675 M1.setDependsOn(M2, 1)
1676
1677 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1678
1679 self.waitUntilSettled()
1680
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001681 self.assertEqual(A.data['status'], 'NEW')
1682 self.assertEqual(B.data['status'], 'NEW')
1683 self.assertEqual(C.data['status'], 'NEW')
James E. Blair8c803f82012-07-31 16:25:42 -07001684
1685 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1686 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1687
1688 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001689 self.assertEqual(M2.queried, 0)
1690 self.assertEqual(A.data['status'], 'MERGED')
1691 self.assertEqual(B.data['status'], 'MERGED')
1692 self.assertEqual(C.data['status'], 'MERGED')
1693 self.assertEqual(A.reported, 2)
1694 self.assertEqual(B.reported, 2)
1695 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -07001696
James E. Blair0e933c52013-07-11 10:18:52 -07001697 def test_trigger_cache(self):
1698 "Test that the trigger cache operates correctly"
1699 self.worker.hold_jobs_in_build = True
1700
1701 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1702 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1703 X = self.fake_gerrit.addFakeChange('org/project', 'master', 'X')
1704 A.addApproval('CRVW', 2)
1705 B.addApproval('CRVW', 2)
1706
1707 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1708 M1.setMerged()
1709
1710 B.setDependsOn(A, 1)
1711 A.setDependsOn(M1, 1)
1712
1713 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1714 self.fake_gerrit.addEvent(X.getPatchsetCreatedEvent(1))
1715
1716 self.waitUntilSettled()
1717
1718 for build in self.builds:
1719 if build.parameters['ZUUL_PIPELINE'] == 'check':
1720 build.release()
1721 self.waitUntilSettled()
1722 for build in self.builds:
1723 if build.parameters['ZUUL_PIPELINE'] == 'check':
1724 build.release()
1725 self.waitUntilSettled()
1726
1727 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1728 self.waitUntilSettled()
1729
James E. Blair6c358e72013-07-29 17:06:47 -07001730 self.log.debug("len %s " % self.gerrit._change_cache.keys())
James E. Blair0e933c52013-07-11 10:18:52 -07001731 # there should still be changes in the cache
James E. Blair6c358e72013-07-29 17:06:47 -07001732 self.assertNotEqual(len(self.gerrit._change_cache.keys()), 0)
James E. Blair0e933c52013-07-11 10:18:52 -07001733
1734 self.worker.hold_jobs_in_build = False
1735 self.worker.release()
1736 self.waitUntilSettled()
1737
1738 self.assertEqual(A.data['status'], 'MERGED')
1739 self.assertEqual(B.data['status'], 'MERGED')
1740 self.assertEqual(A.queried, 2) # Initial and isMerged
1741 self.assertEqual(B.queried, 3) # Initial A, refresh from B, isMerged
1742
James E. Blair8c803f82012-07-31 16:25:42 -07001743 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -07001744 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -07001745 # TODO: move to test_gerrit (this is a unit test!)
1746 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair6c358e72013-07-29 17:06:47 -07001747 trigger = self.sched.layout.pipelines['gate'].trigger
1748 a = self.sched.triggers['gerrit'].getChange(1, 2)
James E. Blaireff88162013-07-01 12:44:14 -04001749 mgr = self.sched.layout.pipelines['gate'].manager
James E. Blair6c358e72013-07-29 17:06:47 -07001750 self.assertFalse(trigger.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -07001751
1752 A.addApproval('CRVW', 2)
James E. Blair6c358e72013-07-29 17:06:47 -07001753 a = trigger.getChange(1, 2, refresh=True)
1754 self.assertFalse(trigger.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -07001755
1756 A.addApproval('APRV', 1)
James E. Blair6c358e72013-07-29 17:06:47 -07001757 a = trigger.getChange(1, 2, refresh=True)
1758 self.assertTrue(trigger.canMerge(a, mgr.getSubmitAllowNeeds()))
1759 trigger.maintainCache([])
James E. Blair4886cc12012-07-18 15:39:41 -07001760
1761 def test_build_configuration(self):
1762 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001763
1764 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -07001765 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1766 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1767 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1768 A.addApproval('CRVW', 2)
1769 B.addApproval('CRVW', 2)
1770 C.addApproval('CRVW', 2)
1771 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1772 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1773 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1774 self.waitUntilSettled()
1775
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001776 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001777 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001778 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001779 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001780 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001781 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001782 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001783 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1784 self.gearman_server.hold_jobs_in_queue = False
1785 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001786 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -07001787
Monty Taylorbc758832013-06-17 17:22:42 -04001788 path = os.path.join(self.git_root, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -07001789 repo = git.Repo(path)
1790 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1791 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -07001792 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001793 self.assertEqual(repo_messages, correct_messages)
James E. Blair973721f2012-08-15 10:19:43 -07001794
1795 def test_build_configuration_conflict(self):
1796 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001797
1798 self.gearman_server.hold_jobs_in_queue = True
James E. Blair6736beb2013-07-11 15:18:15 -07001799 A = self.fake_gerrit.addFakeChange('org/conflict-project',
1800 'master', 'A')
James E. Blair973721f2012-08-15 10:19:43 -07001801 A.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -07001802 B = self.fake_gerrit.addFakeChange('org/conflict-project',
1803 'master', 'B')
James E. Blair973721f2012-08-15 10:19:43 -07001804 B.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -07001805 C = self.fake_gerrit.addFakeChange('org/conflict-project',
1806 'master', 'C')
James E. Blair973721f2012-08-15 10:19:43 -07001807 A.addApproval('CRVW', 2)
1808 B.addApproval('CRVW', 2)
1809 C.addApproval('CRVW', 2)
1810 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1811 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1812 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1813 self.waitUntilSettled()
1814
James E. Blair6736beb2013-07-11 15:18:15 -07001815 self.assertEqual(A.reported, 1)
1816 self.assertEqual(B.reported, 1)
1817 self.assertEqual(C.reported, 1)
1818
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001819 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001820 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001821 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001822 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001823 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001824 self.waitUntilSettled()
James E. Blair972e3c72013-08-29 12:04:55 -07001825
1826 self.assertEqual(len(self.history), 2) # A and C merge jobs
1827
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001828 self.gearman_server.hold_jobs_in_queue = False
1829 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001830 self.waitUntilSettled()
1831
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001832 self.assertEqual(A.data['status'], 'MERGED')
1833 self.assertEqual(B.data['status'], 'NEW')
1834 self.assertEqual(C.data['status'], 'MERGED')
1835 self.assertEqual(A.reported, 2)
1836 self.assertEqual(B.reported, 2)
1837 self.assertEqual(C.reported, 2)
James E. Blair972e3c72013-08-29 12:04:55 -07001838 self.assertEqual(len(self.history), 6)
James E. Blair6736beb2013-07-11 15:18:15 -07001839
James E. Blairdaabed22012-08-15 15:38:57 -07001840 def test_post(self):
1841 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001842
Zhongyue Luo5d556072012-09-21 02:00:47 +09001843 e = {
1844 "type": "ref-updated",
1845 "submitter": {
1846 "name": "User Name",
1847 },
1848 "refUpdate": {
1849 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1850 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1851 "refName": "master",
1852 "project": "org/project",
1853 }
1854 }
James E. Blairdaabed22012-08-15 15:38:57 -07001855 self.fake_gerrit.addEvent(e)
1856 self.waitUntilSettled()
1857
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001858 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001859 self.assertEqual(len(self.history), 1)
1860 self.assertIn('project-post', job_names)
James E. Blairc6294a52012-08-17 10:19:48 -07001861
1862 def test_build_configuration_branch(self):
1863 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001864
1865 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001866 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1867 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1868 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1869 A.addApproval('CRVW', 2)
1870 B.addApproval('CRVW', 2)
1871 C.addApproval('CRVW', 2)
1872 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1873 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1874 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1875 self.waitUntilSettled()
1876
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001877 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001878 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001879 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001880 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001881 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001882 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001883 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001884 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1885 self.gearman_server.hold_jobs_in_queue = False
1886 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001887 self.waitUntilSettled()
1888
Monty Taylorbc758832013-06-17 17:22:42 -04001889 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001890 repo = git.Repo(path)
1891 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1892 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001893 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001894 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -07001895
1896 def test_build_configuration_branch_interaction(self):
1897 "Test that switching between branches works"
1898 self.test_build_configuration()
1899 self.test_build_configuration_branch()
1900 # C has been merged, undo that
Monty Taylorbc758832013-06-17 17:22:42 -04001901 path = os.path.join(self.upstream_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001902 repo = git.Repo(path)
1903 repo.heads.master.commit = repo.commit('init')
1904 self.test_build_configuration()
1905
1906 def test_build_configuration_multi_branch(self):
1907 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001908
1909 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001910 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1911 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1912 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1913 A.addApproval('CRVW', 2)
1914 B.addApproval('CRVW', 2)
1915 C.addApproval('CRVW', 2)
1916 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1917 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1918 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1919 self.waitUntilSettled()
1920
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001921 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001922 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001923 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001924 job_B = None
1925 for job in queue:
1926 if 'project-merge' in job.name:
1927 job_B = job
1928 ref_B = self.getParameter(job_B, 'ZUUL_REF')
James E. Blairf750aa02013-07-15 14:11:24 -07001929 self.log.debug("Got Zuul ref for change B: %s" % ref_B)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001930 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001931 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001932 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001933 for job in queue:
1934 if 'project-merge' in job.name:
1935 job_C = job
1936 ref_C = self.getParameter(job_C, 'ZUUL_REF')
James E. Blairf750aa02013-07-15 14:11:24 -07001937 self.log.debug("Got Zuul ref for change C: %s" % ref_C)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001938 self.gearman_server.hold_jobs_in_queue = False
1939 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001940 self.waitUntilSettled()
1941
Monty Taylorbc758832013-06-17 17:22:42 -04001942 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001943 repo = git.Repo(path)
1944
1945 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001946 for c in repo.iter_commits(ref_C)]
James E. Blairc6294a52012-08-17 10:19:48 -07001947 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001948 correct_messages = ['initial commit', 'A-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001949 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -07001950
1951 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001952 for c in repo.iter_commits(ref_B)]
James E. Blairc6294a52012-08-17 10:19:48 -07001953 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001954 correct_messages = ['initial commit', 'mp commit', 'B-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001955 self.assertEqual(repo_messages, correct_messages)
James E. Blair7f71c802012-08-22 13:04:32 -07001956
1957 def test_one_job_project(self):
1958 "Test that queueing works with one job"
1959 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1960 'master', 'A')
1961 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1962 'master', 'B')
1963 A.addApproval('CRVW', 2)
1964 B.addApproval('CRVW', 2)
1965 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1966 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1967 self.waitUntilSettled()
1968
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001969 self.assertEqual(A.data['status'], 'MERGED')
1970 self.assertEqual(A.reported, 2)
1971 self.assertEqual(B.data['status'], 'MERGED')
1972 self.assertEqual(B.reported, 2)
James E. Blaircaec0c52012-08-22 14:52:22 -07001973
Antoine Musso80edd5a2013-02-13 15:37:53 +01001974 def test_job_from_templates_launched(self):
1975 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001976
Antoine Musso80edd5a2013-02-13 15:37:53 +01001977 A = self.fake_gerrit.addFakeChange(
1978 'org/templated-project', 'master', 'A')
1979 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1980 self.waitUntilSettled()
Antoine Musso80edd5a2013-02-13 15:37:53 +01001981
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001982 self.assertEqual(self.getJobFromHistory('project-test1').result,
1983 'SUCCESS')
1984 self.assertEqual(self.getJobFromHistory('project-test2').result,
1985 'SUCCESS')
Antoine Musso80edd5a2013-02-13 15:37:53 +01001986
James E. Blair3e98c022013-12-16 15:25:38 -08001987 def test_layered_templates(self):
1988 "Test whether a job generated via a template can be launched"
1989
1990 A = self.fake_gerrit.addFakeChange(
1991 'org/layered-project', 'master', 'A')
1992 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1993 self.waitUntilSettled()
1994
1995 self.assertEqual(self.getJobFromHistory('project-test1').result,
1996 'SUCCESS')
1997 self.assertEqual(self.getJobFromHistory('project-test2').result,
1998 'SUCCESS')
James E. Blairaea6cf62013-12-16 15:38:12 -08001999 self.assertEqual(self.getJobFromHistory('layered-project-test3'
2000 ).result, 'SUCCESS')
2001 self.assertEqual(self.getJobFromHistory('layered-project-test4'
2002 ).result, 'SUCCESS')
2003 # test5 should run twice because two templates define it
James E. Blair3e98c022013-12-16 15:25:38 -08002004 test5_count = 0
2005 for job in self.worker.build_history:
James E. Blairaea6cf62013-12-16 15:38:12 -08002006 if job.name == 'layered-project-foo-test5':
James E. Blair3e98c022013-12-16 15:25:38 -08002007 test5_count += 1
2008 self.assertEqual(job.result, 'SUCCESS')
2009 self.assertEqual(test5_count, 2)
2010 self.assertEqual(self.getJobFromHistory('project-test6').result,
2011 'SUCCESS')
2012
James E. Blaircaec0c52012-08-22 14:52:22 -07002013 def test_dependent_changes_dequeue(self):
2014 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002015
James E. Blaircaec0c52012-08-22 14:52:22 -07002016 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2017 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2018 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2019 A.addApproval('CRVW', 2)
2020 B.addApproval('CRVW', 2)
2021 C.addApproval('CRVW', 2)
2022
2023 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
2024 M1.setMerged()
2025
2026 # C -> B -> A -> M1
2027
2028 C.setDependsOn(B, 1)
2029 B.setDependsOn(A, 1)
2030 A.setDependsOn(M1, 1)
2031
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002032 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07002033
2034 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2035 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2036 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2037
2038 self.waitUntilSettled()
2039
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002040 self.assertEqual(A.data['status'], 'NEW')
2041 self.assertEqual(A.reported, 2)
2042 self.assertEqual(B.data['status'], 'NEW')
2043 self.assertEqual(B.reported, 2)
2044 self.assertEqual(C.data['status'], 'NEW')
2045 self.assertEqual(C.reported, 2)
2046 self.assertEqual(len(self.history), 1)
James E. Blairec590122012-08-22 15:19:31 -07002047
James E. Blair972e3c72013-08-29 12:04:55 -07002048 def test_failing_dependent_changes(self):
2049 "Test that failing dependent patches are taken out of stream"
2050 self.worker.hold_jobs_in_build = True
2051 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2052 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2053 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2054 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
2055 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
2056 A.addApproval('CRVW', 2)
2057 B.addApproval('CRVW', 2)
2058 C.addApproval('CRVW', 2)
2059 D.addApproval('CRVW', 2)
2060 E.addApproval('CRVW', 2)
2061
2062 # E, D -> C -> B, A
2063
2064 D.setDependsOn(C, 1)
2065 C.setDependsOn(B, 1)
2066
2067 self.worker.addFailTest('project-test1', B)
2068
2069 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2070 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2071 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2072 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2073 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
2074
2075 self.waitUntilSettled()
2076 self.worker.release('.*-merge')
2077 self.waitUntilSettled()
2078 self.worker.release('.*-merge')
2079 self.waitUntilSettled()
2080 self.worker.release('.*-merge')
2081 self.waitUntilSettled()
2082 self.worker.release('.*-merge')
2083 self.waitUntilSettled()
2084 self.worker.release('.*-merge')
2085 self.waitUntilSettled()
2086
2087 self.worker.hold_jobs_in_build = False
2088 for build in self.builds:
2089 if build.parameters['ZUUL_CHANGE'] != '1':
2090 build.release()
2091 self.waitUntilSettled()
2092
2093 self.worker.release()
2094 self.waitUntilSettled()
2095
2096 self.assertEqual(A.data['status'], 'MERGED')
2097 self.assertEqual(A.reported, 2)
2098 self.assertEqual(B.data['status'], 'NEW')
2099 self.assertEqual(B.reported, 2)
2100 self.assertEqual(C.data['status'], 'NEW')
2101 self.assertEqual(C.reported, 2)
2102 self.assertEqual(D.data['status'], 'NEW')
2103 self.assertEqual(D.reported, 2)
2104 self.assertEqual(E.data['status'], 'MERGED')
2105 self.assertEqual(E.reported, 2)
2106 self.assertEqual(len(self.history), 18)
2107
James E. Blairec590122012-08-22 15:19:31 -07002108 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08002109 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07002110 # If it's dequeued more than once, we should see extra
2111 # aborted jobs.
James E. Blairec590122012-08-22 15:19:31 -07002112
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002113 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07002114 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2115 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2116 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
2117 A.addApproval('CRVW', 2)
2118 B.addApproval('CRVW', 2)
2119 C.addApproval('CRVW', 2)
2120
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002121 self.worker.addFailTest('project1-test1', A)
2122 self.worker.addFailTest('project1-test2', A)
2123 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07002124
2125 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2126 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2127 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2128
2129 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07002130
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002131 self.assertEqual(len(self.builds), 1)
2132 self.assertEqual(self.builds[0].name, 'project1-merge')
2133 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairec590122012-08-22 15:19:31 -07002134
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002135 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07002136 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002137 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07002138 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002139 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07002140 self.waitUntilSettled()
2141
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002142 self.assertEqual(len(self.builds), 9)
2143 self.assertEqual(self.builds[0].name, 'project1-test1')
2144 self.assertEqual(self.builds[1].name, 'project1-test2')
2145 self.assertEqual(self.builds[2].name, 'project1-project2-integration')
2146 self.assertEqual(self.builds[3].name, 'project1-test1')
2147 self.assertEqual(self.builds[4].name, 'project1-test2')
2148 self.assertEqual(self.builds[5].name, 'project1-project2-integration')
2149 self.assertEqual(self.builds[6].name, 'project1-test1')
2150 self.assertEqual(self.builds[7].name, 'project1-test2')
2151 self.assertEqual(self.builds[8].name, 'project1-project2-integration')
James E. Blairec590122012-08-22 15:19:31 -07002152
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002153 self.release(self.builds[0])
James E. Blairec590122012-08-22 15:19:31 -07002154 self.waitUntilSettled()
2155
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002156 self.assertEqual(len(self.builds), 3) # test2,integration, merge for B
2157 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 6)
James E. Blairec590122012-08-22 15:19:31 -07002158
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002159 self.worker.hold_jobs_in_build = False
2160 self.worker.release()
James E. Blairec590122012-08-22 15:19:31 -07002161 self.waitUntilSettled()
2162
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002163 self.assertEqual(len(self.builds), 0)
2164 self.assertEqual(len(self.history), 20)
James E. Blaircaec0c52012-08-22 14:52:22 -07002165
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002166 self.assertEqual(A.data['status'], 'NEW')
2167 self.assertEqual(B.data['status'], 'MERGED')
2168 self.assertEqual(C.data['status'], 'MERGED')
2169 self.assertEqual(A.reported, 2)
2170 self.assertEqual(B.reported, 2)
2171 self.assertEqual(C.reported, 2)
James E. Blair4ec821f2012-08-23 15:28:28 -07002172
2173 def test_nonvoting_job(self):
2174 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002175
James E. Blair4ec821f2012-08-23 15:28:28 -07002176 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
2177 'master', 'A')
2178 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002179 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07002180 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2181
2182 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07002183
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002184 self.assertEqual(A.data['status'], 'MERGED')
2185 self.assertEqual(A.reported, 2)
2186 self.assertEqual(
2187 self.getJobFromHistory('nonvoting-project-merge').result,
2188 'SUCCESS')
2189 self.assertEqual(
2190 self.getJobFromHistory('nonvoting-project-test1').result,
2191 'SUCCESS')
2192 self.assertEqual(
2193 self.getJobFromHistory('nonvoting-project-test2').result,
2194 'FAILURE')
James E. Blaire0487072012-08-29 17:38:31 -07002195
2196 def test_check_queue_success(self):
2197 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002198
James E. Blaire0487072012-08-29 17:38:31 -07002199 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2200 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2201
2202 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07002203
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002204 self.assertEqual(A.data['status'], 'NEW')
2205 self.assertEqual(A.reported, 1)
2206 self.assertEqual(self.getJobFromHistory('project-merge').result,
2207 'SUCCESS')
2208 self.assertEqual(self.getJobFromHistory('project-test1').result,
2209 'SUCCESS')
2210 self.assertEqual(self.getJobFromHistory('project-test2').result,
2211 'SUCCESS')
James E. Blaire0487072012-08-29 17:38:31 -07002212
2213 def test_check_queue_failure(self):
2214 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002215
James E. Blaire0487072012-08-29 17:38:31 -07002216 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002217 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07002218 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2219
2220 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07002221
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002222 self.assertEqual(A.data['status'], 'NEW')
2223 self.assertEqual(A.reported, 1)
2224 self.assertEqual(self.getJobFromHistory('project-merge').result,
James E. Blair78e31b32013-07-09 09:11:34 -07002225 'SUCCESS')
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002226 self.assertEqual(self.getJobFromHistory('project-test1').result,
2227 'SUCCESS')
2228 self.assertEqual(self.getJobFromHistory('project-test2').result,
2229 'FAILURE')
James E. Blair127bc182012-08-28 15:55:15 -07002230
2231 def test_dependent_behind_dequeue(self):
2232 "test that dependent changes behind dequeued changes work"
2233 # This complicated test is a reproduction of a real life bug
2234 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07002235
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002236 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07002237 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2238 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2239 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
2240 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
2241 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
2242 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
2243 D.setDependsOn(C, 1)
2244 E.setDependsOn(D, 1)
2245 A.addApproval('CRVW', 2)
2246 B.addApproval('CRVW', 2)
2247 C.addApproval('CRVW', 2)
2248 D.addApproval('CRVW', 2)
2249 E.addApproval('CRVW', 2)
2250 F.addApproval('CRVW', 2)
2251
2252 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07002253
2254 # Change object re-use in the gerrit trigger is hidden if
2255 # changes are added in quick succession; waiting makes it more
2256 # like real life.
2257 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2258 self.waitUntilSettled()
2259 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2260 self.waitUntilSettled()
2261
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002262 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002263 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002264 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002265 self.waitUntilSettled()
2266
2267 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2268 self.waitUntilSettled()
2269 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2270 self.waitUntilSettled()
2271 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
2272 self.waitUntilSettled()
2273 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
2274 self.waitUntilSettled()
2275
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002276 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002277 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002278 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002279 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002280 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002281 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002282 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002283 self.waitUntilSettled()
2284
2285 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07002286
2287 # Grab pointers to the jobs we want to release before
2288 # releasing any, because list indexes may change as
2289 # the jobs complete.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002290 a, b, c = self.builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07002291 a.release()
2292 b.release()
2293 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07002294 self.waitUntilSettled()
2295
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002296 self.worker.hold_jobs_in_build = False
2297 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07002298 self.waitUntilSettled()
2299
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002300 self.assertEqual(A.data['status'], 'NEW')
2301 self.assertEqual(B.data['status'], 'MERGED')
2302 self.assertEqual(C.data['status'], 'MERGED')
2303 self.assertEqual(D.data['status'], 'MERGED')
2304 self.assertEqual(E.data['status'], 'MERGED')
2305 self.assertEqual(F.data['status'], 'MERGED')
James E. Blair127bc182012-08-28 15:55:15 -07002306
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002307 self.assertEqual(A.reported, 2)
2308 self.assertEqual(B.reported, 2)
2309 self.assertEqual(C.reported, 2)
2310 self.assertEqual(D.reported, 2)
2311 self.assertEqual(E.reported, 2)
2312 self.assertEqual(F.reported, 2)
James E. Blair127bc182012-08-28 15:55:15 -07002313
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002314 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 15)
2315 self.assertEqual(len(self.history), 44)
James E. Blair05fed602012-09-07 12:45:24 -07002316
2317 def test_merger_repack(self):
2318 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002319
James E. Blair05fed602012-09-07 12:45:24 -07002320 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2321 A.addApproval('CRVW', 2)
2322 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2323 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002324 self.assertEqual(self.getJobFromHistory('project-merge').result,
2325 'SUCCESS')
2326 self.assertEqual(self.getJobFromHistory('project-test1').result,
2327 'SUCCESS')
2328 self.assertEqual(self.getJobFromHistory('project-test2').result,
2329 'SUCCESS')
2330 self.assertEqual(A.data['status'], 'MERGED')
2331 self.assertEqual(A.reported, 2)
James E. Blair05fed602012-09-07 12:45:24 -07002332 self.assertEmptyQueues()
James E. Blair4ca985f2013-05-30 12:27:43 -07002333 self.worker.build_history = []
James E. Blair05fed602012-09-07 12:45:24 -07002334
Monty Taylorbc758832013-06-17 17:22:42 -04002335 path = os.path.join(self.git_root, "org/project")
2336 print repack_repo(path)
James E. Blair05fed602012-09-07 12:45:24 -07002337
2338 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2339 A.addApproval('CRVW', 2)
2340 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2341 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002342 self.assertEqual(self.getJobFromHistory('project-merge').result,
2343 'SUCCESS')
2344 self.assertEqual(self.getJobFromHistory('project-test1').result,
2345 'SUCCESS')
2346 self.assertEqual(self.getJobFromHistory('project-test2').result,
2347 'SUCCESS')
2348 self.assertEqual(A.data['status'], 'MERGED')
2349 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02002350
James E. Blair4886f282012-11-15 09:27:33 -08002351 def test_merger_repack_large_change(self):
2352 "Test that the merger works with large changes after a repack"
2353 # https://bugs.launchpad.net/zuul/+bug/1078946
James E. Blairac2c3242014-01-24 13:38:51 -08002354 # This test assumes the repo is already cloned; make sure it is
2355 url = self.sched.triggers['gerrit'].getGitUrl(
2356 self.sched.layout.projects['org/project1'])
2357 self.sched.merger.addProject('org/project1', url)
James E. Blair4886f282012-11-15 09:27:33 -08002358 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2359 A.addPatchset(large=True)
Monty Taylorbc758832013-06-17 17:22:42 -04002360 path = os.path.join(self.upstream_root, "org/project1")
2361 print repack_repo(path)
2362 path = os.path.join(self.git_root, "org/project1")
2363 print repack_repo(path)
James E. Blair4886f282012-11-15 09:27:33 -08002364
2365 A.addApproval('CRVW', 2)
2366 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2367 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002368 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2369 'SUCCESS')
2370 self.assertEqual(self.getJobFromHistory('project1-test1').result,
2371 'SUCCESS')
2372 self.assertEqual(self.getJobFromHistory('project1-test2').result,
2373 'SUCCESS')
2374 self.assertEqual(A.data['status'], 'MERGED')
2375 self.assertEqual(A.reported, 2)
James E. Blair4886f282012-11-15 09:27:33 -08002376
James E. Blair7ee88a22012-09-12 18:59:31 +02002377 def test_nonexistent_job(self):
2378 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002379 # Set to the state immediately after a restart
2380 self.resetGearmanServer()
2381 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02002382
2383 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2384 A.addApproval('CRVW', 2)
2385 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2386 # There may be a thread about to report a lost change
2387 while A.reported < 2:
2388 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002389 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002390 self.assertFalse(job_names)
2391 self.assertEqual(A.data['status'], 'NEW')
2392 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02002393 self.assertEmptyQueues()
2394
2395 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002396 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02002397 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2398 A.addApproval('CRVW', 2)
2399 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2400 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002401 self.assertEqual(self.getJobFromHistory('project-merge').result,
2402 'SUCCESS')
2403 self.assertEqual(self.getJobFromHistory('project-test1').result,
2404 'SUCCESS')
2405 self.assertEqual(self.getJobFromHistory('project-test2').result,
2406 'SUCCESS')
2407 self.assertEqual(A.data['status'], 'MERGED')
2408 self.assertEqual(A.reported, 2)
James E. Blairf62d4282012-12-31 17:01:50 -08002409
2410 def test_single_nonexistent_post_job(self):
2411 "Test launching a single post job that doesn't exist"
James E. Blairf62d4282012-12-31 17:01:50 -08002412 e = {
2413 "type": "ref-updated",
2414 "submitter": {
2415 "name": "User Name",
2416 },
2417 "refUpdate": {
2418 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
2419 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
2420 "refName": "master",
2421 "project": "org/project",
2422 }
2423 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002424 # Set to the state immediately after a restart
2425 self.resetGearmanServer()
2426 self.launcher.negative_function_cache_ttl = 0
2427
James E. Blairf62d4282012-12-31 17:01:50 -08002428 self.fake_gerrit.addEvent(e)
2429 self.waitUntilSettled()
2430
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002431 self.assertEqual(len(self.history), 0)
James E. Blair2fa50962013-01-30 21:50:41 -08002432
2433 def test_new_patchset_dequeues_old(self):
2434 "Test that a new patchset causes the old to be dequeued"
2435 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002436 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002437 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
2438 M.setMerged()
2439
2440 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2441 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2442 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2443 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
2444 A.addApproval('CRVW', 2)
2445 B.addApproval('CRVW', 2)
2446 C.addApproval('CRVW', 2)
2447 D.addApproval('CRVW', 2)
2448
2449 C.setDependsOn(B, 1)
2450 B.setDependsOn(A, 1)
2451 A.setDependsOn(M, 1)
2452
2453 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2454 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2455 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2456 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2457 self.waitUntilSettled()
2458
2459 B.addPatchset()
2460 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2461 self.waitUntilSettled()
2462
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002463 self.worker.hold_jobs_in_build = False
2464 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002465 self.waitUntilSettled()
2466
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002467 self.assertEqual(A.data['status'], 'MERGED')
2468 self.assertEqual(A.reported, 2)
2469 self.assertEqual(B.data['status'], 'NEW')
2470 self.assertEqual(B.reported, 2)
2471 self.assertEqual(C.data['status'], 'NEW')
2472 self.assertEqual(C.reported, 2)
2473 self.assertEqual(D.data['status'], 'MERGED')
2474 self.assertEqual(D.reported, 2)
2475 self.assertEqual(len(self.history), 9) # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08002476
Arx Cruzb1b010d2013-10-28 19:49:59 -02002477 def test_zuul_url_return(self):
2478 "Test if ZUUL_URL is returning when zuul_url is set in zuul.conf"
2479 self.assertTrue(self.sched.config.has_option('zuul', 'zuul_url'))
2480 self.worker.hold_jobs_in_build = True
2481
2482 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2483 A.addApproval('CRVW', 2)
2484 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2485 self.waitUntilSettled()
2486
2487 self.assertEqual(len(self.builds), 1)
2488 for build in self.builds:
2489 self.assertTrue('ZUUL_URL' in build.parameters)
2490
2491 self.worker.hold_jobs_in_build = False
2492 self.worker.release()
2493 self.waitUntilSettled()
2494
James E. Blair2fa50962013-01-30 21:50:41 -08002495 def test_new_patchset_dequeues_old_on_head(self):
2496 "Test that a new patchset causes the old to be dequeued (at head)"
2497 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002498 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002499 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
2500 M.setMerged()
2501 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2502 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2503 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2504 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
2505 A.addApproval('CRVW', 2)
2506 B.addApproval('CRVW', 2)
2507 C.addApproval('CRVW', 2)
2508 D.addApproval('CRVW', 2)
2509
2510 C.setDependsOn(B, 1)
2511 B.setDependsOn(A, 1)
2512 A.setDependsOn(M, 1)
2513
2514 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2515 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2516 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2517 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2518 self.waitUntilSettled()
2519
2520 A.addPatchset()
2521 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
2522 self.waitUntilSettled()
2523
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002524 self.worker.hold_jobs_in_build = False
2525 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002526 self.waitUntilSettled()
2527
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002528 self.assertEqual(A.data['status'], 'NEW')
2529 self.assertEqual(A.reported, 2)
2530 self.assertEqual(B.data['status'], 'NEW')
2531 self.assertEqual(B.reported, 2)
2532 self.assertEqual(C.data['status'], 'NEW')
2533 self.assertEqual(C.reported, 2)
2534 self.assertEqual(D.data['status'], 'MERGED')
2535 self.assertEqual(D.reported, 2)
2536 self.assertEqual(len(self.history), 7)
James E. Blair2fa50962013-01-30 21:50:41 -08002537
2538 def test_new_patchset_dequeues_old_without_dependents(self):
2539 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002540 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002541 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2542 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2543 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2544 A.addApproval('CRVW', 2)
2545 B.addApproval('CRVW', 2)
2546 C.addApproval('CRVW', 2)
2547
2548 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2549 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2550 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2551 self.waitUntilSettled()
2552
2553 B.addPatchset()
2554 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2555 self.waitUntilSettled()
2556
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002557 self.worker.hold_jobs_in_build = False
2558 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002559 self.waitUntilSettled()
2560
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002561 self.assertEqual(A.data['status'], 'MERGED')
2562 self.assertEqual(A.reported, 2)
2563 self.assertEqual(B.data['status'], 'NEW')
2564 self.assertEqual(B.reported, 2)
2565 self.assertEqual(C.data['status'], 'MERGED')
2566 self.assertEqual(C.reported, 2)
2567 self.assertEqual(len(self.history), 9)
James E. Blair2fa50962013-01-30 21:50:41 -08002568
2569 def test_new_patchset_dequeues_old_independent_queue(self):
2570 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002571 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002572 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2573 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2574 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2575 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2576 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2577 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2578 self.waitUntilSettled()
2579
2580 B.addPatchset()
2581 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2582 self.waitUntilSettled()
2583
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002584 self.worker.hold_jobs_in_build = False
2585 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002586 self.waitUntilSettled()
2587
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002588 self.assertEqual(A.data['status'], 'NEW')
2589 self.assertEqual(A.reported, 1)
2590 self.assertEqual(B.data['status'], 'NEW')
2591 self.assertEqual(B.reported, 1)
2592 self.assertEqual(C.data['status'], 'NEW')
2593 self.assertEqual(C.reported, 1)
2594 self.assertEqual(len(self.history), 10)
2595 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002596
2597 def test_zuul_refs(self):
2598 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002599 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08002600 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
2601 M1.setMerged()
2602 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
2603 M2.setMerged()
2604
2605 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2606 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2607 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
2608 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
2609 A.addApproval('CRVW', 2)
2610 B.addApproval('CRVW', 2)
2611 C.addApproval('CRVW', 2)
2612 D.addApproval('CRVW', 2)
2613 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2614 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2615 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2616 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2617
2618 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002619 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002620 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002621 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002622 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002623 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002624 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002625 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002626 self.waitUntilSettled()
2627
James E. Blair7d0dedc2013-02-21 17:26:09 -08002628 a_zref = b_zref = c_zref = d_zref = None
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002629 for x in self.builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08002630 if x.parameters['ZUUL_CHANGE'] == '3':
2631 a_zref = x.parameters['ZUUL_REF']
2632 if x.parameters['ZUUL_CHANGE'] == '4':
2633 b_zref = x.parameters['ZUUL_REF']
2634 if x.parameters['ZUUL_CHANGE'] == '5':
2635 c_zref = x.parameters['ZUUL_REF']
2636 if x.parameters['ZUUL_CHANGE'] == '6':
2637 d_zref = x.parameters['ZUUL_REF']
2638
2639 # There are... four... refs.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002640 self.assertIsNotNone(a_zref)
2641 self.assertIsNotNone(b_zref)
2642 self.assertIsNotNone(c_zref)
2643 self.assertIsNotNone(d_zref)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002644
2645 # And they should all be different
2646 refs = set([a_zref, b_zref, c_zref, d_zref])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002647 self.assertEqual(len(refs), 4)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002648
2649 # a ref should have a, not b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002650 self.assertTrue(self.ref_has_change(a_zref, A))
2651 self.assertFalse(self.ref_has_change(a_zref, B))
2652 self.assertFalse(self.ref_has_change(a_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002653
2654 # b ref should have a and b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002655 self.assertTrue(self.ref_has_change(b_zref, A))
2656 self.assertTrue(self.ref_has_change(b_zref, B))
2657 self.assertFalse(self.ref_has_change(b_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002658
2659 # c ref should have a and b in 1, c in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002660 self.assertTrue(self.ref_has_change(c_zref, A))
2661 self.assertTrue(self.ref_has_change(c_zref, B))
2662 self.assertTrue(self.ref_has_change(c_zref, C))
2663 self.assertFalse(self.ref_has_change(c_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002664
2665 # d ref should have a and b in 1, c and d in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002666 self.assertTrue(self.ref_has_change(d_zref, A))
2667 self.assertTrue(self.ref_has_change(d_zref, B))
2668 self.assertTrue(self.ref_has_change(d_zref, C))
2669 self.assertTrue(self.ref_has_change(d_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002670
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002671 self.worker.hold_jobs_in_build = False
2672 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002673 self.waitUntilSettled()
2674
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002675 self.assertEqual(A.data['status'], 'MERGED')
2676 self.assertEqual(A.reported, 2)
2677 self.assertEqual(B.data['status'], 'MERGED')
2678 self.assertEqual(B.reported, 2)
2679 self.assertEqual(C.data['status'], 'MERGED')
2680 self.assertEqual(C.reported, 2)
2681 self.assertEqual(D.data['status'], 'MERGED')
2682 self.assertEqual(D.reported, 2)
James E. Blair70c71582013-03-06 08:50:50 -08002683
James E. Blairc053d022014-01-22 14:57:33 -08002684 def test_required_approval_check_and_gate(self):
2685 "Test required-approval triggers both check and gate"
2686 self.config.set('zuul', 'layout_config',
2687 'tests/fixtures/layout-require-approval.yaml')
2688 self.sched.reconfigure(self.config)
2689 self.registerJobs()
2690
2691 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2692 A.addApproval('CRVW', 2)
2693 # Add a too-old +1
2694 A.addApproval('VRFY', 1, granted_on=time.time() - 72 * 60 * 60)
2695
2696 aprv = A.addApproval('APRV', 1)
2697 self.fake_gerrit.addEvent(aprv)
2698 self.waitUntilSettled()
2699 # Should have run a check job
2700 self.assertEqual(len(self.history), 1)
2701 self.assertEqual(self.history[0].name, 'project-check')
2702
2703 # Report the result of that check job (overrides previous vrfy)
2704 # Skynet alert: this should trigger a gate job now that
2705 # all reqs are met
2706 self.fake_gerrit.addEvent(A.addApproval('VRFY', 1))
2707 self.waitUntilSettled()
2708 self.assertEqual(len(self.history), 2)
2709 self.assertEqual(self.history[1].name, 'project-gate')
2710
2711 def test_required_approval_newer(self):
2712 "Test required-approval newer trigger parameter"
2713 self.config.set('zuul', 'layout_config',
2714 'tests/fixtures/layout-require-approval.yaml')
2715 self.sched.reconfigure(self.config)
2716 self.registerJobs()
2717
2718 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2719 A.addApproval('CRVW', 2)
2720 aprv = A.addApproval('APRV', 1)
2721 self.fake_gerrit.addEvent(aprv)
2722 self.waitUntilSettled()
2723 # No +1 from Jenkins so should not be enqueued
2724 self.assertEqual(len(self.history), 0)
2725
2726 # Add a too-old +1, should trigger check but not gate
2727 A.addApproval('VRFY', 1, granted_on=time.time() - 72 * 60 * 60)
2728 self.fake_gerrit.addEvent(aprv)
2729 self.waitUntilSettled()
2730 self.assertEqual(len(self.history), 1)
2731 self.assertEqual(self.history[0].name, 'project-check')
2732
2733 # Add a recent +1
2734 self.fake_gerrit.addEvent(A.addApproval('VRFY', 1))
2735 self.fake_gerrit.addEvent(aprv)
2736 self.waitUntilSettled()
2737 self.assertEqual(len(self.history), 2)
2738 self.assertEqual(self.history[1].name, 'project-gate')
2739
2740 def test_required_approval_older(self):
2741 "Test required-approval older trigger parameter"
2742 self.config.set('zuul', 'layout_config',
2743 'tests/fixtures/layout-require-approval.yaml')
2744 self.sched.reconfigure(self.config)
2745 self.registerJobs()
2746
2747 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2748 crvw = A.addApproval('CRVW', 2)
2749 self.fake_gerrit.addEvent(crvw)
2750 self.waitUntilSettled()
2751 # No +1 from Jenkins so should not be enqueued
2752 self.assertEqual(len(self.history), 0)
2753
2754 # Add an old +1 and trigger check with a comment
2755 A.addApproval('VRFY', 1, granted_on=time.time() - 72 * 60 * 60)
2756 self.fake_gerrit.addEvent(crvw)
2757 self.waitUntilSettled()
2758 self.assertEqual(len(self.history), 1)
2759 self.assertEqual(self.history[0].name, 'project-check')
2760
2761 # Add a recent +1 and make sure nothing changes
2762 A.addApproval('VRFY', 1)
2763 self.fake_gerrit.addEvent(crvw)
2764 self.waitUntilSettled()
2765 self.assertEqual(len(self.history), 1)
2766
2767 # The last thing we did was query a change then do nothing
2768 # with a pipeline, so it will be in the cache; clean it up so
2769 # it does not fail the test.
2770 for pipeline in self.sched.layout.pipelines.values():
2771 pipeline.trigger.maintainCache([])
2772
James E. Blair4a28a882013-08-23 15:17:33 -07002773 def test_rerun_on_error(self):
2774 "Test that if a worker fails to run a job, it is run again"
2775 self.worker.hold_jobs_in_build = True
2776 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2777 A.addApproval('CRVW', 2)
2778 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2779 self.waitUntilSettled()
2780
2781 self.builds[0].run_error = True
2782 self.worker.hold_jobs_in_build = False
2783 self.worker.release()
2784 self.waitUntilSettled()
2785 self.assertEqual(self.countJobResults(self.history, 'RUN_ERROR'), 1)
2786 self.assertEqual(self.countJobResults(self.history, 'SUCCESS'), 3)
2787
James E. Blair412e5582013-04-22 15:50:12 -07002788 def test_statsd(self):
2789 "Test each of the statsd methods used in the scheduler"
2790 import extras
2791 statsd = extras.try_import('statsd.statsd')
2792 statsd.incr('test-incr')
2793 statsd.timing('test-timing', 3)
2794 statsd.gauge('test-guage', 12)
2795 self.assertReportedStat('test-incr', '1|c')
2796 self.assertReportedStat('test-timing', '3|ms')
2797 self.assertReportedStat('test-guage', '12|g')
2798
James E. Blair70c71582013-03-06 08:50:50 -08002799 def test_file_jobs(self):
2800 "Test that file jobs run only when appropriate"
2801 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2802 A.addPatchset(['pip-requires'])
2803 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2804 A.addApproval('CRVW', 2)
2805 B.addApproval('CRVW', 2)
2806 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2807 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2808 self.waitUntilSettled()
2809
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002810 testfile_jobs = [x for x in self.history
James E. Blair70c71582013-03-06 08:50:50 -08002811 if x.name == 'project-testfile']
2812
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002813 self.assertEqual(len(testfile_jobs), 1)
2814 self.assertEqual(testfile_jobs[0].changes, '1,2')
2815 self.assertEqual(A.data['status'], 'MERGED')
2816 self.assertEqual(A.reported, 2)
2817 self.assertEqual(B.data['status'], 'MERGED')
2818 self.assertEqual(B.reported, 2)
James E. Blair3c5e5b52013-04-26 11:17:03 -07002819
2820 def test_test_config(self):
2821 "Test that we can test the config"
2822 sched = zuul.scheduler.Scheduler()
James E. Blair6c358e72013-07-29 17:06:47 -07002823 sched.registerTrigger(None, 'gerrit')
James E. Blair63bb0ef2013-07-29 17:14:51 -07002824 sched.registerTrigger(None, 'timer')
James E. Blair3c5e5b52013-04-26 11:17:03 -07002825 sched.testConfig(CONFIG.get('zuul', 'layout_config'))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002826
2827 def test_build_description(self):
2828 "Test that build descriptions update"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002829 self.worker.registerFunction('set_description:' +
2830 self.worker.worker_id)
2831
2832 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2833 A.addApproval('CRVW', 2)
2834 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2835 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002836 desc = self.history[0].description
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002837 self.log.debug("Description: %s" % desc)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002838 self.assertTrue(re.search("Branch.*master", desc))
2839 self.assertTrue(re.search("Pipeline.*gate", desc))
2840 self.assertTrue(re.search("project-merge.*SUCCESS", desc))
2841 self.assertTrue(re.search("project-test1.*SUCCESS", desc))
2842 self.assertTrue(re.search("project-test2.*SUCCESS", desc))
2843 self.assertTrue(re.search("Reported result.*SUCCESS", desc))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002844
James E. Blair64ed6f22013-07-10 14:07:23 -07002845 def test_queue_precedence(self):
2846 "Test that queue precedence works"
2847
2848 self.gearman_server.hold_jobs_in_queue = True
James E. Blair8de58bd2013-07-18 16:23:33 -07002849 self.worker.hold_jobs_in_build = True
James E. Blair64ed6f22013-07-10 14:07:23 -07002850 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2851 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2852 A.addApproval('CRVW', 2)
2853 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2854
2855 self.waitUntilSettled()
2856 self.gearman_server.hold_jobs_in_queue = False
2857 self.gearman_server.release()
2858 self.waitUntilSettled()
2859
James E. Blair8de58bd2013-07-18 16:23:33 -07002860 # Run one build at a time to ensure non-race order:
2861 for x in range(6):
2862 self.release(self.builds[0])
2863 self.waitUntilSettled()
2864 self.worker.hold_jobs_in_build = False
2865 self.waitUntilSettled()
2866
James E. Blair64ed6f22013-07-10 14:07:23 -07002867 self.log.debug(self.history)
2868 self.assertEqual(self.history[0].pipeline, 'gate')
2869 self.assertEqual(self.history[1].pipeline, 'check')
2870 self.assertEqual(self.history[2].pipeline, 'gate')
2871 self.assertEqual(self.history[3].pipeline, 'gate')
2872 self.assertEqual(self.history[4].pipeline, 'check')
2873 self.assertEqual(self.history[5].pipeline, 'check')
2874
James E. Blair1843a552013-07-03 14:19:52 -07002875 def test_json_status(self):
2876 "Test that we can retrieve JSON status info"
2877 self.worker.hold_jobs_in_build = True
2878 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2879 A.addApproval('CRVW', 2)
2880 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2881 self.waitUntilSettled()
2882
2883 port = self.webapp.server.socket.getsockname()[1]
2884
2885 f = urllib.urlopen("http://localhost:%s/status.json" % port)
2886 data = f.read()
2887
2888 self.worker.hold_jobs_in_build = False
2889 self.worker.release()
2890 self.waitUntilSettled()
2891
2892 data = json.loads(data)
2893 status_jobs = set()
2894 for p in data['pipelines']:
2895 for q in p['change_queues']:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002896 if q['dependent']:
2897 self.assertEqual(q['window'], 20)
2898 else:
2899 self.assertEqual(q['window'], 0)
James E. Blair1843a552013-07-03 14:19:52 -07002900 for head in q['heads']:
2901 for change in head:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002902 self.assertTrue(change['active'])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002903 self.assertEqual(change['id'], '1,1')
James E. Blair1843a552013-07-03 14:19:52 -07002904 for job in change['jobs']:
2905 status_jobs.add(job['name'])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002906 self.assertIn('project-merge', status_jobs)
2907 self.assertIn('project-test1', status_jobs)
2908 self.assertIn('project-test2', status_jobs)
James E. Blair1843a552013-07-03 14:19:52 -07002909
James E. Blairc3d428e2013-12-03 15:06:48 -08002910 def test_merging_queues(self):
2911 "Test that transitively-connected change queues are merged"
2912 self.config.set('zuul', 'layout_config',
2913 'tests/fixtures/layout-merge-queues.yaml')
2914 self.sched.reconfigure(self.config)
2915 self.assertEqual(len(self.sched.layout.pipelines['gate'].queues), 1)
2916
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002917 def test_node_label(self):
2918 "Test that a job runs on a specific node label"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002919 self.worker.registerFunction('build:node-project-test1:debian')
2920
2921 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2922 A.addApproval('CRVW', 2)
2923 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2924 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07002925
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002926 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2927 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2928 'debian')
2929 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
James E. Blaircdccd972013-07-01 12:10:22 -07002930
2931 def test_live_reconfiguration(self):
2932 "Test that live reconfiguration works"
2933 self.worker.hold_jobs_in_build = True
2934 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2935 A.addApproval('CRVW', 2)
2936 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2937 self.waitUntilSettled()
2938
2939 self.sched.reconfigure(self.config)
2940
2941 self.worker.hold_jobs_in_build = False
2942 self.worker.release()
2943 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002944 self.assertEqual(self.getJobFromHistory('project-merge').result,
2945 'SUCCESS')
2946 self.assertEqual(self.getJobFromHistory('project-test1').result,
2947 'SUCCESS')
2948 self.assertEqual(self.getJobFromHistory('project-test2').result,
2949 'SUCCESS')
2950 self.assertEqual(A.data['status'], 'MERGED')
2951 self.assertEqual(A.reported, 2)
James E. Blair287c06d2013-07-24 10:39:30 -07002952
James E. Blaire712d9f2013-07-31 11:40:11 -07002953 def test_live_reconfiguration_functions(self):
2954 "Test live reconfiguration with a custom function"
2955 self.worker.registerFunction('build:node-project-test1:debian')
2956 self.worker.registerFunction('build:node-project-test1:wheezy')
2957 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2958 A.addApproval('CRVW', 2)
2959 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2960 self.waitUntilSettled()
2961
2962 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2963 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2964 'debian')
2965 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2966
2967 self.config.set('zuul', 'layout_config',
2968 'tests/fixtures/layout-live-'
2969 'reconfiguration-functions.yaml')
2970 self.sched.reconfigure(self.config)
2971 self.worker.build_history = []
2972
2973 B = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'B')
2974 B.addApproval('CRVW', 2)
2975 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2976 self.waitUntilSettled()
2977
2978 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2979 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2980 'wheezy')
2981 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2982
James E. Blair287c06d2013-07-24 10:39:30 -07002983 def test_delayed_repo_init(self):
2984 self.config.set('zuul', 'layout_config',
2985 'tests/fixtures/layout-delayed-repo-init.yaml')
2986 self.sched.reconfigure(self.config)
2987
2988 self.init_repo("org/new-project")
2989 A = self.fake_gerrit.addFakeChange('org/new-project', 'master', 'A')
2990
2991 A.addApproval('CRVW', 2)
2992 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2993 self.waitUntilSettled()
2994 self.assertEqual(self.getJobFromHistory('project-merge').result,
2995 'SUCCESS')
2996 self.assertEqual(self.getJobFromHistory('project-test1').result,
2997 'SUCCESS')
2998 self.assertEqual(self.getJobFromHistory('project-test2').result,
2999 'SUCCESS')
3000 self.assertEqual(A.data['status'], 'MERGED')
3001 self.assertEqual(A.reported, 2)
James E. Blair63bb0ef2013-07-29 17:14:51 -07003002
Clark Boylan6dbbc482013-10-18 10:57:31 -07003003 def test_repo_deleted(self):
3004 self.config.set('zuul', 'layout_config',
3005 'tests/fixtures/layout-repo-deleted.yaml')
3006 self.sched.reconfigure(self.config)
3007
3008 self.init_repo("org/delete-project")
3009 A = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'A')
3010
3011 A.addApproval('CRVW', 2)
3012 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3013 self.waitUntilSettled()
3014 self.assertEqual(self.getJobFromHistory('project-merge').result,
3015 'SUCCESS')
3016 self.assertEqual(self.getJobFromHistory('project-test1').result,
3017 'SUCCESS')
3018 self.assertEqual(self.getJobFromHistory('project-test2').result,
3019 'SUCCESS')
3020 self.assertEqual(A.data['status'], 'MERGED')
3021 self.assertEqual(A.reported, 2)
3022
3023 # Delete org/new-project zuul repo. Should be recloned.
3024 shutil.rmtree(os.path.join(self.git_root, "org/delete-project"))
3025
3026 B = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'B')
3027
3028 B.addApproval('CRVW', 2)
3029 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3030 self.waitUntilSettled()
3031 self.assertEqual(self.getJobFromHistory('project-merge').result,
3032 'SUCCESS')
3033 self.assertEqual(self.getJobFromHistory('project-test1').result,
3034 'SUCCESS')
3035 self.assertEqual(self.getJobFromHistory('project-test2').result,
3036 'SUCCESS')
3037 self.assertEqual(B.data['status'], 'MERGED')
3038 self.assertEqual(B.reported, 2)
3039
James E. Blair63bb0ef2013-07-29 17:14:51 -07003040 def test_timer(self):
3041 "Test that a periodic job is triggered"
3042 self.worker.hold_jobs_in_build = True
3043 self.config.set('zuul', 'layout_config',
3044 'tests/fixtures/layout-timer.yaml')
3045 self.sched.reconfigure(self.config)
3046 self.registerJobs()
3047
3048 start = time.time()
3049 failed = True
3050 while ((time.time() - start) < 30):
3051 if len(self.builds) == 2:
3052 failed = False
3053 break
3054 else:
3055 time.sleep(1)
3056
3057 if failed:
3058 raise Exception("Expected jobs never ran")
3059
3060 self.waitUntilSettled()
3061 port = self.webapp.server.socket.getsockname()[1]
3062
3063 f = urllib.urlopen("http://localhost:%s/status.json" % port)
3064 data = f.read()
3065
3066 self.worker.hold_jobs_in_build = False
3067 self.worker.release()
3068 self.waitUntilSettled()
3069
3070 self.assertEqual(self.getJobFromHistory(
3071 'project-bitrot-stable-old').result, 'SUCCESS')
3072 self.assertEqual(self.getJobFromHistory(
3073 'project-bitrot-stable-older').result, 'SUCCESS')
3074
3075 data = json.loads(data)
3076 status_jobs = set()
3077 for p in data['pipelines']:
3078 for q in p['change_queues']:
3079 for head in q['heads']:
3080 for change in head:
Alex Gaynorddb9ef32013-09-16 21:04:58 -07003081 self.assertEqual(change['id'], None)
James E. Blair63bb0ef2013-07-29 17:14:51 -07003082 for job in change['jobs']:
3083 status_jobs.add(job['name'])
3084 self.assertIn('project-bitrot-stable-old', status_jobs)
3085 self.assertIn('project-bitrot-stable-older', status_jobs)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003086
3087 def test_check_smtp_pool(self):
3088 self.config.set('zuul', 'layout_config',
3089 'tests/fixtures/layout-smtp.yaml')
3090 self.sched.reconfigure(self.config)
3091
3092 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3093 self.waitUntilSettled()
3094
3095 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3096 self.waitUntilSettled()
3097
James E. Blairff80a2f2013-12-27 13:24:06 -08003098 self.assertEqual(len(self.smtp_messages), 2)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003099
3100 # A.messages only holds what FakeGerrit places in it. Thus we
3101 # work on the knowledge of what the first message should be as
3102 # it is only configured to go to SMTP.
3103
3104 self.assertEqual('zuul@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08003105 self.smtp_messages[0]['from_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003106 self.assertEqual(['you@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08003107 self.smtp_messages[0]['to_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003108 self.assertEqual('Starting check jobs.',
James E. Blairff80a2f2013-12-27 13:24:06 -08003109 self.smtp_messages[0]['body'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003110
3111 self.assertEqual('zuul_from@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08003112 self.smtp_messages[1]['from_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003113 self.assertEqual(['alternative_me@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08003114 self.smtp_messages[1]['to_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003115 self.assertEqual(A.messages[0],
James E. Blairff80a2f2013-12-27 13:24:06 -08003116 self.smtp_messages[1]['body'])
James E. Blairad28e912013-11-27 10:43:22 -08003117
James E. Blaire5910202013-12-27 09:50:31 -08003118 def test_timer_smtp(self):
3119 "Test that a periodic job is triggered"
3120 self.config.set('zuul', 'layout_config',
3121 'tests/fixtures/layout-timer-smtp.yaml')
3122 self.sched.reconfigure(self.config)
3123 self.registerJobs()
3124
3125 start = time.time()
3126 failed = True
3127 while ((time.time() - start) < 30):
3128 if len(self.history) == 2:
3129 failed = False
3130 break
3131 else:
3132 time.sleep(1)
3133
3134 if failed:
3135 raise Exception("Expected jobs never ran")
3136
3137 self.waitUntilSettled()
3138
3139 self.assertEqual(self.getJobFromHistory(
3140 'project-bitrot-stable-old').result, 'SUCCESS')
3141 self.assertEqual(self.getJobFromHistory(
3142 'project-bitrot-stable-older').result, 'SUCCESS')
3143
James E. Blairff80a2f2013-12-27 13:24:06 -08003144 self.assertEqual(len(self.smtp_messages), 1)
James E. Blaire5910202013-12-27 09:50:31 -08003145
3146 # A.messages only holds what FakeGerrit places in it. Thus we
3147 # work on the knowledge of what the first message should be as
3148 # it is only configured to go to SMTP.
3149
3150 self.assertEqual('zuul_from@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08003151 self.smtp_messages[0]['from_email'])
James E. Blaire5910202013-12-27 09:50:31 -08003152 self.assertEqual(['alternative_me@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08003153 self.smtp_messages[0]['to_email'])
James E. Blaire5910202013-12-27 09:50:31 -08003154 self.assertIn('Subject: Periodic check for org/project succeeded',
James E. Blairff80a2f2013-12-27 13:24:06 -08003155 self.smtp_messages[0]['headers'])
James E. Blaire5910202013-12-27 09:50:31 -08003156
James E. Blairad28e912013-11-27 10:43:22 -08003157 def test_client_enqueue(self):
3158 "Test that the RPC client can enqueue a change"
3159 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3160 A.addApproval('CRVW', 2)
3161 A.addApproval('APRV', 1)
3162
3163 client = zuul.rpcclient.RPCClient('127.0.0.1',
3164 self.gearman_server.port)
3165 r = client.enqueue(pipeline='gate',
3166 project='org/project',
3167 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003168 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003169 self.waitUntilSettled()
3170 self.assertEqual(self.getJobFromHistory('project-merge').result,
3171 'SUCCESS')
3172 self.assertEqual(self.getJobFromHistory('project-test1').result,
3173 'SUCCESS')
3174 self.assertEqual(self.getJobFromHistory('project-test2').result,
3175 'SUCCESS')
3176 self.assertEqual(A.data['status'], 'MERGED')
3177 self.assertEqual(A.reported, 2)
3178 self.assertEqual(r, True)
3179
3180 def test_client_enqueue_negative(self):
3181 "Test that the RPC client returns errors"
3182 client = zuul.rpcclient.RPCClient('127.0.0.1',
3183 self.gearman_server.port)
3184 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3185 "Invalid project"):
3186 r = client.enqueue(pipeline='gate',
3187 project='project-does-not-exist',
3188 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003189 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003190 client.shutdown()
3191 self.assertEqual(r, False)
3192
3193 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3194 "Invalid pipeline"):
3195 r = client.enqueue(pipeline='pipeline-does-not-exist',
3196 project='org/project',
3197 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003198 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003199 client.shutdown()
3200 self.assertEqual(r, False)
3201
3202 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3203 "Invalid trigger"):
3204 r = client.enqueue(pipeline='gate',
3205 project='org/project',
3206 trigger='trigger-does-not-exist',
James E. Blair36658cf2013-12-06 17:53:48 -08003207 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003208 client.shutdown()
3209 self.assertEqual(r, False)
3210
3211 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3212 "Invalid change"):
3213 r = client.enqueue(pipeline='gate',
3214 project='org/project',
3215 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003216 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003217 client.shutdown()
3218 self.assertEqual(r, False)
3219
3220 self.waitUntilSettled()
3221 self.assertEqual(len(self.history), 0)
3222 self.assertEqual(len(self.builds), 0)
James E. Blair36658cf2013-12-06 17:53:48 -08003223
3224 def test_client_promote(self):
3225 "Test that the RPC client can promote a change"
3226 self.worker.hold_jobs_in_build = True
3227 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3228 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3229 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3230 A.addApproval('CRVW', 2)
3231 B.addApproval('CRVW', 2)
3232 C.addApproval('CRVW', 2)
3233
3234 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3235 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3236 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3237
3238 self.waitUntilSettled()
3239
Sean Daguef39b9ca2014-01-10 21:34:35 -05003240 items = self.sched.layout.pipelines['gate'].getAllItems()
3241 enqueue_times = {}
3242 for item in items:
3243 enqueue_times[str(item.change)] = item.enqueue_time
3244
James E. Blair36658cf2013-12-06 17:53:48 -08003245 client = zuul.rpcclient.RPCClient('127.0.0.1',
3246 self.gearman_server.port)
3247 r = client.promote(pipeline='gate',
3248 change_ids=['2,1', '3,1'])
3249
Sean Daguef39b9ca2014-01-10 21:34:35 -05003250 # ensure that enqueue times are durable
3251 items = self.sched.layout.pipelines['gate'].getAllItems()
3252 for item in items:
3253 self.assertEqual(
3254 enqueue_times[str(item.change)], item.enqueue_time)
3255
James E. Blair78acec92014-02-06 07:11:32 -08003256 self.waitUntilSettled()
James E. Blair36658cf2013-12-06 17:53:48 -08003257 self.worker.release('.*-merge')
3258 self.waitUntilSettled()
3259 self.worker.release('.*-merge')
3260 self.waitUntilSettled()
3261 self.worker.release('.*-merge')
3262 self.waitUntilSettled()
3263
3264 self.assertEqual(len(self.builds), 6)
3265 self.assertEqual(self.builds[0].name, 'project-test1')
3266 self.assertEqual(self.builds[1].name, 'project-test2')
3267 self.assertEqual(self.builds[2].name, 'project-test1')
3268 self.assertEqual(self.builds[3].name, 'project-test2')
3269 self.assertEqual(self.builds[4].name, 'project-test1')
3270 self.assertEqual(self.builds[5].name, 'project-test2')
3271
3272 self.assertTrue(self.job_has_changes(self.builds[0], B))
3273 self.assertFalse(self.job_has_changes(self.builds[0], A))
3274 self.assertFalse(self.job_has_changes(self.builds[0], C))
3275
3276 self.assertTrue(self.job_has_changes(self.builds[2], B))
3277 self.assertTrue(self.job_has_changes(self.builds[2], C))
3278 self.assertFalse(self.job_has_changes(self.builds[2], A))
3279
3280 self.assertTrue(self.job_has_changes(self.builds[4], B))
3281 self.assertTrue(self.job_has_changes(self.builds[4], C))
3282 self.assertTrue(self.job_has_changes(self.builds[4], A))
3283
3284 self.worker.release()
3285 self.waitUntilSettled()
3286
3287 self.assertEqual(A.data['status'], 'MERGED')
3288 self.assertEqual(A.reported, 2)
3289 self.assertEqual(B.data['status'], 'MERGED')
3290 self.assertEqual(B.reported, 2)
3291 self.assertEqual(C.data['status'], 'MERGED')
3292 self.assertEqual(C.reported, 2)
3293
3294 client.shutdown()
3295 self.assertEqual(r, True)
3296
3297 def test_client_promote_dependent(self):
3298 "Test that the RPC client can promote a dependent change"
3299 # C (depends on B) -> B -> A ; then promote C to get:
3300 # A -> C (depends on B) -> B
3301 self.worker.hold_jobs_in_build = True
3302 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3303 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3304 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3305
3306 C.setDependsOn(B, 1)
3307
3308 A.addApproval('CRVW', 2)
3309 B.addApproval('CRVW', 2)
3310 C.addApproval('CRVW', 2)
3311
3312 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3313 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3314 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3315
3316 self.waitUntilSettled()
3317
3318 client = zuul.rpcclient.RPCClient('127.0.0.1',
3319 self.gearman_server.port)
3320 r = client.promote(pipeline='gate',
3321 change_ids=['3,1'])
3322
James E. Blair78acec92014-02-06 07:11:32 -08003323 self.waitUntilSettled()
James E. Blair36658cf2013-12-06 17:53:48 -08003324 self.worker.release('.*-merge')
3325 self.waitUntilSettled()
3326 self.worker.release('.*-merge')
3327 self.waitUntilSettled()
3328 self.worker.release('.*-merge')
3329 self.waitUntilSettled()
3330
3331 self.assertEqual(len(self.builds), 6)
3332 self.assertEqual(self.builds[0].name, 'project-test1')
3333 self.assertEqual(self.builds[1].name, 'project-test2')
3334 self.assertEqual(self.builds[2].name, 'project-test1')
3335 self.assertEqual(self.builds[3].name, 'project-test2')
3336 self.assertEqual(self.builds[4].name, 'project-test1')
3337 self.assertEqual(self.builds[5].name, 'project-test2')
3338
3339 self.assertTrue(self.job_has_changes(self.builds[0], B))
3340 self.assertFalse(self.job_has_changes(self.builds[0], A))
3341 self.assertFalse(self.job_has_changes(self.builds[0], C))
3342
3343 self.assertTrue(self.job_has_changes(self.builds[2], B))
3344 self.assertTrue(self.job_has_changes(self.builds[2], C))
3345 self.assertFalse(self.job_has_changes(self.builds[2], A))
3346
3347 self.assertTrue(self.job_has_changes(self.builds[4], B))
3348 self.assertTrue(self.job_has_changes(self.builds[4], C))
3349 self.assertTrue(self.job_has_changes(self.builds[4], A))
3350
3351 self.worker.release()
3352 self.waitUntilSettled()
3353
3354 self.assertEqual(A.data['status'], 'MERGED')
3355 self.assertEqual(A.reported, 2)
3356 self.assertEqual(B.data['status'], 'MERGED')
3357 self.assertEqual(B.reported, 2)
3358 self.assertEqual(C.data['status'], 'MERGED')
3359 self.assertEqual(C.reported, 2)
3360
3361 client.shutdown()
3362 self.assertEqual(r, True)
3363
3364 def test_client_promote_negative(self):
3365 "Test that the RPC client returns errors for promotion"
3366 self.worker.hold_jobs_in_build = True
3367 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3368 A.addApproval('CRVW', 2)
3369 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3370 self.waitUntilSettled()
3371
3372 client = zuul.rpcclient.RPCClient('127.0.0.1',
3373 self.gearman_server.port)
3374
3375 with testtools.ExpectedException(zuul.rpcclient.RPCFailure):
3376 r = client.promote(pipeline='nonexistent',
3377 change_ids=['2,1', '3,1'])
3378 client.shutdown()
3379 self.assertEqual(r, False)
3380
3381 with testtools.ExpectedException(zuul.rpcclient.RPCFailure):
3382 r = client.promote(pipeline='gate',
3383 change_ids=['4,1'])
3384 client.shutdown()
3385 self.assertEqual(r, False)
3386
3387 self.worker.hold_jobs_in_build = False
3388 self.worker.release()
3389 self.waitUntilSettled()
Clark Boylan7603a372014-01-21 11:43:20 -08003390
3391 def test_queue_rate_limiting(self):
3392 "Test that DependentPipelines are rate limited with dep across window"
3393 self.config.set('zuul', 'layout_config',
3394 'tests/fixtures/layout-rate-limit.yaml')
3395 self.sched.reconfigure(self.config)
3396 self.worker.hold_jobs_in_build = True
3397 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3398 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3399 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3400
3401 C.setDependsOn(B, 1)
3402 self.worker.addFailTest('project-test1', A)
3403
3404 A.addApproval('CRVW', 2)
3405 B.addApproval('CRVW', 2)
3406 C.addApproval('CRVW', 2)
3407
3408 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3409 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3410 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3411 self.waitUntilSettled()
3412
3413 # Only A and B will have their merge jobs queued because
3414 # window is 2.
3415 self.assertEqual(len(self.builds), 2)
3416 self.assertEqual(self.builds[0].name, 'project-merge')
3417 self.assertEqual(self.builds[1].name, 'project-merge')
3418
3419 self.worker.release('.*-merge')
3420 self.waitUntilSettled()
3421 self.worker.release('.*-merge')
3422 self.waitUntilSettled()
3423
3424 # Only A and B will have their test jobs queued because
3425 # window is 2.
3426 self.assertEqual(len(self.builds), 4)
3427 self.assertEqual(self.builds[0].name, 'project-test1')
3428 self.assertEqual(self.builds[1].name, 'project-test2')
3429 self.assertEqual(self.builds[2].name, 'project-test1')
3430 self.assertEqual(self.builds[3].name, 'project-test2')
3431
3432 self.worker.release('project-.*')
3433 self.waitUntilSettled()
3434
3435 queue = self.sched.layout.pipelines['gate'].queues[0]
3436 # A failed so window is reduced by 1 to 1.
3437 self.assertEqual(queue.window, 1)
3438 self.assertEqual(queue.window_floor, 1)
3439 self.assertEqual(A.data['status'], 'NEW')
3440
3441 # Gate is reset and only B's merge job is queued because
3442 # window shrunk to 1.
3443 self.assertEqual(len(self.builds), 1)
3444 self.assertEqual(self.builds[0].name, 'project-merge')
3445
3446 self.worker.release('.*-merge')
3447 self.waitUntilSettled()
3448
3449 # Only B's test jobs are queued because window is still 1.
3450 self.assertEqual(len(self.builds), 2)
3451 self.assertEqual(self.builds[0].name, 'project-test1')
3452 self.assertEqual(self.builds[1].name, 'project-test2')
3453
3454 self.worker.release('project-.*')
3455 self.waitUntilSettled()
3456
3457 # B was successfully merged so window is increased to 2.
3458 self.assertEqual(queue.window, 2)
3459 self.assertEqual(queue.window_floor, 1)
3460 self.assertEqual(B.data['status'], 'MERGED')
3461
3462 # Only C is left and its merge job is queued.
3463 self.assertEqual(len(self.builds), 1)
3464 self.assertEqual(self.builds[0].name, 'project-merge')
3465
3466 self.worker.release('.*-merge')
3467 self.waitUntilSettled()
3468
3469 # After successful merge job the test jobs for C are queued.
3470 self.assertEqual(len(self.builds), 2)
3471 self.assertEqual(self.builds[0].name, 'project-test1')
3472 self.assertEqual(self.builds[1].name, 'project-test2')
3473
3474 self.worker.release('project-.*')
3475 self.waitUntilSettled()
3476
3477 # C successfully merged so window is bumped to 3.
3478 self.assertEqual(queue.window, 3)
3479 self.assertEqual(queue.window_floor, 1)
3480 self.assertEqual(C.data['status'], 'MERGED')
3481
3482 def test_queue_rate_limiting_dependent(self):
3483 "Test that DependentPipelines are rate limited with dep in window"
3484 self.config.set('zuul', 'layout_config',
3485 'tests/fixtures/layout-rate-limit.yaml')
3486 self.sched.reconfigure(self.config)
3487 self.worker.hold_jobs_in_build = True
3488 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3489 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3490 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3491
3492 B.setDependsOn(A, 1)
3493
3494 self.worker.addFailTest('project-test1', A)
3495
3496 A.addApproval('CRVW', 2)
3497 B.addApproval('CRVW', 2)
3498 C.addApproval('CRVW', 2)
3499
3500 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3501 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3502 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3503 self.waitUntilSettled()
3504
3505 # Only A and B will have their merge jobs queued because
3506 # window is 2.
3507 self.assertEqual(len(self.builds), 2)
3508 self.assertEqual(self.builds[0].name, 'project-merge')
3509 self.assertEqual(self.builds[1].name, 'project-merge')
3510
3511 self.worker.release('.*-merge')
3512 self.waitUntilSettled()
3513 self.worker.release('.*-merge')
3514 self.waitUntilSettled()
3515
3516 # Only A and B will have their test jobs queued because
3517 # window is 2.
3518 self.assertEqual(len(self.builds), 4)
3519 self.assertEqual(self.builds[0].name, 'project-test1')
3520 self.assertEqual(self.builds[1].name, 'project-test2')
3521 self.assertEqual(self.builds[2].name, 'project-test1')
3522 self.assertEqual(self.builds[3].name, 'project-test2')
3523
3524 self.worker.release('project-.*')
3525 self.waitUntilSettled()
3526
3527 queue = self.sched.layout.pipelines['gate'].queues[0]
3528 # A failed so window is reduced by 1 to 1.
3529 self.assertEqual(queue.window, 1)
3530 self.assertEqual(queue.window_floor, 1)
3531 self.assertEqual(A.data['status'], 'NEW')
3532 self.assertEqual(B.data['status'], 'NEW')
3533
3534 # Gate is reset and only C's merge job is queued because
3535 # window shrunk to 1 and A and B were dequeued.
3536 self.assertEqual(len(self.builds), 1)
3537 self.assertEqual(self.builds[0].name, 'project-merge')
3538
3539 self.worker.release('.*-merge')
3540 self.waitUntilSettled()
3541
3542 # Only C's test jobs are queued because window is still 1.
3543 self.assertEqual(len(self.builds), 2)
3544 self.assertEqual(self.builds[0].name, 'project-test1')
3545 self.assertEqual(self.builds[1].name, 'project-test2')
3546
3547 self.worker.release('project-.*')
3548 self.waitUntilSettled()
3549
3550 # C was successfully merged so window is increased to 2.
3551 self.assertEqual(queue.window, 2)
3552 self.assertEqual(queue.window_floor, 1)
3553 self.assertEqual(C.data['status'], 'MERGED')