blob: 301ea2fbe3a99d955456ad5a4176f7cbc60816a2 [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
145 A.writers.append('derp')
146 # 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
159 # A positive from nobody should not cause it to be enqueued
160 A.addReview('nobody', 'APPROVED')
161 self.fake_github.emitEvent(comment)
162 self.waitUntilSettled()
163 self.assertEqual(len(self.history), 0)
164
165 # A positive review from derp should cause it to be enqueued
166 A.addReview('derp', 'APPROVED')
167 self.fake_github.emitEvent(comment)
168 self.waitUntilSettled()
169 self.assertEqual(len(self.history), 1)
170 self.assertEqual(self.history[0].name, 'project4-reviewreq')
171
172 @simple_layout('layouts/requirements-github.yaml', driver='github')
173 def test_pipeline_require_review_user_state(self):
174 "Test pipeline requirement: review state from user"
175
176 A = self.fake_github.openFakePullRequest('org/project5', 'master', 'A')
177 # Add derp and herp to writers
178 A.writers.extend(('derp', 'herp'))
179 # A comment event that we will keep submitting to trigger
180 comment = A.getCommentAddedEvent('test me')
181 self.fake_github.emitEvent(comment)
182 self.waitUntilSettled()
183 # No positive review from derp so should not be enqueued
184 self.assertEqual(len(self.history), 0)
185
186 # A negative review from derp should not cause it to be enqueued
187 A.addReview('derp', 'CHANGES_REQUESTED')
188 self.fake_github.emitEvent(comment)
189 self.waitUntilSettled()
190 self.assertEqual(len(self.history), 0)
191
192 # A positive from nobody should not cause it to be enqueued
193 A.addReview('nobody', 'APPROVED')
194 self.fake_github.emitEvent(comment)
195 self.waitUntilSettled()
196 self.assertEqual(len(self.history), 0)
197
198 # A positive review from herp (a writer) should not cause it to be
199 # enqueued
200 A.addReview('herp', 'APPROVED')
201 self.fake_github.emitEvent(comment)
202 self.waitUntilSettled()
203 self.assertEqual(len(self.history), 0)
204
205 # A positive review from derp should cause it to be enqueued
206 A.addReview('derp', 'APPROVED')
207 self.fake_github.emitEvent(comment)
208 self.waitUntilSettled()
209 self.assertEqual(len(self.history), 1)
210 self.assertEqual(self.history[0].name, 'project5-reviewuserstate')
Adam Gandelmand81dd762017-02-09 15:15:49 -0800211
212# TODO: Implement reject on approval username/state
213
214 @simple_layout('layouts/requirements-github.yaml', driver='github')
215 def test_pipeline_require_review_latest_user_state(self):
216 "Test pipeline requirement: review state from user"
217
218 A = self.fake_github.openFakePullRequest('org/project5', 'master', 'A')
219 # Add derp and herp to writers
220 A.writers.extend(('derp', 'herp'))
221 # A comment event that we will keep submitting to trigger
222 comment = A.getCommentAddedEvent('test me')
223 self.fake_github.emitEvent(comment)
224 self.waitUntilSettled()
225 # No positive review from derp so should not be enqueued
226 self.assertEqual(len(self.history), 0)
227
228 # The first negative review from derp should not cause it to be
229 # enqueued
230 for i in range(1, 4):
231 submitted_at = time.time() - 72 * 60 * 60
232 A.addReview('derp', 'CHANGES_REQUESTED',
233 submitted_at)
234 self.fake_github.emitEvent(comment)
235 self.waitUntilSettled()
236 self.assertEqual(len(self.history), 0)
237
238 # A positive review from derp should cause it to be enqueued
239 A.addReview('derp', 'APPROVED')
240 self.fake_github.emitEvent(comment)
241 self.waitUntilSettled()
242 self.assertEqual(len(self.history), 1)
243 self.assertEqual(self.history[0].name, 'project5-reviewuserstate')
244
245 @simple_layout('layouts/requirements-github.yaml', driver='github')
246 def test_require_review_newer_than(self):
247
248 A = self.fake_github.openFakePullRequest('org/project6', 'master', 'A')
249 # Add derp and herp to writers
250 A.writers.extend(('derp', 'herp'))
251 # A comment event that we will keep submitting to trigger
252 comment = A.getCommentAddedEvent('test me')
253 self.fake_github.emitEvent(comment)
254 self.waitUntilSettled()
255 # No positive review from derp so should not be enqueued
256 self.assertEqual(len(self.history), 0)
257
258 # Add a too-old positive review, should not be enqueued
259 submitted_at = time.time() - 72 * 60 * 60
260 A.addReview('derp', 'APPROVED',
261 submitted_at)
262 self.fake_github.emitEvent(comment)
263 self.waitUntilSettled()
264 self.assertEqual(len(self.history), 0)
265
266 # Add a recent positive review
267 submitted_at = time.time() - 12 * 60 * 60
268 A.addReview('derp', 'APPROVED', submitted_at)
269 self.fake_github.emitEvent(comment)
270 self.waitUntilSettled()
271 self.assertEqual(len(self.history), 1)
272 self.assertEqual(self.history[0].name, 'project6-newerthan')
273
274 @simple_layout('layouts/requirements-github.yaml', driver='github')
275 def test_require_review_older_than(self):
276
277 A = self.fake_github.openFakePullRequest('org/project7', 'master', 'A')
278 # Add derp and herp to writers
279 A.writers.extend(('derp', 'herp'))
280 # A comment event that we will keep submitting to trigger
281 comment = A.getCommentAddedEvent('test me')
282 self.fake_github.emitEvent(comment)
283 self.waitUntilSettled()
284 # No positive review from derp so should not be enqueued
285 self.assertEqual(len(self.history), 0)
286
287 # Add a too-new positive, should not be enqueued
288 submitted_at = time.time() - 12 * 60 * 60
289 A.addReview('derp', 'APPROVED',
290 submitted_at)
291 self.fake_github.emitEvent(comment)
292 self.waitUntilSettled()
293 self.assertEqual(len(self.history), 0)
294
295 # Add an old enough positive, should enqueue
296 submitted_at = time.time() - 72 * 60 * 60
297 A.addReview('herp', 'APPROVED', submitted_at)
298 self.fake_github.emitEvent(comment)
299 self.waitUntilSettled()
300 self.assertEqual(len(self.history), 1)
301 self.assertEqual(self.history[0].name, 'project7-olderthan')
Jesse Keating4a27f132017-05-25 16:44:01 -0700302
303 @simple_layout('layouts/requirements-github.yaml', driver='github')
304 def test_require_open(self):
305
306 A = self.fake_github.openFakePullRequest('org/project8', 'master', 'A')
307 # A comment event that we will keep submitting to trigger
308 comment = A.getCommentAddedEvent('test me')
309 self.fake_github.emitEvent(comment)
310 self.waitUntilSettled()
311
312 # PR is open, we should have enqueued
313 self.assertEqual(len(self.history), 1)
314
315 # close the PR and try again
316 A.state = 'closed'
317 self.fake_github.emitEvent(comment)
318 self.waitUntilSettled()
319 # PR is closed, should not trigger
320 self.assertEqual(len(self.history), 1)
Jesse Keating0d40c122017-05-26 11:32:53 -0700321
322 @simple_layout('layouts/requirements-github.yaml', driver='github')
323 def test_require_current(self):
324
325 A = self.fake_github.openFakePullRequest('org/project9', 'master', 'A')
326 # A sync event that we will keep submitting to trigger
327 sync = A.getPullRequestSynchronizeEvent()
328 self.fake_github.emitEvent(sync)
329 self.waitUntilSettled()
330
331 # PR head is current should enqueue
332 self.assertEqual(len(self.history), 1)
333
334 # Add a commit to the PR, re-issue the original comment event
335 A.addCommit()
336 self.fake_github.emitEvent(sync)
337 self.waitUntilSettled()
338 # Event hash is not current, should not trigger
339 self.assertEqual(len(self.history), 1)