blob: e36c8f61e26dbc022141aa28eccf9c15ccc9f98a [file] [log] [blame]
James E. Blair59fdbac2015-12-07 17:08:06 -08001#!/usr/bin/env python
2
3# Copyright 2012 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
Monty Taylor0e2489a2017-10-10 11:57:29 -050017import io
James E. Blaira00910c2017-08-23 09:15:04 -070018import json
Monty Taylor0e2489a2017-10-10 11:57:29 -050019import logging
James E. Blaira92cbc82017-01-23 14:56:49 -080020import os
James E. Blair14abdf42015-12-09 16:11:53 -080021import textwrap
James E. Blair3a098dd2017-10-04 14:37:29 -070022import gc
James E. Blairbacbb882017-10-17 09:48:23 -070023import time
James E. Blair3a098dd2017-10-04 14:37:29 -070024from unittest import skip
James E. Blair59fdbac2015-12-07 17:08:06 -080025
James E. Blairb9c0d772017-03-03 14:34:49 -080026import testtools
27
28import zuul.configloader
James E. Blairbf1a4f22017-03-17 10:59:37 -070029from zuul.lib import encryption
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +000030from tests.base import AnsibleZuulTestCase, ZuulTestCase, FIXTURE_DIR
James E. Blair59fdbac2015-12-07 17:08:06 -080031
James E. Blair59fdbac2015-12-07 17:08:06 -080032
James E. Blair3f876d52016-07-22 13:07:14 -070033class TestMultipleTenants(AnsibleZuulTestCase):
James E. Blair59fdbac2015-12-07 17:08:06 -080034 # A temporary class to hold new tests while others are disabled
35
James E. Blair2a629ec2015-12-22 15:32:02 -080036 tenant_config_file = 'config/multi-tenant/main.yaml'
James E. Blair59fdbac2015-12-07 17:08:06 -080037
James E. Blair83005782015-12-11 14:46:03 -080038 def test_multiple_tenants(self):
James E. Blair96f26942015-12-09 10:15:59 -080039 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +020040 A.addApproval('Code-Review', 2)
41 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair59fdbac2015-12-07 17:08:06 -080042 self.waitUntilSettled()
James E. Blair96f26942015-12-09 10:15:59 -080043 self.assertEqual(self.getJobFromHistory('project1-test1').result,
James E. Blair59fdbac2015-12-07 17:08:06 -080044 'SUCCESS')
James E. Blair96c6bf82016-01-15 16:20:40 -080045 self.assertEqual(self.getJobFromHistory('python27').result,
46 'SUCCESS')
James E. Blair59fdbac2015-12-07 17:08:06 -080047 self.assertEqual(A.data['status'], 'MERGED')
James E. Blair96f26942015-12-09 10:15:59 -080048 self.assertEqual(A.reported, 2,
49 "A should report start and success")
50 self.assertIn('tenant-one-gate', A.messages[1],
51 "A should transit tenant-one gate")
52 self.assertNotIn('tenant-two-gate', A.messages[1],
53 "A should *not* transit tenant-two gate")
James E. Blair59fdbac2015-12-07 17:08:06 -080054
James E. Blair96f26942015-12-09 10:15:59 -080055 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +020056 B.addApproval('Code-Review', 2)
57 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair96f26942015-12-09 10:15:59 -080058 self.waitUntilSettled()
James E. Blair96c6bf82016-01-15 16:20:40 -080059 self.assertEqual(self.getJobFromHistory('python27',
60 'org/project2').result,
61 'SUCCESS')
James E. Blair96f26942015-12-09 10:15:59 -080062 self.assertEqual(self.getJobFromHistory('project2-test1').result,
63 'SUCCESS')
64 self.assertEqual(B.data['status'], 'MERGED')
65 self.assertEqual(B.reported, 2,
66 "B should report start and success")
67 self.assertIn('tenant-two-gate', B.messages[1],
68 "B should transit tenant-two gate")
69 self.assertNotIn('tenant-one-gate', B.messages[1],
70 "B should *not* transit tenant-one gate")
James E. Blair59fdbac2015-12-07 17:08:06 -080071
James E. Blair96f26942015-12-09 10:15:59 -080072 self.assertEqual(A.reported, 2, "Activity in tenant two should"
73 "not affect tenant one")
James E. Blair14abdf42015-12-09 16:11:53 -080074
James E. Blair83005782015-12-11 14:46:03 -080075
Tobias Henkel130b0002017-11-26 20:27:59 +010076class TestProtected(ZuulTestCase):
Tobias Henkel130b0002017-11-26 20:27:59 +010077 tenant_config_file = 'config/protected/main.yaml'
78
79 def test_protected_ok(self):
James E. Blair979bf242017-09-15 21:13:32 -060080 # test clean usage of final parent job
81 in_repo_conf = textwrap.dedent(
82 """
83 - job:
84 name: job-protected
85 protected: true
86 run: playbooks/job-protected.yaml
Tobias Henkel130b0002017-11-26 20:27:59 +010087
James E. Blair979bf242017-09-15 21:13:32 -060088 - project:
89 name: org/project
90 check:
91 jobs:
92 - job-child-ok
Tobias Henkel130b0002017-11-26 20:27:59 +010093
James E. Blair979bf242017-09-15 21:13:32 -060094 - job:
95 name: job-child-ok
96 parent: job-protected
Tobias Henkel130b0002017-11-26 20:27:59 +010097
James E. Blair979bf242017-09-15 21:13:32 -060098 - project:
99 name: org/project
100 check:
101 jobs:
102 - job-child-ok
Tobias Henkel130b0002017-11-26 20:27:59 +0100103
James E. Blair979bf242017-09-15 21:13:32 -0600104 """)
Tobias Henkel130b0002017-11-26 20:27:59 +0100105
James E. Blair979bf242017-09-15 21:13:32 -0600106 file_dict = {'zuul.yaml': in_repo_conf}
107 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
108 files=file_dict)
109 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
110 self.waitUntilSettled()
Tobias Henkel130b0002017-11-26 20:27:59 +0100111
James E. Blair979bf242017-09-15 21:13:32 -0600112 self.assertEqual(A.reported, 1)
113 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1')
Tobias Henkel130b0002017-11-26 20:27:59 +0100114
115 def test_protected_reset(self):
116 # try to reset protected flag
117 in_repo_conf = textwrap.dedent(
118 """
119 - job:
120 name: job-protected
121 protected: true
122 run: playbooks/job-protected.yaml
123
124 - job:
125 name: job-child-reset-protected
126 parent: job-protected
127 protected: false
128
129 - project:
130 name: org/project
131 check:
132 jobs:
133 - job-child-reset-protected
134
135 """)
136
137 file_dict = {'zuul.yaml': in_repo_conf}
138 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
139 files=file_dict)
140 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
141 self.waitUntilSettled()
142
143 # The second patch tried to override some variables.
144 # Thus it should fail.
145 self.assertEqual(A.reported, 1)
146 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
147 self.assertIn('Unable to reset protected attribute', A.messages[0])
148
149 def test_protected_inherit_not_ok(self):
150 # try to inherit from a protected job in different project
151 in_repo_conf = textwrap.dedent(
152 """
153 - job:
154 name: job-child-notok
155 run: playbooks/job-child-notok.yaml
156 parent: job-protected
157
158 - project:
159 name: org/project1
160 check:
161 jobs:
162 - job-child-notok
163
164 """)
165
166 file_dict = {'zuul.yaml': in_repo_conf}
167 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
168 files=file_dict)
169 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
170 self.waitUntilSettled()
171
172 self.assertEqual(A.reported, 1)
173 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
174 self.assertIn(
175 "which is defined in review.example.com/org/project is protected "
176 "and cannot be inherited from other projects.", A.messages[0])
177
178
James E. Blair979bf242017-09-15 21:13:32 -0600179class TestAbstract(ZuulTestCase):
180 tenant_config_file = 'config/abstract/main.yaml'
181
182 def test_abstract_fail(self):
183 in_repo_conf = textwrap.dedent(
184 """
185 - project:
186 check:
187 jobs:
188 - job-abstract
189 """)
190
191 file_dict = {'zuul.yaml': in_repo_conf}
192 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
193 files=file_dict)
194 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
195 self.waitUntilSettled()
196
197 self.assertEqual(A.reported, 1)
198 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
199 self.assertIn('may not be directly run', A.messages[0])
200
201 def test_child_of_abstract(self):
202 in_repo_conf = textwrap.dedent(
203 """
204 - project:
205 check:
206 jobs:
207 - job-child
208 """)
209
210 file_dict = {'zuul.yaml': in_repo_conf}
211 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
212 files=file_dict)
213 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
214 self.waitUntilSettled()
215
216 self.assertEqual(A.reported, 1)
217 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1')
218
219
Tobias Henkel83167622017-06-30 19:45:03 +0200220class TestFinal(ZuulTestCase):
221
222 tenant_config_file = 'config/final/main.yaml'
223
224 def test_final_variant_ok(self):
225 # test clean usage of final parent job
226 in_repo_conf = textwrap.dedent(
227 """
228 - project:
229 name: org/project
230 check:
231 jobs:
232 - job-final
233 """)
234
235 file_dict = {'.zuul.yaml': in_repo_conf}
236 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
237 files=file_dict)
238 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
239 self.waitUntilSettled()
240
241 self.assertEqual(A.reported, 1)
242 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1')
243
244 def test_final_variant_error(self):
245 # test misuse of final parent job
246 in_repo_conf = textwrap.dedent(
247 """
248 - project:
249 name: org/project
250 check:
251 jobs:
252 - job-final:
253 vars:
254 dont_override_this: bar
255 """)
256 file_dict = {'.zuul.yaml': in_repo_conf}
257 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
258 files=file_dict)
259 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
260 self.waitUntilSettled()
261
262 # The second patch tried to override some variables.
263 # Thus it should fail.
264 self.assertEqual(A.reported, 1)
265 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
266 self.assertIn('Unable to modify final job', A.messages[0])
267
268 def test_final_inheritance(self):
269 # test misuse of final parent job
270 in_repo_conf = textwrap.dedent(
271 """
272 - job:
273 name: project-test
274 parent: job-final
James E. Blair2f589fe2017-10-26 12:57:41 -0700275 run: playbooks/project-test.yaml
Tobias Henkel83167622017-06-30 19:45:03 +0200276
277 - project:
278 name: org/project
279 check:
280 jobs:
281 - project-test
282 """)
283
284 in_repo_playbook = textwrap.dedent(
285 """
286 - hosts: all
287 tasks: []
288 """)
289
290 file_dict = {'.zuul.yaml': in_repo_conf,
291 'playbooks/project-test.yaml': in_repo_playbook}
292 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
293 files=file_dict)
294 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
295 self.waitUntilSettled()
296
297 # The second patch tried to override some variables.
298 # Thus it should fail.
299 self.assertEqual(A.reported, 1)
300 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
James E. Blairc32a8352017-10-11 16:27:50 -0700301 self.assertIn('Unable to modify final job', A.messages[0])
Tobias Henkel83167622017-06-30 19:45:03 +0200302
303
James E. Blairc6d48652018-02-14 14:20:13 -0800304class TestBranchDeletion(ZuulTestCase):
305 tenant_config_file = 'config/branch-deletion/main.yaml'
306
307 def test_branch_delete(self):
308 # This tests a tenant reconfiguration on deleting a branch
309 # *after* an earlier failed tenant reconfiguration. This
310 # ensures that cached data are appropriately removed, even if
311 # we are recovering from an invalid config.
312 self.create_branch('org/project', 'stable/queens')
313 self.fake_gerrit.addEvent(
314 self.fake_gerrit.getFakeBranchCreatedEvent(
315 'org/project', 'stable/queens'))
316 self.waitUntilSettled()
317
318 in_repo_conf = textwrap.dedent(
319 """
320 - project:
321 check:
322 jobs:
323 - nonexistent-job
324 """)
325
326 file_dict = {'zuul.yaml': in_repo_conf}
327 A = self.fake_gerrit.addFakeChange('org/project', 'stable/queens', 'A',
328 files=file_dict)
329 A.setMerged()
330 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
331 self.waitUntilSettled()
332
333 self.delete_branch('org/project', 'stable/queens')
334 self.fake_gerrit.addEvent(
335 self.fake_gerrit.getFakeBranchDeletedEvent(
336 'org/project', 'stable/queens'))
337 self.waitUntilSettled()
338
339 in_repo_conf = textwrap.dedent(
340 """
341 - project:
342 check:
343 jobs:
344 - base
345 """)
346
347 file_dict = {'zuul.yaml': in_repo_conf}
348 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
349 files=file_dict)
350 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
351 self.waitUntilSettled()
352 self.assertEqual(B.reported, 1)
353 self.assertHistory([
354 dict(name='base', result='SUCCESS', changes='2,1')])
355
356 def test_branch_delete_full_reconfiguration(self):
357 # This tests a full configuration after deleting a branch
358 # *after* an earlier failed tenant reconfiguration. This
359 # ensures that cached data are appropriately removed, even if
360 # we are recovering from an invalid config.
361 self.create_branch('org/project', 'stable/queens')
362 self.fake_gerrit.addEvent(
363 self.fake_gerrit.getFakeBranchCreatedEvent(
364 'org/project', 'stable/queens'))
365 self.waitUntilSettled()
366
367 in_repo_conf = textwrap.dedent(
368 """
369 - project:
370 check:
371 jobs:
372 - nonexistent-job
373 """)
374
375 file_dict = {'zuul.yaml': in_repo_conf}
376 A = self.fake_gerrit.addFakeChange('org/project', 'stable/queens', 'A',
377 files=file_dict)
378 A.setMerged()
379 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
380 self.waitUntilSettled()
381
382 self.delete_branch('org/project', 'stable/queens')
383 self.sched.reconfigure(self.config)
384 self.waitUntilSettled()
385
386 in_repo_conf = textwrap.dedent(
387 """
388 - project:
389 check:
390 jobs:
391 - base
392 """)
393
394 file_dict = {'zuul.yaml': in_repo_conf}
395 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
396 files=file_dict)
397 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
398 self.waitUntilSettled()
399 self.assertEqual(B.reported, 1)
400 self.assertHistory([
401 dict(name='base', result='SUCCESS', changes='2,1')])
402
403
James E. Blair1edfd972017-12-01 15:54:24 -0800404class TestBranchTag(ZuulTestCase):
405 tenant_config_file = 'config/branch-tag/main.yaml'
406
407 def test_negative_branch_match(self):
408 # Test that a negative branch matcher works with implied branches.
409 event = self.fake_gerrit.addFakeTag('org/project', 'master', 'foo')
410 self.fake_gerrit.addEvent(event)
411 self.waitUntilSettled()
412 self.assertHistory([
413 dict(name='test-job', result='SUCCESS', ref='refs/tags/foo')])
414
415
James E. Blair9ab8db42017-12-01 15:12:04 -0800416class TestBranchNegative(ZuulTestCase):
417 tenant_config_file = 'config/branch-negative/main.yaml'
418
419 def test_negative_branch_match(self):
420 # Test that a negative branch matcher works with implied branches.
421 self.create_branch('org/project', 'stable/pike')
422 self.fake_gerrit.addEvent(
423 self.fake_gerrit.getFakeBranchCreatedEvent(
424 'org/project', 'stable/pike'))
425 self.waitUntilSettled()
426
427 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
428 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
429 self.waitUntilSettled()
430 B = self.fake_gerrit.addFakeChange('org/project', 'stable/pike', 'A')
431 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
432 self.waitUntilSettled()
433 self.assertHistory([
434 dict(name='test-job', result='SUCCESS', changes='1,1')])
435
436
James E. Blaire36d1a32017-11-28 13:33:38 -0800437class TestBranchTemplates(ZuulTestCase):
438 tenant_config_file = 'config/branch-templates/main.yaml'
439
440 def test_template_removal_from_branch(self):
441 # Test that a template can be removed from one branch but not
442 # another.
443 # This creates a new branch with a copy of the config in master
444 self.create_branch('puppet-integration', 'stable/newton')
445 self.create_branch('puppet-integration', 'stable/ocata')
446 self.create_branch('puppet-tripleo', 'stable/newton')
447 self.create_branch('puppet-tripleo', 'stable/ocata')
448 self.fake_gerrit.addEvent(
449 self.fake_gerrit.getFakeBranchCreatedEvent(
450 'puppet-integration', 'stable/newton'))
451 self.fake_gerrit.addEvent(
452 self.fake_gerrit.getFakeBranchCreatedEvent(
453 'puppet-integration', 'stable/ocata'))
454 self.fake_gerrit.addEvent(
455 self.fake_gerrit.getFakeBranchCreatedEvent(
456 'puppet-tripleo', 'stable/newton'))
457 self.fake_gerrit.addEvent(
458 self.fake_gerrit.getFakeBranchCreatedEvent(
459 'puppet-tripleo', 'stable/ocata'))
460 self.waitUntilSettled()
461
462 in_repo_conf = textwrap.dedent(
463 """
464 - project:
465 name: puppet-tripleo
466 check:
467 jobs:
468 - puppet-something
469 """)
470
471 file_dict = {'.zuul.yaml': in_repo_conf}
472 A = self.fake_gerrit.addFakeChange('puppet-tripleo', 'stable/newton',
473 'A', files=file_dict)
474 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
475 self.waitUntilSettled()
476 self.assertHistory([
477 dict(name='puppet-something', result='SUCCESS', changes='1,1')])
478
479 def test_template_change_on_branch(self):
480 # Test that the contents of a template can be changed on one
481 # branch without affecting another.
482
483 # This creates a new branch with a copy of the config in master
484 self.create_branch('puppet-integration', 'stable/newton')
485 self.create_branch('puppet-integration', 'stable/ocata')
486 self.create_branch('puppet-tripleo', 'stable/newton')
487 self.create_branch('puppet-tripleo', 'stable/ocata')
488 self.fake_gerrit.addEvent(
489 self.fake_gerrit.getFakeBranchCreatedEvent(
490 'puppet-integration', 'stable/newton'))
491 self.fake_gerrit.addEvent(
492 self.fake_gerrit.getFakeBranchCreatedEvent(
493 'puppet-integration', 'stable/ocata'))
494 self.fake_gerrit.addEvent(
495 self.fake_gerrit.getFakeBranchCreatedEvent(
496 'puppet-tripleo', 'stable/newton'))
497 self.fake_gerrit.addEvent(
498 self.fake_gerrit.getFakeBranchCreatedEvent(
499 'puppet-tripleo', 'stable/ocata'))
500 self.waitUntilSettled()
501
502 in_repo_conf = textwrap.dedent("""
503 - job:
504 name: puppet-unit-base
505 run: playbooks/run-unit-tests.yaml
506
507 - job:
508 name: puppet-unit-3.8
509 parent: puppet-unit-base
510 branches: ^(stable/(newton|ocata)).*$
511 vars:
512 puppet_gem_version: 3.8
513
514 - job:
515 name: puppet-something
516 run: playbooks/run-unit-tests.yaml
517
518 - project-template:
519 name: puppet-unit
520 check:
521 jobs:
522 - puppet-something
523
524 - project:
525 name: puppet-integration
526 templates:
527 - puppet-unit
528 """)
529
530 file_dict = {'.zuul.yaml': in_repo_conf}
531 A = self.fake_gerrit.addFakeChange('puppet-integration',
532 'stable/newton',
533 'A', files=file_dict)
534 B = self.fake_gerrit.addFakeChange('puppet-tripleo',
535 'stable/newton',
536 'B')
537 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
538 B.subject, A.data['id'])
539 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
540 self.waitUntilSettled()
541 self.assertHistory([
542 dict(name='puppet-something', result='SUCCESS',
543 changes='1,1 2,1')])
544
545
James E. Blair09998792017-10-15 18:02:18 -0700546class TestBranchVariants(ZuulTestCase):
547 tenant_config_file = 'config/branch-variants/main.yaml'
548
549 def test_branch_variants(self):
550 # Test branch variants of jobs with inheritance
551 self.executor_server.hold_jobs_in_build = True
552 # This creates a new branch with a copy of the config in master
553 self.create_branch('puppet-integration', 'stable')
554 self.fake_gerrit.addEvent(
555 self.fake_gerrit.getFakeBranchCreatedEvent(
556 'puppet-integration', 'stable'))
557 self.waitUntilSettled()
558
559 A = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'A')
560 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
561 self.waitUntilSettled()
562
563 self.assertEqual(len(self.builds[0].parameters['pre_playbooks']), 3)
564 self.executor_server.hold_jobs_in_build = False
565 self.executor_server.release()
566 self.waitUntilSettled()
567
James E. Blairc9e77592017-10-24 09:25:23 -0700568 def test_branch_variants_reconfigure(self):
569 # Test branch variants of jobs with inheritance
570 self.executor_server.hold_jobs_in_build = True
571 # This creates a new branch with a copy of the config in master
572 self.create_branch('puppet-integration', 'stable')
573 self.fake_gerrit.addEvent(
574 self.fake_gerrit.getFakeBranchCreatedEvent(
575 'puppet-integration', 'stable'))
576 self.waitUntilSettled()
577
578 with open(os.path.join(FIXTURE_DIR,
579 'config/branch-variants/git/',
580 'puppet-integration/.zuul.yaml')) as f:
581 config = f.read()
582
583 # Push a change that triggers a dynamic reconfiguration
584 file_dict = {'.zuul.yaml': config}
585 A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A',
586 files=file_dict)
587 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
588 self.waitUntilSettled()
589
590 ipath = self.builds[0].parameters['zuul']['_inheritance_path']
591 for i in ipath:
592 self.log.debug("inheritance path %s", i)
593 self.assertEqual(len(ipath), 5)
594 self.executor_server.hold_jobs_in_build = False
595 self.executor_server.release()
596 self.waitUntilSettled()
597
James E. Blairc32a8352017-10-11 16:27:50 -0700598 def test_branch_variants_divergent(self):
599 # Test branches can diverge and become independent
600 self.executor_server.hold_jobs_in_build = True
601 # This creates a new branch with a copy of the config in master
602 self.create_branch('puppet-integration', 'stable')
603 self.fake_gerrit.addEvent(
604 self.fake_gerrit.getFakeBranchCreatedEvent(
605 'puppet-integration', 'stable'))
606 self.waitUntilSettled()
607
608 with open(os.path.join(FIXTURE_DIR,
609 'config/branch-variants/git/',
610 'puppet-integration/stable.zuul.yaml')) as f:
611 config = f.read()
612
613 file_dict = {'.zuul.yaml': config}
614 C = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'C',
615 files=file_dict)
616 C.addApproval('Code-Review', 2)
617 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
618 self.waitUntilSettled()
619 self.fake_gerrit.addEvent(C.getChangeMergedEvent())
620 self.waitUntilSettled()
621
622 A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A')
623 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
624 self.waitUntilSettled()
625 B = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'B')
626 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
627 self.waitUntilSettled()
628
629 self.assertEqual(self.builds[0].parameters['zuul']['jobtags'],
630 ['master'])
631
632 self.assertEqual(self.builds[1].parameters['zuul']['jobtags'],
633 ['stable'])
634
635 self.executor_server.hold_jobs_in_build = False
636 self.executor_server.release()
637 self.waitUntilSettled()
638
James E. Blair09998792017-10-15 18:02:18 -0700639
James E. Blair7fb04512018-01-23 13:23:13 -0800640class TestBranchMismatch(ZuulTestCase):
641 tenant_config_file = 'config/branch-mismatch/main.yaml'
642
643 def test_job_override_branch(self):
644 "Test that override-checkout overrides branch matchers as well"
645
646 # Make sure the parent job repo is branched, so it gets
647 # implied branch matchers.
648 self.create_branch('org/project1', 'stable')
649 self.fake_gerrit.addEvent(
650 self.fake_gerrit.getFakeBranchCreatedEvent(
651 'org/project1', 'stable'))
652
653 # The child job repo should have a branch which does not exist
654 # in the parent job repo.
655 self.create_branch('org/project2', 'devel')
656 self.fake_gerrit.addEvent(
657 self.fake_gerrit.getFakeBranchCreatedEvent(
658 'org/project2', 'devel'))
659
660 # A job in a repo with a weird branch name should use the
661 # parent job from the parent job's master (default) branch.
662 A = self.fake_gerrit.addFakeChange('org/project2', 'devel', 'A')
663 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
664 self.waitUntilSettled()
665 # project-test2 should run because it inherits from
666 # project-test1 and we will use the fallback branch to find
667 # project-test1 variants, but project-test1 itself, even
668 # though it is in the project-pipeline config, should not run
669 # because it doesn't directly match.
670 self.assertHistory([
671 dict(name='project-test1', result='SUCCESS', changes='1,1'),
672 dict(name='project-test2', result='SUCCESS', changes='1,1'),
673 ], ordered=False)
674
675
James E. Blair5d71d1a2018-01-26 14:26:18 -0800676class TestAllowedProjects(ZuulTestCase):
677 tenant_config_file = 'config/allowed-projects/main.yaml'
678
679 def test_allowed_projects(self):
680 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
681 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
682 self.waitUntilSettled()
683 self.assertEqual(A.reported, 1)
684 self.assertIn('Build succeeded', A.messages[0])
685
686 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
687 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
688 self.waitUntilSettled()
689 self.assertEqual(B.reported, 1)
690 self.assertIn('Project org/project2 is not allowed '
691 'to run job test-project2', B.messages[0])
692
693 C = self.fake_gerrit.addFakeChange('org/project3', 'master', 'C')
694 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
695 self.waitUntilSettled()
696 self.assertEqual(C.reported, 1)
697 self.assertIn('Project org/project3 is not allowed '
698 'to run job restricted-job', C.messages[0])
699
700 self.assertHistory([
701 dict(name='test-project1', result='SUCCESS', changes='1,1'),
702 dict(name='restricted-job', result='SUCCESS', changes='1,1'),
703 ], ordered=False)
704
705
James E. Blair2a664502017-10-27 11:39:33 -0700706class TestCentralJobs(ZuulTestCase):
707 tenant_config_file = 'config/central-jobs/main.yaml'
708
709 def setUp(self):
710 super(TestCentralJobs, self).setUp()
711 self.create_branch('org/project', 'stable')
712 self.fake_gerrit.addEvent(
713 self.fake_gerrit.getFakeBranchCreatedEvent(
714 'org/project', 'stable'))
715 self.waitUntilSettled()
716
717 def _updateConfig(self, config, branch):
718 file_dict = {'.zuul.yaml': config}
719 C = self.fake_gerrit.addFakeChange('org/project', branch, 'C',
720 files=file_dict)
721 C.addApproval('Code-Review', 2)
722 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
723 self.waitUntilSettled()
724 self.fake_gerrit.addEvent(C.getChangeMergedEvent())
725 self.waitUntilSettled()
726
727 def _test_central_job_on_branch(self, branch, other_branch):
728 # Test that a job defined on a branchless repo only runs on
729 # the branch applied
730 config = textwrap.dedent(
731 """
732 - project:
733 name: org/project
734 check:
735 jobs:
736 - central-job
737 """)
738 self._updateConfig(config, branch)
739
740 A = self.fake_gerrit.addFakeChange('org/project', branch, 'A')
741 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
742 self.waitUntilSettled()
743
744 self.assertHistory([
745 dict(name='central-job', result='SUCCESS', changes='2,1')])
746
747 # No jobs should run for this change.
748 B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B')
749 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
750 self.waitUntilSettled()
751
752 self.assertHistory([
753 dict(name='central-job', result='SUCCESS', changes='2,1')])
754
755 def test_central_job_on_stable(self):
756 self._test_central_job_on_branch('master', 'stable')
757
758 def test_central_job_on_master(self):
759 self._test_central_job_on_branch('stable', 'master')
760
761 def _test_central_template_on_branch(self, branch, other_branch):
762 # Test that a project-template defined on a branchless repo
763 # only runs on the branch applied
764 config = textwrap.dedent(
765 """
766 - project:
767 name: org/project
768 templates: ['central-jobs']
769 """)
770 self._updateConfig(config, branch)
771
772 A = self.fake_gerrit.addFakeChange('org/project', branch, 'A')
773 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
774 self.waitUntilSettled()
775
776 self.assertHistory([
777 dict(name='central-job', result='SUCCESS', changes='2,1')])
778
779 # No jobs should run for this change.
780 B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B')
781 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
782 self.waitUntilSettled()
783
784 self.assertHistory([
785 dict(name='central-job', result='SUCCESS', changes='2,1')])
786
787 def test_central_template_on_stable(self):
788 self._test_central_template_on_branch('master', 'stable')
789
790 def test_central_template_on_master(self):
791 self._test_central_template_on_branch('stable', 'master')
792
793
James E. Blairff555742017-02-19 11:34:27 -0800794class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -0800795 # A temporary class to hold new tests while others are disabled
796
Tobias Henkelabf973e2017-07-28 10:07:34 +0200797 config_file = 'zuul-connections-gerrit-and-github.conf'
James E. Blair2a629ec2015-12-22 15:32:02 -0800798 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -0800799
James E. Blair83005782015-12-11 14:46:03 -0800800 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -0800801 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200802 A.addApproval('Code-Review', 2)
803 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -0800804 self.waitUntilSettled()
805 self.assertEqual(self.getJobFromHistory('project-test1').result,
806 'SUCCESS')
807 self.assertEqual(A.data['status'], 'MERGED')
808 self.assertEqual(A.reported, 2,
809 "A should report start and success")
810 self.assertIn('tenant-one-gate', A.messages[1],
811 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -0800812
James E. Blair3a098dd2017-10-04 14:37:29 -0700813 @skip("This test is useful, but not reliable")
814 def test_full_and_dynamic_reconfig(self):
815 self.executor_server.hold_jobs_in_build = True
816 in_repo_conf = textwrap.dedent(
817 """
818 - job:
819 name: project-test1
820
821 - project:
822 name: org/project
823 tenant-one-gate:
824 jobs:
825 - project-test1
826 """)
827
828 file_dict = {'.zuul.yaml': in_repo_conf}
829 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
830 files=file_dict)
831 A.addApproval('Code-Review', 2)
832 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
833 self.waitUntilSettled()
834 self.sched.reconfigure(self.config)
835 self.waitUntilSettled()
836
837 gc.collect()
838 pipelines = [obj for obj in gc.get_objects()
839 if isinstance(obj, zuul.model.Pipeline)]
840 self.assertEqual(len(pipelines), 4)
841
842 self.executor_server.hold_jobs_in_build = False
843 self.executor_server.release()
844 self.waitUntilSettled()
845
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700846 def test_dynamic_config(self):
847 in_repo_conf = textwrap.dedent(
848 """
849 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200850 name: project-test1
851
852 - job:
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700853 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700854 run: playbooks/project-test2.yaml
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700855
Tobias Henkel53aa2ad2017-12-22 09:59:45 +0100856 - job:
857 name: project-test3
858 run: playbooks/project-test2.yaml
859
860 # add a job by the short project name
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700861 - project:
862 name: org/project
863 tenant-one-gate:
864 jobs:
865 - project-test2
Tobias Henkel53aa2ad2017-12-22 09:59:45 +0100866
867 # add a job by the canonical project name
868 - project:
869 name: review.example.com/org/project
870 tenant-one-gate:
871 jobs:
872 - project-test3
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700873 """)
874
James E. Blairc73c73a2017-01-20 15:15:15 -0800875 in_repo_playbook = textwrap.dedent(
876 """
877 - hosts: all
878 tasks: []
879 """)
880
881 file_dict = {'.zuul.yaml': in_repo_conf,
882 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700883 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800884 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200885 A.addApproval('Code-Review', 2)
886 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700887 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700888 self.assertEqual(A.data['status'], 'MERGED')
889 self.assertEqual(A.reported, 2,
890 "A should report start and success")
891 self.assertIn('tenant-one-gate', A.messages[1],
892 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800893 self.assertHistory([
Tobias Henkel53aa2ad2017-12-22 09:59:45 +0100894 dict(name='project-test2', result='SUCCESS', changes='1,1'),
895 dict(name='project-test3', result='SUCCESS', changes='1,1'),
896 ], ordered=False)
James E. Blair646322f2017-01-27 15:50:34 -0800897
James E. Blairc2a5ed72017-02-20 14:12:01 -0500898 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800899 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500900
James E. Blair646322f2017-01-27 15:50:34 -0800901 # Now that the config change is landed, it should be live for
902 # subsequent changes.
903 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200904 B.addApproval('Code-Review', 2)
905 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair646322f2017-01-27 15:50:34 -0800906 self.waitUntilSettled()
907 self.assertEqual(self.getJobFromHistory('project-test2').result,
908 'SUCCESS')
909 self.assertHistory([
910 dict(name='project-test2', result='SUCCESS', changes='1,1'),
Tobias Henkel53aa2ad2017-12-22 09:59:45 +0100911 dict(name='project-test3', result='SUCCESS', changes='1,1'),
912 dict(name='project-test2', result='SUCCESS', changes='2,1'),
913 dict(name='project-test3', result='SUCCESS', changes='2,1'),
914 ], ordered=False)
James E. Blairc73c73a2017-01-20 15:15:15 -0800915
James E. Blair6bc10482017-10-20 11:28:53 -0700916 def test_dynamic_template(self):
James E. Blair2a664502017-10-27 11:39:33 -0700917 # Tests that a project can't update a template in another
918 # project.
James E. Blair6bc10482017-10-20 11:28:53 -0700919 in_repo_conf = textwrap.dedent(
920 """
921 - job:
922 name: project-test1
923
924 - project-template:
925 name: common-config-template
926 check:
927 jobs:
928 - project-test1
929
930 - project:
931 name: org/project
932 templates: [common-config-template]
933 """)
934
935 file_dict = {'.zuul.yaml': in_repo_conf}
936 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
937 files=file_dict)
938 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
939 self.waitUntilSettled()
James E. Blair2a664502017-10-27 11:39:33 -0700940
941 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
942 self.assertIn('Project template common-config-template '
943 'is already defined',
944 A.messages[0],
945 "A should have failed the check pipeline")
James E. Blair6bc10482017-10-20 11:28:53 -0700946
Tobias Henkelf02cf512017-07-21 22:55:34 +0200947 def test_dynamic_config_non_existing_job(self):
948 """Test that requesting a non existent job fails"""
949 in_repo_conf = textwrap.dedent(
950 """
951 - job:
952 name: project-test1
953
954 - project:
955 name: org/project
956 check:
957 jobs:
958 - non-existent-job
959 """)
960
961 in_repo_playbook = textwrap.dedent(
962 """
963 - hosts: all
964 tasks: []
965 """)
966
967 file_dict = {'.zuul.yaml': in_repo_conf,
968 'playbooks/project-test2.yaml': in_repo_playbook}
969 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
970 files=file_dict)
971 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
972 self.waitUntilSettled()
973 self.assertEqual(A.reported, 1,
974 "A should report failure")
975 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
976 self.assertIn('Job non-existent-job not defined', A.messages[0],
977 "A should have failed the check pipeline")
978 self.assertHistory([])
979
980 def test_dynamic_config_non_existing_job_in_template(self):
981 """Test that requesting a non existent job fails"""
982 in_repo_conf = textwrap.dedent(
983 """
984 - job:
985 name: project-test1
986
987 - project-template:
988 name: test-template
989 check:
990 jobs:
991 - non-existent-job
992
993 - project:
994 name: org/project
995 templates:
996 - test-template
997 """)
998
999 in_repo_playbook = textwrap.dedent(
1000 """
1001 - hosts: all
1002 tasks: []
1003 """)
1004
1005 file_dict = {'.zuul.yaml': in_repo_conf,
1006 'playbooks/project-test2.yaml': in_repo_playbook}
1007 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1008 files=file_dict)
1009 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1010 self.waitUntilSettled()
1011 self.assertEqual(A.reported, 1,
1012 "A should report failure")
1013 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
1014 self.assertIn('Job non-existent-job not defined', A.messages[0],
1015 "A should have failed the check pipeline")
1016 self.assertHistory([])
1017
Tobias Henkel0f714002017-06-30 23:30:52 +02001018 def test_dynamic_config_new_patchset(self):
1019 self.executor_server.hold_jobs_in_build = True
1020
1021 tenant = self.sched.abide.tenants.get('tenant-one')
1022 check_pipeline = tenant.layout.pipelines['check']
1023
1024 in_repo_conf = textwrap.dedent(
1025 """
1026 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +02001027 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001028 run: playbooks/project-test1.yaml
Tobias Henkelf02cf512017-07-21 22:55:34 +02001029
1030 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +02001031 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -07001032 run: playbooks/project-test2.yaml
Tobias Henkel0f714002017-06-30 23:30:52 +02001033
1034 - project:
1035 name: org/project
1036 check:
1037 jobs:
1038 - project-test2
1039 """)
1040
1041 in_repo_playbook = textwrap.dedent(
1042 """
1043 - hosts: all
1044 tasks: []
1045 """)
1046
1047 file_dict = {'.zuul.yaml': in_repo_conf,
1048 'playbooks/project-test2.yaml': in_repo_playbook}
1049 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1050 files=file_dict)
1051 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1052 self.waitUntilSettled()
1053
1054 items = check_pipeline.getAllItems()
1055 self.assertEqual(items[0].change.number, '1')
1056 self.assertEqual(items[0].change.patchset, '1')
1057 self.assertTrue(items[0].live)
1058
1059 in_repo_conf = textwrap.dedent(
1060 """
1061 - job:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +02001062 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001063 run: playbooks/project-test1.yaml
Tobias Henkel0ce7ec62017-07-21 22:50:17 +02001064
1065 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +02001066 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -07001067 run: playbooks/project-test2.yaml
Tobias Henkel0f714002017-06-30 23:30:52 +02001068
1069 - project:
1070 name: org/project
1071 check:
1072 jobs:
1073 - project-test1
1074 - project-test2
1075 """)
1076 file_dict = {'.zuul.yaml': in_repo_conf,
1077 'playbooks/project-test2.yaml': in_repo_playbook}
1078
1079 A.addPatchset(files=file_dict)
1080 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1081
1082 self.waitUntilSettled()
1083
1084 items = check_pipeline.getAllItems()
1085 self.assertEqual(items[0].change.number, '1')
1086 self.assertEqual(items[0].change.patchset, '2')
1087 self.assertTrue(items[0].live)
1088
1089 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +02001090 self.executor_server.release('project-test1')
1091 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +02001092 self.executor_server.release()
1093 self.waitUntilSettled()
1094
Tobias Henkel0ce7ec62017-07-21 22:50:17 +02001095 self.assertHistory([
1096 dict(name='project-test2', result='ABORTED', changes='1,1'),
1097 dict(name='project-test1', result='SUCCESS', changes='1,2'),
1098 dict(name='project-test2', result='SUCCESS', changes='1,2')])
1099
James E. Blairff555742017-02-19 11:34:27 -08001100 def test_in_repo_branch(self):
1101 in_repo_conf = textwrap.dedent(
1102 """
1103 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +02001104 name: project-test1
1105
1106 - job:
James E. Blairff555742017-02-19 11:34:27 -08001107 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -07001108 run: playbooks/project-test2.yaml
James E. Blairff555742017-02-19 11:34:27 -08001109
1110 - project:
1111 name: org/project
1112 tenant-one-gate:
1113 jobs:
1114 - project-test2
1115 """)
1116
1117 in_repo_playbook = textwrap.dedent(
1118 """
1119 - hosts: all
1120 tasks: []
1121 """)
1122
1123 file_dict = {'.zuul.yaml': in_repo_conf,
1124 'playbooks/project-test2.yaml': in_repo_playbook}
1125 self.create_branch('org/project', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -07001126 self.fake_gerrit.addEvent(
1127 self.fake_gerrit.getFakeBranchCreatedEvent(
1128 'org/project', 'stable'))
James E. Blair6069f2b2017-09-26 16:34:11 -07001129 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -08001130 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
1131 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001132 A.addApproval('Code-Review', 2)
1133 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -08001134 self.waitUntilSettled()
1135 self.assertEqual(A.data['status'], 'MERGED')
1136 self.assertEqual(A.reported, 2,
1137 "A should report start and success")
1138 self.assertIn('tenant-one-gate', A.messages[1],
1139 "A should transit tenant-one gate")
1140 self.assertHistory([
1141 dict(name='project-test2', result='SUCCESS', changes='1,1')])
1142 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -08001143 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -08001144
1145 # The config change should not affect master.
1146 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001147 B.addApproval('Code-Review', 2)
1148 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -08001149 self.waitUntilSettled()
1150 self.assertHistory([
1151 dict(name='project-test2', result='SUCCESS', changes='1,1'),
1152 dict(name='project-test1', result='SUCCESS', changes='2,1')])
1153
1154 # The config change should be live for further changes on
1155 # stable.
1156 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001157 C.addApproval('Code-Review', 2)
1158 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -08001159 self.waitUntilSettled()
1160 self.assertHistory([
1161 dict(name='project-test2', result='SUCCESS', changes='1,1'),
1162 dict(name='project-test1', result='SUCCESS', changes='2,1'),
1163 dict(name='project-test2', result='SUCCESS', changes='3,1')])
1164
James E. Blaira5a12492017-05-03 11:40:48 -07001165 def test_crd_dynamic_config_branch(self):
1166 # Test that we can create a job in one repo and be able to use
1167 # it from a different branch on a different repo.
1168
1169 self.create_branch('org/project1', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -07001170 self.fake_gerrit.addEvent(
1171 self.fake_gerrit.getFakeBranchCreatedEvent(
1172 'org/project1', 'stable'))
James E. Blaira5a12492017-05-03 11:40:48 -07001173
1174 in_repo_conf = textwrap.dedent(
1175 """
1176 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +02001177 name: project-test1
1178
1179 - job:
James E. Blaira5a12492017-05-03 11:40:48 -07001180 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -07001181 run: playbooks/project-test2.yaml
James E. Blaira5a12492017-05-03 11:40:48 -07001182
1183 - project:
1184 name: org/project
1185 check:
1186 jobs:
1187 - project-test2
1188 """)
1189
1190 in_repo_playbook = textwrap.dedent(
1191 """
1192 - hosts: all
1193 tasks: []
1194 """)
1195
1196 file_dict = {'.zuul.yaml': in_repo_conf,
1197 'playbooks/project-test2.yaml': in_repo_playbook}
1198 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1199 files=file_dict)
1200
1201 second_repo_conf = textwrap.dedent(
1202 """
1203 - project:
1204 name: org/project1
1205 check:
1206 jobs:
1207 - project-test2
1208 """)
1209
1210 second_file_dict = {'.zuul.yaml': second_repo_conf}
1211 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
1212 files=second_file_dict)
1213 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1214 B.subject, A.data['id'])
1215
1216 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1217 self.waitUntilSettled()
1218 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1219 self.waitUntilSettled()
1220
1221 self.assertEqual(A.reported, 1, "A should report")
1222 self.assertHistory([
1223 dict(name='project-test2', result='SUCCESS', changes='1,1'),
1224 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
1225 ])
1226
James E. Blair97043882017-09-06 15:51:17 -07001227 def test_yaml_list_error(self):
1228 in_repo_conf = textwrap.dedent(
1229 """
1230 job: foo
1231 """)
1232
1233 file_dict = {'.zuul.yaml': in_repo_conf}
1234 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1235 files=file_dict)
1236 A.addApproval('Code-Review', 2)
1237 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1238 self.waitUntilSettled()
1239
1240 self.assertEqual(A.data['status'], 'NEW')
1241 self.assertEqual(A.reported, 1,
1242 "A should report failure")
1243 self.assertIn('not a list', A.messages[0],
1244 "A should have a syntax error reported")
1245
1246 def test_yaml_dict_error(self):
1247 in_repo_conf = textwrap.dedent(
1248 """
1249 - job
1250 """)
1251
1252 file_dict = {'.zuul.yaml': in_repo_conf}
1253 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1254 files=file_dict)
1255 A.addApproval('Code-Review', 2)
1256 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1257 self.waitUntilSettled()
1258
1259 self.assertEqual(A.data['status'], 'NEW')
1260 self.assertEqual(A.reported, 1,
1261 "A should report failure")
1262 self.assertIn('not a dictionary', A.messages[0],
1263 "A should have a syntax error reported")
1264
James E. Blairec953e12017-12-11 11:56:18 -08001265 def test_yaml_duplicate_key_error(self):
1266 in_repo_conf = textwrap.dedent(
1267 """
1268 - job:
1269 name: foo
1270 name: bar
1271 """)
1272
1273 file_dict = {'.zuul.yaml': in_repo_conf}
1274 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1275 files=file_dict)
1276 A.addApproval('Code-Review', 2)
1277 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1278 self.waitUntilSettled()
1279
1280 self.assertEqual(A.data['status'], 'NEW')
1281 self.assertEqual(A.reported, 1,
1282 "A should report failure")
1283 self.assertIn('appears more than once', A.messages[0],
1284 "A should have a syntax error reported")
1285
James E. Blair97043882017-09-06 15:51:17 -07001286 def test_yaml_key_error(self):
1287 in_repo_conf = textwrap.dedent(
1288 """
1289 - job:
1290 name: project-test2
1291 """)
1292
1293 file_dict = {'.zuul.yaml': in_repo_conf}
1294 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1295 files=file_dict)
1296 A.addApproval('Code-Review', 2)
1297 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1298 self.waitUntilSettled()
1299
1300 self.assertEqual(A.data['status'], 'NEW')
1301 self.assertEqual(A.reported, 1,
1302 "A should report failure")
1303 self.assertIn('has more than one key', A.messages[0],
1304 "A should have a syntax error reported")
1305
1306 def test_yaml_unknown_error(self):
1307 in_repo_conf = textwrap.dedent(
1308 """
1309 - foobar:
1310 foo: bar
1311 """)
1312
1313 file_dict = {'.zuul.yaml': in_repo_conf}
1314 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1315 files=file_dict)
1316 A.addApproval('Code-Review', 2)
1317 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1318 self.waitUntilSettled()
1319
1320 self.assertEqual(A.data['status'], 'NEW')
1321 self.assertEqual(A.reported, 1,
1322 "A should report failure")
1323 self.assertIn('not recognized', A.messages[0],
1324 "A should have a syntax error reported")
1325
James E. Blair149b69c2017-03-02 10:48:16 -08001326 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -08001327 in_repo_conf = textwrap.dedent(
1328 """
1329 - job:
1330 name: project-test2
1331 foo: error
1332 """)
1333
1334 file_dict = {'.zuul.yaml': in_repo_conf}
1335 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1336 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001337 A.addApproval('Code-Review', 2)
1338 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -08001339 self.waitUntilSettled()
1340
1341 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001342 self.assertEqual(A.reported, 1,
1343 "A should report failure")
1344 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -08001345 "A should have a syntax error reported")
1346
James E. Blair149b69c2017-03-02 10:48:16 -08001347 def test_trusted_syntax_error(self):
1348 in_repo_conf = textwrap.dedent(
1349 """
1350 - job:
1351 name: project-test2
1352 foo: error
1353 """)
1354
1355 file_dict = {'zuul.yaml': in_repo_conf}
1356 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1357 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001358 A.addApproval('Code-Review', 2)
1359 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -08001360 self.waitUntilSettled()
1361
1362 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001363 self.assertEqual(A.reported, 1,
1364 "A should report failure")
1365 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -08001366 "A should have a syntax error reported")
1367
James E. Blair6f140c72017-03-03 10:32:07 -08001368 def test_untrusted_yaml_error(self):
1369 in_repo_conf = textwrap.dedent(
1370 """
1371 - job:
1372 foo: error
1373 """)
1374
1375 file_dict = {'.zuul.yaml': in_repo_conf}
1376 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1377 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001378 A.addApproval('Code-Review', 2)
1379 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -08001380 self.waitUntilSettled()
1381
1382 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001383 self.assertEqual(A.reported, 1,
1384 "A should report failure")
1385 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -08001386 "A should have a syntax error reported")
1387
James E. Blairdb04e6a2017-05-03 14:49:36 -07001388 def test_untrusted_shadow_error(self):
1389 in_repo_conf = textwrap.dedent(
1390 """
1391 - job:
1392 name: common-config-test
1393 """)
1394
1395 file_dict = {'.zuul.yaml': in_repo_conf}
1396 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1397 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001398 A.addApproval('Code-Review', 2)
1399 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -07001400 self.waitUntilSettled()
1401
1402 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001403 self.assertEqual(A.reported, 1,
1404 "A should report failure")
1405 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -07001406 "A should have a syntax error reported")
1407
James E. Blaird5656ad2017-06-02 14:29:41 -07001408 def test_untrusted_pipeline_error(self):
1409 in_repo_conf = textwrap.dedent(
1410 """
1411 - pipeline:
1412 name: test
1413 """)
1414
1415 file_dict = {'.zuul.yaml': in_repo_conf}
1416 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1417 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001418 A.addApproval('Code-Review', 2)
1419 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -07001420 self.waitUntilSettled()
1421
1422 self.assertEqual(A.data['status'], 'NEW')
1423 self.assertEqual(A.reported, 1,
1424 "A should report failure")
1425 self.assertIn('Pipelines may not be defined', A.messages[0],
1426 "A should have a syntax error reported")
1427
1428 def test_untrusted_project_error(self):
1429 in_repo_conf = textwrap.dedent(
1430 """
1431 - project:
1432 name: org/project1
1433 """)
1434
1435 file_dict = {'.zuul.yaml': in_repo_conf}
1436 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1437 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001438 A.addApproval('Code-Review', 2)
1439 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -07001440 self.waitUntilSettled()
1441
1442 self.assertEqual(A.data['status'], 'NEW')
1443 self.assertEqual(A.reported, 1,
1444 "A should report failure")
1445 self.assertIn('the only project definition permitted', A.messages[0],
1446 "A should have a syntax error reported")
1447
James E. Blairf03173b2017-10-10 10:46:43 -07001448 def test_untrusted_depends_on_trusted(self):
1449 with open(os.path.join(FIXTURE_DIR,
1450 'config/in-repo/git/',
1451 'common-config/zuul.yaml')) as f:
1452 common_config = f.read()
1453
1454 common_config += textwrap.dedent(
1455 """
1456 - job:
1457 name: project-test9
1458 """)
1459
1460 file_dict = {'zuul.yaml': common_config}
1461 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1462 files=file_dict)
1463 in_repo_conf = textwrap.dedent(
1464 """
1465 - job:
1466 name: project-test1
1467 - project:
1468 name: org/project
1469 check:
1470 jobs:
1471 - project-test9
1472 """)
1473
1474 file_dict = {'zuul.yaml': in_repo_conf}
1475 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1476 files=file_dict)
1477 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1478 B.subject, A.data['id'])
1479 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1480 self.waitUntilSettled()
1481
1482 self.assertEqual(B.data['status'], 'NEW')
1483 self.assertEqual(B.reported, 1,
1484 "B should report failure")
1485 self.assertIn('depends on a change to a config project',
1486 B.messages[0],
1487 "A should have a syntax error reported")
1488
James E. Blaire64b0e42017-06-08 11:23:34 -07001489 def test_duplicate_node_error(self):
1490 in_repo_conf = textwrap.dedent(
1491 """
1492 - nodeset:
1493 name: duplicate
1494 nodes:
1495 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001496 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001497 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001498 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001499 """)
1500
1501 file_dict = {'.zuul.yaml': in_repo_conf}
1502 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1503 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001504 A.addApproval('Code-Review', 2)
1505 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -07001506 self.waitUntilSettled()
1507
1508 self.assertEqual(A.data['status'], 'NEW')
1509 self.assertEqual(A.reported, 1,
1510 "A should report failure")
1511 self.assertIn('appears multiple times', A.messages[0],
1512 "A should have a syntax error reported")
1513
1514 def test_duplicate_group_error(self):
1515 in_repo_conf = textwrap.dedent(
1516 """
1517 - nodeset:
1518 name: duplicate
1519 nodes:
1520 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001521 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001522 groups:
1523 - name: group
1524 nodes: compute
1525 - name: group
1526 nodes: compute
1527 """)
1528
1529 file_dict = {'.zuul.yaml': in_repo_conf}
1530 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1531 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001532 A.addApproval('Code-Review', 2)
1533 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -07001534 self.waitUntilSettled()
1535
1536 self.assertEqual(A.data['status'], 'NEW')
1537 self.assertEqual(A.reported, 1,
1538 "A should report failure")
1539 self.assertIn('appears multiple times', A.messages[0],
1540 "A should have a syntax error reported")
1541
James E. Blair4ae399f2017-09-20 17:15:09 -07001542 def test_secret_not_found_error(self):
1543 in_repo_conf = textwrap.dedent(
1544 """
1545 - job:
1546 name: test
1547 secrets: does-not-exist
1548 """)
1549
1550 file_dict = {'.zuul.yaml': in_repo_conf}
1551 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1552 files=file_dict)
1553 A.addApproval('Code-Review', 2)
1554 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1555 self.waitUntilSettled()
1556
1557 self.assertEqual(A.data['status'], 'NEW')
1558 self.assertEqual(A.reported, 1,
1559 "A should report failure")
1560 self.assertIn('secret "does-not-exist" was not found', A.messages[0],
1561 "A should have a syntax error reported")
1562
1563 def test_nodeset_not_found_error(self):
1564 in_repo_conf = textwrap.dedent(
1565 """
1566 - job:
1567 name: test
1568 nodeset: does-not-exist
1569 """)
1570
1571 file_dict = {'.zuul.yaml': in_repo_conf}
1572 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1573 files=file_dict)
1574 A.addApproval('Code-Review', 2)
1575 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1576 self.waitUntilSettled()
1577
1578 self.assertEqual(A.data['status'], 'NEW')
1579 self.assertEqual(A.reported, 1,
1580 "A should report failure")
1581 self.assertIn('nodeset "does-not-exist" was not found', A.messages[0],
1582 "A should have a syntax error reported")
1583
James E. Blair89e25eb2017-09-26 09:11:31 -07001584 def test_template_not_found_error(self):
1585 in_repo_conf = textwrap.dedent(
1586 """
1587 - job:
1588 name: project-test1
1589 - project:
1590 name: org/project
1591 templates:
1592 - does-not-exist
1593 """)
1594
1595 file_dict = {'.zuul.yaml': in_repo_conf}
1596 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1597 files=file_dict)
1598 A.addApproval('Code-Review', 2)
1599 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1600 self.waitUntilSettled()
1601
1602 self.assertEqual(A.data['status'], 'NEW')
1603 self.assertEqual(A.reported, 1,
1604 "A should report failure")
1605 self.assertIn('project template "does-not-exist" was not found',
1606 A.messages[0],
1607 "A should have a syntax error reported")
1608
Monty Taylor8be3c0c2017-10-06 10:37:37 -05001609 def test_job_list_in_project_template_not_dict_error(self):
1610 in_repo_conf = textwrap.dedent(
1611 """
1612 - job:
1613 name: project-test1
1614 - project-template:
1615 name: some-jobs
1616 check:
1617 jobs:
1618 - project-test1:
1619 - required-projects:
1620 org/project2
1621 """)
1622
1623 file_dict = {'.zuul.yaml': in_repo_conf}
1624 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1625 files=file_dict)
1626 A.addApproval('Code-Review', 2)
1627 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1628 self.waitUntilSettled()
1629
1630 self.assertEqual(A.data['status'], 'NEW')
1631 self.assertEqual(A.reported, 1,
1632 "A should report failure")
1633 self.assertIn('expected str for dictionary value',
1634 A.messages[0], "A should have a syntax error reported")
1635
1636 def test_job_list_in_project_not_dict_error(self):
1637 in_repo_conf = textwrap.dedent(
1638 """
1639 - job:
1640 name: project-test1
1641 - project:
1642 name: org/project1
1643 check:
1644 jobs:
1645 - project-test1:
1646 - required-projects:
1647 org/project2
1648 """)
1649
1650 file_dict = {'.zuul.yaml': in_repo_conf}
1651 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1652 files=file_dict)
1653 A.addApproval('Code-Review', 2)
1654 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1655 self.waitUntilSettled()
1656
1657 self.assertEqual(A.data['status'], 'NEW')
1658 self.assertEqual(A.reported, 1,
1659 "A should report failure")
1660 self.assertIn('expected str for dictionary value',
1661 A.messages[0], "A should have a syntax error reported")
1662
James E. Blair1235f142017-10-07 09:11:43 -07001663 def test_project_template(self):
1664 # Tests that a project template is not modified when used, and
1665 # can therefore be used in subsequent reconfigurations.
1666 in_repo_conf = textwrap.dedent(
1667 """
1668 - job:
1669 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001670 run: playbooks/project-test1.yaml
James E. Blair1235f142017-10-07 09:11:43 -07001671 - project-template:
1672 name: some-jobs
1673 tenant-one-gate:
1674 jobs:
1675 - project-test1:
1676 required-projects:
1677 - org/project1
1678 - project:
1679 name: org/project
1680 templates:
1681 - some-jobs
1682 """)
1683
1684 file_dict = {'.zuul.yaml': in_repo_conf}
1685 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1686 files=file_dict)
1687 A.addApproval('Code-Review', 2)
1688 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1689 self.waitUntilSettled()
1690 self.assertEqual(A.data['status'], 'MERGED')
1691 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1692 self.waitUntilSettled()
1693 in_repo_conf = textwrap.dedent(
1694 """
1695 - project:
1696 name: org/project1
1697 templates:
1698 - some-jobs
1699 """)
1700 file_dict = {'.zuul.yaml': in_repo_conf}
1701 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
1702 files=file_dict)
1703 B.addApproval('Code-Review', 2)
1704 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1705 self.waitUntilSettled()
1706 self.assertEqual(B.data['status'], 'MERGED')
1707
James E. Blairbccdfcf2017-10-07 13:37:26 -07001708 def test_job_remove_add(self):
1709 # Tests that a job can be removed from one repo and added in another.
1710 # First, remove the current config for project1 since it
1711 # references the job we want to remove.
1712 file_dict = {'.zuul.yaml': None}
1713 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1714 files=file_dict)
1715 A.setMerged()
1716 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1717 self.waitUntilSettled()
1718 # Then propose a change to delete the job from one repo...
1719 file_dict = {'.zuul.yaml': None}
1720 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1721 files=file_dict)
1722 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1723 self.waitUntilSettled()
1724 # ...and a second that depends on it that adds it to another repo.
1725 in_repo_conf = textwrap.dedent(
1726 """
1727 - job:
1728 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001729 run: playbooks/project-test1.yaml
James E. Blairbccdfcf2017-10-07 13:37:26 -07001730
1731 - project:
1732 name: org/project1
1733 check:
1734 jobs:
1735 - project-test1
1736 """)
1737 in_repo_playbook = textwrap.dedent(
1738 """
1739 - hosts: all
1740 tasks: []
1741 """)
1742 file_dict = {'.zuul.yaml': in_repo_conf,
1743 'playbooks/project-test1.yaml': in_repo_playbook}
1744 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C',
1745 files=file_dict,
1746 parent='refs/changes/1/1/1')
1747 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1748 C.subject, B.data['id'])
1749 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1750 self.waitUntilSettled()
1751 self.assertHistory([
1752 dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'),
1753 ], ordered=False)
1754
James E. Blair09f9ffe2017-07-11 15:30:25 -07001755 def test_multi_repo(self):
1756 downstream_repo_conf = textwrap.dedent(
1757 """
1758 - project:
1759 name: org/project1
1760 tenant-one-gate:
1761 jobs:
1762 - project-test1
1763
1764 - job:
1765 name: project1-test1
1766 parent: project-test1
1767 """)
1768
1769 file_dict = {'.zuul.yaml': downstream_repo_conf}
1770 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1771 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001772 A.addApproval('Code-Review', 2)
1773 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001774 self.waitUntilSettled()
1775
1776 self.assertEqual(A.data['status'], 'MERGED')
1777 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1778 self.waitUntilSettled()
1779
1780 upstream_repo_conf = textwrap.dedent(
1781 """
1782 - job:
1783 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001784 run: playbooks/project-test1.yaml
James E. Blair09f9ffe2017-07-11 15:30:25 -07001785
1786 - job:
1787 name: project-test2
1788
1789 - project:
1790 name: org/project
1791 tenant-one-gate:
1792 jobs:
1793 - project-test1
1794 """)
1795
1796 file_dict = {'.zuul.yaml': upstream_repo_conf}
1797 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1798 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001799 B.addApproval('Code-Review', 2)
1800 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001801 self.waitUntilSettled()
1802
1803 self.assertEqual(B.data['status'], 'MERGED')
1804 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
1805 self.waitUntilSettled()
1806
1807 tenant = self.sched.abide.tenants.get('tenant-one')
1808 # Ensure the latest change is reflected in the config; if it
1809 # isn't this will raise an exception.
1810 tenant.layout.getJob('project-test2')
1811
James E. Blair332636e2017-09-05 10:14:35 -07001812 def test_pipeline_error(self):
1813 with open(os.path.join(FIXTURE_DIR,
1814 'config/in-repo/git/',
1815 'common-config/zuul.yaml')) as f:
1816 base_common_config = f.read()
1817
1818 in_repo_conf_A = textwrap.dedent(
1819 """
1820 - pipeline:
1821 name: periodic
1822 foo: error
1823 """)
1824
1825 file_dict = {'zuul.yaml': None,
1826 'zuul.d/main.yaml': base_common_config,
1827 'zuul.d/test1.yaml': in_repo_conf_A}
1828 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1829 files=file_dict)
1830 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1831 self.waitUntilSettled()
1832 self.assertEqual(A.reported, 1,
1833 "A should report failure")
1834 self.assertIn('syntax error',
1835 A.messages[0],
1836 "A should have an error reported")
1837
1838 def test_change_series_error(self):
1839 with open(os.path.join(FIXTURE_DIR,
1840 'config/in-repo/git/',
1841 'common-config/zuul.yaml')) as f:
1842 base_common_config = f.read()
1843
1844 in_repo_conf_A = textwrap.dedent(
1845 """
1846 - pipeline:
1847 name: periodic
1848 foo: error
1849 """)
1850
1851 file_dict = {'zuul.yaml': None,
1852 'zuul.d/main.yaml': base_common_config,
1853 'zuul.d/test1.yaml': in_repo_conf_A}
1854 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1855 files=file_dict)
1856
1857 in_repo_conf_B = textwrap.dedent(
1858 """
1859 - job:
1860 name: project-test2
1861 foo: error
1862 """)
1863
1864 file_dict = {'zuul.yaml': None,
1865 'zuul.d/main.yaml': base_common_config,
1866 'zuul.d/test1.yaml': in_repo_conf_A,
1867 'zuul.d/test2.yaml': in_repo_conf_B}
1868 B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B',
1869 files=file_dict)
1870 B.setDependsOn(A, 1)
1871 C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C')
1872 C.setDependsOn(B, 1)
1873 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1874 self.waitUntilSettled()
1875
1876 self.assertEqual(C.reported, 1,
1877 "C should report failure")
1878 self.assertIn('depends on a change that failed to merge',
1879 C.messages[0],
1880 "C should have an error reported")
1881
James E. Blair1ef8f7c2017-12-13 17:18:34 -08001882 def test_pipeline_debug(self):
1883 in_repo_conf = textwrap.dedent(
1884 """
1885 - job:
1886 name: project-test1
1887 run: playbooks/project-test1.yaml
1888 - project:
1889 name: org/project
1890 check:
1891 debug: True
1892 jobs:
1893 - project-test1
1894 """)
1895
1896 file_dict = {'.zuul.yaml': in_repo_conf}
1897 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1898 files=file_dict)
1899 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1900 self.waitUntilSettled()
1901
1902 self.assertEqual(A.data['status'], 'NEW')
1903 self.assertEqual(A.reported, 1,
1904 "A should report success")
1905 self.assertIn('Debug information:',
1906 A.messages[0], "A should have debug info")
1907
James E. Blairc73c73a2017-01-20 15:15:15 -08001908
James E. Blairc9455002017-09-06 09:22:19 -07001909class TestInRepoJoin(ZuulTestCase):
1910 # In this config, org/project is not a member of any pipelines, so
1911 # that we may test the changes that cause it to join them.
1912
1913 tenant_config_file = 'config/in-repo-join/main.yaml'
1914
1915 def test_dynamic_dependent_pipeline(self):
1916 # Test dynamically adding a project to a
1917 # dependent pipeline for the first time
1918 self.executor_server.hold_jobs_in_build = True
1919
1920 tenant = self.sched.abide.tenants.get('tenant-one')
1921 gate_pipeline = tenant.layout.pipelines['gate']
1922
1923 in_repo_conf = textwrap.dedent(
1924 """
1925 - job:
1926 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001927 run: playbooks/project-test1.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001928
1929 - job:
1930 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -07001931 run: playbooks/project-test2.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001932
1933 - project:
1934 name: org/project
1935 gate:
1936 jobs:
1937 - project-test2
1938 """)
1939
1940 in_repo_playbook = textwrap.dedent(
1941 """
1942 - hosts: all
1943 tasks: []
1944 """)
1945
1946 file_dict = {'.zuul.yaml': in_repo_conf,
1947 'playbooks/project-test2.yaml': in_repo_playbook}
1948 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1949 files=file_dict)
1950 A.addApproval('Code-Review', 2)
1951 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1952 self.waitUntilSettled()
1953
1954 items = gate_pipeline.getAllItems()
1955 self.assertEqual(items[0].change.number, '1')
1956 self.assertEqual(items[0].change.patchset, '1')
1957 self.assertTrue(items[0].live)
1958
1959 self.executor_server.hold_jobs_in_build = False
1960 self.executor_server.release()
1961 self.waitUntilSettled()
1962
1963 # Make sure the dynamic queue got cleaned up
1964 self.assertEqual(gate_pipeline.queues, [])
1965
1966 def test_dynamic_dependent_pipeline_failure(self):
1967 # Test that a change behind a failing change adding a project
1968 # to a dependent pipeline is dequeued.
1969 self.executor_server.hold_jobs_in_build = True
1970
1971 in_repo_conf = textwrap.dedent(
1972 """
1973 - job:
1974 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001975 run: playbooks/project-test1.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001976
1977 - project:
1978 name: org/project
1979 gate:
1980 jobs:
1981 - project-test1
1982 """)
1983
1984 file_dict = {'.zuul.yaml': in_repo_conf}
1985 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1986 files=file_dict)
1987 self.executor_server.failJob('project-test1', A)
1988 A.addApproval('Code-Review', 2)
1989 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1990 self.waitUntilSettled()
1991
1992 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1993 B.addApproval('Code-Review', 2)
1994 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1995 self.waitUntilSettled()
1996
James E. Blair3490c5d2017-09-07 08:33:23 -07001997 self.orderedRelease()
James E. Blairc9455002017-09-06 09:22:19 -07001998 self.waitUntilSettled()
1999 self.assertEqual(A.reported, 2,
2000 "A should report start and failure")
2001 self.assertEqual(A.data['status'], 'NEW')
2002 self.assertEqual(B.reported, 1,
2003 "B should report start")
2004 self.assertHistory([
2005 dict(name='project-test1', result='FAILURE', changes='1,1'),
James E. Blair3490c5d2017-09-07 08:33:23 -07002006 dict(name='project-test1', result='ABORTED', changes='1,1 2,1'),
James E. Blairc9455002017-09-06 09:22:19 -07002007 ], ordered=False)
2008
James E. Blair0af198f2017-09-06 09:52:35 -07002009 def test_dynamic_dependent_pipeline_absent(self):
2010 # Test that a series of dependent changes don't report merge
2011 # failures to a pipeline they aren't in.
2012 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2013 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2014 B.setDependsOn(A, 1)
2015
2016 A.addApproval('Code-Review', 2)
2017 A.addApproval('Approved', 1)
2018 B.addApproval('Code-Review', 2)
2019 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
2020 self.waitUntilSettled()
2021 self.assertEqual(A.reported, 0,
2022 "A should not report")
2023 self.assertEqual(A.data['status'], 'NEW')
2024 self.assertEqual(B.reported, 0,
2025 "B should not report")
2026 self.assertEqual(B.data['status'], 'NEW')
2027 self.assertHistory([])
2028
James E. Blairc9455002017-09-06 09:22:19 -07002029
James E. Blairc73c73a2017-01-20 15:15:15 -08002030class TestAnsible(AnsibleZuulTestCase):
2031 # A temporary class to hold new tests while others are disabled
2032
2033 tenant_config_file = 'config/ansible/main.yaml'
2034
2035 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +11002036 # Keep the jobdir around so we can inspect contents if an
2037 # assert fails.
2038 self.executor_server.keep_jobdir = True
2039 # Output extra ansible info so we might see errors.
2040 self.executor_server.verbose = True
2041 # Add a site variables file, used by check-vars
2042 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
2043 'variables.yaml')
2044 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -08002045 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2046 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2047 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +02002048 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +11002049 with self.jobLog(build_timeout):
2050 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Clark Boylanb2c22b32018-02-16 11:00:50 -08002051 post_flag_path = os.path.join(self.test_root, build_timeout.uuid +
2052 '.post.flag')
2053 self.assertTrue(os.path.exists(post_flag_path))
2054 build_post_timeout = self.getJobFromHistory('post-timeout')
2055 with self.jobLog(build_post_timeout):
2056 self.assertEqual(build_post_timeout.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02002057 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +11002058 with self.jobLog(build_faillocal):
2059 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02002060 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +11002061 with self.jobLog(build_failpost):
2062 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02002063 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +11002064 with self.jobLog(build_check_vars):
2065 self.assertEqual(build_check_vars.result, 'SUCCESS')
Monty Tayloraff8b402017-08-16 18:40:41 -05002066 build_check_secret_names = self.getJobFromHistory('check-secret-names')
2067 with self.jobLog(build_check_secret_names):
2068 self.assertEqual(build_check_secret_names.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02002069 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +11002070 with self.jobLog(build_hello):
2071 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02002072 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +11002073 with self.jobLog(build_python27):
2074 self.assertEqual(build_python27.result, 'SUCCESS')
2075 flag_path = os.path.join(self.test_root,
2076 build_python27.uuid + '.flag')
2077 self.assertTrue(os.path.exists(flag_path))
2078 copied_path = os.path.join(self.test_root, build_python27.uuid +
2079 '.copied')
2080 self.assertTrue(os.path.exists(copied_path))
2081 failed_path = os.path.join(self.test_root, build_python27.uuid +
2082 '.failed')
2083 self.assertFalse(os.path.exists(failed_path))
2084 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
2085 '.pre.flag')
2086 self.assertTrue(os.path.exists(pre_flag_path))
2087 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
2088 '.post.flag')
2089 self.assertTrue(os.path.exists(post_flag_path))
2090 bare_role_flag_path = os.path.join(self.test_root,
2091 build_python27.uuid +
2092 '.bare-role.flag')
2093 self.assertTrue(os.path.exists(bare_role_flag_path))
2094 secrets_path = os.path.join(self.test_root,
2095 build_python27.uuid + '.secrets')
2096 with open(secrets_path) as f:
2097 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -08002098
Jamie Lennox7655b552017-03-17 12:33:38 +11002099 msg = A.messages[0]
2100 success = "{} https://success.example.com/zuul-logs/{}"
2101 fail = "{} https://failure.example.com/zuul-logs/{}"
2102 self.assertIn(success.format("python27", build_python27.uuid), msg)
2103 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
2104 self.assertIn(success.format("check-vars",
2105 build_check_vars.uuid), msg)
2106 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
2107 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
2108 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +02002109
James E. Blairabbaa6f2017-04-06 16:11:44 -07002110 def _add_job(self, job_name):
2111 conf = textwrap.dedent(
2112 """
2113 - job:
2114 name: %s
James E. Blair2f589fe2017-10-26 12:57:41 -07002115 run: playbooks/%s.yaml
James E. Blairabbaa6f2017-04-06 16:11:44 -07002116
2117 - project:
2118 name: org/plugin-project
2119 check:
2120 jobs:
2121 - %s
James E. Blair2f589fe2017-10-26 12:57:41 -07002122 """ % (job_name, job_name, job_name))
James E. Blairabbaa6f2017-04-06 16:11:44 -07002123
2124 file_dict = {'.zuul.yaml': conf}
2125 A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A',
2126 files=file_dict)
2127 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2128 self.waitUntilSettled()
2129
2130 def test_plugins(self):
2131 # Keep the jobdir around so we can inspect contents if an
2132 # assert fails.
2133 self.executor_server.keep_jobdir = True
2134 # Output extra ansible info so we might see errors.
2135 self.executor_server.verbose = True
2136
2137 count = 0
2138 plugin_tests = [
2139 ('passwd', 'FAILURE'),
2140 ('cartesian', 'SUCCESS'),
2141 ('consul_kv', 'FAILURE'),
2142 ('credstash', 'FAILURE'),
2143 ('csvfile_good', 'SUCCESS'),
2144 ('csvfile_bad', 'FAILURE'),
Monty Taylor93ad2212017-08-02 14:59:50 -05002145 ('uri_bad_path', 'FAILURE'),
2146 ('uri_bad_scheme', 'FAILURE'),
Monty Taylor788a40e2017-08-02 16:14:05 -05002147 ('block_local_override', 'FAILURE'),
Monty Taylor8da768f2017-08-31 14:15:35 -05002148 ('file_local_good', 'SUCCESS'),
2149 ('file_local_bad', 'FAILURE'),
James E. Blairabbaa6f2017-04-06 16:11:44 -07002150 ]
2151 for job_name, result in plugin_tests:
2152 count += 1
2153 self._add_job(job_name)
2154
2155 job = self.getJobFromHistory(job_name)
2156 with self.jobLog(job):
2157 self.assertEqual(count, len(self.history))
2158 build = self.history[-1]
2159 self.assertEqual(build.result, result)
2160
2161 # TODOv3(jeblair): parse the ansible output and verify we're
2162 # getting the exception we expect.
2163
James E. Blairb9c0d772017-03-03 14:34:49 -08002164
James E. Blaira4d4eef2017-06-30 14:49:17 -07002165class TestPrePlaybooks(AnsibleZuulTestCase):
2166 # A temporary class to hold new tests while others are disabled
2167
2168 tenant_config_file = 'config/pre-playbook/main.yaml'
2169
2170 def test_pre_playbook_fail(self):
2171 # Test that we run the post playbooks (but not the actual
2172 # playbook) when a pre-playbook fails.
2173 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2174 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2175 self.waitUntilSettled()
2176 build = self.getJobFromHistory('python27')
2177 self.assertIsNone(build.result)
2178 self.assertIn('RETRY_LIMIT', A.messages[0])
2179 flag_path = os.path.join(self.test_root, build.uuid +
2180 '.main.flag')
2181 self.assertFalse(os.path.exists(flag_path))
2182 pre_flag_path = os.path.join(self.test_root, build.uuid +
2183 '.pre.flag')
2184 self.assertFalse(os.path.exists(pre_flag_path))
2185 post_flag_path = os.path.join(self.test_root, build.uuid +
2186 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -07002187 self.assertTrue(os.path.exists(post_flag_path),
2188 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -07002189
2190
James E. Blairbacbb882017-10-17 09:48:23 -07002191class TestPostPlaybooks(AnsibleZuulTestCase):
2192 tenant_config_file = 'config/post-playbook/main.yaml'
2193
2194 def test_post_playbook_abort(self):
2195 # Test that when we abort a job in the post playbook, that we
2196 # don't send back POST_FAILURE.
2197 self.executor_server.verbose = True
2198 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2199 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2200
2201 while not len(self.builds):
2202 time.sleep(0.1)
2203 build = self.builds[0]
2204
2205 post_start = os.path.join(self.test_root, build.uuid +
2206 '.post_start.flag')
2207 start = time.time()
2208 while time.time() < start + 90:
2209 if os.path.exists(post_start):
2210 break
2211 time.sleep(0.1)
2212 # The post playbook has started, abort the job
2213 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
2214 self.waitUntilSettled()
2215
2216 build = self.getJobFromHistory('python27')
2217 self.assertEqual('ABORTED', build.result)
2218
2219 post_end = os.path.join(self.test_root, build.uuid +
2220 '.post_end.flag')
2221 self.assertTrue(os.path.exists(post_start))
2222 self.assertFalse(os.path.exists(post_end))
2223
2224
James E. Blairb9c0d772017-03-03 14:34:49 -08002225class TestBrokenConfig(ZuulTestCase):
2226 # Test that we get an appropriate syntax error if we start with a
2227 # broken config.
2228
2229 tenant_config_file = 'config/broken/main.yaml'
2230
2231 def setUp(self):
2232 with testtools.ExpectedException(
2233 zuul.configloader.ConfigurationSyntaxError,
2234 "\nZuul encountered a syntax error"):
2235 super(TestBrokenConfig, self).setUp()
2236
2237 def test_broken_config_on_startup(self):
2238 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00002239
2240
2241class TestProjectKeys(ZuulTestCase):
2242 # Test that we can generate project keys
2243
2244 # Normally the test infrastructure copies a static key in place
2245 # for each project before starting tests. This saves time because
2246 # Zuul's automatic key-generation on startup can be slow. To make
2247 # sure we exercise that code, in this test we allow Zuul to create
2248 # keys for the project on startup.
2249 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +02002250 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00002251 tenant_config_file = 'config/in-repo/main.yaml'
2252
2253 def test_key_generation(self):
2254 key_root = os.path.join(self.state_root, 'keys')
2255 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
2256 # Make sure that a proper key was created on startup
2257 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -07002258 private_key, public_key = \
2259 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00002260
2261 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
2262 fixture_private_key = i.read()
2263
2264 # Make sure that we didn't just end up with the static fixture
2265 # key
2266 self.assertNotEqual(fixture_private_key, private_key)
2267
2268 # Make sure it's the right length
2269 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -07002270
2271
James E. Blairbb94dfa2017-07-11 07:45:19 -07002272class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -07002273 def _assertRolePath(self, build, playbook, content):
2274 path = os.path.join(self.test_root, build.uuid,
2275 'ansible', playbook, 'ansible.cfg')
2276 roles_paths = []
2277 with open(path) as f:
2278 for line in f:
2279 if line.startswith('roles_path'):
2280 roles_paths.append(line)
2281 print(roles_paths)
2282 if content:
2283 self.assertEqual(len(roles_paths), 1,
2284 "Should have one roles_path line in %s" %
2285 (playbook,))
2286 self.assertIn(content, roles_paths[0])
2287 else:
2288 self.assertEqual(len(roles_paths), 0,
2289 "Should have no roles_path line in %s" %
2290 (playbook,))
2291
James E. Blairbb94dfa2017-07-11 07:45:19 -07002292
2293class TestRoles(RoleTestCase):
2294 tenant_config_file = 'config/roles/main.yaml'
2295
James E. Blairbce76932017-05-04 10:03:15 -07002296 def test_role(self):
2297 # This exercises a proposed change to a role being checked out
2298 # and used.
2299 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
2300 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2301 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
2302 B.subject, A.data['id'])
2303 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2304 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2305 self.waitUntilSettled()
2306 self.assertHistory([
2307 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
2308 ])
James E. Blair6459db12017-06-29 14:57:20 -07002309
James E. Blair1b27f6a2017-07-14 14:09:07 -07002310 def test_role_inheritance(self):
2311 self.executor_server.hold_jobs_in_build = True
2312 conf = textwrap.dedent(
2313 """
2314 - job:
2315 name: parent
2316 roles:
2317 - zuul: bare-role
Ian Wienand548c43c2017-12-05 14:16:32 +11002318 pre-run: playbooks/parent-pre.yaml
2319 post-run: playbooks/parent-post.yaml
James E. Blair1b27f6a2017-07-14 14:09:07 -07002320
2321 - job:
2322 name: project-test
2323 parent: parent
James E. Blair2f589fe2017-10-26 12:57:41 -07002324 run: playbooks/project-test.yaml
James E. Blair1b27f6a2017-07-14 14:09:07 -07002325 roles:
2326 - zuul: org/project
2327
2328 - project:
2329 name: org/project
2330 check:
2331 jobs:
2332 - project-test
2333 """)
2334
2335 file_dict = {'.zuul.yaml': conf}
2336 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2337 files=file_dict)
2338 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2339 self.waitUntilSettled()
2340
2341 self.assertEqual(len(self.builds), 1)
2342 build = self.getBuildByName('project-test')
2343 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
2344 self._assertRolePath(build, 'playbook_0', 'role_0')
2345 self._assertRolePath(build, 'playbook_0', 'role_1')
2346 self._assertRolePath(build, 'post_playbook_0', 'role_0')
2347
2348 self.executor_server.hold_jobs_in_build = False
2349 self.executor_server.release()
2350 self.waitUntilSettled()
2351
2352 self.assertHistory([
2353 dict(name='project-test', result='SUCCESS', changes='1,1'),
2354 ])
2355
James E. Blair6f699732017-07-18 14:19:11 -07002356 def test_role_error(self):
2357 conf = textwrap.dedent(
2358 """
2359 - job:
2360 name: project-test
James E. Blair2f589fe2017-10-26 12:57:41 -07002361 run: playbooks/project-test.yaml
James E. Blair6f699732017-07-18 14:19:11 -07002362 roles:
2363 - zuul: common-config
2364
2365 - project:
2366 name: org/project
2367 check:
2368 jobs:
2369 - project-test
2370 """)
2371
2372 file_dict = {'.zuul.yaml': conf}
2373 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2374 files=file_dict)
2375 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2376 self.waitUntilSettled()
2377 self.assertIn(
2378 '- project-test project-test : ERROR Unable to find role',
2379 A.messages[-1])
2380
James E. Blair6459db12017-06-29 14:57:20 -07002381
James E. Blairbb94dfa2017-07-11 07:45:19 -07002382class TestImplicitRoles(RoleTestCase):
2383 tenant_config_file = 'config/implicit-roles/main.yaml'
2384
2385 def test_missing_roles(self):
2386 # Test implicit and explicit roles for a project which does
2387 # not have roles. The implicit role should be silently
2388 # ignored since the project doesn't supply roles, but if a
2389 # user declares an explicit role, it should error.
2390 self.executor_server.hold_jobs_in_build = True
2391 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
2392 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2393 self.waitUntilSettled()
2394
2395 self.assertEqual(len(self.builds), 2)
2396 build = self.getBuildByName('implicit-role-fail')
2397 self._assertRolePath(build, 'playbook_0', None)
2398
2399 self.executor_server.hold_jobs_in_build = False
2400 self.executor_server.release()
2401 self.waitUntilSettled()
2402 # The retry_limit doesn't get recorded
2403 self.assertHistory([
2404 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
2405 ])
2406
2407 def test_roles(self):
2408 # Test implicit and explicit roles for a project which does
2409 # have roles. In both cases, we should end up with the role
2410 # in the path. In the explicit case, ensure we end up with
2411 # the name we specified.
2412 self.executor_server.hold_jobs_in_build = True
2413 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
2414 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2415 self.waitUntilSettled()
2416
2417 self.assertEqual(len(self.builds), 2)
2418 build = self.getBuildByName('implicit-role-ok')
2419 self._assertRolePath(build, 'playbook_0', 'role_0')
2420
2421 build = self.getBuildByName('explicit-role-ok')
2422 self._assertRolePath(build, 'playbook_0', 'role_0')
2423
2424 self.executor_server.hold_jobs_in_build = False
2425 self.executor_server.release()
2426 self.waitUntilSettled()
2427 self.assertHistory([
2428 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
2429 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
2430 ], ordered=False)
2431
2432
James E. Blair6459db12017-06-29 14:57:20 -07002433class TestShadow(ZuulTestCase):
2434 tenant_config_file = 'config/shadow/main.yaml'
2435
2436 def test_shadow(self):
2437 # Test that a repo is allowed to shadow another's job definitions.
2438 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2439 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2440 self.waitUntilSettled()
2441 self.assertHistory([
2442 dict(name='test1', result='SUCCESS', changes='1,1'),
2443 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -07002444 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -07002445
2446
2447class TestDataReturn(AnsibleZuulTestCase):
2448 tenant_config_file = 'config/data-return/main.yaml'
2449
2450 def test_data_return(self):
James E. Blair196f61a2017-06-30 15:42:29 -07002451 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2452 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2453 self.waitUntilSettled()
2454 self.assertHistory([
2455 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07002456 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
James E. Blair698703c2017-09-15 20:58:30 -06002457 dict(name='child', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07002458 ], ordered=False)
2459 self.assertIn('- data-return http://example.com/test/log/url/',
2460 A.messages[-1])
2461 self.assertIn('- data-return-relative '
2462 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -07002463 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -07002464
2465
2466class TestDiskAccounting(AnsibleZuulTestCase):
2467 config_file = 'zuul-disk-accounting.conf'
2468 tenant_config_file = 'config/disk-accountant/main.yaml'
2469
2470 def test_disk_accountant_kills_job(self):
2471 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2472 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2473 self.waitUntilSettled()
2474 self.assertHistory([
2475 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002476
2477
2478class TestMaxNodesPerJob(AnsibleZuulTestCase):
2479 tenant_config_file = 'config/multi-tenant/main.yaml'
2480
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00002481 def test_max_timeout_exceeded(self):
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002482 in_repo_conf = textwrap.dedent(
2483 """
2484 - job:
2485 name: test-job
James E. Blair7e3e6882017-09-20 15:47:13 -07002486 nodeset:
2487 nodes:
2488 - name: node01
2489 label: fake
2490 - name: node02
2491 label: fake
2492 - name: node03
2493 label: fake
2494 - name: node04
2495 label: fake
2496 - name: node05
2497 label: fake
2498 - name: node06
2499 label: fake
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002500 """)
2501 file_dict = {'.zuul.yaml': in_repo_conf}
2502 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2503 files=file_dict)
2504 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2505 self.waitUntilSettled()
2506 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
2507 A.messages[0], "A should fail because of nodes limit")
2508
2509 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2510 files=file_dict)
2511 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2512 self.waitUntilSettled()
2513 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
2514 "B should not fail because of nodes limit")
James E. Blair2bab6e72017-08-07 09:52:45 -07002515
2516
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00002517class TestMaxTimeout(AnsibleZuulTestCase):
2518 tenant_config_file = 'config/multi-tenant/main.yaml'
2519
2520 def test_max_nodes_reached(self):
2521 in_repo_conf = textwrap.dedent(
2522 """
2523 - job:
2524 name: test-job
2525 timeout: 3600
2526 """)
2527 file_dict = {'.zuul.yaml': in_repo_conf}
2528 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2529 files=file_dict)
2530 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2531 self.waitUntilSettled()
2532 self.assertIn('The job "test-job" exceeds tenant max-job-timeout',
2533 A.messages[0], "A should fail because of timeout limit")
2534
2535 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2536 files=file_dict)
2537 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2538 self.waitUntilSettled()
2539 self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0],
2540 "B should not fail because of timeout limit")
2541
2542
James E. Blair7edc25f2017-10-26 10:47:14 -07002543class TestPragma(ZuulTestCase):
2544 tenant_config_file = 'config/pragma/main.yaml'
2545
2546 def test_no_pragma(self):
2547 self.create_branch('org/project', 'stable')
2548 with open(os.path.join(FIXTURE_DIR,
2549 'config/pragma/git/',
2550 'org_project/nopragma.yaml')) as f:
2551 config = f.read()
2552 file_dict = {'.zuul.yaml': config}
2553 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2554 files=file_dict)
2555 A.addApproval('Code-Review', 2)
2556 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2557 self.waitUntilSettled()
2558 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2559 self.waitUntilSettled()
2560
2561 # This is an untrusted repo with 2 branches, so it should have
2562 # an implied branch matcher for the job.
2563 tenant = self.sched.abide.tenants.get('tenant-one')
2564 jobs = tenant.layout.getJobs('test-job')
2565 self.assertEqual(len(jobs), 1)
2566 for job in tenant.layout.getJobs('test-job'):
2567 self.assertIsNotNone(job.branch_matcher)
2568
2569 def test_pragma(self):
2570 self.create_branch('org/project', 'stable')
2571 with open(os.path.join(FIXTURE_DIR,
2572 'config/pragma/git/',
2573 'org_project/pragma.yaml')) as f:
2574 config = f.read()
2575 file_dict = {'.zuul.yaml': config}
2576 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2577 files=file_dict)
2578 A.addApproval('Code-Review', 2)
2579 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2580 self.waitUntilSettled()
2581 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2582 self.waitUntilSettled()
2583
2584 # This is an untrusted repo with 2 branches, so it would
2585 # normally have an implied branch matcher, but our pragma
2586 # overrides it.
2587 tenant = self.sched.abide.tenants.get('tenant-one')
2588 jobs = tenant.layout.getJobs('test-job')
2589 self.assertEqual(len(jobs), 1)
2590 for job in tenant.layout.getJobs('test-job'):
2591 self.assertIsNone(job.branch_matcher)
2592
2593
James E. Blair37c3d8c2017-12-13 15:06:11 -08002594class TestPragmaMultibranch(ZuulTestCase):
2595 tenant_config_file = 'config/pragma-multibranch/main.yaml'
2596
2597 def test_no_branch_matchers(self):
2598 self.create_branch('org/project1', 'stable/pike')
2599 self.create_branch('org/project2', 'stable/jewel')
2600 self.fake_gerrit.addEvent(
2601 self.fake_gerrit.getFakeBranchCreatedEvent(
2602 'org/project1', 'stable/pike'))
2603 self.fake_gerrit.addEvent(
2604 self.fake_gerrit.getFakeBranchCreatedEvent(
2605 'org/project2', 'stable/jewel'))
2606 self.waitUntilSettled()
2607 # We want the jobs defined on the stable/pike branch of
2608 # project1 to apply to the stable/jewel branch of project2.
2609
2610 # First, without the pragma line, the jobs should not run
2611 # because in project1 they have branch matchers for pike, so
2612 # they will not match a jewel change.
2613 B = self.fake_gerrit.addFakeChange('org/project2', 'stable/jewel', 'B')
2614 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2615 self.waitUntilSettled()
2616 self.assertHistory([])
2617
2618 # Add a pragma line to disable implied branch matchers in
2619 # project1, so that the jobs and templates apply to both
2620 # branches.
2621 with open(os.path.join(FIXTURE_DIR,
2622 'config/pragma-multibranch/git/',
2623 'org_project1/zuul.yaml')) as f:
2624 config = f.read()
2625 extra_conf = textwrap.dedent(
2626 """
2627 - pragma:
2628 implied-branch-matchers: False
2629 """)
2630 config = extra_conf + config
2631 file_dict = {'zuul.yaml': config}
2632 A = self.fake_gerrit.addFakeChange('org/project1', 'stable/pike', 'A',
2633 files=file_dict)
2634 A.addApproval('Code-Review', 2)
2635 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2636 self.waitUntilSettled()
2637 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2638 self.waitUntilSettled()
2639
2640 # Now verify that when we propose a change to jewel, we get
2641 # the pike/jewel jobs.
2642 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2643 self.waitUntilSettled()
2644 self.assertHistory([
2645 dict(name='test-job1', result='SUCCESS', changes='1,1'),
2646 dict(name='test-job2', result='SUCCESS', changes='1,1'),
2647 ], ordered=False)
2648
2649 def test_supplied_branch_matchers(self):
2650 self.create_branch('org/project1', 'stable/pike')
2651 self.create_branch('org/project2', 'stable/jewel')
2652 self.fake_gerrit.addEvent(
2653 self.fake_gerrit.getFakeBranchCreatedEvent(
2654 'org/project1', 'stable/pike'))
2655 self.fake_gerrit.addEvent(
2656 self.fake_gerrit.getFakeBranchCreatedEvent(
2657 'org/project2', 'stable/jewel'))
2658 self.waitUntilSettled()
2659 # We want the jobs defined on the stable/pike branch of
2660 # project1 to apply to the stable/jewel branch of project2.
2661
2662 # First, without the pragma line, the jobs should not run
2663 # because in project1 they have branch matchers for pike, so
2664 # they will not match a jewel change.
2665 B = self.fake_gerrit.addFakeChange('org/project2', 'stable/jewel', 'B')
2666 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2667 self.waitUntilSettled()
2668 self.assertHistory([])
2669
2670 # Add a pragma line to disable implied branch matchers in
2671 # project1, so that the jobs and templates apply to both
2672 # branches.
2673 with open(os.path.join(FIXTURE_DIR,
2674 'config/pragma-multibranch/git/',
2675 'org_project1/zuul.yaml')) as f:
2676 config = f.read()
2677 extra_conf = textwrap.dedent(
2678 """
2679 - pragma:
2680 implied-branches:
2681 - stable/pike
2682 - stable/jewel
2683 """)
2684 config = extra_conf + config
2685 file_dict = {'zuul.yaml': config}
2686 A = self.fake_gerrit.addFakeChange('org/project1', 'stable/pike', 'A',
2687 files=file_dict)
2688 A.addApproval('Code-Review', 2)
2689 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2690 self.waitUntilSettled()
2691 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2692 self.waitUntilSettled()
2693 # Now verify that when we propose a change to jewel, we get
2694 # the pike/jewel jobs.
2695 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2696 self.waitUntilSettled()
2697 self.assertHistory([
2698 dict(name='test-job1', result='SUCCESS', changes='1,1'),
2699 dict(name='test-job2', result='SUCCESS', changes='1,1'),
2700 ], ordered=False)
2701
2702
James E. Blair2bab6e72017-08-07 09:52:45 -07002703class TestBaseJobs(ZuulTestCase):
2704 tenant_config_file = 'config/base-jobs/main.yaml'
2705
2706 def test_multiple_base_jobs(self):
2707 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2708 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2709 self.waitUntilSettled()
2710 self.assertHistory([
2711 dict(name='my-job', result='SUCCESS', changes='1,1'),
2712 dict(name='other-job', result='SUCCESS', changes='1,1'),
2713 ], ordered=False)
2714 self.assertEqual(self.getJobFromHistory('my-job').
2715 parameters['zuul']['jobtags'],
2716 ['mybase'])
2717 self.assertEqual(self.getJobFromHistory('other-job').
2718 parameters['zuul']['jobtags'],
2719 ['otherbase'])
2720
2721 def test_untrusted_base_job(self):
2722 """Test that a base job may not be defined in an untrusted repo"""
2723 in_repo_conf = textwrap.dedent(
2724 """
2725 - job:
2726 name: fail-base
2727 parent: null
2728 """)
2729
2730 file_dict = {'.zuul.yaml': in_repo_conf}
2731 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2732 files=file_dict)
2733 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2734 self.waitUntilSettled()
2735 self.assertEqual(A.reported, 1,
2736 "A should report failure")
2737 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
2738 self.assertIn('Base jobs must be defined in config projects',
2739 A.messages[0])
2740 self.assertHistory([])
James E. Blairdb089032017-08-15 13:42:12 -07002741
2742
James E. Blaira17a8e72018-01-17 13:45:25 -08002743class TestSecrets(ZuulTestCase):
2744 tenant_config_file = 'config/secrets/main.yaml'
2745 secret = {'password': 'test-password',
2746 'username': 'test-username'}
2747
2748 def _getSecrets(self, job, pbtype):
2749 secrets = []
2750 build = self.getJobFromHistory(job)
2751 for pb in build.parameters[pbtype]:
2752 secrets.append(pb['secrets'])
2753 return secrets
2754
2755 def test_secret_branch(self):
2756 # Test that we can use a secret defined in another branch of
2757 # the same project.
2758 self.create_branch('org/project2', 'stable')
2759 self.fake_gerrit.addEvent(
2760 self.fake_gerrit.getFakeBranchCreatedEvent(
2761 'org/project2', 'stable'))
2762 self.waitUntilSettled()
2763
2764 with open(os.path.join(FIXTURE_DIR,
2765 'config/secrets/git/',
2766 'org_project2/zuul-secret.yaml')) as f:
2767 config = f.read()
2768
2769 file_dict = {'zuul.yaml': config}
2770 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2771 files=file_dict)
2772 A.addApproval('Code-Review', 2)
2773 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2774 self.waitUntilSettled()
2775 self.assertEqual(A.data['status'], 'MERGED')
2776 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2777 self.waitUntilSettled()
2778
2779 in_repo_conf = textwrap.dedent(
2780 """
2781 - job:
2782 parent: base
2783 name: project2-secret
2784 run: playbooks/secret.yaml
2785 secrets: [project2_secret]
2786
2787 - project:
2788 check:
2789 jobs:
2790 - project2-secret
2791 gate:
2792 jobs:
2793 - noop
2794 """)
2795 file_dict = {'zuul.yaml': in_repo_conf}
2796 B = self.fake_gerrit.addFakeChange('org/project2', 'stable', 'B',
2797 files=file_dict)
2798 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2799 self.waitUntilSettled()
2800 self.assertEqual(B.reported, 1, "B should report success")
2801 self.assertHistory([
2802 dict(name='project2-secret', result='SUCCESS', changes='2,1'),
2803 ])
2804 self.assertEqual(
2805 self._getSecrets('project2-secret', 'playbooks'),
2806 [{'project2_secret': self.secret}])
2807
2808 def test_secret_branch_duplicate(self):
2809 # Test that we can create a duplicate secret on a different
2810 # branch of the same project -- i.e., that when we branch
2811 # master to stable on a project with a secret, nothing
2812 # changes.
2813 self.create_branch('org/project1', 'stable')
2814 self.fake_gerrit.addEvent(
2815 self.fake_gerrit.getFakeBranchCreatedEvent(
2816 'org/project1', 'stable'))
2817 self.waitUntilSettled()
2818
2819 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A')
2820 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2821 self.waitUntilSettled()
2822 self.assertEqual(A.reported, 1,
2823 "A should report success")
2824 self.assertHistory([
2825 dict(name='project1-secret', result='SUCCESS', changes='1,1'),
2826 ])
2827 self.assertEqual(
2828 self._getSecrets('project1-secret', 'playbooks'),
2829 [{'project1_secret': self.secret}])
2830
2831 def test_secret_branch_error_same_branch(self):
2832 # Test that we are unable to define a secret twice on the same
2833 # project-branch.
2834 in_repo_conf = textwrap.dedent(
2835 """
2836 - secret:
2837 name: project1_secret
2838 data: {}
2839 - secret:
2840 name: project1_secret
2841 data: {}
2842 """)
2843 file_dict = {'zuul.yaml': in_repo_conf}
2844 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2845 files=file_dict)
2846 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2847 self.waitUntilSettled()
2848 self.assertIn('already defined', A.messages[0])
2849
2850 def test_secret_branch_error_same_project(self):
2851 # Test that we are unable to create a secret which differs
2852 # from another with the same name -- i.e., that if we have a
2853 # duplicate secret on multiple branches of the same project,
2854 # they must be identical.
2855 self.create_branch('org/project1', 'stable')
2856 self.fake_gerrit.addEvent(
2857 self.fake_gerrit.getFakeBranchCreatedEvent(
2858 'org/project1', 'stable'))
2859 self.waitUntilSettled()
2860
2861 in_repo_conf = textwrap.dedent(
2862 """
2863 - secret:
2864 name: project1_secret
2865 data: {}
2866 """)
2867 file_dict = {'zuul.yaml': in_repo_conf}
2868 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A',
2869 files=file_dict)
2870 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2871 self.waitUntilSettled()
2872 self.assertIn('does not match existing definition in branch master',
2873 A.messages[0])
2874
2875 def test_secret_branch_error_other_project(self):
2876 # Test that we are unable to create a secret with the same
2877 # name as another. We're never allowed to have a secret with
2878 # the same name outside of a project.
2879 in_repo_conf = textwrap.dedent(
2880 """
2881 - secret:
2882 name: project1_secret
2883 data: {}
2884 """)
2885 file_dict = {'zuul.yaml': in_repo_conf}
2886 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2887 files=file_dict)
2888 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2889 self.waitUntilSettled()
2890 self.assertIn('already defined in project org/project1',
2891 A.messages[0])
2892
2893
James E. Blairdf91ab32017-10-25 17:57:13 -07002894class TestSecretInheritance(ZuulTestCase):
2895 tenant_config_file = 'config/secret-inheritance/main.yaml'
2896
2897 def _getSecrets(self, job, pbtype):
2898 secrets = []
2899 build = self.getJobFromHistory(job)
2900 for pb in build.parameters[pbtype]:
2901 secrets.append(pb['secrets'])
2902 return secrets
2903
2904 def _checkTrustedSecrets(self):
2905 secret = {'longpassword': 'test-passwordtest-password',
2906 'password': 'test-password',
2907 'username': 'test-username'}
2908 self.assertEqual(
2909 self._getSecrets('trusted-secrets', 'playbooks'),
James E. Blair2f589fe2017-10-26 12:57:41 -07002910 [{'trusted-secret': secret}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002911 self.assertEqual(
2912 self._getSecrets('trusted-secrets', 'pre_playbooks'), [])
2913 self.assertEqual(
2914 self._getSecrets('trusted-secrets', 'post_playbooks'), [])
2915
2916 self.assertEqual(
2917 self._getSecrets('trusted-secrets-trusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002918 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002919 self.assertEqual(
2920 self._getSecrets('trusted-secrets-trusted-child',
2921 'pre_playbooks'), [])
2922 self.assertEqual(
2923 self._getSecrets('trusted-secrets-trusted-child',
2924 'post_playbooks'), [])
2925
2926 self.assertEqual(
2927 self._getSecrets('trusted-secrets-untrusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002928 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002929 self.assertEqual(
2930 self._getSecrets('trusted-secrets-untrusted-child',
2931 'pre_playbooks'), [])
2932 self.assertEqual(
2933 self._getSecrets('trusted-secrets-untrusted-child',
2934 'post_playbooks'), [])
2935
2936 def _checkUntrustedSecrets(self):
2937 secret = {'longpassword': 'test-passwordtest-password',
2938 'password': 'test-password',
2939 'username': 'test-username'}
2940 self.assertEqual(
2941 self._getSecrets('untrusted-secrets', 'playbooks'),
James E. Blair2f589fe2017-10-26 12:57:41 -07002942 [{'untrusted-secret': secret}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002943 self.assertEqual(
2944 self._getSecrets('untrusted-secrets', 'pre_playbooks'), [])
2945 self.assertEqual(
2946 self._getSecrets('untrusted-secrets', 'post_playbooks'), [])
2947
2948 self.assertEqual(
2949 self._getSecrets('untrusted-secrets-trusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002950 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002951 self.assertEqual(
2952 self._getSecrets('untrusted-secrets-trusted-child',
2953 'pre_playbooks'), [])
2954 self.assertEqual(
2955 self._getSecrets('untrusted-secrets-trusted-child',
2956 'post_playbooks'), [])
2957
2958 self.assertEqual(
2959 self._getSecrets('untrusted-secrets-untrusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002960 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002961 self.assertEqual(
2962 self._getSecrets('untrusted-secrets-untrusted-child',
2963 'pre_playbooks'), [])
2964 self.assertEqual(
2965 self._getSecrets('untrusted-secrets-untrusted-child',
2966 'post_playbooks'), [])
2967
2968 def test_trusted_secret_inheritance_check(self):
2969 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
2970 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2971 self.waitUntilSettled()
2972 self.assertHistory([
2973 dict(name='trusted-secrets', result='SUCCESS', changes='1,1'),
2974 dict(name='trusted-secrets-trusted-child',
2975 result='SUCCESS', changes='1,1'),
2976 dict(name='trusted-secrets-untrusted-child',
2977 result='SUCCESS', changes='1,1'),
2978 ], ordered=False)
2979
2980 self._checkTrustedSecrets()
2981
2982 def test_untrusted_secret_inheritance_gate(self):
2983 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
2984 A.addApproval('Code-Review', 2)
2985 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2986 self.waitUntilSettled()
2987 self.assertHistory([
2988 dict(name='untrusted-secrets', result='SUCCESS', changes='1,1'),
2989 dict(name='untrusted-secrets-trusted-child',
2990 result='SUCCESS', changes='1,1'),
2991 dict(name='untrusted-secrets-untrusted-child',
2992 result='SUCCESS', changes='1,1'),
2993 ], ordered=False)
2994
2995 self._checkUntrustedSecrets()
2996
2997 def test_untrusted_secret_inheritance_check(self):
2998 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2999 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3000 self.waitUntilSettled()
3001 # This configuration tries to run untrusted secrets in an
3002 # non-post-review pipeline and should therefore run no jobs.
3003 self.assertHistory([])
3004
3005
James E. Blairdb089032017-08-15 13:42:12 -07003006class TestSecretLeaks(AnsibleZuulTestCase):
3007 tenant_config_file = 'config/secret-leaks/main.yaml'
3008
3009 def searchForContent(self, path, content):
3010 matches = []
3011 for (dirpath, dirnames, filenames) in os.walk(path):
3012 for filename in filenames:
3013 filepath = os.path.join(dirpath, filename)
3014 with open(filepath, 'rb') as f:
3015 if content in f.read():
3016 matches.append(filepath[len(path):])
3017 return matches
3018
3019 def _test_secret_file(self):
3020 # Or rather -- test that they *don't* leak.
3021 # Keep the jobdir around so we can inspect contents.
3022 self.executor_server.keep_jobdir = True
3023 conf = textwrap.dedent(
3024 """
3025 - project:
3026 name: org/project
3027 check:
3028 jobs:
3029 - secret-file
3030 """)
3031
3032 file_dict = {'.zuul.yaml': conf}
3033 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
3034 files=file_dict)
3035 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3036 self.waitUntilSettled()
3037 self.assertHistory([
3038 dict(name='secret-file', result='SUCCESS', changes='1,1'),
3039 ], ordered=False)
3040 matches = self.searchForContent(self.history[0].jobdir.root,
3041 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07003042 self.assertEqual(set(['/work/secret-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07003043 set(matches))
3044
3045 def test_secret_file(self):
3046 self._test_secret_file()
3047
3048 def test_secret_file_verbose(self):
3049 # Output extra ansible info to exercise alternate logging code
3050 # paths.
3051 self.executor_server.verbose = True
3052 self._test_secret_file()
3053
3054 def _test_secret_file_fail(self):
3055 # Or rather -- test that they *don't* leak.
3056 # Keep the jobdir around so we can inspect contents.
3057 self.executor_server.keep_jobdir = True
3058 conf = textwrap.dedent(
3059 """
3060 - project:
3061 name: org/project
3062 check:
3063 jobs:
3064 - secret-file-fail
3065 """)
3066
3067 file_dict = {'.zuul.yaml': conf}
3068 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
3069 files=file_dict)
3070 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3071 self.waitUntilSettled()
3072 self.assertHistory([
3073 dict(name='secret-file-fail', result='FAILURE', changes='1,1'),
3074 ], ordered=False)
3075 matches = self.searchForContent(self.history[0].jobdir.root,
3076 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07003077 self.assertEqual(set(['/work/failure-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07003078 set(matches))
3079
3080 def test_secret_file_fail(self):
3081 self._test_secret_file_fail()
3082
3083 def test_secret_file_fail_verbose(self):
3084 # Output extra ansible info to exercise alternate logging code
3085 # paths.
3086 self.executor_server.verbose = True
3087 self._test_secret_file_fail()
James E. Blaira00910c2017-08-23 09:15:04 -07003088
3089
James E. Blair8446c412018-01-17 15:49:59 -08003090class TestNodesets(ZuulTestCase):
3091 tenant_config_file = 'config/nodesets/main.yaml'
3092
3093 def test_nodeset_branch(self):
3094 # Test that we can use a nodeset defined in another branch of
3095 # the same project.
3096 self.create_branch('org/project2', 'stable')
3097 self.fake_gerrit.addEvent(
3098 self.fake_gerrit.getFakeBranchCreatedEvent(
3099 'org/project2', 'stable'))
3100 self.waitUntilSettled()
3101
3102 with open(os.path.join(FIXTURE_DIR,
3103 'config/nodesets/git/',
3104 'org_project2/zuul-nodeset.yaml')) as f:
3105 config = f.read()
3106
3107 file_dict = {'zuul.yaml': config}
3108 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
3109 files=file_dict)
3110 A.addApproval('Code-Review', 2)
3111 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
3112 self.waitUntilSettled()
3113 self.assertEqual(A.data['status'], 'MERGED')
3114 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
3115 self.waitUntilSettled()
3116
3117 in_repo_conf = textwrap.dedent(
3118 """
3119 - job:
3120 parent: base
3121 name: project2-test
3122 nodeset: project2-nodeset
3123
3124 - project:
3125 check:
3126 jobs:
3127 - project2-test
3128 gate:
3129 jobs:
3130 - noop
3131 """)
3132 file_dict = {'zuul.yaml': in_repo_conf}
3133 B = self.fake_gerrit.addFakeChange('org/project2', 'stable', 'B',
3134 files=file_dict)
3135 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
3136 self.waitUntilSettled()
3137 self.assertEqual(B.reported, 1, "B should report success")
3138 self.assertHistory([
3139 dict(name='project2-test', result='SUCCESS', changes='2,1',
3140 node='ubuntu-xenial'),
3141 ])
3142
3143 def test_nodeset_branch_duplicate(self):
Monty Taylorbc1d0bb2018-01-22 17:05:31 -06003144 # Test that we can create a duplicate nodeset on a different
James E. Blair8446c412018-01-17 15:49:59 -08003145 # branch of the same project -- i.e., that when we branch
Monty Taylorbc1d0bb2018-01-22 17:05:31 -06003146 # master to stable on a project with a nodeset, nothing
James E. Blair8446c412018-01-17 15:49:59 -08003147 # changes.
3148 self.create_branch('org/project1', 'stable')
3149 self.fake_gerrit.addEvent(
3150 self.fake_gerrit.getFakeBranchCreatedEvent(
3151 'org/project1', 'stable'))
3152 self.waitUntilSettled()
3153
3154 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A')
3155 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3156 self.waitUntilSettled()
3157 self.assertEqual(A.reported, 1,
3158 "A should report success")
3159 self.assertHistory([
3160 dict(name='project1-test', result='SUCCESS', changes='1,1',
3161 node='ubuntu-xenial'),
3162 ])
3163
3164 def test_nodeset_branch_error_same_branch(self):
3165 # Test that we are unable to define a nodeset twice on the same
3166 # project-branch.
3167 in_repo_conf = textwrap.dedent(
3168 """
3169 - nodeset:
3170 name: project1-nodeset
3171 nodes: []
3172 - nodeset:
3173 name: project1-nodeset
3174 nodes: []
3175 """)
3176 file_dict = {'zuul.yaml': in_repo_conf}
3177 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
3178 files=file_dict)
3179 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3180 self.waitUntilSettled()
3181 self.assertIn('already defined', A.messages[0])
3182
3183 def test_nodeset_branch_error_same_project(self):
3184 # Test that we are unable to create a nodeset which differs
3185 # from another with the same name -- i.e., that if we have a
3186 # duplicate nodeset on multiple branches of the same project,
3187 # they must be identical.
3188 self.create_branch('org/project1', 'stable')
3189 self.fake_gerrit.addEvent(
3190 self.fake_gerrit.getFakeBranchCreatedEvent(
3191 'org/project1', 'stable'))
3192 self.waitUntilSettled()
3193
3194 in_repo_conf = textwrap.dedent(
3195 """
3196 - nodeset:
3197 name: project1-nodeset
3198 nodes: []
3199 """)
3200 file_dict = {'zuul.yaml': in_repo_conf}
3201 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A',
3202 files=file_dict)
3203 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3204 self.waitUntilSettled()
3205 self.assertIn('does not match existing definition in branch master',
3206 A.messages[0])
3207
3208 def test_nodeset_branch_error_other_project(self):
3209 # Test that we are unable to create a nodeset with the same
3210 # name as another. We're never allowed to have a nodeset with
3211 # the same name outside of a project.
3212 in_repo_conf = textwrap.dedent(
3213 """
3214 - nodeset:
3215 name: project1-nodeset
3216 nodes: []
3217 """)
3218 file_dict = {'zuul.yaml': in_repo_conf}
3219 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
3220 files=file_dict)
3221 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3222 self.waitUntilSettled()
3223 self.assertIn('already defined in project org/project1',
3224 A.messages[0])
3225
3226
James E. Blair9596b942018-01-18 14:21:44 -08003227class TestSemaphoreBranches(ZuulTestCase):
3228 tenant_config_file = 'config/semaphore-branches/main.yaml'
3229
3230 def test_semaphore_branch(self):
3231 # Test that we can use a semaphore defined in another branch of
3232 # the same project.
3233 self.create_branch('org/project2', 'stable')
3234 self.fake_gerrit.addEvent(
3235 self.fake_gerrit.getFakeBranchCreatedEvent(
3236 'org/project2', 'stable'))
3237 self.waitUntilSettled()
3238
3239 with open(os.path.join(FIXTURE_DIR,
3240 'config/semaphore-branches/git/',
3241 'org_project2/zuul-semaphore.yaml')) as f:
3242 config = f.read()
3243
3244 file_dict = {'zuul.yaml': config}
3245 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
3246 files=file_dict)
3247 A.addApproval('Code-Review', 2)
3248 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
3249 self.waitUntilSettled()
3250 self.assertEqual(A.data['status'], 'MERGED')
3251 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
3252 self.waitUntilSettled()
3253
3254 in_repo_conf = textwrap.dedent(
3255 """
3256 - job:
3257 parent: base
3258 name: project2-test
3259 semaphore: project2-semaphore
3260
3261 - project:
3262 check:
3263 jobs:
3264 - project2-test
3265 gate:
3266 jobs:
3267 - noop
3268 """)
3269 file_dict = {'zuul.yaml': in_repo_conf}
3270 B = self.fake_gerrit.addFakeChange('org/project2', 'stable', 'B',
3271 files=file_dict)
3272 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
3273 self.waitUntilSettled()
3274 self.assertEqual(B.reported, 1, "B should report success")
3275 self.assertHistory([
3276 dict(name='project2-test', result='SUCCESS', changes='2,1')
3277 ])
3278
3279 def test_semaphore_branch_duplicate(self):
3280 # Test that we can create a duplicate semaphore on a different
3281 # branch of the same project -- i.e., that when we branch
3282 # master to stable on a project with a semaphore, nothing
3283 # changes.
3284 self.create_branch('org/project1', 'stable')
3285 self.fake_gerrit.addEvent(
3286 self.fake_gerrit.getFakeBranchCreatedEvent(
3287 'org/project1', 'stable'))
3288 self.waitUntilSettled()
3289
3290 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A')
3291 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3292 self.waitUntilSettled()
3293 self.assertEqual(A.reported, 1,
3294 "A should report success")
3295 self.assertHistory([
3296 dict(name='project1-test', result='SUCCESS', changes='1,1')
3297 ])
3298
3299 def test_semaphore_branch_error_same_branch(self):
3300 # Test that we are unable to define a semaphore twice on the same
3301 # project-branch.
3302 in_repo_conf = textwrap.dedent(
3303 """
3304 - semaphore:
3305 name: project1-semaphore
3306 max: 2
3307 - semaphore:
3308 name: project1-semaphore
3309 max: 2
3310 """)
3311 file_dict = {'zuul.yaml': in_repo_conf}
3312 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
3313 files=file_dict)
3314 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3315 self.waitUntilSettled()
3316 self.assertIn('already defined', A.messages[0])
3317
3318 def test_semaphore_branch_error_same_project(self):
3319 # Test that we are unable to create a semaphore which differs
3320 # from another with the same name -- i.e., that if we have a
3321 # duplicate semaphore on multiple branches of the same project,
3322 # they must be identical.
3323 self.create_branch('org/project1', 'stable')
3324 self.fake_gerrit.addEvent(
3325 self.fake_gerrit.getFakeBranchCreatedEvent(
3326 'org/project1', 'stable'))
3327 self.waitUntilSettled()
3328
3329 in_repo_conf = textwrap.dedent(
3330 """
3331 - semaphore:
3332 name: project1-semaphore
3333 max: 4
3334 """)
3335 file_dict = {'zuul.yaml': in_repo_conf}
3336 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A',
3337 files=file_dict)
3338 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3339 self.waitUntilSettled()
3340 self.assertIn('does not match existing definition in branch master',
3341 A.messages[0])
3342
3343 def test_semaphore_branch_error_other_project(self):
3344 # Test that we are unable to create a semaphore with the same
3345 # name as another. We're never allowed to have a semaphore with
3346 # the same name outside of a project.
3347 in_repo_conf = textwrap.dedent(
3348 """
3349 - semaphore:
3350 name: project1-semaphore
3351 max: 2
3352 """)
3353 file_dict = {'zuul.yaml': in_repo_conf}
3354 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
3355 files=file_dict)
3356 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3357 self.waitUntilSettled()
3358 self.assertIn('already defined in project org/project1',
3359 A.messages[0])
3360
3361
James E. Blaira00910c2017-08-23 09:15:04 -07003362class TestJobOutput(AnsibleZuulTestCase):
3363 tenant_config_file = 'config/job-output/main.yaml'
3364
3365 def _get_file(self, build, path):
3366 p = os.path.join(build.jobdir.root, path)
3367 with open(p) as f:
3368 return f.read()
3369
3370 def test_job_output(self):
Monty Taylor0e2489a2017-10-10 11:57:29 -05003371 # Verify that command standard output appears in the job output,
3372 # and that failures in the final playbook get logged.
James E. Blaira00910c2017-08-23 09:15:04 -07003373
3374 # This currently only verifies we receive output from
3375 # localhost. Notably, it does not verify we receive output
3376 # via zuul_console streaming.
3377 self.executor_server.keep_jobdir = True
3378 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3379 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3380 self.waitUntilSettled()
3381 self.assertHistory([
3382 dict(name='job-output', result='SUCCESS', changes='1,1'),
3383 ], ordered=False)
3384
3385 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
3386 j = json.loads(self._get_file(self.history[0],
3387 'work/logs/job-output.json'))
3388 self.assertEqual(token,
3389 j[0]['plays'][0]['tasks'][0]
3390 ['hosts']['localhost']['stdout'])
3391
3392 print(self._get_file(self.history[0],
3393 'work/logs/job-output.txt'))
3394 self.assertIn(token,
3395 self._get_file(self.history[0],
3396 'work/logs/job-output.txt'))
Monty Taylor0e2489a2017-10-10 11:57:29 -05003397
3398 def test_job_output_failure_log(self):
3399 logger = logging.getLogger('zuul.AnsibleJob')
3400 output = io.StringIO()
3401 logger.addHandler(logging.StreamHandler(output))
3402
3403 # Verify that a failure in the last post playbook emits the contents
3404 # of the json output to the log
3405 self.executor_server.keep_jobdir = True
3406 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
3407 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3408 self.waitUntilSettled()
3409 self.assertHistory([
3410 dict(name='job-output-failure',
3411 result='POST_FAILURE', changes='1,1'),
3412 ], ordered=False)
3413
3414 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
3415 j = json.loads(self._get_file(self.history[0],
3416 'work/logs/job-output.json'))
3417 self.assertEqual(token,
3418 j[0]['plays'][0]['tasks'][0]
3419 ['hosts']['localhost']['stdout'])
3420
3421 print(self._get_file(self.history[0],
3422 'work/logs/job-output.json'))
3423 self.assertIn(token,
3424 self._get_file(self.history[0],
3425 'work/logs/job-output.txt'))
3426
3427 log_output = output.getvalue()
3428 self.assertIn('Final playbook failed', log_output)
3429 self.assertIn('Failure test', log_output)