blob: c5d19ceb4a954a40a0207d7b6d2ff60bf3d179ca [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. Blair2a664502017-10-27 11:39:33 -0700500class TestCentralJobs(ZuulTestCase):
501 tenant_config_file = 'config/central-jobs/main.yaml'
502
503 def setUp(self):
504 super(TestCentralJobs, self).setUp()
505 self.create_branch('org/project', 'stable')
506 self.fake_gerrit.addEvent(
507 self.fake_gerrit.getFakeBranchCreatedEvent(
508 'org/project', 'stable'))
509 self.waitUntilSettled()
510
511 def _updateConfig(self, config, branch):
512 file_dict = {'.zuul.yaml': config}
513 C = self.fake_gerrit.addFakeChange('org/project', branch, 'C',
514 files=file_dict)
515 C.addApproval('Code-Review', 2)
516 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
517 self.waitUntilSettled()
518 self.fake_gerrit.addEvent(C.getChangeMergedEvent())
519 self.waitUntilSettled()
520
521 def _test_central_job_on_branch(self, branch, other_branch):
522 # Test that a job defined on a branchless repo only runs on
523 # the branch applied
524 config = textwrap.dedent(
525 """
526 - project:
527 name: org/project
528 check:
529 jobs:
530 - central-job
531 """)
532 self._updateConfig(config, branch)
533
534 A = self.fake_gerrit.addFakeChange('org/project', branch, 'A')
535 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
536 self.waitUntilSettled()
537
538 self.assertHistory([
539 dict(name='central-job', result='SUCCESS', changes='2,1')])
540
541 # No jobs should run for this change.
542 B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B')
543 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
544 self.waitUntilSettled()
545
546 self.assertHistory([
547 dict(name='central-job', result='SUCCESS', changes='2,1')])
548
549 def test_central_job_on_stable(self):
550 self._test_central_job_on_branch('master', 'stable')
551
552 def test_central_job_on_master(self):
553 self._test_central_job_on_branch('stable', 'master')
554
555 def _test_central_template_on_branch(self, branch, other_branch):
556 # Test that a project-template defined on a branchless repo
557 # only runs on the branch applied
558 config = textwrap.dedent(
559 """
560 - project:
561 name: org/project
562 templates: ['central-jobs']
563 """)
564 self._updateConfig(config, branch)
565
566 A = self.fake_gerrit.addFakeChange('org/project', branch, 'A')
567 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
568 self.waitUntilSettled()
569
570 self.assertHistory([
571 dict(name='central-job', result='SUCCESS', changes='2,1')])
572
573 # No jobs should run for this change.
574 B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B')
575 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
576 self.waitUntilSettled()
577
578 self.assertHistory([
579 dict(name='central-job', result='SUCCESS', changes='2,1')])
580
581 def test_central_template_on_stable(self):
582 self._test_central_template_on_branch('master', 'stable')
583
584 def test_central_template_on_master(self):
585 self._test_central_template_on_branch('stable', 'master')
586
587
James E. Blairff555742017-02-19 11:34:27 -0800588class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -0800589 # A temporary class to hold new tests while others are disabled
590
Tobias Henkelabf973e2017-07-28 10:07:34 +0200591 config_file = 'zuul-connections-gerrit-and-github.conf'
James E. Blair2a629ec2015-12-22 15:32:02 -0800592 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -0800593
James E. Blair83005782015-12-11 14:46:03 -0800594 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -0800595 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200596 A.addApproval('Code-Review', 2)
597 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -0800598 self.waitUntilSettled()
599 self.assertEqual(self.getJobFromHistory('project-test1').result,
600 'SUCCESS')
601 self.assertEqual(A.data['status'], 'MERGED')
602 self.assertEqual(A.reported, 2,
603 "A should report start and success")
604 self.assertIn('tenant-one-gate', A.messages[1],
605 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -0800606
James E. Blair3a098dd2017-10-04 14:37:29 -0700607 @skip("This test is useful, but not reliable")
608 def test_full_and_dynamic_reconfig(self):
609 self.executor_server.hold_jobs_in_build = True
610 in_repo_conf = textwrap.dedent(
611 """
612 - job:
613 name: project-test1
614
615 - project:
616 name: org/project
617 tenant-one-gate:
618 jobs:
619 - project-test1
620 """)
621
622 file_dict = {'.zuul.yaml': in_repo_conf}
623 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
624 files=file_dict)
625 A.addApproval('Code-Review', 2)
626 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
627 self.waitUntilSettled()
628 self.sched.reconfigure(self.config)
629 self.waitUntilSettled()
630
631 gc.collect()
632 pipelines = [obj for obj in gc.get_objects()
633 if isinstance(obj, zuul.model.Pipeline)]
634 self.assertEqual(len(pipelines), 4)
635
636 self.executor_server.hold_jobs_in_build = False
637 self.executor_server.release()
638 self.waitUntilSettled()
639
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700640 def test_dynamic_config(self):
641 in_repo_conf = textwrap.dedent(
642 """
643 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200644 name: project-test1
645
646 - job:
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700647 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700648 run: playbooks/project-test2.yaml
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700649
650 - project:
651 name: org/project
652 tenant-one-gate:
653 jobs:
654 - project-test2
655 """)
656
James E. Blairc73c73a2017-01-20 15:15:15 -0800657 in_repo_playbook = textwrap.dedent(
658 """
659 - hosts: all
660 tasks: []
661 """)
662
663 file_dict = {'.zuul.yaml': in_repo_conf,
664 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700665 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800666 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200667 A.addApproval('Code-Review', 2)
668 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700669 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700670 self.assertEqual(A.data['status'], 'MERGED')
671 self.assertEqual(A.reported, 2,
672 "A should report start and success")
673 self.assertIn('tenant-one-gate', A.messages[1],
674 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800675 self.assertHistory([
676 dict(name='project-test2', result='SUCCESS', changes='1,1')])
677
James E. Blairc2a5ed72017-02-20 14:12:01 -0500678 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800679 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500680
James E. Blair646322f2017-01-27 15:50:34 -0800681 # Now that the config change is landed, it should be live for
682 # subsequent changes.
683 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200684 B.addApproval('Code-Review', 2)
685 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair646322f2017-01-27 15:50:34 -0800686 self.waitUntilSettled()
687 self.assertEqual(self.getJobFromHistory('project-test2').result,
688 'SUCCESS')
689 self.assertHistory([
690 dict(name='project-test2', result='SUCCESS', changes='1,1'),
691 dict(name='project-test2', result='SUCCESS', changes='2,1')])
James E. Blairc73c73a2017-01-20 15:15:15 -0800692
James E. Blair6bc10482017-10-20 11:28:53 -0700693 def test_dynamic_template(self):
James E. Blair2a664502017-10-27 11:39:33 -0700694 # Tests that a project can't update a template in another
695 # project.
James E. Blair6bc10482017-10-20 11:28:53 -0700696 in_repo_conf = textwrap.dedent(
697 """
698 - job:
699 name: project-test1
700
701 - project-template:
702 name: common-config-template
703 check:
704 jobs:
705 - project-test1
706
707 - project:
708 name: org/project
709 templates: [common-config-template]
710 """)
711
712 file_dict = {'.zuul.yaml': in_repo_conf}
713 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
714 files=file_dict)
715 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
716 self.waitUntilSettled()
James E. Blair2a664502017-10-27 11:39:33 -0700717
718 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
719 self.assertIn('Project template common-config-template '
720 'is already defined',
721 A.messages[0],
722 "A should have failed the check pipeline")
James E. Blair6bc10482017-10-20 11:28:53 -0700723
Tobias Henkelf02cf512017-07-21 22:55:34 +0200724 def test_dynamic_config_non_existing_job(self):
725 """Test that requesting a non existent job fails"""
726 in_repo_conf = textwrap.dedent(
727 """
728 - job:
729 name: project-test1
730
731 - project:
732 name: org/project
733 check:
734 jobs:
735 - non-existent-job
736 """)
737
738 in_repo_playbook = textwrap.dedent(
739 """
740 - hosts: all
741 tasks: []
742 """)
743
744 file_dict = {'.zuul.yaml': in_repo_conf,
745 'playbooks/project-test2.yaml': in_repo_playbook}
746 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
747 files=file_dict)
748 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
749 self.waitUntilSettled()
750 self.assertEqual(A.reported, 1,
751 "A should report failure")
752 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
753 self.assertIn('Job non-existent-job not defined', A.messages[0],
754 "A should have failed the check pipeline")
755 self.assertHistory([])
756
757 def test_dynamic_config_non_existing_job_in_template(self):
758 """Test that requesting a non existent job fails"""
759 in_repo_conf = textwrap.dedent(
760 """
761 - job:
762 name: project-test1
763
764 - project-template:
765 name: test-template
766 check:
767 jobs:
768 - non-existent-job
769
770 - project:
771 name: org/project
772 templates:
773 - test-template
774 """)
775
776 in_repo_playbook = textwrap.dedent(
777 """
778 - hosts: all
779 tasks: []
780 """)
781
782 file_dict = {'.zuul.yaml': in_repo_conf,
783 'playbooks/project-test2.yaml': in_repo_playbook}
784 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
785 files=file_dict)
786 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
787 self.waitUntilSettled()
788 self.assertEqual(A.reported, 1,
789 "A should report failure")
790 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
791 self.assertIn('Job non-existent-job not defined', A.messages[0],
792 "A should have failed the check pipeline")
793 self.assertHistory([])
794
Tobias Henkel0f714002017-06-30 23:30:52 +0200795 def test_dynamic_config_new_patchset(self):
796 self.executor_server.hold_jobs_in_build = True
797
798 tenant = self.sched.abide.tenants.get('tenant-one')
799 check_pipeline = tenant.layout.pipelines['check']
800
801 in_repo_conf = textwrap.dedent(
802 """
803 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200804 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -0700805 run: playbooks/project-test1.yaml
Tobias Henkelf02cf512017-07-21 22:55:34 +0200806
807 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200808 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700809 run: playbooks/project-test2.yaml
Tobias Henkel0f714002017-06-30 23:30:52 +0200810
811 - project:
812 name: org/project
813 check:
814 jobs:
815 - project-test2
816 """)
817
818 in_repo_playbook = textwrap.dedent(
819 """
820 - hosts: all
821 tasks: []
822 """)
823
824 file_dict = {'.zuul.yaml': in_repo_conf,
825 'playbooks/project-test2.yaml': in_repo_playbook}
826 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
827 files=file_dict)
828 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
829 self.waitUntilSettled()
830
831 items = check_pipeline.getAllItems()
832 self.assertEqual(items[0].change.number, '1')
833 self.assertEqual(items[0].change.patchset, '1')
834 self.assertTrue(items[0].live)
835
836 in_repo_conf = textwrap.dedent(
837 """
838 - job:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200839 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -0700840 run: playbooks/project-test1.yaml
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200841
842 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200843 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700844 run: playbooks/project-test2.yaml
Tobias Henkel0f714002017-06-30 23:30:52 +0200845
846 - project:
847 name: org/project
848 check:
849 jobs:
850 - project-test1
851 - project-test2
852 """)
853 file_dict = {'.zuul.yaml': in_repo_conf,
854 'playbooks/project-test2.yaml': in_repo_playbook}
855
856 A.addPatchset(files=file_dict)
857 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
858
859 self.waitUntilSettled()
860
861 items = check_pipeline.getAllItems()
862 self.assertEqual(items[0].change.number, '1')
863 self.assertEqual(items[0].change.patchset, '2')
864 self.assertTrue(items[0].live)
865
866 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200867 self.executor_server.release('project-test1')
868 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +0200869 self.executor_server.release()
870 self.waitUntilSettled()
871
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200872 self.assertHistory([
873 dict(name='project-test2', result='ABORTED', changes='1,1'),
874 dict(name='project-test1', result='SUCCESS', changes='1,2'),
875 dict(name='project-test2', result='SUCCESS', changes='1,2')])
876
James E. Blairff555742017-02-19 11:34:27 -0800877 def test_in_repo_branch(self):
878 in_repo_conf = textwrap.dedent(
879 """
880 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200881 name: project-test1
882
883 - job:
James E. Blairff555742017-02-19 11:34:27 -0800884 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700885 run: playbooks/project-test2.yaml
James E. Blairff555742017-02-19 11:34:27 -0800886
887 - project:
888 name: org/project
889 tenant-one-gate:
890 jobs:
891 - project-test2
892 """)
893
894 in_repo_playbook = textwrap.dedent(
895 """
896 - hosts: all
897 tasks: []
898 """)
899
900 file_dict = {'.zuul.yaml': in_repo_conf,
901 'playbooks/project-test2.yaml': in_repo_playbook}
902 self.create_branch('org/project', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700903 self.fake_gerrit.addEvent(
904 self.fake_gerrit.getFakeBranchCreatedEvent(
905 'org/project', 'stable'))
James E. Blair6069f2b2017-09-26 16:34:11 -0700906 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800907 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
908 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200909 A.addApproval('Code-Review', 2)
910 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800911 self.waitUntilSettled()
912 self.assertEqual(A.data['status'], 'MERGED')
913 self.assertEqual(A.reported, 2,
914 "A should report start and success")
915 self.assertIn('tenant-one-gate', A.messages[1],
916 "A should transit tenant-one gate")
917 self.assertHistory([
918 dict(name='project-test2', result='SUCCESS', changes='1,1')])
919 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800920 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800921
922 # The config change should not affect master.
923 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200924 B.addApproval('Code-Review', 2)
925 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800926 self.waitUntilSettled()
927 self.assertHistory([
928 dict(name='project-test2', result='SUCCESS', changes='1,1'),
929 dict(name='project-test1', result='SUCCESS', changes='2,1')])
930
931 # The config change should be live for further changes on
932 # stable.
933 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200934 C.addApproval('Code-Review', 2)
935 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800936 self.waitUntilSettled()
937 self.assertHistory([
938 dict(name='project-test2', result='SUCCESS', changes='1,1'),
939 dict(name='project-test1', result='SUCCESS', changes='2,1'),
940 dict(name='project-test2', result='SUCCESS', changes='3,1')])
941
James E. Blaira5a12492017-05-03 11:40:48 -0700942 def test_crd_dynamic_config_branch(self):
943 # Test that we can create a job in one repo and be able to use
944 # it from a different branch on a different repo.
945
946 self.create_branch('org/project1', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700947 self.fake_gerrit.addEvent(
948 self.fake_gerrit.getFakeBranchCreatedEvent(
949 'org/project1', 'stable'))
James E. Blaira5a12492017-05-03 11:40:48 -0700950
951 in_repo_conf = textwrap.dedent(
952 """
953 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200954 name: project-test1
955
956 - job:
James E. Blaira5a12492017-05-03 11:40:48 -0700957 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700958 run: playbooks/project-test2.yaml
James E. Blaira5a12492017-05-03 11:40:48 -0700959
960 - project:
961 name: org/project
962 check:
963 jobs:
964 - project-test2
965 """)
966
967 in_repo_playbook = textwrap.dedent(
968 """
969 - hosts: all
970 tasks: []
971 """)
972
973 file_dict = {'.zuul.yaml': in_repo_conf,
974 'playbooks/project-test2.yaml': in_repo_playbook}
975 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
976 files=file_dict)
977
978 second_repo_conf = textwrap.dedent(
979 """
980 - project:
981 name: org/project1
982 check:
983 jobs:
984 - project-test2
985 """)
986
987 second_file_dict = {'.zuul.yaml': second_repo_conf}
988 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
989 files=second_file_dict)
990 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
991 B.subject, A.data['id'])
992
993 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
994 self.waitUntilSettled()
995 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
996 self.waitUntilSettled()
997
998 self.assertEqual(A.reported, 1, "A should report")
999 self.assertHistory([
1000 dict(name='project-test2', result='SUCCESS', changes='1,1'),
1001 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
1002 ])
1003
James E. Blair97043882017-09-06 15:51:17 -07001004 def test_yaml_list_error(self):
1005 in_repo_conf = textwrap.dedent(
1006 """
1007 job: foo
1008 """)
1009
1010 file_dict = {'.zuul.yaml': in_repo_conf}
1011 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1012 files=file_dict)
1013 A.addApproval('Code-Review', 2)
1014 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1015 self.waitUntilSettled()
1016
1017 self.assertEqual(A.data['status'], 'NEW')
1018 self.assertEqual(A.reported, 1,
1019 "A should report failure")
1020 self.assertIn('not a list', A.messages[0],
1021 "A should have a syntax error reported")
1022
1023 def test_yaml_dict_error(self):
1024 in_repo_conf = textwrap.dedent(
1025 """
1026 - job
1027 """)
1028
1029 file_dict = {'.zuul.yaml': in_repo_conf}
1030 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1031 files=file_dict)
1032 A.addApproval('Code-Review', 2)
1033 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1034 self.waitUntilSettled()
1035
1036 self.assertEqual(A.data['status'], 'NEW')
1037 self.assertEqual(A.reported, 1,
1038 "A should report failure")
1039 self.assertIn('not a dictionary', A.messages[0],
1040 "A should have a syntax error reported")
1041
1042 def test_yaml_key_error(self):
1043 in_repo_conf = textwrap.dedent(
1044 """
1045 - job:
1046 name: project-test2
1047 """)
1048
1049 file_dict = {'.zuul.yaml': in_repo_conf}
1050 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1051 files=file_dict)
1052 A.addApproval('Code-Review', 2)
1053 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1054 self.waitUntilSettled()
1055
1056 self.assertEqual(A.data['status'], 'NEW')
1057 self.assertEqual(A.reported, 1,
1058 "A should report failure")
1059 self.assertIn('has more than one key', A.messages[0],
1060 "A should have a syntax error reported")
1061
1062 def test_yaml_unknown_error(self):
1063 in_repo_conf = textwrap.dedent(
1064 """
1065 - foobar:
1066 foo: bar
1067 """)
1068
1069 file_dict = {'.zuul.yaml': in_repo_conf}
1070 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1071 files=file_dict)
1072 A.addApproval('Code-Review', 2)
1073 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1074 self.waitUntilSettled()
1075
1076 self.assertEqual(A.data['status'], 'NEW')
1077 self.assertEqual(A.reported, 1,
1078 "A should report failure")
1079 self.assertIn('not recognized', A.messages[0],
1080 "A should have a syntax error reported")
1081
James E. Blair149b69c2017-03-02 10:48:16 -08001082 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -08001083 in_repo_conf = textwrap.dedent(
1084 """
1085 - job:
1086 name: project-test2
1087 foo: error
1088 """)
1089
1090 file_dict = {'.zuul.yaml': in_repo_conf}
1091 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1092 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001093 A.addApproval('Code-Review', 2)
1094 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -08001095 self.waitUntilSettled()
1096
1097 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001098 self.assertEqual(A.reported, 1,
1099 "A should report failure")
1100 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -08001101 "A should have a syntax error reported")
1102
James E. Blair149b69c2017-03-02 10:48:16 -08001103 def test_trusted_syntax_error(self):
1104 in_repo_conf = textwrap.dedent(
1105 """
1106 - job:
1107 name: project-test2
1108 foo: error
1109 """)
1110
1111 file_dict = {'zuul.yaml': in_repo_conf}
1112 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1113 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001114 A.addApproval('Code-Review', 2)
1115 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -08001116 self.waitUntilSettled()
1117
1118 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001119 self.assertEqual(A.reported, 1,
1120 "A should report failure")
1121 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -08001122 "A should have a syntax error reported")
1123
James E. Blair6f140c72017-03-03 10:32:07 -08001124 def test_untrusted_yaml_error(self):
1125 in_repo_conf = textwrap.dedent(
1126 """
1127 - job:
1128 foo: error
1129 """)
1130
1131 file_dict = {'.zuul.yaml': in_repo_conf}
1132 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1133 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001134 A.addApproval('Code-Review', 2)
1135 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -08001136 self.waitUntilSettled()
1137
1138 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001139 self.assertEqual(A.reported, 1,
1140 "A should report failure")
1141 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -08001142 "A should have a syntax error reported")
1143
James E. Blairdb04e6a2017-05-03 14:49:36 -07001144 def test_untrusted_shadow_error(self):
1145 in_repo_conf = textwrap.dedent(
1146 """
1147 - job:
1148 name: common-config-test
1149 """)
1150
1151 file_dict = {'.zuul.yaml': in_repo_conf}
1152 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1153 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001154 A.addApproval('Code-Review', 2)
1155 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -07001156 self.waitUntilSettled()
1157
1158 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001159 self.assertEqual(A.reported, 1,
1160 "A should report failure")
1161 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -07001162 "A should have a syntax error reported")
1163
James E. Blaird5656ad2017-06-02 14:29:41 -07001164 def test_untrusted_pipeline_error(self):
1165 in_repo_conf = textwrap.dedent(
1166 """
1167 - pipeline:
1168 name: test
1169 """)
1170
1171 file_dict = {'.zuul.yaml': in_repo_conf}
1172 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1173 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001174 A.addApproval('Code-Review', 2)
1175 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -07001176 self.waitUntilSettled()
1177
1178 self.assertEqual(A.data['status'], 'NEW')
1179 self.assertEqual(A.reported, 1,
1180 "A should report failure")
1181 self.assertIn('Pipelines may not be defined', A.messages[0],
1182 "A should have a syntax error reported")
1183
1184 def test_untrusted_project_error(self):
1185 in_repo_conf = textwrap.dedent(
1186 """
1187 - project:
1188 name: org/project1
1189 """)
1190
1191 file_dict = {'.zuul.yaml': in_repo_conf}
1192 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1193 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001194 A.addApproval('Code-Review', 2)
1195 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -07001196 self.waitUntilSettled()
1197
1198 self.assertEqual(A.data['status'], 'NEW')
1199 self.assertEqual(A.reported, 1,
1200 "A should report failure")
1201 self.assertIn('the only project definition permitted', A.messages[0],
1202 "A should have a syntax error reported")
1203
James E. Blairf03173b2017-10-10 10:46:43 -07001204 def test_untrusted_depends_on_trusted(self):
1205 with open(os.path.join(FIXTURE_DIR,
1206 'config/in-repo/git/',
1207 'common-config/zuul.yaml')) as f:
1208 common_config = f.read()
1209
1210 common_config += textwrap.dedent(
1211 """
1212 - job:
1213 name: project-test9
1214 """)
1215
1216 file_dict = {'zuul.yaml': common_config}
1217 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1218 files=file_dict)
1219 in_repo_conf = textwrap.dedent(
1220 """
1221 - job:
1222 name: project-test1
1223 - project:
1224 name: org/project
1225 check:
1226 jobs:
1227 - project-test9
1228 """)
1229
1230 file_dict = {'zuul.yaml': in_repo_conf}
1231 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1232 files=file_dict)
1233 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1234 B.subject, A.data['id'])
1235 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1236 self.waitUntilSettled()
1237
1238 self.assertEqual(B.data['status'], 'NEW')
1239 self.assertEqual(B.reported, 1,
1240 "B should report failure")
1241 self.assertIn('depends on a change to a config project',
1242 B.messages[0],
1243 "A should have a syntax error reported")
1244
James E. Blaire64b0e42017-06-08 11:23:34 -07001245 def test_duplicate_node_error(self):
1246 in_repo_conf = textwrap.dedent(
1247 """
1248 - nodeset:
1249 name: duplicate
1250 nodes:
1251 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001252 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001253 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001254 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001255 """)
1256
1257 file_dict = {'.zuul.yaml': in_repo_conf}
1258 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1259 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001260 A.addApproval('Code-Review', 2)
1261 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -07001262 self.waitUntilSettled()
1263
1264 self.assertEqual(A.data['status'], 'NEW')
1265 self.assertEqual(A.reported, 1,
1266 "A should report failure")
1267 self.assertIn('appears multiple times', A.messages[0],
1268 "A should have a syntax error reported")
1269
1270 def test_duplicate_group_error(self):
1271 in_repo_conf = textwrap.dedent(
1272 """
1273 - nodeset:
1274 name: duplicate
1275 nodes:
1276 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001277 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001278 groups:
1279 - name: group
1280 nodes: compute
1281 - name: group
1282 nodes: compute
1283 """)
1284
1285 file_dict = {'.zuul.yaml': in_repo_conf}
1286 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1287 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001288 A.addApproval('Code-Review', 2)
1289 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -07001290 self.waitUntilSettled()
1291
1292 self.assertEqual(A.data['status'], 'NEW')
1293 self.assertEqual(A.reported, 1,
1294 "A should report failure")
1295 self.assertIn('appears multiple times', A.messages[0],
1296 "A should have a syntax error reported")
1297
James E. Blair4ae399f2017-09-20 17:15:09 -07001298 def test_secret_not_found_error(self):
1299 in_repo_conf = textwrap.dedent(
1300 """
1301 - job:
1302 name: test
1303 secrets: does-not-exist
1304 """)
1305
1306 file_dict = {'.zuul.yaml': in_repo_conf}
1307 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1308 files=file_dict)
1309 A.addApproval('Code-Review', 2)
1310 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1311 self.waitUntilSettled()
1312
1313 self.assertEqual(A.data['status'], 'NEW')
1314 self.assertEqual(A.reported, 1,
1315 "A should report failure")
1316 self.assertIn('secret "does-not-exist" was not found', A.messages[0],
1317 "A should have a syntax error reported")
1318
1319 def test_nodeset_not_found_error(self):
1320 in_repo_conf = textwrap.dedent(
1321 """
1322 - job:
1323 name: test
1324 nodeset: does-not-exist
1325 """)
1326
1327 file_dict = {'.zuul.yaml': in_repo_conf}
1328 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1329 files=file_dict)
1330 A.addApproval('Code-Review', 2)
1331 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1332 self.waitUntilSettled()
1333
1334 self.assertEqual(A.data['status'], 'NEW')
1335 self.assertEqual(A.reported, 1,
1336 "A should report failure")
1337 self.assertIn('nodeset "does-not-exist" was not found', A.messages[0],
1338 "A should have a syntax error reported")
1339
James E. Blair89e25eb2017-09-26 09:11:31 -07001340 def test_template_not_found_error(self):
1341 in_repo_conf = textwrap.dedent(
1342 """
1343 - job:
1344 name: project-test1
1345 - project:
1346 name: org/project
1347 templates:
1348 - does-not-exist
1349 """)
1350
1351 file_dict = {'.zuul.yaml': in_repo_conf}
1352 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1353 files=file_dict)
1354 A.addApproval('Code-Review', 2)
1355 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1356 self.waitUntilSettled()
1357
1358 self.assertEqual(A.data['status'], 'NEW')
1359 self.assertEqual(A.reported, 1,
1360 "A should report failure")
1361 self.assertIn('project template "does-not-exist" was not found',
1362 A.messages[0],
1363 "A should have a syntax error reported")
1364
Monty Taylor8be3c0c2017-10-06 10:37:37 -05001365 def test_job_list_in_project_template_not_dict_error(self):
1366 in_repo_conf = textwrap.dedent(
1367 """
1368 - job:
1369 name: project-test1
1370 - project-template:
1371 name: some-jobs
1372 check:
1373 jobs:
1374 - project-test1:
1375 - required-projects:
1376 org/project2
1377 """)
1378
1379 file_dict = {'.zuul.yaml': in_repo_conf}
1380 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1381 files=file_dict)
1382 A.addApproval('Code-Review', 2)
1383 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1384 self.waitUntilSettled()
1385
1386 self.assertEqual(A.data['status'], 'NEW')
1387 self.assertEqual(A.reported, 1,
1388 "A should report failure")
1389 self.assertIn('expected str for dictionary value',
1390 A.messages[0], "A should have a syntax error reported")
1391
1392 def test_job_list_in_project_not_dict_error(self):
1393 in_repo_conf = textwrap.dedent(
1394 """
1395 - job:
1396 name: project-test1
1397 - project:
1398 name: org/project1
1399 check:
1400 jobs:
1401 - project-test1:
1402 - required-projects:
1403 org/project2
1404 """)
1405
1406 file_dict = {'.zuul.yaml': in_repo_conf}
1407 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1408 files=file_dict)
1409 A.addApproval('Code-Review', 2)
1410 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1411 self.waitUntilSettled()
1412
1413 self.assertEqual(A.data['status'], 'NEW')
1414 self.assertEqual(A.reported, 1,
1415 "A should report failure")
1416 self.assertIn('expected str for dictionary value',
1417 A.messages[0], "A should have a syntax error reported")
1418
James E. Blair1235f142017-10-07 09:11:43 -07001419 def test_project_template(self):
1420 # Tests that a project template is not modified when used, and
1421 # can therefore be used in subsequent reconfigurations.
1422 in_repo_conf = textwrap.dedent(
1423 """
1424 - job:
1425 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001426 run: playbooks/project-test1.yaml
James E. Blair1235f142017-10-07 09:11:43 -07001427 - project-template:
1428 name: some-jobs
1429 tenant-one-gate:
1430 jobs:
1431 - project-test1:
1432 required-projects:
1433 - org/project1
1434 - project:
1435 name: org/project
1436 templates:
1437 - some-jobs
1438 """)
1439
1440 file_dict = {'.zuul.yaml': in_repo_conf}
1441 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1442 files=file_dict)
1443 A.addApproval('Code-Review', 2)
1444 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1445 self.waitUntilSettled()
1446 self.assertEqual(A.data['status'], 'MERGED')
1447 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1448 self.waitUntilSettled()
1449 in_repo_conf = textwrap.dedent(
1450 """
1451 - project:
1452 name: org/project1
1453 templates:
1454 - some-jobs
1455 """)
1456 file_dict = {'.zuul.yaml': in_repo_conf}
1457 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
1458 files=file_dict)
1459 B.addApproval('Code-Review', 2)
1460 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1461 self.waitUntilSettled()
1462 self.assertEqual(B.data['status'], 'MERGED')
1463
James E. Blairbccdfcf2017-10-07 13:37:26 -07001464 def test_job_remove_add(self):
1465 # Tests that a job can be removed from one repo and added in another.
1466 # First, remove the current config for project1 since it
1467 # references the job we want to remove.
1468 file_dict = {'.zuul.yaml': None}
1469 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1470 files=file_dict)
1471 A.setMerged()
1472 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1473 self.waitUntilSettled()
1474 # Then propose a change to delete the job from one repo...
1475 file_dict = {'.zuul.yaml': None}
1476 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1477 files=file_dict)
1478 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1479 self.waitUntilSettled()
1480 # ...and a second that depends on it that adds it to another repo.
1481 in_repo_conf = textwrap.dedent(
1482 """
1483 - job:
1484 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001485 run: playbooks/project-test1.yaml
James E. Blairbccdfcf2017-10-07 13:37:26 -07001486
1487 - project:
1488 name: org/project1
1489 check:
1490 jobs:
1491 - project-test1
1492 """)
1493 in_repo_playbook = textwrap.dedent(
1494 """
1495 - hosts: all
1496 tasks: []
1497 """)
1498 file_dict = {'.zuul.yaml': in_repo_conf,
1499 'playbooks/project-test1.yaml': in_repo_playbook}
1500 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C',
1501 files=file_dict,
1502 parent='refs/changes/1/1/1')
1503 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1504 C.subject, B.data['id'])
1505 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1506 self.waitUntilSettled()
1507 self.assertHistory([
1508 dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'),
1509 ], ordered=False)
1510
James E. Blair09f9ffe2017-07-11 15:30:25 -07001511 def test_multi_repo(self):
1512 downstream_repo_conf = textwrap.dedent(
1513 """
1514 - project:
1515 name: org/project1
1516 tenant-one-gate:
1517 jobs:
1518 - project-test1
1519
1520 - job:
1521 name: project1-test1
1522 parent: project-test1
1523 """)
1524
1525 file_dict = {'.zuul.yaml': downstream_repo_conf}
1526 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1527 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001528 A.addApproval('Code-Review', 2)
1529 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001530 self.waitUntilSettled()
1531
1532 self.assertEqual(A.data['status'], 'MERGED')
1533 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1534 self.waitUntilSettled()
1535
1536 upstream_repo_conf = textwrap.dedent(
1537 """
1538 - job:
1539 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001540 run: playbooks/project-test1.yaml
James E. Blair09f9ffe2017-07-11 15:30:25 -07001541
1542 - job:
1543 name: project-test2
1544
1545 - project:
1546 name: org/project
1547 tenant-one-gate:
1548 jobs:
1549 - project-test1
1550 """)
1551
1552 file_dict = {'.zuul.yaml': upstream_repo_conf}
1553 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1554 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001555 B.addApproval('Code-Review', 2)
1556 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001557 self.waitUntilSettled()
1558
1559 self.assertEqual(B.data['status'], 'MERGED')
1560 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
1561 self.waitUntilSettled()
1562
1563 tenant = self.sched.abide.tenants.get('tenant-one')
1564 # Ensure the latest change is reflected in the config; if it
1565 # isn't this will raise an exception.
1566 tenant.layout.getJob('project-test2')
1567
James E. Blair332636e2017-09-05 10:14:35 -07001568 def test_pipeline_error(self):
1569 with open(os.path.join(FIXTURE_DIR,
1570 'config/in-repo/git/',
1571 'common-config/zuul.yaml')) as f:
1572 base_common_config = f.read()
1573
1574 in_repo_conf_A = textwrap.dedent(
1575 """
1576 - pipeline:
1577 name: periodic
1578 foo: error
1579 """)
1580
1581 file_dict = {'zuul.yaml': None,
1582 'zuul.d/main.yaml': base_common_config,
1583 'zuul.d/test1.yaml': in_repo_conf_A}
1584 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1585 files=file_dict)
1586 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1587 self.waitUntilSettled()
1588 self.assertEqual(A.reported, 1,
1589 "A should report failure")
1590 self.assertIn('syntax error',
1591 A.messages[0],
1592 "A should have an error reported")
1593
1594 def test_change_series_error(self):
1595 with open(os.path.join(FIXTURE_DIR,
1596 'config/in-repo/git/',
1597 'common-config/zuul.yaml')) as f:
1598 base_common_config = f.read()
1599
1600 in_repo_conf_A = textwrap.dedent(
1601 """
1602 - pipeline:
1603 name: periodic
1604 foo: error
1605 """)
1606
1607 file_dict = {'zuul.yaml': None,
1608 'zuul.d/main.yaml': base_common_config,
1609 'zuul.d/test1.yaml': in_repo_conf_A}
1610 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1611 files=file_dict)
1612
1613 in_repo_conf_B = textwrap.dedent(
1614 """
1615 - job:
1616 name: project-test2
1617 foo: error
1618 """)
1619
1620 file_dict = {'zuul.yaml': None,
1621 'zuul.d/main.yaml': base_common_config,
1622 'zuul.d/test1.yaml': in_repo_conf_A,
1623 'zuul.d/test2.yaml': in_repo_conf_B}
1624 B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B',
1625 files=file_dict)
1626 B.setDependsOn(A, 1)
1627 C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C')
1628 C.setDependsOn(B, 1)
1629 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1630 self.waitUntilSettled()
1631
1632 self.assertEqual(C.reported, 1,
1633 "C should report failure")
1634 self.assertIn('depends on a change that failed to merge',
1635 C.messages[0],
1636 "C should have an error reported")
1637
James E. Blairc73c73a2017-01-20 15:15:15 -08001638
James E. Blairc9455002017-09-06 09:22:19 -07001639class TestInRepoJoin(ZuulTestCase):
1640 # In this config, org/project is not a member of any pipelines, so
1641 # that we may test the changes that cause it to join them.
1642
1643 tenant_config_file = 'config/in-repo-join/main.yaml'
1644
1645 def test_dynamic_dependent_pipeline(self):
1646 # Test dynamically adding a project to a
1647 # dependent pipeline for the first time
1648 self.executor_server.hold_jobs_in_build = True
1649
1650 tenant = self.sched.abide.tenants.get('tenant-one')
1651 gate_pipeline = tenant.layout.pipelines['gate']
1652
1653 in_repo_conf = textwrap.dedent(
1654 """
1655 - job:
1656 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001657 run: playbooks/project-test1.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001658
1659 - job:
1660 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -07001661 run: playbooks/project-test2.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001662
1663 - project:
1664 name: org/project
1665 gate:
1666 jobs:
1667 - project-test2
1668 """)
1669
1670 in_repo_playbook = textwrap.dedent(
1671 """
1672 - hosts: all
1673 tasks: []
1674 """)
1675
1676 file_dict = {'.zuul.yaml': in_repo_conf,
1677 'playbooks/project-test2.yaml': in_repo_playbook}
1678 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1679 files=file_dict)
1680 A.addApproval('Code-Review', 2)
1681 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1682 self.waitUntilSettled()
1683
1684 items = gate_pipeline.getAllItems()
1685 self.assertEqual(items[0].change.number, '1')
1686 self.assertEqual(items[0].change.patchset, '1')
1687 self.assertTrue(items[0].live)
1688
1689 self.executor_server.hold_jobs_in_build = False
1690 self.executor_server.release()
1691 self.waitUntilSettled()
1692
1693 # Make sure the dynamic queue got cleaned up
1694 self.assertEqual(gate_pipeline.queues, [])
1695
1696 def test_dynamic_dependent_pipeline_failure(self):
1697 # Test that a change behind a failing change adding a project
1698 # to a dependent pipeline is dequeued.
1699 self.executor_server.hold_jobs_in_build = True
1700
1701 in_repo_conf = textwrap.dedent(
1702 """
1703 - job:
1704 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001705 run: playbooks/project-test1.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001706
1707 - project:
1708 name: org/project
1709 gate:
1710 jobs:
1711 - project-test1
1712 """)
1713
1714 file_dict = {'.zuul.yaml': in_repo_conf}
1715 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1716 files=file_dict)
1717 self.executor_server.failJob('project-test1', A)
1718 A.addApproval('Code-Review', 2)
1719 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1720 self.waitUntilSettled()
1721
1722 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1723 B.addApproval('Code-Review', 2)
1724 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1725 self.waitUntilSettled()
1726
James E. Blair3490c5d2017-09-07 08:33:23 -07001727 self.orderedRelease()
James E. Blairc9455002017-09-06 09:22:19 -07001728 self.waitUntilSettled()
1729 self.assertEqual(A.reported, 2,
1730 "A should report start and failure")
1731 self.assertEqual(A.data['status'], 'NEW')
1732 self.assertEqual(B.reported, 1,
1733 "B should report start")
1734 self.assertHistory([
1735 dict(name='project-test1', result='FAILURE', changes='1,1'),
James E. Blair3490c5d2017-09-07 08:33:23 -07001736 dict(name='project-test1', result='ABORTED', changes='1,1 2,1'),
James E. Blairc9455002017-09-06 09:22:19 -07001737 ], ordered=False)
1738
James E. Blair0af198f2017-09-06 09:52:35 -07001739 def test_dynamic_dependent_pipeline_absent(self):
1740 # Test that a series of dependent changes don't report merge
1741 # failures to a pipeline they aren't in.
1742 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1743 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1744 B.setDependsOn(A, 1)
1745
1746 A.addApproval('Code-Review', 2)
1747 A.addApproval('Approved', 1)
1748 B.addApproval('Code-Review', 2)
1749 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1750 self.waitUntilSettled()
1751 self.assertEqual(A.reported, 0,
1752 "A should not report")
1753 self.assertEqual(A.data['status'], 'NEW')
1754 self.assertEqual(B.reported, 0,
1755 "B should not report")
1756 self.assertEqual(B.data['status'], 'NEW')
1757 self.assertHistory([])
1758
James E. Blairc9455002017-09-06 09:22:19 -07001759
James E. Blairc73c73a2017-01-20 15:15:15 -08001760class TestAnsible(AnsibleZuulTestCase):
1761 # A temporary class to hold new tests while others are disabled
1762
1763 tenant_config_file = 'config/ansible/main.yaml'
1764
1765 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +11001766 # Keep the jobdir around so we can inspect contents if an
1767 # assert fails.
1768 self.executor_server.keep_jobdir = True
1769 # Output extra ansible info so we might see errors.
1770 self.executor_server.verbose = True
1771 # Add a site variables file, used by check-vars
1772 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
1773 'variables.yaml')
1774 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -08001775 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1776 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1777 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +02001778 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +11001779 with self.jobLog(build_timeout):
1780 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001781 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +11001782 with self.jobLog(build_faillocal):
1783 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001784 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +11001785 with self.jobLog(build_failpost):
1786 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001787 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +11001788 with self.jobLog(build_check_vars):
1789 self.assertEqual(build_check_vars.result, 'SUCCESS')
Monty Tayloraff8b402017-08-16 18:40:41 -05001790 build_check_secret_names = self.getJobFromHistory('check-secret-names')
1791 with self.jobLog(build_check_secret_names):
1792 self.assertEqual(build_check_secret_names.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001793 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +11001794 with self.jobLog(build_hello):
1795 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001796 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +11001797 with self.jobLog(build_python27):
1798 self.assertEqual(build_python27.result, 'SUCCESS')
1799 flag_path = os.path.join(self.test_root,
1800 build_python27.uuid + '.flag')
1801 self.assertTrue(os.path.exists(flag_path))
1802 copied_path = os.path.join(self.test_root, build_python27.uuid +
1803 '.copied')
1804 self.assertTrue(os.path.exists(copied_path))
1805 failed_path = os.path.join(self.test_root, build_python27.uuid +
1806 '.failed')
1807 self.assertFalse(os.path.exists(failed_path))
1808 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
1809 '.pre.flag')
1810 self.assertTrue(os.path.exists(pre_flag_path))
1811 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
1812 '.post.flag')
1813 self.assertTrue(os.path.exists(post_flag_path))
1814 bare_role_flag_path = os.path.join(self.test_root,
1815 build_python27.uuid +
1816 '.bare-role.flag')
1817 self.assertTrue(os.path.exists(bare_role_flag_path))
1818 secrets_path = os.path.join(self.test_root,
1819 build_python27.uuid + '.secrets')
1820 with open(secrets_path) as f:
1821 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -08001822
Jamie Lennox7655b552017-03-17 12:33:38 +11001823 msg = A.messages[0]
1824 success = "{} https://success.example.com/zuul-logs/{}"
1825 fail = "{} https://failure.example.com/zuul-logs/{}"
1826 self.assertIn(success.format("python27", build_python27.uuid), msg)
1827 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
1828 self.assertIn(success.format("check-vars",
1829 build_check_vars.uuid), msg)
1830 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
1831 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
1832 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +02001833
James E. Blairabbaa6f2017-04-06 16:11:44 -07001834 def _add_job(self, job_name):
1835 conf = textwrap.dedent(
1836 """
1837 - job:
1838 name: %s
James E. Blair2f589fe2017-10-26 12:57:41 -07001839 run: playbooks/%s.yaml
James E. Blairabbaa6f2017-04-06 16:11:44 -07001840
1841 - project:
1842 name: org/plugin-project
1843 check:
1844 jobs:
1845 - %s
James E. Blair2f589fe2017-10-26 12:57:41 -07001846 """ % (job_name, job_name, job_name))
James E. Blairabbaa6f2017-04-06 16:11:44 -07001847
1848 file_dict = {'.zuul.yaml': conf}
1849 A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A',
1850 files=file_dict)
1851 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1852 self.waitUntilSettled()
1853
1854 def test_plugins(self):
1855 # Keep the jobdir around so we can inspect contents if an
1856 # assert fails.
1857 self.executor_server.keep_jobdir = True
1858 # Output extra ansible info so we might see errors.
1859 self.executor_server.verbose = True
1860
1861 count = 0
1862 plugin_tests = [
1863 ('passwd', 'FAILURE'),
1864 ('cartesian', 'SUCCESS'),
1865 ('consul_kv', 'FAILURE'),
1866 ('credstash', 'FAILURE'),
1867 ('csvfile_good', 'SUCCESS'),
1868 ('csvfile_bad', 'FAILURE'),
Monty Taylor93ad2212017-08-02 14:59:50 -05001869 ('uri_bad_path', 'FAILURE'),
1870 ('uri_bad_scheme', 'FAILURE'),
Monty Taylor788a40e2017-08-02 16:14:05 -05001871 ('block_local_override', 'FAILURE'),
Monty Taylor8da768f2017-08-31 14:15:35 -05001872 ('file_local_good', 'SUCCESS'),
1873 ('file_local_bad', 'FAILURE'),
James E. Blairabbaa6f2017-04-06 16:11:44 -07001874 ]
1875 for job_name, result in plugin_tests:
1876 count += 1
1877 self._add_job(job_name)
1878
1879 job = self.getJobFromHistory(job_name)
1880 with self.jobLog(job):
1881 self.assertEqual(count, len(self.history))
1882 build = self.history[-1]
1883 self.assertEqual(build.result, result)
1884
1885 # TODOv3(jeblair): parse the ansible output and verify we're
1886 # getting the exception we expect.
1887
James E. Blairb9c0d772017-03-03 14:34:49 -08001888
James E. Blaira4d4eef2017-06-30 14:49:17 -07001889class TestPrePlaybooks(AnsibleZuulTestCase):
1890 # A temporary class to hold new tests while others are disabled
1891
1892 tenant_config_file = 'config/pre-playbook/main.yaml'
1893
1894 def test_pre_playbook_fail(self):
1895 # Test that we run the post playbooks (but not the actual
1896 # playbook) when a pre-playbook fails.
1897 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1898 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1899 self.waitUntilSettled()
1900 build = self.getJobFromHistory('python27')
1901 self.assertIsNone(build.result)
1902 self.assertIn('RETRY_LIMIT', A.messages[0])
1903 flag_path = os.path.join(self.test_root, build.uuid +
1904 '.main.flag')
1905 self.assertFalse(os.path.exists(flag_path))
1906 pre_flag_path = os.path.join(self.test_root, build.uuid +
1907 '.pre.flag')
1908 self.assertFalse(os.path.exists(pre_flag_path))
1909 post_flag_path = os.path.join(self.test_root, build.uuid +
1910 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -07001911 self.assertTrue(os.path.exists(post_flag_path),
1912 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -07001913
1914
James E. Blairbacbb882017-10-17 09:48:23 -07001915class TestPostPlaybooks(AnsibleZuulTestCase):
1916 tenant_config_file = 'config/post-playbook/main.yaml'
1917
1918 def test_post_playbook_abort(self):
1919 # Test that when we abort a job in the post playbook, that we
1920 # don't send back POST_FAILURE.
1921 self.executor_server.verbose = True
1922 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1923 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1924
1925 while not len(self.builds):
1926 time.sleep(0.1)
1927 build = self.builds[0]
1928
1929 post_start = os.path.join(self.test_root, build.uuid +
1930 '.post_start.flag')
1931 start = time.time()
1932 while time.time() < start + 90:
1933 if os.path.exists(post_start):
1934 break
1935 time.sleep(0.1)
1936 # The post playbook has started, abort the job
1937 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1938 self.waitUntilSettled()
1939
1940 build = self.getJobFromHistory('python27')
1941 self.assertEqual('ABORTED', build.result)
1942
1943 post_end = os.path.join(self.test_root, build.uuid +
1944 '.post_end.flag')
1945 self.assertTrue(os.path.exists(post_start))
1946 self.assertFalse(os.path.exists(post_end))
1947
1948
James E. Blairb9c0d772017-03-03 14:34:49 -08001949class TestBrokenConfig(ZuulTestCase):
1950 # Test that we get an appropriate syntax error if we start with a
1951 # broken config.
1952
1953 tenant_config_file = 'config/broken/main.yaml'
1954
1955 def setUp(self):
1956 with testtools.ExpectedException(
1957 zuul.configloader.ConfigurationSyntaxError,
1958 "\nZuul encountered a syntax error"):
1959 super(TestBrokenConfig, self).setUp()
1960
1961 def test_broken_config_on_startup(self):
1962 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001963
1964
1965class TestProjectKeys(ZuulTestCase):
1966 # Test that we can generate project keys
1967
1968 # Normally the test infrastructure copies a static key in place
1969 # for each project before starting tests. This saves time because
1970 # Zuul's automatic key-generation on startup can be slow. To make
1971 # sure we exercise that code, in this test we allow Zuul to create
1972 # keys for the project on startup.
1973 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +02001974 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001975 tenant_config_file = 'config/in-repo/main.yaml'
1976
1977 def test_key_generation(self):
1978 key_root = os.path.join(self.state_root, 'keys')
1979 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
1980 # Make sure that a proper key was created on startup
1981 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -07001982 private_key, public_key = \
1983 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001984
1985 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
1986 fixture_private_key = i.read()
1987
1988 # Make sure that we didn't just end up with the static fixture
1989 # key
1990 self.assertNotEqual(fixture_private_key, private_key)
1991
1992 # Make sure it's the right length
1993 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -07001994
1995
James E. Blairbb94dfa2017-07-11 07:45:19 -07001996class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -07001997 def _assertRolePath(self, build, playbook, content):
1998 path = os.path.join(self.test_root, build.uuid,
1999 'ansible', playbook, 'ansible.cfg')
2000 roles_paths = []
2001 with open(path) as f:
2002 for line in f:
2003 if line.startswith('roles_path'):
2004 roles_paths.append(line)
2005 print(roles_paths)
2006 if content:
2007 self.assertEqual(len(roles_paths), 1,
2008 "Should have one roles_path line in %s" %
2009 (playbook,))
2010 self.assertIn(content, roles_paths[0])
2011 else:
2012 self.assertEqual(len(roles_paths), 0,
2013 "Should have no roles_path line in %s" %
2014 (playbook,))
2015
James E. Blairbb94dfa2017-07-11 07:45:19 -07002016
2017class TestRoles(RoleTestCase):
2018 tenant_config_file = 'config/roles/main.yaml'
2019
James E. Blairbce76932017-05-04 10:03:15 -07002020 def test_role(self):
2021 # This exercises a proposed change to a role being checked out
2022 # and used.
2023 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
2024 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2025 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
2026 B.subject, A.data['id'])
2027 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2028 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2029 self.waitUntilSettled()
2030 self.assertHistory([
2031 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
2032 ])
James E. Blair6459db12017-06-29 14:57:20 -07002033
James E. Blair1b27f6a2017-07-14 14:09:07 -07002034 def test_role_inheritance(self):
2035 self.executor_server.hold_jobs_in_build = True
2036 conf = textwrap.dedent(
2037 """
2038 - job:
2039 name: parent
2040 roles:
2041 - zuul: bare-role
Ian Wienand548c43c2017-12-05 14:16:32 +11002042 pre-run: playbooks/parent-pre.yaml
2043 post-run: playbooks/parent-post.yaml
James E. Blair1b27f6a2017-07-14 14:09:07 -07002044
2045 - job:
2046 name: project-test
2047 parent: parent
James E. Blair2f589fe2017-10-26 12:57:41 -07002048 run: playbooks/project-test.yaml
James E. Blair1b27f6a2017-07-14 14:09:07 -07002049 roles:
2050 - zuul: org/project
2051
2052 - project:
2053 name: org/project
2054 check:
2055 jobs:
2056 - project-test
2057 """)
2058
2059 file_dict = {'.zuul.yaml': conf}
2060 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2061 files=file_dict)
2062 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2063 self.waitUntilSettled()
2064
2065 self.assertEqual(len(self.builds), 1)
2066 build = self.getBuildByName('project-test')
2067 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
2068 self._assertRolePath(build, 'playbook_0', 'role_0')
2069 self._assertRolePath(build, 'playbook_0', 'role_1')
2070 self._assertRolePath(build, 'post_playbook_0', 'role_0')
2071
2072 self.executor_server.hold_jobs_in_build = False
2073 self.executor_server.release()
2074 self.waitUntilSettled()
2075
2076 self.assertHistory([
2077 dict(name='project-test', result='SUCCESS', changes='1,1'),
2078 ])
2079
James E. Blair6f699732017-07-18 14:19:11 -07002080 def test_role_error(self):
2081 conf = textwrap.dedent(
2082 """
2083 - job:
2084 name: project-test
James E. Blair2f589fe2017-10-26 12:57:41 -07002085 run: playbooks/project-test.yaml
James E. Blair6f699732017-07-18 14:19:11 -07002086 roles:
2087 - zuul: common-config
2088
2089 - project:
2090 name: org/project
2091 check:
2092 jobs:
2093 - project-test
2094 """)
2095
2096 file_dict = {'.zuul.yaml': conf}
2097 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2098 files=file_dict)
2099 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2100 self.waitUntilSettled()
2101 self.assertIn(
2102 '- project-test project-test : ERROR Unable to find role',
2103 A.messages[-1])
2104
James E. Blair6459db12017-06-29 14:57:20 -07002105
James E. Blairbb94dfa2017-07-11 07:45:19 -07002106class TestImplicitRoles(RoleTestCase):
2107 tenant_config_file = 'config/implicit-roles/main.yaml'
2108
2109 def test_missing_roles(self):
2110 # Test implicit and explicit roles for a project which does
2111 # not have roles. The implicit role should be silently
2112 # ignored since the project doesn't supply roles, but if a
2113 # user declares an explicit role, it should error.
2114 self.executor_server.hold_jobs_in_build = True
2115 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
2116 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2117 self.waitUntilSettled()
2118
2119 self.assertEqual(len(self.builds), 2)
2120 build = self.getBuildByName('implicit-role-fail')
2121 self._assertRolePath(build, 'playbook_0', None)
2122
2123 self.executor_server.hold_jobs_in_build = False
2124 self.executor_server.release()
2125 self.waitUntilSettled()
2126 # The retry_limit doesn't get recorded
2127 self.assertHistory([
2128 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
2129 ])
2130
2131 def test_roles(self):
2132 # Test implicit and explicit roles for a project which does
2133 # have roles. In both cases, we should end up with the role
2134 # in the path. In the explicit case, ensure we end up with
2135 # the name we specified.
2136 self.executor_server.hold_jobs_in_build = True
2137 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
2138 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2139 self.waitUntilSettled()
2140
2141 self.assertEqual(len(self.builds), 2)
2142 build = self.getBuildByName('implicit-role-ok')
2143 self._assertRolePath(build, 'playbook_0', 'role_0')
2144
2145 build = self.getBuildByName('explicit-role-ok')
2146 self._assertRolePath(build, 'playbook_0', 'role_0')
2147
2148 self.executor_server.hold_jobs_in_build = False
2149 self.executor_server.release()
2150 self.waitUntilSettled()
2151 self.assertHistory([
2152 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
2153 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
2154 ], ordered=False)
2155
2156
James E. Blair6459db12017-06-29 14:57:20 -07002157class TestShadow(ZuulTestCase):
2158 tenant_config_file = 'config/shadow/main.yaml'
2159
2160 def test_shadow(self):
2161 # Test that a repo is allowed to shadow another's job definitions.
2162 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2163 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2164 self.waitUntilSettled()
2165 self.assertHistory([
2166 dict(name='test1', result='SUCCESS', changes='1,1'),
2167 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -07002168 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -07002169
2170
2171class TestDataReturn(AnsibleZuulTestCase):
2172 tenant_config_file = 'config/data-return/main.yaml'
2173
2174 def test_data_return(self):
James E. Blair196f61a2017-06-30 15:42:29 -07002175 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2176 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2177 self.waitUntilSettled()
2178 self.assertHistory([
2179 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07002180 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
James E. Blair698703c2017-09-15 20:58:30 -06002181 dict(name='child', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07002182 ], ordered=False)
2183 self.assertIn('- data-return http://example.com/test/log/url/',
2184 A.messages[-1])
2185 self.assertIn('- data-return-relative '
2186 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -07002187 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -07002188
2189
2190class TestDiskAccounting(AnsibleZuulTestCase):
2191 config_file = 'zuul-disk-accounting.conf'
2192 tenant_config_file = 'config/disk-accountant/main.yaml'
2193
2194 def test_disk_accountant_kills_job(self):
2195 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2196 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2197 self.waitUntilSettled()
2198 self.assertHistory([
2199 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002200
2201
2202class TestMaxNodesPerJob(AnsibleZuulTestCase):
2203 tenant_config_file = 'config/multi-tenant/main.yaml'
2204
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00002205 def test_max_timeout_exceeded(self):
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002206 in_repo_conf = textwrap.dedent(
2207 """
2208 - job:
2209 name: test-job
James E. Blair7e3e6882017-09-20 15:47:13 -07002210 nodeset:
2211 nodes:
2212 - name: node01
2213 label: fake
2214 - name: node02
2215 label: fake
2216 - name: node03
2217 label: fake
2218 - name: node04
2219 label: fake
2220 - name: node05
2221 label: fake
2222 - name: node06
2223 label: fake
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002224 """)
2225 file_dict = {'.zuul.yaml': in_repo_conf}
2226 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2227 files=file_dict)
2228 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2229 self.waitUntilSettled()
2230 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
2231 A.messages[0], "A should fail because of nodes limit")
2232
2233 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2234 files=file_dict)
2235 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2236 self.waitUntilSettled()
2237 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
2238 "B should not fail because of nodes limit")
James E. Blair2bab6e72017-08-07 09:52:45 -07002239
2240
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00002241class TestMaxTimeout(AnsibleZuulTestCase):
2242 tenant_config_file = 'config/multi-tenant/main.yaml'
2243
2244 def test_max_nodes_reached(self):
2245 in_repo_conf = textwrap.dedent(
2246 """
2247 - job:
2248 name: test-job
2249 timeout: 3600
2250 """)
2251 file_dict = {'.zuul.yaml': in_repo_conf}
2252 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2253 files=file_dict)
2254 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2255 self.waitUntilSettled()
2256 self.assertIn('The job "test-job" exceeds tenant max-job-timeout',
2257 A.messages[0], "A should fail because of timeout limit")
2258
2259 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2260 files=file_dict)
2261 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2262 self.waitUntilSettled()
2263 self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0],
2264 "B should not fail because of timeout limit")
2265
2266
James E. Blair7edc25f2017-10-26 10:47:14 -07002267class TestPragma(ZuulTestCase):
2268 tenant_config_file = 'config/pragma/main.yaml'
2269
2270 def test_no_pragma(self):
2271 self.create_branch('org/project', 'stable')
2272 with open(os.path.join(FIXTURE_DIR,
2273 'config/pragma/git/',
2274 'org_project/nopragma.yaml')) as f:
2275 config = f.read()
2276 file_dict = {'.zuul.yaml': config}
2277 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2278 files=file_dict)
2279 A.addApproval('Code-Review', 2)
2280 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2281 self.waitUntilSettled()
2282 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2283 self.waitUntilSettled()
2284
2285 # This is an untrusted repo with 2 branches, so it should have
2286 # an implied branch matcher for the job.
2287 tenant = self.sched.abide.tenants.get('tenant-one')
2288 jobs = tenant.layout.getJobs('test-job')
2289 self.assertEqual(len(jobs), 1)
2290 for job in tenant.layout.getJobs('test-job'):
2291 self.assertIsNotNone(job.branch_matcher)
2292
2293 def test_pragma(self):
2294 self.create_branch('org/project', 'stable')
2295 with open(os.path.join(FIXTURE_DIR,
2296 'config/pragma/git/',
2297 'org_project/pragma.yaml')) as f:
2298 config = f.read()
2299 file_dict = {'.zuul.yaml': config}
2300 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2301 files=file_dict)
2302 A.addApproval('Code-Review', 2)
2303 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2304 self.waitUntilSettled()
2305 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2306 self.waitUntilSettled()
2307
2308 # This is an untrusted repo with 2 branches, so it would
2309 # normally have an implied branch matcher, but our pragma
2310 # overrides it.
2311 tenant = self.sched.abide.tenants.get('tenant-one')
2312 jobs = tenant.layout.getJobs('test-job')
2313 self.assertEqual(len(jobs), 1)
2314 for job in tenant.layout.getJobs('test-job'):
2315 self.assertIsNone(job.branch_matcher)
2316
2317
James E. Blair2bab6e72017-08-07 09:52:45 -07002318class TestBaseJobs(ZuulTestCase):
2319 tenant_config_file = 'config/base-jobs/main.yaml'
2320
2321 def test_multiple_base_jobs(self):
2322 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2323 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2324 self.waitUntilSettled()
2325 self.assertHistory([
2326 dict(name='my-job', result='SUCCESS', changes='1,1'),
2327 dict(name='other-job', result='SUCCESS', changes='1,1'),
2328 ], ordered=False)
2329 self.assertEqual(self.getJobFromHistory('my-job').
2330 parameters['zuul']['jobtags'],
2331 ['mybase'])
2332 self.assertEqual(self.getJobFromHistory('other-job').
2333 parameters['zuul']['jobtags'],
2334 ['otherbase'])
2335
2336 def test_untrusted_base_job(self):
2337 """Test that a base job may not be defined in an untrusted repo"""
2338 in_repo_conf = textwrap.dedent(
2339 """
2340 - job:
2341 name: fail-base
2342 parent: null
2343 """)
2344
2345 file_dict = {'.zuul.yaml': in_repo_conf}
2346 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2347 files=file_dict)
2348 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2349 self.waitUntilSettled()
2350 self.assertEqual(A.reported, 1,
2351 "A should report failure")
2352 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
2353 self.assertIn('Base jobs must be defined in config projects',
2354 A.messages[0])
2355 self.assertHistory([])
James E. Blairdb089032017-08-15 13:42:12 -07002356
2357
James E. Blairdf91ab32017-10-25 17:57:13 -07002358class TestSecretInheritance(ZuulTestCase):
2359 tenant_config_file = 'config/secret-inheritance/main.yaml'
2360
2361 def _getSecrets(self, job, pbtype):
2362 secrets = []
2363 build = self.getJobFromHistory(job)
2364 for pb in build.parameters[pbtype]:
2365 secrets.append(pb['secrets'])
2366 return secrets
2367
2368 def _checkTrustedSecrets(self):
2369 secret = {'longpassword': 'test-passwordtest-password',
2370 'password': 'test-password',
2371 'username': 'test-username'}
2372 self.assertEqual(
2373 self._getSecrets('trusted-secrets', 'playbooks'),
James E. Blair2f589fe2017-10-26 12:57:41 -07002374 [{'trusted-secret': secret}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002375 self.assertEqual(
2376 self._getSecrets('trusted-secrets', 'pre_playbooks'), [])
2377 self.assertEqual(
2378 self._getSecrets('trusted-secrets', 'post_playbooks'), [])
2379
2380 self.assertEqual(
2381 self._getSecrets('trusted-secrets-trusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002382 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002383 self.assertEqual(
2384 self._getSecrets('trusted-secrets-trusted-child',
2385 'pre_playbooks'), [])
2386 self.assertEqual(
2387 self._getSecrets('trusted-secrets-trusted-child',
2388 'post_playbooks'), [])
2389
2390 self.assertEqual(
2391 self._getSecrets('trusted-secrets-untrusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002392 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002393 self.assertEqual(
2394 self._getSecrets('trusted-secrets-untrusted-child',
2395 'pre_playbooks'), [])
2396 self.assertEqual(
2397 self._getSecrets('trusted-secrets-untrusted-child',
2398 'post_playbooks'), [])
2399
2400 def _checkUntrustedSecrets(self):
2401 secret = {'longpassword': 'test-passwordtest-password',
2402 'password': 'test-password',
2403 'username': 'test-username'}
2404 self.assertEqual(
2405 self._getSecrets('untrusted-secrets', 'playbooks'),
James E. Blair2f589fe2017-10-26 12:57:41 -07002406 [{'untrusted-secret': secret}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002407 self.assertEqual(
2408 self._getSecrets('untrusted-secrets', 'pre_playbooks'), [])
2409 self.assertEqual(
2410 self._getSecrets('untrusted-secrets', 'post_playbooks'), [])
2411
2412 self.assertEqual(
2413 self._getSecrets('untrusted-secrets-trusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002414 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002415 self.assertEqual(
2416 self._getSecrets('untrusted-secrets-trusted-child',
2417 'pre_playbooks'), [])
2418 self.assertEqual(
2419 self._getSecrets('untrusted-secrets-trusted-child',
2420 'post_playbooks'), [])
2421
2422 self.assertEqual(
2423 self._getSecrets('untrusted-secrets-untrusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002424 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002425 self.assertEqual(
2426 self._getSecrets('untrusted-secrets-untrusted-child',
2427 'pre_playbooks'), [])
2428 self.assertEqual(
2429 self._getSecrets('untrusted-secrets-untrusted-child',
2430 'post_playbooks'), [])
2431
2432 def test_trusted_secret_inheritance_check(self):
2433 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
2434 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2435 self.waitUntilSettled()
2436 self.assertHistory([
2437 dict(name='trusted-secrets', result='SUCCESS', changes='1,1'),
2438 dict(name='trusted-secrets-trusted-child',
2439 result='SUCCESS', changes='1,1'),
2440 dict(name='trusted-secrets-untrusted-child',
2441 result='SUCCESS', changes='1,1'),
2442 ], ordered=False)
2443
2444 self._checkTrustedSecrets()
2445
2446 def test_untrusted_secret_inheritance_gate(self):
2447 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
2448 A.addApproval('Code-Review', 2)
2449 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2450 self.waitUntilSettled()
2451 self.assertHistory([
2452 dict(name='untrusted-secrets', result='SUCCESS', changes='1,1'),
2453 dict(name='untrusted-secrets-trusted-child',
2454 result='SUCCESS', changes='1,1'),
2455 dict(name='untrusted-secrets-untrusted-child',
2456 result='SUCCESS', changes='1,1'),
2457 ], ordered=False)
2458
2459 self._checkUntrustedSecrets()
2460
2461 def test_untrusted_secret_inheritance_check(self):
2462 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2463 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2464 self.waitUntilSettled()
2465 # This configuration tries to run untrusted secrets in an
2466 # non-post-review pipeline and should therefore run no jobs.
2467 self.assertHistory([])
2468
2469
James E. Blairdb089032017-08-15 13:42:12 -07002470class TestSecretLeaks(AnsibleZuulTestCase):
2471 tenant_config_file = 'config/secret-leaks/main.yaml'
2472
2473 def searchForContent(self, path, content):
2474 matches = []
2475 for (dirpath, dirnames, filenames) in os.walk(path):
2476 for filename in filenames:
2477 filepath = os.path.join(dirpath, filename)
2478 with open(filepath, 'rb') as f:
2479 if content in f.read():
2480 matches.append(filepath[len(path):])
2481 return matches
2482
2483 def _test_secret_file(self):
2484 # Or rather -- test that they *don't* leak.
2485 # Keep the jobdir around so we can inspect contents.
2486 self.executor_server.keep_jobdir = True
2487 conf = textwrap.dedent(
2488 """
2489 - project:
2490 name: org/project
2491 check:
2492 jobs:
2493 - secret-file
2494 """)
2495
2496 file_dict = {'.zuul.yaml': conf}
2497 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2498 files=file_dict)
2499 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2500 self.waitUntilSettled()
2501 self.assertHistory([
2502 dict(name='secret-file', result='SUCCESS', changes='1,1'),
2503 ], ordered=False)
2504 matches = self.searchForContent(self.history[0].jobdir.root,
2505 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07002506 self.assertEqual(set(['/work/secret-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07002507 set(matches))
2508
2509 def test_secret_file(self):
2510 self._test_secret_file()
2511
2512 def test_secret_file_verbose(self):
2513 # Output extra ansible info to exercise alternate logging code
2514 # paths.
2515 self.executor_server.verbose = True
2516 self._test_secret_file()
2517
2518 def _test_secret_file_fail(self):
2519 # Or rather -- test that they *don't* leak.
2520 # Keep the jobdir around so we can inspect contents.
2521 self.executor_server.keep_jobdir = True
2522 conf = textwrap.dedent(
2523 """
2524 - project:
2525 name: org/project
2526 check:
2527 jobs:
2528 - secret-file-fail
2529 """)
2530
2531 file_dict = {'.zuul.yaml': conf}
2532 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2533 files=file_dict)
2534 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2535 self.waitUntilSettled()
2536 self.assertHistory([
2537 dict(name='secret-file-fail', result='FAILURE', changes='1,1'),
2538 ], ordered=False)
2539 matches = self.searchForContent(self.history[0].jobdir.root,
2540 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07002541 self.assertEqual(set(['/work/failure-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07002542 set(matches))
2543
2544 def test_secret_file_fail(self):
2545 self._test_secret_file_fail()
2546
2547 def test_secret_file_fail_verbose(self):
2548 # Output extra ansible info to exercise alternate logging code
2549 # paths.
2550 self.executor_server.verbose = True
2551 self._test_secret_file_fail()
James E. Blaira00910c2017-08-23 09:15:04 -07002552
2553
2554class TestJobOutput(AnsibleZuulTestCase):
2555 tenant_config_file = 'config/job-output/main.yaml'
2556
2557 def _get_file(self, build, path):
2558 p = os.path.join(build.jobdir.root, path)
2559 with open(p) as f:
2560 return f.read()
2561
2562 def test_job_output(self):
Monty Taylor0e2489a2017-10-10 11:57:29 -05002563 # Verify that command standard output appears in the job output,
2564 # and that failures in the final playbook get logged.
James E. Blaira00910c2017-08-23 09:15:04 -07002565
2566 # This currently only verifies we receive output from
2567 # localhost. Notably, it does not verify we receive output
2568 # via zuul_console streaming.
2569 self.executor_server.keep_jobdir = True
2570 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2571 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2572 self.waitUntilSettled()
2573 self.assertHistory([
2574 dict(name='job-output', result='SUCCESS', changes='1,1'),
2575 ], ordered=False)
2576
2577 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2578 j = json.loads(self._get_file(self.history[0],
2579 'work/logs/job-output.json'))
2580 self.assertEqual(token,
2581 j[0]['plays'][0]['tasks'][0]
2582 ['hosts']['localhost']['stdout'])
2583
2584 print(self._get_file(self.history[0],
2585 'work/logs/job-output.txt'))
2586 self.assertIn(token,
2587 self._get_file(self.history[0],
2588 'work/logs/job-output.txt'))
Monty Taylor0e2489a2017-10-10 11:57:29 -05002589
2590 def test_job_output_failure_log(self):
2591 logger = logging.getLogger('zuul.AnsibleJob')
2592 output = io.StringIO()
2593 logger.addHandler(logging.StreamHandler(output))
2594
2595 # Verify that a failure in the last post playbook emits the contents
2596 # of the json output to the log
2597 self.executor_server.keep_jobdir = True
2598 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
2599 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2600 self.waitUntilSettled()
2601 self.assertHistory([
2602 dict(name='job-output-failure',
2603 result='POST_FAILURE', changes='1,1'),
2604 ], ordered=False)
2605
2606 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2607 j = json.loads(self._get_file(self.history[0],
2608 'work/logs/job-output.json'))
2609 self.assertEqual(token,
2610 j[0]['plays'][0]['tasks'][0]
2611 ['hosts']['localhost']['stdout'])
2612
2613 print(self._get_file(self.history[0],
2614 'work/logs/job-output.json'))
2615 self.assertIn(token,
2616 self._get_file(self.history[0],
2617 'work/logs/job-output.txt'))
2618
2619 log_output = output.getvalue()
2620 self.assertIn('Final playbook failed', log_output)
2621 self.assertIn('Failure test', log_output)