blob: 43bdfc2622b005e0e2c3d1572cac08397f0a83da [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
243 for i in range(1, 4):
244 submitted_at = time.time() - 72 * 60 * 60
245 A.addReview('derp', 'CHANGES_REQUESTED',
246 submitted_at)
247 self.fake_github.emitEvent(comment)
248 self.waitUntilSettled()
249 self.assertEqual(len(self.history), 0)
250
251 # A positive review from derp should cause it to be enqueued
252 A.addReview('derp', 'APPROVED')
253 self.fake_github.emitEvent(comment)
254 self.waitUntilSettled()
255 self.assertEqual(len(self.history), 1)
256 self.assertEqual(self.history[0].name, 'project5-reviewuserstate')
257
258 @simple_layout('layouts/requirements-github.yaml', driver='github')
259 def test_require_review_newer_than(self):
260
261 A = self.fake_github.openFakePullRequest('org/project6', 'master', 'A')
262 # Add derp and herp to writers
263 A.writers.extend(('derp', 'herp'))
264 # A comment event that we will keep submitting to trigger
265 comment = A.getCommentAddedEvent('test me')
266 self.fake_github.emitEvent(comment)
267 self.waitUntilSettled()
268 # No positive review from derp so should not be enqueued
269 self.assertEqual(len(self.history), 0)
270
271 # Add a too-old positive review, should not be enqueued
272 submitted_at = time.time() - 72 * 60 * 60
273 A.addReview('derp', 'APPROVED',
274 submitted_at)
275 self.fake_github.emitEvent(comment)
276 self.waitUntilSettled()
277 self.assertEqual(len(self.history), 0)
278
279 # Add a recent positive review
280 submitted_at = time.time() - 12 * 60 * 60
281 A.addReview('derp', 'APPROVED', submitted_at)
282 self.fake_github.emitEvent(comment)
283 self.waitUntilSettled()
284 self.assertEqual(len(self.history), 1)
285 self.assertEqual(self.history[0].name, 'project6-newerthan')
286
287 @simple_layout('layouts/requirements-github.yaml', driver='github')
288 def test_require_review_older_than(self):
289
290 A = self.fake_github.openFakePullRequest('org/project7', 'master', 'A')
291 # Add derp and herp to writers
292 A.writers.extend(('derp', 'herp'))
293 # A comment event that we will keep submitting to trigger
294 comment = A.getCommentAddedEvent('test me')
295 self.fake_github.emitEvent(comment)
296 self.waitUntilSettled()
297 # No positive review from derp so should not be enqueued
298 self.assertEqual(len(self.history), 0)
299
300 # Add a too-new positive, should not be enqueued
301 submitted_at = time.time() - 12 * 60 * 60
302 A.addReview('derp', 'APPROVED',
303 submitted_at)
304 self.fake_github.emitEvent(comment)
305 self.waitUntilSettled()
306 self.assertEqual(len(self.history), 0)
307
308 # Add an old enough positive, should enqueue
309 submitted_at = time.time() - 72 * 60 * 60
310 A.addReview('herp', 'APPROVED', submitted_at)
311 self.fake_github.emitEvent(comment)
312 self.waitUntilSettled()
313 self.assertEqual(len(self.history), 1)
314 self.assertEqual(self.history[0].name, 'project7-olderthan')
Jesse Keating4a27f132017-05-25 16:44:01 -0700315
316 @simple_layout('layouts/requirements-github.yaml', driver='github')
317 def test_require_open(self):
318
319 A = self.fake_github.openFakePullRequest('org/project8', 'master', 'A')
320 # A comment event that we will keep submitting to trigger
321 comment = A.getCommentAddedEvent('test me')
322 self.fake_github.emitEvent(comment)
323 self.waitUntilSettled()
324
325 # PR is open, we should have enqueued
326 self.assertEqual(len(self.history), 1)
327
328 # close the PR and try again
329 A.state = 'closed'
330 self.fake_github.emitEvent(comment)
331 self.waitUntilSettled()
332 # PR is closed, should not trigger
333 self.assertEqual(len(self.history), 1)
Jesse Keating0d40c122017-05-26 11:32:53 -0700334
335 @simple_layout('layouts/requirements-github.yaml', driver='github')
336 def test_require_current(self):
337
338 A = self.fake_github.openFakePullRequest('org/project9', 'master', 'A')
339 # A sync event that we will keep submitting to trigger
340 sync = A.getPullRequestSynchronizeEvent()
341 self.fake_github.emitEvent(sync)
342 self.waitUntilSettled()
343
344 # PR head is current should enqueue
345 self.assertEqual(len(self.history), 1)
346
347 # Add a commit to the PR, re-issue the original comment event
348 A.addCommit()
349 self.fake_github.emitEvent(sync)
350 self.waitUntilSettled()
351 # Event hash is not current, should not trigger
352 self.assertEqual(len(self.history), 1)