blob: 1cad6591b9138214f47a9a49722009b8280569f1 [file] [log] [blame]
James E. Blair9c17dbf2014-06-23 14:21:58 -07001#!/usr/bin/env python
2
3# Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17import logging
18import time
19
20from tests.base import ZuulTestCase
21
22logging.basicConfig(level=logging.DEBUG,
23 format='%(asctime)s %(name)-32s '
24 '%(levelname)-8s %(message)s')
25
26
27class TestRequirements(ZuulTestCase):
28 """Test pipeline and trigger requirements"""
29
James E. Blair509cada2015-12-08 16:31:16 -080030 def setUp(self):
31 self.skip("Disabled for early v3 development")
32
James E. Blair9c17dbf2014-06-23 14:21:58 -070033 def test_pipeline_require_approval_newer_than(self):
34 "Test pipeline requirement: approval newer than"
35 return self._test_require_approval_newer_than('org/project1',
36 'project1-pipeline')
37
38 def test_trigger_require_approval_newer_than(self):
39 "Test trigger requirement: approval newer than"
40 return self._test_require_approval_newer_than('org/project2',
41 'project2-trigger')
42
43 def _test_require_approval_newer_than(self, project, job):
James E. Blairf84026c2015-12-08 16:11:46 -080044 self.updateConfigLayout(
45 'tests/fixtures/layout-requirement-newer-than.yaml')
James E. Blair9c17dbf2014-06-23 14:21:58 -070046 self.sched.reconfigure(self.config)
47 self.registerJobs()
48
49 A = self.fake_gerrit.addFakeChange(project, 'master', 'A')
50 # A comment event that we will keep submitting to trigger
51 comment = A.addApproval('CRVW', 2, username='nobody')
52 self.fake_gerrit.addEvent(comment)
53 self.waitUntilSettled()
54 # No +1 from Jenkins so should not be enqueued
55 self.assertEqual(len(self.history), 0)
56
57 # Add a too-old +1, should not be enqueued
Joshua Hesketh642824b2014-07-01 17:54:59 +100058 A.addApproval('VRFY', 1, username='jenkins',
59 granted_on=time.time() - 72 * 60 * 60)
James E. Blair9c17dbf2014-06-23 14:21:58 -070060 self.fake_gerrit.addEvent(comment)
61 self.waitUntilSettled()
62 self.assertEqual(len(self.history), 0)
63
64 # Add a recent +1
Joshua Hesketh642824b2014-07-01 17:54:59 +100065 self.fake_gerrit.addEvent(A.addApproval('VRFY', 1, username='jenkins'))
James E. Blair9c17dbf2014-06-23 14:21:58 -070066 self.fake_gerrit.addEvent(comment)
67 self.waitUntilSettled()
68 self.assertEqual(len(self.history), 1)
69 self.assertEqual(self.history[0].name, job)
70
71 def test_pipeline_require_approval_older_than(self):
72 "Test pipeline requirement: approval older than"
73 return self._test_require_approval_older_than('org/project1',
74 'project1-pipeline')
75
76 def test_trigger_require_approval_older_than(self):
77 "Test trigger requirement: approval older than"
78 return self._test_require_approval_older_than('org/project2',
79 'project2-trigger')
80
81 def _test_require_approval_older_than(self, project, job):
James E. Blairf84026c2015-12-08 16:11:46 -080082 self.updateConfigLayout(
83 'tests/fixtures/layout-requirement-older-than.yaml')
James E. Blair9c17dbf2014-06-23 14:21:58 -070084 self.sched.reconfigure(self.config)
85 self.registerJobs()
86
87 A = self.fake_gerrit.addFakeChange(project, 'master', 'A')
88 # A comment event that we will keep submitting to trigger
89 comment = A.addApproval('CRVW', 2, username='nobody')
90 self.fake_gerrit.addEvent(comment)
91 self.waitUntilSettled()
92 # No +1 from Jenkins so should not be enqueued
93 self.assertEqual(len(self.history), 0)
94
95 # Add a recent +1 which should not be enqueued
96 A.addApproval('VRFY', 1)
97 self.fake_gerrit.addEvent(comment)
98 self.waitUntilSettled()
99 self.assertEqual(len(self.history), 0)
100
101 # Add an old +1 which should be enqueued
Joshua Hesketh642824b2014-07-01 17:54:59 +1000102 A.addApproval('VRFY', 1, username='jenkins',
103 granted_on=time.time() - 72 * 60 * 60)
James E. Blair9c17dbf2014-06-23 14:21:58 -0700104 self.fake_gerrit.addEvent(comment)
105 self.waitUntilSettled()
106 self.assertEqual(len(self.history), 1)
107 self.assertEqual(self.history[0].name, job)
108
109 def test_pipeline_require_approval_username(self):
110 "Test pipeline requirement: approval username"
111 return self._test_require_approval_username('org/project1',
112 'project1-pipeline')
113
114 def test_trigger_require_approval_username(self):
115 "Test trigger requirement: approval username"
116 return self._test_require_approval_username('org/project2',
117 'project2-trigger')
118
119 def _test_require_approval_username(self, project, job):
James E. Blairf84026c2015-12-08 16:11:46 -0800120 self.updateConfigLayout(
121 'tests/fixtures/layout-requirement-username.yaml')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700122 self.sched.reconfigure(self.config)
123 self.registerJobs()
124
125 A = self.fake_gerrit.addFakeChange(project, 'master', 'A')
126 # A comment event that we will keep submitting to trigger
127 comment = A.addApproval('CRVW', 2, username='nobody')
128 self.fake_gerrit.addEvent(comment)
129 self.waitUntilSettled()
130 # No approval from Jenkins so should not be enqueued
131 self.assertEqual(len(self.history), 0)
132
133 # Add an approval from Jenkins
Joshua Hesketh642824b2014-07-01 17:54:59 +1000134 A.addApproval('VRFY', 1, username='jenkins')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700135 self.fake_gerrit.addEvent(comment)
136 self.waitUntilSettled()
137 self.assertEqual(len(self.history), 1)
138 self.assertEqual(self.history[0].name, job)
139
140 def test_pipeline_require_approval_email(self):
141 "Test pipeline requirement: approval email"
142 return self._test_require_approval_email('org/project1',
143 'project1-pipeline')
144
145 def test_trigger_require_approval_email(self):
146 "Test trigger requirement: approval email"
147 return self._test_require_approval_email('org/project2',
148 'project2-trigger')
149
150 def _test_require_approval_email(self, project, job):
James E. Blairf84026c2015-12-08 16:11:46 -0800151 self.updateConfigLayout(
152 'tests/fixtures/layout-requirement-email.yaml')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700153 self.sched.reconfigure(self.config)
154 self.registerJobs()
155
156 A = self.fake_gerrit.addFakeChange(project, 'master', 'A')
157 # A comment event that we will keep submitting to trigger
158 comment = A.addApproval('CRVW', 2, username='nobody')
159 self.fake_gerrit.addEvent(comment)
160 self.waitUntilSettled()
161 # No approval from Jenkins so should not be enqueued
162 self.assertEqual(len(self.history), 0)
163
164 # Add an approval from Jenkins
Joshua Hesketh642824b2014-07-01 17:54:59 +1000165 A.addApproval('VRFY', 1, username='jenkins')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700166 self.fake_gerrit.addEvent(comment)
167 self.waitUntilSettled()
168 self.assertEqual(len(self.history), 1)
169 self.assertEqual(self.history[0].name, job)
170
171 def test_pipeline_require_approval_vote1(self):
172 "Test pipeline requirement: approval vote with one value"
173 return self._test_require_approval_vote1('org/project1',
174 'project1-pipeline')
175
176 def test_trigger_require_approval_vote1(self):
177 "Test trigger requirement: approval vote with one value"
178 return self._test_require_approval_vote1('org/project2',
179 'project2-trigger')
180
181 def _test_require_approval_vote1(self, project, job):
James E. Blairf84026c2015-12-08 16:11:46 -0800182 self.updateConfigLayout(
183 'tests/fixtures/layout-requirement-vote1.yaml')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700184 self.sched.reconfigure(self.config)
185 self.registerJobs()
186
187 A = self.fake_gerrit.addFakeChange(project, 'master', 'A')
188 # A comment event that we will keep submitting to trigger
189 comment = A.addApproval('CRVW', 2, username='nobody')
190 self.fake_gerrit.addEvent(comment)
191 self.waitUntilSettled()
192 # No approval from Jenkins so should not be enqueued
193 self.assertEqual(len(self.history), 0)
194
195 # A -1 from jenkins should not cause it to be enqueued
Joshua Hesketh642824b2014-07-01 17:54:59 +1000196 A.addApproval('VRFY', -1, username='jenkins')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700197 self.fake_gerrit.addEvent(comment)
198 self.waitUntilSettled()
199 self.assertEqual(len(self.history), 0)
200
201 # A +1 should allow it to be enqueued
Joshua Hesketh642824b2014-07-01 17:54:59 +1000202 A.addApproval('VRFY', 1, username='jenkins')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700203 self.fake_gerrit.addEvent(comment)
204 self.waitUntilSettled()
205 self.assertEqual(len(self.history), 1)
206 self.assertEqual(self.history[0].name, job)
207
208 def test_pipeline_require_approval_vote2(self):
209 "Test pipeline requirement: approval vote with two values"
210 return self._test_require_approval_vote2('org/project1',
211 'project1-pipeline')
212
213 def test_trigger_require_approval_vote2(self):
214 "Test trigger requirement: approval vote with two values"
215 return self._test_require_approval_vote2('org/project2',
216 'project2-trigger')
217
218 def _test_require_approval_vote2(self, project, job):
James E. Blairf84026c2015-12-08 16:11:46 -0800219 self.updateConfigLayout(
220 'tests/fixtures/layout-requirement-vote2.yaml')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700221 self.sched.reconfigure(self.config)
222 self.registerJobs()
223
224 A = self.fake_gerrit.addFakeChange(project, 'master', 'A')
225 # A comment event that we will keep submitting to trigger
226 comment = A.addApproval('CRVW', 2, username='nobody')
227 self.fake_gerrit.addEvent(comment)
228 self.waitUntilSettled()
229 # No approval from Jenkins so should not be enqueued
230 self.assertEqual(len(self.history), 0)
231
232 # A -1 from jenkins should not cause it to be enqueued
Joshua Hesketh642824b2014-07-01 17:54:59 +1000233 A.addApproval('VRFY', -1, username='jenkins')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700234 self.fake_gerrit.addEvent(comment)
235 self.waitUntilSettled()
236 self.assertEqual(len(self.history), 0)
237
238 # A -2 from jenkins should not cause it to be enqueued
Joshua Hesketh642824b2014-07-01 17:54:59 +1000239 A.addApproval('VRFY', -2, username='jenkins')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700240 self.fake_gerrit.addEvent(comment)
241 self.waitUntilSettled()
242 self.assertEqual(len(self.history), 0)
243
Joshua Hesketh642824b2014-07-01 17:54:59 +1000244 # A +1 from jenkins should allow it to be enqueued
245 A.addApproval('VRFY', 1, username='jenkins')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700246 self.fake_gerrit.addEvent(comment)
247 self.waitUntilSettled()
248 self.assertEqual(len(self.history), 1)
249 self.assertEqual(self.history[0].name, job)
250
251 # A +2 should allow it to be enqueued
252 B = self.fake_gerrit.addFakeChange(project, 'master', 'B')
253 # A comment event that we will keep submitting to trigger
254 comment = B.addApproval('CRVW', 2, username='nobody')
255 self.fake_gerrit.addEvent(comment)
256 self.waitUntilSettled()
257 self.assertEqual(len(self.history), 1)
258
Joshua Hesketh642824b2014-07-01 17:54:59 +1000259 B.addApproval('VRFY', 2, username='jenkins')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700260 self.fake_gerrit.addEvent(comment)
261 self.waitUntilSettled()
262 self.assertEqual(len(self.history), 2)
263 self.assertEqual(self.history[1].name, job)
264
265 def test_pipeline_require_current_patchset(self):
266 "Test pipeline requirement: current-patchset"
James E. Blairf84026c2015-12-08 16:11:46 -0800267 self.updateConfigLayout(
268 'tests/fixtures/layout-requirement-current-patchset.yaml')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700269 self.sched.reconfigure(self.config)
270 self.registerJobs()
271 # Create two patchsets and let their tests settle out. Then
272 # comment on first patchset and check that no additional
273 # jobs are run.
274 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
275 self.fake_gerrit.addEvent(A.addApproval('CRVW', 1))
276 self.waitUntilSettled()
277 A.addPatchset()
278 self.fake_gerrit.addEvent(A.addApproval('CRVW', 1))
279 self.waitUntilSettled()
280
281 self.assertEqual(len(self.history), 2) # one job for each ps
282 self.fake_gerrit.addEvent(A.getChangeCommentEvent(1))
283 self.waitUntilSettled()
284
285 # Assert no new jobs ran after event for old patchset.
286 self.assertEqual(len(self.history), 2)
287
288 # Make sure the same event on a new PS will trigger
289 self.fake_gerrit.addEvent(A.getChangeCommentEvent(2))
290 self.waitUntilSettled()
291 self.assertEqual(len(self.history), 3)
292
293 def test_pipeline_require_open(self):
294 "Test pipeline requirement: open"
James E. Blairf84026c2015-12-08 16:11:46 -0800295 self.updateConfigLayout(
296 'tests/fixtures/layout-requirement-open.yaml')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700297 self.sched.reconfigure(self.config)
298 self.registerJobs()
299
300 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
301 status='MERGED')
302 self.fake_gerrit.addEvent(A.addApproval('CRVW', 2))
303 self.waitUntilSettled()
304 self.assertEqual(len(self.history), 0)
305
306 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
307 self.fake_gerrit.addEvent(B.addApproval('CRVW', 2))
308 self.waitUntilSettled()
309 self.assertEqual(len(self.history), 1)
310
311 def test_pipeline_require_status(self):
312 "Test pipeline requirement: status"
James E. Blairf84026c2015-12-08 16:11:46 -0800313 self.updateConfigLayout(
314 'tests/fixtures/layout-requirement-status.yaml')
James E. Blair9c17dbf2014-06-23 14:21:58 -0700315 self.sched.reconfigure(self.config)
316 self.registerJobs()
317
318 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
319 status='MERGED')
320 self.fake_gerrit.addEvent(A.addApproval('CRVW', 2))
321 self.waitUntilSettled()
322 self.assertEqual(len(self.history), 0)
323
324 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
325 self.fake_gerrit.addEvent(B.addApproval('CRVW', 2))
326 self.waitUntilSettled()
327 self.assertEqual(len(self.history), 1)
Joshua Hesketh66c8e522014-06-26 15:30:08 +1000328
329 def _test_require_reject_username(self, project, job):
330 "Test negative username's match"
331 # Should only trigger if Jenkins hasn't voted.
James E. Blairf84026c2015-12-08 16:11:46 -0800332 self.updateConfigLayout(
Joshua Hesketh66c8e522014-06-26 15:30:08 +1000333 'tests/fixtures/layout-requirement-reject-username.yaml')
334 self.sched.reconfigure(self.config)
335 self.registerJobs()
336
337 # add in a change with no comments
338 A = self.fake_gerrit.addFakeChange(project, 'master', 'A')
339 self.waitUntilSettled()
340 self.assertEqual(len(self.history), 0)
341
342 # add in a comment that will trigger
343 self.fake_gerrit.addEvent(A.addApproval('CRVW', 1,
344 username='reviewer'))
345 self.waitUntilSettled()
346 self.assertEqual(len(self.history), 1)
347 self.assertEqual(self.history[0].name, job)
348
349 # add in a comment from jenkins user which shouldn't trigger
350 self.fake_gerrit.addEvent(A.addApproval('VRFY', 1, username='jenkins'))
351 self.waitUntilSettled()
352 self.assertEqual(len(self.history), 1)
353
354 # Check future reviews also won't trigger as a 'jenkins' user has
355 # commented previously
356 self.fake_gerrit.addEvent(A.addApproval('CRVW', 1,
357 username='reviewer'))
358 self.waitUntilSettled()
359 self.assertEqual(len(self.history), 1)
360
361 def test_pipeline_reject_username(self):
362 "Test negative pipeline requirement: no comment from jenkins"
363 return self._test_require_reject_username('org/project1',
364 'project1-pipeline')
365
366 def test_trigger_reject_username(self):
367 "Test negative trigger requirement: no comment from jenkins"
368 return self._test_require_reject_username('org/project2',
369 'project2-trigger')
370
371 def _test_require_reject(self, project, job):
372 "Test no approval matches a reject param"
James E. Blairf84026c2015-12-08 16:11:46 -0800373 self.updateConfigLayout(
Joshua Hesketh66c8e522014-06-26 15:30:08 +1000374 'tests/fixtures/layout-requirement-reject.yaml')
375 self.sched.reconfigure(self.config)
376 self.registerJobs()
377
378 A = self.fake_gerrit.addFakeChange(project, 'master', 'A')
379 self.waitUntilSettled()
380 self.assertEqual(len(self.history), 0)
381
382 # First positive vote should not queue until jenkins has +1'd
383 comment = A.addApproval('VRFY', 1, username='reviewer_a')
384 self.fake_gerrit.addEvent(comment)
385 self.waitUntilSettled()
386 self.assertEqual(len(self.history), 0)
387
388 # Jenkins should put in a +1 which will also queue
389 comment = A.addApproval('VRFY', 1, username='jenkins')
390 self.fake_gerrit.addEvent(comment)
391 self.waitUntilSettled()
392 self.assertEqual(len(self.history), 1)
393 self.assertEqual(self.history[0].name, job)
394
395 # Negative vote should not queue
396 comment = A.addApproval('VRFY', -1, username='reviewer_b')
397 self.fake_gerrit.addEvent(comment)
398 self.waitUntilSettled()
399 self.assertEqual(len(self.history), 1)
400
401 # Future approvals should do nothing
402 comment = A.addApproval('VRFY', 1, username='reviewer_c')
403 self.fake_gerrit.addEvent(comment)
404 self.waitUntilSettled()
405 self.assertEqual(len(self.history), 1)
406
407 # Change/update negative vote should queue
408 comment = A.addApproval('VRFY', 1, username='reviewer_b')
409 self.fake_gerrit.addEvent(comment)
410 self.waitUntilSettled()
411 self.assertEqual(len(self.history), 2)
412 self.assertEqual(self.history[1].name, job)
413
414 # Future approvals should also queue
415 comment = A.addApproval('VRFY', 1, username='reviewer_d')
416 self.fake_gerrit.addEvent(comment)
417 self.waitUntilSettled()
418 self.assertEqual(len(self.history), 3)
419 self.assertEqual(self.history[2].name, job)
420
421 def test_pipeline_require_reject(self):
422 "Test pipeline requirement: rejections absent"
423 return self._test_require_reject('org/project1', 'project1-pipeline')
424
425 def test_trigger_require_reject(self):
426 "Test trigger requirement: rejections absent"
427 return self._test_require_reject('org/project2', 'project2-trigger')