blob: 44eda82fe30c0d4ff93e78f31ee99f56fc6e27f8 [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):
77
78 tenant_config_file = 'config/protected/main.yaml'
79
80 def test_protected_ok(self):
81 # test clean usage of final parent job
82 in_repo_conf = textwrap.dedent(
83 """
84 - job:
85 name: job-protected
86 protected: true
87 run: playbooks/job-protected.yaml
88
89 - project:
90 name: org/project
91 check:
92 jobs:
93 - job-child-ok
94
95 - job:
96 name: job-child-ok
97 parent: job-protected
98
99 - project:
100 name: org/project
101 check:
102 jobs:
103 - job-child-ok
104
105 """)
106
107 file_dict = {'zuul.yaml': in_repo_conf}
108 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
109 files=file_dict)
110 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
111 self.waitUntilSettled()
112
113 self.assertEqual(A.reported, 1)
114 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1')
115
116 def test_protected_reset(self):
117 # try to reset protected flag
118 in_repo_conf = textwrap.dedent(
119 """
120 - job:
121 name: job-protected
122 protected: true
123 run: playbooks/job-protected.yaml
124
125 - job:
126 name: job-child-reset-protected
127 parent: job-protected
128 protected: false
129
130 - project:
131 name: org/project
132 check:
133 jobs:
134 - job-child-reset-protected
135
136 """)
137
138 file_dict = {'zuul.yaml': in_repo_conf}
139 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
140 files=file_dict)
141 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
142 self.waitUntilSettled()
143
144 # The second patch tried to override some variables.
145 # Thus it should fail.
146 self.assertEqual(A.reported, 1)
147 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
148 self.assertIn('Unable to reset protected attribute', A.messages[0])
149
150 def test_protected_inherit_not_ok(self):
151 # try to inherit from a protected job in different project
152 in_repo_conf = textwrap.dedent(
153 """
154 - job:
155 name: job-child-notok
156 run: playbooks/job-child-notok.yaml
157 parent: job-protected
158
159 - project:
160 name: org/project1
161 check:
162 jobs:
163 - job-child-notok
164
165 """)
166
167 file_dict = {'zuul.yaml': in_repo_conf}
168 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
169 files=file_dict)
170 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
171 self.waitUntilSettled()
172
173 self.assertEqual(A.reported, 1)
174 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
175 self.assertIn(
176 "which is defined in review.example.com/org/project is protected "
177 "and cannot be inherited from other projects.", A.messages[0])
178
179
Tobias Henkel83167622017-06-30 19:45:03 +0200180class TestFinal(ZuulTestCase):
181
182 tenant_config_file = 'config/final/main.yaml'
183
184 def test_final_variant_ok(self):
185 # test clean usage of final parent job
186 in_repo_conf = textwrap.dedent(
187 """
188 - project:
189 name: org/project
190 check:
191 jobs:
192 - job-final
193 """)
194
195 file_dict = {'.zuul.yaml': in_repo_conf}
196 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
197 files=file_dict)
198 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
199 self.waitUntilSettled()
200
201 self.assertEqual(A.reported, 1)
202 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1')
203
204 def test_final_variant_error(self):
205 # test misuse of final parent job
206 in_repo_conf = textwrap.dedent(
207 """
208 - project:
209 name: org/project
210 check:
211 jobs:
212 - job-final:
213 vars:
214 dont_override_this: bar
215 """)
216 file_dict = {'.zuul.yaml': in_repo_conf}
217 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
218 files=file_dict)
219 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
220 self.waitUntilSettled()
221
222 # The second patch tried to override some variables.
223 # Thus it should fail.
224 self.assertEqual(A.reported, 1)
225 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
226 self.assertIn('Unable to modify final job', A.messages[0])
227
228 def test_final_inheritance(self):
229 # test misuse of final parent job
230 in_repo_conf = textwrap.dedent(
231 """
232 - job:
233 name: project-test
234 parent: job-final
James E. Blair2f589fe2017-10-26 12:57:41 -0700235 run: playbooks/project-test.yaml
Tobias Henkel83167622017-06-30 19:45:03 +0200236
237 - project:
238 name: org/project
239 check:
240 jobs:
241 - project-test
242 """)
243
244 in_repo_playbook = textwrap.dedent(
245 """
246 - hosts: all
247 tasks: []
248 """)
249
250 file_dict = {'.zuul.yaml': in_repo_conf,
251 'playbooks/project-test.yaml': in_repo_playbook}
252 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
253 files=file_dict)
254 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
255 self.waitUntilSettled()
256
257 # The second patch tried to override some variables.
258 # Thus it should fail.
259 self.assertEqual(A.reported, 1)
260 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
James E. Blairc32a8352017-10-11 16:27:50 -0700261 self.assertIn('Unable to modify final job', A.messages[0])
Tobias Henkel83167622017-06-30 19:45:03 +0200262
263
James E. Blair1edfd972017-12-01 15:54:24 -0800264class TestBranchTag(ZuulTestCase):
265 tenant_config_file = 'config/branch-tag/main.yaml'
266
267 def test_negative_branch_match(self):
268 # Test that a negative branch matcher works with implied branches.
269 event = self.fake_gerrit.addFakeTag('org/project', 'master', 'foo')
270 self.fake_gerrit.addEvent(event)
271 self.waitUntilSettled()
272 self.assertHistory([
273 dict(name='test-job', result='SUCCESS', ref='refs/tags/foo')])
274
275
James E. Blair9ab8db42017-12-01 15:12:04 -0800276class TestBranchNegative(ZuulTestCase):
277 tenant_config_file = 'config/branch-negative/main.yaml'
278
279 def test_negative_branch_match(self):
280 # Test that a negative branch matcher works with implied branches.
281 self.create_branch('org/project', 'stable/pike')
282 self.fake_gerrit.addEvent(
283 self.fake_gerrit.getFakeBranchCreatedEvent(
284 'org/project', 'stable/pike'))
285 self.waitUntilSettled()
286
287 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
288 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
289 self.waitUntilSettled()
290 B = self.fake_gerrit.addFakeChange('org/project', 'stable/pike', 'A')
291 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
292 self.waitUntilSettled()
293 self.assertHistory([
294 dict(name='test-job', result='SUCCESS', changes='1,1')])
295
296
James E. Blaire36d1a32017-11-28 13:33:38 -0800297class TestBranchTemplates(ZuulTestCase):
298 tenant_config_file = 'config/branch-templates/main.yaml'
299
300 def test_template_removal_from_branch(self):
301 # Test that a template can be removed from one branch but not
302 # another.
303 # This creates a new branch with a copy of the config in master
304 self.create_branch('puppet-integration', 'stable/newton')
305 self.create_branch('puppet-integration', 'stable/ocata')
306 self.create_branch('puppet-tripleo', 'stable/newton')
307 self.create_branch('puppet-tripleo', 'stable/ocata')
308 self.fake_gerrit.addEvent(
309 self.fake_gerrit.getFakeBranchCreatedEvent(
310 'puppet-integration', 'stable/newton'))
311 self.fake_gerrit.addEvent(
312 self.fake_gerrit.getFakeBranchCreatedEvent(
313 'puppet-integration', 'stable/ocata'))
314 self.fake_gerrit.addEvent(
315 self.fake_gerrit.getFakeBranchCreatedEvent(
316 'puppet-tripleo', 'stable/newton'))
317 self.fake_gerrit.addEvent(
318 self.fake_gerrit.getFakeBranchCreatedEvent(
319 'puppet-tripleo', 'stable/ocata'))
320 self.waitUntilSettled()
321
322 in_repo_conf = textwrap.dedent(
323 """
324 - project:
325 name: puppet-tripleo
326 check:
327 jobs:
328 - puppet-something
329 """)
330
331 file_dict = {'.zuul.yaml': in_repo_conf}
332 A = self.fake_gerrit.addFakeChange('puppet-tripleo', 'stable/newton',
333 'A', files=file_dict)
334 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
335 self.waitUntilSettled()
336 self.assertHistory([
337 dict(name='puppet-something', result='SUCCESS', changes='1,1')])
338
339 def test_template_change_on_branch(self):
340 # Test that the contents of a template can be changed on one
341 # branch without affecting another.
342
343 # This creates a new branch with a copy of the config in master
344 self.create_branch('puppet-integration', 'stable/newton')
345 self.create_branch('puppet-integration', 'stable/ocata')
346 self.create_branch('puppet-tripleo', 'stable/newton')
347 self.create_branch('puppet-tripleo', 'stable/ocata')
348 self.fake_gerrit.addEvent(
349 self.fake_gerrit.getFakeBranchCreatedEvent(
350 'puppet-integration', 'stable/newton'))
351 self.fake_gerrit.addEvent(
352 self.fake_gerrit.getFakeBranchCreatedEvent(
353 'puppet-integration', 'stable/ocata'))
354 self.fake_gerrit.addEvent(
355 self.fake_gerrit.getFakeBranchCreatedEvent(
356 'puppet-tripleo', 'stable/newton'))
357 self.fake_gerrit.addEvent(
358 self.fake_gerrit.getFakeBranchCreatedEvent(
359 'puppet-tripleo', 'stable/ocata'))
360 self.waitUntilSettled()
361
362 in_repo_conf = textwrap.dedent("""
363 - job:
364 name: puppet-unit-base
365 run: playbooks/run-unit-tests.yaml
366
367 - job:
368 name: puppet-unit-3.8
369 parent: puppet-unit-base
370 branches: ^(stable/(newton|ocata)).*$
371 vars:
372 puppet_gem_version: 3.8
373
374 - job:
375 name: puppet-something
376 run: playbooks/run-unit-tests.yaml
377
378 - project-template:
379 name: puppet-unit
380 check:
381 jobs:
382 - puppet-something
383
384 - project:
385 name: puppet-integration
386 templates:
387 - puppet-unit
388 """)
389
390 file_dict = {'.zuul.yaml': in_repo_conf}
391 A = self.fake_gerrit.addFakeChange('puppet-integration',
392 'stable/newton',
393 'A', files=file_dict)
394 B = self.fake_gerrit.addFakeChange('puppet-tripleo',
395 'stable/newton',
396 'B')
397 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
398 B.subject, A.data['id'])
399 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
400 self.waitUntilSettled()
401 self.assertHistory([
402 dict(name='puppet-something', result='SUCCESS',
403 changes='1,1 2,1')])
404
405
James E. Blair09998792017-10-15 18:02:18 -0700406class TestBranchVariants(ZuulTestCase):
407 tenant_config_file = 'config/branch-variants/main.yaml'
408
409 def test_branch_variants(self):
410 # Test branch variants of jobs with inheritance
411 self.executor_server.hold_jobs_in_build = True
412 # This creates a new branch with a copy of the config in master
413 self.create_branch('puppet-integration', 'stable')
414 self.fake_gerrit.addEvent(
415 self.fake_gerrit.getFakeBranchCreatedEvent(
416 'puppet-integration', 'stable'))
417 self.waitUntilSettled()
418
419 A = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'A')
420 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
421 self.waitUntilSettled()
422
423 self.assertEqual(len(self.builds[0].parameters['pre_playbooks']), 3)
424 self.executor_server.hold_jobs_in_build = False
425 self.executor_server.release()
426 self.waitUntilSettled()
427
James E. Blairc9e77592017-10-24 09:25:23 -0700428 def test_branch_variants_reconfigure(self):
429 # Test branch variants of jobs with inheritance
430 self.executor_server.hold_jobs_in_build = True
431 # This creates a new branch with a copy of the config in master
432 self.create_branch('puppet-integration', 'stable')
433 self.fake_gerrit.addEvent(
434 self.fake_gerrit.getFakeBranchCreatedEvent(
435 'puppet-integration', 'stable'))
436 self.waitUntilSettled()
437
438 with open(os.path.join(FIXTURE_DIR,
439 'config/branch-variants/git/',
440 'puppet-integration/.zuul.yaml')) as f:
441 config = f.read()
442
443 # Push a change that triggers a dynamic reconfiguration
444 file_dict = {'.zuul.yaml': config}
445 A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A',
446 files=file_dict)
447 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
448 self.waitUntilSettled()
449
450 ipath = self.builds[0].parameters['zuul']['_inheritance_path']
451 for i in ipath:
452 self.log.debug("inheritance path %s", i)
453 self.assertEqual(len(ipath), 5)
454 self.executor_server.hold_jobs_in_build = False
455 self.executor_server.release()
456 self.waitUntilSettled()
457
James E. Blairc32a8352017-10-11 16:27:50 -0700458 def test_branch_variants_divergent(self):
459 # Test branches can diverge and become independent
460 self.executor_server.hold_jobs_in_build = True
461 # This creates a new branch with a copy of the config in master
462 self.create_branch('puppet-integration', 'stable')
463 self.fake_gerrit.addEvent(
464 self.fake_gerrit.getFakeBranchCreatedEvent(
465 'puppet-integration', 'stable'))
466 self.waitUntilSettled()
467
468 with open(os.path.join(FIXTURE_DIR,
469 'config/branch-variants/git/',
470 'puppet-integration/stable.zuul.yaml')) as f:
471 config = f.read()
472
473 file_dict = {'.zuul.yaml': config}
474 C = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'C',
475 files=file_dict)
476 C.addApproval('Code-Review', 2)
477 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
478 self.waitUntilSettled()
479 self.fake_gerrit.addEvent(C.getChangeMergedEvent())
480 self.waitUntilSettled()
481
482 A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A')
483 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
484 self.waitUntilSettled()
485 B = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'B')
486 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
487 self.waitUntilSettled()
488
489 self.assertEqual(self.builds[0].parameters['zuul']['jobtags'],
490 ['master'])
491
492 self.assertEqual(self.builds[1].parameters['zuul']['jobtags'],
493 ['stable'])
494
495 self.executor_server.hold_jobs_in_build = False
496 self.executor_server.release()
497 self.waitUntilSettled()
498
James E. Blair09998792017-10-15 18:02:18 -0700499
James E. Blair7fb04512018-01-23 13:23:13 -0800500class TestBranchMismatch(ZuulTestCase):
501 tenant_config_file = 'config/branch-mismatch/main.yaml'
502
503 def test_job_override_branch(self):
504 "Test that override-checkout overrides branch matchers as well"
505
506 # Make sure the parent job repo is branched, so it gets
507 # implied branch matchers.
508 self.create_branch('org/project1', 'stable')
509 self.fake_gerrit.addEvent(
510 self.fake_gerrit.getFakeBranchCreatedEvent(
511 'org/project1', 'stable'))
512
513 # The child job repo should have a branch which does not exist
514 # in the parent job repo.
515 self.create_branch('org/project2', 'devel')
516 self.fake_gerrit.addEvent(
517 self.fake_gerrit.getFakeBranchCreatedEvent(
518 'org/project2', 'devel'))
519
520 # A job in a repo with a weird branch name should use the
521 # parent job from the parent job's master (default) branch.
522 A = self.fake_gerrit.addFakeChange('org/project2', 'devel', 'A')
523 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
524 self.waitUntilSettled()
525 # project-test2 should run because it inherits from
526 # project-test1 and we will use the fallback branch to find
527 # project-test1 variants, but project-test1 itself, even
528 # though it is in the project-pipeline config, should not run
529 # because it doesn't directly match.
530 self.assertHistory([
531 dict(name='project-test1', result='SUCCESS', changes='1,1'),
532 dict(name='project-test2', result='SUCCESS', changes='1,1'),
533 ], ordered=False)
534
535
James E. Blair5d71d1a2018-01-26 14:26:18 -0800536class TestAllowedProjects(ZuulTestCase):
537 tenant_config_file = 'config/allowed-projects/main.yaml'
538
539 def test_allowed_projects(self):
540 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
541 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
542 self.waitUntilSettled()
543 self.assertEqual(A.reported, 1)
544 self.assertIn('Build succeeded', A.messages[0])
545
546 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
547 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
548 self.waitUntilSettled()
549 self.assertEqual(B.reported, 1)
550 self.assertIn('Project org/project2 is not allowed '
551 'to run job test-project2', B.messages[0])
552
553 C = self.fake_gerrit.addFakeChange('org/project3', 'master', 'C')
554 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
555 self.waitUntilSettled()
556 self.assertEqual(C.reported, 1)
557 self.assertIn('Project org/project3 is not allowed '
558 'to run job restricted-job', C.messages[0])
559
560 self.assertHistory([
561 dict(name='test-project1', result='SUCCESS', changes='1,1'),
562 dict(name='restricted-job', result='SUCCESS', changes='1,1'),
563 ], ordered=False)
564
565
James E. Blair2a664502017-10-27 11:39:33 -0700566class TestCentralJobs(ZuulTestCase):
567 tenant_config_file = 'config/central-jobs/main.yaml'
568
569 def setUp(self):
570 super(TestCentralJobs, self).setUp()
571 self.create_branch('org/project', 'stable')
572 self.fake_gerrit.addEvent(
573 self.fake_gerrit.getFakeBranchCreatedEvent(
574 'org/project', 'stable'))
575 self.waitUntilSettled()
576
577 def _updateConfig(self, config, branch):
578 file_dict = {'.zuul.yaml': config}
579 C = self.fake_gerrit.addFakeChange('org/project', branch, 'C',
580 files=file_dict)
581 C.addApproval('Code-Review', 2)
582 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
583 self.waitUntilSettled()
584 self.fake_gerrit.addEvent(C.getChangeMergedEvent())
585 self.waitUntilSettled()
586
587 def _test_central_job_on_branch(self, branch, other_branch):
588 # Test that a job defined on a branchless repo only runs on
589 # the branch applied
590 config = textwrap.dedent(
591 """
592 - project:
593 name: org/project
594 check:
595 jobs:
596 - central-job
597 """)
598 self._updateConfig(config, branch)
599
600 A = self.fake_gerrit.addFakeChange('org/project', branch, 'A')
601 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
602 self.waitUntilSettled()
603
604 self.assertHistory([
605 dict(name='central-job', result='SUCCESS', changes='2,1')])
606
607 # No jobs should run for this change.
608 B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B')
609 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
610 self.waitUntilSettled()
611
612 self.assertHistory([
613 dict(name='central-job', result='SUCCESS', changes='2,1')])
614
615 def test_central_job_on_stable(self):
616 self._test_central_job_on_branch('master', 'stable')
617
618 def test_central_job_on_master(self):
619 self._test_central_job_on_branch('stable', 'master')
620
621 def _test_central_template_on_branch(self, branch, other_branch):
622 # Test that a project-template defined on a branchless repo
623 # only runs on the branch applied
624 config = textwrap.dedent(
625 """
626 - project:
627 name: org/project
628 templates: ['central-jobs']
629 """)
630 self._updateConfig(config, branch)
631
632 A = self.fake_gerrit.addFakeChange('org/project', branch, 'A')
633 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
634 self.waitUntilSettled()
635
636 self.assertHistory([
637 dict(name='central-job', result='SUCCESS', changes='2,1')])
638
639 # No jobs should run for this change.
640 B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B')
641 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
642 self.waitUntilSettled()
643
644 self.assertHistory([
645 dict(name='central-job', result='SUCCESS', changes='2,1')])
646
647 def test_central_template_on_stable(self):
648 self._test_central_template_on_branch('master', 'stable')
649
650 def test_central_template_on_master(self):
651 self._test_central_template_on_branch('stable', 'master')
652
653
James E. Blairff555742017-02-19 11:34:27 -0800654class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -0800655 # A temporary class to hold new tests while others are disabled
656
Tobias Henkelabf973e2017-07-28 10:07:34 +0200657 config_file = 'zuul-connections-gerrit-and-github.conf'
James E. Blair2a629ec2015-12-22 15:32:02 -0800658 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -0800659
James E. Blair83005782015-12-11 14:46:03 -0800660 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -0800661 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200662 A.addApproval('Code-Review', 2)
663 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -0800664 self.waitUntilSettled()
665 self.assertEqual(self.getJobFromHistory('project-test1').result,
666 'SUCCESS')
667 self.assertEqual(A.data['status'], 'MERGED')
668 self.assertEqual(A.reported, 2,
669 "A should report start and success")
670 self.assertIn('tenant-one-gate', A.messages[1],
671 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -0800672
James E. Blair3a098dd2017-10-04 14:37:29 -0700673 @skip("This test is useful, but not reliable")
674 def test_full_and_dynamic_reconfig(self):
675 self.executor_server.hold_jobs_in_build = True
676 in_repo_conf = textwrap.dedent(
677 """
678 - job:
679 name: project-test1
680
681 - project:
682 name: org/project
683 tenant-one-gate:
684 jobs:
685 - project-test1
686 """)
687
688 file_dict = {'.zuul.yaml': in_repo_conf}
689 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
690 files=file_dict)
691 A.addApproval('Code-Review', 2)
692 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
693 self.waitUntilSettled()
694 self.sched.reconfigure(self.config)
695 self.waitUntilSettled()
696
697 gc.collect()
698 pipelines = [obj for obj in gc.get_objects()
699 if isinstance(obj, zuul.model.Pipeline)]
700 self.assertEqual(len(pipelines), 4)
701
702 self.executor_server.hold_jobs_in_build = False
703 self.executor_server.release()
704 self.waitUntilSettled()
705
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700706 def test_dynamic_config(self):
707 in_repo_conf = textwrap.dedent(
708 """
709 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200710 name: project-test1
711
712 - job:
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700713 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700714 run: playbooks/project-test2.yaml
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700715
Tobias Henkel53aa2ad2017-12-22 09:59:45 +0100716 - job:
717 name: project-test3
718 run: playbooks/project-test2.yaml
719
720 # add a job by the short project name
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700721 - project:
722 name: org/project
723 tenant-one-gate:
724 jobs:
725 - project-test2
Tobias Henkel53aa2ad2017-12-22 09:59:45 +0100726
727 # add a job by the canonical project name
728 - project:
729 name: review.example.com/org/project
730 tenant-one-gate:
731 jobs:
732 - project-test3
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700733 """)
734
James E. Blairc73c73a2017-01-20 15:15:15 -0800735 in_repo_playbook = textwrap.dedent(
736 """
737 - hosts: all
738 tasks: []
739 """)
740
741 file_dict = {'.zuul.yaml': in_repo_conf,
742 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700743 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800744 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200745 A.addApproval('Code-Review', 2)
746 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700747 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700748 self.assertEqual(A.data['status'], 'MERGED')
749 self.assertEqual(A.reported, 2,
750 "A should report start and success")
751 self.assertIn('tenant-one-gate', A.messages[1],
752 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800753 self.assertHistory([
Tobias Henkel53aa2ad2017-12-22 09:59:45 +0100754 dict(name='project-test2', result='SUCCESS', changes='1,1'),
755 dict(name='project-test3', result='SUCCESS', changes='1,1'),
756 ], ordered=False)
James E. Blair646322f2017-01-27 15:50:34 -0800757
James E. Blairc2a5ed72017-02-20 14:12:01 -0500758 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800759 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500760
James E. Blair646322f2017-01-27 15:50:34 -0800761 # Now that the config change is landed, it should be live for
762 # subsequent changes.
763 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200764 B.addApproval('Code-Review', 2)
765 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair646322f2017-01-27 15:50:34 -0800766 self.waitUntilSettled()
767 self.assertEqual(self.getJobFromHistory('project-test2').result,
768 'SUCCESS')
769 self.assertHistory([
770 dict(name='project-test2', result='SUCCESS', changes='1,1'),
Tobias Henkel53aa2ad2017-12-22 09:59:45 +0100771 dict(name='project-test3', result='SUCCESS', changes='1,1'),
772 dict(name='project-test2', result='SUCCESS', changes='2,1'),
773 dict(name='project-test3', result='SUCCESS', changes='2,1'),
774 ], ordered=False)
James E. Blairc73c73a2017-01-20 15:15:15 -0800775
James E. Blair6bc10482017-10-20 11:28:53 -0700776 def test_dynamic_template(self):
James E. Blair2a664502017-10-27 11:39:33 -0700777 # Tests that a project can't update a template in another
778 # project.
James E. Blair6bc10482017-10-20 11:28:53 -0700779 in_repo_conf = textwrap.dedent(
780 """
781 - job:
782 name: project-test1
783
784 - project-template:
785 name: common-config-template
786 check:
787 jobs:
788 - project-test1
789
790 - project:
791 name: org/project
792 templates: [common-config-template]
793 """)
794
795 file_dict = {'.zuul.yaml': in_repo_conf}
796 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
797 files=file_dict)
798 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
799 self.waitUntilSettled()
James E. Blair2a664502017-10-27 11:39:33 -0700800
801 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
802 self.assertIn('Project template common-config-template '
803 'is already defined',
804 A.messages[0],
805 "A should have failed the check pipeline")
James E. Blair6bc10482017-10-20 11:28:53 -0700806
Tobias Henkelf02cf512017-07-21 22:55:34 +0200807 def test_dynamic_config_non_existing_job(self):
808 """Test that requesting a non existent job fails"""
809 in_repo_conf = textwrap.dedent(
810 """
811 - job:
812 name: project-test1
813
814 - project:
815 name: org/project
816 check:
817 jobs:
818 - non-existent-job
819 """)
820
821 in_repo_playbook = textwrap.dedent(
822 """
823 - hosts: all
824 tasks: []
825 """)
826
827 file_dict = {'.zuul.yaml': in_repo_conf,
828 'playbooks/project-test2.yaml': in_repo_playbook}
829 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
830 files=file_dict)
831 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
832 self.waitUntilSettled()
833 self.assertEqual(A.reported, 1,
834 "A should report failure")
835 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
836 self.assertIn('Job non-existent-job not defined', A.messages[0],
837 "A should have failed the check pipeline")
838 self.assertHistory([])
839
840 def test_dynamic_config_non_existing_job_in_template(self):
841 """Test that requesting a non existent job fails"""
842 in_repo_conf = textwrap.dedent(
843 """
844 - job:
845 name: project-test1
846
847 - project-template:
848 name: test-template
849 check:
850 jobs:
851 - non-existent-job
852
853 - project:
854 name: org/project
855 templates:
856 - test-template
857 """)
858
859 in_repo_playbook = textwrap.dedent(
860 """
861 - hosts: all
862 tasks: []
863 """)
864
865 file_dict = {'.zuul.yaml': in_repo_conf,
866 'playbooks/project-test2.yaml': in_repo_playbook}
867 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
868 files=file_dict)
869 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
870 self.waitUntilSettled()
871 self.assertEqual(A.reported, 1,
872 "A should report failure")
873 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
874 self.assertIn('Job non-existent-job not defined', A.messages[0],
875 "A should have failed the check pipeline")
876 self.assertHistory([])
877
Tobias Henkel0f714002017-06-30 23:30:52 +0200878 def test_dynamic_config_new_patchset(self):
879 self.executor_server.hold_jobs_in_build = True
880
881 tenant = self.sched.abide.tenants.get('tenant-one')
882 check_pipeline = tenant.layout.pipelines['check']
883
884 in_repo_conf = textwrap.dedent(
885 """
886 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200887 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -0700888 run: playbooks/project-test1.yaml
Tobias Henkelf02cf512017-07-21 22:55:34 +0200889
890 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200891 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700892 run: playbooks/project-test2.yaml
Tobias Henkel0f714002017-06-30 23:30:52 +0200893
894 - project:
895 name: org/project
896 check:
897 jobs:
898 - project-test2
899 """)
900
901 in_repo_playbook = textwrap.dedent(
902 """
903 - hosts: all
904 tasks: []
905 """)
906
907 file_dict = {'.zuul.yaml': in_repo_conf,
908 'playbooks/project-test2.yaml': in_repo_playbook}
909 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
910 files=file_dict)
911 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
912 self.waitUntilSettled()
913
914 items = check_pipeline.getAllItems()
915 self.assertEqual(items[0].change.number, '1')
916 self.assertEqual(items[0].change.patchset, '1')
917 self.assertTrue(items[0].live)
918
919 in_repo_conf = textwrap.dedent(
920 """
921 - job:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200922 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -0700923 run: playbooks/project-test1.yaml
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200924
925 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200926 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700927 run: playbooks/project-test2.yaml
Tobias Henkel0f714002017-06-30 23:30:52 +0200928
929 - project:
930 name: org/project
931 check:
932 jobs:
933 - project-test1
934 - project-test2
935 """)
936 file_dict = {'.zuul.yaml': in_repo_conf,
937 'playbooks/project-test2.yaml': in_repo_playbook}
938
939 A.addPatchset(files=file_dict)
940 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
941
942 self.waitUntilSettled()
943
944 items = check_pipeline.getAllItems()
945 self.assertEqual(items[0].change.number, '1')
946 self.assertEqual(items[0].change.patchset, '2')
947 self.assertTrue(items[0].live)
948
949 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200950 self.executor_server.release('project-test1')
951 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +0200952 self.executor_server.release()
953 self.waitUntilSettled()
954
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200955 self.assertHistory([
956 dict(name='project-test2', result='ABORTED', changes='1,1'),
957 dict(name='project-test1', result='SUCCESS', changes='1,2'),
958 dict(name='project-test2', result='SUCCESS', changes='1,2')])
959
James E. Blairff555742017-02-19 11:34:27 -0800960 def test_in_repo_branch(self):
961 in_repo_conf = textwrap.dedent(
962 """
963 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200964 name: project-test1
965
966 - job:
James E. Blairff555742017-02-19 11:34:27 -0800967 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700968 run: playbooks/project-test2.yaml
James E. Blairff555742017-02-19 11:34:27 -0800969
970 - project:
971 name: org/project
972 tenant-one-gate:
973 jobs:
974 - project-test2
975 """)
976
977 in_repo_playbook = textwrap.dedent(
978 """
979 - hosts: all
980 tasks: []
981 """)
982
983 file_dict = {'.zuul.yaml': in_repo_conf,
984 'playbooks/project-test2.yaml': in_repo_playbook}
985 self.create_branch('org/project', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700986 self.fake_gerrit.addEvent(
987 self.fake_gerrit.getFakeBranchCreatedEvent(
988 'org/project', 'stable'))
James E. Blair6069f2b2017-09-26 16:34:11 -0700989 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800990 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
991 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200992 A.addApproval('Code-Review', 2)
993 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800994 self.waitUntilSettled()
995 self.assertEqual(A.data['status'], 'MERGED')
996 self.assertEqual(A.reported, 2,
997 "A should report start and success")
998 self.assertIn('tenant-one-gate', A.messages[1],
999 "A should transit tenant-one gate")
1000 self.assertHistory([
1001 dict(name='project-test2', result='SUCCESS', changes='1,1')])
1002 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -08001003 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -08001004
1005 # The config change should not affect master.
1006 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001007 B.addApproval('Code-Review', 2)
1008 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -08001009 self.waitUntilSettled()
1010 self.assertHistory([
1011 dict(name='project-test2', result='SUCCESS', changes='1,1'),
1012 dict(name='project-test1', result='SUCCESS', changes='2,1')])
1013
1014 # The config change should be live for further changes on
1015 # stable.
1016 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001017 C.addApproval('Code-Review', 2)
1018 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -08001019 self.waitUntilSettled()
1020 self.assertHistory([
1021 dict(name='project-test2', result='SUCCESS', changes='1,1'),
1022 dict(name='project-test1', result='SUCCESS', changes='2,1'),
1023 dict(name='project-test2', result='SUCCESS', changes='3,1')])
1024
James E. Blaira5a12492017-05-03 11:40:48 -07001025 def test_crd_dynamic_config_branch(self):
1026 # Test that we can create a job in one repo and be able to use
1027 # it from a different branch on a different repo.
1028
1029 self.create_branch('org/project1', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -07001030 self.fake_gerrit.addEvent(
1031 self.fake_gerrit.getFakeBranchCreatedEvent(
1032 'org/project1', 'stable'))
James E. Blaira5a12492017-05-03 11:40:48 -07001033
1034 in_repo_conf = textwrap.dedent(
1035 """
1036 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +02001037 name: project-test1
1038
1039 - job:
James E. Blaira5a12492017-05-03 11:40:48 -07001040 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -07001041 run: playbooks/project-test2.yaml
James E. Blaira5a12492017-05-03 11:40:48 -07001042
1043 - project:
1044 name: org/project
1045 check:
1046 jobs:
1047 - project-test2
1048 """)
1049
1050 in_repo_playbook = textwrap.dedent(
1051 """
1052 - hosts: all
1053 tasks: []
1054 """)
1055
1056 file_dict = {'.zuul.yaml': in_repo_conf,
1057 'playbooks/project-test2.yaml': in_repo_playbook}
1058 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1059 files=file_dict)
1060
1061 second_repo_conf = textwrap.dedent(
1062 """
1063 - project:
1064 name: org/project1
1065 check:
1066 jobs:
1067 - project-test2
1068 """)
1069
1070 second_file_dict = {'.zuul.yaml': second_repo_conf}
1071 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
1072 files=second_file_dict)
1073 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1074 B.subject, A.data['id'])
1075
1076 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1077 self.waitUntilSettled()
1078 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1079 self.waitUntilSettled()
1080
1081 self.assertEqual(A.reported, 1, "A should report")
1082 self.assertHistory([
1083 dict(name='project-test2', result='SUCCESS', changes='1,1'),
1084 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
1085 ])
1086
James E. Blair97043882017-09-06 15:51:17 -07001087 def test_yaml_list_error(self):
1088 in_repo_conf = textwrap.dedent(
1089 """
1090 job: foo
1091 """)
1092
1093 file_dict = {'.zuul.yaml': in_repo_conf}
1094 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1095 files=file_dict)
1096 A.addApproval('Code-Review', 2)
1097 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1098 self.waitUntilSettled()
1099
1100 self.assertEqual(A.data['status'], 'NEW')
1101 self.assertEqual(A.reported, 1,
1102 "A should report failure")
1103 self.assertIn('not a list', A.messages[0],
1104 "A should have a syntax error reported")
1105
1106 def test_yaml_dict_error(self):
1107 in_repo_conf = textwrap.dedent(
1108 """
1109 - job
1110 """)
1111
1112 file_dict = {'.zuul.yaml': in_repo_conf}
1113 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1114 files=file_dict)
1115 A.addApproval('Code-Review', 2)
1116 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1117 self.waitUntilSettled()
1118
1119 self.assertEqual(A.data['status'], 'NEW')
1120 self.assertEqual(A.reported, 1,
1121 "A should report failure")
1122 self.assertIn('not a dictionary', A.messages[0],
1123 "A should have a syntax error reported")
1124
James E. Blairec953e12017-12-11 11:56:18 -08001125 def test_yaml_duplicate_key_error(self):
1126 in_repo_conf = textwrap.dedent(
1127 """
1128 - job:
1129 name: foo
1130 name: bar
1131 """)
1132
1133 file_dict = {'.zuul.yaml': in_repo_conf}
1134 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1135 files=file_dict)
1136 A.addApproval('Code-Review', 2)
1137 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1138 self.waitUntilSettled()
1139
1140 self.assertEqual(A.data['status'], 'NEW')
1141 self.assertEqual(A.reported, 1,
1142 "A should report failure")
1143 self.assertIn('appears more than once', A.messages[0],
1144 "A should have a syntax error reported")
1145
James E. Blair97043882017-09-06 15:51:17 -07001146 def test_yaml_key_error(self):
1147 in_repo_conf = textwrap.dedent(
1148 """
1149 - job:
1150 name: project-test2
1151 """)
1152
1153 file_dict = {'.zuul.yaml': in_repo_conf}
1154 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1155 files=file_dict)
1156 A.addApproval('Code-Review', 2)
1157 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1158 self.waitUntilSettled()
1159
1160 self.assertEqual(A.data['status'], 'NEW')
1161 self.assertEqual(A.reported, 1,
1162 "A should report failure")
1163 self.assertIn('has more than one key', A.messages[0],
1164 "A should have a syntax error reported")
1165
1166 def test_yaml_unknown_error(self):
1167 in_repo_conf = textwrap.dedent(
1168 """
1169 - foobar:
1170 foo: bar
1171 """)
1172
1173 file_dict = {'.zuul.yaml': in_repo_conf}
1174 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1175 files=file_dict)
1176 A.addApproval('Code-Review', 2)
1177 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1178 self.waitUntilSettled()
1179
1180 self.assertEqual(A.data['status'], 'NEW')
1181 self.assertEqual(A.reported, 1,
1182 "A should report failure")
1183 self.assertIn('not recognized', A.messages[0],
1184 "A should have a syntax error reported")
1185
James E. Blair149b69c2017-03-02 10:48:16 -08001186 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -08001187 in_repo_conf = textwrap.dedent(
1188 """
1189 - job:
1190 name: project-test2
1191 foo: error
1192 """)
1193
1194 file_dict = {'.zuul.yaml': in_repo_conf}
1195 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1196 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001197 A.addApproval('Code-Review', 2)
1198 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -08001199 self.waitUntilSettled()
1200
1201 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001202 self.assertEqual(A.reported, 1,
1203 "A should report failure")
1204 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -08001205 "A should have a syntax error reported")
1206
James E. Blair149b69c2017-03-02 10:48:16 -08001207 def test_trusted_syntax_error(self):
1208 in_repo_conf = textwrap.dedent(
1209 """
1210 - job:
1211 name: project-test2
1212 foo: error
1213 """)
1214
1215 file_dict = {'zuul.yaml': in_repo_conf}
1216 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1217 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001218 A.addApproval('Code-Review', 2)
1219 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -08001220 self.waitUntilSettled()
1221
1222 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001223 self.assertEqual(A.reported, 1,
1224 "A should report failure")
1225 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -08001226 "A should have a syntax error reported")
1227
James E. Blair6f140c72017-03-03 10:32:07 -08001228 def test_untrusted_yaml_error(self):
1229 in_repo_conf = textwrap.dedent(
1230 """
1231 - job:
1232 foo: error
1233 """)
1234
1235 file_dict = {'.zuul.yaml': in_repo_conf}
1236 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1237 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001238 A.addApproval('Code-Review', 2)
1239 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -08001240 self.waitUntilSettled()
1241
1242 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001243 self.assertEqual(A.reported, 1,
1244 "A should report failure")
1245 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -08001246 "A should have a syntax error reported")
1247
James E. Blairdb04e6a2017-05-03 14:49:36 -07001248 def test_untrusted_shadow_error(self):
1249 in_repo_conf = textwrap.dedent(
1250 """
1251 - job:
1252 name: common-config-test
1253 """)
1254
1255 file_dict = {'.zuul.yaml': in_repo_conf}
1256 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1257 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001258 A.addApproval('Code-Review', 2)
1259 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -07001260 self.waitUntilSettled()
1261
1262 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001263 self.assertEqual(A.reported, 1,
1264 "A should report failure")
1265 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -07001266 "A should have a syntax error reported")
1267
James E. Blaird5656ad2017-06-02 14:29:41 -07001268 def test_untrusted_pipeline_error(self):
1269 in_repo_conf = textwrap.dedent(
1270 """
1271 - pipeline:
1272 name: test
1273 """)
1274
1275 file_dict = {'.zuul.yaml': in_repo_conf}
1276 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1277 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001278 A.addApproval('Code-Review', 2)
1279 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -07001280 self.waitUntilSettled()
1281
1282 self.assertEqual(A.data['status'], 'NEW')
1283 self.assertEqual(A.reported, 1,
1284 "A should report failure")
1285 self.assertIn('Pipelines may not be defined', A.messages[0],
1286 "A should have a syntax error reported")
1287
1288 def test_untrusted_project_error(self):
1289 in_repo_conf = textwrap.dedent(
1290 """
1291 - project:
1292 name: org/project1
1293 """)
1294
1295 file_dict = {'.zuul.yaml': in_repo_conf}
1296 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1297 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001298 A.addApproval('Code-Review', 2)
1299 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -07001300 self.waitUntilSettled()
1301
1302 self.assertEqual(A.data['status'], 'NEW')
1303 self.assertEqual(A.reported, 1,
1304 "A should report failure")
1305 self.assertIn('the only project definition permitted', A.messages[0],
1306 "A should have a syntax error reported")
1307
James E. Blairf03173b2017-10-10 10:46:43 -07001308 def test_untrusted_depends_on_trusted(self):
1309 with open(os.path.join(FIXTURE_DIR,
1310 'config/in-repo/git/',
1311 'common-config/zuul.yaml')) as f:
1312 common_config = f.read()
1313
1314 common_config += textwrap.dedent(
1315 """
1316 - job:
1317 name: project-test9
1318 """)
1319
1320 file_dict = {'zuul.yaml': common_config}
1321 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1322 files=file_dict)
1323 in_repo_conf = textwrap.dedent(
1324 """
1325 - job:
1326 name: project-test1
1327 - project:
1328 name: org/project
1329 check:
1330 jobs:
1331 - project-test9
1332 """)
1333
1334 file_dict = {'zuul.yaml': in_repo_conf}
1335 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1336 files=file_dict)
1337 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1338 B.subject, A.data['id'])
1339 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1340 self.waitUntilSettled()
1341
1342 self.assertEqual(B.data['status'], 'NEW')
1343 self.assertEqual(B.reported, 1,
1344 "B should report failure")
1345 self.assertIn('depends on a change to a config project',
1346 B.messages[0],
1347 "A should have a syntax error reported")
1348
James E. Blaire64b0e42017-06-08 11:23:34 -07001349 def test_duplicate_node_error(self):
1350 in_repo_conf = textwrap.dedent(
1351 """
1352 - nodeset:
1353 name: duplicate
1354 nodes:
1355 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001356 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001357 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001358 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001359 """)
1360
1361 file_dict = {'.zuul.yaml': in_repo_conf}
1362 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1363 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001364 A.addApproval('Code-Review', 2)
1365 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -07001366 self.waitUntilSettled()
1367
1368 self.assertEqual(A.data['status'], 'NEW')
1369 self.assertEqual(A.reported, 1,
1370 "A should report failure")
1371 self.assertIn('appears multiple times', A.messages[0],
1372 "A should have a syntax error reported")
1373
1374 def test_duplicate_group_error(self):
1375 in_repo_conf = textwrap.dedent(
1376 """
1377 - nodeset:
1378 name: duplicate
1379 nodes:
1380 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001381 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001382 groups:
1383 - name: group
1384 nodes: compute
1385 - name: group
1386 nodes: compute
1387 """)
1388
1389 file_dict = {'.zuul.yaml': in_repo_conf}
1390 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1391 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001392 A.addApproval('Code-Review', 2)
1393 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -07001394 self.waitUntilSettled()
1395
1396 self.assertEqual(A.data['status'], 'NEW')
1397 self.assertEqual(A.reported, 1,
1398 "A should report failure")
1399 self.assertIn('appears multiple times', A.messages[0],
1400 "A should have a syntax error reported")
1401
James E. Blair4ae399f2017-09-20 17:15:09 -07001402 def test_secret_not_found_error(self):
1403 in_repo_conf = textwrap.dedent(
1404 """
1405 - job:
1406 name: test
1407 secrets: does-not-exist
1408 """)
1409
1410 file_dict = {'.zuul.yaml': in_repo_conf}
1411 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1412 files=file_dict)
1413 A.addApproval('Code-Review', 2)
1414 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1415 self.waitUntilSettled()
1416
1417 self.assertEqual(A.data['status'], 'NEW')
1418 self.assertEqual(A.reported, 1,
1419 "A should report failure")
1420 self.assertIn('secret "does-not-exist" was not found', A.messages[0],
1421 "A should have a syntax error reported")
1422
1423 def test_nodeset_not_found_error(self):
1424 in_repo_conf = textwrap.dedent(
1425 """
1426 - job:
1427 name: test
1428 nodeset: does-not-exist
1429 """)
1430
1431 file_dict = {'.zuul.yaml': in_repo_conf}
1432 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1433 files=file_dict)
1434 A.addApproval('Code-Review', 2)
1435 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1436 self.waitUntilSettled()
1437
1438 self.assertEqual(A.data['status'], 'NEW')
1439 self.assertEqual(A.reported, 1,
1440 "A should report failure")
1441 self.assertIn('nodeset "does-not-exist" was not found', A.messages[0],
1442 "A should have a syntax error reported")
1443
James E. Blair89e25eb2017-09-26 09:11:31 -07001444 def test_template_not_found_error(self):
1445 in_repo_conf = textwrap.dedent(
1446 """
1447 - job:
1448 name: project-test1
1449 - project:
1450 name: org/project
1451 templates:
1452 - does-not-exist
1453 """)
1454
1455 file_dict = {'.zuul.yaml': in_repo_conf}
1456 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1457 files=file_dict)
1458 A.addApproval('Code-Review', 2)
1459 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1460 self.waitUntilSettled()
1461
1462 self.assertEqual(A.data['status'], 'NEW')
1463 self.assertEqual(A.reported, 1,
1464 "A should report failure")
1465 self.assertIn('project template "does-not-exist" was not found',
1466 A.messages[0],
1467 "A should have a syntax error reported")
1468
Monty Taylor8be3c0c2017-10-06 10:37:37 -05001469 def test_job_list_in_project_template_not_dict_error(self):
1470 in_repo_conf = textwrap.dedent(
1471 """
1472 - job:
1473 name: project-test1
1474 - project-template:
1475 name: some-jobs
1476 check:
1477 jobs:
1478 - project-test1:
1479 - required-projects:
1480 org/project2
1481 """)
1482
1483 file_dict = {'.zuul.yaml': in_repo_conf}
1484 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1485 files=file_dict)
1486 A.addApproval('Code-Review', 2)
1487 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1488 self.waitUntilSettled()
1489
1490 self.assertEqual(A.data['status'], 'NEW')
1491 self.assertEqual(A.reported, 1,
1492 "A should report failure")
1493 self.assertIn('expected str for dictionary value',
1494 A.messages[0], "A should have a syntax error reported")
1495
1496 def test_job_list_in_project_not_dict_error(self):
1497 in_repo_conf = textwrap.dedent(
1498 """
1499 - job:
1500 name: project-test1
1501 - project:
1502 name: org/project1
1503 check:
1504 jobs:
1505 - project-test1:
1506 - required-projects:
1507 org/project2
1508 """)
1509
1510 file_dict = {'.zuul.yaml': in_repo_conf}
1511 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1512 files=file_dict)
1513 A.addApproval('Code-Review', 2)
1514 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1515 self.waitUntilSettled()
1516
1517 self.assertEqual(A.data['status'], 'NEW')
1518 self.assertEqual(A.reported, 1,
1519 "A should report failure")
1520 self.assertIn('expected str for dictionary value',
1521 A.messages[0], "A should have a syntax error reported")
1522
James E. Blair1235f142017-10-07 09:11:43 -07001523 def test_project_template(self):
1524 # Tests that a project template is not modified when used, and
1525 # can therefore be used in subsequent reconfigurations.
1526 in_repo_conf = textwrap.dedent(
1527 """
1528 - job:
1529 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001530 run: playbooks/project-test1.yaml
James E. Blair1235f142017-10-07 09:11:43 -07001531 - project-template:
1532 name: some-jobs
1533 tenant-one-gate:
1534 jobs:
1535 - project-test1:
1536 required-projects:
1537 - org/project1
1538 - project:
1539 name: org/project
1540 templates:
1541 - some-jobs
1542 """)
1543
1544 file_dict = {'.zuul.yaml': in_repo_conf}
1545 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1546 files=file_dict)
1547 A.addApproval('Code-Review', 2)
1548 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1549 self.waitUntilSettled()
1550 self.assertEqual(A.data['status'], 'MERGED')
1551 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1552 self.waitUntilSettled()
1553 in_repo_conf = textwrap.dedent(
1554 """
1555 - project:
1556 name: org/project1
1557 templates:
1558 - some-jobs
1559 """)
1560 file_dict = {'.zuul.yaml': in_repo_conf}
1561 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
1562 files=file_dict)
1563 B.addApproval('Code-Review', 2)
1564 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1565 self.waitUntilSettled()
1566 self.assertEqual(B.data['status'], 'MERGED')
1567
James E. Blairbccdfcf2017-10-07 13:37:26 -07001568 def test_job_remove_add(self):
1569 # Tests that a job can be removed from one repo and added in another.
1570 # First, remove the current config for project1 since it
1571 # references the job we want to remove.
1572 file_dict = {'.zuul.yaml': None}
1573 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1574 files=file_dict)
1575 A.setMerged()
1576 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1577 self.waitUntilSettled()
1578 # Then propose a change to delete the job from one repo...
1579 file_dict = {'.zuul.yaml': None}
1580 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1581 files=file_dict)
1582 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1583 self.waitUntilSettled()
1584 # ...and a second that depends on it that adds it to another repo.
1585 in_repo_conf = textwrap.dedent(
1586 """
1587 - job:
1588 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001589 run: playbooks/project-test1.yaml
James E. Blairbccdfcf2017-10-07 13:37:26 -07001590
1591 - project:
1592 name: org/project1
1593 check:
1594 jobs:
1595 - project-test1
1596 """)
1597 in_repo_playbook = textwrap.dedent(
1598 """
1599 - hosts: all
1600 tasks: []
1601 """)
1602 file_dict = {'.zuul.yaml': in_repo_conf,
1603 'playbooks/project-test1.yaml': in_repo_playbook}
1604 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C',
1605 files=file_dict,
1606 parent='refs/changes/1/1/1')
1607 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1608 C.subject, B.data['id'])
1609 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1610 self.waitUntilSettled()
1611 self.assertHistory([
1612 dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'),
1613 ], ordered=False)
1614
James E. Blair09f9ffe2017-07-11 15:30:25 -07001615 def test_multi_repo(self):
1616 downstream_repo_conf = textwrap.dedent(
1617 """
1618 - project:
1619 name: org/project1
1620 tenant-one-gate:
1621 jobs:
1622 - project-test1
1623
1624 - job:
1625 name: project1-test1
1626 parent: project-test1
1627 """)
1628
1629 file_dict = {'.zuul.yaml': downstream_repo_conf}
1630 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1631 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001632 A.addApproval('Code-Review', 2)
1633 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001634 self.waitUntilSettled()
1635
1636 self.assertEqual(A.data['status'], 'MERGED')
1637 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1638 self.waitUntilSettled()
1639
1640 upstream_repo_conf = textwrap.dedent(
1641 """
1642 - job:
1643 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001644 run: playbooks/project-test1.yaml
James E. Blair09f9ffe2017-07-11 15:30:25 -07001645
1646 - job:
1647 name: project-test2
1648
1649 - project:
1650 name: org/project
1651 tenant-one-gate:
1652 jobs:
1653 - project-test1
1654 """)
1655
1656 file_dict = {'.zuul.yaml': upstream_repo_conf}
1657 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1658 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001659 B.addApproval('Code-Review', 2)
1660 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001661 self.waitUntilSettled()
1662
1663 self.assertEqual(B.data['status'], 'MERGED')
1664 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
1665 self.waitUntilSettled()
1666
1667 tenant = self.sched.abide.tenants.get('tenant-one')
1668 # Ensure the latest change is reflected in the config; if it
1669 # isn't this will raise an exception.
1670 tenant.layout.getJob('project-test2')
1671
James E. Blair332636e2017-09-05 10:14:35 -07001672 def test_pipeline_error(self):
1673 with open(os.path.join(FIXTURE_DIR,
1674 'config/in-repo/git/',
1675 'common-config/zuul.yaml')) as f:
1676 base_common_config = f.read()
1677
1678 in_repo_conf_A = textwrap.dedent(
1679 """
1680 - pipeline:
1681 name: periodic
1682 foo: error
1683 """)
1684
1685 file_dict = {'zuul.yaml': None,
1686 'zuul.d/main.yaml': base_common_config,
1687 'zuul.d/test1.yaml': in_repo_conf_A}
1688 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1689 files=file_dict)
1690 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1691 self.waitUntilSettled()
1692 self.assertEqual(A.reported, 1,
1693 "A should report failure")
1694 self.assertIn('syntax error',
1695 A.messages[0],
1696 "A should have an error reported")
1697
1698 def test_change_series_error(self):
1699 with open(os.path.join(FIXTURE_DIR,
1700 'config/in-repo/git/',
1701 'common-config/zuul.yaml')) as f:
1702 base_common_config = f.read()
1703
1704 in_repo_conf_A = textwrap.dedent(
1705 """
1706 - pipeline:
1707 name: periodic
1708 foo: error
1709 """)
1710
1711 file_dict = {'zuul.yaml': None,
1712 'zuul.d/main.yaml': base_common_config,
1713 'zuul.d/test1.yaml': in_repo_conf_A}
1714 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1715 files=file_dict)
1716
1717 in_repo_conf_B = textwrap.dedent(
1718 """
1719 - job:
1720 name: project-test2
1721 foo: error
1722 """)
1723
1724 file_dict = {'zuul.yaml': None,
1725 'zuul.d/main.yaml': base_common_config,
1726 'zuul.d/test1.yaml': in_repo_conf_A,
1727 'zuul.d/test2.yaml': in_repo_conf_B}
1728 B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B',
1729 files=file_dict)
1730 B.setDependsOn(A, 1)
1731 C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C')
1732 C.setDependsOn(B, 1)
1733 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1734 self.waitUntilSettled()
1735
1736 self.assertEqual(C.reported, 1,
1737 "C should report failure")
1738 self.assertIn('depends on a change that failed to merge',
1739 C.messages[0],
1740 "C should have an error reported")
1741
James E. Blair1ef8f7c2017-12-13 17:18:34 -08001742 def test_pipeline_debug(self):
1743 in_repo_conf = textwrap.dedent(
1744 """
1745 - job:
1746 name: project-test1
1747 run: playbooks/project-test1.yaml
1748 - project:
1749 name: org/project
1750 check:
1751 debug: True
1752 jobs:
1753 - project-test1
1754 """)
1755
1756 file_dict = {'.zuul.yaml': in_repo_conf}
1757 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1758 files=file_dict)
1759 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1760 self.waitUntilSettled()
1761
1762 self.assertEqual(A.data['status'], 'NEW')
1763 self.assertEqual(A.reported, 1,
1764 "A should report success")
1765 self.assertIn('Debug information:',
1766 A.messages[0], "A should have debug info")
1767
James E. Blairc73c73a2017-01-20 15:15:15 -08001768
James E. Blairc9455002017-09-06 09:22:19 -07001769class TestInRepoJoin(ZuulTestCase):
1770 # In this config, org/project is not a member of any pipelines, so
1771 # that we may test the changes that cause it to join them.
1772
1773 tenant_config_file = 'config/in-repo-join/main.yaml'
1774
1775 def test_dynamic_dependent_pipeline(self):
1776 # Test dynamically adding a project to a
1777 # dependent pipeline for the first time
1778 self.executor_server.hold_jobs_in_build = True
1779
1780 tenant = self.sched.abide.tenants.get('tenant-one')
1781 gate_pipeline = tenant.layout.pipelines['gate']
1782
1783 in_repo_conf = textwrap.dedent(
1784 """
1785 - job:
1786 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001787 run: playbooks/project-test1.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001788
1789 - job:
1790 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -07001791 run: playbooks/project-test2.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001792
1793 - project:
1794 name: org/project
1795 gate:
1796 jobs:
1797 - project-test2
1798 """)
1799
1800 in_repo_playbook = textwrap.dedent(
1801 """
1802 - hosts: all
1803 tasks: []
1804 """)
1805
1806 file_dict = {'.zuul.yaml': in_repo_conf,
1807 'playbooks/project-test2.yaml': in_repo_playbook}
1808 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1809 files=file_dict)
1810 A.addApproval('Code-Review', 2)
1811 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1812 self.waitUntilSettled()
1813
1814 items = gate_pipeline.getAllItems()
1815 self.assertEqual(items[0].change.number, '1')
1816 self.assertEqual(items[0].change.patchset, '1')
1817 self.assertTrue(items[0].live)
1818
1819 self.executor_server.hold_jobs_in_build = False
1820 self.executor_server.release()
1821 self.waitUntilSettled()
1822
1823 # Make sure the dynamic queue got cleaned up
1824 self.assertEqual(gate_pipeline.queues, [])
1825
1826 def test_dynamic_dependent_pipeline_failure(self):
1827 # Test that a change behind a failing change adding a project
1828 # to a dependent pipeline is dequeued.
1829 self.executor_server.hold_jobs_in_build = True
1830
1831 in_repo_conf = textwrap.dedent(
1832 """
1833 - job:
1834 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001835 run: playbooks/project-test1.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001836
1837 - project:
1838 name: org/project
1839 gate:
1840 jobs:
1841 - project-test1
1842 """)
1843
1844 file_dict = {'.zuul.yaml': in_repo_conf}
1845 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1846 files=file_dict)
1847 self.executor_server.failJob('project-test1', A)
1848 A.addApproval('Code-Review', 2)
1849 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1850 self.waitUntilSettled()
1851
1852 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1853 B.addApproval('Code-Review', 2)
1854 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1855 self.waitUntilSettled()
1856
James E. Blair3490c5d2017-09-07 08:33:23 -07001857 self.orderedRelease()
James E. Blairc9455002017-09-06 09:22:19 -07001858 self.waitUntilSettled()
1859 self.assertEqual(A.reported, 2,
1860 "A should report start and failure")
1861 self.assertEqual(A.data['status'], 'NEW')
1862 self.assertEqual(B.reported, 1,
1863 "B should report start")
1864 self.assertHistory([
1865 dict(name='project-test1', result='FAILURE', changes='1,1'),
James E. Blair3490c5d2017-09-07 08:33:23 -07001866 dict(name='project-test1', result='ABORTED', changes='1,1 2,1'),
James E. Blairc9455002017-09-06 09:22:19 -07001867 ], ordered=False)
1868
James E. Blair0af198f2017-09-06 09:52:35 -07001869 def test_dynamic_dependent_pipeline_absent(self):
1870 # Test that a series of dependent changes don't report merge
1871 # failures to a pipeline they aren't in.
1872 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1873 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1874 B.setDependsOn(A, 1)
1875
1876 A.addApproval('Code-Review', 2)
1877 A.addApproval('Approved', 1)
1878 B.addApproval('Code-Review', 2)
1879 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1880 self.waitUntilSettled()
1881 self.assertEqual(A.reported, 0,
1882 "A should not report")
1883 self.assertEqual(A.data['status'], 'NEW')
1884 self.assertEqual(B.reported, 0,
1885 "B should not report")
1886 self.assertEqual(B.data['status'], 'NEW')
1887 self.assertHistory([])
1888
James E. Blairc9455002017-09-06 09:22:19 -07001889
James E. Blairc73c73a2017-01-20 15:15:15 -08001890class TestAnsible(AnsibleZuulTestCase):
1891 # A temporary class to hold new tests while others are disabled
1892
1893 tenant_config_file = 'config/ansible/main.yaml'
1894
1895 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +11001896 # Keep the jobdir around so we can inspect contents if an
1897 # assert fails.
1898 self.executor_server.keep_jobdir = True
1899 # Output extra ansible info so we might see errors.
1900 self.executor_server.verbose = True
1901 # Add a site variables file, used by check-vars
1902 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
1903 'variables.yaml')
1904 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -08001905 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1906 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1907 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +02001908 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +11001909 with self.jobLog(build_timeout):
1910 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001911 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +11001912 with self.jobLog(build_faillocal):
1913 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001914 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +11001915 with self.jobLog(build_failpost):
1916 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001917 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +11001918 with self.jobLog(build_check_vars):
1919 self.assertEqual(build_check_vars.result, 'SUCCESS')
Monty Tayloraff8b402017-08-16 18:40:41 -05001920 build_check_secret_names = self.getJobFromHistory('check-secret-names')
1921 with self.jobLog(build_check_secret_names):
1922 self.assertEqual(build_check_secret_names.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001923 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +11001924 with self.jobLog(build_hello):
1925 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001926 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +11001927 with self.jobLog(build_python27):
1928 self.assertEqual(build_python27.result, 'SUCCESS')
1929 flag_path = os.path.join(self.test_root,
1930 build_python27.uuid + '.flag')
1931 self.assertTrue(os.path.exists(flag_path))
1932 copied_path = os.path.join(self.test_root, build_python27.uuid +
1933 '.copied')
1934 self.assertTrue(os.path.exists(copied_path))
1935 failed_path = os.path.join(self.test_root, build_python27.uuid +
1936 '.failed')
1937 self.assertFalse(os.path.exists(failed_path))
1938 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
1939 '.pre.flag')
1940 self.assertTrue(os.path.exists(pre_flag_path))
1941 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
1942 '.post.flag')
1943 self.assertTrue(os.path.exists(post_flag_path))
1944 bare_role_flag_path = os.path.join(self.test_root,
1945 build_python27.uuid +
1946 '.bare-role.flag')
1947 self.assertTrue(os.path.exists(bare_role_flag_path))
1948 secrets_path = os.path.join(self.test_root,
1949 build_python27.uuid + '.secrets')
1950 with open(secrets_path) as f:
1951 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -08001952
Jamie Lennox7655b552017-03-17 12:33:38 +11001953 msg = A.messages[0]
1954 success = "{} https://success.example.com/zuul-logs/{}"
1955 fail = "{} https://failure.example.com/zuul-logs/{}"
1956 self.assertIn(success.format("python27", build_python27.uuid), msg)
1957 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
1958 self.assertIn(success.format("check-vars",
1959 build_check_vars.uuid), msg)
1960 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
1961 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
1962 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +02001963
James E. Blairabbaa6f2017-04-06 16:11:44 -07001964 def _add_job(self, job_name):
1965 conf = textwrap.dedent(
1966 """
1967 - job:
1968 name: %s
James E. Blair2f589fe2017-10-26 12:57:41 -07001969 run: playbooks/%s.yaml
James E. Blairabbaa6f2017-04-06 16:11:44 -07001970
1971 - project:
1972 name: org/plugin-project
1973 check:
1974 jobs:
1975 - %s
James E. Blair2f589fe2017-10-26 12:57:41 -07001976 """ % (job_name, job_name, job_name))
James E. Blairabbaa6f2017-04-06 16:11:44 -07001977
1978 file_dict = {'.zuul.yaml': conf}
1979 A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A',
1980 files=file_dict)
1981 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1982 self.waitUntilSettled()
1983
1984 def test_plugins(self):
1985 # Keep the jobdir around so we can inspect contents if an
1986 # assert fails.
1987 self.executor_server.keep_jobdir = True
1988 # Output extra ansible info so we might see errors.
1989 self.executor_server.verbose = True
1990
1991 count = 0
1992 plugin_tests = [
1993 ('passwd', 'FAILURE'),
1994 ('cartesian', 'SUCCESS'),
1995 ('consul_kv', 'FAILURE'),
1996 ('credstash', 'FAILURE'),
1997 ('csvfile_good', 'SUCCESS'),
1998 ('csvfile_bad', 'FAILURE'),
Monty Taylor93ad2212017-08-02 14:59:50 -05001999 ('uri_bad_path', 'FAILURE'),
2000 ('uri_bad_scheme', 'FAILURE'),
Monty Taylor788a40e2017-08-02 16:14:05 -05002001 ('block_local_override', 'FAILURE'),
Monty Taylor8da768f2017-08-31 14:15:35 -05002002 ('file_local_good', 'SUCCESS'),
2003 ('file_local_bad', 'FAILURE'),
James E. Blairabbaa6f2017-04-06 16:11:44 -07002004 ]
2005 for job_name, result in plugin_tests:
2006 count += 1
2007 self._add_job(job_name)
2008
2009 job = self.getJobFromHistory(job_name)
2010 with self.jobLog(job):
2011 self.assertEqual(count, len(self.history))
2012 build = self.history[-1]
2013 self.assertEqual(build.result, result)
2014
2015 # TODOv3(jeblair): parse the ansible output and verify we're
2016 # getting the exception we expect.
2017
James E. Blairb9c0d772017-03-03 14:34:49 -08002018
James E. Blaira4d4eef2017-06-30 14:49:17 -07002019class TestPrePlaybooks(AnsibleZuulTestCase):
2020 # A temporary class to hold new tests while others are disabled
2021
2022 tenant_config_file = 'config/pre-playbook/main.yaml'
2023
2024 def test_pre_playbook_fail(self):
2025 # Test that we run the post playbooks (but not the actual
2026 # playbook) when a pre-playbook fails.
2027 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2028 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2029 self.waitUntilSettled()
2030 build = self.getJobFromHistory('python27')
2031 self.assertIsNone(build.result)
2032 self.assertIn('RETRY_LIMIT', A.messages[0])
2033 flag_path = os.path.join(self.test_root, build.uuid +
2034 '.main.flag')
2035 self.assertFalse(os.path.exists(flag_path))
2036 pre_flag_path = os.path.join(self.test_root, build.uuid +
2037 '.pre.flag')
2038 self.assertFalse(os.path.exists(pre_flag_path))
2039 post_flag_path = os.path.join(self.test_root, build.uuid +
2040 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -07002041 self.assertTrue(os.path.exists(post_flag_path),
2042 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -07002043
2044
James E. Blairbacbb882017-10-17 09:48:23 -07002045class TestPostPlaybooks(AnsibleZuulTestCase):
2046 tenant_config_file = 'config/post-playbook/main.yaml'
2047
2048 def test_post_playbook_abort(self):
2049 # Test that when we abort a job in the post playbook, that we
2050 # don't send back POST_FAILURE.
2051 self.executor_server.verbose = True
2052 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2053 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2054
2055 while not len(self.builds):
2056 time.sleep(0.1)
2057 build = self.builds[0]
2058
2059 post_start = os.path.join(self.test_root, build.uuid +
2060 '.post_start.flag')
2061 start = time.time()
2062 while time.time() < start + 90:
2063 if os.path.exists(post_start):
2064 break
2065 time.sleep(0.1)
2066 # The post playbook has started, abort the job
2067 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
2068 self.waitUntilSettled()
2069
2070 build = self.getJobFromHistory('python27')
2071 self.assertEqual('ABORTED', build.result)
2072
2073 post_end = os.path.join(self.test_root, build.uuid +
2074 '.post_end.flag')
2075 self.assertTrue(os.path.exists(post_start))
2076 self.assertFalse(os.path.exists(post_end))
2077
2078
James E. Blairb9c0d772017-03-03 14:34:49 -08002079class TestBrokenConfig(ZuulTestCase):
2080 # Test that we get an appropriate syntax error if we start with a
2081 # broken config.
2082
2083 tenant_config_file = 'config/broken/main.yaml'
2084
2085 def setUp(self):
2086 with testtools.ExpectedException(
2087 zuul.configloader.ConfigurationSyntaxError,
2088 "\nZuul encountered a syntax error"):
2089 super(TestBrokenConfig, self).setUp()
2090
2091 def test_broken_config_on_startup(self):
2092 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00002093
2094
2095class TestProjectKeys(ZuulTestCase):
2096 # Test that we can generate project keys
2097
2098 # Normally the test infrastructure copies a static key in place
2099 # for each project before starting tests. This saves time because
2100 # Zuul's automatic key-generation on startup can be slow. To make
2101 # sure we exercise that code, in this test we allow Zuul to create
2102 # keys for the project on startup.
2103 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +02002104 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00002105 tenant_config_file = 'config/in-repo/main.yaml'
2106
2107 def test_key_generation(self):
2108 key_root = os.path.join(self.state_root, 'keys')
2109 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
2110 # Make sure that a proper key was created on startup
2111 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -07002112 private_key, public_key = \
2113 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00002114
2115 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
2116 fixture_private_key = i.read()
2117
2118 # Make sure that we didn't just end up with the static fixture
2119 # key
2120 self.assertNotEqual(fixture_private_key, private_key)
2121
2122 # Make sure it's the right length
2123 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -07002124
2125
James E. Blairbb94dfa2017-07-11 07:45:19 -07002126class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -07002127 def _assertRolePath(self, build, playbook, content):
2128 path = os.path.join(self.test_root, build.uuid,
2129 'ansible', playbook, 'ansible.cfg')
2130 roles_paths = []
2131 with open(path) as f:
2132 for line in f:
2133 if line.startswith('roles_path'):
2134 roles_paths.append(line)
2135 print(roles_paths)
2136 if content:
2137 self.assertEqual(len(roles_paths), 1,
2138 "Should have one roles_path line in %s" %
2139 (playbook,))
2140 self.assertIn(content, roles_paths[0])
2141 else:
2142 self.assertEqual(len(roles_paths), 0,
2143 "Should have no roles_path line in %s" %
2144 (playbook,))
2145
James E. Blairbb94dfa2017-07-11 07:45:19 -07002146
2147class TestRoles(RoleTestCase):
2148 tenant_config_file = 'config/roles/main.yaml'
2149
James E. Blairbce76932017-05-04 10:03:15 -07002150 def test_role(self):
2151 # This exercises a proposed change to a role being checked out
2152 # and used.
2153 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
2154 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2155 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
2156 B.subject, A.data['id'])
2157 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2158 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2159 self.waitUntilSettled()
2160 self.assertHistory([
2161 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
2162 ])
James E. Blair6459db12017-06-29 14:57:20 -07002163
James E. Blair1b27f6a2017-07-14 14:09:07 -07002164 def test_role_inheritance(self):
2165 self.executor_server.hold_jobs_in_build = True
2166 conf = textwrap.dedent(
2167 """
2168 - job:
2169 name: parent
2170 roles:
2171 - zuul: bare-role
Ian Wienand548c43c2017-12-05 14:16:32 +11002172 pre-run: playbooks/parent-pre.yaml
2173 post-run: playbooks/parent-post.yaml
James E. Blair1b27f6a2017-07-14 14:09:07 -07002174
2175 - job:
2176 name: project-test
2177 parent: parent
James E. Blair2f589fe2017-10-26 12:57:41 -07002178 run: playbooks/project-test.yaml
James E. Blair1b27f6a2017-07-14 14:09:07 -07002179 roles:
2180 - zuul: org/project
2181
2182 - project:
2183 name: org/project
2184 check:
2185 jobs:
2186 - project-test
2187 """)
2188
2189 file_dict = {'.zuul.yaml': conf}
2190 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2191 files=file_dict)
2192 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2193 self.waitUntilSettled()
2194
2195 self.assertEqual(len(self.builds), 1)
2196 build = self.getBuildByName('project-test')
2197 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
2198 self._assertRolePath(build, 'playbook_0', 'role_0')
2199 self._assertRolePath(build, 'playbook_0', 'role_1')
2200 self._assertRolePath(build, 'post_playbook_0', 'role_0')
2201
2202 self.executor_server.hold_jobs_in_build = False
2203 self.executor_server.release()
2204 self.waitUntilSettled()
2205
2206 self.assertHistory([
2207 dict(name='project-test', result='SUCCESS', changes='1,1'),
2208 ])
2209
James E. Blair6f699732017-07-18 14:19:11 -07002210 def test_role_error(self):
2211 conf = textwrap.dedent(
2212 """
2213 - job:
2214 name: project-test
James E. Blair2f589fe2017-10-26 12:57:41 -07002215 run: playbooks/project-test.yaml
James E. Blair6f699732017-07-18 14:19:11 -07002216 roles:
2217 - zuul: common-config
2218
2219 - project:
2220 name: org/project
2221 check:
2222 jobs:
2223 - project-test
2224 """)
2225
2226 file_dict = {'.zuul.yaml': conf}
2227 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2228 files=file_dict)
2229 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2230 self.waitUntilSettled()
2231 self.assertIn(
2232 '- project-test project-test : ERROR Unable to find role',
2233 A.messages[-1])
2234
James E. Blair6459db12017-06-29 14:57:20 -07002235
James E. Blairbb94dfa2017-07-11 07:45:19 -07002236class TestImplicitRoles(RoleTestCase):
2237 tenant_config_file = 'config/implicit-roles/main.yaml'
2238
2239 def test_missing_roles(self):
2240 # Test implicit and explicit roles for a project which does
2241 # not have roles. The implicit role should be silently
2242 # ignored since the project doesn't supply roles, but if a
2243 # user declares an explicit role, it should error.
2244 self.executor_server.hold_jobs_in_build = True
2245 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
2246 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2247 self.waitUntilSettled()
2248
2249 self.assertEqual(len(self.builds), 2)
2250 build = self.getBuildByName('implicit-role-fail')
2251 self._assertRolePath(build, 'playbook_0', None)
2252
2253 self.executor_server.hold_jobs_in_build = False
2254 self.executor_server.release()
2255 self.waitUntilSettled()
2256 # The retry_limit doesn't get recorded
2257 self.assertHistory([
2258 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
2259 ])
2260
2261 def test_roles(self):
2262 # Test implicit and explicit roles for a project which does
2263 # have roles. In both cases, we should end up with the role
2264 # in the path. In the explicit case, ensure we end up with
2265 # the name we specified.
2266 self.executor_server.hold_jobs_in_build = True
2267 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
2268 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2269 self.waitUntilSettled()
2270
2271 self.assertEqual(len(self.builds), 2)
2272 build = self.getBuildByName('implicit-role-ok')
2273 self._assertRolePath(build, 'playbook_0', 'role_0')
2274
2275 build = self.getBuildByName('explicit-role-ok')
2276 self._assertRolePath(build, 'playbook_0', 'role_0')
2277
2278 self.executor_server.hold_jobs_in_build = False
2279 self.executor_server.release()
2280 self.waitUntilSettled()
2281 self.assertHistory([
2282 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
2283 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
2284 ], ordered=False)
2285
2286
James E. Blair6459db12017-06-29 14:57:20 -07002287class TestShadow(ZuulTestCase):
2288 tenant_config_file = 'config/shadow/main.yaml'
2289
2290 def test_shadow(self):
2291 # Test that a repo is allowed to shadow another's job definitions.
2292 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2293 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2294 self.waitUntilSettled()
2295 self.assertHistory([
2296 dict(name='test1', result='SUCCESS', changes='1,1'),
2297 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -07002298 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -07002299
2300
2301class TestDataReturn(AnsibleZuulTestCase):
2302 tenant_config_file = 'config/data-return/main.yaml'
2303
2304 def test_data_return(self):
James E. Blair196f61a2017-06-30 15:42:29 -07002305 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2306 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2307 self.waitUntilSettled()
2308 self.assertHistory([
2309 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07002310 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
James E. Blair698703c2017-09-15 20:58:30 -06002311 dict(name='child', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07002312 ], ordered=False)
2313 self.assertIn('- data-return http://example.com/test/log/url/',
2314 A.messages[-1])
2315 self.assertIn('- data-return-relative '
2316 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -07002317 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -07002318
2319
2320class TestDiskAccounting(AnsibleZuulTestCase):
2321 config_file = 'zuul-disk-accounting.conf'
2322 tenant_config_file = 'config/disk-accountant/main.yaml'
2323
2324 def test_disk_accountant_kills_job(self):
2325 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2326 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2327 self.waitUntilSettled()
2328 self.assertHistory([
2329 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002330
2331
2332class TestMaxNodesPerJob(AnsibleZuulTestCase):
2333 tenant_config_file = 'config/multi-tenant/main.yaml'
2334
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00002335 def test_max_timeout_exceeded(self):
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002336 in_repo_conf = textwrap.dedent(
2337 """
2338 - job:
2339 name: test-job
James E. Blair7e3e6882017-09-20 15:47:13 -07002340 nodeset:
2341 nodes:
2342 - name: node01
2343 label: fake
2344 - name: node02
2345 label: fake
2346 - name: node03
2347 label: fake
2348 - name: node04
2349 label: fake
2350 - name: node05
2351 label: fake
2352 - name: node06
2353 label: fake
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002354 """)
2355 file_dict = {'.zuul.yaml': in_repo_conf}
2356 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2357 files=file_dict)
2358 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2359 self.waitUntilSettled()
2360 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
2361 A.messages[0], "A should fail because of nodes limit")
2362
2363 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2364 files=file_dict)
2365 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2366 self.waitUntilSettled()
2367 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
2368 "B should not fail because of nodes limit")
James E. Blair2bab6e72017-08-07 09:52:45 -07002369
2370
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00002371class TestMaxTimeout(AnsibleZuulTestCase):
2372 tenant_config_file = 'config/multi-tenant/main.yaml'
2373
2374 def test_max_nodes_reached(self):
2375 in_repo_conf = textwrap.dedent(
2376 """
2377 - job:
2378 name: test-job
2379 timeout: 3600
2380 """)
2381 file_dict = {'.zuul.yaml': in_repo_conf}
2382 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2383 files=file_dict)
2384 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2385 self.waitUntilSettled()
2386 self.assertIn('The job "test-job" exceeds tenant max-job-timeout',
2387 A.messages[0], "A should fail because of timeout limit")
2388
2389 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2390 files=file_dict)
2391 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2392 self.waitUntilSettled()
2393 self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0],
2394 "B should not fail because of timeout limit")
2395
2396
James E. Blair7edc25f2017-10-26 10:47:14 -07002397class TestPragma(ZuulTestCase):
2398 tenant_config_file = 'config/pragma/main.yaml'
2399
2400 def test_no_pragma(self):
2401 self.create_branch('org/project', 'stable')
2402 with open(os.path.join(FIXTURE_DIR,
2403 'config/pragma/git/',
2404 'org_project/nopragma.yaml')) as f:
2405 config = f.read()
2406 file_dict = {'.zuul.yaml': config}
2407 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2408 files=file_dict)
2409 A.addApproval('Code-Review', 2)
2410 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2411 self.waitUntilSettled()
2412 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2413 self.waitUntilSettled()
2414
2415 # This is an untrusted repo with 2 branches, so it should have
2416 # an implied branch matcher for the job.
2417 tenant = self.sched.abide.tenants.get('tenant-one')
2418 jobs = tenant.layout.getJobs('test-job')
2419 self.assertEqual(len(jobs), 1)
2420 for job in tenant.layout.getJobs('test-job'):
2421 self.assertIsNotNone(job.branch_matcher)
2422
2423 def test_pragma(self):
2424 self.create_branch('org/project', 'stable')
2425 with open(os.path.join(FIXTURE_DIR,
2426 'config/pragma/git/',
2427 'org_project/pragma.yaml')) as f:
2428 config = f.read()
2429 file_dict = {'.zuul.yaml': config}
2430 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2431 files=file_dict)
2432 A.addApproval('Code-Review', 2)
2433 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2434 self.waitUntilSettled()
2435 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2436 self.waitUntilSettled()
2437
2438 # This is an untrusted repo with 2 branches, so it would
2439 # normally have an implied branch matcher, but our pragma
2440 # overrides it.
2441 tenant = self.sched.abide.tenants.get('tenant-one')
2442 jobs = tenant.layout.getJobs('test-job')
2443 self.assertEqual(len(jobs), 1)
2444 for job in tenant.layout.getJobs('test-job'):
2445 self.assertIsNone(job.branch_matcher)
2446
2447
James E. Blair37c3d8c2017-12-13 15:06:11 -08002448class TestPragmaMultibranch(ZuulTestCase):
2449 tenant_config_file = 'config/pragma-multibranch/main.yaml'
2450
2451 def test_no_branch_matchers(self):
2452 self.create_branch('org/project1', 'stable/pike')
2453 self.create_branch('org/project2', 'stable/jewel')
2454 self.fake_gerrit.addEvent(
2455 self.fake_gerrit.getFakeBranchCreatedEvent(
2456 'org/project1', 'stable/pike'))
2457 self.fake_gerrit.addEvent(
2458 self.fake_gerrit.getFakeBranchCreatedEvent(
2459 'org/project2', 'stable/jewel'))
2460 self.waitUntilSettled()
2461 # We want the jobs defined on the stable/pike branch of
2462 # project1 to apply to the stable/jewel branch of project2.
2463
2464 # First, without the pragma line, the jobs should not run
2465 # because in project1 they have branch matchers for pike, so
2466 # they will not match a jewel change.
2467 B = self.fake_gerrit.addFakeChange('org/project2', 'stable/jewel', 'B')
2468 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2469 self.waitUntilSettled()
2470 self.assertHistory([])
2471
2472 # Add a pragma line to disable implied branch matchers in
2473 # project1, so that the jobs and templates apply to both
2474 # branches.
2475 with open(os.path.join(FIXTURE_DIR,
2476 'config/pragma-multibranch/git/',
2477 'org_project1/zuul.yaml')) as f:
2478 config = f.read()
2479 extra_conf = textwrap.dedent(
2480 """
2481 - pragma:
2482 implied-branch-matchers: False
2483 """)
2484 config = extra_conf + config
2485 file_dict = {'zuul.yaml': config}
2486 A = self.fake_gerrit.addFakeChange('org/project1', 'stable/pike', 'A',
2487 files=file_dict)
2488 A.addApproval('Code-Review', 2)
2489 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2490 self.waitUntilSettled()
2491 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2492 self.waitUntilSettled()
2493
2494 # Now verify that when we propose a change to jewel, we get
2495 # the pike/jewel jobs.
2496 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2497 self.waitUntilSettled()
2498 self.assertHistory([
2499 dict(name='test-job1', result='SUCCESS', changes='1,1'),
2500 dict(name='test-job2', result='SUCCESS', changes='1,1'),
2501 ], ordered=False)
2502
2503 def test_supplied_branch_matchers(self):
2504 self.create_branch('org/project1', 'stable/pike')
2505 self.create_branch('org/project2', 'stable/jewel')
2506 self.fake_gerrit.addEvent(
2507 self.fake_gerrit.getFakeBranchCreatedEvent(
2508 'org/project1', 'stable/pike'))
2509 self.fake_gerrit.addEvent(
2510 self.fake_gerrit.getFakeBranchCreatedEvent(
2511 'org/project2', 'stable/jewel'))
2512 self.waitUntilSettled()
2513 # We want the jobs defined on the stable/pike branch of
2514 # project1 to apply to the stable/jewel branch of project2.
2515
2516 # First, without the pragma line, the jobs should not run
2517 # because in project1 they have branch matchers for pike, so
2518 # they will not match a jewel change.
2519 B = self.fake_gerrit.addFakeChange('org/project2', 'stable/jewel', 'B')
2520 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2521 self.waitUntilSettled()
2522 self.assertHistory([])
2523
2524 # Add a pragma line to disable implied branch matchers in
2525 # project1, so that the jobs and templates apply to both
2526 # branches.
2527 with open(os.path.join(FIXTURE_DIR,
2528 'config/pragma-multibranch/git/',
2529 'org_project1/zuul.yaml')) as f:
2530 config = f.read()
2531 extra_conf = textwrap.dedent(
2532 """
2533 - pragma:
2534 implied-branches:
2535 - stable/pike
2536 - stable/jewel
2537 """)
2538 config = extra_conf + config
2539 file_dict = {'zuul.yaml': config}
2540 A = self.fake_gerrit.addFakeChange('org/project1', 'stable/pike', 'A',
2541 files=file_dict)
2542 A.addApproval('Code-Review', 2)
2543 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2544 self.waitUntilSettled()
2545 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2546 self.waitUntilSettled()
2547 # Now verify that when we propose a change to jewel, we get
2548 # the pike/jewel jobs.
2549 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2550 self.waitUntilSettled()
2551 self.assertHistory([
2552 dict(name='test-job1', result='SUCCESS', changes='1,1'),
2553 dict(name='test-job2', result='SUCCESS', changes='1,1'),
2554 ], ordered=False)
2555
2556
James E. Blair2bab6e72017-08-07 09:52:45 -07002557class TestBaseJobs(ZuulTestCase):
2558 tenant_config_file = 'config/base-jobs/main.yaml'
2559
2560 def test_multiple_base_jobs(self):
2561 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2562 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2563 self.waitUntilSettled()
2564 self.assertHistory([
2565 dict(name='my-job', result='SUCCESS', changes='1,1'),
2566 dict(name='other-job', result='SUCCESS', changes='1,1'),
2567 ], ordered=False)
2568 self.assertEqual(self.getJobFromHistory('my-job').
2569 parameters['zuul']['jobtags'],
2570 ['mybase'])
2571 self.assertEqual(self.getJobFromHistory('other-job').
2572 parameters['zuul']['jobtags'],
2573 ['otherbase'])
2574
2575 def test_untrusted_base_job(self):
2576 """Test that a base job may not be defined in an untrusted repo"""
2577 in_repo_conf = textwrap.dedent(
2578 """
2579 - job:
2580 name: fail-base
2581 parent: null
2582 """)
2583
2584 file_dict = {'.zuul.yaml': in_repo_conf}
2585 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2586 files=file_dict)
2587 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2588 self.waitUntilSettled()
2589 self.assertEqual(A.reported, 1,
2590 "A should report failure")
2591 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
2592 self.assertIn('Base jobs must be defined in config projects',
2593 A.messages[0])
2594 self.assertHistory([])
James E. Blairdb089032017-08-15 13:42:12 -07002595
2596
James E. Blaira17a8e72018-01-17 13:45:25 -08002597class TestSecrets(ZuulTestCase):
2598 tenant_config_file = 'config/secrets/main.yaml'
2599 secret = {'password': 'test-password',
2600 'username': 'test-username'}
2601
2602 def _getSecrets(self, job, pbtype):
2603 secrets = []
2604 build = self.getJobFromHistory(job)
2605 for pb in build.parameters[pbtype]:
2606 secrets.append(pb['secrets'])
2607 return secrets
2608
2609 def test_secret_branch(self):
2610 # Test that we can use a secret defined in another branch of
2611 # the same project.
2612 self.create_branch('org/project2', 'stable')
2613 self.fake_gerrit.addEvent(
2614 self.fake_gerrit.getFakeBranchCreatedEvent(
2615 'org/project2', 'stable'))
2616 self.waitUntilSettled()
2617
2618 with open(os.path.join(FIXTURE_DIR,
2619 'config/secrets/git/',
2620 'org_project2/zuul-secret.yaml')) as f:
2621 config = f.read()
2622
2623 file_dict = {'zuul.yaml': config}
2624 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2625 files=file_dict)
2626 A.addApproval('Code-Review', 2)
2627 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2628 self.waitUntilSettled()
2629 self.assertEqual(A.data['status'], 'MERGED')
2630 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2631 self.waitUntilSettled()
2632
2633 in_repo_conf = textwrap.dedent(
2634 """
2635 - job:
2636 parent: base
2637 name: project2-secret
2638 run: playbooks/secret.yaml
2639 secrets: [project2_secret]
2640
2641 - project:
2642 check:
2643 jobs:
2644 - project2-secret
2645 gate:
2646 jobs:
2647 - noop
2648 """)
2649 file_dict = {'zuul.yaml': in_repo_conf}
2650 B = self.fake_gerrit.addFakeChange('org/project2', 'stable', 'B',
2651 files=file_dict)
2652 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2653 self.waitUntilSettled()
2654 self.assertEqual(B.reported, 1, "B should report success")
2655 self.assertHistory([
2656 dict(name='project2-secret', result='SUCCESS', changes='2,1'),
2657 ])
2658 self.assertEqual(
2659 self._getSecrets('project2-secret', 'playbooks'),
2660 [{'project2_secret': self.secret}])
2661
2662 def test_secret_branch_duplicate(self):
2663 # Test that we can create a duplicate secret on a different
2664 # branch of the same project -- i.e., that when we branch
2665 # master to stable on a project with a secret, nothing
2666 # changes.
2667 self.create_branch('org/project1', 'stable')
2668 self.fake_gerrit.addEvent(
2669 self.fake_gerrit.getFakeBranchCreatedEvent(
2670 'org/project1', 'stable'))
2671 self.waitUntilSettled()
2672
2673 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A')
2674 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2675 self.waitUntilSettled()
2676 self.assertEqual(A.reported, 1,
2677 "A should report success")
2678 self.assertHistory([
2679 dict(name='project1-secret', result='SUCCESS', changes='1,1'),
2680 ])
2681 self.assertEqual(
2682 self._getSecrets('project1-secret', 'playbooks'),
2683 [{'project1_secret': self.secret}])
2684
2685 def test_secret_branch_error_same_branch(self):
2686 # Test that we are unable to define a secret twice on the same
2687 # project-branch.
2688 in_repo_conf = textwrap.dedent(
2689 """
2690 - secret:
2691 name: project1_secret
2692 data: {}
2693 - secret:
2694 name: project1_secret
2695 data: {}
2696 """)
2697 file_dict = {'zuul.yaml': in_repo_conf}
2698 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2699 files=file_dict)
2700 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2701 self.waitUntilSettled()
2702 self.assertIn('already defined', A.messages[0])
2703
2704 def test_secret_branch_error_same_project(self):
2705 # Test that we are unable to create a secret which differs
2706 # from another with the same name -- i.e., that if we have a
2707 # duplicate secret on multiple branches of the same project,
2708 # they must be identical.
2709 self.create_branch('org/project1', 'stable')
2710 self.fake_gerrit.addEvent(
2711 self.fake_gerrit.getFakeBranchCreatedEvent(
2712 'org/project1', 'stable'))
2713 self.waitUntilSettled()
2714
2715 in_repo_conf = textwrap.dedent(
2716 """
2717 - secret:
2718 name: project1_secret
2719 data: {}
2720 """)
2721 file_dict = {'zuul.yaml': in_repo_conf}
2722 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A',
2723 files=file_dict)
2724 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2725 self.waitUntilSettled()
2726 self.assertIn('does not match existing definition in branch master',
2727 A.messages[0])
2728
2729 def test_secret_branch_error_other_project(self):
2730 # Test that we are unable to create a secret with the same
2731 # name as another. We're never allowed to have a secret with
2732 # the same name outside of a project.
2733 in_repo_conf = textwrap.dedent(
2734 """
2735 - secret:
2736 name: project1_secret
2737 data: {}
2738 """)
2739 file_dict = {'zuul.yaml': in_repo_conf}
2740 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2741 files=file_dict)
2742 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2743 self.waitUntilSettled()
2744 self.assertIn('already defined in project org/project1',
2745 A.messages[0])
2746
2747
James E. Blairdf91ab32017-10-25 17:57:13 -07002748class TestSecretInheritance(ZuulTestCase):
2749 tenant_config_file = 'config/secret-inheritance/main.yaml'
2750
2751 def _getSecrets(self, job, pbtype):
2752 secrets = []
2753 build = self.getJobFromHistory(job)
2754 for pb in build.parameters[pbtype]:
2755 secrets.append(pb['secrets'])
2756 return secrets
2757
2758 def _checkTrustedSecrets(self):
2759 secret = {'longpassword': 'test-passwordtest-password',
2760 'password': 'test-password',
2761 'username': 'test-username'}
2762 self.assertEqual(
2763 self._getSecrets('trusted-secrets', 'playbooks'),
James E. Blair2f589fe2017-10-26 12:57:41 -07002764 [{'trusted-secret': secret}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002765 self.assertEqual(
2766 self._getSecrets('trusted-secrets', 'pre_playbooks'), [])
2767 self.assertEqual(
2768 self._getSecrets('trusted-secrets', 'post_playbooks'), [])
2769
2770 self.assertEqual(
2771 self._getSecrets('trusted-secrets-trusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002772 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002773 self.assertEqual(
2774 self._getSecrets('trusted-secrets-trusted-child',
2775 'pre_playbooks'), [])
2776 self.assertEqual(
2777 self._getSecrets('trusted-secrets-trusted-child',
2778 'post_playbooks'), [])
2779
2780 self.assertEqual(
2781 self._getSecrets('trusted-secrets-untrusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002782 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002783 self.assertEqual(
2784 self._getSecrets('trusted-secrets-untrusted-child',
2785 'pre_playbooks'), [])
2786 self.assertEqual(
2787 self._getSecrets('trusted-secrets-untrusted-child',
2788 'post_playbooks'), [])
2789
2790 def _checkUntrustedSecrets(self):
2791 secret = {'longpassword': 'test-passwordtest-password',
2792 'password': 'test-password',
2793 'username': 'test-username'}
2794 self.assertEqual(
2795 self._getSecrets('untrusted-secrets', 'playbooks'),
James E. Blair2f589fe2017-10-26 12:57:41 -07002796 [{'untrusted-secret': secret}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002797 self.assertEqual(
2798 self._getSecrets('untrusted-secrets', 'pre_playbooks'), [])
2799 self.assertEqual(
2800 self._getSecrets('untrusted-secrets', 'post_playbooks'), [])
2801
2802 self.assertEqual(
2803 self._getSecrets('untrusted-secrets-trusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002804 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002805 self.assertEqual(
2806 self._getSecrets('untrusted-secrets-trusted-child',
2807 'pre_playbooks'), [])
2808 self.assertEqual(
2809 self._getSecrets('untrusted-secrets-trusted-child',
2810 'post_playbooks'), [])
2811
2812 self.assertEqual(
2813 self._getSecrets('untrusted-secrets-untrusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002814 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002815 self.assertEqual(
2816 self._getSecrets('untrusted-secrets-untrusted-child',
2817 'pre_playbooks'), [])
2818 self.assertEqual(
2819 self._getSecrets('untrusted-secrets-untrusted-child',
2820 'post_playbooks'), [])
2821
2822 def test_trusted_secret_inheritance_check(self):
2823 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
2824 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2825 self.waitUntilSettled()
2826 self.assertHistory([
2827 dict(name='trusted-secrets', result='SUCCESS', changes='1,1'),
2828 dict(name='trusted-secrets-trusted-child',
2829 result='SUCCESS', changes='1,1'),
2830 dict(name='trusted-secrets-untrusted-child',
2831 result='SUCCESS', changes='1,1'),
2832 ], ordered=False)
2833
2834 self._checkTrustedSecrets()
2835
2836 def test_untrusted_secret_inheritance_gate(self):
2837 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
2838 A.addApproval('Code-Review', 2)
2839 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2840 self.waitUntilSettled()
2841 self.assertHistory([
2842 dict(name='untrusted-secrets', result='SUCCESS', changes='1,1'),
2843 dict(name='untrusted-secrets-trusted-child',
2844 result='SUCCESS', changes='1,1'),
2845 dict(name='untrusted-secrets-untrusted-child',
2846 result='SUCCESS', changes='1,1'),
2847 ], ordered=False)
2848
2849 self._checkUntrustedSecrets()
2850
2851 def test_untrusted_secret_inheritance_check(self):
2852 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2853 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2854 self.waitUntilSettled()
2855 # This configuration tries to run untrusted secrets in an
2856 # non-post-review pipeline and should therefore run no jobs.
2857 self.assertHistory([])
2858
2859
James E. Blairdb089032017-08-15 13:42:12 -07002860class TestSecretLeaks(AnsibleZuulTestCase):
2861 tenant_config_file = 'config/secret-leaks/main.yaml'
2862
2863 def searchForContent(self, path, content):
2864 matches = []
2865 for (dirpath, dirnames, filenames) in os.walk(path):
2866 for filename in filenames:
2867 filepath = os.path.join(dirpath, filename)
2868 with open(filepath, 'rb') as f:
2869 if content in f.read():
2870 matches.append(filepath[len(path):])
2871 return matches
2872
2873 def _test_secret_file(self):
2874 # Or rather -- test that they *don't* leak.
2875 # Keep the jobdir around so we can inspect contents.
2876 self.executor_server.keep_jobdir = True
2877 conf = textwrap.dedent(
2878 """
2879 - project:
2880 name: org/project
2881 check:
2882 jobs:
2883 - secret-file
2884 """)
2885
2886 file_dict = {'.zuul.yaml': conf}
2887 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2888 files=file_dict)
2889 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2890 self.waitUntilSettled()
2891 self.assertHistory([
2892 dict(name='secret-file', result='SUCCESS', changes='1,1'),
2893 ], ordered=False)
2894 matches = self.searchForContent(self.history[0].jobdir.root,
2895 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07002896 self.assertEqual(set(['/work/secret-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07002897 set(matches))
2898
2899 def test_secret_file(self):
2900 self._test_secret_file()
2901
2902 def test_secret_file_verbose(self):
2903 # Output extra ansible info to exercise alternate logging code
2904 # paths.
2905 self.executor_server.verbose = True
2906 self._test_secret_file()
2907
2908 def _test_secret_file_fail(self):
2909 # Or rather -- test that they *don't* leak.
2910 # Keep the jobdir around so we can inspect contents.
2911 self.executor_server.keep_jobdir = True
2912 conf = textwrap.dedent(
2913 """
2914 - project:
2915 name: org/project
2916 check:
2917 jobs:
2918 - secret-file-fail
2919 """)
2920
2921 file_dict = {'.zuul.yaml': conf}
2922 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2923 files=file_dict)
2924 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2925 self.waitUntilSettled()
2926 self.assertHistory([
2927 dict(name='secret-file-fail', result='FAILURE', changes='1,1'),
2928 ], ordered=False)
2929 matches = self.searchForContent(self.history[0].jobdir.root,
2930 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07002931 self.assertEqual(set(['/work/failure-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07002932 set(matches))
2933
2934 def test_secret_file_fail(self):
2935 self._test_secret_file_fail()
2936
2937 def test_secret_file_fail_verbose(self):
2938 # Output extra ansible info to exercise alternate logging code
2939 # paths.
2940 self.executor_server.verbose = True
2941 self._test_secret_file_fail()
James E. Blaira00910c2017-08-23 09:15:04 -07002942
2943
James E. Blair8446c412018-01-17 15:49:59 -08002944class TestNodesets(ZuulTestCase):
2945 tenant_config_file = 'config/nodesets/main.yaml'
2946
2947 def test_nodeset_branch(self):
2948 # Test that we can use a nodeset defined in another branch of
2949 # the same project.
2950 self.create_branch('org/project2', 'stable')
2951 self.fake_gerrit.addEvent(
2952 self.fake_gerrit.getFakeBranchCreatedEvent(
2953 'org/project2', 'stable'))
2954 self.waitUntilSettled()
2955
2956 with open(os.path.join(FIXTURE_DIR,
2957 'config/nodesets/git/',
2958 'org_project2/zuul-nodeset.yaml')) as f:
2959 config = f.read()
2960
2961 file_dict = {'zuul.yaml': config}
2962 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2963 files=file_dict)
2964 A.addApproval('Code-Review', 2)
2965 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2966 self.waitUntilSettled()
2967 self.assertEqual(A.data['status'], 'MERGED')
2968 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2969 self.waitUntilSettled()
2970
2971 in_repo_conf = textwrap.dedent(
2972 """
2973 - job:
2974 parent: base
2975 name: project2-test
2976 nodeset: project2-nodeset
2977
2978 - project:
2979 check:
2980 jobs:
2981 - project2-test
2982 gate:
2983 jobs:
2984 - noop
2985 """)
2986 file_dict = {'zuul.yaml': in_repo_conf}
2987 B = self.fake_gerrit.addFakeChange('org/project2', 'stable', 'B',
2988 files=file_dict)
2989 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2990 self.waitUntilSettled()
2991 self.assertEqual(B.reported, 1, "B should report success")
2992 self.assertHistory([
2993 dict(name='project2-test', result='SUCCESS', changes='2,1',
2994 node='ubuntu-xenial'),
2995 ])
2996
2997 def test_nodeset_branch_duplicate(self):
Monty Taylorbc1d0bb2018-01-22 17:05:31 -06002998 # Test that we can create a duplicate nodeset on a different
James E. Blair8446c412018-01-17 15:49:59 -08002999 # branch of the same project -- i.e., that when we branch
Monty Taylorbc1d0bb2018-01-22 17:05:31 -06003000 # master to stable on a project with a nodeset, nothing
James E. Blair8446c412018-01-17 15:49:59 -08003001 # changes.
3002 self.create_branch('org/project1', 'stable')
3003 self.fake_gerrit.addEvent(
3004 self.fake_gerrit.getFakeBranchCreatedEvent(
3005 'org/project1', 'stable'))
3006 self.waitUntilSettled()
3007
3008 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A')
3009 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3010 self.waitUntilSettled()
3011 self.assertEqual(A.reported, 1,
3012 "A should report success")
3013 self.assertHistory([
3014 dict(name='project1-test', result='SUCCESS', changes='1,1',
3015 node='ubuntu-xenial'),
3016 ])
3017
3018 def test_nodeset_branch_error_same_branch(self):
3019 # Test that we are unable to define a nodeset twice on the same
3020 # project-branch.
3021 in_repo_conf = textwrap.dedent(
3022 """
3023 - nodeset:
3024 name: project1-nodeset
3025 nodes: []
3026 - nodeset:
3027 name: project1-nodeset
3028 nodes: []
3029 """)
3030 file_dict = {'zuul.yaml': in_repo_conf}
3031 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
3032 files=file_dict)
3033 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3034 self.waitUntilSettled()
3035 self.assertIn('already defined', A.messages[0])
3036
3037 def test_nodeset_branch_error_same_project(self):
3038 # Test that we are unable to create a nodeset which differs
3039 # from another with the same name -- i.e., that if we have a
3040 # duplicate nodeset on multiple branches of the same project,
3041 # they must be identical.
3042 self.create_branch('org/project1', 'stable')
3043 self.fake_gerrit.addEvent(
3044 self.fake_gerrit.getFakeBranchCreatedEvent(
3045 'org/project1', 'stable'))
3046 self.waitUntilSettled()
3047
3048 in_repo_conf = textwrap.dedent(
3049 """
3050 - nodeset:
3051 name: project1-nodeset
3052 nodes: []
3053 """)
3054 file_dict = {'zuul.yaml': in_repo_conf}
3055 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A',
3056 files=file_dict)
3057 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3058 self.waitUntilSettled()
3059 self.assertIn('does not match existing definition in branch master',
3060 A.messages[0])
3061
3062 def test_nodeset_branch_error_other_project(self):
3063 # Test that we are unable to create a nodeset with the same
3064 # name as another. We're never allowed to have a nodeset with
3065 # the same name outside of a project.
3066 in_repo_conf = textwrap.dedent(
3067 """
3068 - nodeset:
3069 name: project1-nodeset
3070 nodes: []
3071 """)
3072 file_dict = {'zuul.yaml': in_repo_conf}
3073 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
3074 files=file_dict)
3075 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3076 self.waitUntilSettled()
3077 self.assertIn('already defined in project org/project1',
3078 A.messages[0])
3079
3080
James E. Blair9596b942018-01-18 14:21:44 -08003081class TestSemaphoreBranches(ZuulTestCase):
3082 tenant_config_file = 'config/semaphore-branches/main.yaml'
3083
3084 def test_semaphore_branch(self):
3085 # Test that we can use a semaphore defined in another branch of
3086 # the same project.
3087 self.create_branch('org/project2', 'stable')
3088 self.fake_gerrit.addEvent(
3089 self.fake_gerrit.getFakeBranchCreatedEvent(
3090 'org/project2', 'stable'))
3091 self.waitUntilSettled()
3092
3093 with open(os.path.join(FIXTURE_DIR,
3094 'config/semaphore-branches/git/',
3095 'org_project2/zuul-semaphore.yaml')) as f:
3096 config = f.read()
3097
3098 file_dict = {'zuul.yaml': config}
3099 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
3100 files=file_dict)
3101 A.addApproval('Code-Review', 2)
3102 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
3103 self.waitUntilSettled()
3104 self.assertEqual(A.data['status'], 'MERGED')
3105 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
3106 self.waitUntilSettled()
3107
3108 in_repo_conf = textwrap.dedent(
3109 """
3110 - job:
3111 parent: base
3112 name: project2-test
3113 semaphore: project2-semaphore
3114
3115 - project:
3116 check:
3117 jobs:
3118 - project2-test
3119 gate:
3120 jobs:
3121 - noop
3122 """)
3123 file_dict = {'zuul.yaml': in_repo_conf}
3124 B = self.fake_gerrit.addFakeChange('org/project2', 'stable', 'B',
3125 files=file_dict)
3126 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
3127 self.waitUntilSettled()
3128 self.assertEqual(B.reported, 1, "B should report success")
3129 self.assertHistory([
3130 dict(name='project2-test', result='SUCCESS', changes='2,1')
3131 ])
3132
3133 def test_semaphore_branch_duplicate(self):
3134 # Test that we can create a duplicate semaphore on a different
3135 # branch of the same project -- i.e., that when we branch
3136 # master to stable on a project with a semaphore, nothing
3137 # changes.
3138 self.create_branch('org/project1', 'stable')
3139 self.fake_gerrit.addEvent(
3140 self.fake_gerrit.getFakeBranchCreatedEvent(
3141 'org/project1', 'stable'))
3142 self.waitUntilSettled()
3143
3144 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A')
3145 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3146 self.waitUntilSettled()
3147 self.assertEqual(A.reported, 1,
3148 "A should report success")
3149 self.assertHistory([
3150 dict(name='project1-test', result='SUCCESS', changes='1,1')
3151 ])
3152
3153 def test_semaphore_branch_error_same_branch(self):
3154 # Test that we are unable to define a semaphore twice on the same
3155 # project-branch.
3156 in_repo_conf = textwrap.dedent(
3157 """
3158 - semaphore:
3159 name: project1-semaphore
3160 max: 2
3161 - semaphore:
3162 name: project1-semaphore
3163 max: 2
3164 """)
3165 file_dict = {'zuul.yaml': in_repo_conf}
3166 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
3167 files=file_dict)
3168 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3169 self.waitUntilSettled()
3170 self.assertIn('already defined', A.messages[0])
3171
3172 def test_semaphore_branch_error_same_project(self):
3173 # Test that we are unable to create a semaphore which differs
3174 # from another with the same name -- i.e., that if we have a
3175 # duplicate semaphore on multiple branches of the same project,
3176 # they must be identical.
3177 self.create_branch('org/project1', 'stable')
3178 self.fake_gerrit.addEvent(
3179 self.fake_gerrit.getFakeBranchCreatedEvent(
3180 'org/project1', 'stable'))
3181 self.waitUntilSettled()
3182
3183 in_repo_conf = textwrap.dedent(
3184 """
3185 - semaphore:
3186 name: project1-semaphore
3187 max: 4
3188 """)
3189 file_dict = {'zuul.yaml': in_repo_conf}
3190 A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A',
3191 files=file_dict)
3192 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3193 self.waitUntilSettled()
3194 self.assertIn('does not match existing definition in branch master',
3195 A.messages[0])
3196
3197 def test_semaphore_branch_error_other_project(self):
3198 # Test that we are unable to create a semaphore with the same
3199 # name as another. We're never allowed to have a semaphore with
3200 # the same name outside of a project.
3201 in_repo_conf = textwrap.dedent(
3202 """
3203 - semaphore:
3204 name: project1-semaphore
3205 max: 2
3206 """)
3207 file_dict = {'zuul.yaml': in_repo_conf}
3208 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
3209 files=file_dict)
3210 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3211 self.waitUntilSettled()
3212 self.assertIn('already defined in project org/project1',
3213 A.messages[0])
3214
3215
James E. Blaira00910c2017-08-23 09:15:04 -07003216class TestJobOutput(AnsibleZuulTestCase):
3217 tenant_config_file = 'config/job-output/main.yaml'
3218
3219 def _get_file(self, build, path):
3220 p = os.path.join(build.jobdir.root, path)
3221 with open(p) as f:
3222 return f.read()
3223
3224 def test_job_output(self):
Monty Taylor0e2489a2017-10-10 11:57:29 -05003225 # Verify that command standard output appears in the job output,
3226 # and that failures in the final playbook get logged.
James E. Blaira00910c2017-08-23 09:15:04 -07003227
3228 # This currently only verifies we receive output from
3229 # localhost. Notably, it does not verify we receive output
3230 # via zuul_console streaming.
3231 self.executor_server.keep_jobdir = True
3232 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3233 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3234 self.waitUntilSettled()
3235 self.assertHistory([
3236 dict(name='job-output', result='SUCCESS', changes='1,1'),
3237 ], ordered=False)
3238
3239 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
3240 j = json.loads(self._get_file(self.history[0],
3241 'work/logs/job-output.json'))
3242 self.assertEqual(token,
3243 j[0]['plays'][0]['tasks'][0]
3244 ['hosts']['localhost']['stdout'])
3245
3246 print(self._get_file(self.history[0],
3247 'work/logs/job-output.txt'))
3248 self.assertIn(token,
3249 self._get_file(self.history[0],
3250 'work/logs/job-output.txt'))
Monty Taylor0e2489a2017-10-10 11:57:29 -05003251
3252 def test_job_output_failure_log(self):
3253 logger = logging.getLogger('zuul.AnsibleJob')
3254 output = io.StringIO()
3255 logger.addHandler(logging.StreamHandler(output))
3256
3257 # Verify that a failure in the last post playbook emits the contents
3258 # of the json output to the log
3259 self.executor_server.keep_jobdir = True
3260 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
3261 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3262 self.waitUntilSettled()
3263 self.assertHistory([
3264 dict(name='job-output-failure',
3265 result='POST_FAILURE', changes='1,1'),
3266 ], ordered=False)
3267
3268 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
3269 j = json.loads(self._get_file(self.history[0],
3270 'work/logs/job-output.json'))
3271 self.assertEqual(token,
3272 j[0]['plays'][0]['tasks'][0]
3273 ['hosts']['localhost']['stdout'])
3274
3275 print(self._get_file(self.history[0],
3276 'work/logs/job-output.json'))
3277 self.assertIn(token,
3278 self._get_file(self.history[0],
3279 'work/logs/job-output.txt'))
3280
3281 log_output = output.getvalue()
3282 self.assertIn('Final playbook failed', log_output)
3283 self.assertIn('Failure test', log_output)