blob: 5dd6e80e43886e5590d1ae91569d0de3146b28fd [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"
28 A = self.fake_github.openFakePullRequest('org/project1', 'master', 'A')
29 # A comment event that we will keep submitting to trigger
30 comment = A.getCommentAddedEvent('test me')
31 self.fake_github.emitEvent(comment)
32 self.waitUntilSettled()
33 # No status from zuul so should not be enqueued
34 self.assertEqual(len(self.history), 0)
35
36 # An error status should not cause it to be enqueued
37 A.setStatus(A.head_sha, 'error', 'null', 'null', 'check')
38 self.fake_github.emitEvent(comment)
39 self.waitUntilSettled()
40 self.assertEqual(len(self.history), 0)
41
42 # A success status goes in
43 A.setStatus(A.head_sha, 'success', 'null', 'null', 'check')
44 self.fake_github.emitEvent(comment)
45 self.waitUntilSettled()
46 self.assertEqual(len(self.history), 1)
47 self.assertEqual(self.history[0].name, 'project1-pipeline')
Adam Gandelman8c6eeb52017-01-23 16:31:06 -080048
49 @simple_layout('layouts/requirements-github.yaml', driver='github')
50 def test_trigger_require_status(self):
51 "Test trigger requirement: status"
Jesse Keating3a00ae82017-05-04 16:08:58 -070052 A = self.fake_github.openFakePullRequest('org/project1', 'master', 'A')
53 # A comment event that we will keep submitting to trigger
54 comment = A.getCommentAddedEvent('trigger me')
55 self.fake_github.emitEvent(comment)
56 self.waitUntilSettled()
57 # No status from zuul so should not be enqueued
58 self.assertEqual(len(self.history), 0)
59
60 # An error status should not cause it to be enqueued
61 A.setStatus(A.head_sha, 'error', 'null', 'null', 'check')
62 self.fake_github.emitEvent(comment)
63 self.waitUntilSettled()
64 self.assertEqual(len(self.history), 0)
65
66 # A success status goes in
67 A.setStatus(A.head_sha, 'success', 'null', 'null', 'check')
68 self.fake_github.emitEvent(comment)
69 self.waitUntilSettled()
70 self.assertEqual(len(self.history), 1)
71 self.assertEqual(self.history[0].name, 'project1-pipeline')
72
73 @simple_layout('layouts/requirements-github.yaml', driver='github')
74 def test_trigger_on_status(self):
75 "Test trigger on: status"
Adam Gandelman8c6eeb52017-01-23 16:31:06 -080076 A = self.fake_github.openFakePullRequest('org/project2', 'master', 'A')
77
78 # An error status should not cause it to be enqueued
79 A.setStatus(A.head_sha, 'error', 'null', 'null', 'check')
80 self.fake_github.emitEvent(A.getCommitStatusEvent('check',
81 state='error'))
82 self.waitUntilSettled()
83 self.assertEqual(len(self.history), 0)
84
Jesse Keatingae4cd272017-01-30 17:10:44 -080085 # A success status from unknown user should not cause it to be
Adam Gandelman8c6eeb52017-01-23 16:31:06 -080086 # enqueued
87 A.setStatus(A.head_sha, 'success', 'null', 'null', 'check', user='foo')
88 self.fake_github.emitEvent(A.getCommitStatusEvent('check',
89 state='success',
90 user='foo'))
91 self.waitUntilSettled()
92 self.assertEqual(len(self.history), 0)
93
Jesse Keatingae4cd272017-01-30 17:10:44 -080094 # A success status from zuul goes in
Adam Gandelman8c6eeb52017-01-23 16:31:06 -080095 A.setStatus(A.head_sha, 'success', 'null', 'null', 'check')
96 self.fake_github.emitEvent(A.getCommitStatusEvent('check'))
97 self.waitUntilSettled()
98 self.assertEqual(len(self.history), 1)
99 self.assertEqual(self.history[0].name, 'project2-trigger')
100
101 # An error status for a different context should not cause it to be
102 # enqueued
103 A.setStatus(A.head_sha, 'error', 'null', 'null', 'gate')
104 self.fake_github.emitEvent(A.getCommitStatusEvent('gate',
105 state='error'))
106 self.waitUntilSettled()
107 self.assertEqual(len(self.history), 1)
Jesse Keatingae4cd272017-01-30 17:10:44 -0800108
109 @simple_layout('layouts/requirements-github.yaml', driver='github')
110 def test_pipeline_require_review_username(self):
111 "Test pipeline requirement: review username"
112
113 A = self.fake_github.openFakePullRequest('org/project3', 'master', 'A')
114 # A comment event that we will keep submitting to trigger
115 comment = A.getCommentAddedEvent('test me')
116 self.fake_github.emitEvent(comment)
117 self.waitUntilSettled()
118 # No approval from derp so should not be enqueued
119 self.assertEqual(len(self.history), 0)
120
121 # Add an approved review from derp
122 A.addReview('derp', 'APPROVED')
123 self.fake_github.emitEvent(comment)
124 self.waitUntilSettled()
125 self.assertEqual(len(self.history), 1)
126 self.assertEqual(self.history[0].name, 'project3-reviewusername')
127
128 @simple_layout('layouts/requirements-github.yaml', driver='github')
129 def test_pipeline_require_review_state(self):
130 "Test pipeline requirement: review state"
131
132 A = self.fake_github.openFakePullRequest('org/project4', 'master', 'A')
133 # Add derp to writers
134 A.writers.append('derp')
135 # A comment event that we will keep submitting to trigger
136 comment = A.getCommentAddedEvent('test me')
137 self.fake_github.emitEvent(comment)
138 self.waitUntilSettled()
139 # No positive review from derp so should not be enqueued
140 self.assertEqual(len(self.history), 0)
141
142 # A negative review from derp should not cause it to be enqueued
143 A.addReview('derp', 'CHANGES_REQUESTED')
144 self.fake_github.emitEvent(comment)
145 self.waitUntilSettled()
146 self.assertEqual(len(self.history), 0)
147
148 # A positive from nobody should not cause it to be enqueued
149 A.addReview('nobody', 'APPROVED')
150 self.fake_github.emitEvent(comment)
151 self.waitUntilSettled()
152 self.assertEqual(len(self.history), 0)
153
154 # A positive review from derp should cause it to be enqueued
155 A.addReview('derp', 'APPROVED')
156 self.fake_github.emitEvent(comment)
157 self.waitUntilSettled()
158 self.assertEqual(len(self.history), 1)
159 self.assertEqual(self.history[0].name, 'project4-reviewreq')
160
161 @simple_layout('layouts/requirements-github.yaml', driver='github')
162 def test_pipeline_require_review_user_state(self):
163 "Test pipeline requirement: review state from user"
164
165 A = self.fake_github.openFakePullRequest('org/project5', 'master', 'A')
166 # Add derp and herp to writers
167 A.writers.extend(('derp', 'herp'))
168 # A comment event that we will keep submitting to trigger
169 comment = A.getCommentAddedEvent('test me')
170 self.fake_github.emitEvent(comment)
171 self.waitUntilSettled()
172 # No positive review from derp so should not be enqueued
173 self.assertEqual(len(self.history), 0)
174
175 # A negative review from derp should not cause it to be enqueued
176 A.addReview('derp', 'CHANGES_REQUESTED')
177 self.fake_github.emitEvent(comment)
178 self.waitUntilSettled()
179 self.assertEqual(len(self.history), 0)
180
181 # A positive from nobody should not cause it to be enqueued
182 A.addReview('nobody', 'APPROVED')
183 self.fake_github.emitEvent(comment)
184 self.waitUntilSettled()
185 self.assertEqual(len(self.history), 0)
186
187 # A positive review from herp (a writer) should not cause it to be
188 # enqueued
189 A.addReview('herp', 'APPROVED')
190 self.fake_github.emitEvent(comment)
191 self.waitUntilSettled()
192 self.assertEqual(len(self.history), 0)
193
194 # A positive review from derp should cause it to be enqueued
195 A.addReview('derp', 'APPROVED')
196 self.fake_github.emitEvent(comment)
197 self.waitUntilSettled()
198 self.assertEqual(len(self.history), 1)
199 self.assertEqual(self.history[0].name, 'project5-reviewuserstate')
Adam Gandelmand81dd762017-02-09 15:15:49 -0800200
201# TODO: Implement reject on approval username/state
202
203 @simple_layout('layouts/requirements-github.yaml', driver='github')
204 def test_pipeline_require_review_latest_user_state(self):
205 "Test pipeline requirement: review state from user"
206
207 A = self.fake_github.openFakePullRequest('org/project5', 'master', 'A')
208 # Add derp and herp to writers
209 A.writers.extend(('derp', 'herp'))
210 # A comment event that we will keep submitting to trigger
211 comment = A.getCommentAddedEvent('test me')
212 self.fake_github.emitEvent(comment)
213 self.waitUntilSettled()
214 # No positive review from derp so should not be enqueued
215 self.assertEqual(len(self.history), 0)
216
217 # The first negative review from derp should not cause it to be
218 # enqueued
219 for i in range(1, 4):
220 submitted_at = time.time() - 72 * 60 * 60
221 A.addReview('derp', 'CHANGES_REQUESTED',
222 submitted_at)
223 self.fake_github.emitEvent(comment)
224 self.waitUntilSettled()
225 self.assertEqual(len(self.history), 0)
226
227 # A positive review from derp should cause it to be enqueued
228 A.addReview('derp', 'APPROVED')
229 self.fake_github.emitEvent(comment)
230 self.waitUntilSettled()
231 self.assertEqual(len(self.history), 1)
232 self.assertEqual(self.history[0].name, 'project5-reviewuserstate')
233
234 @simple_layout('layouts/requirements-github.yaml', driver='github')
235 def test_require_review_newer_than(self):
236
237 A = self.fake_github.openFakePullRequest('org/project6', 'master', 'A')
238 # Add derp and herp to writers
239 A.writers.extend(('derp', 'herp'))
240 # A comment event that we will keep submitting to trigger
241 comment = A.getCommentAddedEvent('test me')
242 self.fake_github.emitEvent(comment)
243 self.waitUntilSettled()
244 # No positive review from derp so should not be enqueued
245 self.assertEqual(len(self.history), 0)
246
247 # Add a too-old positive review, should not be enqueued
248 submitted_at = time.time() - 72 * 60 * 60
249 A.addReview('derp', 'APPROVED',
250 submitted_at)
251 self.fake_github.emitEvent(comment)
252 self.waitUntilSettled()
253 self.assertEqual(len(self.history), 0)
254
255 # Add a recent positive review
256 submitted_at = time.time() - 12 * 60 * 60
257 A.addReview('derp', 'APPROVED', submitted_at)
258 self.fake_github.emitEvent(comment)
259 self.waitUntilSettled()
260 self.assertEqual(len(self.history), 1)
261 self.assertEqual(self.history[0].name, 'project6-newerthan')
262
263 @simple_layout('layouts/requirements-github.yaml', driver='github')
264 def test_require_review_older_than(self):
265
266 A = self.fake_github.openFakePullRequest('org/project7', 'master', 'A')
267 # Add derp and herp to writers
268 A.writers.extend(('derp', 'herp'))
269 # A comment event that we will keep submitting to trigger
270 comment = A.getCommentAddedEvent('test me')
271 self.fake_github.emitEvent(comment)
272 self.waitUntilSettled()
273 # No positive review from derp so should not be enqueued
274 self.assertEqual(len(self.history), 0)
275
276 # Add a too-new positive, should not be enqueued
277 submitted_at = time.time() - 12 * 60 * 60
278 A.addReview('derp', 'APPROVED',
279 submitted_at)
280 self.fake_github.emitEvent(comment)
281 self.waitUntilSettled()
282 self.assertEqual(len(self.history), 0)
283
284 # Add an old enough positive, should enqueue
285 submitted_at = time.time() - 72 * 60 * 60
286 A.addReview('herp', 'APPROVED', submitted_at)
287 self.fake_github.emitEvent(comment)
288 self.waitUntilSettled()
289 self.assertEqual(len(self.history), 1)
290 self.assertEqual(self.history[0].name, 'project7-olderthan')
Jesse Keating4a27f132017-05-25 16:44:01 -0700291
292 @simple_layout('layouts/requirements-github.yaml', driver='github')
293 def test_require_open(self):
294
295 A = self.fake_github.openFakePullRequest('org/project8', 'master', 'A')
296 # A comment event that we will keep submitting to trigger
297 comment = A.getCommentAddedEvent('test me')
298 self.fake_github.emitEvent(comment)
299 self.waitUntilSettled()
300
301 # PR is open, we should have enqueued
302 self.assertEqual(len(self.history), 1)
303
304 # close the PR and try again
305 A.state = 'closed'
306 self.fake_github.emitEvent(comment)
307 self.waitUntilSettled()
308 # PR is closed, should not trigger
309 self.assertEqual(len(self.history), 1)
Jesse Keating0d40c122017-05-26 11:32:53 -0700310
311 @simple_layout('layouts/requirements-github.yaml', driver='github')
312 def test_require_current(self):
313
314 A = self.fake_github.openFakePullRequest('org/project9', 'master', 'A')
315 # A sync event that we will keep submitting to trigger
316 sync = A.getPullRequestSynchronizeEvent()
317 self.fake_github.emitEvent(sync)
318 self.waitUntilSettled()
319
320 # PR head is current should enqueue
321 self.assertEqual(len(self.history), 1)
322
323 # Add a commit to the PR, re-issue the original comment event
324 A.addCommit()
325 self.fake_github.emitEvent(sync)
326 self.waitUntilSettled()
327 # Event hash is not current, should not trigger
328 self.assertEqual(len(self.history), 1)