blob: ba8e497ae6a0001c22f6bcbc0944f527d3169119 [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
Jan Hrubane252a732017-01-03 15:03:09 +010015import re
Jamie Lennox3f16de52017-05-09 14:24:11 +100016from testtools.matchers import MatchesRegex, StartsWith
Jan Hruban324ca5b2015-11-05 19:28:54 +010017import time
Gregory Haynes4fc12542015-04-22 20:38:06 -070018
Wayne1a78c612015-06-11 17:14:13 -070019from tests.base import ZuulTestCase, simple_layout, random_sha1
Gregory Haynes4fc12542015-04-22 20:38:06 -070020
Gregory Haynes4fc12542015-04-22 20:38:06 -070021
22class TestGithubDriver(ZuulTestCase):
23 config_file = 'zuul-github-driver.conf'
24
25 @simple_layout('layouts/basic-github.yaml', driver='github')
26 def test_pull_event(self):
27 self.executor_server.hold_jobs_in_build = True
28
Jan Hruban37615e52015-11-19 14:30:49 +010029 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
30 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
Gregory Haynes4fc12542015-04-22 20:38:06 -070031 self.waitUntilSettled()
32
33 build_params = self.builds[0].parameters
34 self.assertEqual('master', build_params['ZUUL_BRANCH'])
Jan Hruban37615e52015-11-19 14:30:49 +010035 self.assertEqual(str(A.number), build_params['ZUUL_CHANGE'])
36 self.assertEqual(A.head_sha, build_params['ZUUL_PATCHSET'])
Gregory Haynes4fc12542015-04-22 20:38:06 -070037
38 self.executor_server.hold_jobs_in_build = False
39 self.executor_server.release()
40 self.waitUntilSettled()
41
42 self.assertEqual('SUCCESS',
43 self.getJobFromHistory('project-test1').result)
44 self.assertEqual('SUCCESS',
45 self.getJobFromHistory('project-test2').result)
46
47 job = self.getJobFromHistory('project-test2')
48 zuulvars = job.parameters['vars']['zuul']
Jan Hruban37615e52015-11-19 14:30:49 +010049 self.assertEqual(A.number, zuulvars['change'])
50 self.assertEqual(A.head_sha, zuulvars['patchset'])
51 self.assertEqual(1, len(A.comments))
Jan Hruband4edee82015-12-16 12:49:51 +010052 self.assertEqual(2, len(self.history))
53
54 # test_pull_unmatched_branch_event(self):
55 self.create_branch('org/project', 'unmatched_branch')
56 B = self.fake_github.openFakePullRequest(
57 'org/project', 'unmatched_branch', 'B')
58 self.fake_github.emitEvent(B.getPullRequestOpenedEvent())
59 self.waitUntilSettled()
60
61 self.assertEqual(2, len(self.history))
Wayne1a78c612015-06-11 17:14:13 -070062
Jan Hruban570d01c2016-03-10 21:51:32 +010063 @simple_layout('layouts/files-github.yaml', driver='github')
64 def test_pull_matched_file_event(self):
65 A = self.fake_github.openFakePullRequest(
66 'org/project', 'master', 'A',
67 files=['random.txt', 'build-requires'])
68 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
69 self.waitUntilSettled()
70 self.assertEqual(1, len(self.history))
71
72 # test_pull_unmatched_file_event
73 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B',
74 files=['random.txt'])
75 self.fake_github.emitEvent(B.getPullRequestOpenedEvent())
76 self.waitUntilSettled()
77 self.assertEqual(1, len(self.history))
78
Jan Hrubanc7ab1602015-10-14 15:29:33 +020079 @simple_layout('layouts/basic-github.yaml', driver='github')
80 def test_comment_event(self):
Jan Hruban37615e52015-11-19 14:30:49 +010081 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
82 self.fake_github.emitEvent(A.getCommentAddedEvent('test me'))
Jan Hrubanc7ab1602015-10-14 15:29:33 +020083 self.waitUntilSettled()
84 self.assertEqual(2, len(self.history))
85
86 # Test an unmatched comment, history should remain the same
Jan Hruban37615e52015-11-19 14:30:49 +010087 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
88 self.fake_github.emitEvent(B.getCommentAddedEvent('casual comment'))
Jan Hrubanc7ab1602015-10-14 15:29:33 +020089 self.waitUntilSettled()
90 self.assertEqual(2, len(self.history))
91
Wayne1a78c612015-06-11 17:14:13 -070092 @simple_layout('layouts/push-tag-github.yaml', driver='github')
93 def test_tag_event(self):
94 self.executor_server.hold_jobs_in_build = True
95
96 sha = random_sha1()
97 self.fake_github.emitEvent(
98 self.fake_github.getPushEvent('org/project', 'refs/tags/newtag',
99 new_rev=sha))
100 self.waitUntilSettled()
101
102 build_params = self.builds[0].parameters
103 self.assertEqual('refs/tags/newtag', build_params['ZUUL_REF'])
104 self.assertEqual('00000000000000000000000000000000',
105 build_params['ZUUL_OLDREV'])
106 self.assertEqual(sha, build_params['ZUUL_NEWREV'])
107
108 self.executor_server.hold_jobs_in_build = False
109 self.executor_server.release()
110 self.waitUntilSettled()
111
112 self.assertEqual('SUCCESS',
113 self.getJobFromHistory('project-tag').result)
114
115 @simple_layout('layouts/push-tag-github.yaml', driver='github')
116 def test_push_event(self):
117 self.executor_server.hold_jobs_in_build = True
118
119 old_sha = random_sha1()
120 new_sha = random_sha1()
121 self.fake_github.emitEvent(
122 self.fake_github.getPushEvent('org/project', 'refs/heads/master',
123 old_sha, new_sha))
124 self.waitUntilSettled()
125
126 build_params = self.builds[0].parameters
127 self.assertEqual('refs/heads/master', build_params['ZUUL_REF'])
128 self.assertEqual(old_sha, build_params['ZUUL_OLDREV'])
129 self.assertEqual(new_sha, build_params['ZUUL_NEWREV'])
130
131 self.executor_server.hold_jobs_in_build = False
132 self.executor_server.release()
133 self.waitUntilSettled()
134
135 self.assertEqual('SUCCESS',
136 self.getJobFromHistory('project-post').result)
Jan Hruband4edee82015-12-16 12:49:51 +0100137 self.assertEqual(1, len(self.history))
138
139 # test unmatched push event
140 old_sha = random_sha1()
141 new_sha = random_sha1()
142 self.fake_github.emitEvent(
143 self.fake_github.getPushEvent('org/project',
144 'refs/heads/unmatched_branch',
145 old_sha, new_sha))
146 self.waitUntilSettled()
147
148 self.assertEqual(1, len(self.history))
Jan Hruban6d53c5e2015-10-24 03:03:34 +0200149
Jan Hruban16ad31f2015-11-07 14:39:07 +0100150 @simple_layout('layouts/labeling-github.yaml', driver='github')
151 def test_labels(self):
Jan Hruban37615e52015-11-19 14:30:49 +0100152 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
Jan Hruban16ad31f2015-11-07 14:39:07 +0100153 self.fake_github.emitEvent(A.addLabel('test'))
154 self.waitUntilSettled()
155 self.assertEqual(1, len(self.history))
156 self.assertEqual('project-labels', self.history[0].name)
157 self.assertEqual(['tests passed'], A.labels)
158
159 # test label removed
Jan Hruban37615e52015-11-19 14:30:49 +0100160 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
Jan Hruban16ad31f2015-11-07 14:39:07 +0100161 B.addLabel('do not test')
162 self.fake_github.emitEvent(B.removeLabel('do not test'))
163 self.waitUntilSettled()
164 self.assertEqual(2, len(self.history))
165 self.assertEqual('project-labels', self.history[1].name)
166 self.assertEqual(['tests passed'], B.labels)
167
168 # test unmatched label
Jan Hruban37615e52015-11-19 14:30:49 +0100169 C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
Jan Hruban16ad31f2015-11-07 14:39:07 +0100170 self.fake_github.emitEvent(C.addLabel('other label'))
171 self.waitUntilSettled()
172 self.assertEqual(2, len(self.history))
173 self.assertEqual(['other label'], C.labels)
174
Jesse Keating5c05a9f2017-01-12 14:44:58 -0800175 @simple_layout('layouts/reviews-github.yaml', driver='github')
176 def test_review_event(self):
177 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
178 self.fake_github.emitEvent(A.getReviewAddedEvent('approve'))
179 self.waitUntilSettled()
180 self.assertEqual(1, len(self.history))
181 self.assertEqual('project-reviews', self.history[0].name)
182 self.assertEqual(['tests passed'], A.labels)
183
184 # test_review_unmatched_event
185 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
186 self.fake_github.emitEvent(B.getReviewAddedEvent('comment'))
187 self.waitUntilSettled()
188 self.assertEqual(1, len(self.history))
189
Jan Hruban324ca5b2015-11-05 19:28:54 +0100190 @simple_layout('layouts/dequeue-github.yaml', driver='github')
191 def test_dequeue_pull_synchronized(self):
192 self.executor_server.hold_jobs_in_build = True
193
Jan Hruban37615e52015-11-19 14:30:49 +0100194 A = self.fake_github.openFakePullRequest(
195 'org/one-job-project', 'master', 'A')
196 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
Jan Hruban324ca5b2015-11-05 19:28:54 +0100197 self.waitUntilSettled()
198
199 # event update stamp has resolution one second, wait so the latter
200 # one has newer timestamp
201 time.sleep(1)
Jan Hruban37615e52015-11-19 14:30:49 +0100202 A.addCommit()
203 self.fake_github.emitEvent(A.getPullRequestSynchronizeEvent())
Jan Hruban324ca5b2015-11-05 19:28:54 +0100204 self.waitUntilSettled()
205
206 self.executor_server.hold_jobs_in_build = False
207 self.executor_server.release()
208 self.waitUntilSettled()
209
210 self.assertEqual(2, len(self.history))
211 self.assertEqual(1, self.countJobResults(self.history, 'ABORTED'))
212
213 @simple_layout('layouts/dequeue-github.yaml', driver='github')
214 def test_dequeue_pull_abandoned(self):
215 self.executor_server.hold_jobs_in_build = True
216
Jan Hruban37615e52015-11-19 14:30:49 +0100217 A = self.fake_github.openFakePullRequest(
218 'org/one-job-project', 'master', 'A')
219 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
Jan Hruban324ca5b2015-11-05 19:28:54 +0100220 self.waitUntilSettled()
Jan Hruban37615e52015-11-19 14:30:49 +0100221 self.fake_github.emitEvent(A.getPullRequestClosedEvent())
Jan Hruban324ca5b2015-11-05 19:28:54 +0100222 self.waitUntilSettled()
223
224 self.executor_server.hold_jobs_in_build = False
225 self.executor_server.release()
226 self.waitUntilSettled()
227
228 self.assertEqual(1, len(self.history))
229 self.assertEqual(1, self.countJobResults(self.history, 'ABORTED'))
230
Jan Hruban6d53c5e2015-10-24 03:03:34 +0200231 @simple_layout('layouts/basic-github.yaml', driver='github')
232 def test_git_https_url(self):
233 """Test that git_ssh option gives git url with ssh"""
234 url = self.fake_github.real_getGitUrl('org/project')
235 self.assertEqual('https://github.com/org/project', url)
236
237 @simple_layout('layouts/basic-github.yaml', driver='github')
238 def test_git_ssh_url(self):
239 """Test that git_ssh option gives git url with ssh"""
240 url = self.fake_github_ssh.real_getGitUrl('org/project')
241 self.assertEqual('ssh://git@github.com/org/project.git', url)
Jan Hrubane252a732017-01-03 15:03:09 +0100242
Jesse Keatingbe4ef8a2016-12-06 11:29:13 -0800243 @simple_layout('layouts/basic-github.yaml', driver='github')
244 def test_git_enterprise_url(self):
245 """Test that git_url option gives git url with proper host"""
246 url = self.fake_github_ent.real_getGitUrl('org/project')
247 self.assertEqual('ssh://git@github.enterprise.io/org/project.git', url)
248
Jan Hrubane252a732017-01-03 15:03:09 +0100249 @simple_layout('layouts/reporting-github.yaml', driver='github')
250 def test_reporting(self):
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700251 project = 'org/project'
Jan Hrubane252a732017-01-03 15:03:09 +0100252 # pipeline reports pull status both on start and success
253 self.executor_server.hold_jobs_in_build = True
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700254 A = self.fake_github.openFakePullRequest(project, 'master', 'A')
Jan Hruban37615e52015-11-19 14:30:49 +0100255 self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
Jan Hrubane252a732017-01-03 15:03:09 +0100256 self.waitUntilSettled()
Jesse Keatingd96e5882017-01-19 13:55:50 -0800257 # We should have a status container for the head sha
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700258 statuses = self.fake_github.statuses[project][A.head_sha]
259 self.assertIn(A.head_sha, self.fake_github.statuses[project].keys())
Jesse Keatingd96e5882017-01-19 13:55:50 -0800260 # We should only have one status for the head sha
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700261 self.assertEqual(1, len(statuses))
262 check_status = statuses[0]
Jan Hrubanddeb95a2017-01-03 15:12:41 +0100263 check_url = ('http://zuul.example.com/status/#%s,%s' %
264 (A.number, A.head_sha))
Jamie Lennox18bc7ed2017-05-10 10:37:55 +1000265 self.assertEqual('tenant-one/check', check_status['context'])
Jan Hrubane252a732017-01-03 15:03:09 +0100266 self.assertEqual('Standard check', check_status['description'])
267 self.assertEqual('pending', check_status['state'])
Jan Hrubanddeb95a2017-01-03 15:12:41 +0100268 self.assertEqual(check_url, check_status['url'])
Jan Hruban37615e52015-11-19 14:30:49 +0100269 self.assertEqual(0, len(A.comments))
Jan Hrubane252a732017-01-03 15:03:09 +0100270
271 self.executor_server.hold_jobs_in_build = False
272 self.executor_server.release()
273 self.waitUntilSettled()
Jesse Keatingd96e5882017-01-19 13:55:50 -0800274 # We should only have two statuses for the head sha
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700275 statuses = self.fake_github.statuses[project][A.head_sha]
276 self.assertEqual(2, len(statuses))
277 check_status = statuses[0]
Jesse Keatingd96e5882017-01-19 13:55:50 -0800278 check_url = ('http://zuul.example.com/status/#%s,%s' %
279 (A.number, A.head_sha))
Jamie Lennox18bc7ed2017-05-10 10:37:55 +1000280 self.assertEqual('tenant-one/check', check_status['context'])
Jan Hrubane252a732017-01-03 15:03:09 +0100281 self.assertEqual('success', check_status['state'])
Jan Hrubanddeb95a2017-01-03 15:12:41 +0100282 self.assertEqual(check_url, check_status['url'])
Jan Hruban37615e52015-11-19 14:30:49 +0100283 self.assertEqual(1, len(A.comments))
284 self.assertThat(A.comments[0],
Jan Hrubane252a732017-01-03 15:03:09 +0100285 MatchesRegex('.*Build succeeded.*', re.DOTALL))
286
287 # pipeline does not report any status but does comment
288 self.executor_server.hold_jobs_in_build = True
289 self.fake_github.emitEvent(
Jan Hruban37615e52015-11-19 14:30:49 +0100290 A.getCommentAddedEvent('reporting check'))
Jan Hrubane252a732017-01-03 15:03:09 +0100291 self.waitUntilSettled()
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700292 statuses = self.fake_github.statuses[project][A.head_sha]
293 self.assertEqual(2, len(statuses))
Jan Hrubane252a732017-01-03 15:03:09 +0100294 # comments increased by one for the start message
Jan Hruban37615e52015-11-19 14:30:49 +0100295 self.assertEqual(2, len(A.comments))
296 self.assertThat(A.comments[1],
Jan Hrubane252a732017-01-03 15:03:09 +0100297 MatchesRegex('.*Starting reporting jobs.*', re.DOTALL))
298 self.executor_server.hold_jobs_in_build = False
299 self.executor_server.release()
300 self.waitUntilSettled()
Jesse Keatingd96e5882017-01-19 13:55:50 -0800301 # pipeline reports success status
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700302 statuses = self.fake_github.statuses[project][A.head_sha]
303 self.assertEqual(3, len(statuses))
304 report_status = statuses[0]
Jamie Lennox18bc7ed2017-05-10 10:37:55 +1000305 self.assertEqual('tenant-one/reporting', report_status['context'])
Jesse Keatingd96e5882017-01-19 13:55:50 -0800306 self.assertEqual('success', report_status['state'])
Jan Hruban37615e52015-11-19 14:30:49 +0100307 self.assertEqual(2, len(A.comments))
Jamie Lennox3f16de52017-05-09 14:24:11 +1000308
309 base = 'http://logs.example.com/tenant-one/reporting/%s/%s/' % (
310 A.project, A.number)
311
312 # Deconstructing the URL because we don't save the BuildSet UUID
313 # anywhere to do a direct comparison and doing regexp matches on a full
314 # URL is painful.
315
316 # The first part of the URL matches the easy base string
317 self.assertThat(report_status['url'], StartsWith(base))
318
319 # The rest of the URL is a UUID and a trailing slash.
320 self.assertThat(report_status['url'][len(base):],
321 MatchesRegex('^[a-fA-F0-9]{32}\/$'))
Jan Hruban49bff072015-11-03 11:45:46 +0100322
323 @simple_layout('layouts/merging-github.yaml', driver='github')
324 def test_report_pull_merge(self):
325 # pipeline merges the pull request on success
Jan Hruban3b415922016-02-03 13:10:22 +0100326 A = self.fake_github.openFakePullRequest('org/project', 'master',
327 'PR title')
Jan Hruban49bff072015-11-03 11:45:46 +0100328 self.fake_github.emitEvent(A.getCommentAddedEvent('merge me'))
329 self.waitUntilSettled()
330 self.assertTrue(A.is_merged)
Jan Hruban3b415922016-02-03 13:10:22 +0100331 self.assertThat(A.merge_message,
332 MatchesRegex('.*PR title.*Reviewed-by.*', re.DOTALL))
Jan Hruban49bff072015-11-03 11:45:46 +0100333
334 # pipeline merges the pull request on success after failure
335 self.fake_github.merge_failure = True
Jan Hruban37615e52015-11-19 14:30:49 +0100336 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
Jan Hruban49bff072015-11-03 11:45:46 +0100337 self.fake_github.emitEvent(B.getCommentAddedEvent('merge me'))
338 self.waitUntilSettled()
339 self.assertFalse(B.is_merged)
340 self.fake_github.merge_failure = False
341
342 # pipeline merges the pull request on second run of merge
343 # first merge failed on 405 Method Not Allowed error
344 self.fake_github.merge_not_allowed_count = 1
Jan Hruban37615e52015-11-19 14:30:49 +0100345 C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
Jan Hruban49bff072015-11-03 11:45:46 +0100346 self.fake_github.emitEvent(C.getCommentAddedEvent('merge me'))
347 self.waitUntilSettled()
348 self.assertTrue(C.is_merged)
349
350 # pipeline does not merge the pull request
351 # merge failed on 405 Method Not Allowed error - twice
352 self.fake_github.merge_not_allowed_count = 2
Jan Hruban37615e52015-11-19 14:30:49 +0100353 D = self.fake_github.openFakePullRequest('org/project', 'master', 'D')
Jan Hruban49bff072015-11-03 11:45:46 +0100354 self.fake_github.emitEvent(D.getCommentAddedEvent('merge me'))
355 self.waitUntilSettled()
356 self.assertFalse(D.is_merged)
Adam Gandelman62198cb2017-02-14 16:11:02 -0800357 self.assertEqual(len(D.comments), 1)
358 self.assertEqual(D.comments[0], 'Merge failed')
Jan Hruban37615e52015-11-19 14:30:49 +0100359
360 @simple_layout('layouts/dependent-github.yaml', driver='github')
361 def test_parallel_changes(self):
362 "Test that changes are tested in parallel and merged in series"
363
364 self.executor_server.hold_jobs_in_build = True
365 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
366 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
367 C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
368
369 self.fake_github.emitEvent(A.addLabel('merge'))
370 self.fake_github.emitEvent(B.addLabel('merge'))
371 self.fake_github.emitEvent(C.addLabel('merge'))
372
373 self.waitUntilSettled()
374 self.assertEqual(len(self.builds), 1)
375 self.assertEqual(self.builds[0].name, 'project-merge')
376 self.assertTrue(self.builds[0].hasChanges(A))
377
378 self.executor_server.release('.*-merge')
379 self.waitUntilSettled()
380 self.assertEqual(len(self.builds), 3)
381 self.assertEqual(self.builds[0].name, 'project-test1')
382 self.assertTrue(self.builds[0].hasChanges(A))
383 self.assertEqual(self.builds[1].name, 'project-test2')
384 self.assertTrue(self.builds[1].hasChanges(A))
385 self.assertEqual(self.builds[2].name, 'project-merge')
386 self.assertTrue(self.builds[2].hasChanges(A, B))
387
388 self.executor_server.release('.*-merge')
389 self.waitUntilSettled()
390 self.assertEqual(len(self.builds), 5)
391 self.assertEqual(self.builds[0].name, 'project-test1')
392 self.assertTrue(self.builds[0].hasChanges(A))
393 self.assertEqual(self.builds[1].name, 'project-test2')
394 self.assertTrue(self.builds[1].hasChanges(A))
395
396 self.assertEqual(self.builds[2].name, 'project-test1')
397 self.assertTrue(self.builds[2].hasChanges(A))
398 self.assertEqual(self.builds[3].name, 'project-test2')
399 self.assertTrue(self.builds[3].hasChanges(A, B))
400
401 self.assertEqual(self.builds[4].name, 'project-merge')
402 self.assertTrue(self.builds[4].hasChanges(A, B, C))
403
404 self.executor_server.release('.*-merge')
405 self.waitUntilSettled()
406 self.assertEqual(len(self.builds), 6)
407 self.assertEqual(self.builds[0].name, 'project-test1')
408 self.assertTrue(self.builds[0].hasChanges(A))
409 self.assertEqual(self.builds[1].name, 'project-test2')
410 self.assertTrue(self.builds[1].hasChanges(A))
411
412 self.assertEqual(self.builds[2].name, 'project-test1')
413 self.assertTrue(self.builds[2].hasChanges(A, B))
414 self.assertEqual(self.builds[3].name, 'project-test2')
415 self.assertTrue(self.builds[3].hasChanges(A, B))
416
417 self.assertEqual(self.builds[4].name, 'project-test1')
418 self.assertTrue(self.builds[4].hasChanges(A, B, C))
419 self.assertEqual(self.builds[5].name, 'project-test2')
420 self.assertTrue(self.builds[5].hasChanges(A, B, C))
421
422 all_builds = self.builds[:]
423 self.release(all_builds[2])
424 self.release(all_builds[3])
425 self.waitUntilSettled()
426 self.assertFalse(A.is_merged)
427 self.assertFalse(B.is_merged)
428 self.assertFalse(C.is_merged)
429
430 self.release(all_builds[0])
431 self.release(all_builds[1])
432 self.waitUntilSettled()
433 self.assertTrue(A.is_merged)
434 self.assertTrue(B.is_merged)
435 self.assertFalse(C.is_merged)
436
437 self.executor_server.hold_jobs_in_build = False
438 self.executor_server.release()
439 self.waitUntilSettled()
440 self.assertEqual(len(self.builds), 0)
441 self.assertEqual(len(self.history), 9)
442 self.assertTrue(C.is_merged)
443
444 self.assertNotIn('merge', A.labels)
445 self.assertNotIn('merge', B.labels)
446 self.assertNotIn('merge', C.labels)
447
448 @simple_layout('layouts/dependent-github.yaml', driver='github')
449 def test_failed_changes(self):
450 "Test that a change behind a failed change is retested"
451 self.executor_server.hold_jobs_in_build = True
452
453 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
454 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
455
456 self.executor_server.failJob('project-test1', A)
457
458 self.fake_github.emitEvent(A.addLabel('merge'))
459 self.fake_github.emitEvent(B.addLabel('merge'))
460 self.waitUntilSettled()
461
462 self.executor_server.release('.*-merge')
463 self.waitUntilSettled()
464
465 self.executor_server.hold_jobs_in_build = False
466 self.executor_server.release()
467
468 self.waitUntilSettled()
469 # It's certain that the merge job for change 2 will run, but
470 # the test1 and test2 jobs may or may not run.
471 self.assertTrue(len(self.history) > 6)
472 self.assertFalse(A.is_merged)
473 self.assertTrue(B.is_merged)
474 self.assertNotIn('merge', A.labels)
475 self.assertNotIn('merge', B.labels)
476
477 @simple_layout('layouts/dependent-github.yaml', driver='github')
478 def test_failed_change_at_head(self):
479 "Test that if a change at the head fails, jobs behind it are canceled"
480
481 self.executor_server.hold_jobs_in_build = True
482 A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
483 B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
484 C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
485
486 self.executor_server.failJob('project-test1', A)
487
488 self.fake_github.emitEvent(A.addLabel('merge'))
489 self.fake_github.emitEvent(B.addLabel('merge'))
490 self.fake_github.emitEvent(C.addLabel('merge'))
491
492 self.waitUntilSettled()
493
494 self.assertEqual(len(self.builds), 1)
495 self.assertEqual(self.builds[0].name, 'project-merge')
496 self.assertTrue(self.builds[0].hasChanges(A))
497
498 self.executor_server.release('.*-merge')
499 self.waitUntilSettled()
500 self.executor_server.release('.*-merge')
501 self.waitUntilSettled()
502 self.executor_server.release('.*-merge')
503 self.waitUntilSettled()
504
505 self.assertEqual(len(self.builds), 6)
506 self.assertEqual(self.builds[0].name, 'project-test1')
507 self.assertEqual(self.builds[1].name, 'project-test2')
508 self.assertEqual(self.builds[2].name, 'project-test1')
509 self.assertEqual(self.builds[3].name, 'project-test2')
510 self.assertEqual(self.builds[4].name, 'project-test1')
511 self.assertEqual(self.builds[5].name, 'project-test2')
512
513 self.release(self.builds[0])
514 self.waitUntilSettled()
515
516 # project-test2, project-merge for B
517 self.assertEqual(len(self.builds), 2)
518 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
519
520 self.executor_server.hold_jobs_in_build = False
521 self.executor_server.release()
522 self.waitUntilSettled()
523
524 self.assertEqual(len(self.builds), 0)
525 self.assertEqual(len(self.history), 15)
526 self.assertFalse(A.is_merged)
527 self.assertTrue(B.is_merged)
528 self.assertTrue(C.is_merged)
529 self.assertNotIn('merge', A.labels)
530 self.assertNotIn('merge', B.labels)
531 self.assertNotIn('merge', C.labels)
Jesse Keating71a47ff2017-06-06 11:36:43 -0700532
533 @simple_layout('layouts/basic-github.yaml', driver='github')
534 def test_push_event_reconfigure(self):
535 pevent = self.fake_github.getPushEvent(project='common-config',
536 ref='refs/heads/master',
537 modified_files=['zuul.yaml'])
538
539 # record previous tenant reconfiguration time, which may not be set
540 old = self.sched.tenant_last_reconfigured.get('tenant-one', 0)
541 time.sleep(1)
542 self.fake_github.emitEvent(pevent)
543 self.waitUntilSettled()
544 new = self.sched.tenant_last_reconfigured.get('tenant-one', 0)
545 # New timestamp should be greater than the old timestamp
546 self.assertLess(old, new)