blob: e4ef619d329c8eadde6119889bb5b98bb8ab0353 [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 Henkel83167622017-06-30 19:45:03 +020076class TestFinal(ZuulTestCase):
77
78 tenant_config_file = 'config/final/main.yaml'
79
80 def test_final_variant_ok(self):
81 # test clean usage of final parent job
82 in_repo_conf = textwrap.dedent(
83 """
84 - project:
85 name: org/project
86 check:
87 jobs:
88 - job-final
89 """)
90
91 file_dict = {'.zuul.yaml': in_repo_conf}
92 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
93 files=file_dict)
94 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
95 self.waitUntilSettled()
96
97 self.assertEqual(A.reported, 1)
98 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1')
99
100 def test_final_variant_error(self):
101 # test misuse of final parent job
102 in_repo_conf = textwrap.dedent(
103 """
104 - project:
105 name: org/project
106 check:
107 jobs:
108 - job-final:
109 vars:
110 dont_override_this: bar
111 """)
112 file_dict = {'.zuul.yaml': in_repo_conf}
113 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
114 files=file_dict)
115 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
116 self.waitUntilSettled()
117
118 # The second patch tried to override some variables.
119 # Thus it should fail.
120 self.assertEqual(A.reported, 1)
121 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
122 self.assertIn('Unable to modify final job', A.messages[0])
123
124 def test_final_inheritance(self):
125 # test misuse of final parent job
126 in_repo_conf = textwrap.dedent(
127 """
128 - job:
129 name: project-test
130 parent: job-final
James E. Blair2f589fe2017-10-26 12:57:41 -0700131 run: playbooks/project-test.yaml
Tobias Henkel83167622017-06-30 19:45:03 +0200132
133 - project:
134 name: org/project
135 check:
136 jobs:
137 - project-test
138 """)
139
140 in_repo_playbook = textwrap.dedent(
141 """
142 - hosts: all
143 tasks: []
144 """)
145
146 file_dict = {'.zuul.yaml': in_repo_conf,
147 'playbooks/project-test.yaml': in_repo_playbook}
148 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
149 files=file_dict)
150 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
151 self.waitUntilSettled()
152
153 # The second patch tried to override some variables.
154 # Thus it should fail.
155 self.assertEqual(A.reported, 1)
156 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
James E. Blairc32a8352017-10-11 16:27:50 -0700157 self.assertIn('Unable to modify final job', A.messages[0])
Tobias Henkel83167622017-06-30 19:45:03 +0200158
159
James E. Blair1edfd972017-12-01 15:54:24 -0800160class TestBranchTag(ZuulTestCase):
161 tenant_config_file = 'config/branch-tag/main.yaml'
162
163 def test_negative_branch_match(self):
164 # Test that a negative branch matcher works with implied branches.
165 event = self.fake_gerrit.addFakeTag('org/project', 'master', 'foo')
166 self.fake_gerrit.addEvent(event)
167 self.waitUntilSettled()
168 self.assertHistory([
169 dict(name='test-job', result='SUCCESS', ref='refs/tags/foo')])
170
171
James E. Blair9ab8db42017-12-01 15:12:04 -0800172class TestBranchNegative(ZuulTestCase):
173 tenant_config_file = 'config/branch-negative/main.yaml'
174
175 def test_negative_branch_match(self):
176 # Test that a negative branch matcher works with implied branches.
177 self.create_branch('org/project', 'stable/pike')
178 self.fake_gerrit.addEvent(
179 self.fake_gerrit.getFakeBranchCreatedEvent(
180 'org/project', 'stable/pike'))
181 self.waitUntilSettled()
182
183 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
184 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
185 self.waitUntilSettled()
186 B = self.fake_gerrit.addFakeChange('org/project', 'stable/pike', 'A')
187 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
188 self.waitUntilSettled()
189 self.assertHistory([
190 dict(name='test-job', result='SUCCESS', changes='1,1')])
191
192
James E. Blaire36d1a32017-11-28 13:33:38 -0800193class TestBranchTemplates(ZuulTestCase):
194 tenant_config_file = 'config/branch-templates/main.yaml'
195
196 def test_template_removal_from_branch(self):
197 # Test that a template can be removed from one branch but not
198 # another.
199 # This creates a new branch with a copy of the config in master
200 self.create_branch('puppet-integration', 'stable/newton')
201 self.create_branch('puppet-integration', 'stable/ocata')
202 self.create_branch('puppet-tripleo', 'stable/newton')
203 self.create_branch('puppet-tripleo', 'stable/ocata')
204 self.fake_gerrit.addEvent(
205 self.fake_gerrit.getFakeBranchCreatedEvent(
206 'puppet-integration', 'stable/newton'))
207 self.fake_gerrit.addEvent(
208 self.fake_gerrit.getFakeBranchCreatedEvent(
209 'puppet-integration', 'stable/ocata'))
210 self.fake_gerrit.addEvent(
211 self.fake_gerrit.getFakeBranchCreatedEvent(
212 'puppet-tripleo', 'stable/newton'))
213 self.fake_gerrit.addEvent(
214 self.fake_gerrit.getFakeBranchCreatedEvent(
215 'puppet-tripleo', 'stable/ocata'))
216 self.waitUntilSettled()
217
218 in_repo_conf = textwrap.dedent(
219 """
220 - project:
221 name: puppet-tripleo
222 check:
223 jobs:
224 - puppet-something
225 """)
226
227 file_dict = {'.zuul.yaml': in_repo_conf}
228 A = self.fake_gerrit.addFakeChange('puppet-tripleo', 'stable/newton',
229 'A', files=file_dict)
230 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
231 self.waitUntilSettled()
232 self.assertHistory([
233 dict(name='puppet-something', result='SUCCESS', changes='1,1')])
234
235 def test_template_change_on_branch(self):
236 # Test that the contents of a template can be changed on one
237 # branch without affecting another.
238
239 # This creates a new branch with a copy of the config in master
240 self.create_branch('puppet-integration', 'stable/newton')
241 self.create_branch('puppet-integration', 'stable/ocata')
242 self.create_branch('puppet-tripleo', 'stable/newton')
243 self.create_branch('puppet-tripleo', 'stable/ocata')
244 self.fake_gerrit.addEvent(
245 self.fake_gerrit.getFakeBranchCreatedEvent(
246 'puppet-integration', 'stable/newton'))
247 self.fake_gerrit.addEvent(
248 self.fake_gerrit.getFakeBranchCreatedEvent(
249 'puppet-integration', 'stable/ocata'))
250 self.fake_gerrit.addEvent(
251 self.fake_gerrit.getFakeBranchCreatedEvent(
252 'puppet-tripleo', 'stable/newton'))
253 self.fake_gerrit.addEvent(
254 self.fake_gerrit.getFakeBranchCreatedEvent(
255 'puppet-tripleo', 'stable/ocata'))
256 self.waitUntilSettled()
257
258 in_repo_conf = textwrap.dedent("""
259 - job:
260 name: puppet-unit-base
261 run: playbooks/run-unit-tests.yaml
262
263 - job:
264 name: puppet-unit-3.8
265 parent: puppet-unit-base
266 branches: ^(stable/(newton|ocata)).*$
267 vars:
268 puppet_gem_version: 3.8
269
270 - job:
271 name: puppet-something
272 run: playbooks/run-unit-tests.yaml
273
274 - project-template:
275 name: puppet-unit
276 check:
277 jobs:
278 - puppet-something
279
280 - project:
281 name: puppet-integration
282 templates:
283 - puppet-unit
284 """)
285
286 file_dict = {'.zuul.yaml': in_repo_conf}
287 A = self.fake_gerrit.addFakeChange('puppet-integration',
288 'stable/newton',
289 'A', files=file_dict)
290 B = self.fake_gerrit.addFakeChange('puppet-tripleo',
291 'stable/newton',
292 'B')
293 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
294 B.subject, A.data['id'])
295 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
296 self.waitUntilSettled()
297 self.assertHistory([
298 dict(name='puppet-something', result='SUCCESS',
299 changes='1,1 2,1')])
300
301
James E. Blair09998792017-10-15 18:02:18 -0700302class TestBranchVariants(ZuulTestCase):
303 tenant_config_file = 'config/branch-variants/main.yaml'
304
305 def test_branch_variants(self):
306 # Test branch variants of jobs with inheritance
307 self.executor_server.hold_jobs_in_build = True
308 # This creates a new branch with a copy of the config in master
309 self.create_branch('puppet-integration', 'stable')
310 self.fake_gerrit.addEvent(
311 self.fake_gerrit.getFakeBranchCreatedEvent(
312 'puppet-integration', 'stable'))
313 self.waitUntilSettled()
314
315 A = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'A')
316 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
317 self.waitUntilSettled()
318
319 self.assertEqual(len(self.builds[0].parameters['pre_playbooks']), 3)
320 self.executor_server.hold_jobs_in_build = False
321 self.executor_server.release()
322 self.waitUntilSettled()
323
James E. Blairc9e77592017-10-24 09:25:23 -0700324 def test_branch_variants_reconfigure(self):
325 # Test branch variants of jobs with inheritance
326 self.executor_server.hold_jobs_in_build = True
327 # This creates a new branch with a copy of the config in master
328 self.create_branch('puppet-integration', 'stable')
329 self.fake_gerrit.addEvent(
330 self.fake_gerrit.getFakeBranchCreatedEvent(
331 'puppet-integration', 'stable'))
332 self.waitUntilSettled()
333
334 with open(os.path.join(FIXTURE_DIR,
335 'config/branch-variants/git/',
336 'puppet-integration/.zuul.yaml')) as f:
337 config = f.read()
338
339 # Push a change that triggers a dynamic reconfiguration
340 file_dict = {'.zuul.yaml': config}
341 A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A',
342 files=file_dict)
343 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
344 self.waitUntilSettled()
345
346 ipath = self.builds[0].parameters['zuul']['_inheritance_path']
347 for i in ipath:
348 self.log.debug("inheritance path %s", i)
349 self.assertEqual(len(ipath), 5)
350 self.executor_server.hold_jobs_in_build = False
351 self.executor_server.release()
352 self.waitUntilSettled()
353
James E. Blairc32a8352017-10-11 16:27:50 -0700354 def test_branch_variants_divergent(self):
355 # Test branches can diverge and become independent
356 self.executor_server.hold_jobs_in_build = True
357 # This creates a new branch with a copy of the config in master
358 self.create_branch('puppet-integration', 'stable')
359 self.fake_gerrit.addEvent(
360 self.fake_gerrit.getFakeBranchCreatedEvent(
361 'puppet-integration', 'stable'))
362 self.waitUntilSettled()
363
364 with open(os.path.join(FIXTURE_DIR,
365 'config/branch-variants/git/',
366 'puppet-integration/stable.zuul.yaml')) as f:
367 config = f.read()
368
369 file_dict = {'.zuul.yaml': config}
370 C = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'C',
371 files=file_dict)
372 C.addApproval('Code-Review', 2)
373 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
374 self.waitUntilSettled()
375 self.fake_gerrit.addEvent(C.getChangeMergedEvent())
376 self.waitUntilSettled()
377
378 A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A')
379 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
380 self.waitUntilSettled()
381 B = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'B')
382 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
383 self.waitUntilSettled()
384
385 self.assertEqual(self.builds[0].parameters['zuul']['jobtags'],
386 ['master'])
387
388 self.assertEqual(self.builds[1].parameters['zuul']['jobtags'],
389 ['stable'])
390
391 self.executor_server.hold_jobs_in_build = False
392 self.executor_server.release()
393 self.waitUntilSettled()
394
James E. Blair09998792017-10-15 18:02:18 -0700395
James E. Blair2a664502017-10-27 11:39:33 -0700396class TestCentralJobs(ZuulTestCase):
397 tenant_config_file = 'config/central-jobs/main.yaml'
398
399 def setUp(self):
400 super(TestCentralJobs, self).setUp()
401 self.create_branch('org/project', 'stable')
402 self.fake_gerrit.addEvent(
403 self.fake_gerrit.getFakeBranchCreatedEvent(
404 'org/project', 'stable'))
405 self.waitUntilSettled()
406
407 def _updateConfig(self, config, branch):
408 file_dict = {'.zuul.yaml': config}
409 C = self.fake_gerrit.addFakeChange('org/project', branch, 'C',
410 files=file_dict)
411 C.addApproval('Code-Review', 2)
412 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
413 self.waitUntilSettled()
414 self.fake_gerrit.addEvent(C.getChangeMergedEvent())
415 self.waitUntilSettled()
416
417 def _test_central_job_on_branch(self, branch, other_branch):
418 # Test that a job defined on a branchless repo only runs on
419 # the branch applied
420 config = textwrap.dedent(
421 """
422 - project:
423 name: org/project
424 check:
425 jobs:
426 - central-job
427 """)
428 self._updateConfig(config, branch)
429
430 A = self.fake_gerrit.addFakeChange('org/project', branch, 'A')
431 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
432 self.waitUntilSettled()
433
434 self.assertHistory([
435 dict(name='central-job', result='SUCCESS', changes='2,1')])
436
437 # No jobs should run for this change.
438 B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B')
439 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
440 self.waitUntilSettled()
441
442 self.assertHistory([
443 dict(name='central-job', result='SUCCESS', changes='2,1')])
444
445 def test_central_job_on_stable(self):
446 self._test_central_job_on_branch('master', 'stable')
447
448 def test_central_job_on_master(self):
449 self._test_central_job_on_branch('stable', 'master')
450
451 def _test_central_template_on_branch(self, branch, other_branch):
452 # Test that a project-template defined on a branchless repo
453 # only runs on the branch applied
454 config = textwrap.dedent(
455 """
456 - project:
457 name: org/project
458 templates: ['central-jobs']
459 """)
460 self._updateConfig(config, branch)
461
462 A = self.fake_gerrit.addFakeChange('org/project', branch, 'A')
463 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
464 self.waitUntilSettled()
465
466 self.assertHistory([
467 dict(name='central-job', result='SUCCESS', changes='2,1')])
468
469 # No jobs should run for this change.
470 B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B')
471 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
472 self.waitUntilSettled()
473
474 self.assertHistory([
475 dict(name='central-job', result='SUCCESS', changes='2,1')])
476
477 def test_central_template_on_stable(self):
478 self._test_central_template_on_branch('master', 'stable')
479
480 def test_central_template_on_master(self):
481 self._test_central_template_on_branch('stable', 'master')
482
483
James E. Blairff555742017-02-19 11:34:27 -0800484class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -0800485 # A temporary class to hold new tests while others are disabled
486
Tobias Henkelabf973e2017-07-28 10:07:34 +0200487 config_file = 'zuul-connections-gerrit-and-github.conf'
James E. Blair2a629ec2015-12-22 15:32:02 -0800488 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -0800489
James E. Blair83005782015-12-11 14:46:03 -0800490 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -0800491 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200492 A.addApproval('Code-Review', 2)
493 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -0800494 self.waitUntilSettled()
495 self.assertEqual(self.getJobFromHistory('project-test1').result,
496 'SUCCESS')
497 self.assertEqual(A.data['status'], 'MERGED')
498 self.assertEqual(A.reported, 2,
499 "A should report start and success")
500 self.assertIn('tenant-one-gate', A.messages[1],
501 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -0800502
James E. Blair3a098dd2017-10-04 14:37:29 -0700503 @skip("This test is useful, but not reliable")
504 def test_full_and_dynamic_reconfig(self):
505 self.executor_server.hold_jobs_in_build = True
506 in_repo_conf = textwrap.dedent(
507 """
508 - job:
509 name: project-test1
510
511 - project:
512 name: org/project
513 tenant-one-gate:
514 jobs:
515 - project-test1
516 """)
517
518 file_dict = {'.zuul.yaml': in_repo_conf}
519 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
520 files=file_dict)
521 A.addApproval('Code-Review', 2)
522 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
523 self.waitUntilSettled()
524 self.sched.reconfigure(self.config)
525 self.waitUntilSettled()
526
527 gc.collect()
528 pipelines = [obj for obj in gc.get_objects()
529 if isinstance(obj, zuul.model.Pipeline)]
530 self.assertEqual(len(pipelines), 4)
531
532 self.executor_server.hold_jobs_in_build = False
533 self.executor_server.release()
534 self.waitUntilSettled()
535
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700536 def test_dynamic_config(self):
537 in_repo_conf = textwrap.dedent(
538 """
539 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200540 name: project-test1
541
542 - job:
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700543 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700544 run: playbooks/project-test2.yaml
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700545
546 - project:
547 name: org/project
548 tenant-one-gate:
549 jobs:
550 - project-test2
551 """)
552
James E. Blairc73c73a2017-01-20 15:15:15 -0800553 in_repo_playbook = textwrap.dedent(
554 """
555 - hosts: all
556 tasks: []
557 """)
558
559 file_dict = {'.zuul.yaml': in_repo_conf,
560 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700561 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800562 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200563 A.addApproval('Code-Review', 2)
564 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700565 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700566 self.assertEqual(A.data['status'], 'MERGED')
567 self.assertEqual(A.reported, 2,
568 "A should report start and success")
569 self.assertIn('tenant-one-gate', A.messages[1],
570 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800571 self.assertHistory([
572 dict(name='project-test2', result='SUCCESS', changes='1,1')])
573
James E. Blairc2a5ed72017-02-20 14:12:01 -0500574 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800575 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500576
James E. Blair646322f2017-01-27 15:50:34 -0800577 # Now that the config change is landed, it should be live for
578 # subsequent changes.
579 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200580 B.addApproval('Code-Review', 2)
581 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair646322f2017-01-27 15:50:34 -0800582 self.waitUntilSettled()
583 self.assertEqual(self.getJobFromHistory('project-test2').result,
584 'SUCCESS')
585 self.assertHistory([
586 dict(name='project-test2', result='SUCCESS', changes='1,1'),
587 dict(name='project-test2', result='SUCCESS', changes='2,1')])
James E. Blairc73c73a2017-01-20 15:15:15 -0800588
James E. Blair6bc10482017-10-20 11:28:53 -0700589 def test_dynamic_template(self):
James E. Blair2a664502017-10-27 11:39:33 -0700590 # Tests that a project can't update a template in another
591 # project.
James E. Blair6bc10482017-10-20 11:28:53 -0700592 in_repo_conf = textwrap.dedent(
593 """
594 - job:
595 name: project-test1
596
597 - project-template:
598 name: common-config-template
599 check:
600 jobs:
601 - project-test1
602
603 - project:
604 name: org/project
605 templates: [common-config-template]
606 """)
607
608 file_dict = {'.zuul.yaml': in_repo_conf}
609 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
610 files=file_dict)
611 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
612 self.waitUntilSettled()
James E. Blair2a664502017-10-27 11:39:33 -0700613
614 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
615 self.assertIn('Project template common-config-template '
616 'is already defined',
617 A.messages[0],
618 "A should have failed the check pipeline")
James E. Blair6bc10482017-10-20 11:28:53 -0700619
Tobias Henkelf02cf512017-07-21 22:55:34 +0200620 def test_dynamic_config_non_existing_job(self):
621 """Test that requesting a non existent job fails"""
622 in_repo_conf = textwrap.dedent(
623 """
624 - job:
625 name: project-test1
626
627 - project:
628 name: org/project
629 check:
630 jobs:
631 - non-existent-job
632 """)
633
634 in_repo_playbook = textwrap.dedent(
635 """
636 - hosts: all
637 tasks: []
638 """)
639
640 file_dict = {'.zuul.yaml': in_repo_conf,
641 'playbooks/project-test2.yaml': in_repo_playbook}
642 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
643 files=file_dict)
644 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
645 self.waitUntilSettled()
646 self.assertEqual(A.reported, 1,
647 "A should report failure")
648 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
649 self.assertIn('Job non-existent-job not defined', A.messages[0],
650 "A should have failed the check pipeline")
651 self.assertHistory([])
652
653 def test_dynamic_config_non_existing_job_in_template(self):
654 """Test that requesting a non existent job fails"""
655 in_repo_conf = textwrap.dedent(
656 """
657 - job:
658 name: project-test1
659
660 - project-template:
661 name: test-template
662 check:
663 jobs:
664 - non-existent-job
665
666 - project:
667 name: org/project
668 templates:
669 - test-template
670 """)
671
672 in_repo_playbook = textwrap.dedent(
673 """
674 - hosts: all
675 tasks: []
676 """)
677
678 file_dict = {'.zuul.yaml': in_repo_conf,
679 'playbooks/project-test2.yaml': in_repo_playbook}
680 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
681 files=file_dict)
682 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
683 self.waitUntilSettled()
684 self.assertEqual(A.reported, 1,
685 "A should report failure")
686 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
687 self.assertIn('Job non-existent-job not defined', A.messages[0],
688 "A should have failed the check pipeline")
689 self.assertHistory([])
690
Tobias Henkel0f714002017-06-30 23:30:52 +0200691 def test_dynamic_config_new_patchset(self):
692 self.executor_server.hold_jobs_in_build = True
693
694 tenant = self.sched.abide.tenants.get('tenant-one')
695 check_pipeline = tenant.layout.pipelines['check']
696
697 in_repo_conf = textwrap.dedent(
698 """
699 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200700 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -0700701 run: playbooks/project-test1.yaml
Tobias Henkelf02cf512017-07-21 22:55:34 +0200702
703 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200704 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700705 run: playbooks/project-test2.yaml
Tobias Henkel0f714002017-06-30 23:30:52 +0200706
707 - project:
708 name: org/project
709 check:
710 jobs:
711 - project-test2
712 """)
713
714 in_repo_playbook = textwrap.dedent(
715 """
716 - hosts: all
717 tasks: []
718 """)
719
720 file_dict = {'.zuul.yaml': in_repo_conf,
721 'playbooks/project-test2.yaml': in_repo_playbook}
722 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
723 files=file_dict)
724 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
725 self.waitUntilSettled()
726
727 items = check_pipeline.getAllItems()
728 self.assertEqual(items[0].change.number, '1')
729 self.assertEqual(items[0].change.patchset, '1')
730 self.assertTrue(items[0].live)
731
732 in_repo_conf = textwrap.dedent(
733 """
734 - job:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200735 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -0700736 run: playbooks/project-test1.yaml
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200737
738 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200739 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700740 run: playbooks/project-test2.yaml
Tobias Henkel0f714002017-06-30 23:30:52 +0200741
742 - project:
743 name: org/project
744 check:
745 jobs:
746 - project-test1
747 - project-test2
748 """)
749 file_dict = {'.zuul.yaml': in_repo_conf,
750 'playbooks/project-test2.yaml': in_repo_playbook}
751
752 A.addPatchset(files=file_dict)
753 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
754
755 self.waitUntilSettled()
756
757 items = check_pipeline.getAllItems()
758 self.assertEqual(items[0].change.number, '1')
759 self.assertEqual(items[0].change.patchset, '2')
760 self.assertTrue(items[0].live)
761
762 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200763 self.executor_server.release('project-test1')
764 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +0200765 self.executor_server.release()
766 self.waitUntilSettled()
767
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200768 self.assertHistory([
769 dict(name='project-test2', result='ABORTED', changes='1,1'),
770 dict(name='project-test1', result='SUCCESS', changes='1,2'),
771 dict(name='project-test2', result='SUCCESS', changes='1,2')])
772
James E. Blairff555742017-02-19 11:34:27 -0800773 def test_in_repo_branch(self):
774 in_repo_conf = textwrap.dedent(
775 """
776 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200777 name: project-test1
778
779 - job:
James E. Blairff555742017-02-19 11:34:27 -0800780 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700781 run: playbooks/project-test2.yaml
James E. Blairff555742017-02-19 11:34:27 -0800782
783 - project:
784 name: org/project
785 tenant-one-gate:
786 jobs:
787 - project-test2
788 """)
789
790 in_repo_playbook = textwrap.dedent(
791 """
792 - hosts: all
793 tasks: []
794 """)
795
796 file_dict = {'.zuul.yaml': in_repo_conf,
797 'playbooks/project-test2.yaml': in_repo_playbook}
798 self.create_branch('org/project', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700799 self.fake_gerrit.addEvent(
800 self.fake_gerrit.getFakeBranchCreatedEvent(
801 'org/project', 'stable'))
James E. Blair6069f2b2017-09-26 16:34:11 -0700802 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800803 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
804 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200805 A.addApproval('Code-Review', 2)
806 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800807 self.waitUntilSettled()
808 self.assertEqual(A.data['status'], 'MERGED')
809 self.assertEqual(A.reported, 2,
810 "A should report start and success")
811 self.assertIn('tenant-one-gate', A.messages[1],
812 "A should transit tenant-one gate")
813 self.assertHistory([
814 dict(name='project-test2', result='SUCCESS', changes='1,1')])
815 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800816 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800817
818 # The config change should not affect master.
819 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200820 B.addApproval('Code-Review', 2)
821 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800822 self.waitUntilSettled()
823 self.assertHistory([
824 dict(name='project-test2', result='SUCCESS', changes='1,1'),
825 dict(name='project-test1', result='SUCCESS', changes='2,1')])
826
827 # The config change should be live for further changes on
828 # stable.
829 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200830 C.addApproval('Code-Review', 2)
831 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800832 self.waitUntilSettled()
833 self.assertHistory([
834 dict(name='project-test2', result='SUCCESS', changes='1,1'),
835 dict(name='project-test1', result='SUCCESS', changes='2,1'),
836 dict(name='project-test2', result='SUCCESS', changes='3,1')])
837
James E. Blaira5a12492017-05-03 11:40:48 -0700838 def test_crd_dynamic_config_branch(self):
839 # Test that we can create a job in one repo and be able to use
840 # it from a different branch on a different repo.
841
842 self.create_branch('org/project1', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700843 self.fake_gerrit.addEvent(
844 self.fake_gerrit.getFakeBranchCreatedEvent(
845 'org/project1', 'stable'))
James E. Blaira5a12492017-05-03 11:40:48 -0700846
847 in_repo_conf = textwrap.dedent(
848 """
849 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200850 name: project-test1
851
852 - job:
James E. Blaira5a12492017-05-03 11:40:48 -0700853 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700854 run: playbooks/project-test2.yaml
James E. Blaira5a12492017-05-03 11:40:48 -0700855
856 - project:
857 name: org/project
858 check:
859 jobs:
860 - project-test2
861 """)
862
863 in_repo_playbook = textwrap.dedent(
864 """
865 - hosts: all
866 tasks: []
867 """)
868
869 file_dict = {'.zuul.yaml': in_repo_conf,
870 'playbooks/project-test2.yaml': in_repo_playbook}
871 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
872 files=file_dict)
873
874 second_repo_conf = textwrap.dedent(
875 """
876 - project:
877 name: org/project1
878 check:
879 jobs:
880 - project-test2
881 """)
882
883 second_file_dict = {'.zuul.yaml': second_repo_conf}
884 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
885 files=second_file_dict)
886 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
887 B.subject, A.data['id'])
888
889 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
890 self.waitUntilSettled()
891 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
892 self.waitUntilSettled()
893
894 self.assertEqual(A.reported, 1, "A should report")
895 self.assertHistory([
896 dict(name='project-test2', result='SUCCESS', changes='1,1'),
897 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
898 ])
899
James E. Blair97043882017-09-06 15:51:17 -0700900 def test_yaml_list_error(self):
901 in_repo_conf = textwrap.dedent(
902 """
903 job: foo
904 """)
905
906 file_dict = {'.zuul.yaml': in_repo_conf}
907 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
908 files=file_dict)
909 A.addApproval('Code-Review', 2)
910 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
911 self.waitUntilSettled()
912
913 self.assertEqual(A.data['status'], 'NEW')
914 self.assertEqual(A.reported, 1,
915 "A should report failure")
916 self.assertIn('not a list', A.messages[0],
917 "A should have a syntax error reported")
918
919 def test_yaml_dict_error(self):
920 in_repo_conf = textwrap.dedent(
921 """
922 - job
923 """)
924
925 file_dict = {'.zuul.yaml': in_repo_conf}
926 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
927 files=file_dict)
928 A.addApproval('Code-Review', 2)
929 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
930 self.waitUntilSettled()
931
932 self.assertEqual(A.data['status'], 'NEW')
933 self.assertEqual(A.reported, 1,
934 "A should report failure")
935 self.assertIn('not a dictionary', A.messages[0],
936 "A should have a syntax error reported")
937
James E. Blairec953e12017-12-11 11:56:18 -0800938 def test_yaml_duplicate_key_error(self):
939 in_repo_conf = textwrap.dedent(
940 """
941 - job:
942 name: foo
943 name: bar
944 """)
945
946 file_dict = {'.zuul.yaml': in_repo_conf}
947 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
948 files=file_dict)
949 A.addApproval('Code-Review', 2)
950 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
951 self.waitUntilSettled()
952
953 self.assertEqual(A.data['status'], 'NEW')
954 self.assertEqual(A.reported, 1,
955 "A should report failure")
956 self.assertIn('appears more than once', A.messages[0],
957 "A should have a syntax error reported")
958
James E. Blair97043882017-09-06 15:51:17 -0700959 def test_yaml_key_error(self):
960 in_repo_conf = textwrap.dedent(
961 """
962 - job:
963 name: project-test2
964 """)
965
966 file_dict = {'.zuul.yaml': in_repo_conf}
967 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
968 files=file_dict)
969 A.addApproval('Code-Review', 2)
970 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
971 self.waitUntilSettled()
972
973 self.assertEqual(A.data['status'], 'NEW')
974 self.assertEqual(A.reported, 1,
975 "A should report failure")
976 self.assertIn('has more than one key', A.messages[0],
977 "A should have a syntax error reported")
978
979 def test_yaml_unknown_error(self):
980 in_repo_conf = textwrap.dedent(
981 """
982 - foobar:
983 foo: bar
984 """)
985
986 file_dict = {'.zuul.yaml': in_repo_conf}
987 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
988 files=file_dict)
989 A.addApproval('Code-Review', 2)
990 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
991 self.waitUntilSettled()
992
993 self.assertEqual(A.data['status'], 'NEW')
994 self.assertEqual(A.reported, 1,
995 "A should report failure")
996 self.assertIn('not recognized', A.messages[0],
997 "A should have a syntax error reported")
998
James E. Blair149b69c2017-03-02 10:48:16 -0800999 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -08001000 in_repo_conf = textwrap.dedent(
1001 """
1002 - job:
1003 name: project-test2
1004 foo: error
1005 """)
1006
1007 file_dict = {'.zuul.yaml': in_repo_conf}
1008 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1009 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001010 A.addApproval('Code-Review', 2)
1011 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -08001012 self.waitUntilSettled()
1013
1014 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001015 self.assertEqual(A.reported, 1,
1016 "A should report failure")
1017 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -08001018 "A should have a syntax error reported")
1019
James E. Blair149b69c2017-03-02 10:48:16 -08001020 def test_trusted_syntax_error(self):
1021 in_repo_conf = textwrap.dedent(
1022 """
1023 - job:
1024 name: project-test2
1025 foo: error
1026 """)
1027
1028 file_dict = {'zuul.yaml': in_repo_conf}
1029 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1030 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001031 A.addApproval('Code-Review', 2)
1032 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -08001033 self.waitUntilSettled()
1034
1035 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001036 self.assertEqual(A.reported, 1,
1037 "A should report failure")
1038 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -08001039 "A should have a syntax error reported")
1040
James E. Blair6f140c72017-03-03 10:32:07 -08001041 def test_untrusted_yaml_error(self):
1042 in_repo_conf = textwrap.dedent(
1043 """
1044 - job:
1045 foo: error
1046 """)
1047
1048 file_dict = {'.zuul.yaml': in_repo_conf}
1049 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1050 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001051 A.addApproval('Code-Review', 2)
1052 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -08001053 self.waitUntilSettled()
1054
1055 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001056 self.assertEqual(A.reported, 1,
1057 "A should report failure")
1058 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -08001059 "A should have a syntax error reported")
1060
James E. Blairdb04e6a2017-05-03 14:49:36 -07001061 def test_untrusted_shadow_error(self):
1062 in_repo_conf = textwrap.dedent(
1063 """
1064 - job:
1065 name: common-config-test
1066 """)
1067
1068 file_dict = {'.zuul.yaml': in_repo_conf}
1069 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1070 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001071 A.addApproval('Code-Review', 2)
1072 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -07001073 self.waitUntilSettled()
1074
1075 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001076 self.assertEqual(A.reported, 1,
1077 "A should report failure")
1078 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -07001079 "A should have a syntax error reported")
1080
James E. Blaird5656ad2017-06-02 14:29:41 -07001081 def test_untrusted_pipeline_error(self):
1082 in_repo_conf = textwrap.dedent(
1083 """
1084 - pipeline:
1085 name: test
1086 """)
1087
1088 file_dict = {'.zuul.yaml': in_repo_conf}
1089 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1090 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001091 A.addApproval('Code-Review', 2)
1092 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -07001093 self.waitUntilSettled()
1094
1095 self.assertEqual(A.data['status'], 'NEW')
1096 self.assertEqual(A.reported, 1,
1097 "A should report failure")
1098 self.assertIn('Pipelines may not be defined', A.messages[0],
1099 "A should have a syntax error reported")
1100
1101 def test_untrusted_project_error(self):
1102 in_repo_conf = textwrap.dedent(
1103 """
1104 - project:
1105 name: org/project1
1106 """)
1107
1108 file_dict = {'.zuul.yaml': in_repo_conf}
1109 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1110 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001111 A.addApproval('Code-Review', 2)
1112 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -07001113 self.waitUntilSettled()
1114
1115 self.assertEqual(A.data['status'], 'NEW')
1116 self.assertEqual(A.reported, 1,
1117 "A should report failure")
1118 self.assertIn('the only project definition permitted', A.messages[0],
1119 "A should have a syntax error reported")
1120
James E. Blairf03173b2017-10-10 10:46:43 -07001121 def test_untrusted_depends_on_trusted(self):
1122 with open(os.path.join(FIXTURE_DIR,
1123 'config/in-repo/git/',
1124 'common-config/zuul.yaml')) as f:
1125 common_config = f.read()
1126
1127 common_config += textwrap.dedent(
1128 """
1129 - job:
1130 name: project-test9
1131 """)
1132
1133 file_dict = {'zuul.yaml': common_config}
1134 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1135 files=file_dict)
1136 in_repo_conf = textwrap.dedent(
1137 """
1138 - job:
1139 name: project-test1
1140 - project:
1141 name: org/project
1142 check:
1143 jobs:
1144 - project-test9
1145 """)
1146
1147 file_dict = {'zuul.yaml': in_repo_conf}
1148 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1149 files=file_dict)
1150 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1151 B.subject, A.data['id'])
1152 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1153 self.waitUntilSettled()
1154
1155 self.assertEqual(B.data['status'], 'NEW')
1156 self.assertEqual(B.reported, 1,
1157 "B should report failure")
1158 self.assertIn('depends on a change to a config project',
1159 B.messages[0],
1160 "A should have a syntax error reported")
1161
James E. Blaire64b0e42017-06-08 11:23:34 -07001162 def test_duplicate_node_error(self):
1163 in_repo_conf = textwrap.dedent(
1164 """
1165 - nodeset:
1166 name: duplicate
1167 nodes:
1168 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001169 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001170 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001171 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001172 """)
1173
1174 file_dict = {'.zuul.yaml': in_repo_conf}
1175 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1176 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001177 A.addApproval('Code-Review', 2)
1178 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -07001179 self.waitUntilSettled()
1180
1181 self.assertEqual(A.data['status'], 'NEW')
1182 self.assertEqual(A.reported, 1,
1183 "A should report failure")
1184 self.assertIn('appears multiple times', A.messages[0],
1185 "A should have a syntax error reported")
1186
1187 def test_duplicate_group_error(self):
1188 in_repo_conf = textwrap.dedent(
1189 """
1190 - nodeset:
1191 name: duplicate
1192 nodes:
1193 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001194 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001195 groups:
1196 - name: group
1197 nodes: compute
1198 - name: group
1199 nodes: compute
1200 """)
1201
1202 file_dict = {'.zuul.yaml': in_repo_conf}
1203 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1204 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001205 A.addApproval('Code-Review', 2)
1206 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -07001207 self.waitUntilSettled()
1208
1209 self.assertEqual(A.data['status'], 'NEW')
1210 self.assertEqual(A.reported, 1,
1211 "A should report failure")
1212 self.assertIn('appears multiple times', A.messages[0],
1213 "A should have a syntax error reported")
1214
James E. Blair4ae399f2017-09-20 17:15:09 -07001215 def test_secret_not_found_error(self):
1216 in_repo_conf = textwrap.dedent(
1217 """
1218 - job:
1219 name: test
1220 secrets: does-not-exist
1221 """)
1222
1223 file_dict = {'.zuul.yaml': in_repo_conf}
1224 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1225 files=file_dict)
1226 A.addApproval('Code-Review', 2)
1227 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1228 self.waitUntilSettled()
1229
1230 self.assertEqual(A.data['status'], 'NEW')
1231 self.assertEqual(A.reported, 1,
1232 "A should report failure")
1233 self.assertIn('secret "does-not-exist" was not found', A.messages[0],
1234 "A should have a syntax error reported")
1235
1236 def test_nodeset_not_found_error(self):
1237 in_repo_conf = textwrap.dedent(
1238 """
1239 - job:
1240 name: test
1241 nodeset: does-not-exist
1242 """)
1243
1244 file_dict = {'.zuul.yaml': in_repo_conf}
1245 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1246 files=file_dict)
1247 A.addApproval('Code-Review', 2)
1248 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1249 self.waitUntilSettled()
1250
1251 self.assertEqual(A.data['status'], 'NEW')
1252 self.assertEqual(A.reported, 1,
1253 "A should report failure")
1254 self.assertIn('nodeset "does-not-exist" was not found', A.messages[0],
1255 "A should have a syntax error reported")
1256
James E. Blair89e25eb2017-09-26 09:11:31 -07001257 def test_template_not_found_error(self):
1258 in_repo_conf = textwrap.dedent(
1259 """
1260 - job:
1261 name: project-test1
1262 - project:
1263 name: org/project
1264 templates:
1265 - does-not-exist
1266 """)
1267
1268 file_dict = {'.zuul.yaml': in_repo_conf}
1269 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1270 files=file_dict)
1271 A.addApproval('Code-Review', 2)
1272 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1273 self.waitUntilSettled()
1274
1275 self.assertEqual(A.data['status'], 'NEW')
1276 self.assertEqual(A.reported, 1,
1277 "A should report failure")
1278 self.assertIn('project template "does-not-exist" was not found',
1279 A.messages[0],
1280 "A should have a syntax error reported")
1281
Monty Taylor8be3c0c2017-10-06 10:37:37 -05001282 def test_job_list_in_project_template_not_dict_error(self):
1283 in_repo_conf = textwrap.dedent(
1284 """
1285 - job:
1286 name: project-test1
1287 - project-template:
1288 name: some-jobs
1289 check:
1290 jobs:
1291 - project-test1:
1292 - required-projects:
1293 org/project2
1294 """)
1295
1296 file_dict = {'.zuul.yaml': in_repo_conf}
1297 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1298 files=file_dict)
1299 A.addApproval('Code-Review', 2)
1300 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1301 self.waitUntilSettled()
1302
1303 self.assertEqual(A.data['status'], 'NEW')
1304 self.assertEqual(A.reported, 1,
1305 "A should report failure")
1306 self.assertIn('expected str for dictionary value',
1307 A.messages[0], "A should have a syntax error reported")
1308
1309 def test_job_list_in_project_not_dict_error(self):
1310 in_repo_conf = textwrap.dedent(
1311 """
1312 - job:
1313 name: project-test1
1314 - project:
1315 name: org/project1
1316 check:
1317 jobs:
1318 - project-test1:
1319 - required-projects:
1320 org/project2
1321 """)
1322
1323 file_dict = {'.zuul.yaml': in_repo_conf}
1324 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1325 files=file_dict)
1326 A.addApproval('Code-Review', 2)
1327 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1328 self.waitUntilSettled()
1329
1330 self.assertEqual(A.data['status'], 'NEW')
1331 self.assertEqual(A.reported, 1,
1332 "A should report failure")
1333 self.assertIn('expected str for dictionary value',
1334 A.messages[0], "A should have a syntax error reported")
1335
James E. Blair1235f142017-10-07 09:11:43 -07001336 def test_project_template(self):
1337 # Tests that a project template is not modified when used, and
1338 # can therefore be used in subsequent reconfigurations.
1339 in_repo_conf = textwrap.dedent(
1340 """
1341 - job:
1342 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001343 run: playbooks/project-test1.yaml
James E. Blair1235f142017-10-07 09:11:43 -07001344 - project-template:
1345 name: some-jobs
1346 tenant-one-gate:
1347 jobs:
1348 - project-test1:
1349 required-projects:
1350 - org/project1
1351 - project:
1352 name: org/project
1353 templates:
1354 - some-jobs
1355 """)
1356
1357 file_dict = {'.zuul.yaml': in_repo_conf}
1358 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1359 files=file_dict)
1360 A.addApproval('Code-Review', 2)
1361 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1362 self.waitUntilSettled()
1363 self.assertEqual(A.data['status'], 'MERGED')
1364 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1365 self.waitUntilSettled()
1366 in_repo_conf = textwrap.dedent(
1367 """
1368 - project:
1369 name: org/project1
1370 templates:
1371 - some-jobs
1372 """)
1373 file_dict = {'.zuul.yaml': in_repo_conf}
1374 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
1375 files=file_dict)
1376 B.addApproval('Code-Review', 2)
1377 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1378 self.waitUntilSettled()
1379 self.assertEqual(B.data['status'], 'MERGED')
1380
James E. Blairbccdfcf2017-10-07 13:37:26 -07001381 def test_job_remove_add(self):
1382 # Tests that a job can be removed from one repo and added in another.
1383 # First, remove the current config for project1 since it
1384 # references the job we want to remove.
1385 file_dict = {'.zuul.yaml': None}
1386 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1387 files=file_dict)
1388 A.setMerged()
1389 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1390 self.waitUntilSettled()
1391 # Then propose a change to delete the job from one repo...
1392 file_dict = {'.zuul.yaml': None}
1393 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1394 files=file_dict)
1395 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1396 self.waitUntilSettled()
1397 # ...and a second that depends on it that adds it to another repo.
1398 in_repo_conf = textwrap.dedent(
1399 """
1400 - job:
1401 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001402 run: playbooks/project-test1.yaml
James E. Blairbccdfcf2017-10-07 13:37:26 -07001403
1404 - project:
1405 name: org/project1
1406 check:
1407 jobs:
1408 - project-test1
1409 """)
1410 in_repo_playbook = textwrap.dedent(
1411 """
1412 - hosts: all
1413 tasks: []
1414 """)
1415 file_dict = {'.zuul.yaml': in_repo_conf,
1416 'playbooks/project-test1.yaml': in_repo_playbook}
1417 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C',
1418 files=file_dict,
1419 parent='refs/changes/1/1/1')
1420 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1421 C.subject, B.data['id'])
1422 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1423 self.waitUntilSettled()
1424 self.assertHistory([
1425 dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'),
1426 ], ordered=False)
1427
James E. Blair09f9ffe2017-07-11 15:30:25 -07001428 def test_multi_repo(self):
1429 downstream_repo_conf = textwrap.dedent(
1430 """
1431 - project:
1432 name: org/project1
1433 tenant-one-gate:
1434 jobs:
1435 - project-test1
1436
1437 - job:
1438 name: project1-test1
1439 parent: project-test1
1440 """)
1441
1442 file_dict = {'.zuul.yaml': downstream_repo_conf}
1443 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1444 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001445 A.addApproval('Code-Review', 2)
1446 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001447 self.waitUntilSettled()
1448
1449 self.assertEqual(A.data['status'], 'MERGED')
1450 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1451 self.waitUntilSettled()
1452
1453 upstream_repo_conf = textwrap.dedent(
1454 """
1455 - job:
1456 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001457 run: playbooks/project-test1.yaml
James E. Blair09f9ffe2017-07-11 15:30:25 -07001458
1459 - job:
1460 name: project-test2
1461
1462 - project:
1463 name: org/project
1464 tenant-one-gate:
1465 jobs:
1466 - project-test1
1467 """)
1468
1469 file_dict = {'.zuul.yaml': upstream_repo_conf}
1470 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1471 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001472 B.addApproval('Code-Review', 2)
1473 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001474 self.waitUntilSettled()
1475
1476 self.assertEqual(B.data['status'], 'MERGED')
1477 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
1478 self.waitUntilSettled()
1479
1480 tenant = self.sched.abide.tenants.get('tenant-one')
1481 # Ensure the latest change is reflected in the config; if it
1482 # isn't this will raise an exception.
1483 tenant.layout.getJob('project-test2')
1484
James E. Blair332636e2017-09-05 10:14:35 -07001485 def test_pipeline_error(self):
1486 with open(os.path.join(FIXTURE_DIR,
1487 'config/in-repo/git/',
1488 'common-config/zuul.yaml')) as f:
1489 base_common_config = f.read()
1490
1491 in_repo_conf_A = textwrap.dedent(
1492 """
1493 - pipeline:
1494 name: periodic
1495 foo: error
1496 """)
1497
1498 file_dict = {'zuul.yaml': None,
1499 'zuul.d/main.yaml': base_common_config,
1500 'zuul.d/test1.yaml': in_repo_conf_A}
1501 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1502 files=file_dict)
1503 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1504 self.waitUntilSettled()
1505 self.assertEqual(A.reported, 1,
1506 "A should report failure")
1507 self.assertIn('syntax error',
1508 A.messages[0],
1509 "A should have an error reported")
1510
1511 def test_change_series_error(self):
1512 with open(os.path.join(FIXTURE_DIR,
1513 'config/in-repo/git/',
1514 'common-config/zuul.yaml')) as f:
1515 base_common_config = f.read()
1516
1517 in_repo_conf_A = textwrap.dedent(
1518 """
1519 - pipeline:
1520 name: periodic
1521 foo: error
1522 """)
1523
1524 file_dict = {'zuul.yaml': None,
1525 'zuul.d/main.yaml': base_common_config,
1526 'zuul.d/test1.yaml': in_repo_conf_A}
1527 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1528 files=file_dict)
1529
1530 in_repo_conf_B = textwrap.dedent(
1531 """
1532 - job:
1533 name: project-test2
1534 foo: error
1535 """)
1536
1537 file_dict = {'zuul.yaml': None,
1538 'zuul.d/main.yaml': base_common_config,
1539 'zuul.d/test1.yaml': in_repo_conf_A,
1540 'zuul.d/test2.yaml': in_repo_conf_B}
1541 B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B',
1542 files=file_dict)
1543 B.setDependsOn(A, 1)
1544 C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C')
1545 C.setDependsOn(B, 1)
1546 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1547 self.waitUntilSettled()
1548
1549 self.assertEqual(C.reported, 1,
1550 "C should report failure")
1551 self.assertIn('depends on a change that failed to merge',
1552 C.messages[0],
1553 "C should have an error reported")
1554
James E. Blairc73c73a2017-01-20 15:15:15 -08001555
James E. Blairc9455002017-09-06 09:22:19 -07001556class TestInRepoJoin(ZuulTestCase):
1557 # In this config, org/project is not a member of any pipelines, so
1558 # that we may test the changes that cause it to join them.
1559
1560 tenant_config_file = 'config/in-repo-join/main.yaml'
1561
1562 def test_dynamic_dependent_pipeline(self):
1563 # Test dynamically adding a project to a
1564 # dependent pipeline for the first time
1565 self.executor_server.hold_jobs_in_build = True
1566
1567 tenant = self.sched.abide.tenants.get('tenant-one')
1568 gate_pipeline = tenant.layout.pipelines['gate']
1569
1570 in_repo_conf = textwrap.dedent(
1571 """
1572 - job:
1573 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001574 run: playbooks/project-test1.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001575
1576 - job:
1577 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -07001578 run: playbooks/project-test2.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001579
1580 - project:
1581 name: org/project
1582 gate:
1583 jobs:
1584 - project-test2
1585 """)
1586
1587 in_repo_playbook = textwrap.dedent(
1588 """
1589 - hosts: all
1590 tasks: []
1591 """)
1592
1593 file_dict = {'.zuul.yaml': in_repo_conf,
1594 'playbooks/project-test2.yaml': in_repo_playbook}
1595 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1596 files=file_dict)
1597 A.addApproval('Code-Review', 2)
1598 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1599 self.waitUntilSettled()
1600
1601 items = gate_pipeline.getAllItems()
1602 self.assertEqual(items[0].change.number, '1')
1603 self.assertEqual(items[0].change.patchset, '1')
1604 self.assertTrue(items[0].live)
1605
1606 self.executor_server.hold_jobs_in_build = False
1607 self.executor_server.release()
1608 self.waitUntilSettled()
1609
1610 # Make sure the dynamic queue got cleaned up
1611 self.assertEqual(gate_pipeline.queues, [])
1612
1613 def test_dynamic_dependent_pipeline_failure(self):
1614 # Test that a change behind a failing change adding a project
1615 # to a dependent pipeline is dequeued.
1616 self.executor_server.hold_jobs_in_build = True
1617
1618 in_repo_conf = textwrap.dedent(
1619 """
1620 - job:
1621 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001622 run: playbooks/project-test1.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001623
1624 - project:
1625 name: org/project
1626 gate:
1627 jobs:
1628 - project-test1
1629 """)
1630
1631 file_dict = {'.zuul.yaml': in_repo_conf}
1632 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1633 files=file_dict)
1634 self.executor_server.failJob('project-test1', A)
1635 A.addApproval('Code-Review', 2)
1636 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1637 self.waitUntilSettled()
1638
1639 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1640 B.addApproval('Code-Review', 2)
1641 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1642 self.waitUntilSettled()
1643
James E. Blair3490c5d2017-09-07 08:33:23 -07001644 self.orderedRelease()
James E. Blairc9455002017-09-06 09:22:19 -07001645 self.waitUntilSettled()
1646 self.assertEqual(A.reported, 2,
1647 "A should report start and failure")
1648 self.assertEqual(A.data['status'], 'NEW')
1649 self.assertEqual(B.reported, 1,
1650 "B should report start")
1651 self.assertHistory([
1652 dict(name='project-test1', result='FAILURE', changes='1,1'),
James E. Blair3490c5d2017-09-07 08:33:23 -07001653 dict(name='project-test1', result='ABORTED', changes='1,1 2,1'),
James E. Blairc9455002017-09-06 09:22:19 -07001654 ], ordered=False)
1655
James E. Blair0af198f2017-09-06 09:52:35 -07001656 def test_dynamic_dependent_pipeline_absent(self):
1657 # Test that a series of dependent changes don't report merge
1658 # failures to a pipeline they aren't in.
1659 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1660 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1661 B.setDependsOn(A, 1)
1662
1663 A.addApproval('Code-Review', 2)
1664 A.addApproval('Approved', 1)
1665 B.addApproval('Code-Review', 2)
1666 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1667 self.waitUntilSettled()
1668 self.assertEqual(A.reported, 0,
1669 "A should not report")
1670 self.assertEqual(A.data['status'], 'NEW')
1671 self.assertEqual(B.reported, 0,
1672 "B should not report")
1673 self.assertEqual(B.data['status'], 'NEW')
1674 self.assertHistory([])
1675
James E. Blairc9455002017-09-06 09:22:19 -07001676
James E. Blairc73c73a2017-01-20 15:15:15 -08001677class TestAnsible(AnsibleZuulTestCase):
1678 # A temporary class to hold new tests while others are disabled
1679
1680 tenant_config_file = 'config/ansible/main.yaml'
1681
1682 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +11001683 # Keep the jobdir around so we can inspect contents if an
1684 # assert fails.
1685 self.executor_server.keep_jobdir = True
1686 # Output extra ansible info so we might see errors.
1687 self.executor_server.verbose = True
1688 # Add a site variables file, used by check-vars
1689 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
1690 'variables.yaml')
1691 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -08001692 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1693 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1694 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +02001695 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +11001696 with self.jobLog(build_timeout):
1697 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001698 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +11001699 with self.jobLog(build_faillocal):
1700 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001701 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +11001702 with self.jobLog(build_failpost):
1703 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001704 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +11001705 with self.jobLog(build_check_vars):
1706 self.assertEqual(build_check_vars.result, 'SUCCESS')
Monty Tayloraff8b402017-08-16 18:40:41 -05001707 build_check_secret_names = self.getJobFromHistory('check-secret-names')
1708 with self.jobLog(build_check_secret_names):
1709 self.assertEqual(build_check_secret_names.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001710 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +11001711 with self.jobLog(build_hello):
1712 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001713 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +11001714 with self.jobLog(build_python27):
1715 self.assertEqual(build_python27.result, 'SUCCESS')
1716 flag_path = os.path.join(self.test_root,
1717 build_python27.uuid + '.flag')
1718 self.assertTrue(os.path.exists(flag_path))
1719 copied_path = os.path.join(self.test_root, build_python27.uuid +
1720 '.copied')
1721 self.assertTrue(os.path.exists(copied_path))
1722 failed_path = os.path.join(self.test_root, build_python27.uuid +
1723 '.failed')
1724 self.assertFalse(os.path.exists(failed_path))
1725 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
1726 '.pre.flag')
1727 self.assertTrue(os.path.exists(pre_flag_path))
1728 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
1729 '.post.flag')
1730 self.assertTrue(os.path.exists(post_flag_path))
1731 bare_role_flag_path = os.path.join(self.test_root,
1732 build_python27.uuid +
1733 '.bare-role.flag')
1734 self.assertTrue(os.path.exists(bare_role_flag_path))
1735 secrets_path = os.path.join(self.test_root,
1736 build_python27.uuid + '.secrets')
1737 with open(secrets_path) as f:
1738 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -08001739
Jamie Lennox7655b552017-03-17 12:33:38 +11001740 msg = A.messages[0]
1741 success = "{} https://success.example.com/zuul-logs/{}"
1742 fail = "{} https://failure.example.com/zuul-logs/{}"
1743 self.assertIn(success.format("python27", build_python27.uuid), msg)
1744 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
1745 self.assertIn(success.format("check-vars",
1746 build_check_vars.uuid), msg)
1747 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
1748 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
1749 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +02001750
James E. Blairabbaa6f2017-04-06 16:11:44 -07001751 def _add_job(self, job_name):
1752 conf = textwrap.dedent(
1753 """
1754 - job:
1755 name: %s
James E. Blair2f589fe2017-10-26 12:57:41 -07001756 run: playbooks/%s.yaml
James E. Blairabbaa6f2017-04-06 16:11:44 -07001757
1758 - project:
1759 name: org/plugin-project
1760 check:
1761 jobs:
1762 - %s
James E. Blair2f589fe2017-10-26 12:57:41 -07001763 """ % (job_name, job_name, job_name))
James E. Blairabbaa6f2017-04-06 16:11:44 -07001764
1765 file_dict = {'.zuul.yaml': conf}
1766 A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A',
1767 files=file_dict)
1768 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1769 self.waitUntilSettled()
1770
1771 def test_plugins(self):
1772 # Keep the jobdir around so we can inspect contents if an
1773 # assert fails.
1774 self.executor_server.keep_jobdir = True
1775 # Output extra ansible info so we might see errors.
1776 self.executor_server.verbose = True
1777
1778 count = 0
1779 plugin_tests = [
1780 ('passwd', 'FAILURE'),
1781 ('cartesian', 'SUCCESS'),
1782 ('consul_kv', 'FAILURE'),
1783 ('credstash', 'FAILURE'),
1784 ('csvfile_good', 'SUCCESS'),
1785 ('csvfile_bad', 'FAILURE'),
Monty Taylor93ad2212017-08-02 14:59:50 -05001786 ('uri_bad_path', 'FAILURE'),
1787 ('uri_bad_scheme', 'FAILURE'),
Monty Taylor788a40e2017-08-02 16:14:05 -05001788 ('block_local_override', 'FAILURE'),
Monty Taylor8da768f2017-08-31 14:15:35 -05001789 ('file_local_good', 'SUCCESS'),
1790 ('file_local_bad', 'FAILURE'),
James E. Blairabbaa6f2017-04-06 16:11:44 -07001791 ]
1792 for job_name, result in plugin_tests:
1793 count += 1
1794 self._add_job(job_name)
1795
1796 job = self.getJobFromHistory(job_name)
1797 with self.jobLog(job):
1798 self.assertEqual(count, len(self.history))
1799 build = self.history[-1]
1800 self.assertEqual(build.result, result)
1801
1802 # TODOv3(jeblair): parse the ansible output and verify we're
1803 # getting the exception we expect.
1804
James E. Blairb9c0d772017-03-03 14:34:49 -08001805
James E. Blaira4d4eef2017-06-30 14:49:17 -07001806class TestPrePlaybooks(AnsibleZuulTestCase):
1807 # A temporary class to hold new tests while others are disabled
1808
1809 tenant_config_file = 'config/pre-playbook/main.yaml'
1810
1811 def test_pre_playbook_fail(self):
1812 # Test that we run the post playbooks (but not the actual
1813 # playbook) when a pre-playbook fails.
1814 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1815 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1816 self.waitUntilSettled()
1817 build = self.getJobFromHistory('python27')
1818 self.assertIsNone(build.result)
1819 self.assertIn('RETRY_LIMIT', A.messages[0])
1820 flag_path = os.path.join(self.test_root, build.uuid +
1821 '.main.flag')
1822 self.assertFalse(os.path.exists(flag_path))
1823 pre_flag_path = os.path.join(self.test_root, build.uuid +
1824 '.pre.flag')
1825 self.assertFalse(os.path.exists(pre_flag_path))
1826 post_flag_path = os.path.join(self.test_root, build.uuid +
1827 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -07001828 self.assertTrue(os.path.exists(post_flag_path),
1829 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -07001830
1831
James E. Blairbacbb882017-10-17 09:48:23 -07001832class TestPostPlaybooks(AnsibleZuulTestCase):
1833 tenant_config_file = 'config/post-playbook/main.yaml'
1834
1835 def test_post_playbook_abort(self):
1836 # Test that when we abort a job in the post playbook, that we
1837 # don't send back POST_FAILURE.
1838 self.executor_server.verbose = True
1839 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1840 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1841
1842 while not len(self.builds):
1843 time.sleep(0.1)
1844 build = self.builds[0]
1845
1846 post_start = os.path.join(self.test_root, build.uuid +
1847 '.post_start.flag')
1848 start = time.time()
1849 while time.time() < start + 90:
1850 if os.path.exists(post_start):
1851 break
1852 time.sleep(0.1)
1853 # The post playbook has started, abort the job
1854 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1855 self.waitUntilSettled()
1856
1857 build = self.getJobFromHistory('python27')
1858 self.assertEqual('ABORTED', build.result)
1859
1860 post_end = os.path.join(self.test_root, build.uuid +
1861 '.post_end.flag')
1862 self.assertTrue(os.path.exists(post_start))
1863 self.assertFalse(os.path.exists(post_end))
1864
1865
James E. Blairb9c0d772017-03-03 14:34:49 -08001866class TestBrokenConfig(ZuulTestCase):
1867 # Test that we get an appropriate syntax error if we start with a
1868 # broken config.
1869
1870 tenant_config_file = 'config/broken/main.yaml'
1871
1872 def setUp(self):
1873 with testtools.ExpectedException(
1874 zuul.configloader.ConfigurationSyntaxError,
1875 "\nZuul encountered a syntax error"):
1876 super(TestBrokenConfig, self).setUp()
1877
1878 def test_broken_config_on_startup(self):
1879 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001880
1881
1882class TestProjectKeys(ZuulTestCase):
1883 # Test that we can generate project keys
1884
1885 # Normally the test infrastructure copies a static key in place
1886 # for each project before starting tests. This saves time because
1887 # Zuul's automatic key-generation on startup can be slow. To make
1888 # sure we exercise that code, in this test we allow Zuul to create
1889 # keys for the project on startup.
1890 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +02001891 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001892 tenant_config_file = 'config/in-repo/main.yaml'
1893
1894 def test_key_generation(self):
1895 key_root = os.path.join(self.state_root, 'keys')
1896 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
1897 # Make sure that a proper key was created on startup
1898 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -07001899 private_key, public_key = \
1900 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001901
1902 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
1903 fixture_private_key = i.read()
1904
1905 # Make sure that we didn't just end up with the static fixture
1906 # key
1907 self.assertNotEqual(fixture_private_key, private_key)
1908
1909 # Make sure it's the right length
1910 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -07001911
1912
James E. Blairbb94dfa2017-07-11 07:45:19 -07001913class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -07001914 def _assertRolePath(self, build, playbook, content):
1915 path = os.path.join(self.test_root, build.uuid,
1916 'ansible', playbook, 'ansible.cfg')
1917 roles_paths = []
1918 with open(path) as f:
1919 for line in f:
1920 if line.startswith('roles_path'):
1921 roles_paths.append(line)
1922 print(roles_paths)
1923 if content:
1924 self.assertEqual(len(roles_paths), 1,
1925 "Should have one roles_path line in %s" %
1926 (playbook,))
1927 self.assertIn(content, roles_paths[0])
1928 else:
1929 self.assertEqual(len(roles_paths), 0,
1930 "Should have no roles_path line in %s" %
1931 (playbook,))
1932
James E. Blairbb94dfa2017-07-11 07:45:19 -07001933
1934class TestRoles(RoleTestCase):
1935 tenant_config_file = 'config/roles/main.yaml'
1936
James E. Blairbce76932017-05-04 10:03:15 -07001937 def test_role(self):
1938 # This exercises a proposed change to a role being checked out
1939 # and used.
1940 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
1941 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1942 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1943 B.subject, A.data['id'])
1944 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1945 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1946 self.waitUntilSettled()
1947 self.assertHistory([
1948 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
1949 ])
James E. Blair6459db12017-06-29 14:57:20 -07001950
James E. Blair1b27f6a2017-07-14 14:09:07 -07001951 def test_role_inheritance(self):
1952 self.executor_server.hold_jobs_in_build = True
1953 conf = textwrap.dedent(
1954 """
1955 - job:
1956 name: parent
1957 roles:
1958 - zuul: bare-role
Ian Wienand548c43c2017-12-05 14:16:32 +11001959 pre-run: playbooks/parent-pre.yaml
1960 post-run: playbooks/parent-post.yaml
James E. Blair1b27f6a2017-07-14 14:09:07 -07001961
1962 - job:
1963 name: project-test
1964 parent: parent
James E. Blair2f589fe2017-10-26 12:57:41 -07001965 run: playbooks/project-test.yaml
James E. Blair1b27f6a2017-07-14 14:09:07 -07001966 roles:
1967 - zuul: org/project
1968
1969 - project:
1970 name: org/project
1971 check:
1972 jobs:
1973 - project-test
1974 """)
1975
1976 file_dict = {'.zuul.yaml': conf}
1977 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1978 files=file_dict)
1979 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1980 self.waitUntilSettled()
1981
1982 self.assertEqual(len(self.builds), 1)
1983 build = self.getBuildByName('project-test')
1984 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
1985 self._assertRolePath(build, 'playbook_0', 'role_0')
1986 self._assertRolePath(build, 'playbook_0', 'role_1')
1987 self._assertRolePath(build, 'post_playbook_0', 'role_0')
1988
1989 self.executor_server.hold_jobs_in_build = False
1990 self.executor_server.release()
1991 self.waitUntilSettled()
1992
1993 self.assertHistory([
1994 dict(name='project-test', result='SUCCESS', changes='1,1'),
1995 ])
1996
James E. Blair6f699732017-07-18 14:19:11 -07001997 def test_role_error(self):
1998 conf = textwrap.dedent(
1999 """
2000 - job:
2001 name: project-test
James E. Blair2f589fe2017-10-26 12:57:41 -07002002 run: playbooks/project-test.yaml
James E. Blair6f699732017-07-18 14:19:11 -07002003 roles:
2004 - zuul: common-config
2005
2006 - project:
2007 name: org/project
2008 check:
2009 jobs:
2010 - project-test
2011 """)
2012
2013 file_dict = {'.zuul.yaml': conf}
2014 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2015 files=file_dict)
2016 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2017 self.waitUntilSettled()
2018 self.assertIn(
2019 '- project-test project-test : ERROR Unable to find role',
2020 A.messages[-1])
2021
James E. Blair6459db12017-06-29 14:57:20 -07002022
James E. Blairbb94dfa2017-07-11 07:45:19 -07002023class TestImplicitRoles(RoleTestCase):
2024 tenant_config_file = 'config/implicit-roles/main.yaml'
2025
2026 def test_missing_roles(self):
2027 # Test implicit and explicit roles for a project which does
2028 # not have roles. The implicit role should be silently
2029 # ignored since the project doesn't supply roles, but if a
2030 # user declares an explicit role, it should error.
2031 self.executor_server.hold_jobs_in_build = True
2032 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
2033 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2034 self.waitUntilSettled()
2035
2036 self.assertEqual(len(self.builds), 2)
2037 build = self.getBuildByName('implicit-role-fail')
2038 self._assertRolePath(build, 'playbook_0', None)
2039
2040 self.executor_server.hold_jobs_in_build = False
2041 self.executor_server.release()
2042 self.waitUntilSettled()
2043 # The retry_limit doesn't get recorded
2044 self.assertHistory([
2045 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
2046 ])
2047
2048 def test_roles(self):
2049 # Test implicit and explicit roles for a project which does
2050 # have roles. In both cases, we should end up with the role
2051 # in the path. In the explicit case, ensure we end up with
2052 # the name we specified.
2053 self.executor_server.hold_jobs_in_build = True
2054 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
2055 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2056 self.waitUntilSettled()
2057
2058 self.assertEqual(len(self.builds), 2)
2059 build = self.getBuildByName('implicit-role-ok')
2060 self._assertRolePath(build, 'playbook_0', 'role_0')
2061
2062 build = self.getBuildByName('explicit-role-ok')
2063 self._assertRolePath(build, 'playbook_0', 'role_0')
2064
2065 self.executor_server.hold_jobs_in_build = False
2066 self.executor_server.release()
2067 self.waitUntilSettled()
2068 self.assertHistory([
2069 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
2070 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
2071 ], ordered=False)
2072
2073
James E. Blair6459db12017-06-29 14:57:20 -07002074class TestShadow(ZuulTestCase):
2075 tenant_config_file = 'config/shadow/main.yaml'
2076
2077 def test_shadow(self):
2078 # Test that a repo is allowed to shadow another's job definitions.
2079 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2080 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2081 self.waitUntilSettled()
2082 self.assertHistory([
2083 dict(name='test1', result='SUCCESS', changes='1,1'),
2084 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -07002085 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -07002086
2087
2088class TestDataReturn(AnsibleZuulTestCase):
2089 tenant_config_file = 'config/data-return/main.yaml'
2090
2091 def test_data_return(self):
James E. Blair196f61a2017-06-30 15:42:29 -07002092 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2093 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2094 self.waitUntilSettled()
2095 self.assertHistory([
2096 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07002097 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
James E. Blair698703c2017-09-15 20:58:30 -06002098 dict(name='child', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07002099 ], ordered=False)
2100 self.assertIn('- data-return http://example.com/test/log/url/',
2101 A.messages[-1])
2102 self.assertIn('- data-return-relative '
2103 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -07002104 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -07002105
2106
2107class TestDiskAccounting(AnsibleZuulTestCase):
2108 config_file = 'zuul-disk-accounting.conf'
2109 tenant_config_file = 'config/disk-accountant/main.yaml'
2110
2111 def test_disk_accountant_kills_job(self):
2112 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2113 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2114 self.waitUntilSettled()
2115 self.assertHistory([
2116 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002117
2118
2119class TestMaxNodesPerJob(AnsibleZuulTestCase):
2120 tenant_config_file = 'config/multi-tenant/main.yaml'
2121
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00002122 def test_max_timeout_exceeded(self):
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002123 in_repo_conf = textwrap.dedent(
2124 """
2125 - job:
2126 name: test-job
James E. Blair7e3e6882017-09-20 15:47:13 -07002127 nodeset:
2128 nodes:
2129 - name: node01
2130 label: fake
2131 - name: node02
2132 label: fake
2133 - name: node03
2134 label: fake
2135 - name: node04
2136 label: fake
2137 - name: node05
2138 label: fake
2139 - name: node06
2140 label: fake
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002141 """)
2142 file_dict = {'.zuul.yaml': in_repo_conf}
2143 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2144 files=file_dict)
2145 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2146 self.waitUntilSettled()
2147 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
2148 A.messages[0], "A should fail because of nodes limit")
2149
2150 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2151 files=file_dict)
2152 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2153 self.waitUntilSettled()
2154 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
2155 "B should not fail because of nodes limit")
James E. Blair2bab6e72017-08-07 09:52:45 -07002156
2157
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00002158class TestMaxTimeout(AnsibleZuulTestCase):
2159 tenant_config_file = 'config/multi-tenant/main.yaml'
2160
2161 def test_max_nodes_reached(self):
2162 in_repo_conf = textwrap.dedent(
2163 """
2164 - job:
2165 name: test-job
2166 timeout: 3600
2167 """)
2168 file_dict = {'.zuul.yaml': in_repo_conf}
2169 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2170 files=file_dict)
2171 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2172 self.waitUntilSettled()
2173 self.assertIn('The job "test-job" exceeds tenant max-job-timeout',
2174 A.messages[0], "A should fail because of timeout limit")
2175
2176 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2177 files=file_dict)
2178 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2179 self.waitUntilSettled()
2180 self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0],
2181 "B should not fail because of timeout limit")
2182
2183
James E. Blair7edc25f2017-10-26 10:47:14 -07002184class TestPragma(ZuulTestCase):
2185 tenant_config_file = 'config/pragma/main.yaml'
2186
2187 def test_no_pragma(self):
2188 self.create_branch('org/project', 'stable')
2189 with open(os.path.join(FIXTURE_DIR,
2190 'config/pragma/git/',
2191 'org_project/nopragma.yaml')) as f:
2192 config = f.read()
2193 file_dict = {'.zuul.yaml': config}
2194 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2195 files=file_dict)
2196 A.addApproval('Code-Review', 2)
2197 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2198 self.waitUntilSettled()
2199 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2200 self.waitUntilSettled()
2201
2202 # This is an untrusted repo with 2 branches, so it should have
2203 # an implied branch matcher for the job.
2204 tenant = self.sched.abide.tenants.get('tenant-one')
2205 jobs = tenant.layout.getJobs('test-job')
2206 self.assertEqual(len(jobs), 1)
2207 for job in tenant.layout.getJobs('test-job'):
2208 self.assertIsNotNone(job.branch_matcher)
2209
2210 def test_pragma(self):
2211 self.create_branch('org/project', 'stable')
2212 with open(os.path.join(FIXTURE_DIR,
2213 'config/pragma/git/',
2214 'org_project/pragma.yaml')) as f:
2215 config = f.read()
2216 file_dict = {'.zuul.yaml': config}
2217 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2218 files=file_dict)
2219 A.addApproval('Code-Review', 2)
2220 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2221 self.waitUntilSettled()
2222 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2223 self.waitUntilSettled()
2224
2225 # This is an untrusted repo with 2 branches, so it would
2226 # normally have an implied branch matcher, but our pragma
2227 # overrides it.
2228 tenant = self.sched.abide.tenants.get('tenant-one')
2229 jobs = tenant.layout.getJobs('test-job')
2230 self.assertEqual(len(jobs), 1)
2231 for job in tenant.layout.getJobs('test-job'):
2232 self.assertIsNone(job.branch_matcher)
2233
2234
James E. Blair37c3d8c2017-12-13 15:06:11 -08002235class TestPragmaMultibranch(ZuulTestCase):
2236 tenant_config_file = 'config/pragma-multibranch/main.yaml'
2237
2238 def test_no_branch_matchers(self):
2239 self.create_branch('org/project1', 'stable/pike')
2240 self.create_branch('org/project2', 'stable/jewel')
2241 self.fake_gerrit.addEvent(
2242 self.fake_gerrit.getFakeBranchCreatedEvent(
2243 'org/project1', 'stable/pike'))
2244 self.fake_gerrit.addEvent(
2245 self.fake_gerrit.getFakeBranchCreatedEvent(
2246 'org/project2', 'stable/jewel'))
2247 self.waitUntilSettled()
2248 # We want the jobs defined on the stable/pike branch of
2249 # project1 to apply to the stable/jewel branch of project2.
2250
2251 # First, without the pragma line, the jobs should not run
2252 # because in project1 they have branch matchers for pike, so
2253 # they will not match a jewel change.
2254 B = self.fake_gerrit.addFakeChange('org/project2', 'stable/jewel', 'B')
2255 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2256 self.waitUntilSettled()
2257 self.assertHistory([])
2258
2259 # Add a pragma line to disable implied branch matchers in
2260 # project1, so that the jobs and templates apply to both
2261 # branches.
2262 with open(os.path.join(FIXTURE_DIR,
2263 'config/pragma-multibranch/git/',
2264 'org_project1/zuul.yaml')) as f:
2265 config = f.read()
2266 extra_conf = textwrap.dedent(
2267 """
2268 - pragma:
2269 implied-branch-matchers: False
2270 """)
2271 config = extra_conf + config
2272 file_dict = {'zuul.yaml': config}
2273 A = self.fake_gerrit.addFakeChange('org/project1', 'stable/pike', 'A',
2274 files=file_dict)
2275 A.addApproval('Code-Review', 2)
2276 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2277 self.waitUntilSettled()
2278 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2279 self.waitUntilSettled()
2280
2281 # Now verify that when we propose a change to jewel, we get
2282 # the pike/jewel jobs.
2283 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2284 self.waitUntilSettled()
2285 self.assertHistory([
2286 dict(name='test-job1', result='SUCCESS', changes='1,1'),
2287 dict(name='test-job2', result='SUCCESS', changes='1,1'),
2288 ], ordered=False)
2289
2290 def test_supplied_branch_matchers(self):
2291 self.create_branch('org/project1', 'stable/pike')
2292 self.create_branch('org/project2', 'stable/jewel')
2293 self.fake_gerrit.addEvent(
2294 self.fake_gerrit.getFakeBranchCreatedEvent(
2295 'org/project1', 'stable/pike'))
2296 self.fake_gerrit.addEvent(
2297 self.fake_gerrit.getFakeBranchCreatedEvent(
2298 'org/project2', 'stable/jewel'))
2299 self.waitUntilSettled()
2300 # We want the jobs defined on the stable/pike branch of
2301 # project1 to apply to the stable/jewel branch of project2.
2302
2303 # First, without the pragma line, the jobs should not run
2304 # because in project1 they have branch matchers for pike, so
2305 # they will not match a jewel change.
2306 B = self.fake_gerrit.addFakeChange('org/project2', 'stable/jewel', 'B')
2307 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2308 self.waitUntilSettled()
2309 self.assertHistory([])
2310
2311 # Add a pragma line to disable implied branch matchers in
2312 # project1, so that the jobs and templates apply to both
2313 # branches.
2314 with open(os.path.join(FIXTURE_DIR,
2315 'config/pragma-multibranch/git/',
2316 'org_project1/zuul.yaml')) as f:
2317 config = f.read()
2318 extra_conf = textwrap.dedent(
2319 """
2320 - pragma:
2321 implied-branches:
2322 - stable/pike
2323 - stable/jewel
2324 """)
2325 config = extra_conf + config
2326 file_dict = {'zuul.yaml': config}
2327 A = self.fake_gerrit.addFakeChange('org/project1', 'stable/pike', 'A',
2328 files=file_dict)
2329 A.addApproval('Code-Review', 2)
2330 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2331 self.waitUntilSettled()
2332 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2333 self.waitUntilSettled()
2334 # Now verify that when we propose a change to jewel, we get
2335 # the pike/jewel jobs.
2336 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2337 self.waitUntilSettled()
2338 self.assertHistory([
2339 dict(name='test-job1', result='SUCCESS', changes='1,1'),
2340 dict(name='test-job2', result='SUCCESS', changes='1,1'),
2341 ], ordered=False)
2342
2343
James E. Blair2bab6e72017-08-07 09:52:45 -07002344class TestBaseJobs(ZuulTestCase):
2345 tenant_config_file = 'config/base-jobs/main.yaml'
2346
2347 def test_multiple_base_jobs(self):
2348 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2349 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2350 self.waitUntilSettled()
2351 self.assertHistory([
2352 dict(name='my-job', result='SUCCESS', changes='1,1'),
2353 dict(name='other-job', result='SUCCESS', changes='1,1'),
2354 ], ordered=False)
2355 self.assertEqual(self.getJobFromHistory('my-job').
2356 parameters['zuul']['jobtags'],
2357 ['mybase'])
2358 self.assertEqual(self.getJobFromHistory('other-job').
2359 parameters['zuul']['jobtags'],
2360 ['otherbase'])
2361
2362 def test_untrusted_base_job(self):
2363 """Test that a base job may not be defined in an untrusted repo"""
2364 in_repo_conf = textwrap.dedent(
2365 """
2366 - job:
2367 name: fail-base
2368 parent: null
2369 """)
2370
2371 file_dict = {'.zuul.yaml': in_repo_conf}
2372 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2373 files=file_dict)
2374 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2375 self.waitUntilSettled()
2376 self.assertEqual(A.reported, 1,
2377 "A should report failure")
2378 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
2379 self.assertIn('Base jobs must be defined in config projects',
2380 A.messages[0])
2381 self.assertHistory([])
James E. Blairdb089032017-08-15 13:42:12 -07002382
2383
James E. Blairdf91ab32017-10-25 17:57:13 -07002384class TestSecretInheritance(ZuulTestCase):
2385 tenant_config_file = 'config/secret-inheritance/main.yaml'
2386
2387 def _getSecrets(self, job, pbtype):
2388 secrets = []
2389 build = self.getJobFromHistory(job)
2390 for pb in build.parameters[pbtype]:
2391 secrets.append(pb['secrets'])
2392 return secrets
2393
2394 def _checkTrustedSecrets(self):
2395 secret = {'longpassword': 'test-passwordtest-password',
2396 'password': 'test-password',
2397 'username': 'test-username'}
2398 self.assertEqual(
2399 self._getSecrets('trusted-secrets', 'playbooks'),
James E. Blair2f589fe2017-10-26 12:57:41 -07002400 [{'trusted-secret': secret}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002401 self.assertEqual(
2402 self._getSecrets('trusted-secrets', 'pre_playbooks'), [])
2403 self.assertEqual(
2404 self._getSecrets('trusted-secrets', 'post_playbooks'), [])
2405
2406 self.assertEqual(
2407 self._getSecrets('trusted-secrets-trusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002408 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002409 self.assertEqual(
2410 self._getSecrets('trusted-secrets-trusted-child',
2411 'pre_playbooks'), [])
2412 self.assertEqual(
2413 self._getSecrets('trusted-secrets-trusted-child',
2414 'post_playbooks'), [])
2415
2416 self.assertEqual(
2417 self._getSecrets('trusted-secrets-untrusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002418 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002419 self.assertEqual(
2420 self._getSecrets('trusted-secrets-untrusted-child',
2421 'pre_playbooks'), [])
2422 self.assertEqual(
2423 self._getSecrets('trusted-secrets-untrusted-child',
2424 'post_playbooks'), [])
2425
2426 def _checkUntrustedSecrets(self):
2427 secret = {'longpassword': 'test-passwordtest-password',
2428 'password': 'test-password',
2429 'username': 'test-username'}
2430 self.assertEqual(
2431 self._getSecrets('untrusted-secrets', 'playbooks'),
James E. Blair2f589fe2017-10-26 12:57:41 -07002432 [{'untrusted-secret': secret}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002433 self.assertEqual(
2434 self._getSecrets('untrusted-secrets', 'pre_playbooks'), [])
2435 self.assertEqual(
2436 self._getSecrets('untrusted-secrets', 'post_playbooks'), [])
2437
2438 self.assertEqual(
2439 self._getSecrets('untrusted-secrets-trusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002440 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002441 self.assertEqual(
2442 self._getSecrets('untrusted-secrets-trusted-child',
2443 'pre_playbooks'), [])
2444 self.assertEqual(
2445 self._getSecrets('untrusted-secrets-trusted-child',
2446 'post_playbooks'), [])
2447
2448 self.assertEqual(
2449 self._getSecrets('untrusted-secrets-untrusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002450 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002451 self.assertEqual(
2452 self._getSecrets('untrusted-secrets-untrusted-child',
2453 'pre_playbooks'), [])
2454 self.assertEqual(
2455 self._getSecrets('untrusted-secrets-untrusted-child',
2456 'post_playbooks'), [])
2457
2458 def test_trusted_secret_inheritance_check(self):
2459 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
2460 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2461 self.waitUntilSettled()
2462 self.assertHistory([
2463 dict(name='trusted-secrets', result='SUCCESS', changes='1,1'),
2464 dict(name='trusted-secrets-trusted-child',
2465 result='SUCCESS', changes='1,1'),
2466 dict(name='trusted-secrets-untrusted-child',
2467 result='SUCCESS', changes='1,1'),
2468 ], ordered=False)
2469
2470 self._checkTrustedSecrets()
2471
2472 def test_untrusted_secret_inheritance_gate(self):
2473 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
2474 A.addApproval('Code-Review', 2)
2475 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2476 self.waitUntilSettled()
2477 self.assertHistory([
2478 dict(name='untrusted-secrets', result='SUCCESS', changes='1,1'),
2479 dict(name='untrusted-secrets-trusted-child',
2480 result='SUCCESS', changes='1,1'),
2481 dict(name='untrusted-secrets-untrusted-child',
2482 result='SUCCESS', changes='1,1'),
2483 ], ordered=False)
2484
2485 self._checkUntrustedSecrets()
2486
2487 def test_untrusted_secret_inheritance_check(self):
2488 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2489 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2490 self.waitUntilSettled()
2491 # This configuration tries to run untrusted secrets in an
2492 # non-post-review pipeline and should therefore run no jobs.
2493 self.assertHistory([])
2494
2495
James E. Blairdb089032017-08-15 13:42:12 -07002496class TestSecretLeaks(AnsibleZuulTestCase):
2497 tenant_config_file = 'config/secret-leaks/main.yaml'
2498
2499 def searchForContent(self, path, content):
2500 matches = []
2501 for (dirpath, dirnames, filenames) in os.walk(path):
2502 for filename in filenames:
2503 filepath = os.path.join(dirpath, filename)
2504 with open(filepath, 'rb') as f:
2505 if content in f.read():
2506 matches.append(filepath[len(path):])
2507 return matches
2508
2509 def _test_secret_file(self):
2510 # Or rather -- test that they *don't* leak.
2511 # Keep the jobdir around so we can inspect contents.
2512 self.executor_server.keep_jobdir = True
2513 conf = textwrap.dedent(
2514 """
2515 - project:
2516 name: org/project
2517 check:
2518 jobs:
2519 - secret-file
2520 """)
2521
2522 file_dict = {'.zuul.yaml': conf}
2523 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2524 files=file_dict)
2525 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2526 self.waitUntilSettled()
2527 self.assertHistory([
2528 dict(name='secret-file', result='SUCCESS', changes='1,1'),
2529 ], ordered=False)
2530 matches = self.searchForContent(self.history[0].jobdir.root,
2531 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07002532 self.assertEqual(set(['/work/secret-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07002533 set(matches))
2534
2535 def test_secret_file(self):
2536 self._test_secret_file()
2537
2538 def test_secret_file_verbose(self):
2539 # Output extra ansible info to exercise alternate logging code
2540 # paths.
2541 self.executor_server.verbose = True
2542 self._test_secret_file()
2543
2544 def _test_secret_file_fail(self):
2545 # Or rather -- test that they *don't* leak.
2546 # Keep the jobdir around so we can inspect contents.
2547 self.executor_server.keep_jobdir = True
2548 conf = textwrap.dedent(
2549 """
2550 - project:
2551 name: org/project
2552 check:
2553 jobs:
2554 - secret-file-fail
2555 """)
2556
2557 file_dict = {'.zuul.yaml': conf}
2558 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2559 files=file_dict)
2560 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2561 self.waitUntilSettled()
2562 self.assertHistory([
2563 dict(name='secret-file-fail', result='FAILURE', changes='1,1'),
2564 ], ordered=False)
2565 matches = self.searchForContent(self.history[0].jobdir.root,
2566 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07002567 self.assertEqual(set(['/work/failure-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07002568 set(matches))
2569
2570 def test_secret_file_fail(self):
2571 self._test_secret_file_fail()
2572
2573 def test_secret_file_fail_verbose(self):
2574 # Output extra ansible info to exercise alternate logging code
2575 # paths.
2576 self.executor_server.verbose = True
2577 self._test_secret_file_fail()
James E. Blaira00910c2017-08-23 09:15:04 -07002578
2579
2580class TestJobOutput(AnsibleZuulTestCase):
2581 tenant_config_file = 'config/job-output/main.yaml'
2582
2583 def _get_file(self, build, path):
2584 p = os.path.join(build.jobdir.root, path)
2585 with open(p) as f:
2586 return f.read()
2587
2588 def test_job_output(self):
Monty Taylor0e2489a2017-10-10 11:57:29 -05002589 # Verify that command standard output appears in the job output,
2590 # and that failures in the final playbook get logged.
James E. Blaira00910c2017-08-23 09:15:04 -07002591
2592 # This currently only verifies we receive output from
2593 # localhost. Notably, it does not verify we receive output
2594 # via zuul_console streaming.
2595 self.executor_server.keep_jobdir = True
2596 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2597 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2598 self.waitUntilSettled()
2599 self.assertHistory([
2600 dict(name='job-output', result='SUCCESS', changes='1,1'),
2601 ], ordered=False)
2602
2603 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2604 j = json.loads(self._get_file(self.history[0],
2605 'work/logs/job-output.json'))
2606 self.assertEqual(token,
2607 j[0]['plays'][0]['tasks'][0]
2608 ['hosts']['localhost']['stdout'])
2609
2610 print(self._get_file(self.history[0],
2611 'work/logs/job-output.txt'))
2612 self.assertIn(token,
2613 self._get_file(self.history[0],
2614 'work/logs/job-output.txt'))
Monty Taylor0e2489a2017-10-10 11:57:29 -05002615
2616 def test_job_output_failure_log(self):
2617 logger = logging.getLogger('zuul.AnsibleJob')
2618 output = io.StringIO()
2619 logger.addHandler(logging.StreamHandler(output))
2620
2621 # Verify that a failure in the last post playbook emits the contents
2622 # of the json output to the log
2623 self.executor_server.keep_jobdir = True
2624 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
2625 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2626 self.waitUntilSettled()
2627 self.assertHistory([
2628 dict(name='job-output-failure',
2629 result='POST_FAILURE', changes='1,1'),
2630 ], ordered=False)
2631
2632 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2633 j = json.loads(self._get_file(self.history[0],
2634 'work/logs/job-output.json'))
2635 self.assertEqual(token,
2636 j[0]['plays'][0]['tasks'][0]
2637 ['hosts']['localhost']['stdout'])
2638
2639 print(self._get_file(self.history[0],
2640 'work/logs/job-output.json'))
2641 self.assertIn(token,
2642 self._get_file(self.history[0],
2643 'work/logs/job-output.txt'))
2644
2645 log_output = output.getvalue()
2646 self.assertIn('Final playbook failed', log_output)
2647 self.assertIn('Failure test', log_output)