blob: f125d1e4ac7864c3903e8f69e29583a07bf9a004 [file] [log] [blame]
Jesse Keatingd96e5882017-01-19 13:55:50 -08001#!/usr/bin/env python
2# Copyright (c) 2017 IBM Corp.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
Adam Gandelmand81dd762017-02-09 15:15:49 -080016import time
17
Jesse Keatingd96e5882017-01-19 13:55:50 -080018from tests.base import ZuulTestCase, simple_layout
19
20
21class TestGithubRequirements(ZuulTestCase):
22 """Test pipeline and trigger requirements"""
23 config_file = 'zuul-github-driver.conf'
24
25 @simple_layout('layouts/requirements-github.yaml', driver='github')
26 def test_pipeline_require_status(self):
27 "Test pipeline requirement: status"
Jesse Keating1f7ebe92017-06-12 17:21:00 -070028 project = 'org/project1'
29 A = self.fake_github.openFakePullRequest(project, 'master', 'A')
Jesse Keatingd96e5882017-01-19 13:55:50 -080030 # A comment event that we will keep submitting to trigger
31 comment = A.getCommentAddedEvent('test me')
32 self.fake_github.emitEvent(comment)
33 self.waitUntilSettled()
34 # No status from zuul so should not be enqueued
35 self.assertEqual(len(self.history), 0)
36
37 # An error status should not cause it to be enqueued
Jesse Keating1f7ebe92017-06-12 17:21:00 -070038 self.fake_github.setCommitStatus(project, A.head_sha, 'error',
39 context='check')
Jesse Keatingd96e5882017-01-19 13:55:50 -080040 self.fake_github.emitEvent(comment)
41 self.waitUntilSettled()
42 self.assertEqual(len(self.history), 0)
43
44 # A success status goes in
Jesse Keating1f7ebe92017-06-12 17:21:00 -070045 self.fake_github.setCommitStatus(project, A.head_sha, 'success',
46 context='check')
Jesse Keatingd96e5882017-01-19 13:55:50 -080047 self.fake_github.emitEvent(comment)
48 self.waitUntilSettled()
49 self.assertEqual(len(self.history), 1)
50 self.assertEqual(self.history[0].name, 'project1-pipeline')
Adam Gandelman8c6eeb52017-01-23 16:31:06 -080051
52 @simple_layout('layouts/requirements-github.yaml', driver='github')
53 def test_trigger_require_status(self):
54 "Test trigger requirement: status"
Jesse Keating1f7ebe92017-06-12 17:21:00 -070055 project = 'org/project1'
56 A = self.fake_github.openFakePullRequest(project, 'master', 'A')
Jesse Keating3a00ae82017-05-04 16:08:58 -070057 # A comment event that we will keep submitting to trigger
58 comment = A.getCommentAddedEvent('trigger me')
59 self.fake_github.emitEvent(comment)
60 self.waitUntilSettled()
61 # No status from zuul so should not be enqueued
62 self.assertEqual(len(self.history), 0)
63
64 # An error status should not cause it to be enqueued
Jesse Keating1f7ebe92017-06-12 17:21:00 -070065 self.fake_github.setCommitStatus(project, A.head_sha, 'error',
66 context='check')
Jesse Keating3a00ae82017-05-04 16:08:58 -070067 self.fake_github.emitEvent(comment)
68 self.waitUntilSettled()
69 self.assertEqual(len(self.history), 0)
70
71 # A success status goes in
Jesse Keating1f7ebe92017-06-12 17:21:00 -070072 self.fake_github.setCommitStatus(project, A.head_sha, 'success',
73 context='check')
Jesse Keating3a00ae82017-05-04 16:08:58 -070074 self.fake_github.emitEvent(comment)
75 self.waitUntilSettled()
76 self.assertEqual(len(self.history), 1)
77 self.assertEqual(self.history[0].name, 'project1-pipeline')
78
79 @simple_layout('layouts/requirements-github.yaml', driver='github')
80 def test_trigger_on_status(self):
81 "Test trigger on: status"
Jesse Keating1f7ebe92017-06-12 17:21:00 -070082 project = 'org/project2'
83 A = self.fake_github.openFakePullRequest(project, 'master', 'A')
Adam Gandelman8c6eeb52017-01-23 16:31:06 -080084
85 # An error status should not cause it to be enqueued
Jesse Keating1f7ebe92017-06-12 17:21:00 -070086 self.fake_github.setCommitStatus(project, A.head_sha, 'error',
87 context='check')
Adam Gandelman8c6eeb52017-01-23 16:31:06 -080088 self.fake_github.emitEvent(A.getCommitStatusEvent('check',
89 state='error'))
90 self.waitUntilSettled()
91 self.assertEqual(len(self.history), 0)
92
Jesse Keatingae4cd272017-01-30 17:10:44 -080093 # A success status from unknown user should not cause it to be
Adam Gandelman8c6eeb52017-01-23 16:31:06 -080094 # enqueued
Jesse Keating1f7ebe92017-06-12 17:21:00 -070095 self.fake_github.setCommitStatus(project, A.head_sha, 'success',
96 context='check', user='foo')
Adam Gandelman8c6eeb52017-01-23 16:31:06 -080097 self.fake_github.emitEvent(A.getCommitStatusEvent('check',
98 state='success',
99 user='foo'))
100 self.waitUntilSettled()
101 self.assertEqual(len(self.history), 0)
102
Jesse Keatingae4cd272017-01-30 17:10:44 -0800103 # A success status from zuul goes in
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700104 self.fake_github.setCommitStatus(project, A.head_sha, 'success',
105 context='check')
Adam Gandelman8c6eeb52017-01-23 16:31:06 -0800106 self.fake_github.emitEvent(A.getCommitStatusEvent('check'))
107 self.waitUntilSettled()
108 self.assertEqual(len(self.history), 1)
109 self.assertEqual(self.history[0].name, 'project2-trigger')
110
111 # An error status for a different context should not cause it to be
112 # enqueued
Jesse Keating1f7ebe92017-06-12 17:21:00 -0700113 self.fake_github.setCommitStatus(project, A.head_sha, 'error',
114 context='gate')
Adam Gandelman8c6eeb52017-01-23 16:31:06 -0800115 self.fake_github.emitEvent(A.getCommitStatusEvent('gate',
116 state='error'))
117 self.waitUntilSettled()
118 self.assertEqual(len(self.history), 1)
Jesse Keatingae4cd272017-01-30 17:10:44 -0800119
120 @simple_layout('layouts/requirements-github.yaml', driver='github')
121 def test_pipeline_require_review_username(self):
122 "Test pipeline requirement: review username"
123
124 A = self.fake_github.openFakePullRequest('org/project3', 'master', 'A')
125 # A comment event that we will keep submitting to trigger
126 comment = A.getCommentAddedEvent('test me')
127 self.fake_github.emitEvent(comment)
128 self.waitUntilSettled()
129 # No approval from derp so should not be enqueued
130 self.assertEqual(len(self.history), 0)
131
132 # Add an approved review from derp
133 A.addReview('derp', 'APPROVED')
134 self.fake_github.emitEvent(comment)
135 self.waitUntilSettled()
136 self.assertEqual(len(self.history), 1)
137 self.assertEqual(self.history[0].name, 'project3-reviewusername')
138
139 @simple_layout('layouts/requirements-github.yaml', driver='github')
140 def test_pipeline_require_review_state(self):
141 "Test pipeline requirement: review state"
142
143 A = self.fake_github.openFakePullRequest('org/project4', 'master', 'A')
144 # Add derp to writers
Jesse Keatingfd2a0ad2017-06-13 15:54:11 -0700145 A.writers.extend(('derp', 'werp'))
Jesse Keatingae4cd272017-01-30 17:10:44 -0800146 # A comment event that we will keep submitting to trigger
147 comment = A.getCommentAddedEvent('test me')
148 self.fake_github.emitEvent(comment)
149 self.waitUntilSettled()
150 # No positive review from derp so should not be enqueued
151 self.assertEqual(len(self.history), 0)
152
153 # A negative review from derp should not cause it to be enqueued
154 A.addReview('derp', 'CHANGES_REQUESTED')
155 self.fake_github.emitEvent(comment)
156 self.waitUntilSettled()
157 self.assertEqual(len(self.history), 0)
158
Jesse Keatingfd2a0ad2017-06-13 15:54:11 -0700159 # A negative review from werp should not cause it to be enqueued
160 A.addReview('werp', 'CHANGES_REQUESTED')
161 self.fake_github.emitEvent(comment)
162 self.waitUntilSettled()
163 self.assertEqual(len(self.history), 0)
164
Jesse Keatingae4cd272017-01-30 17:10:44 -0800165 # A positive from nobody should not cause it to be enqueued
166 A.addReview('nobody', 'APPROVED')
167 self.fake_github.emitEvent(comment)
168 self.waitUntilSettled()
169 self.assertEqual(len(self.history), 0)
170
Jesse Keatingfd2a0ad2017-06-13 15:54:11 -0700171 # A positive review from derp should still be blocked by the
172 # negative review from werp
Jesse Keatingae4cd272017-01-30 17:10:44 -0800173 A.addReview('derp', 'APPROVED')
174 self.fake_github.emitEvent(comment)
175 self.waitUntilSettled()
Jesse Keatingfd2a0ad2017-06-13 15:54:11 -0700176 self.assertEqual(len(self.history), 0)
177
178 # A positive review from werp should cause it to be enqueued
179 A.addReview('werp', 'APPROVED')
180 self.fake_github.emitEvent(comment)
181 self.waitUntilSettled()
Jesse Keatingae4cd272017-01-30 17:10:44 -0800182 self.assertEqual(len(self.history), 1)
183 self.assertEqual(self.history[0].name, 'project4-reviewreq')
184
185 @simple_layout('layouts/requirements-github.yaml', driver='github')
186 def test_pipeline_require_review_user_state(self):
187 "Test pipeline requirement: review state from user"
188
189 A = self.fake_github.openFakePullRequest('org/project5', 'master', 'A')
190 # Add derp and herp to writers
191 A.writers.extend(('derp', 'herp'))
192 # A comment event that we will keep submitting to trigger
193 comment = A.getCommentAddedEvent('test me')
194 self.fake_github.emitEvent(comment)
195 self.waitUntilSettled()
196 # No positive review from derp so should not be enqueued
197 self.assertEqual(len(self.history), 0)
198
199 # A negative review from derp should not cause it to be enqueued
200 A.addReview('derp', 'CHANGES_REQUESTED')
201 self.fake_github.emitEvent(comment)
202 self.waitUntilSettled()
203 self.assertEqual(len(self.history), 0)
204
205 # A positive from nobody should not cause it to be enqueued
206 A.addReview('nobody', 'APPROVED')
207 self.fake_github.emitEvent(comment)
208 self.waitUntilSettled()
209 self.assertEqual(len(self.history), 0)
210
211 # A positive review from herp (a writer) should not cause it to be
212 # enqueued
213 A.addReview('herp', 'APPROVED')
214 self.fake_github.emitEvent(comment)
215 self.waitUntilSettled()
216 self.assertEqual(len(self.history), 0)
217
218 # A positive review from derp should cause it to be enqueued
219 A.addReview('derp', 'APPROVED')
220 self.fake_github.emitEvent(comment)
221 self.waitUntilSettled()
222 self.assertEqual(len(self.history), 1)
223 self.assertEqual(self.history[0].name, 'project5-reviewuserstate')
Adam Gandelmand81dd762017-02-09 15:15:49 -0800224
225# TODO: Implement reject on approval username/state
226
227 @simple_layout('layouts/requirements-github.yaml', driver='github')
228 def test_pipeline_require_review_latest_user_state(self):
229 "Test pipeline requirement: review state from user"
230
231 A = self.fake_github.openFakePullRequest('org/project5', 'master', 'A')
232 # Add derp and herp to writers
233 A.writers.extend(('derp', 'herp'))
234 # A comment event that we will keep submitting to trigger
235 comment = A.getCommentAddedEvent('test me')
236 self.fake_github.emitEvent(comment)
237 self.waitUntilSettled()
238 # No positive review from derp so should not be enqueued
239 self.assertEqual(len(self.history), 0)
240
241 # The first negative review from derp should not cause it to be
242 # enqueued
Jesse Keating3e785722017-07-06 15:59:03 -0700243 A.addReview('derp', 'CHANGES_REQUESTED')
244 self.fake_github.emitEvent(comment)
245 self.waitUntilSettled()
246 self.assertEqual(len(self.history), 0)
Adam Gandelmand81dd762017-02-09 15:15:49 -0800247
248 # A positive review from derp should cause it to be enqueued
249 A.addReview('derp', 'APPROVED')
250 self.fake_github.emitEvent(comment)
251 self.waitUntilSettled()
252 self.assertEqual(len(self.history), 1)
253 self.assertEqual(self.history[0].name, 'project5-reviewuserstate')
254
255 @simple_layout('layouts/requirements-github.yaml', driver='github')
Jesse Keating3f74f6f2017-07-06 15:45:36 -0700256 def test_pipeline_require_review_comment_masked(self):
257 "Test pipeline requirement: review comments on top of votes"
258
259 A = self.fake_github.openFakePullRequest('org/project5', 'master', 'A')
260 # Add derp to writers
261 A.writers.append('derp')
262 # A comment event that we will keep submitting to trigger
263 comment = A.getCommentAddedEvent('test me')
264 self.fake_github.emitEvent(comment)
265 self.waitUntilSettled()
266 # No positive review from derp so should not be enqueued
267 self.assertEqual(len(self.history), 0)
268
269 # The first negative review from derp should not cause it to be
270 # enqueued
271 A.addReview('derp', 'CHANGES_REQUESTED')
272 self.fake_github.emitEvent(comment)
273 self.waitUntilSettled()
274 self.assertEqual(len(self.history), 0)
275
276 # A positive review is required, so provide it
277 A.addReview('derp', 'APPROVED')
278
279 # Add a comment review on top to make sure we can still enqueue
280 A.addReview('derp', 'COMMENTED')
281 self.fake_github.emitEvent(comment)
282 self.waitUntilSettled()
283 self.assertEqual(len(self.history), 1)
284 self.assertEqual(self.history[0].name, 'project5-reviewuserstate')
285
286 @simple_layout('layouts/requirements-github.yaml', driver='github')
Adam Gandelmand81dd762017-02-09 15:15:49 -0800287 def test_require_review_newer_than(self):
288
289 A = self.fake_github.openFakePullRequest('org/project6', 'master', 'A')
290 # Add derp and herp to writers
291 A.writers.extend(('derp', 'herp'))
292 # A comment event that we will keep submitting to trigger
293 comment = A.getCommentAddedEvent('test me')
294 self.fake_github.emitEvent(comment)
295 self.waitUntilSettled()
296 # No positive review from derp so should not be enqueued
297 self.assertEqual(len(self.history), 0)
298
299 # Add a too-old positive review, should not be enqueued
300 submitted_at = time.time() - 72 * 60 * 60
301 A.addReview('derp', 'APPROVED',
302 submitted_at)
303 self.fake_github.emitEvent(comment)
304 self.waitUntilSettled()
305 self.assertEqual(len(self.history), 0)
306
307 # Add a recent positive review
308 submitted_at = time.time() - 12 * 60 * 60
309 A.addReview('derp', 'APPROVED', submitted_at)
310 self.fake_github.emitEvent(comment)
311 self.waitUntilSettled()
312 self.assertEqual(len(self.history), 1)
313 self.assertEqual(self.history[0].name, 'project6-newerthan')
314
315 @simple_layout('layouts/requirements-github.yaml', driver='github')
316 def test_require_review_older_than(self):
317
318 A = self.fake_github.openFakePullRequest('org/project7', 'master', 'A')
319 # Add derp and herp to writers
320 A.writers.extend(('derp', 'herp'))
321 # A comment event that we will keep submitting to trigger
322 comment = A.getCommentAddedEvent('test me')
323 self.fake_github.emitEvent(comment)
324 self.waitUntilSettled()
325 # No positive review from derp so should not be enqueued
326 self.assertEqual(len(self.history), 0)
327
328 # Add a too-new positive, should not be enqueued
329 submitted_at = time.time() - 12 * 60 * 60
330 A.addReview('derp', 'APPROVED',
331 submitted_at)
332 self.fake_github.emitEvent(comment)
333 self.waitUntilSettled()
334 self.assertEqual(len(self.history), 0)
335
336 # Add an old enough positive, should enqueue
337 submitted_at = time.time() - 72 * 60 * 60
338 A.addReview('herp', 'APPROVED', submitted_at)
339 self.fake_github.emitEvent(comment)
340 self.waitUntilSettled()
341 self.assertEqual(len(self.history), 1)
342 self.assertEqual(self.history[0].name, 'project7-olderthan')
Jesse Keating4a27f132017-05-25 16:44:01 -0700343
344 @simple_layout('layouts/requirements-github.yaml', driver='github')
345 def test_require_open(self):
346
347 A = self.fake_github.openFakePullRequest('org/project8', 'master', 'A')
348 # A comment event that we will keep submitting to trigger
349 comment = A.getCommentAddedEvent('test me')
350 self.fake_github.emitEvent(comment)
351 self.waitUntilSettled()
352
353 # PR is open, we should have enqueued
354 self.assertEqual(len(self.history), 1)
355
356 # close the PR and try again
357 A.state = 'closed'
358 self.fake_github.emitEvent(comment)
359 self.waitUntilSettled()
360 # PR is closed, should not trigger
361 self.assertEqual(len(self.history), 1)
Jesse Keating0d40c122017-05-26 11:32:53 -0700362
363 @simple_layout('layouts/requirements-github.yaml', driver='github')
364 def test_require_current(self):
365
366 A = self.fake_github.openFakePullRequest('org/project9', 'master', 'A')
367 # A sync event that we will keep submitting to trigger
368 sync = A.getPullRequestSynchronizeEvent()
369 self.fake_github.emitEvent(sync)
370 self.waitUntilSettled()
371
372 # PR head is current should enqueue
373 self.assertEqual(len(self.history), 1)
374
375 # Add a commit to the PR, re-issue the original comment event
376 A.addCommit()
377 self.fake_github.emitEvent(sync)
378 self.waitUntilSettled()
379 # Event hash is not current, should not trigger
380 self.assertEqual(len(self.history), 1)
Jesse Keating19dfb492017-06-13 12:32:33 -0700381
382 @simple_layout('layouts/requirements-github.yaml', driver='github')
383 def test_pipeline_require_label(self):
384 "Test pipeline requirement: label"
385 A = self.fake_github.openFakePullRequest('org/project10', 'master',
386 'A')
387 # A comment event that we will keep submitting to trigger
388 comment = A.getCommentAddedEvent('test me')
389 self.fake_github.emitEvent(comment)
390 self.waitUntilSettled()
391 # No label so should not be enqueued
392 self.assertEqual(len(self.history), 0)
393
394 # A derp label should not cause it to be enqueued
395 A.addLabel('derp')
396 self.fake_github.emitEvent(comment)
397 self.waitUntilSettled()
398 self.assertEqual(len(self.history), 0)
399
400 # An approved label goes in
401 A.addLabel('approved')
402 self.fake_github.emitEvent(comment)
403 self.waitUntilSettled()
404 self.assertEqual(len(self.history), 1)
405 self.assertEqual(self.history[0].name, 'project10-label')