blob: a473ccb2445fc5e8cb356c90f1b5973b801f0834 [file] [log] [blame]
James E. Blairb0fcae42012-07-17 11:12:10 -07001#!/usr/bin/env python
2
3# Copyright 2012 Hewlett-Packard Development Company, L.P.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
James E. Blairb0fcae42012-07-17 11:12:10 -070017import ConfigParser
Monty Taylorbc758832013-06-17 17:22:42 -040018from cStringIO import StringIO
James E. Blair8cc15a82012-08-01 11:17:57 -070019import hashlib
James E. Blairb0fcae42012-07-17 11:12:10 -070020import json
Monty Taylorbc758832013-06-17 17:22:42 -040021import logging
22import os
James E. Blairb0fcae42012-07-17 11:12:10 -070023import pprint
Monty Taylorbc758832013-06-17 17:22:42 -040024import Queue
25import random
James E. Blairb0fcae42012-07-17 11:12:10 -070026import re
James E. Blair412e5582013-04-22 15:50:12 -070027import select
James E. Blair4886cc12012-07-18 15:39:41 -070028import shutil
James E. Blair412e5582013-04-22 15:50:12 -070029import socket
James E. Blair4886f282012-11-15 09:27:33 -080030import string
Monty Taylorbc758832013-06-17 17:22:42 -040031import subprocess
Monty Taylorbc758832013-06-17 17:22:42 -040032import threading
33import time
James E. Blair1843a552013-07-03 14:19:52 -070034import urllib
Monty Taylorbc758832013-06-17 17:22:42 -040035import urllib2
36import urlparse
37
James E. Blair4886cc12012-07-18 15:39:41 -070038import git
James E. Blair1f4c2bb2013-04-26 08:40:46 -070039import gear
Monty Taylorbc758832013-06-17 17:22:42 -040040import fixtures
41import statsd
42import testtools
James E. Blairb0fcae42012-07-17 11:12:10 -070043
James E. Blairb0fcae42012-07-17 11:12:10 -070044import zuul.scheduler
James E. Blair1843a552013-07-03 14:19:52 -070045import zuul.webapp
James E. Blair1f4c2bb2013-04-26 08:40:46 -070046import zuul.launcher.gearman
Joshua Hesketh1879cf72013-08-19 14:13:15 +100047import zuul.reporter.gerrit
James E. Blairb0fcae42012-07-17 11:12:10 -070048import zuul.trigger.gerrit
James E. Blair63bb0ef2013-07-29 17:14:51 -070049import zuul.trigger.timer
James E. Blairb0fcae42012-07-17 11:12:10 -070050
51FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
52 'fixtures')
53CONFIG = ConfigParser.ConfigParser()
54CONFIG.read(os.path.join(FIXTURE_DIR, "zuul.conf"))
55
56CONFIG.set('zuul', 'layout_config',
57 os.path.join(FIXTURE_DIR, "layout.yaml"))
58
James E. Blair1f4c2bb2013-04-26 08:40:46 -070059logging.basicConfig(level=logging.DEBUG,
60 format='%(asctime)s %(name)-32s '
61 '%(levelname)-8s %(message)s')
James E. Blairb0fcae42012-07-17 11:12:10 -070062
63
Monty Taylorbc758832013-06-17 17:22:42 -040064def repack_repo(path):
65 output = subprocess.Popen(
66 ['git', '--git-dir=%s/.git' % path, 'repack', '-afd'],
67 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
68 out = output.communicate()
69 if output.returncode:
70 raise Exception("git repack returned %d" % output.returncode)
71 return out
72
73
James E. Blair8cc15a82012-08-01 11:17:57 -070074def random_sha1():
75 return hashlib.sha1(str(random.random())).hexdigest()
76
77
James E. Blair4886cc12012-07-18 15:39:41 -070078class ChangeReference(git.Reference):
79 _common_path_default = "refs/changes"
80 _points_to_commits_only = True
81
82
James E. Blairb0fcae42012-07-17 11:12:10 -070083class FakeChange(object):
James E. Blair8c803f82012-07-31 16:25:42 -070084 categories = {'APRV': ('Approved', -1, 1),
85 'CRVW': ('Code-Review', -2, 2),
86 'VRFY': ('Verified', -2, 2)}
James E. Blairb0fcae42012-07-17 11:12:10 -070087
Monty Taylorbc758832013-06-17 17:22:42 -040088 def __init__(self, gerrit, number, project, branch, subject,
89 status='NEW', upstream_root=None):
James E. Blair8cc15a82012-08-01 11:17:57 -070090 self.gerrit = gerrit
James E. Blaird466dc42012-07-31 10:42:56 -070091 self.reported = 0
James E. Blair8c803f82012-07-31 16:25:42 -070092 self.queried = 0
James E. Blairb0fcae42012-07-17 11:12:10 -070093 self.patchsets = []
James E. Blairb0fcae42012-07-17 11:12:10 -070094 self.number = number
95 self.project = project
96 self.branch = branch
97 self.subject = subject
98 self.latest_patchset = 0
James E. Blair8c803f82012-07-31 16:25:42 -070099 self.depends_on_change = None
100 self.needed_by_changes = []
James E. Blair127bc182012-08-28 15:55:15 -0700101 self.fail_merge = False
James E. Blair42f74822013-05-14 15:18:03 -0700102 self.messages = []
James E. Blairb0fcae42012-07-17 11:12:10 -0700103 self.data = {
104 'branch': branch,
105 'comments': [],
106 'commitMessage': subject,
107 'createdOn': time.time(),
James E. Blair8cc15a82012-08-01 11:17:57 -0700108 'id': 'I' + random_sha1(),
James E. Blairb0fcae42012-07-17 11:12:10 -0700109 'lastUpdated': time.time(),
110 'number': str(number),
111 'open': True,
112 'owner': {'email': 'user@example.com',
113 'name': 'User Name',
114 'username': 'username'},
115 'patchSets': self.patchsets,
116 'project': project,
117 'status': status,
118 'subject': subject,
James E. Blair8c803f82012-07-31 16:25:42 -0700119 'submitRecords': [],
James E. Blairb0fcae42012-07-17 11:12:10 -0700120 'url': 'https://hostname/%s' % number}
121
Monty Taylorbc758832013-06-17 17:22:42 -0400122 self.upstream_root = upstream_root
James E. Blairb0fcae42012-07-17 11:12:10 -0700123 self.addPatchset()
James E. Blair8c803f82012-07-31 16:25:42 -0700124 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700125
Monty Taylorbc758832013-06-17 17:22:42 -0400126 def add_fake_change_to_repo(self, msg, fn, large):
127 path = os.path.join(self.upstream_root, self.project)
128 repo = git.Repo(path)
129 ref = ChangeReference.create(repo, '1/%s/%s' % (self.number,
130 self.latest_patchset),
131 'refs/tags/init')
132 repo.head.reference = ref
133 repo.head.reset(index=True, working_tree=True)
134 repo.git.clean('-x', '-f', '-d')
135
136 path = os.path.join(self.upstream_root, self.project)
137 if not large:
138 fn = os.path.join(path, fn)
139 f = open(fn, 'w')
140 f.write("test %s %s %s\n" %
141 (self.branch, self.number, self.latest_patchset))
142 f.close()
143 repo.index.add([fn])
144 else:
145 for fni in range(100):
146 fn = os.path.join(path, str(fni))
147 f = open(fn, 'w')
148 for ci in range(4096):
149 f.write(random.choice(string.printable))
150 f.close()
151 repo.index.add([fn])
152
James E. Blair287c06d2013-07-24 10:39:30 -0700153 r = repo.index.commit(msg)
154 repo.head.reference = 'master'
155 repo.head.reset(index=True, working_tree=True)
156 repo.git.clean('-x', '-f', '-d')
157 return r
Monty Taylorbc758832013-06-17 17:22:42 -0400158
James E. Blair70c71582013-03-06 08:50:50 -0800159 def addPatchset(self, files=[], large=False):
James E. Blairb0fcae42012-07-17 11:12:10 -0700160 self.latest_patchset += 1
James E. Blairdaabed22012-08-15 15:38:57 -0700161 if files:
162 fn = files[0]
163 else:
164 fn = '%s-%s' % (self.branch, self.number)
165 msg = self.subject + '-' + str(self.latest_patchset)
Monty Taylorbc758832013-06-17 17:22:42 -0400166 c = self.add_fake_change_to_repo(msg, fn, large)
James E. Blair70c71582013-03-06 08:50:50 -0800167 ps_files = [{'file': '/COMMIT_MSG',
168 'type': 'ADDED'},
169 {'file': 'README',
170 'type': 'MODIFIED'}]
171 for f in files:
172 ps_files.append({'file': f, 'type': 'ADDED'})
James E. Blairb0fcae42012-07-17 11:12:10 -0700173 d = {'approvals': [],
174 'createdOn': time.time(),
James E. Blair70c71582013-03-06 08:50:50 -0800175 'files': ps_files,
James E. Blair8c803f82012-07-31 16:25:42 -0700176 'number': str(self.latest_patchset),
James E. Blairb0fcae42012-07-17 11:12:10 -0700177 'ref': 'refs/changes/1/%s/%s' % (self.number,
178 self.latest_patchset),
James E. Blairdaabed22012-08-15 15:38:57 -0700179 'revision': c.hexsha,
James E. Blairb0fcae42012-07-17 11:12:10 -0700180 'uploader': {'email': 'user@example.com',
181 'name': 'User name',
182 'username': 'user'}}
183 self.data['currentPatchSet'] = d
184 self.patchsets.append(d)
James E. Blair8c803f82012-07-31 16:25:42 -0700185 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700186
James E. Blaire0487072012-08-29 17:38:31 -0700187 def getPatchsetCreatedEvent(self, patchset):
188 event = {"type": "patchset-created",
189 "change": {"project": self.project,
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800190 "branch": self.branch,
191 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
192 "number": str(self.number),
193 "subject": self.subject,
194 "owner": {"name": "User Name"},
195 "url": "https://hostname/3"},
James E. Blaire0487072012-08-29 17:38:31 -0700196 "patchSet": self.patchsets[patchset - 1],
197 "uploader": {"name": "User Name"}}
198 return event
199
James E. Blair42f74822013-05-14 15:18:03 -0700200 def getChangeRestoredEvent(self):
201 event = {"type": "change-restored",
202 "change": {"project": self.project,
203 "branch": self.branch,
204 "id": "I5459869c07352a31bfb1e7a8cac379cabfcb25af",
205 "number": str(self.number),
206 "subject": self.subject,
207 "owner": {"name": "User Name"},
208 "url": "https://hostname/3"},
209 "restorer": {"name": "User Name"},
210 "reason": ""}
211 return event
212
James E. Blairb0fcae42012-07-17 11:12:10 -0700213 def addApproval(self, category, value):
James E. Blair8c803f82012-07-31 16:25:42 -0700214 approval = {'description': self.categories[category][0],
215 'type': category,
216 'value': str(value)}
217 self.patchsets[-1]['approvals'].append(approval)
218 event = {'approvals': [approval],
James E. Blairb0fcae42012-07-17 11:12:10 -0700219 'author': {'email': 'user@example.com',
220 'name': 'User Name',
221 'username': 'username'},
222 'change': {'branch': self.branch,
223 'id': 'Iaa69c46accf97d0598111724a38250ae76a22c87',
224 'number': str(self.number),
225 'owner': {'email': 'user@example.com',
226 'name': 'User Name',
227 'username': 'username'},
228 'project': self.project,
229 'subject': self.subject,
230 'topic': 'master',
231 'url': 'https://hostname/459'},
232 'comment': '',
233 'patchSet': self.patchsets[-1],
234 'type': 'comment-added'}
James E. Blair8c803f82012-07-31 16:25:42 -0700235 self.data['submitRecords'] = self.getSubmitRecords()
James E. Blairb0fcae42012-07-17 11:12:10 -0700236 return json.loads(json.dumps(event))
237
James E. Blair8c803f82012-07-31 16:25:42 -0700238 def getSubmitRecords(self):
239 status = {}
240 for cat in self.categories.keys():
241 status[cat] = 0
242
243 for a in self.patchsets[-1]['approvals']:
244 cur = status[a['type']]
245 cat_min, cat_max = self.categories[a['type']][1:]
246 new = int(a['value'])
247 if new == cat_min:
248 cur = new
249 elif abs(new) > abs(cur):
250 cur = new
251 status[a['type']] = cur
252
253 labels = []
254 ok = True
255 for typ, cat in self.categories.items():
256 cur = status[typ]
257 cat_min, cat_max = cat[1:]
258 if cur == cat_min:
259 value = 'REJECT'
260 ok = False
261 elif cur == cat_max:
262 value = 'OK'
263 else:
264 value = 'NEED'
265 ok = False
266 labels.append({'label': cat[0], 'status': value})
267 if ok:
268 return [{'status': 'OK'}]
269 return [{'status': 'NOT_READY',
270 'labels': labels}]
271
272 def setDependsOn(self, other, patchset):
273 self.depends_on_change = other
274 d = {'id': other.data['id'],
275 'number': other.data['number'],
276 'ref': other.patchsets[patchset - 1]['ref']
277 }
278 self.data['dependsOn'] = [d]
279
280 other.needed_by_changes.append(self)
281 needed = other.data.get('neededBy', [])
282 d = {'id': self.data['id'],
283 'number': self.data['number'],
284 'ref': self.patchsets[patchset - 1]['ref'],
285 'revision': self.patchsets[patchset - 1]['revision']
286 }
287 needed.append(d)
288 other.data['neededBy'] = needed
289
James E. Blairb0fcae42012-07-17 11:12:10 -0700290 def query(self):
James E. Blair8c803f82012-07-31 16:25:42 -0700291 self.queried += 1
292 d = self.data.get('dependsOn')
293 if d:
294 d = d[0]
295 if (self.depends_on_change.patchsets[-1]['ref'] == d['ref']):
296 d['isCurrentPatchSet'] = True
297 else:
298 d['isCurrentPatchSet'] = False
James E. Blairb0fcae42012-07-17 11:12:10 -0700299 return json.loads(json.dumps(self.data))
300
301 def setMerged(self):
Zhongyue Luoaa85ebf2012-09-21 16:38:33 +0800302 if (self.depends_on_change and
303 self.depends_on_change.data['status'] != 'MERGED'):
James E. Blaircaec0c52012-08-22 14:52:22 -0700304 return
James E. Blair127bc182012-08-28 15:55:15 -0700305 if self.fail_merge:
306 return
James E. Blairb0fcae42012-07-17 11:12:10 -0700307 self.data['status'] = 'MERGED'
308 self.open = False
James E. Blairdaabed22012-08-15 15:38:57 -0700309
Monty Taylorbc758832013-06-17 17:22:42 -0400310 path = os.path.join(self.upstream_root, self.project)
James E. Blairdaabed22012-08-15 15:38:57 -0700311 repo = git.Repo(path)
312 repo.heads[self.branch].commit = \
313 repo.commit(self.patchsets[-1]['revision'])
James E. Blairb0fcae42012-07-17 11:12:10 -0700314
James E. Blaird466dc42012-07-31 10:42:56 -0700315 def setReported(self):
316 self.reported += 1
317
James E. Blairb0fcae42012-07-17 11:12:10 -0700318
319class FakeGerrit(object):
320 def __init__(self, *args, **kw):
321 self.event_queue = Queue.Queue()
322 self.fixture_dir = os.path.join(FIXTURE_DIR, 'gerrit')
323 self.change_number = 0
324 self.changes = {}
325
326 def addFakeChange(self, project, branch, subject):
327 self.change_number += 1
Monty Taylorbc758832013-06-17 17:22:42 -0400328 c = FakeChange(self, self.change_number, project, branch, subject,
329 upstream_root=self.upstream_root)
James E. Blairb0fcae42012-07-17 11:12:10 -0700330 self.changes[self.change_number] = c
331 return c
332
333 def addEvent(self, data):
334 return self.event_queue.put(data)
335
336 def getEvent(self):
337 return self.event_queue.get()
338
339 def eventDone(self):
340 self.event_queue.task_done()
341
342 def review(self, project, changeid, message, action):
James E. Blaird466dc42012-07-31 10:42:56 -0700343 number, ps = changeid.split(',')
344 change = self.changes[int(number)]
James E. Blair42f74822013-05-14 15:18:03 -0700345 change.messages.append(message)
James E. Blairb0fcae42012-07-17 11:12:10 -0700346 if 'submit' in action:
James E. Blairb0fcae42012-07-17 11:12:10 -0700347 change.setMerged()
James E. Blaird466dc42012-07-31 10:42:56 -0700348 if message:
349 change.setReported()
James E. Blairb0fcae42012-07-17 11:12:10 -0700350
351 def query(self, number):
352 change = self.changes[int(number)]
353 return change.query()
354
355 def startWatching(self, *args, **kw):
356 pass
357
358
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700359class BuildHistory(object):
360 def __init__(self, **kw):
361 self.__dict__.update(kw)
James E. Blairb0fcae42012-07-17 11:12:10 -0700362
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700363 def __repr__(self):
364 return ("<Completed build, result: %s name: %s #%s changes: %s>" %
365 (self.result, self.name, self.number, self.changes))
James E. Blairb0fcae42012-07-17 11:12:10 -0700366
367
James E. Blair8cc15a82012-08-01 11:17:57 -0700368class FakeURLOpener(object):
Monty Taylorbc758832013-06-17 17:22:42 -0400369 def __init__(self, upstream_root, fake_gerrit, url):
370 self.upstream_root = upstream_root
James E. Blair8cc15a82012-08-01 11:17:57 -0700371 self.fake_gerrit = fake_gerrit
372 self.url = url
373
374 def read(self):
375 res = urlparse.urlparse(self.url)
376 path = res.path
377 project = '/'.join(path.split('/')[2:-2])
James E. Blair35956c52012-09-17 22:13:36 +0200378 ret = '001e# service=git-upload-pack\n'
379 ret += ('000000a31270149696713ba7e06f1beb760f20d359c4abed HEAD\x00'
380 'multi_ack thin-pack side-band side-band-64k ofs-delta '
381 'shallow no-progress include-tag multi_ack_detailed no-done\n')
Monty Taylorbc758832013-06-17 17:22:42 -0400382 path = os.path.join(self.upstream_root, project)
James E. Blairdaabed22012-08-15 15:38:57 -0700383 repo = git.Repo(path)
384 for ref in repo.refs:
James E. Blair35956c52012-09-17 22:13:36 +0200385 r = ref.object.hexsha + ' ' + ref.path + '\n'
386 ret += '%04x%s' % (len(r) + 4, r)
387 ret += '0000'
James E. Blair8cc15a82012-08-01 11:17:57 -0700388 return ret
389
390
James E. Blair4886cc12012-07-18 15:39:41 -0700391class FakeGerritTrigger(zuul.trigger.gerrit.Gerrit):
Joshua Hesketh1879cf72013-08-19 14:13:15 +1000392 name = 'gerrit'
393
Monty Taylorbc758832013-06-17 17:22:42 -0400394 def __init__(self, upstream_root, *args):
395 super(FakeGerritTrigger, self).__init__(*args)
396 self.upstream_root = upstream_root
397
James E. Blair4886cc12012-07-18 15:39:41 -0700398 def getGitUrl(self, project):
Monty Taylorbc758832013-06-17 17:22:42 -0400399 return os.path.join(self.upstream_root, project.name)
James E. Blair4886cc12012-07-18 15:39:41 -0700400
401
James E. Blair412e5582013-04-22 15:50:12 -0700402class FakeStatsd(threading.Thread):
403 def __init__(self):
404 threading.Thread.__init__(self)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400405 self.daemon = True
James E. Blair412e5582013-04-22 15:50:12 -0700406 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
407 self.sock.bind(('', 0))
408 self.port = self.sock.getsockname()[1]
409 self.wake_read, self.wake_write = os.pipe()
410 self.stats = []
411
412 def run(self):
413 while True:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700414 poll = select.poll()
415 poll.register(self.sock, select.POLLIN)
416 poll.register(self.wake_read, select.POLLIN)
417 ret = poll.poll()
418 for (fd, event) in ret:
419 if fd == self.sock.fileno():
James E. Blair412e5582013-04-22 15:50:12 -0700420 data = self.sock.recvfrom(1024)
421 if not data:
422 return
423 self.stats.append(data[0])
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700424 if fd == self.wake_read:
James E. Blair412e5582013-04-22 15:50:12 -0700425 return
426
427 def stop(self):
428 os.write(self.wake_write, '1\n')
429
430
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700431class FakeBuild(threading.Thread):
432 log = logging.getLogger("zuul.test")
433
434 def __init__(self, worker, job, number, node):
435 threading.Thread.__init__(self)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400436 self.daemon = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700437 self.worker = worker
438 self.job = job
439 self.name = job.name.split(':')[1]
440 self.number = number
441 self.node = node
442 self.parameters = json.loads(job.arguments)
443 self.unique = self.parameters['ZUUL_UUID']
444 self.wait_condition = threading.Condition()
445 self.waiting = False
446 self.aborted = False
447 self.created = time.time()
448 self.description = ''
James E. Blair4a28a882013-08-23 15:17:33 -0700449 self.run_error = False
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700450
451 def release(self):
452 self.wait_condition.acquire()
453 self.wait_condition.notify()
454 self.waiting = False
455 self.log.debug("Build %s released" % self.unique)
456 self.wait_condition.release()
457
458 def isWaiting(self):
459 self.wait_condition.acquire()
460 if self.waiting:
461 ret = True
462 else:
463 ret = False
464 self.wait_condition.release()
465 return ret
466
467 def _wait(self):
468 self.wait_condition.acquire()
469 self.waiting = True
470 self.log.debug("Build %s waiting" % self.unique)
471 self.wait_condition.wait()
472 self.wait_condition.release()
473
474 def run(self):
475 data = {
James E. Blair3c483cf2013-06-04 16:30:43 -0700476 'url': 'https://server/job/%s/%s/' % (self.name, self.number),
477 'name': self.name,
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700478 'number': self.number,
James E. Blair3c483cf2013-06-04 16:30:43 -0700479 'manager': self.worker.worker_id,
Paul Belangerec49b4c2013-07-20 20:32:20 -0400480 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700481
482 self.job.sendWorkData(json.dumps(data))
483 self.job.sendWorkStatus(0, 100)
484
485 if self.worker.hold_jobs_in_build:
486 self._wait()
487 self.log.debug("Build %s continuing" % self.unique)
488
489 self.worker.lock.acquire()
490
491 result = 'SUCCESS'
492 if (('ZUUL_REF' in self.parameters) and
493 self.worker.shouldFailTest(self.name,
494 self.parameters['ZUUL_REF'])):
495 result = 'FAILURE'
496 if self.aborted:
497 result = 'ABORTED'
498
James E. Blair4a28a882013-08-23 15:17:33 -0700499 if self.run_error:
500 work_fail = True
501 result = 'RUN_ERROR'
502 else:
503 data['result'] = result
504 work_fail = False
505
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700506 changes = None
507 if 'ZUUL_CHANGE_IDS' in self.parameters:
508 changes = self.parameters['ZUUL_CHANGE_IDS']
509
510 self.worker.build_history.append(
511 BuildHistory(name=self.name, number=self.number,
512 result=result, changes=changes, node=self.node,
James E. Blair64ed6f22013-07-10 14:07:23 -0700513 uuid=self.unique, description=self.description,
514 pipeline=self.parameters['ZUUL_PIPELINE'])
Paul Belangerec49b4c2013-07-20 20:32:20 -0400515 )
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700516
James E. Blair4a28a882013-08-23 15:17:33 -0700517 self.job.sendWorkData(json.dumps(data))
518 if work_fail:
519 self.job.sendWorkFail()
520 else:
521 self.job.sendWorkComplete(json.dumps(data))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700522 del self.worker.gearman_jobs[self.job.unique]
523 self.worker.running_builds.remove(self)
524 self.worker.lock.release()
525
526
527class FakeWorker(gear.Worker):
Monty Taylorbc758832013-06-17 17:22:42 -0400528 def __init__(self, worker_id, test):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700529 super(FakeWorker, self).__init__(worker_id)
530 self.gearman_jobs = {}
531 self.build_history = []
532 self.running_builds = []
533 self.build_counter = 0
534 self.fail_tests = {}
Monty Taylorbc758832013-06-17 17:22:42 -0400535 self.test = test
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700536
537 self.hold_jobs_in_build = False
538 self.lock = threading.Lock()
539 self.__work_thread = threading.Thread(target=self.work)
James E. Blair8a6f0c22013-07-01 12:31:34 -0400540 self.__work_thread.daemon = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700541 self.__work_thread.start()
542
543 def handleJob(self, job):
544 parts = job.name.split(":")
545 cmd = parts[0]
546 name = parts[1]
547 if len(parts) > 2:
548 node = parts[2]
549 else:
550 node = None
551 if cmd == 'build':
552 self.handleBuild(job, name, node)
553 elif cmd == 'stop':
554 self.handleStop(job, name)
555 elif cmd == 'set_description':
556 self.handleSetDescription(job, name)
557
558 def handleBuild(self, job, name, node):
559 build = FakeBuild(self, job, self.build_counter, node)
560 job.build = build
561 self.gearman_jobs[job.unique] = job
562 self.build_counter += 1
563
564 self.running_builds.append(build)
565 build.start()
566
567 def handleStop(self, job, name):
568 self.log.debug("handle stop")
James E. Blair3c483cf2013-06-04 16:30:43 -0700569 parameters = json.loads(job.arguments)
570 name = parameters['name']
571 number = parameters['number']
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700572 for build in self.running_builds:
James E. Blair3c483cf2013-06-04 16:30:43 -0700573 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700574 build.aborted = True
575 build.release()
576 job.sendWorkComplete()
577 return
578 job.sendWorkFail()
579
580 def handleSetDescription(self, job, name):
581 self.log.debug("handle set description")
582 parameters = json.loads(job.arguments)
James E. Blair3c483cf2013-06-04 16:30:43 -0700583 name = parameters['name']
584 number = parameters['number']
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700585 descr = parameters['html_description']
586 for build in self.running_builds:
James E. Blair3c483cf2013-06-04 16:30:43 -0700587 if build.name == name and build.number == number:
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700588 build.description = descr
589 job.sendWorkComplete()
590 return
591 for build in self.build_history:
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.description = descr
594 job.sendWorkComplete()
595 return
596 job.sendWorkFail()
597
598 def work(self):
599 while self.running:
600 try:
601 job = self.getJob()
602 except gear.InterruptedError:
603 continue
604 try:
605 self.handleJob(job)
606 except:
607 self.log.exception("Worker exception:")
608
609 def addFailTest(self, name, change):
610 l = self.fail_tests.get(name, [])
611 l.append(change)
612 self.fail_tests[name] = l
613
614 def shouldFailTest(self, name, ref):
615 l = self.fail_tests.get(name, [])
616 for change in l:
Monty Taylorbc758832013-06-17 17:22:42 -0400617 if self.test.ref_has_change(ref, change):
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700618 return True
619 return False
620
621 def release(self, regex=None):
622 builds = self.running_builds[:]
623 self.log.debug("releasing build %s (%s)" % (regex,
James E. Blair78e31b32013-07-09 09:11:34 -0700624 len(self.running_builds)))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700625 for build in builds:
626 if not regex or re.match(regex, build.name):
627 self.log.debug("releasing build %s" %
628 (build.parameters['ZUUL_UUID']))
629 build.release()
630 else:
631 self.log.debug("not releasing build %s" %
632 (build.parameters['ZUUL_UUID']))
633 self.log.debug("done releasing builds %s (%s)" %
634 (regex, len(self.running_builds)))
635
636
637class FakeGearmanServer(gear.Server):
638 def __init__(self):
639 self.hold_jobs_in_queue = False
640 super(FakeGearmanServer, self).__init__(0)
641
642 def getJobForConnection(self, connection, peek=False):
James E. Blair701c5b42013-06-06 09:34:59 -0700643 for queue in [self.high_queue, self.normal_queue, self.low_queue]:
644 for job in queue:
645 if not hasattr(job, 'waiting'):
646 if job.name.startswith('build:'):
647 job.waiting = self.hold_jobs_in_queue
648 else:
649 job.waiting = False
650 if job.waiting:
651 continue
652 if job.name in connection.functions:
653 if not peek:
654 queue.remove(job)
James E. Blaire2819012013-06-28 17:17:26 -0400655 connection.related_jobs[job.handle] = job
656 job.worker_connection = connection
657 job.running = True
James E. Blair701c5b42013-06-06 09:34:59 -0700658 return job
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700659 return None
660
661 def release(self, regex=None):
662 released = False
James E. Blair701c5b42013-06-06 09:34:59 -0700663 qlen = (len(self.high_queue) + len(self.normal_queue) +
664 len(self.low_queue))
665 self.log.debug("releasing queued job %s (%s)" % (regex, qlen))
James E. Blairdda6c912013-07-29 14:12:12 -0700666 for job in self.getQueue():
667 cmd, name = job.name.split(':')
668 if cmd != 'build':
669 continue
670 if not regex or re.match(regex, name):
671 self.log.debug("releasing queued job %s" %
672 job.unique)
673 job.waiting = False
674 released = True
675 else:
676 self.log.debug("not releasing queued job %s" %
677 job.unique)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700678 if released:
679 self.wakeConnections()
James E. Blair701c5b42013-06-06 09:34:59 -0700680 qlen = (len(self.high_queue) + len(self.normal_queue) +
681 len(self.low_queue))
682 self.log.debug("done releasing queued jobs %s (%s)" % (regex, qlen))
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700683
684
Monty Taylorbc758832013-06-17 17:22:42 -0400685class TestScheduler(testtools.TestCase):
James E. Blairb0fcae42012-07-17 11:12:10 -0700686 log = logging.getLogger("zuul.test")
687
688 def setUp(self):
Monty Taylorbc758832013-06-17 17:22:42 -0400689 super(TestScheduler, self).setUp()
690 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
691 try:
692 test_timeout = int(test_timeout)
693 except ValueError:
694 # If timeout value is invalid do not set a timeout.
695 test_timeout = 0
696 if test_timeout > 0:
697 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
698
699 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
700 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
701 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
702 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
703 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
704 os.environ.get('OS_STDERR_CAPTURE') == '1'):
705 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
706 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Monty Taylore6a6c402013-07-02 09:25:55 -0700707 if (os.environ.get('OS_LOG_CAPTURE') == 'True' or
708 os.environ.get('OS_LOG_CAPTURE') == '1'):
James E. Blaire2819012013-06-28 17:17:26 -0400709 self.useFixture(fixtures.FakeLogger(
710 level=logging.DEBUG,
711 format='%(asctime)s %(name)-32s '
712 '%(levelname)-8s %(message)s'))
Monty Taylor5a5a95c2013-07-03 13:39:14 -0700713 tmp_root = self.useFixture(fixtures.TempDir(
714 rootdir=os.environ.get("ZUUL_TEST_ROOT"))).path
Monty Taylorbc758832013-06-17 17:22:42 -0400715 self.test_root = os.path.join(tmp_root, "zuul-test")
716 self.upstream_root = os.path.join(self.test_root, "upstream")
717 self.git_root = os.path.join(self.test_root, "git")
718
719 CONFIG.set('zuul', 'git_dir', self.git_root)
720 if os.path.exists(self.test_root):
721 shutil.rmtree(self.test_root)
722 os.makedirs(self.test_root)
723 os.makedirs(self.upstream_root)
724 os.makedirs(self.git_root)
James E. Blair4886cc12012-07-18 15:39:41 -0700725
726 # For each project in config:
Monty Taylorbc758832013-06-17 17:22:42 -0400727 self.init_repo("org/project")
728 self.init_repo("org/project1")
729 self.init_repo("org/project2")
730 self.init_repo("org/project3")
731 self.init_repo("org/one-job-project")
732 self.init_repo("org/nonvoting-project")
733 self.init_repo("org/templated-project")
734 self.init_repo("org/node-project")
James E. Blair6736beb2013-07-11 15:18:15 -0700735 self.init_repo("org/conflict-project")
James E. Blair412e5582013-04-22 15:50:12 -0700736
737 self.statsd = FakeStatsd()
738 os.environ['STATSD_HOST'] = 'localhost'
739 os.environ['STATSD_PORT'] = str(self.statsd.port)
740 self.statsd.start()
741 # the statsd client object is configured in the statsd module import
742 reload(statsd)
743 reload(zuul.scheduler)
744
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700745 self.gearman_server = FakeGearmanServer()
746
747 self.config = ConfigParser.ConfigParser()
748 cfg = StringIO()
749 CONFIG.write(cfg)
750 cfg.seek(0)
751 self.config.readfp(cfg)
752 self.config.set('gearman', 'port', str(self.gearman_server.port))
753
Monty Taylorbc758832013-06-17 17:22:42 -0400754 self.worker = FakeWorker('fake_worker', self)
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700755 self.worker.addServer('127.0.0.1', self.gearman_server.port)
756 self.gearman_server.worker = self.worker
757
James E. Blairb0fcae42012-07-17 11:12:10 -0700758 self.sched = zuul.scheduler.Scheduler()
759
James E. Blair8cc15a82012-08-01 11:17:57 -0700760 def URLOpenerFactory(*args, **kw):
761 args = [self.fake_gerrit] + list(args)
Monty Taylorbc758832013-06-17 17:22:42 -0400762 return FakeURLOpener(self.upstream_root, *args, **kw)
James E. Blair8cc15a82012-08-01 11:17:57 -0700763
James E. Blair8cc15a82012-08-01 11:17:57 -0700764 urllib2.urlopen = URLOpenerFactory
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700765 self.launcher = zuul.launcher.gearman.Gearman(self.config, self.sched)
James E. Blairb0fcae42012-07-17 11:12:10 -0700766
767 zuul.lib.gerrit.Gerrit = FakeGerrit
768
Monty Taylorbc758832013-06-17 17:22:42 -0400769 self.gerrit = FakeGerritTrigger(
770 self.upstream_root, self.config, self.sched)
James E. Blair8cc15a82012-08-01 11:17:57 -0700771 self.gerrit.replication_timeout = 1.5
772 self.gerrit.replication_retry_interval = 0.5
James E. Blairb0fcae42012-07-17 11:12:10 -0700773 self.fake_gerrit = self.gerrit.gerrit
Monty Taylorbc758832013-06-17 17:22:42 -0400774 self.fake_gerrit.upstream_root = self.upstream_root
James E. Blairb0fcae42012-07-17 11:12:10 -0700775
James E. Blair1843a552013-07-03 14:19:52 -0700776 self.webapp = zuul.webapp.WebApp(self.sched, port=0)
777
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700778 self.sched.setLauncher(self.launcher)
James E. Blair6c358e72013-07-29 17:06:47 -0700779 self.sched.registerTrigger(self.gerrit)
James E. Blair63bb0ef2013-07-29 17:14:51 -0700780 self.timer = zuul.trigger.timer.Timer(self.config, self.sched)
781 self.sched.registerTrigger(self.timer)
James E. Blairb0fcae42012-07-17 11:12:10 -0700782
Joshua Hesketh1879cf72013-08-19 14:13:15 +1000783 self.sched.registerReporter(
784 zuul.reporter.gerrit.Reporter(self.gerrit))
785
James E. Blairb0fcae42012-07-17 11:12:10 -0700786 self.sched.start()
787 self.sched.reconfigure(self.config)
788 self.sched.resume()
James E. Blair1843a552013-07-03 14:19:52 -0700789 self.webapp.start()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700790 self.launcher.gearman.waitForServer()
791 self.registerJobs()
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400792 self.builds = self.worker.running_builds
793 self.history = self.worker.build_history
James E. Blairb0fcae42012-07-17 11:12:10 -0700794
James E. Blairfee8d652013-06-07 08:57:52 -0700795 self.addCleanup(self.assertFinalState)
796 self.addCleanup(self.shutdown)
797
798 def assertFinalState(self):
799 # Make sure that the change cache is cleared
James E. Blair6c358e72013-07-29 17:06:47 -0700800 self.assertEqual(len(self.gerrit._change_cache.keys()), 0)
James E. Blairfee8d652013-06-07 08:57:52 -0700801 self.assertEmptyQueues()
802
803 def shutdown(self):
804 self.log.debug("Shutting down after tests")
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700805 self.launcher.stop()
806 self.worker.shutdown()
807 self.gearman_server.shutdown()
James E. Blairb0fcae42012-07-17 11:12:10 -0700808 self.gerrit.stop()
James E. Blair63bb0ef2013-07-29 17:14:51 -0700809 self.timer.stop()
James E. Blairb0fcae42012-07-17 11:12:10 -0700810 self.sched.stop()
811 self.sched.join()
James E. Blair412e5582013-04-22 15:50:12 -0700812 self.statsd.stop()
813 self.statsd.join()
James E. Blair1843a552013-07-03 14:19:52 -0700814 self.webapp.stop()
815 self.webapp.join()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700816 threads = threading.enumerate()
817 if len(threads) > 1:
818 self.log.error("More than one thread is running: %s" % threads)
Monty Taylorbc758832013-06-17 17:22:42 -0400819 super(TestScheduler, self).tearDown()
820
821 def init_repo(self, project):
822 parts = project.split('/')
823 path = os.path.join(self.upstream_root, *parts[:-1])
824 if not os.path.exists(path):
825 os.makedirs(path)
826 path = os.path.join(self.upstream_root, project)
827 repo = git.Repo.init(path)
828
829 repo.config_writer().set_value('user', 'email', 'user@example.com')
830 repo.config_writer().set_value('user', 'name', 'User Name')
831 repo.config_writer().write()
832
833 fn = os.path.join(path, 'README')
834 f = open(fn, 'w')
835 f.write("test\n")
836 f.close()
837 repo.index.add([fn])
838 repo.index.commit('initial commit')
839 master = repo.create_head('master')
840 repo.create_tag('init')
841
842 mp = repo.create_head('mp')
843 repo.head.reference = mp
844 f = open(fn, 'a')
845 f.write("test mp\n")
846 f.close()
847 repo.index.add([fn])
848 repo.index.commit('mp commit')
849
850 repo.head.reference = master
851 repo.head.reset(index=True, working_tree=True)
852 repo.git.clean('-x', '-f', '-d')
853
854 def ref_has_change(self, ref, change):
855 path = os.path.join(self.git_root, change.project)
856 repo = git.Repo(path)
857 for commit in repo.iter_commits(ref):
858 if commit.message.strip() == ('%s-1' % change.subject):
859 return True
860 return False
861
862 def job_has_changes(self, *args):
863 job = args[0]
864 commits = args[1:]
865 if isinstance(job, FakeBuild):
866 parameters = job.parameters
867 else:
868 parameters = json.loads(job.arguments)
869 project = parameters['ZUUL_PROJECT']
870 path = os.path.join(self.git_root, project)
871 repo = git.Repo(path)
872 ref = parameters['ZUUL_REF']
873 sha = parameters['ZUUL_COMMIT']
874 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
875 repo_shas = [c.hexsha for c in repo.iter_commits(ref)]
876 commit_messages = ['%s-1' % commit.subject for commit in commits]
877 for msg in commit_messages:
878 if msg not in repo_messages:
879 return False
880 if repo_shas[0] != sha:
881 return False
882 return True
James E. Blairb0fcae42012-07-17 11:12:10 -0700883
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700884 def registerJobs(self):
885 count = 0
James E. Blaireff88162013-07-01 12:44:14 -0400886 for job in self.sched.layout.jobs.keys():
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700887 self.worker.registerFunction('build:' + job)
888 count += 1
889 self.worker.registerFunction('stop:' + self.worker.worker_id)
890 count += 1
891
892 while len(self.gearman_server.functions) < count:
893 time.sleep(0)
894
895 def release(self, job):
896 if isinstance(job, FakeBuild):
897 job.release()
898 else:
899 job.waiting = False
900 self.log.debug("Queued job %s released" % job.unique)
901 self.gearman_server.wakeConnections()
902
903 def getParameter(self, job, name):
904 if isinstance(job, FakeBuild):
905 return job.parameters[name]
906 else:
907 parameters = json.loads(job.arguments)
908 return parameters[name]
909
910 def resetGearmanServer(self):
911 self.worker.setFunctions([])
912 while True:
913 done = True
914 for connection in self.gearman_server.active_connections:
915 if connection.functions:
916 done = False
917 if done:
918 break
919 time.sleep(0)
920 self.gearman_server.functions = set()
921
922 def haveAllBuildsReported(self):
923 # See if Zuul is waiting on a meta job to complete
924 if self.launcher.meta_jobs:
925 return False
926 # Find out if every build that the worker has completed has been
927 # reported back to Zuul. If it hasn't then that means a Gearman
928 # event is still in transit and the system is not stable.
929 for build in self.worker.build_history:
930 zbuild = self.launcher.builds.get(build.uuid)
931 if not zbuild:
932 # It has already been reported
933 continue
934 # It hasn't been reported yet.
935 return False
936 # Make sure that none of the worker connections are in GRAB_WAIT
937 for connection in self.worker.active_connections:
938 if connection.state == 'GRAB_WAIT':
939 return False
940 return True
941
942 def areAllBuildsWaiting(self):
943 ret = True
944
945 builds = self.launcher.builds.values()
946 for build in builds:
947 client_job = None
948 for conn in self.launcher.gearman.active_connections:
949 for j in conn.related_jobs.values():
950 if j.unique == build.uuid:
951 client_job = j
952 break
953 if not client_job:
954 self.log.debug("%s is not known to the gearman client" %
955 build)
956 ret = False
957 continue
958 if not client_job.handle:
959 self.log.debug("%s has no handle" % client_job)
960 ret = False
961 continue
962 server_job = self.gearman_server.jobs.get(client_job.handle)
963 if not server_job:
964 self.log.debug("%s is not known to the gearman server" %
965 client_job)
966 ret = False
967 continue
968 if not hasattr(server_job, 'waiting'):
969 self.log.debug("%s is being enqueued" % server_job)
970 ret = False
971 continue
972 if server_job.waiting:
973 continue
974 worker_job = self.worker.gearman_jobs.get(server_job.unique)
975 if worker_job:
976 if worker_job.build.isWaiting():
977 continue
978 else:
979 self.log.debug("%s is running" % worker_job)
980 ret = False
981 else:
982 self.log.debug("%s is unassigned" % server_job)
983 ret = False
984 return ret
985
James E. Blairb0fcae42012-07-17 11:12:10 -0700986 def waitUntilSettled(self):
987 self.log.debug("Waiting until settled...")
988 start = time.time()
989 while True:
990 if time.time() - start > 10:
991 print 'queue status:',
992 print self.sched.trigger_event_queue.empty(),
993 print self.sched.result_event_queue.empty(),
994 print self.fake_gerrit.event_queue.empty(),
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700995 print self.areAllBuildsWaiting()
James E. Blairb0fcae42012-07-17 11:12:10 -0700996 raise Exception("Timeout waiting for Zuul to settle")
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700997 # Make sure no new events show up while we're checking
998 self.worker.lock.acquire()
999 # have all build states propogated to zuul?
1000 if self.haveAllBuildsReported():
1001 # Join ensures that the queue is empty _and_ events have been
1002 # processed
1003 self.fake_gerrit.event_queue.join()
1004 self.sched.trigger_event_queue.join()
1005 self.sched.result_event_queue.join()
1006 if (self.sched.trigger_event_queue.empty() and
1007 self.sched.result_event_queue.empty() and
1008 self.fake_gerrit.event_queue.empty() and
1009 self.areAllBuildsWaiting()):
1010 self.worker.lock.release()
1011 self.log.debug("...settled.")
1012 return
1013 self.worker.lock.release()
James E. Blairb0fcae42012-07-17 11:12:10 -07001014 self.sched.wake_event.wait(0.1)
1015
James E. Blaird466dc42012-07-31 10:42:56 -07001016 def countJobResults(self, jobs, result):
James E. Blair0018a6c2013-02-27 14:11:45 -08001017 jobs = filter(lambda x: x.result == result, jobs)
James E. Blaird466dc42012-07-31 10:42:56 -07001018 return len(jobs)
1019
James E. Blair4ca985f2013-05-30 12:27:43 -07001020 def getJobFromHistory(self, name):
1021 history = self.worker.build_history
1022 for job in history:
1023 if job.name == name:
1024 return job
1025 raise Exception("Unable to find job %s in history" % name)
1026
James E. Blaire0487072012-08-29 17:38:31 -07001027 def assertEmptyQueues(self):
1028 # Make sure there are no orphaned jobs
James E. Blaireff88162013-07-01 12:44:14 -04001029 for pipeline in self.sched.layout.pipelines.values():
James E. Blaire0487072012-08-29 17:38:31 -07001030 for queue in pipeline.queues:
1031 if len(queue.queue) != 0:
James E. Blairf62d4282012-12-31 17:01:50 -08001032 print 'pipeline %s queue %s contents %s' % (
1033 pipeline.name, queue.name, queue.queue)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001034 self.assertEqual(len(queue.queue), 0)
James E. Blaire0487072012-08-29 17:38:31 -07001035 if len(queue.severed_heads) != 0:
1036 print 'heads', queue.severed_heads
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001037 self.assertEqual(len(queue.severed_heads), 0)
James E. Blaire0487072012-08-29 17:38:31 -07001038
James E. Blair66eeebf2013-07-27 17:44:32 -07001039 def assertReportedStat(self, key, value=None, kind=None):
James E. Blair412e5582013-04-22 15:50:12 -07001040 start = time.time()
1041 while time.time() < (start + 5):
1042 for stat in self.statsd.stats:
James E. Blair66eeebf2013-07-27 17:44:32 -07001043 pprint.pprint(self.statsd.stats)
James E. Blair412e5582013-04-22 15:50:12 -07001044 k, v = stat.split(':')
1045 if key == k:
James E. Blair66eeebf2013-07-27 17:44:32 -07001046 if value is None and kind is None:
James E. Blair412e5582013-04-22 15:50:12 -07001047 return
James E. Blair66eeebf2013-07-27 17:44:32 -07001048 elif value:
1049 if value == v:
1050 return
1051 elif kind:
1052 if v.endswith('|' + kind):
1053 return
James E. Blair412e5582013-04-22 15:50:12 -07001054 time.sleep(0.1)
1055
1056 pprint.pprint(self.statsd.stats)
1057 raise Exception("Key %s not found in reported stats" % key)
1058
James E. Blairb0fcae42012-07-17 11:12:10 -07001059 def test_jobs_launched(self):
1060 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001061
James E. Blairb0fcae42012-07-17 11:12:10 -07001062 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -07001063 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001064 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1065 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001066 self.assertEqual(self.getJobFromHistory('project-merge').result,
1067 'SUCCESS')
1068 self.assertEqual(self.getJobFromHistory('project-test1').result,
1069 'SUCCESS')
1070 self.assertEqual(self.getJobFromHistory('project-test2').result,
1071 'SUCCESS')
1072 self.assertEqual(A.data['status'], 'MERGED')
1073 self.assertEqual(A.reported, 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001074
James E. Blair66eeebf2013-07-27 17:44:32 -07001075 self.assertReportedStat('gerrit.event.comment-added', value='1|c')
1076 self.assertReportedStat('zuul.pipeline.gate.current_changes',
1077 value='1|g')
1078 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
1079 kind='ms')
1080 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
1081 value='1|c')
1082 self.assertReportedStat('zuul.pipeline.gate.resident_time', kind='ms')
1083 self.assertReportedStat('zuul.pipeline.gate.total_changes',
1084 value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -07001085 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -07001086 'zuul.pipeline.gate.org.project.resident_time', kind='ms')
James E. Blair412e5582013-04-22 15:50:12 -07001087 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -07001088 'zuul.pipeline.gate.org.project.total_changes', value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -07001089
James E. Blair3cb10702013-08-24 08:56:03 -07001090 def test_initial_pipeline_gauges(self):
1091 "Test that each pipeline reported its length on start"
1092 pipeline_names = self.sched.layout.pipelines.keys()
1093 self.assertNotEqual(len(pipeline_names), 0)
1094 for name in pipeline_names:
1095 self.assertReportedStat('zuul.pipeline.%s.current_changes' % name,
1096 value='0|g')
1097
James E. Blair42f74822013-05-14 15:18:03 -07001098 def test_duplicate_pipelines(self):
1099 "Test that a change matching multiple pipelines works"
James E. Blair1b4d9722013-05-21 10:32:04 -07001100
James E. Blair42f74822013-05-14 15:18:03 -07001101 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1102 self.fake_gerrit.addEvent(A.getChangeRestoredEvent())
1103 self.waitUntilSettled()
James E. Blair42f74822013-05-14 15:18:03 -07001104
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001105 self.assertEqual(len(self.history), 2)
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001106 self.history[0].name == 'project-test1'
1107 self.history[1].name == 'project-test1'
James E. Blair42f74822013-05-14 15:18:03 -07001108
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001109 self.assertEqual(len(A.messages), 2)
James E. Blair42f74822013-05-14 15:18:03 -07001110 if 'dup1/project-test1' in A.messages[0]:
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001111 self.assertIn('dup1/project-test1', A.messages[0])
1112 self.assertNotIn('dup2/project-test1', A.messages[0])
1113 self.assertNotIn('dup1/project-test1', A.messages[1])
1114 self.assertIn('dup2/project-test1', A.messages[1])
James E. Blair42f74822013-05-14 15:18:03 -07001115 else:
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001116 self.assertIn('dup1/project-test1', A.messages[1])
1117 self.assertNotIn('dup2/project-test1', A.messages[1])
1118 self.assertNotIn('dup1/project-test1', A.messages[0])
1119 self.assertIn('dup2/project-test1', A.messages[0])
James E. Blair42f74822013-05-14 15:18:03 -07001120
James E. Blairb0fcae42012-07-17 11:12:10 -07001121 def test_parallel_changes(self):
1122 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001123
1124 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -07001125 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1126 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1127 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001128 A.addApproval('CRVW', 2)
1129 B.addApproval('CRVW', 2)
1130 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -07001131
1132 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1133 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1134 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1135
1136 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001137 self.assertEqual(len(self.builds), 1)
1138 self.assertEqual(self.builds[0].name, 'project-merge')
1139 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairb0fcae42012-07-17 11:12:10 -07001140
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001141 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001142 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001143 self.assertEqual(len(self.builds), 3)
1144 self.assertEqual(self.builds[0].name, 'project-test1')
1145 self.assertTrue(self.job_has_changes(self.builds[0], A))
1146 self.assertEqual(self.builds[1].name, 'project-test2')
1147 self.assertTrue(self.job_has_changes(self.builds[1], A))
1148 self.assertEqual(self.builds[2].name, 'project-merge')
1149 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -07001150
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001151 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001152 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001153 self.assertEqual(len(self.builds), 5)
1154 self.assertEqual(self.builds[0].name, 'project-test1')
1155 self.assertTrue(self.job_has_changes(self.builds[0], A))
1156 self.assertEqual(self.builds[1].name, 'project-test2')
1157 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -07001158
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001159 self.assertEqual(self.builds[2].name, 'project-test1')
1160 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
1161 self.assertEqual(self.builds[3].name, 'project-test2')
1162 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -07001163
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001164 self.assertEqual(self.builds[4].name, 'project-merge')
1165 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -07001166
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001167 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -07001168 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001169 self.assertEqual(len(self.builds), 6)
1170 self.assertEqual(self.builds[0].name, 'project-test1')
1171 self.assertTrue(self.job_has_changes(self.builds[0], A))
1172 self.assertEqual(self.builds[1].name, 'project-test2')
1173 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -07001174
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001175 self.assertEqual(self.builds[2].name, 'project-test1')
1176 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
1177 self.assertEqual(self.builds[3].name, 'project-test2')
1178 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -07001179
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001180 self.assertEqual(self.builds[4].name, 'project-test1')
1181 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
1182 self.assertEqual(self.builds[5].name, 'project-test2')
1183 self.assertTrue(self.job_has_changes(self.builds[5], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -07001184
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001185 self.worker.hold_jobs_in_build = False
1186 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -07001187 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001188 self.assertEqual(len(self.builds), 0)
James E. Blairb0fcae42012-07-17 11:12:10 -07001189
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001190 self.assertEqual(len(self.history), 9)
1191 self.assertEqual(A.data['status'], 'MERGED')
1192 self.assertEqual(B.data['status'], 'MERGED')
1193 self.assertEqual(C.data['status'], 'MERGED')
1194 self.assertEqual(A.reported, 2)
1195 self.assertEqual(B.reported, 2)
1196 self.assertEqual(C.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001197
1198 def test_failed_changes(self):
1199 "Test that a change behind a failed change is retested"
James E. Blaire2819012013-06-28 17:17:26 -04001200 self.worker.hold_jobs_in_build = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001201
James E. Blairb02a3bb2012-07-30 17:49:55 -07001202 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1203 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -07001204 A.addApproval('CRVW', 2)
1205 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001206
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001207 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001208
James E. Blaire2819012013-06-28 17:17:26 -04001209 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1210 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
James E. Blairb02a3bb2012-07-30 17:49:55 -07001211 self.waitUntilSettled()
James E. Blaire2819012013-06-28 17:17:26 -04001212
1213 self.worker.release('.*-merge')
1214 self.waitUntilSettled()
1215
1216 self.worker.hold_jobs_in_build = False
1217 self.worker.release()
1218
1219 self.waitUntilSettled()
1220 # It's certain that the merge job for change 2 will run, but
1221 # the test1 and test2 jobs may or may not run.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001222 self.assertTrue(len(self.history) > 6)
1223 self.assertEqual(A.data['status'], 'NEW')
1224 self.assertEqual(B.data['status'], 'MERGED')
1225 self.assertEqual(A.reported, 2)
1226 self.assertEqual(B.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001227
1228 def test_independent_queues(self):
1229 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001230
1231 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +09001232 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001233 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1234 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001235 A.addApproval('CRVW', 2)
1236 B.addApproval('CRVW', 2)
1237 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001238
1239 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1240 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1241 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1242
James E. Blairb02a3bb2012-07-30 17:49:55 -07001243 self.waitUntilSettled()
1244
1245 # There should be one merge job at the head of each queue running
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001246 self.assertEqual(len(self.builds), 2)
1247 self.assertEqual(self.builds[0].name, 'project-merge')
1248 self.assertTrue(self.job_has_changes(self.builds[0], A))
1249 self.assertEqual(self.builds[1].name, 'project1-merge')
1250 self.assertTrue(self.job_has_changes(self.builds[1], B))
James E. Blairb02a3bb2012-07-30 17:49:55 -07001251
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001252 # Release the current merge builds
1253 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001254 self.waitUntilSettled()
1255 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001256 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -07001257 self.waitUntilSettled()
1258
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001259 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -07001260 # project1 (3) + project2 (3) + project (2) = 8
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001261 self.assertEqual(len(self.builds), 8)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001262
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001263 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -07001264 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001265 self.assertEqual(len(self.builds), 0)
James E. Blairb02a3bb2012-07-30 17:49:55 -07001266
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001267 self.assertEqual(len(self.history), 11)
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. Blaird466dc42012-07-31 10:42:56 -07001274
1275 def test_failed_change_at_head(self):
1276 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -07001277
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001278 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -07001279 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1280 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1281 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001282 A.addApproval('CRVW', 2)
1283 B.addApproval('CRVW', 2)
1284 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001285
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001286 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001287
1288 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1289 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1290 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1291
1292 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -07001293
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001294 self.assertEqual(len(self.builds), 1)
1295 self.assertEqual(self.builds[0].name, 'project-merge')
1296 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -07001297
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001298 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001299 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001300 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001301 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001302 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001303 self.waitUntilSettled()
1304
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001305 self.assertEqual(len(self.builds), 6)
1306 self.assertEqual(self.builds[0].name, 'project-test1')
1307 self.assertEqual(self.builds[1].name, 'project-test2')
1308 self.assertEqual(self.builds[2].name, 'project-test1')
1309 self.assertEqual(self.builds[3].name, 'project-test2')
1310 self.assertEqual(self.builds[4].name, 'project-test1')
1311 self.assertEqual(self.builds[5].name, 'project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -07001312
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001313 self.release(self.builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001314 self.waitUntilSettled()
1315
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001316 # project-test2, project-merge for B
1317 self.assertEqual(len(self.builds), 2)
1318 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
James E. Blaird466dc42012-07-31 10:42:56 -07001319
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001320 self.worker.hold_jobs_in_build = False
1321 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001322 self.waitUntilSettled()
1323
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001324 self.assertEqual(len(self.builds), 0)
1325 self.assertEqual(len(self.history), 15)
1326 self.assertEqual(A.data['status'], 'NEW')
1327 self.assertEqual(B.data['status'], 'MERGED')
1328 self.assertEqual(C.data['status'], 'MERGED')
1329 self.assertEqual(A.reported, 2)
1330 self.assertEqual(B.reported, 2)
1331 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001332
James E. Blair0aac4872013-08-23 14:02:38 -07001333 def test_failed_change_in_middle(self):
1334 "Test a failed change in the middle of the queue"
1335
1336 self.worker.hold_jobs_in_build = True
1337 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1338 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1339 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1340 A.addApproval('CRVW', 2)
1341 B.addApproval('CRVW', 2)
1342 C.addApproval('CRVW', 2)
1343
1344 self.worker.addFailTest('project-test1', B)
1345
1346 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1347 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1348 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1349
1350 self.waitUntilSettled()
1351
1352 self.worker.release('.*-merge')
1353 self.waitUntilSettled()
1354 self.worker.release('.*-merge')
1355 self.waitUntilSettled()
1356 self.worker.release('.*-merge')
1357 self.waitUntilSettled()
1358
1359 self.assertEqual(len(self.builds), 6)
1360 self.assertEqual(self.builds[0].name, 'project-test1')
1361 self.assertEqual(self.builds[1].name, 'project-test2')
1362 self.assertEqual(self.builds[2].name, 'project-test1')
1363 self.assertEqual(self.builds[3].name, 'project-test2')
1364 self.assertEqual(self.builds[4].name, 'project-test1')
1365 self.assertEqual(self.builds[5].name, 'project-test2')
1366
1367 self.release(self.builds[2])
1368 self.waitUntilSettled()
1369
1370 # project-test1 and project-test2 for A, project-test2 for B
1371 self.assertEqual(len(self.builds), 3)
1372 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 2)
1373
1374 # check that build status of aborted jobs are masked ('CANCELED')
1375 items = self.sched.layout.pipelines['gate'].getAllItems()
1376 builds = items[0].current_build_set.getBuilds()
1377 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
1378 self.assertEqual(self.countJobResults(builds, None), 2)
1379 builds = items[1].current_build_set.getBuilds()
1380 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
1381 self.assertEqual(self.countJobResults(builds, 'FAILURE'), 1)
1382 self.assertEqual(self.countJobResults(builds, None), 1)
1383 builds = items[2].current_build_set.getBuilds()
1384 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
1385 self.assertEqual(self.countJobResults(builds, 'CANCELED'), 2)
1386
1387 self.worker.hold_jobs_in_build = False
1388 self.worker.release()
1389 self.waitUntilSettled()
1390
1391 self.assertEqual(len(self.builds), 0)
1392 self.assertEqual(len(self.history), 12)
1393 self.assertEqual(A.data['status'], 'MERGED')
1394 self.assertEqual(B.data['status'], 'NEW')
1395 self.assertEqual(C.data['status'], 'MERGED')
1396 self.assertEqual(A.reported, 2)
1397 self.assertEqual(B.reported, 2)
1398 self.assertEqual(C.reported, 2)
1399
James E. Blaird466dc42012-07-31 10:42:56 -07001400 def test_failed_change_at_head_with_queue(self):
1401 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -07001402
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001403 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -07001404 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1405 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1406 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -07001407 A.addApproval('CRVW', 2)
1408 B.addApproval('CRVW', 2)
1409 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -07001410
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001411 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -07001412
1413 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1414 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1415 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1416
1417 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001418 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001419 self.assertEqual(len(self.builds), 0)
1420 self.assertEqual(len(queue), 1)
1421 self.assertEqual(queue[0].name, 'build:project-merge')
1422 self.assertTrue(self.job_has_changes(queue[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -07001423
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001424 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001425 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001426 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001427 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001428 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -07001429 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001430 queue = self.gearman_server.getQueue()
James E. Blaird466dc42012-07-31 10:42:56 -07001431
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001432 self.assertEqual(len(self.builds), 0)
1433 self.assertEqual(len(queue), 6)
1434 self.assertEqual(queue[0].name, 'build:project-test1')
1435 self.assertEqual(queue[1].name, 'build:project-test2')
1436 self.assertEqual(queue[2].name, 'build:project-test1')
1437 self.assertEqual(queue[3].name, 'build:project-test2')
1438 self.assertEqual(queue[4].name, 'build:project-test1')
1439 self.assertEqual(queue[5].name, 'build:project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -07001440
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001441 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -07001442 self.waitUntilSettled()
1443
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001444 self.assertEqual(len(self.builds), 0)
James E. Blair701c5b42013-06-06 09:34:59 -07001445 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001446 self.assertEqual(len(queue), 2) # project-test2, project-merge for B
1447 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 0)
James E. Blaird466dc42012-07-31 10:42:56 -07001448
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001449 self.gearman_server.hold_jobs_in_queue = False
1450 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -07001451 self.waitUntilSettled()
1452
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001453 self.assertEqual(len(self.builds), 0)
1454 self.assertEqual(len(self.history), 11)
1455 self.assertEqual(A.data['status'], 'NEW')
1456 self.assertEqual(B.data['status'], 'MERGED')
1457 self.assertEqual(C.data['status'], 'MERGED')
1458 self.assertEqual(A.reported, 2)
1459 self.assertEqual(B.reported, 2)
1460 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -07001461
1462 def test_patch_order(self):
1463 "Test that dependent patches are tested in the right order"
1464 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1465 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1466 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1467 A.addApproval('CRVW', 2)
1468 B.addApproval('CRVW', 2)
1469 C.addApproval('CRVW', 2)
1470
1471 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
1472 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1473 M2.setMerged()
1474 M1.setMerged()
1475
1476 # C -> B -> A -> M1 -> M2
1477 # M2 is here to make sure it is never queried. If it is, it
1478 # means zuul is walking down the entire history of merged
1479 # changes.
1480
1481 C.setDependsOn(B, 1)
1482 B.setDependsOn(A, 1)
1483 A.setDependsOn(M1, 1)
1484 M1.setDependsOn(M2, 1)
1485
1486 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1487
1488 self.waitUntilSettled()
1489
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001490 self.assertEqual(A.data['status'], 'NEW')
1491 self.assertEqual(B.data['status'], 'NEW')
1492 self.assertEqual(C.data['status'], 'NEW')
James E. Blair8c803f82012-07-31 16:25:42 -07001493
1494 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1495 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1496
1497 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001498 self.assertEqual(M2.queried, 0)
1499 self.assertEqual(A.data['status'], 'MERGED')
1500 self.assertEqual(B.data['status'], 'MERGED')
1501 self.assertEqual(C.data['status'], 'MERGED')
1502 self.assertEqual(A.reported, 2)
1503 self.assertEqual(B.reported, 2)
1504 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -07001505
James E. Blair0e933c52013-07-11 10:18:52 -07001506 def test_trigger_cache(self):
1507 "Test that the trigger cache operates correctly"
1508 self.worker.hold_jobs_in_build = True
1509
1510 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1511 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1512 X = self.fake_gerrit.addFakeChange('org/project', 'master', 'X')
1513 A.addApproval('CRVW', 2)
1514 B.addApproval('CRVW', 2)
1515
1516 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1517 M1.setMerged()
1518
1519 B.setDependsOn(A, 1)
1520 A.setDependsOn(M1, 1)
1521
1522 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1523 self.fake_gerrit.addEvent(X.getPatchsetCreatedEvent(1))
1524
1525 self.waitUntilSettled()
1526
1527 for build in self.builds:
1528 if build.parameters['ZUUL_PIPELINE'] == 'check':
1529 build.release()
1530 self.waitUntilSettled()
1531 for build in self.builds:
1532 if build.parameters['ZUUL_PIPELINE'] == 'check':
1533 build.release()
1534 self.waitUntilSettled()
1535
1536 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1537 self.waitUntilSettled()
1538
James E. Blair6c358e72013-07-29 17:06:47 -07001539 self.log.debug("len %s " % self.gerrit._change_cache.keys())
James E. Blair0e933c52013-07-11 10:18:52 -07001540 # there should still be changes in the cache
James E. Blair6c358e72013-07-29 17:06:47 -07001541 self.assertNotEqual(len(self.gerrit._change_cache.keys()), 0)
James E. Blair0e933c52013-07-11 10:18:52 -07001542
1543 self.worker.hold_jobs_in_build = False
1544 self.worker.release()
1545 self.waitUntilSettled()
1546
1547 self.assertEqual(A.data['status'], 'MERGED')
1548 self.assertEqual(B.data['status'], 'MERGED')
1549 self.assertEqual(A.queried, 2) # Initial and isMerged
1550 self.assertEqual(B.queried, 3) # Initial A, refresh from B, isMerged
1551
James E. Blair8c803f82012-07-31 16:25:42 -07001552 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -07001553 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -07001554 # TODO: move to test_gerrit (this is a unit test!)
1555 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair6c358e72013-07-29 17:06:47 -07001556 trigger = self.sched.layout.pipelines['gate'].trigger
1557 a = self.sched.triggers['gerrit'].getChange(1, 2)
James E. Blaireff88162013-07-01 12:44:14 -04001558 mgr = self.sched.layout.pipelines['gate'].manager
James E. Blair6c358e72013-07-29 17:06:47 -07001559 self.assertFalse(trigger.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -07001560
1561 A.addApproval('CRVW', 2)
James E. Blair6c358e72013-07-29 17:06:47 -07001562 a = trigger.getChange(1, 2, refresh=True)
1563 self.assertFalse(trigger.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -07001564
1565 A.addApproval('APRV', 1)
James E. Blair6c358e72013-07-29 17:06:47 -07001566 a = trigger.getChange(1, 2, refresh=True)
1567 self.assertTrue(trigger.canMerge(a, mgr.getSubmitAllowNeeds()))
1568 trigger.maintainCache([])
James E. Blair4886cc12012-07-18 15:39:41 -07001569
1570 def test_build_configuration(self):
1571 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001572
1573 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -07001574 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1575 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1576 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1577 A.addApproval('CRVW', 2)
1578 B.addApproval('CRVW', 2)
1579 C.addApproval('CRVW', 2)
1580 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1581 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1582 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1583 self.waitUntilSettled()
1584
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001585 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001586 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001587 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001588 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001589 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -07001590 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001591 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001592 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1593 self.gearman_server.hold_jobs_in_queue = False
1594 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001595 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -07001596
Monty Taylorbc758832013-06-17 17:22:42 -04001597 path = os.path.join(self.git_root, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -07001598 repo = git.Repo(path)
1599 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1600 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -07001601 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001602 self.assertEqual(repo_messages, correct_messages)
James E. Blair973721f2012-08-15 10:19:43 -07001603
1604 def test_build_configuration_conflict(self):
1605 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001606
1607 self.gearman_server.hold_jobs_in_queue = True
James E. Blair6736beb2013-07-11 15:18:15 -07001608 A = self.fake_gerrit.addFakeChange('org/conflict-project',
1609 'master', 'A')
James E. Blair973721f2012-08-15 10:19:43 -07001610 A.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -07001611 B = self.fake_gerrit.addFakeChange('org/conflict-project',
1612 'master', 'B')
James E. Blair973721f2012-08-15 10:19:43 -07001613 B.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -07001614 C = self.fake_gerrit.addFakeChange('org/conflict-project',
1615 'master', 'C')
James E. Blair973721f2012-08-15 10:19:43 -07001616 A.addApproval('CRVW', 2)
1617 B.addApproval('CRVW', 2)
1618 C.addApproval('CRVW', 2)
1619 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1620 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1621 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1622 self.waitUntilSettled()
1623
James E. Blair6736beb2013-07-11 15:18:15 -07001624 self.assertEqual(A.reported, 1)
1625 self.assertEqual(B.reported, 1)
1626 self.assertEqual(C.reported, 1)
1627
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001628 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001629 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001630 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001631 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001632 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -07001633 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001634 queue = self.gearman_server.getQueue()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001635 self.getParameter(queue[-1], 'ZUUL_REF')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001636 self.gearman_server.hold_jobs_in_queue = False
1637 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -07001638 self.waitUntilSettled()
1639
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001640 self.assertEqual(A.data['status'], 'MERGED')
1641 self.assertEqual(B.data['status'], 'NEW')
1642 self.assertEqual(C.data['status'], 'MERGED')
1643 self.assertEqual(A.reported, 2)
1644 self.assertEqual(B.reported, 2)
1645 self.assertEqual(C.reported, 2)
James E. Blairdaabed22012-08-15 15:38:57 -07001646
James E. Blair6736beb2013-07-11 15:18:15 -07001647 def test_dequeue_conflict(self):
1648 "Test that the option to dequeue merge conflicts works"
1649
1650 self.gearman_server.hold_jobs_in_queue = True
1651 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1652 A.addPatchset(['conflict'])
1653 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1654 B.addPatchset(['conflict'])
1655 A.addApproval('CRVW', 2)
1656 B.addApproval('CRVW', 2)
1657 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1658 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1659 self.waitUntilSettled()
1660
1661 self.assertEqual(A.reported, 1)
1662 self.assertEqual(B.reported, 2)
1663
1664 self.gearman_server.hold_jobs_in_queue = False
1665 self.gearman_server.release()
1666 self.waitUntilSettled()
1667
1668 self.assertEqual(A.data['status'], 'MERGED')
1669 self.assertEqual(B.data['status'], 'NEW')
1670 self.assertEqual(A.reported, 2)
1671 self.assertEqual(B.reported, 2)
1672
James E. Blairdaabed22012-08-15 15:38:57 -07001673 def test_post(self):
1674 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001675
Zhongyue Luo5d556072012-09-21 02:00:47 +09001676 e = {
1677 "type": "ref-updated",
1678 "submitter": {
1679 "name": "User Name",
1680 },
1681 "refUpdate": {
1682 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1683 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1684 "refName": "master",
1685 "project": "org/project",
1686 }
1687 }
James E. Blairdaabed22012-08-15 15:38:57 -07001688 self.fake_gerrit.addEvent(e)
1689 self.waitUntilSettled()
1690
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001691 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001692 self.assertEqual(len(self.history), 1)
1693 self.assertIn('project-post', job_names)
James E. Blairc6294a52012-08-17 10:19:48 -07001694
1695 def test_build_configuration_branch(self):
1696 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001697
1698 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001699 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1700 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1701 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1702 A.addApproval('CRVW', 2)
1703 B.addApproval('CRVW', 2)
1704 C.addApproval('CRVW', 2)
1705 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1706 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1707 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1708 self.waitUntilSettled()
1709
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001710 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001711 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001712 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001713 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001714 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001715 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001716 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001717 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1718 self.gearman_server.hold_jobs_in_queue = False
1719 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001720 self.waitUntilSettled()
1721
Monty Taylorbc758832013-06-17 17:22:42 -04001722 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001723 repo = git.Repo(path)
1724 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1725 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001726 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001727 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -07001728
1729 def test_build_configuration_branch_interaction(self):
1730 "Test that switching between branches works"
1731 self.test_build_configuration()
1732 self.test_build_configuration_branch()
1733 # C has been merged, undo that
Monty Taylorbc758832013-06-17 17:22:42 -04001734 path = os.path.join(self.upstream_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001735 repo = git.Repo(path)
1736 repo.heads.master.commit = repo.commit('init')
1737 self.test_build_configuration()
1738
1739 def test_build_configuration_multi_branch(self):
1740 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001741
1742 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001743 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1744 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1745 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1746 A.addApproval('CRVW', 2)
1747 B.addApproval('CRVW', 2)
1748 C.addApproval('CRVW', 2)
1749 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1750 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1751 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1752 self.waitUntilSettled()
1753
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001754 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001755 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001756 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001757 job_B = None
1758 for job in queue:
1759 if 'project-merge' in job.name:
1760 job_B = job
1761 ref_B = self.getParameter(job_B, 'ZUUL_REF')
James E. Blairf750aa02013-07-15 14:11:24 -07001762 self.log.debug("Got Zuul ref for change B: %s" % ref_B)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001763 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001764 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001765 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001766 for job in queue:
1767 if 'project-merge' in job.name:
1768 job_C = job
1769 ref_C = self.getParameter(job_C, 'ZUUL_REF')
James E. Blairf750aa02013-07-15 14:11:24 -07001770 self.log.debug("Got Zuul ref for change C: %s" % ref_C)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001771 self.gearman_server.hold_jobs_in_queue = False
1772 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001773 self.waitUntilSettled()
1774
Monty Taylorbc758832013-06-17 17:22:42 -04001775 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001776 repo = git.Repo(path)
1777
1778 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001779 for c in repo.iter_commits(ref_C)]
James E. Blairc6294a52012-08-17 10:19:48 -07001780 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001781 correct_messages = ['initial commit', 'A-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001782 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -07001783
1784 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001785 for c in repo.iter_commits(ref_B)]
James E. Blairc6294a52012-08-17 10:19:48 -07001786 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001787 correct_messages = ['initial commit', 'mp commit', 'B-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001788 self.assertEqual(repo_messages, correct_messages)
James E. Blair7f71c802012-08-22 13:04:32 -07001789
1790 def test_one_job_project(self):
1791 "Test that queueing works with one job"
1792 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1793 'master', 'A')
1794 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1795 'master', 'B')
1796 A.addApproval('CRVW', 2)
1797 B.addApproval('CRVW', 2)
1798 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1799 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1800 self.waitUntilSettled()
1801
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001802 self.assertEqual(A.data['status'], 'MERGED')
1803 self.assertEqual(A.reported, 2)
1804 self.assertEqual(B.data['status'], 'MERGED')
1805 self.assertEqual(B.reported, 2)
James E. Blaircaec0c52012-08-22 14:52:22 -07001806
Antoine Musso80edd5a2013-02-13 15:37:53 +01001807 def test_job_from_templates_launched(self):
1808 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001809
Antoine Musso80edd5a2013-02-13 15:37:53 +01001810 A = self.fake_gerrit.addFakeChange(
1811 'org/templated-project', 'master', 'A')
1812 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1813 self.waitUntilSettled()
Antoine Musso80edd5a2013-02-13 15:37:53 +01001814
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001815 self.assertEqual(self.getJobFromHistory('project-test1').result,
1816 'SUCCESS')
1817 self.assertEqual(self.getJobFromHistory('project-test2').result,
1818 'SUCCESS')
Antoine Musso80edd5a2013-02-13 15:37:53 +01001819
James E. Blaircaec0c52012-08-22 14:52:22 -07001820 def test_dependent_changes_dequeue(self):
1821 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001822
James E. Blaircaec0c52012-08-22 14:52:22 -07001823 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1824 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1825 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1826 A.addApproval('CRVW', 2)
1827 B.addApproval('CRVW', 2)
1828 C.addApproval('CRVW', 2)
1829
1830 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1831 M1.setMerged()
1832
1833 # C -> B -> A -> M1
1834
1835 C.setDependsOn(B, 1)
1836 B.setDependsOn(A, 1)
1837 A.setDependsOn(M1, 1)
1838
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001839 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07001840
1841 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1842 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1843 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1844
1845 self.waitUntilSettled()
1846
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001847 self.assertEqual(A.data['status'], 'NEW')
1848 self.assertEqual(A.reported, 2)
1849 self.assertEqual(B.data['status'], 'NEW')
1850 self.assertEqual(B.reported, 2)
1851 self.assertEqual(C.data['status'], 'NEW')
1852 self.assertEqual(C.reported, 2)
1853 self.assertEqual(len(self.history), 1)
James E. Blairec590122012-08-22 15:19:31 -07001854
1855 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001856 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001857 # If it's dequeued more than once, we should see extra
1858 # aborted jobs.
James E. Blairec590122012-08-22 15:19:31 -07001859
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001860 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07001861 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1862 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1863 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1864 A.addApproval('CRVW', 2)
1865 B.addApproval('CRVW', 2)
1866 C.addApproval('CRVW', 2)
1867
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001868 self.worker.addFailTest('project1-test1', A)
1869 self.worker.addFailTest('project1-test2', A)
1870 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07001871
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
1876 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07001877
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001878 self.assertEqual(len(self.builds), 1)
1879 self.assertEqual(self.builds[0].name, 'project1-merge')
1880 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairec590122012-08-22 15:19:31 -07001881
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001882 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001883 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001884 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001885 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001886 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001887 self.waitUntilSettled()
1888
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001889 self.assertEqual(len(self.builds), 9)
1890 self.assertEqual(self.builds[0].name, 'project1-test1')
1891 self.assertEqual(self.builds[1].name, 'project1-test2')
1892 self.assertEqual(self.builds[2].name, 'project1-project2-integration')
1893 self.assertEqual(self.builds[3].name, 'project1-test1')
1894 self.assertEqual(self.builds[4].name, 'project1-test2')
1895 self.assertEqual(self.builds[5].name, 'project1-project2-integration')
1896 self.assertEqual(self.builds[6].name, 'project1-test1')
1897 self.assertEqual(self.builds[7].name, 'project1-test2')
1898 self.assertEqual(self.builds[8].name, 'project1-project2-integration')
James E. Blairec590122012-08-22 15:19:31 -07001899
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001900 self.release(self.builds[0])
James E. Blairec590122012-08-22 15:19:31 -07001901 self.waitUntilSettled()
1902
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001903 self.assertEqual(len(self.builds), 3) # test2,integration, merge for B
1904 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 6)
James E. Blairec590122012-08-22 15:19:31 -07001905
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001906 self.worker.hold_jobs_in_build = False
1907 self.worker.release()
James E. Blairec590122012-08-22 15:19:31 -07001908 self.waitUntilSettled()
1909
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001910 self.assertEqual(len(self.builds), 0)
1911 self.assertEqual(len(self.history), 20)
James E. Blaircaec0c52012-08-22 14:52:22 -07001912
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001913 self.assertEqual(A.data['status'], 'NEW')
1914 self.assertEqual(B.data['status'], 'MERGED')
1915 self.assertEqual(C.data['status'], 'MERGED')
1916 self.assertEqual(A.reported, 2)
1917 self.assertEqual(B.reported, 2)
1918 self.assertEqual(C.reported, 2)
James E. Blair4ec821f2012-08-23 15:28:28 -07001919
1920 def test_nonvoting_job(self):
1921 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001922
James E. Blair4ec821f2012-08-23 15:28:28 -07001923 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1924 'master', 'A')
1925 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001926 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07001927 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1928
1929 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07001930
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001931 self.assertEqual(A.data['status'], 'MERGED')
1932 self.assertEqual(A.reported, 2)
1933 self.assertEqual(
1934 self.getJobFromHistory('nonvoting-project-merge').result,
1935 'SUCCESS')
1936 self.assertEqual(
1937 self.getJobFromHistory('nonvoting-project-test1').result,
1938 'SUCCESS')
1939 self.assertEqual(
1940 self.getJobFromHistory('nonvoting-project-test2').result,
1941 'FAILURE')
James E. Blaire0487072012-08-29 17:38:31 -07001942
1943 def test_check_queue_success(self):
1944 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001945
James E. Blaire0487072012-08-29 17:38:31 -07001946 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1947 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1948
1949 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001950
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001951 self.assertEqual(A.data['status'], 'NEW')
1952 self.assertEqual(A.reported, 1)
1953 self.assertEqual(self.getJobFromHistory('project-merge').result,
1954 'SUCCESS')
1955 self.assertEqual(self.getJobFromHistory('project-test1').result,
1956 'SUCCESS')
1957 self.assertEqual(self.getJobFromHistory('project-test2').result,
1958 'SUCCESS')
James E. Blaire0487072012-08-29 17:38:31 -07001959
1960 def test_check_queue_failure(self):
1961 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001962
James E. Blaire0487072012-08-29 17:38:31 -07001963 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001964 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07001965 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1966
1967 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001968
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001969 self.assertEqual(A.data['status'], 'NEW')
1970 self.assertEqual(A.reported, 1)
1971 self.assertEqual(self.getJobFromHistory('project-merge').result,
James E. Blair78e31b32013-07-09 09:11:34 -07001972 'SUCCESS')
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001973 self.assertEqual(self.getJobFromHistory('project-test1').result,
1974 'SUCCESS')
1975 self.assertEqual(self.getJobFromHistory('project-test2').result,
1976 'FAILURE')
James E. Blair127bc182012-08-28 15:55:15 -07001977
1978 def test_dependent_behind_dequeue(self):
1979 "test that dependent changes behind dequeued changes work"
1980 # This complicated test is a reproduction of a real life bug
1981 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07001982
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001983 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07001984 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1985 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1986 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1987 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1988 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1989 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1990 D.setDependsOn(C, 1)
1991 E.setDependsOn(D, 1)
1992 A.addApproval('CRVW', 2)
1993 B.addApproval('CRVW', 2)
1994 C.addApproval('CRVW', 2)
1995 D.addApproval('CRVW', 2)
1996 E.addApproval('CRVW', 2)
1997 F.addApproval('CRVW', 2)
1998
1999 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07002000
2001 # Change object re-use in the gerrit trigger is hidden if
2002 # changes are added in quick succession; waiting makes it more
2003 # like real life.
2004 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2005 self.waitUntilSettled()
2006 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2007 self.waitUntilSettled()
2008
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002009 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002010 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002011 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002012 self.waitUntilSettled()
2013
2014 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2015 self.waitUntilSettled()
2016 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2017 self.waitUntilSettled()
2018 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
2019 self.waitUntilSettled()
2020 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
2021 self.waitUntilSettled()
2022
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002023 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002024 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002025 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002026 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002027 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002028 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002029 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07002030 self.waitUntilSettled()
2031
2032 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07002033
2034 # Grab pointers to the jobs we want to release before
2035 # releasing any, because list indexes may change as
2036 # the jobs complete.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002037 a, b, c = self.builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07002038 a.release()
2039 b.release()
2040 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07002041 self.waitUntilSettled()
2042
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002043 self.worker.hold_jobs_in_build = False
2044 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07002045 self.waitUntilSettled()
2046
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002047 self.assertEqual(A.data['status'], 'NEW')
2048 self.assertEqual(B.data['status'], 'MERGED')
2049 self.assertEqual(C.data['status'], 'MERGED')
2050 self.assertEqual(D.data['status'], 'MERGED')
2051 self.assertEqual(E.data['status'], 'MERGED')
2052 self.assertEqual(F.data['status'], 'MERGED')
James E. Blair127bc182012-08-28 15:55:15 -07002053
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002054 self.assertEqual(A.reported, 2)
2055 self.assertEqual(B.reported, 2)
2056 self.assertEqual(C.reported, 2)
2057 self.assertEqual(D.reported, 2)
2058 self.assertEqual(E.reported, 2)
2059 self.assertEqual(F.reported, 2)
James E. Blair127bc182012-08-28 15:55:15 -07002060
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002061 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 15)
2062 self.assertEqual(len(self.history), 44)
James E. Blair05fed602012-09-07 12:45:24 -07002063
2064 def test_merger_repack(self):
2065 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002066
James E. Blair05fed602012-09-07 12:45:24 -07002067 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2068 A.addApproval('CRVW', 2)
2069 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2070 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002071 self.assertEqual(self.getJobFromHistory('project-merge').result,
2072 'SUCCESS')
2073 self.assertEqual(self.getJobFromHistory('project-test1').result,
2074 'SUCCESS')
2075 self.assertEqual(self.getJobFromHistory('project-test2').result,
2076 'SUCCESS')
2077 self.assertEqual(A.data['status'], 'MERGED')
2078 self.assertEqual(A.reported, 2)
James E. Blair05fed602012-09-07 12:45:24 -07002079 self.assertEmptyQueues()
James E. Blair4ca985f2013-05-30 12:27:43 -07002080 self.worker.build_history = []
James E. Blair05fed602012-09-07 12:45:24 -07002081
Monty Taylorbc758832013-06-17 17:22:42 -04002082 path = os.path.join(self.git_root, "org/project")
2083 print repack_repo(path)
James E. Blair05fed602012-09-07 12:45:24 -07002084
2085 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2086 A.addApproval('CRVW', 2)
2087 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2088 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002089 self.assertEqual(self.getJobFromHistory('project-merge').result,
2090 'SUCCESS')
2091 self.assertEqual(self.getJobFromHistory('project-test1').result,
2092 'SUCCESS')
2093 self.assertEqual(self.getJobFromHistory('project-test2').result,
2094 'SUCCESS')
2095 self.assertEqual(A.data['status'], 'MERGED')
2096 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02002097
James E. Blair4886f282012-11-15 09:27:33 -08002098 def test_merger_repack_large_change(self):
2099 "Test that the merger works with large changes after a repack"
2100 # https://bugs.launchpad.net/zuul/+bug/1078946
2101 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2102 A.addPatchset(large=True)
Monty Taylorbc758832013-06-17 17:22:42 -04002103 path = os.path.join(self.upstream_root, "org/project1")
2104 print repack_repo(path)
2105 path = os.path.join(self.git_root, "org/project1")
2106 print repack_repo(path)
James E. Blair4886f282012-11-15 09:27:33 -08002107
2108 A.addApproval('CRVW', 2)
2109 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2110 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002111 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2112 'SUCCESS')
2113 self.assertEqual(self.getJobFromHistory('project1-test1').result,
2114 'SUCCESS')
2115 self.assertEqual(self.getJobFromHistory('project1-test2').result,
2116 'SUCCESS')
2117 self.assertEqual(A.data['status'], 'MERGED')
2118 self.assertEqual(A.reported, 2)
James E. Blair4886f282012-11-15 09:27:33 -08002119
James E. Blair7ee88a22012-09-12 18:59:31 +02002120 def test_nonexistent_job(self):
2121 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002122 # Set to the state immediately after a restart
2123 self.resetGearmanServer()
2124 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02002125
2126 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2127 A.addApproval('CRVW', 2)
2128 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2129 # There may be a thread about to report a lost change
2130 while A.reported < 2:
2131 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002132 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002133 self.assertFalse(job_names)
2134 self.assertEqual(A.data['status'], 'NEW')
2135 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02002136 self.assertEmptyQueues()
2137
2138 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002139 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02002140 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2141 A.addApproval('CRVW', 2)
2142 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2143 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002144 self.assertEqual(self.getJobFromHistory('project-merge').result,
2145 'SUCCESS')
2146 self.assertEqual(self.getJobFromHistory('project-test1').result,
2147 'SUCCESS')
2148 self.assertEqual(self.getJobFromHistory('project-test2').result,
2149 'SUCCESS')
2150 self.assertEqual(A.data['status'], 'MERGED')
2151 self.assertEqual(A.reported, 2)
James E. Blairf62d4282012-12-31 17:01:50 -08002152
2153 def test_single_nonexistent_post_job(self):
2154 "Test launching a single post job that doesn't exist"
James E. Blairf62d4282012-12-31 17:01:50 -08002155 e = {
2156 "type": "ref-updated",
2157 "submitter": {
2158 "name": "User Name",
2159 },
2160 "refUpdate": {
2161 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
2162 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
2163 "refName": "master",
2164 "project": "org/project",
2165 }
2166 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002167 # Set to the state immediately after a restart
2168 self.resetGearmanServer()
2169 self.launcher.negative_function_cache_ttl = 0
2170
James E. Blairf62d4282012-12-31 17:01:50 -08002171 self.fake_gerrit.addEvent(e)
2172 self.waitUntilSettled()
2173
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002174 self.assertEqual(len(self.history), 0)
James E. Blair2fa50962013-01-30 21:50:41 -08002175
2176 def test_new_patchset_dequeues_old(self):
2177 "Test that a new patchset causes the old to be dequeued"
2178 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002179 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002180 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
2181 M.setMerged()
2182
2183 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2184 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2185 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2186 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
2187 A.addApproval('CRVW', 2)
2188 B.addApproval('CRVW', 2)
2189 C.addApproval('CRVW', 2)
2190 D.addApproval('CRVW', 2)
2191
2192 C.setDependsOn(B, 1)
2193 B.setDependsOn(A, 1)
2194 A.setDependsOn(M, 1)
2195
2196 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2197 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2198 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2199 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2200 self.waitUntilSettled()
2201
2202 B.addPatchset()
2203 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2204 self.waitUntilSettled()
2205
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002206 self.worker.hold_jobs_in_build = False
2207 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002208 self.waitUntilSettled()
2209
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002210 self.assertEqual(A.data['status'], 'MERGED')
2211 self.assertEqual(A.reported, 2)
2212 self.assertEqual(B.data['status'], 'NEW')
2213 self.assertEqual(B.reported, 2)
2214 self.assertEqual(C.data['status'], 'NEW')
2215 self.assertEqual(C.reported, 2)
2216 self.assertEqual(D.data['status'], 'MERGED')
2217 self.assertEqual(D.reported, 2)
2218 self.assertEqual(len(self.history), 9) # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08002219
2220 def test_new_patchset_dequeues_old_on_head(self):
2221 "Test that a new patchset causes the old to be dequeued (at head)"
2222 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002223 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002224 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
2225 M.setMerged()
2226 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2227 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2228 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2229 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
2230 A.addApproval('CRVW', 2)
2231 B.addApproval('CRVW', 2)
2232 C.addApproval('CRVW', 2)
2233 D.addApproval('CRVW', 2)
2234
2235 C.setDependsOn(B, 1)
2236 B.setDependsOn(A, 1)
2237 A.setDependsOn(M, 1)
2238
2239 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2240 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2241 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2242 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2243 self.waitUntilSettled()
2244
2245 A.addPatchset()
2246 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
2247 self.waitUntilSettled()
2248
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002249 self.worker.hold_jobs_in_build = False
2250 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002251 self.waitUntilSettled()
2252
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002253 self.assertEqual(A.data['status'], 'NEW')
2254 self.assertEqual(A.reported, 2)
2255 self.assertEqual(B.data['status'], 'NEW')
2256 self.assertEqual(B.reported, 2)
2257 self.assertEqual(C.data['status'], 'NEW')
2258 self.assertEqual(C.reported, 2)
2259 self.assertEqual(D.data['status'], 'MERGED')
2260 self.assertEqual(D.reported, 2)
2261 self.assertEqual(len(self.history), 7)
James E. Blair2fa50962013-01-30 21:50:41 -08002262
2263 def test_new_patchset_dequeues_old_without_dependents(self):
2264 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002265 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002266 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2267 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2268 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2269 A.addApproval('CRVW', 2)
2270 B.addApproval('CRVW', 2)
2271 C.addApproval('CRVW', 2)
2272
2273 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2274 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2275 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2276 self.waitUntilSettled()
2277
2278 B.addPatchset()
2279 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2280 self.waitUntilSettled()
2281
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002282 self.worker.hold_jobs_in_build = False
2283 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002284 self.waitUntilSettled()
2285
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002286 self.assertEqual(A.data['status'], 'MERGED')
2287 self.assertEqual(A.reported, 2)
2288 self.assertEqual(B.data['status'], 'NEW')
2289 self.assertEqual(B.reported, 2)
2290 self.assertEqual(C.data['status'], 'MERGED')
2291 self.assertEqual(C.reported, 2)
2292 self.assertEqual(len(self.history), 9)
James E. Blair2fa50962013-01-30 21:50:41 -08002293
2294 def test_new_patchset_dequeues_old_independent_queue(self):
2295 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002296 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08002297 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2298 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2299 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2300 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2301 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2302 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2303 self.waitUntilSettled()
2304
2305 B.addPatchset()
2306 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
2307 self.waitUntilSettled()
2308
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002309 self.worker.hold_jobs_in_build = False
2310 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08002311 self.waitUntilSettled()
2312
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002313 self.assertEqual(A.data['status'], 'NEW')
2314 self.assertEqual(A.reported, 1)
2315 self.assertEqual(B.data['status'], 'NEW')
2316 self.assertEqual(B.reported, 1)
2317 self.assertEqual(C.data['status'], 'NEW')
2318 self.assertEqual(C.reported, 1)
2319 self.assertEqual(len(self.history), 10)
2320 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002321
2322 def test_zuul_refs(self):
2323 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002324 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08002325 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
2326 M1.setMerged()
2327 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
2328 M2.setMerged()
2329
2330 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2331 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2332 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
2333 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
2334 A.addApproval('CRVW', 2)
2335 B.addApproval('CRVW', 2)
2336 C.addApproval('CRVW', 2)
2337 D.addApproval('CRVW', 2)
2338 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2339 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2340 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2341 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2342
2343 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002344 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002345 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002346 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002347 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002348 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002349 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002350 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002351 self.waitUntilSettled()
2352
James E. Blair7d0dedc2013-02-21 17:26:09 -08002353 a_zref = b_zref = c_zref = d_zref = None
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002354 for x in self.builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08002355 if x.parameters['ZUUL_CHANGE'] == '3':
2356 a_zref = x.parameters['ZUUL_REF']
2357 if x.parameters['ZUUL_CHANGE'] == '4':
2358 b_zref = x.parameters['ZUUL_REF']
2359 if x.parameters['ZUUL_CHANGE'] == '5':
2360 c_zref = x.parameters['ZUUL_REF']
2361 if x.parameters['ZUUL_CHANGE'] == '6':
2362 d_zref = x.parameters['ZUUL_REF']
2363
2364 # There are... four... refs.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002365 self.assertIsNotNone(a_zref)
2366 self.assertIsNotNone(b_zref)
2367 self.assertIsNotNone(c_zref)
2368 self.assertIsNotNone(d_zref)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002369
2370 # And they should all be different
2371 refs = set([a_zref, b_zref, c_zref, d_zref])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002372 self.assertEqual(len(refs), 4)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002373
2374 # a ref should have a, not b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002375 self.assertTrue(self.ref_has_change(a_zref, A))
2376 self.assertFalse(self.ref_has_change(a_zref, B))
2377 self.assertFalse(self.ref_has_change(a_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002378
2379 # b ref should have a and b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002380 self.assertTrue(self.ref_has_change(b_zref, A))
2381 self.assertTrue(self.ref_has_change(b_zref, B))
2382 self.assertFalse(self.ref_has_change(b_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002383
2384 # c ref should have a and b in 1, c in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002385 self.assertTrue(self.ref_has_change(c_zref, A))
2386 self.assertTrue(self.ref_has_change(c_zref, B))
2387 self.assertTrue(self.ref_has_change(c_zref, C))
2388 self.assertFalse(self.ref_has_change(c_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002389
2390 # d ref should have a and b in 1, c and d in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002391 self.assertTrue(self.ref_has_change(d_zref, A))
2392 self.assertTrue(self.ref_has_change(d_zref, B))
2393 self.assertTrue(self.ref_has_change(d_zref, C))
2394 self.assertTrue(self.ref_has_change(d_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002395
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002396 self.worker.hold_jobs_in_build = False
2397 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002398 self.waitUntilSettled()
2399
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002400 self.assertEqual(A.data['status'], 'MERGED')
2401 self.assertEqual(A.reported, 2)
2402 self.assertEqual(B.data['status'], 'MERGED')
2403 self.assertEqual(B.reported, 2)
2404 self.assertEqual(C.data['status'], 'MERGED')
2405 self.assertEqual(C.reported, 2)
2406 self.assertEqual(D.data['status'], 'MERGED')
2407 self.assertEqual(D.reported, 2)
James E. Blair70c71582013-03-06 08:50:50 -08002408
James E. Blair4a28a882013-08-23 15:17:33 -07002409 def test_rerun_on_error(self):
2410 "Test that if a worker fails to run a job, it is run again"
2411 self.worker.hold_jobs_in_build = True
2412 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2413 A.addApproval('CRVW', 2)
2414 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2415 self.waitUntilSettled()
2416
2417 self.builds[0].run_error = True
2418 self.worker.hold_jobs_in_build = False
2419 self.worker.release()
2420 self.waitUntilSettled()
2421 self.assertEqual(self.countJobResults(self.history, 'RUN_ERROR'), 1)
2422 self.assertEqual(self.countJobResults(self.history, 'SUCCESS'), 3)
2423
James E. Blair412e5582013-04-22 15:50:12 -07002424 def test_statsd(self):
2425 "Test each of the statsd methods used in the scheduler"
2426 import extras
2427 statsd = extras.try_import('statsd.statsd')
2428 statsd.incr('test-incr')
2429 statsd.timing('test-timing', 3)
2430 statsd.gauge('test-guage', 12)
2431 self.assertReportedStat('test-incr', '1|c')
2432 self.assertReportedStat('test-timing', '3|ms')
2433 self.assertReportedStat('test-guage', '12|g')
2434
James E. Blair70c71582013-03-06 08:50:50 -08002435 def test_file_jobs(self):
2436 "Test that file jobs run only when appropriate"
2437 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2438 A.addPatchset(['pip-requires'])
2439 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2440 A.addApproval('CRVW', 2)
2441 B.addApproval('CRVW', 2)
2442 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2443 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2444 self.waitUntilSettled()
2445
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002446 testfile_jobs = [x for x in self.history
James E. Blair70c71582013-03-06 08:50:50 -08002447 if x.name == 'project-testfile']
2448
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002449 self.assertEqual(len(testfile_jobs), 1)
2450 self.assertEqual(testfile_jobs[0].changes, '1,2')
2451 self.assertEqual(A.data['status'], 'MERGED')
2452 self.assertEqual(A.reported, 2)
2453 self.assertEqual(B.data['status'], 'MERGED')
2454 self.assertEqual(B.reported, 2)
James E. Blair3c5e5b52013-04-26 11:17:03 -07002455
2456 def test_test_config(self):
2457 "Test that we can test the config"
2458 sched = zuul.scheduler.Scheduler()
James E. Blair6c358e72013-07-29 17:06:47 -07002459 sched.registerTrigger(None, 'gerrit')
James E. Blair63bb0ef2013-07-29 17:14:51 -07002460 sched.registerTrigger(None, 'timer')
James E. Blair3c5e5b52013-04-26 11:17:03 -07002461 sched.testConfig(CONFIG.get('zuul', 'layout_config'))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002462
2463 def test_build_description(self):
2464 "Test that build descriptions update"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002465 self.worker.registerFunction('set_description:' +
2466 self.worker.worker_id)
2467
2468 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2469 A.addApproval('CRVW', 2)
2470 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2471 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002472 desc = self.history[0].description
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002473 self.log.debug("Description: %s" % desc)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002474 self.assertTrue(re.search("Branch.*master", desc))
2475 self.assertTrue(re.search("Pipeline.*gate", desc))
2476 self.assertTrue(re.search("project-merge.*SUCCESS", desc))
2477 self.assertTrue(re.search("project-test1.*SUCCESS", desc))
2478 self.assertTrue(re.search("project-test2.*SUCCESS", desc))
2479 self.assertTrue(re.search("Reported result.*SUCCESS", desc))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002480
James E. Blair64ed6f22013-07-10 14:07:23 -07002481 def test_queue_precedence(self):
2482 "Test that queue precedence works"
2483
2484 self.gearman_server.hold_jobs_in_queue = True
James E. Blair8de58bd2013-07-18 16:23:33 -07002485 self.worker.hold_jobs_in_build = True
James E. Blair64ed6f22013-07-10 14:07:23 -07002486 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2487 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2488 A.addApproval('CRVW', 2)
2489 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2490
2491 self.waitUntilSettled()
2492 self.gearman_server.hold_jobs_in_queue = False
2493 self.gearman_server.release()
2494 self.waitUntilSettled()
2495
James E. Blair8de58bd2013-07-18 16:23:33 -07002496 # Run one build at a time to ensure non-race order:
2497 for x in range(6):
2498 self.release(self.builds[0])
2499 self.waitUntilSettled()
2500 self.worker.hold_jobs_in_build = False
2501 self.waitUntilSettled()
2502
James E. Blair64ed6f22013-07-10 14:07:23 -07002503 self.log.debug(self.history)
2504 self.assertEqual(self.history[0].pipeline, 'gate')
2505 self.assertEqual(self.history[1].pipeline, 'check')
2506 self.assertEqual(self.history[2].pipeline, 'gate')
2507 self.assertEqual(self.history[3].pipeline, 'gate')
2508 self.assertEqual(self.history[4].pipeline, 'check')
2509 self.assertEqual(self.history[5].pipeline, 'check')
2510
James E. Blair1843a552013-07-03 14:19:52 -07002511 def test_json_status(self):
2512 "Test that we can retrieve JSON status info"
2513 self.worker.hold_jobs_in_build = True
2514 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2515 A.addApproval('CRVW', 2)
2516 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2517 self.waitUntilSettled()
2518
2519 port = self.webapp.server.socket.getsockname()[1]
2520
2521 f = urllib.urlopen("http://localhost:%s/status.json" % port)
2522 data = f.read()
2523
2524 self.worker.hold_jobs_in_build = False
2525 self.worker.release()
2526 self.waitUntilSettled()
2527
2528 data = json.loads(data)
2529 status_jobs = set()
2530 for p in data['pipelines']:
2531 for q in p['change_queues']:
2532 for head in q['heads']:
2533 for change in head:
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002534 self.assertEqual(change['id'], '1,1')
James E. Blair1843a552013-07-03 14:19:52 -07002535 for job in change['jobs']:
2536 status_jobs.add(job['name'])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002537 self.assertIn('project-merge', status_jobs)
2538 self.assertIn('project-test1', status_jobs)
2539 self.assertIn('project-test2', status_jobs)
James E. Blair1843a552013-07-03 14:19:52 -07002540
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002541 def test_node_label(self):
2542 "Test that a job runs on a specific node label"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002543 self.worker.registerFunction('build:node-project-test1:debian')
2544
2545 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2546 A.addApproval('CRVW', 2)
2547 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2548 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07002549
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002550 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2551 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2552 'debian')
2553 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
James E. Blaircdccd972013-07-01 12:10:22 -07002554
2555 def test_live_reconfiguration(self):
2556 "Test that live reconfiguration works"
2557 self.worker.hold_jobs_in_build = True
2558 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2559 A.addApproval('CRVW', 2)
2560 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2561 self.waitUntilSettled()
2562
2563 self.sched.reconfigure(self.config)
2564
2565 self.worker.hold_jobs_in_build = False
2566 self.worker.release()
2567 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002568 self.assertEqual(self.getJobFromHistory('project-merge').result,
2569 'SUCCESS')
2570 self.assertEqual(self.getJobFromHistory('project-test1').result,
2571 'SUCCESS')
2572 self.assertEqual(self.getJobFromHistory('project-test2').result,
2573 'SUCCESS')
2574 self.assertEqual(A.data['status'], 'MERGED')
2575 self.assertEqual(A.reported, 2)
James E. Blair287c06d2013-07-24 10:39:30 -07002576
James E. Blaire712d9f2013-07-31 11:40:11 -07002577 def test_live_reconfiguration_functions(self):
2578 "Test live reconfiguration with a custom function"
2579 self.worker.registerFunction('build:node-project-test1:debian')
2580 self.worker.registerFunction('build:node-project-test1:wheezy')
2581 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2582 A.addApproval('CRVW', 2)
2583 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2584 self.waitUntilSettled()
2585
2586 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2587 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2588 'debian')
2589 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2590
2591 self.config.set('zuul', 'layout_config',
2592 'tests/fixtures/layout-live-'
2593 'reconfiguration-functions.yaml')
2594 self.sched.reconfigure(self.config)
2595 self.worker.build_history = []
2596
2597 B = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'B')
2598 B.addApproval('CRVW', 2)
2599 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2600 self.waitUntilSettled()
2601
2602 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2603 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2604 'wheezy')
2605 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2606
James E. Blair287c06d2013-07-24 10:39:30 -07002607 def test_delayed_repo_init(self):
2608 self.config.set('zuul', 'layout_config',
2609 'tests/fixtures/layout-delayed-repo-init.yaml')
2610 self.sched.reconfigure(self.config)
2611
2612 self.init_repo("org/new-project")
2613 A = self.fake_gerrit.addFakeChange('org/new-project', 'master', 'A')
2614
2615 A.addApproval('CRVW', 2)
2616 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2617 self.waitUntilSettled()
2618 self.assertEqual(self.getJobFromHistory('project-merge').result,
2619 'SUCCESS')
2620 self.assertEqual(self.getJobFromHistory('project-test1').result,
2621 'SUCCESS')
2622 self.assertEqual(self.getJobFromHistory('project-test2').result,
2623 'SUCCESS')
2624 self.assertEqual(A.data['status'], 'MERGED')
2625 self.assertEqual(A.reported, 2)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002626
2627 def test_timer(self):
2628 "Test that a periodic job is triggered"
2629 self.worker.hold_jobs_in_build = True
2630 self.config.set('zuul', 'layout_config',
2631 'tests/fixtures/layout-timer.yaml')
2632 self.sched.reconfigure(self.config)
2633 self.registerJobs()
2634
2635 start = time.time()
2636 failed = True
2637 while ((time.time() - start) < 30):
2638 if len(self.builds) == 2:
2639 failed = False
2640 break
2641 else:
2642 time.sleep(1)
2643
2644 if failed:
2645 raise Exception("Expected jobs never ran")
2646
2647 self.waitUntilSettled()
2648 port = self.webapp.server.socket.getsockname()[1]
2649
2650 f = urllib.urlopen("http://localhost:%s/status.json" % port)
2651 data = f.read()
2652
2653 self.worker.hold_jobs_in_build = False
2654 self.worker.release()
2655 self.waitUntilSettled()
2656
2657 self.assertEqual(self.getJobFromHistory(
2658 'project-bitrot-stable-old').result, 'SUCCESS')
2659 self.assertEqual(self.getJobFromHistory(
2660 'project-bitrot-stable-older').result, 'SUCCESS')
2661
2662 data = json.loads(data)
2663 status_jobs = set()
2664 for p in data['pipelines']:
2665 for q in p['change_queues']:
2666 for head in q['heads']:
2667 for change in head:
2668 self.assertEqual(change['id'], 'None')
2669 for job in change['jobs']:
2670 status_jobs.add(job['name'])
2671 self.assertIn('project-bitrot-stable-old', status_jobs)
2672 self.assertIn('project-bitrot-stable-older', status_jobs)