blob: ec90cd6f85283d16694d9286d7e771d2897aee66 [file] [log] [blame]
Gregory Haynes4fc12542015-04-22 20:38:06 -07001# Copyright 2015 GoodData
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
James E. Blair21037782017-07-19 11:56:55 -070015import os
Jan Hrubane252a732017-01-03 15:03:09 +010016import re
Jamie Lennox3f16de52017-05-09 14:24:11 +100017from testtools.matchers import MatchesRegex, StartsWith
Tristan Cacqueray2bafb1f2017-06-12 07:10:26 +000018import urllib
Jan Hruban324ca5b2015-11-05 19:28:54 +010019import time
Gregory Haynes4fc12542015-04-22 20:38:06 -070020
James E. Blair21037782017-07-19 11:56:55 -070021import git
22
Wayne1a78c612015-06-11 17:14:13 -070023from tests.base import ZuulTestCase, simple_layout, random_sha1
Gregory Haynes4fc12542015-04-22 20:38:06 -070024
Gregory Haynes4fc12542015-04-22 20:38:06 -070025
26class TestGithubDriver(ZuulTestCase):
27 config_file = 'zuul-github-driver.conf'
28
29 @simple_layout('layouts/basic-github.yaml', driver='github')
30 def test_pull_event(self):
31 self.executor_server.hold_jobs_in_build = True
32
Jan Hruban37615e52015-11-19 14:30:49 +010033 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
34 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
Gregory Haynes4fc12542015-04-22 20:38:06 -070035 self.waitUntilSettled()
36
37 build_params = self.builds[0].parameters
38 self.assertEqual('master', build_params['ZUUL_BRANCH'])
Jan Hruban37615e52015-11-19 14:30:49 +010039 self.assertEqual(str(A.number), build_params['ZUUL_CHANGE'])
40 self.assertEqual(A.head_sha, build_params['ZUUL_PATCHSET'])
Gregory Haynes4fc12542015-04-22 20:38:06 -070041
42 self.executor_server.hold_jobs_in_build = False
43 self.executor_server.release()
44 self.waitUntilSettled()
45
46 self.assertEqual('SUCCESS',
47 self.getJobFromHistory('project-test1').result)
48 self.assertEqual('SUCCESS',
49 self.getJobFromHistory('project-test2').result)
50
51 job = self.getJobFromHistory('project-test2')
Monty Taylord13bc362017-06-30 13:11:37 -050052 zuulvars = job.parameters['zuul']
Jan Hruban37615e52015-11-19 14:30:49 +010053 self.assertEqual(A.number, zuulvars['change'])
54 self.assertEqual(A.head_sha, zuulvars['patchset'])
55 self.assertEqual(1, len(A.comments))
Jan Hruband4edee82015-12-16 12:49:51 +010056 self.assertEqual(2, len(self.history))
57
58 # test_pull_unmatched_branch_event(self):
59 self.create_branch('org/project', 'unmatched_branch')
60 B = self.fake_github.openFakePullRequest(
61 'org/project', 'unmatched_branch', 'B')
62 self.fake_github.emitEvent(B.getPullRequestOpenedEvent())
63 self.waitUntilSettled()
64
65 self.assertEqual(2, len(self.history))
Wayne1a78c612015-06-11 17:14:13 -070066
Jan Hruban570d01c2016-03-10 21:51:32 +010067 @simple_layout('layouts/files-github.yaml', driver='github')
68 def test_pull_matched_file_event(self):
69 A = self.fake_github.openFakePullRequest(
70 'org/project', 'master', 'A',
71 files=['random.txt', 'build-requires'])
72 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
73 self.waitUntilSettled()
74 self.assertEqual(1, len(self.history))
75
76 # test_pull_unmatched_file_event
77 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B',
78 files=['random.txt'])
79 self.fake_github.emitEvent(B.getPullRequestOpenedEvent())
80 self.waitUntilSettled()
81 self.assertEqual(1, len(self.history))
82
Jan Hrubanc7ab1602015-10-14 15:29:33 +020083 @simple_layout('layouts/basic-github.yaml', driver='github')
84 def test_comment_event(self):
Jan Hruban37615e52015-11-19 14:30:49 +010085 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
86 self.fake_github.emitEvent(A.getCommentAddedEvent('test me'))
Jan Hrubanc7ab1602015-10-14 15:29:33 +020087 self.waitUntilSettled()
88 self.assertEqual(2, len(self.history))
89
90 # Test an unmatched comment, history should remain the same
Jan Hruban37615e52015-11-19 14:30:49 +010091 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
92 self.fake_github.emitEvent(B.getCommentAddedEvent('casual comment'))
Jan Hrubanc7ab1602015-10-14 15:29:33 +020093 self.waitUntilSettled()
94 self.assertEqual(2, len(self.history))
95
Wayne1a78c612015-06-11 17:14:13 -070096 @simple_layout('layouts/push-tag-github.yaml', driver='github')
97 def test_tag_event(self):
98 self.executor_server.hold_jobs_in_build = True
99
James E. Blair21037782017-07-19 11:56:55 -0700100 self.create_branch('org/project', 'tagbranch')
101 files = {'README.txt': 'test'}
102 self.addCommitToRepo('org/project', 'test tag',
103 files, branch='tagbranch', tag='newtag')
104 path = os.path.join(self.upstream_root, 'org/project')
105 repo = git.Repo(path)
106 tag = repo.tags['newtag']
107 sha = tag.commit.hexsha
108 del repo
109
Wayne1a78c612015-06-11 17:14:13 -0700110 self.fake_github.emitEvent(
111 self.fake_github.getPushEvent('org/project', 'refs/tags/newtag',
112 new_rev=sha))
113 self.waitUntilSettled()
114
115 build_params = self.builds[0].parameters
James E. Blaira438c172017-07-21 14:54:42 -0700116 self.assertEqual('refs/tags/newtag', build_params['zuul']['ref'])
Wayne1a78c612015-06-11 17:14:13 -0700117 self.assertEqual('00000000000000000000000000000000',
James E. Blaired8b0012017-07-21 14:49:29 -0700118 build_params['zuul']['oldrev'])
119 self.assertEqual(sha, build_params['zuul']['newrev'])
Wayne1a78c612015-06-11 17:14:13 -0700120
121 self.executor_server.hold_jobs_in_build = False
122 self.executor_server.release()
123 self.waitUntilSettled()
124
125 self.assertEqual('SUCCESS',
126 self.getJobFromHistory('project-tag').result)
127
128 @simple_layout('layouts/push-tag-github.yaml', driver='github')
129 def test_push_event(self):
130 self.executor_server.hold_jobs_in_build = True
131
132 old_sha = random_sha1()
133 new_sha = random_sha1()
134 self.fake_github.emitEvent(
135 self.fake_github.getPushEvent('org/project', 'refs/heads/master',
136 old_sha, new_sha))
137 self.waitUntilSettled()
138
139 build_params = self.builds[0].parameters
James E. Blaira438c172017-07-21 14:54:42 -0700140 self.assertEqual('refs/heads/master', build_params['zuul']['ref'])
James E. Blaired8b0012017-07-21 14:49:29 -0700141 self.assertEqual(old_sha, build_params['zuul']['oldrev'])
142 self.assertEqual(new_sha, build_params['zuul']['newrev'])
Wayne1a78c612015-06-11 17:14:13 -0700143
144 self.executor_server.hold_jobs_in_build = False
145 self.executor_server.release()
146 self.waitUntilSettled()
147
148 self.assertEqual('SUCCESS',
149 self.getJobFromHistory('project-post').result)
Jan Hruband4edee82015-12-16 12:49:51 +0100150 self.assertEqual(1, len(self.history))
151
152 # test unmatched push event
153 old_sha = random_sha1()
154 new_sha = random_sha1()
155 self.fake_github.emitEvent(
156 self.fake_github.getPushEvent('org/project',
157 'refs/heads/unmatched_branch',
158 old_sha, new_sha))
159 self.waitUntilSettled()
160
161 self.assertEqual(1, len(self.history))
Jan Hruban6d53c5e2015-10-24 03:03:34 +0200162
Jan Hruban16ad31f2015-11-07 14:39:07 +0100163 @simple_layout('layouts/labeling-github.yaml', driver='github')
164 def test_labels(self):
Jan Hruban37615e52015-11-19 14:30:49 +0100165 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
Jan Hruban16ad31f2015-11-07 14:39:07 +0100166 self.fake_github.emitEvent(A.addLabel('test'))
167 self.waitUntilSettled()
168 self.assertEqual(1, len(self.history))
169 self.assertEqual('project-labels', self.history[0].name)
170 self.assertEqual(['tests passed'], A.labels)
171
172 # test label removed
Jan Hruban37615e52015-11-19 14:30:49 +0100173 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
Jan Hruban16ad31f2015-11-07 14:39:07 +0100174 B.addLabel('do not test')
175 self.fake_github.emitEvent(B.removeLabel('do not test'))
176 self.waitUntilSettled()
177 self.assertEqual(2, len(self.history))
178 self.assertEqual('project-labels', self.history[1].name)
179 self.assertEqual(['tests passed'], B.labels)
180
181 # test unmatched label
Jan Hruban37615e52015-11-19 14:30:49 +0100182 C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
Jan Hruban16ad31f2015-11-07 14:39:07 +0100183 self.fake_github.emitEvent(C.addLabel('other label'))
184 self.waitUntilSettled()
185 self.assertEqual(2, len(self.history))
186 self.assertEqual(['other label'], C.labels)
187
Jesse Keating5c05a9f2017-01-12 14:44:58 -0800188 @simple_layout('layouts/reviews-github.yaml', driver='github')
189 def test_review_event(self):
190 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
191 self.fake_github.emitEvent(A.getReviewAddedEvent('approve'))
192 self.waitUntilSettled()
193 self.assertEqual(1, len(self.history))
194 self.assertEqual('project-reviews', self.history[0].name)
195 self.assertEqual(['tests passed'], A.labels)
196
197 # test_review_unmatched_event
198 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
199 self.fake_github.emitEvent(B.getReviewAddedEvent('comment'))
200 self.waitUntilSettled()
201 self.assertEqual(1, len(self.history))
202
Jan Hruban324ca5b2015-11-05 19:28:54 +0100203 @simple_layout('layouts/dequeue-github.yaml', driver='github')
204 def test_dequeue_pull_synchronized(self):
205 self.executor_server.hold_jobs_in_build = True
206
Jan Hruban37615e52015-11-19 14:30:49 +0100207 A = self.fake_github.openFakePullRequest(
208 'org/one-job-project', 'master', 'A')
209 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
Jan Hruban324ca5b2015-11-05 19:28:54 +0100210 self.waitUntilSettled()
211
212 # event update stamp has resolution one second, wait so the latter
213 # one has newer timestamp
214 time.sleep(1)
Jan Hruban37615e52015-11-19 14:30:49 +0100215 A.addCommit()
216 self.fake_github.emitEvent(A.getPullRequestSynchronizeEvent())
Jan Hruban324ca5b2015-11-05 19:28:54 +0100217 self.waitUntilSettled()
218
219 self.executor_server.hold_jobs_in_build = False
220 self.executor_server.release()
221 self.waitUntilSettled()
222
223 self.assertEqual(2, len(self.history))
224 self.assertEqual(1, self.countJobResults(self.history, 'ABORTED'))
225
226 @simple_layout('layouts/dequeue-github.yaml', driver='github')
227 def test_dequeue_pull_abandoned(self):
228 self.executor_server.hold_jobs_in_build = True
229
Jan Hruban37615e52015-11-19 14:30:49 +0100230 A = self.fake_github.openFakePullRequest(
231 'org/one-job-project', 'master', 'A')
232 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
Jan Hruban324ca5b2015-11-05 19:28:54 +0100233 self.waitUntilSettled()
Jan Hruban37615e52015-11-19 14:30:49 +0100234 self.fake_github.emitEvent(A.getPullRequestClosedEvent())
Jan Hruban324ca5b2015-11-05 19:28:54 +0100235 self.waitUntilSettled()
236
237 self.executor_server.hold_jobs_in_build = False
238 self.executor_server.release()
239 self.waitUntilSettled()
240
241 self.assertEqual(1, len(self.history))
242 self.assertEqual(1, self.countJobResults(self.history, 'ABORTED'))
243
Jan Hruban6d53c5e2015-10-24 03:03:34 +0200244 @simple_layout('layouts/basic-github.yaml', driver='github')
245 def test_git_https_url(self):
246 """Test that git_ssh option gives git url with ssh"""
247 url = self.fake_github.real_getGitUrl('org/project')
248 self.assertEqual('https://github.com/org/project', url)
249
250 @simple_layout('layouts/basic-github.yaml', driver='github')
251 def test_git_ssh_url(self):
252 """Test that git_ssh option gives git url with ssh"""
253 url = self.fake_github_ssh.real_getGitUrl('org/project')
254 self.assertEqual('ssh://git@github.com/org/project.git', url)
Jan Hrubane252a732017-01-03 15:03:09 +0100255
Jesse Keatingbe4ef8a2016-12-06 11:29:13 -0800256 @simple_layout('layouts/basic-github.yaml', driver='github')
257 def test_git_enterprise_url(self):
258 """Test that git_url option gives git url with proper host"""
259 url = self.fake_github_ent.real_getGitUrl('org/project')
260 self.assertEqual('ssh://git@github.enterprise.io/org/project.git', url)
261
Jan Hrubane252a732017-01-03 15:03:09 +0100262 @simple_layout('layouts/reporting-github.yaml', driver='github')
263 def test_reporting(self):
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700264 project = 'org/project'
Jan Hrubane252a732017-01-03 15:03:09 +0100265 # pipeline reports pull status both on start and success
266 self.executor_server.hold_jobs_in_build = True
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700267 A = self.fake_github.openFakePullRequest(project, 'master', 'A')
Jan Hruban37615e52015-11-19 14:30:49 +0100268 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
Jan Hrubane252a732017-01-03 15:03:09 +0100269 self.waitUntilSettled()
Jesse Keatingd96e5882017-01-19 13:55:50 -0800270 # We should have a status container for the head sha
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700271 statuses = self.fake_github.statuses[project][A.head_sha]
272 self.assertIn(A.head_sha, self.fake_github.statuses[project].keys())
Jesse Keatingd96e5882017-01-19 13:55:50 -0800273 # We should only have one status for the head sha
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700274 self.assertEqual(1, len(statuses))
275 check_status = statuses[0]
Jan Hrubanddeb95a2017-01-03 15:12:41 +0100276 check_url = ('http://zuul.example.com/status/#%s,%s' %
277 (A.number, A.head_sha))
Jamie Lennox18bc7ed2017-05-10 10:37:55 +1000278 self.assertEqual('tenant-one/check', check_status['context'])
Jan Hrubane252a732017-01-03 15:03:09 +0100279 self.assertEqual('Standard check', check_status['description'])
280 self.assertEqual('pending', check_status['state'])
Jan Hrubanddeb95a2017-01-03 15:12:41 +0100281 self.assertEqual(check_url, check_status['url'])
Jan Hruban37615e52015-11-19 14:30:49 +0100282 self.assertEqual(0, len(A.comments))
Jan Hrubane252a732017-01-03 15:03:09 +0100283
284 self.executor_server.hold_jobs_in_build = False
285 self.executor_server.release()
286 self.waitUntilSettled()
Jesse Keatingd96e5882017-01-19 13:55:50 -0800287 # We should only have two statuses for the head sha
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700288 statuses = self.fake_github.statuses[project][A.head_sha]
289 self.assertEqual(2, len(statuses))
290 check_status = statuses[0]
Jesse Keatingd96e5882017-01-19 13:55:50 -0800291 check_url = ('http://zuul.example.com/status/#%s,%s' %
292 (A.number, A.head_sha))
Jamie Lennox18bc7ed2017-05-10 10:37:55 +1000293 self.assertEqual('tenant-one/check', check_status['context'])
Jan Hrubane252a732017-01-03 15:03:09 +0100294 self.assertEqual('success', check_status['state'])
Jan Hrubanddeb95a2017-01-03 15:12:41 +0100295 self.assertEqual(check_url, check_status['url'])
Jan Hruban37615e52015-11-19 14:30:49 +0100296 self.assertEqual(1, len(A.comments))
297 self.assertThat(A.comments[0],
Jan Hrubane252a732017-01-03 15:03:09 +0100298 MatchesRegex('.*Build succeeded.*', re.DOTALL))
299
300 # pipeline does not report any status but does comment
301 self.executor_server.hold_jobs_in_build = True
302 self.fake_github.emitEvent(
Jan Hruban37615e52015-11-19 14:30:49 +0100303 A.getCommentAddedEvent('reporting check'))
Jan Hrubane252a732017-01-03 15:03:09 +0100304 self.waitUntilSettled()
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700305 statuses = self.fake_github.statuses[project][A.head_sha]
306 self.assertEqual(2, len(statuses))
Jan Hrubane252a732017-01-03 15:03:09 +0100307 # comments increased by one for the start message
Jan Hruban37615e52015-11-19 14:30:49 +0100308 self.assertEqual(2, len(A.comments))
309 self.assertThat(A.comments[1],
Jan Hrubane252a732017-01-03 15:03:09 +0100310 MatchesRegex('.*Starting reporting jobs.*', re.DOTALL))
311 self.executor_server.hold_jobs_in_build = False
312 self.executor_server.release()
313 self.waitUntilSettled()
Jesse Keatingd96e5882017-01-19 13:55:50 -0800314 # pipeline reports success status
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700315 statuses = self.fake_github.statuses[project][A.head_sha]
316 self.assertEqual(3, len(statuses))
317 report_status = statuses[0]
Jamie Lennox18bc7ed2017-05-10 10:37:55 +1000318 self.assertEqual('tenant-one/reporting', report_status['context'])
Jesse Keatingd96e5882017-01-19 13:55:50 -0800319 self.assertEqual('success', report_status['state'])
Jan Hruban37615e52015-11-19 14:30:49 +0100320 self.assertEqual(2, len(A.comments))
Jamie Lennox3f16de52017-05-09 14:24:11 +1000321
322 base = 'http://logs.example.com/tenant-one/reporting/%s/%s/' % (
323 A.project, A.number)
324
325 # Deconstructing the URL because we don't save the BuildSet UUID
326 # anywhere to do a direct comparison and doing regexp matches on a full
327 # URL is painful.
328
329 # The first part of the URL matches the easy base string
330 self.assertThat(report_status['url'], StartsWith(base))
331
332 # The rest of the URL is a UUID and a trailing slash.
333 self.assertThat(report_status['url'][len(base):],
334 MatchesRegex('^[a-fA-F0-9]{32}\/$'))
Jan Hruban49bff072015-11-03 11:45:46 +0100335
Jesse Keating08dab8f2017-06-21 12:59:23 +0100336 @simple_layout('layouts/reporting-github.yaml', driver='github')
337 def test_push_reporting(self):
338 project = 'org/project2'
339 # pipeline reports pull status both on start and success
340 self.executor_server.hold_jobs_in_build = True
341 pevent = self.fake_github.getPushEvent(project=project,
342 ref='refs/heads/master')
343
344 self.fake_github.emitEvent(pevent)
345 self.waitUntilSettled()
346
347 # there should only be one report, a status
348 self.assertEqual(1, len(self.fake_github.reports))
349 # Verify the user/context/state of the status
350 status = ('zuul', 'tenant-one/push-reporting', 'pending')
351 self.assertEqual(status, self.fake_github.reports[0][-1])
352
353 # free the executor, allow the build to finish
354 self.executor_server.hold_jobs_in_build = False
355 self.executor_server.release()
356 self.waitUntilSettled()
357
358 # Now there should be a second report, the success of the build
359 self.assertEqual(2, len(self.fake_github.reports))
360 # Verify the user/context/state of the status
361 status = ('zuul', 'tenant-one/push-reporting', 'success')
362 self.assertEqual(status, self.fake_github.reports[-1][-1])
363
364 # now make a PR which should also comment
365 self.executor_server.hold_jobs_in_build = True
366 A = self.fake_github.openFakePullRequest(project, 'master', 'A')
367 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
368 self.waitUntilSettled()
369
370 # Now there should be a four reports, a new comment
371 # and status
372 self.assertEqual(4, len(self.fake_github.reports))
373 self.executor_server.release()
374 self.waitUntilSettled()
375
Jan Hruban49bff072015-11-03 11:45:46 +0100376 @simple_layout('layouts/merging-github.yaml', driver='github')
377 def test_report_pull_merge(self):
378 # pipeline merges the pull request on success
Jan Hruban3b415922016-02-03 13:10:22 +0100379 A = self.fake_github.openFakePullRequest('org/project', 'master',
380 'PR title')
Jan Hruban49bff072015-11-03 11:45:46 +0100381 self.fake_github.emitEvent(A.getCommentAddedEvent('merge me'))
382 self.waitUntilSettled()
383 self.assertTrue(A.is_merged)
Jan Hruban3b415922016-02-03 13:10:22 +0100384 self.assertThat(A.merge_message,
385 MatchesRegex('.*PR title.*Reviewed-by.*', re.DOTALL))
Jan Hruban49bff072015-11-03 11:45:46 +0100386
387 # pipeline merges the pull request on success after failure
388 self.fake_github.merge_failure = True
Jan Hruban37615e52015-11-19 14:30:49 +0100389 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
Jan Hruban49bff072015-11-03 11:45:46 +0100390 self.fake_github.emitEvent(B.getCommentAddedEvent('merge me'))
391 self.waitUntilSettled()
392 self.assertFalse(B.is_merged)
393 self.fake_github.merge_failure = False
394
395 # pipeline merges the pull request on second run of merge
396 # first merge failed on 405 Method Not Allowed error
397 self.fake_github.merge_not_allowed_count = 1
Jan Hruban37615e52015-11-19 14:30:49 +0100398 C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
Jan Hruban49bff072015-11-03 11:45:46 +0100399 self.fake_github.emitEvent(C.getCommentAddedEvent('merge me'))
400 self.waitUntilSettled()
401 self.assertTrue(C.is_merged)
402
403 # pipeline does not merge the pull request
404 # merge failed on 405 Method Not Allowed error - twice
405 self.fake_github.merge_not_allowed_count = 2
Jan Hruban37615e52015-11-19 14:30:49 +0100406 D = self.fake_github.openFakePullRequest('org/project', 'master', 'D')
Jan Hruban49bff072015-11-03 11:45:46 +0100407 self.fake_github.emitEvent(D.getCommentAddedEvent('merge me'))
408 self.waitUntilSettled()
409 self.assertFalse(D.is_merged)
Adam Gandelman62198cb2017-02-14 16:11:02 -0800410 self.assertEqual(len(D.comments), 1)
411 self.assertEqual(D.comments[0], 'Merge failed')
Jan Hruban37615e52015-11-19 14:30:49 +0100412
413 @simple_layout('layouts/dependent-github.yaml', driver='github')
414 def test_parallel_changes(self):
415 "Test that changes are tested in parallel and merged in series"
416
417 self.executor_server.hold_jobs_in_build = True
418 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
419 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
420 C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
421
422 self.fake_github.emitEvent(A.addLabel('merge'))
423 self.fake_github.emitEvent(B.addLabel('merge'))
424 self.fake_github.emitEvent(C.addLabel('merge'))
425
426 self.waitUntilSettled()
427 self.assertEqual(len(self.builds), 1)
428 self.assertEqual(self.builds[0].name, 'project-merge')
429 self.assertTrue(self.builds[0].hasChanges(A))
430
431 self.executor_server.release('.*-merge')
432 self.waitUntilSettled()
433 self.assertEqual(len(self.builds), 3)
434 self.assertEqual(self.builds[0].name, 'project-test1')
435 self.assertTrue(self.builds[0].hasChanges(A))
436 self.assertEqual(self.builds[1].name, 'project-test2')
437 self.assertTrue(self.builds[1].hasChanges(A))
438 self.assertEqual(self.builds[2].name, 'project-merge')
439 self.assertTrue(self.builds[2].hasChanges(A, B))
440
441 self.executor_server.release('.*-merge')
442 self.waitUntilSettled()
443 self.assertEqual(len(self.builds), 5)
444 self.assertEqual(self.builds[0].name, 'project-test1')
445 self.assertTrue(self.builds[0].hasChanges(A))
446 self.assertEqual(self.builds[1].name, 'project-test2')
447 self.assertTrue(self.builds[1].hasChanges(A))
448
449 self.assertEqual(self.builds[2].name, 'project-test1')
450 self.assertTrue(self.builds[2].hasChanges(A))
451 self.assertEqual(self.builds[3].name, 'project-test2')
452 self.assertTrue(self.builds[3].hasChanges(A, B))
453
454 self.assertEqual(self.builds[4].name, 'project-merge')
455 self.assertTrue(self.builds[4].hasChanges(A, B, C))
456
457 self.executor_server.release('.*-merge')
458 self.waitUntilSettled()
459 self.assertEqual(len(self.builds), 6)
460 self.assertEqual(self.builds[0].name, 'project-test1')
461 self.assertTrue(self.builds[0].hasChanges(A))
462 self.assertEqual(self.builds[1].name, 'project-test2')
463 self.assertTrue(self.builds[1].hasChanges(A))
464
465 self.assertEqual(self.builds[2].name, 'project-test1')
466 self.assertTrue(self.builds[2].hasChanges(A, B))
467 self.assertEqual(self.builds[3].name, 'project-test2')
468 self.assertTrue(self.builds[3].hasChanges(A, B))
469
470 self.assertEqual(self.builds[4].name, 'project-test1')
471 self.assertTrue(self.builds[4].hasChanges(A, B, C))
472 self.assertEqual(self.builds[5].name, 'project-test2')
473 self.assertTrue(self.builds[5].hasChanges(A, B, C))
474
475 all_builds = self.builds[:]
476 self.release(all_builds[2])
477 self.release(all_builds[3])
478 self.waitUntilSettled()
479 self.assertFalse(A.is_merged)
480 self.assertFalse(B.is_merged)
481 self.assertFalse(C.is_merged)
482
483 self.release(all_builds[0])
484 self.release(all_builds[1])
485 self.waitUntilSettled()
486 self.assertTrue(A.is_merged)
487 self.assertTrue(B.is_merged)
488 self.assertFalse(C.is_merged)
489
490 self.executor_server.hold_jobs_in_build = False
491 self.executor_server.release()
492 self.waitUntilSettled()
493 self.assertEqual(len(self.builds), 0)
494 self.assertEqual(len(self.history), 9)
495 self.assertTrue(C.is_merged)
496
497 self.assertNotIn('merge', A.labels)
498 self.assertNotIn('merge', B.labels)
499 self.assertNotIn('merge', C.labels)
500
501 @simple_layout('layouts/dependent-github.yaml', driver='github')
502 def test_failed_changes(self):
503 "Test that a change behind a failed change is retested"
504 self.executor_server.hold_jobs_in_build = True
505
506 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
507 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
508
509 self.executor_server.failJob('project-test1', A)
510
511 self.fake_github.emitEvent(A.addLabel('merge'))
512 self.fake_github.emitEvent(B.addLabel('merge'))
513 self.waitUntilSettled()
514
515 self.executor_server.release('.*-merge')
516 self.waitUntilSettled()
517
518 self.executor_server.hold_jobs_in_build = False
519 self.executor_server.release()
520
521 self.waitUntilSettled()
522 # It's certain that the merge job for change 2 will run, but
523 # the test1 and test2 jobs may or may not run.
524 self.assertTrue(len(self.history) > 6)
525 self.assertFalse(A.is_merged)
526 self.assertTrue(B.is_merged)
527 self.assertNotIn('merge', A.labels)
528 self.assertNotIn('merge', B.labels)
529
530 @simple_layout('layouts/dependent-github.yaml', driver='github')
531 def test_failed_change_at_head(self):
532 "Test that if a change at the head fails, jobs behind it are canceled"
533
534 self.executor_server.hold_jobs_in_build = True
535 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
536 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
537 C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
538
539 self.executor_server.failJob('project-test1', A)
540
541 self.fake_github.emitEvent(A.addLabel('merge'))
542 self.fake_github.emitEvent(B.addLabel('merge'))
543 self.fake_github.emitEvent(C.addLabel('merge'))
544
545 self.waitUntilSettled()
546
547 self.assertEqual(len(self.builds), 1)
548 self.assertEqual(self.builds[0].name, 'project-merge')
549 self.assertTrue(self.builds[0].hasChanges(A))
550
551 self.executor_server.release('.*-merge')
552 self.waitUntilSettled()
553 self.executor_server.release('.*-merge')
554 self.waitUntilSettled()
555 self.executor_server.release('.*-merge')
556 self.waitUntilSettled()
557
558 self.assertEqual(len(self.builds), 6)
559 self.assertEqual(self.builds[0].name, 'project-test1')
560 self.assertEqual(self.builds[1].name, 'project-test2')
561 self.assertEqual(self.builds[2].name, 'project-test1')
562 self.assertEqual(self.builds[3].name, 'project-test2')
563 self.assertEqual(self.builds[4].name, 'project-test1')
564 self.assertEqual(self.builds[5].name, 'project-test2')
565
566 self.release(self.builds[0])
567 self.waitUntilSettled()
568
569 # project-test2, project-merge for B
570 self.assertEqual(len(self.builds), 2)
571 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
572
573 self.executor_server.hold_jobs_in_build = False
574 self.executor_server.release()
575 self.waitUntilSettled()
576
577 self.assertEqual(len(self.builds), 0)
578 self.assertEqual(len(self.history), 15)
579 self.assertFalse(A.is_merged)
580 self.assertTrue(B.is_merged)
581 self.assertTrue(C.is_merged)
582 self.assertNotIn('merge', A.labels)
583 self.assertNotIn('merge', B.labels)
584 self.assertNotIn('merge', C.labels)
Jesse Keating71a47ff2017-06-06 11:36:43 -0700585
586 @simple_layout('layouts/basic-github.yaml', driver='github')
587 def test_push_event_reconfigure(self):
588 pevent = self.fake_github.getPushEvent(project='common-config',
589 ref='refs/heads/master',
590 modified_files=['zuul.yaml'])
591
592 # record previous tenant reconfiguration time, which may not be set
593 old = self.sched.tenant_last_reconfigured.get('tenant-one', 0)
594 time.sleep(1)
595 self.fake_github.emitEvent(pevent)
596 self.waitUntilSettled()
597 new = self.sched.tenant_last_reconfigured.get('tenant-one', 0)
598 # New timestamp should be greater than the old timestamp
599 self.assertLess(old, new)
Tristan Cacqueray2bafb1f2017-06-12 07:10:26 +0000600
601 @simple_layout('layouts/basic-github.yaml', driver='github')
602 def test_ping_event(self):
603 # Test valid ping
604 pevent = {'repository': {'full_name': 'org/project'}}
605 req = self.fake_github.emitEvent(('ping', pevent))
606 self.assertEqual(req.status, 200, "Ping event didn't succeed")
607
608 # Test invalid ping
609 pevent = {'repository': {'full_name': 'unknown-project'}}
610 self.assertRaises(
611 urllib.error.HTTPError,
612 self.fake_github.emitEvent,
613 ('ping', pevent),
614 )