blob: e2da808cbffbad22f86f9aac74e151e472e36e43 [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. Blaire36d1a32017-11-28 13:33:38 -0800160class TestBranchTemplates(ZuulTestCase):
161 tenant_config_file = 'config/branch-templates/main.yaml'
162
163 def test_template_removal_from_branch(self):
164 # Test that a template can be removed from one branch but not
165 # another.
166 # This creates a new branch with a copy of the config in master
167 self.create_branch('puppet-integration', 'stable/newton')
168 self.create_branch('puppet-integration', 'stable/ocata')
169 self.create_branch('puppet-tripleo', 'stable/newton')
170 self.create_branch('puppet-tripleo', 'stable/ocata')
171 self.fake_gerrit.addEvent(
172 self.fake_gerrit.getFakeBranchCreatedEvent(
173 'puppet-integration', 'stable/newton'))
174 self.fake_gerrit.addEvent(
175 self.fake_gerrit.getFakeBranchCreatedEvent(
176 'puppet-integration', 'stable/ocata'))
177 self.fake_gerrit.addEvent(
178 self.fake_gerrit.getFakeBranchCreatedEvent(
179 'puppet-tripleo', 'stable/newton'))
180 self.fake_gerrit.addEvent(
181 self.fake_gerrit.getFakeBranchCreatedEvent(
182 'puppet-tripleo', 'stable/ocata'))
183 self.waitUntilSettled()
184
185 in_repo_conf = textwrap.dedent(
186 """
187 - project:
188 name: puppet-tripleo
189 check:
190 jobs:
191 - puppet-something
192 """)
193
194 file_dict = {'.zuul.yaml': in_repo_conf}
195 A = self.fake_gerrit.addFakeChange('puppet-tripleo', 'stable/newton',
196 'A', files=file_dict)
197 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
198 self.waitUntilSettled()
199 self.assertHistory([
200 dict(name='puppet-something', result='SUCCESS', changes='1,1')])
201
202 def test_template_change_on_branch(self):
203 # Test that the contents of a template can be changed on one
204 # branch without affecting another.
205
206 # This creates a new branch with a copy of the config in master
207 self.create_branch('puppet-integration', 'stable/newton')
208 self.create_branch('puppet-integration', 'stable/ocata')
209 self.create_branch('puppet-tripleo', 'stable/newton')
210 self.create_branch('puppet-tripleo', 'stable/ocata')
211 self.fake_gerrit.addEvent(
212 self.fake_gerrit.getFakeBranchCreatedEvent(
213 'puppet-integration', 'stable/newton'))
214 self.fake_gerrit.addEvent(
215 self.fake_gerrit.getFakeBranchCreatedEvent(
216 'puppet-integration', 'stable/ocata'))
217 self.fake_gerrit.addEvent(
218 self.fake_gerrit.getFakeBranchCreatedEvent(
219 'puppet-tripleo', 'stable/newton'))
220 self.fake_gerrit.addEvent(
221 self.fake_gerrit.getFakeBranchCreatedEvent(
222 'puppet-tripleo', 'stable/ocata'))
223 self.waitUntilSettled()
224
225 in_repo_conf = textwrap.dedent("""
226 - job:
227 name: puppet-unit-base
228 run: playbooks/run-unit-tests.yaml
229
230 - job:
231 name: puppet-unit-3.8
232 parent: puppet-unit-base
233 branches: ^(stable/(newton|ocata)).*$
234 vars:
235 puppet_gem_version: 3.8
236
237 - job:
238 name: puppet-something
239 run: playbooks/run-unit-tests.yaml
240
241 - project-template:
242 name: puppet-unit
243 check:
244 jobs:
245 - puppet-something
246
247 - project:
248 name: puppet-integration
249 templates:
250 - puppet-unit
251 """)
252
253 file_dict = {'.zuul.yaml': in_repo_conf}
254 A = self.fake_gerrit.addFakeChange('puppet-integration',
255 'stable/newton',
256 'A', files=file_dict)
257 B = self.fake_gerrit.addFakeChange('puppet-tripleo',
258 'stable/newton',
259 'B')
260 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
261 B.subject, A.data['id'])
262 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
263 self.waitUntilSettled()
264 self.assertHistory([
265 dict(name='puppet-something', result='SUCCESS',
266 changes='1,1 2,1')])
267
268
James E. Blair09998792017-10-15 18:02:18 -0700269class TestBranchVariants(ZuulTestCase):
270 tenant_config_file = 'config/branch-variants/main.yaml'
271
272 def test_branch_variants(self):
273 # Test branch variants of jobs with inheritance
274 self.executor_server.hold_jobs_in_build = True
275 # This creates a new branch with a copy of the config in master
276 self.create_branch('puppet-integration', 'stable')
277 self.fake_gerrit.addEvent(
278 self.fake_gerrit.getFakeBranchCreatedEvent(
279 'puppet-integration', 'stable'))
280 self.waitUntilSettled()
281
282 A = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'A')
283 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
284 self.waitUntilSettled()
285
286 self.assertEqual(len(self.builds[0].parameters['pre_playbooks']), 3)
287 self.executor_server.hold_jobs_in_build = False
288 self.executor_server.release()
289 self.waitUntilSettled()
290
James E. Blairc9e77592017-10-24 09:25:23 -0700291 def test_branch_variants_reconfigure(self):
292 # Test branch variants of jobs with inheritance
293 self.executor_server.hold_jobs_in_build = True
294 # This creates a new branch with a copy of the config in master
295 self.create_branch('puppet-integration', 'stable')
296 self.fake_gerrit.addEvent(
297 self.fake_gerrit.getFakeBranchCreatedEvent(
298 'puppet-integration', 'stable'))
299 self.waitUntilSettled()
300
301 with open(os.path.join(FIXTURE_DIR,
302 'config/branch-variants/git/',
303 'puppet-integration/.zuul.yaml')) as f:
304 config = f.read()
305
306 # Push a change that triggers a dynamic reconfiguration
307 file_dict = {'.zuul.yaml': config}
308 A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A',
309 files=file_dict)
310 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
311 self.waitUntilSettled()
312
313 ipath = self.builds[0].parameters['zuul']['_inheritance_path']
314 for i in ipath:
315 self.log.debug("inheritance path %s", i)
316 self.assertEqual(len(ipath), 5)
317 self.executor_server.hold_jobs_in_build = False
318 self.executor_server.release()
319 self.waitUntilSettled()
320
James E. Blairc32a8352017-10-11 16:27:50 -0700321 def test_branch_variants_divergent(self):
322 # Test branches can diverge and become independent
323 self.executor_server.hold_jobs_in_build = True
324 # This creates a new branch with a copy of the config in master
325 self.create_branch('puppet-integration', 'stable')
326 self.fake_gerrit.addEvent(
327 self.fake_gerrit.getFakeBranchCreatedEvent(
328 'puppet-integration', 'stable'))
329 self.waitUntilSettled()
330
331 with open(os.path.join(FIXTURE_DIR,
332 'config/branch-variants/git/',
333 'puppet-integration/stable.zuul.yaml')) as f:
334 config = f.read()
335
336 file_dict = {'.zuul.yaml': config}
337 C = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'C',
338 files=file_dict)
339 C.addApproval('Code-Review', 2)
340 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
341 self.waitUntilSettled()
342 self.fake_gerrit.addEvent(C.getChangeMergedEvent())
343 self.waitUntilSettled()
344
345 A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A')
346 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
347 self.waitUntilSettled()
348 B = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'B')
349 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
350 self.waitUntilSettled()
351
352 self.assertEqual(self.builds[0].parameters['zuul']['jobtags'],
353 ['master'])
354
355 self.assertEqual(self.builds[1].parameters['zuul']['jobtags'],
356 ['stable'])
357
358 self.executor_server.hold_jobs_in_build = False
359 self.executor_server.release()
360 self.waitUntilSettled()
361
James E. Blair09998792017-10-15 18:02:18 -0700362
James E. Blair2a664502017-10-27 11:39:33 -0700363class TestCentralJobs(ZuulTestCase):
364 tenant_config_file = 'config/central-jobs/main.yaml'
365
366 def setUp(self):
367 super(TestCentralJobs, self).setUp()
368 self.create_branch('org/project', 'stable')
369 self.fake_gerrit.addEvent(
370 self.fake_gerrit.getFakeBranchCreatedEvent(
371 'org/project', 'stable'))
372 self.waitUntilSettled()
373
374 def _updateConfig(self, config, branch):
375 file_dict = {'.zuul.yaml': config}
376 C = self.fake_gerrit.addFakeChange('org/project', branch, 'C',
377 files=file_dict)
378 C.addApproval('Code-Review', 2)
379 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
380 self.waitUntilSettled()
381 self.fake_gerrit.addEvent(C.getChangeMergedEvent())
382 self.waitUntilSettled()
383
384 def _test_central_job_on_branch(self, branch, other_branch):
385 # Test that a job defined on a branchless repo only runs on
386 # the branch applied
387 config = textwrap.dedent(
388 """
389 - project:
390 name: org/project
391 check:
392 jobs:
393 - central-job
394 """)
395 self._updateConfig(config, branch)
396
397 A = self.fake_gerrit.addFakeChange('org/project', branch, 'A')
398 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
399 self.waitUntilSettled()
400
401 self.assertHistory([
402 dict(name='central-job', result='SUCCESS', changes='2,1')])
403
404 # No jobs should run for this change.
405 B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B')
406 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
407 self.waitUntilSettled()
408
409 self.assertHistory([
410 dict(name='central-job', result='SUCCESS', changes='2,1')])
411
412 def test_central_job_on_stable(self):
413 self._test_central_job_on_branch('master', 'stable')
414
415 def test_central_job_on_master(self):
416 self._test_central_job_on_branch('stable', 'master')
417
418 def _test_central_template_on_branch(self, branch, other_branch):
419 # Test that a project-template defined on a branchless repo
420 # only runs on the branch applied
421 config = textwrap.dedent(
422 """
423 - project:
424 name: org/project
425 templates: ['central-jobs']
426 """)
427 self._updateConfig(config, branch)
428
429 A = self.fake_gerrit.addFakeChange('org/project', branch, 'A')
430 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
431 self.waitUntilSettled()
432
433 self.assertHistory([
434 dict(name='central-job', result='SUCCESS', changes='2,1')])
435
436 # No jobs should run for this change.
437 B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B')
438 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
439 self.waitUntilSettled()
440
441 self.assertHistory([
442 dict(name='central-job', result='SUCCESS', changes='2,1')])
443
444 def test_central_template_on_stable(self):
445 self._test_central_template_on_branch('master', 'stable')
446
447 def test_central_template_on_master(self):
448 self._test_central_template_on_branch('stable', 'master')
449
450
James E. Blairff555742017-02-19 11:34:27 -0800451class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -0800452 # A temporary class to hold new tests while others are disabled
453
Tobias Henkelabf973e2017-07-28 10:07:34 +0200454 config_file = 'zuul-connections-gerrit-and-github.conf'
James E. Blair2a629ec2015-12-22 15:32:02 -0800455 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -0800456
James E. Blair83005782015-12-11 14:46:03 -0800457 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -0800458 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200459 A.addApproval('Code-Review', 2)
460 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -0800461 self.waitUntilSettled()
462 self.assertEqual(self.getJobFromHistory('project-test1').result,
463 'SUCCESS')
464 self.assertEqual(A.data['status'], 'MERGED')
465 self.assertEqual(A.reported, 2,
466 "A should report start and success")
467 self.assertIn('tenant-one-gate', A.messages[1],
468 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -0800469
James E. Blair3a098dd2017-10-04 14:37:29 -0700470 @skip("This test is useful, but not reliable")
471 def test_full_and_dynamic_reconfig(self):
472 self.executor_server.hold_jobs_in_build = True
473 in_repo_conf = textwrap.dedent(
474 """
475 - job:
476 name: project-test1
477
478 - project:
479 name: org/project
480 tenant-one-gate:
481 jobs:
482 - project-test1
483 """)
484
485 file_dict = {'.zuul.yaml': in_repo_conf}
486 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
487 files=file_dict)
488 A.addApproval('Code-Review', 2)
489 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
490 self.waitUntilSettled()
491 self.sched.reconfigure(self.config)
492 self.waitUntilSettled()
493
494 gc.collect()
495 pipelines = [obj for obj in gc.get_objects()
496 if isinstance(obj, zuul.model.Pipeline)]
497 self.assertEqual(len(pipelines), 4)
498
499 self.executor_server.hold_jobs_in_build = False
500 self.executor_server.release()
501 self.waitUntilSettled()
502
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700503 def test_dynamic_config(self):
504 in_repo_conf = textwrap.dedent(
505 """
506 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200507 name: project-test1
508
509 - job:
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700510 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700511 run: playbooks/project-test2.yaml
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700512
513 - project:
514 name: org/project
515 tenant-one-gate:
516 jobs:
517 - project-test2
518 """)
519
James E. Blairc73c73a2017-01-20 15:15:15 -0800520 in_repo_playbook = textwrap.dedent(
521 """
522 - hosts: all
523 tasks: []
524 """)
525
526 file_dict = {'.zuul.yaml': in_repo_conf,
527 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700528 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800529 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200530 A.addApproval('Code-Review', 2)
531 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700532 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700533 self.assertEqual(A.data['status'], 'MERGED')
534 self.assertEqual(A.reported, 2,
535 "A should report start and success")
536 self.assertIn('tenant-one-gate', A.messages[1],
537 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800538 self.assertHistory([
539 dict(name='project-test2', result='SUCCESS', changes='1,1')])
540
James E. Blairc2a5ed72017-02-20 14:12:01 -0500541 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800542 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500543
James E. Blair646322f2017-01-27 15:50:34 -0800544 # Now that the config change is landed, it should be live for
545 # subsequent changes.
546 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200547 B.addApproval('Code-Review', 2)
548 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair646322f2017-01-27 15:50:34 -0800549 self.waitUntilSettled()
550 self.assertEqual(self.getJobFromHistory('project-test2').result,
551 'SUCCESS')
552 self.assertHistory([
553 dict(name='project-test2', result='SUCCESS', changes='1,1'),
554 dict(name='project-test2', result='SUCCESS', changes='2,1')])
James E. Blairc73c73a2017-01-20 15:15:15 -0800555
James E. Blair6bc10482017-10-20 11:28:53 -0700556 def test_dynamic_template(self):
James E. Blair2a664502017-10-27 11:39:33 -0700557 # Tests that a project can't update a template in another
558 # project.
James E. Blair6bc10482017-10-20 11:28:53 -0700559 in_repo_conf = textwrap.dedent(
560 """
561 - job:
562 name: project-test1
563
564 - project-template:
565 name: common-config-template
566 check:
567 jobs:
568 - project-test1
569
570 - project:
571 name: org/project
572 templates: [common-config-template]
573 """)
574
575 file_dict = {'.zuul.yaml': in_repo_conf}
576 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
577 files=file_dict)
578 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
579 self.waitUntilSettled()
James E. Blair2a664502017-10-27 11:39:33 -0700580
581 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
582 self.assertIn('Project template common-config-template '
583 'is already defined',
584 A.messages[0],
585 "A should have failed the check pipeline")
James E. Blair6bc10482017-10-20 11:28:53 -0700586
Tobias Henkelf02cf512017-07-21 22:55:34 +0200587 def test_dynamic_config_non_existing_job(self):
588 """Test that requesting a non existent job fails"""
589 in_repo_conf = textwrap.dedent(
590 """
591 - job:
592 name: project-test1
593
594 - project:
595 name: org/project
596 check:
597 jobs:
598 - non-existent-job
599 """)
600
601 in_repo_playbook = textwrap.dedent(
602 """
603 - hosts: all
604 tasks: []
605 """)
606
607 file_dict = {'.zuul.yaml': in_repo_conf,
608 'playbooks/project-test2.yaml': in_repo_playbook}
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()
613 self.assertEqual(A.reported, 1,
614 "A should report failure")
615 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
616 self.assertIn('Job non-existent-job not defined', A.messages[0],
617 "A should have failed the check pipeline")
618 self.assertHistory([])
619
620 def test_dynamic_config_non_existing_job_in_template(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-template:
628 name: test-template
629 check:
630 jobs:
631 - non-existent-job
632
633 - project:
634 name: org/project
635 templates:
636 - test-template
637 """)
638
639 in_repo_playbook = textwrap.dedent(
640 """
641 - hosts: all
642 tasks: []
643 """)
644
645 file_dict = {'.zuul.yaml': in_repo_conf,
646 'playbooks/project-test2.yaml': in_repo_playbook}
647 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
648 files=file_dict)
649 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
650 self.waitUntilSettled()
651 self.assertEqual(A.reported, 1,
652 "A should report failure")
653 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
654 self.assertIn('Job non-existent-job not defined', A.messages[0],
655 "A should have failed the check pipeline")
656 self.assertHistory([])
657
Tobias Henkel0f714002017-06-30 23:30:52 +0200658 def test_dynamic_config_new_patchset(self):
659 self.executor_server.hold_jobs_in_build = True
660
661 tenant = self.sched.abide.tenants.get('tenant-one')
662 check_pipeline = tenant.layout.pipelines['check']
663
664 in_repo_conf = textwrap.dedent(
665 """
666 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200667 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -0700668 run: playbooks/project-test1.yaml
Tobias Henkelf02cf512017-07-21 22:55:34 +0200669
670 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200671 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700672 run: playbooks/project-test2.yaml
Tobias Henkel0f714002017-06-30 23:30:52 +0200673
674 - project:
675 name: org/project
676 check:
677 jobs:
678 - project-test2
679 """)
680
681 in_repo_playbook = textwrap.dedent(
682 """
683 - hosts: all
684 tasks: []
685 """)
686
687 file_dict = {'.zuul.yaml': in_repo_conf,
688 'playbooks/project-test2.yaml': in_repo_playbook}
689 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
690 files=file_dict)
691 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
692 self.waitUntilSettled()
693
694 items = check_pipeline.getAllItems()
695 self.assertEqual(items[0].change.number, '1')
696 self.assertEqual(items[0].change.patchset, '1')
697 self.assertTrue(items[0].live)
698
699 in_repo_conf = textwrap.dedent(
700 """
701 - job:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200702 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -0700703 run: playbooks/project-test1.yaml
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200704
705 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200706 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700707 run: playbooks/project-test2.yaml
Tobias Henkel0f714002017-06-30 23:30:52 +0200708
709 - project:
710 name: org/project
711 check:
712 jobs:
713 - project-test1
714 - project-test2
715 """)
716 file_dict = {'.zuul.yaml': in_repo_conf,
717 'playbooks/project-test2.yaml': in_repo_playbook}
718
719 A.addPatchset(files=file_dict)
720 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
721
722 self.waitUntilSettled()
723
724 items = check_pipeline.getAllItems()
725 self.assertEqual(items[0].change.number, '1')
726 self.assertEqual(items[0].change.patchset, '2')
727 self.assertTrue(items[0].live)
728
729 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200730 self.executor_server.release('project-test1')
731 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +0200732 self.executor_server.release()
733 self.waitUntilSettled()
734
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200735 self.assertHistory([
736 dict(name='project-test2', result='ABORTED', changes='1,1'),
737 dict(name='project-test1', result='SUCCESS', changes='1,2'),
738 dict(name='project-test2', result='SUCCESS', changes='1,2')])
739
James E. Blairff555742017-02-19 11:34:27 -0800740 def test_in_repo_branch(self):
741 in_repo_conf = textwrap.dedent(
742 """
743 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200744 name: project-test1
745
746 - job:
James E. Blairff555742017-02-19 11:34:27 -0800747 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700748 run: playbooks/project-test2.yaml
James E. Blairff555742017-02-19 11:34:27 -0800749
750 - project:
751 name: org/project
752 tenant-one-gate:
753 jobs:
754 - project-test2
755 """)
756
757 in_repo_playbook = textwrap.dedent(
758 """
759 - hosts: all
760 tasks: []
761 """)
762
763 file_dict = {'.zuul.yaml': in_repo_conf,
764 'playbooks/project-test2.yaml': in_repo_playbook}
765 self.create_branch('org/project', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700766 self.fake_gerrit.addEvent(
767 self.fake_gerrit.getFakeBranchCreatedEvent(
768 'org/project', 'stable'))
James E. Blair6069f2b2017-09-26 16:34:11 -0700769 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800770 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
771 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200772 A.addApproval('Code-Review', 2)
773 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800774 self.waitUntilSettled()
775 self.assertEqual(A.data['status'], 'MERGED')
776 self.assertEqual(A.reported, 2,
777 "A should report start and success")
778 self.assertIn('tenant-one-gate', A.messages[1],
779 "A should transit tenant-one gate")
780 self.assertHistory([
781 dict(name='project-test2', result='SUCCESS', changes='1,1')])
782 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800783 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800784
785 # The config change should not affect master.
786 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200787 B.addApproval('Code-Review', 2)
788 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800789 self.waitUntilSettled()
790 self.assertHistory([
791 dict(name='project-test2', result='SUCCESS', changes='1,1'),
792 dict(name='project-test1', result='SUCCESS', changes='2,1')])
793
794 # The config change should be live for further changes on
795 # stable.
796 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200797 C.addApproval('Code-Review', 2)
798 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800799 self.waitUntilSettled()
800 self.assertHistory([
801 dict(name='project-test2', result='SUCCESS', changes='1,1'),
802 dict(name='project-test1', result='SUCCESS', changes='2,1'),
803 dict(name='project-test2', result='SUCCESS', changes='3,1')])
804
James E. Blaira5a12492017-05-03 11:40:48 -0700805 def test_crd_dynamic_config_branch(self):
806 # Test that we can create a job in one repo and be able to use
807 # it from a different branch on a different repo.
808
809 self.create_branch('org/project1', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700810 self.fake_gerrit.addEvent(
811 self.fake_gerrit.getFakeBranchCreatedEvent(
812 'org/project1', 'stable'))
James E. Blaira5a12492017-05-03 11:40:48 -0700813
814 in_repo_conf = textwrap.dedent(
815 """
816 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200817 name: project-test1
818
819 - job:
James E. Blaira5a12492017-05-03 11:40:48 -0700820 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -0700821 run: playbooks/project-test2.yaml
James E. Blaira5a12492017-05-03 11:40:48 -0700822
823 - project:
824 name: org/project
825 check:
826 jobs:
827 - project-test2
828 """)
829
830 in_repo_playbook = textwrap.dedent(
831 """
832 - hosts: all
833 tasks: []
834 """)
835
836 file_dict = {'.zuul.yaml': in_repo_conf,
837 'playbooks/project-test2.yaml': in_repo_playbook}
838 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
839 files=file_dict)
840
841 second_repo_conf = textwrap.dedent(
842 """
843 - project:
844 name: org/project1
845 check:
846 jobs:
847 - project-test2
848 """)
849
850 second_file_dict = {'.zuul.yaml': second_repo_conf}
851 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
852 files=second_file_dict)
853 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
854 B.subject, A.data['id'])
855
856 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
857 self.waitUntilSettled()
858 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
859 self.waitUntilSettled()
860
861 self.assertEqual(A.reported, 1, "A should report")
862 self.assertHistory([
863 dict(name='project-test2', result='SUCCESS', changes='1,1'),
864 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
865 ])
866
James E. Blair97043882017-09-06 15:51:17 -0700867 def test_yaml_list_error(self):
868 in_repo_conf = textwrap.dedent(
869 """
870 job: foo
871 """)
872
873 file_dict = {'.zuul.yaml': in_repo_conf}
874 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
875 files=file_dict)
876 A.addApproval('Code-Review', 2)
877 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
878 self.waitUntilSettled()
879
880 self.assertEqual(A.data['status'], 'NEW')
881 self.assertEqual(A.reported, 1,
882 "A should report failure")
883 self.assertIn('not a list', A.messages[0],
884 "A should have a syntax error reported")
885
886 def test_yaml_dict_error(self):
887 in_repo_conf = textwrap.dedent(
888 """
889 - job
890 """)
891
892 file_dict = {'.zuul.yaml': in_repo_conf}
893 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
894 files=file_dict)
895 A.addApproval('Code-Review', 2)
896 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
897 self.waitUntilSettled()
898
899 self.assertEqual(A.data['status'], 'NEW')
900 self.assertEqual(A.reported, 1,
901 "A should report failure")
902 self.assertIn('not a dictionary', A.messages[0],
903 "A should have a syntax error reported")
904
905 def test_yaml_key_error(self):
906 in_repo_conf = textwrap.dedent(
907 """
908 - job:
909 name: project-test2
910 """)
911
912 file_dict = {'.zuul.yaml': in_repo_conf}
913 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
914 files=file_dict)
915 A.addApproval('Code-Review', 2)
916 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
917 self.waitUntilSettled()
918
919 self.assertEqual(A.data['status'], 'NEW')
920 self.assertEqual(A.reported, 1,
921 "A should report failure")
922 self.assertIn('has more than one key', A.messages[0],
923 "A should have a syntax error reported")
924
925 def test_yaml_unknown_error(self):
926 in_repo_conf = textwrap.dedent(
927 """
928 - foobar:
929 foo: bar
930 """)
931
932 file_dict = {'.zuul.yaml': in_repo_conf}
933 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
934 files=file_dict)
935 A.addApproval('Code-Review', 2)
936 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
937 self.waitUntilSettled()
938
939 self.assertEqual(A.data['status'], 'NEW')
940 self.assertEqual(A.reported, 1,
941 "A should report failure")
942 self.assertIn('not recognized', A.messages[0],
943 "A should have a syntax error reported")
944
James E. Blair149b69c2017-03-02 10:48:16 -0800945 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -0800946 in_repo_conf = textwrap.dedent(
947 """
948 - job:
949 name: project-test2
950 foo: error
951 """)
952
953 file_dict = {'.zuul.yaml': in_repo_conf}
954 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
955 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200956 A.addApproval('Code-Review', 2)
957 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -0800958 self.waitUntilSettled()
959
960 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200961 self.assertEqual(A.reported, 1,
962 "A should report failure")
963 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -0800964 "A should have a syntax error reported")
965
James E. Blair149b69c2017-03-02 10:48:16 -0800966 def test_trusted_syntax_error(self):
967 in_repo_conf = textwrap.dedent(
968 """
969 - job:
970 name: project-test2
971 foo: error
972 """)
973
974 file_dict = {'zuul.yaml': in_repo_conf}
975 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
976 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200977 A.addApproval('Code-Review', 2)
978 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -0800979 self.waitUntilSettled()
980
981 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200982 self.assertEqual(A.reported, 1,
983 "A should report failure")
984 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -0800985 "A should have a syntax error reported")
986
James E. Blair6f140c72017-03-03 10:32:07 -0800987 def test_untrusted_yaml_error(self):
988 in_repo_conf = textwrap.dedent(
989 """
990 - job:
991 foo: error
992 """)
993
994 file_dict = {'.zuul.yaml': in_repo_conf}
995 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
996 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200997 A.addApproval('Code-Review', 2)
998 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -0800999 self.waitUntilSettled()
1000
1001 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001002 self.assertEqual(A.reported, 1,
1003 "A should report failure")
1004 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -08001005 "A should have a syntax error reported")
1006
James E. Blairdb04e6a2017-05-03 14:49:36 -07001007 def test_untrusted_shadow_error(self):
1008 in_repo_conf = textwrap.dedent(
1009 """
1010 - job:
1011 name: common-config-test
1012 """)
1013
1014 file_dict = {'.zuul.yaml': in_repo_conf}
1015 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1016 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001017 A.addApproval('Code-Review', 2)
1018 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -07001019 self.waitUntilSettled()
1020
1021 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +02001022 self.assertEqual(A.reported, 1,
1023 "A should report failure")
1024 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -07001025 "A should have a syntax error reported")
1026
James E. Blaird5656ad2017-06-02 14:29:41 -07001027 def test_untrusted_pipeline_error(self):
1028 in_repo_conf = textwrap.dedent(
1029 """
1030 - pipeline:
1031 name: test
1032 """)
1033
1034 file_dict = {'.zuul.yaml': in_repo_conf}
1035 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1036 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001037 A.addApproval('Code-Review', 2)
1038 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -07001039 self.waitUntilSettled()
1040
1041 self.assertEqual(A.data['status'], 'NEW')
1042 self.assertEqual(A.reported, 1,
1043 "A should report failure")
1044 self.assertIn('Pipelines may not be defined', A.messages[0],
1045 "A should have a syntax error reported")
1046
1047 def test_untrusted_project_error(self):
1048 in_repo_conf = textwrap.dedent(
1049 """
1050 - project:
1051 name: org/project1
1052 """)
1053
1054 file_dict = {'.zuul.yaml': in_repo_conf}
1055 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1056 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001057 A.addApproval('Code-Review', 2)
1058 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -07001059 self.waitUntilSettled()
1060
1061 self.assertEqual(A.data['status'], 'NEW')
1062 self.assertEqual(A.reported, 1,
1063 "A should report failure")
1064 self.assertIn('the only project definition permitted', A.messages[0],
1065 "A should have a syntax error reported")
1066
James E. Blairf03173b2017-10-10 10:46:43 -07001067 def test_untrusted_depends_on_trusted(self):
1068 with open(os.path.join(FIXTURE_DIR,
1069 'config/in-repo/git/',
1070 'common-config/zuul.yaml')) as f:
1071 common_config = f.read()
1072
1073 common_config += textwrap.dedent(
1074 """
1075 - job:
1076 name: project-test9
1077 """)
1078
1079 file_dict = {'zuul.yaml': common_config}
1080 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1081 files=file_dict)
1082 in_repo_conf = textwrap.dedent(
1083 """
1084 - job:
1085 name: project-test1
1086 - project:
1087 name: org/project
1088 check:
1089 jobs:
1090 - project-test9
1091 """)
1092
1093 file_dict = {'zuul.yaml': in_repo_conf}
1094 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1095 files=file_dict)
1096 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1097 B.subject, A.data['id'])
1098 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1099 self.waitUntilSettled()
1100
1101 self.assertEqual(B.data['status'], 'NEW')
1102 self.assertEqual(B.reported, 1,
1103 "B should report failure")
1104 self.assertIn('depends on a change to a config project',
1105 B.messages[0],
1106 "A should have a syntax error reported")
1107
James E. Blaire64b0e42017-06-08 11:23:34 -07001108 def test_duplicate_node_error(self):
1109 in_repo_conf = textwrap.dedent(
1110 """
1111 - nodeset:
1112 name: duplicate
1113 nodes:
1114 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001115 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001116 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001117 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001118 """)
1119
1120 file_dict = {'.zuul.yaml': in_repo_conf}
1121 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1122 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001123 A.addApproval('Code-Review', 2)
1124 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -07001125 self.waitUntilSettled()
1126
1127 self.assertEqual(A.data['status'], 'NEW')
1128 self.assertEqual(A.reported, 1,
1129 "A should report failure")
1130 self.assertIn('appears multiple times', A.messages[0],
1131 "A should have a syntax error reported")
1132
1133 def test_duplicate_group_error(self):
1134 in_repo_conf = textwrap.dedent(
1135 """
1136 - nodeset:
1137 name: duplicate
1138 nodes:
1139 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -07001140 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -07001141 groups:
1142 - name: group
1143 nodes: compute
1144 - name: group
1145 nodes: compute
1146 """)
1147
1148 file_dict = {'.zuul.yaml': in_repo_conf}
1149 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1150 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001151 A.addApproval('Code-Review', 2)
1152 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -07001153 self.waitUntilSettled()
1154
1155 self.assertEqual(A.data['status'], 'NEW')
1156 self.assertEqual(A.reported, 1,
1157 "A should report failure")
1158 self.assertIn('appears multiple times', A.messages[0],
1159 "A should have a syntax error reported")
1160
James E. Blair4ae399f2017-09-20 17:15:09 -07001161 def test_secret_not_found_error(self):
1162 in_repo_conf = textwrap.dedent(
1163 """
1164 - job:
1165 name: test
1166 secrets: does-not-exist
1167 """)
1168
1169 file_dict = {'.zuul.yaml': in_repo_conf}
1170 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1171 files=file_dict)
1172 A.addApproval('Code-Review', 2)
1173 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1174 self.waitUntilSettled()
1175
1176 self.assertEqual(A.data['status'], 'NEW')
1177 self.assertEqual(A.reported, 1,
1178 "A should report failure")
1179 self.assertIn('secret "does-not-exist" was not found', A.messages[0],
1180 "A should have a syntax error reported")
1181
1182 def test_nodeset_not_found_error(self):
1183 in_repo_conf = textwrap.dedent(
1184 """
1185 - job:
1186 name: test
1187 nodeset: does-not-exist
1188 """)
1189
1190 file_dict = {'.zuul.yaml': in_repo_conf}
1191 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1192 files=file_dict)
1193 A.addApproval('Code-Review', 2)
1194 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1195 self.waitUntilSettled()
1196
1197 self.assertEqual(A.data['status'], 'NEW')
1198 self.assertEqual(A.reported, 1,
1199 "A should report failure")
1200 self.assertIn('nodeset "does-not-exist" was not found', A.messages[0],
1201 "A should have a syntax error reported")
1202
James E. Blair89e25eb2017-09-26 09:11:31 -07001203 def test_template_not_found_error(self):
1204 in_repo_conf = textwrap.dedent(
1205 """
1206 - job:
1207 name: project-test1
1208 - project:
1209 name: org/project
1210 templates:
1211 - does-not-exist
1212 """)
1213
1214 file_dict = {'.zuul.yaml': in_repo_conf}
1215 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1216 files=file_dict)
1217 A.addApproval('Code-Review', 2)
1218 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1219 self.waitUntilSettled()
1220
1221 self.assertEqual(A.data['status'], 'NEW')
1222 self.assertEqual(A.reported, 1,
1223 "A should report failure")
1224 self.assertIn('project template "does-not-exist" was not found',
1225 A.messages[0],
1226 "A should have a syntax error reported")
1227
Monty Taylor8be3c0c2017-10-06 10:37:37 -05001228 def test_job_list_in_project_template_not_dict_error(self):
1229 in_repo_conf = textwrap.dedent(
1230 """
1231 - job:
1232 name: project-test1
1233 - project-template:
1234 name: some-jobs
1235 check:
1236 jobs:
1237 - project-test1:
1238 - required-projects:
1239 org/project2
1240 """)
1241
1242 file_dict = {'.zuul.yaml': in_repo_conf}
1243 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1244 files=file_dict)
1245 A.addApproval('Code-Review', 2)
1246 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1247 self.waitUntilSettled()
1248
1249 self.assertEqual(A.data['status'], 'NEW')
1250 self.assertEqual(A.reported, 1,
1251 "A should report failure")
1252 self.assertIn('expected str for dictionary value',
1253 A.messages[0], "A should have a syntax error reported")
1254
1255 def test_job_list_in_project_not_dict_error(self):
1256 in_repo_conf = textwrap.dedent(
1257 """
1258 - job:
1259 name: project-test1
1260 - project:
1261 name: org/project1
1262 check:
1263 jobs:
1264 - project-test1:
1265 - required-projects:
1266 org/project2
1267 """)
1268
1269 file_dict = {'.zuul.yaml': in_repo_conf}
1270 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1271 files=file_dict)
1272 A.addApproval('Code-Review', 2)
1273 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1274 self.waitUntilSettled()
1275
1276 self.assertEqual(A.data['status'], 'NEW')
1277 self.assertEqual(A.reported, 1,
1278 "A should report failure")
1279 self.assertIn('expected str for dictionary value',
1280 A.messages[0], "A should have a syntax error reported")
1281
James E. Blair1235f142017-10-07 09:11:43 -07001282 def test_project_template(self):
1283 # Tests that a project template is not modified when used, and
1284 # can therefore be used in subsequent reconfigurations.
1285 in_repo_conf = textwrap.dedent(
1286 """
1287 - job:
1288 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001289 run: playbooks/project-test1.yaml
James E. Blair1235f142017-10-07 09:11:43 -07001290 - project-template:
1291 name: some-jobs
1292 tenant-one-gate:
1293 jobs:
1294 - project-test1:
1295 required-projects:
1296 - org/project1
1297 - project:
1298 name: org/project
1299 templates:
1300 - some-jobs
1301 """)
1302
1303 file_dict = {'.zuul.yaml': in_repo_conf}
1304 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1305 files=file_dict)
1306 A.addApproval('Code-Review', 2)
1307 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1308 self.waitUntilSettled()
1309 self.assertEqual(A.data['status'], 'MERGED')
1310 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1311 self.waitUntilSettled()
1312 in_repo_conf = textwrap.dedent(
1313 """
1314 - project:
1315 name: org/project1
1316 templates:
1317 - some-jobs
1318 """)
1319 file_dict = {'.zuul.yaml': in_repo_conf}
1320 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
1321 files=file_dict)
1322 B.addApproval('Code-Review', 2)
1323 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1324 self.waitUntilSettled()
1325 self.assertEqual(B.data['status'], 'MERGED')
1326
James E. Blairbccdfcf2017-10-07 13:37:26 -07001327 def test_job_remove_add(self):
1328 # Tests that a job can be removed from one repo and added in another.
1329 # First, remove the current config for project1 since it
1330 # references the job we want to remove.
1331 file_dict = {'.zuul.yaml': None}
1332 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1333 files=file_dict)
1334 A.setMerged()
1335 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1336 self.waitUntilSettled()
1337 # Then propose a change to delete the job from one repo...
1338 file_dict = {'.zuul.yaml': None}
1339 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1340 files=file_dict)
1341 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1342 self.waitUntilSettled()
1343 # ...and a second that depends on it that adds it to another repo.
1344 in_repo_conf = textwrap.dedent(
1345 """
1346 - job:
1347 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001348 run: playbooks/project-test1.yaml
James E. Blairbccdfcf2017-10-07 13:37:26 -07001349
1350 - project:
1351 name: org/project1
1352 check:
1353 jobs:
1354 - project-test1
1355 """)
1356 in_repo_playbook = textwrap.dedent(
1357 """
1358 - hosts: all
1359 tasks: []
1360 """)
1361 file_dict = {'.zuul.yaml': in_repo_conf,
1362 'playbooks/project-test1.yaml': in_repo_playbook}
1363 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C',
1364 files=file_dict,
1365 parent='refs/changes/1/1/1')
1366 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1367 C.subject, B.data['id'])
1368 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1369 self.waitUntilSettled()
1370 self.assertHistory([
1371 dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'),
1372 ], ordered=False)
1373
James E. Blair09f9ffe2017-07-11 15:30:25 -07001374 def test_multi_repo(self):
1375 downstream_repo_conf = textwrap.dedent(
1376 """
1377 - project:
1378 name: org/project1
1379 tenant-one-gate:
1380 jobs:
1381 - project-test1
1382
1383 - job:
1384 name: project1-test1
1385 parent: project-test1
1386 """)
1387
1388 file_dict = {'.zuul.yaml': downstream_repo_conf}
1389 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1390 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001391 A.addApproval('Code-Review', 2)
1392 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001393 self.waitUntilSettled()
1394
1395 self.assertEqual(A.data['status'], 'MERGED')
1396 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1397 self.waitUntilSettled()
1398
1399 upstream_repo_conf = textwrap.dedent(
1400 """
1401 - job:
1402 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001403 run: playbooks/project-test1.yaml
James E. Blair09f9ffe2017-07-11 15:30:25 -07001404
1405 - job:
1406 name: project-test2
1407
1408 - project:
1409 name: org/project
1410 tenant-one-gate:
1411 jobs:
1412 - project-test1
1413 """)
1414
1415 file_dict = {'.zuul.yaml': upstream_repo_conf}
1416 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1417 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001418 B.addApproval('Code-Review', 2)
1419 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001420 self.waitUntilSettled()
1421
1422 self.assertEqual(B.data['status'], 'MERGED')
1423 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
1424 self.waitUntilSettled()
1425
1426 tenant = self.sched.abide.tenants.get('tenant-one')
1427 # Ensure the latest change is reflected in the config; if it
1428 # isn't this will raise an exception.
1429 tenant.layout.getJob('project-test2')
1430
James E. Blair332636e2017-09-05 10:14:35 -07001431 def test_pipeline_error(self):
1432 with open(os.path.join(FIXTURE_DIR,
1433 'config/in-repo/git/',
1434 'common-config/zuul.yaml')) as f:
1435 base_common_config = f.read()
1436
1437 in_repo_conf_A = textwrap.dedent(
1438 """
1439 - pipeline:
1440 name: periodic
1441 foo: error
1442 """)
1443
1444 file_dict = {'zuul.yaml': None,
1445 'zuul.d/main.yaml': base_common_config,
1446 'zuul.d/test1.yaml': in_repo_conf_A}
1447 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1448 files=file_dict)
1449 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1450 self.waitUntilSettled()
1451 self.assertEqual(A.reported, 1,
1452 "A should report failure")
1453 self.assertIn('syntax error',
1454 A.messages[0],
1455 "A should have an error reported")
1456
1457 def test_change_series_error(self):
1458 with open(os.path.join(FIXTURE_DIR,
1459 'config/in-repo/git/',
1460 'common-config/zuul.yaml')) as f:
1461 base_common_config = f.read()
1462
1463 in_repo_conf_A = textwrap.dedent(
1464 """
1465 - pipeline:
1466 name: periodic
1467 foo: error
1468 """)
1469
1470 file_dict = {'zuul.yaml': None,
1471 'zuul.d/main.yaml': base_common_config,
1472 'zuul.d/test1.yaml': in_repo_conf_A}
1473 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1474 files=file_dict)
1475
1476 in_repo_conf_B = textwrap.dedent(
1477 """
1478 - job:
1479 name: project-test2
1480 foo: error
1481 """)
1482
1483 file_dict = {'zuul.yaml': None,
1484 'zuul.d/main.yaml': base_common_config,
1485 'zuul.d/test1.yaml': in_repo_conf_A,
1486 'zuul.d/test2.yaml': in_repo_conf_B}
1487 B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B',
1488 files=file_dict)
1489 B.setDependsOn(A, 1)
1490 C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C')
1491 C.setDependsOn(B, 1)
1492 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1493 self.waitUntilSettled()
1494
1495 self.assertEqual(C.reported, 1,
1496 "C should report failure")
1497 self.assertIn('depends on a change that failed to merge',
1498 C.messages[0],
1499 "C should have an error reported")
1500
James E. Blairc73c73a2017-01-20 15:15:15 -08001501
James E. Blairc9455002017-09-06 09:22:19 -07001502class TestInRepoJoin(ZuulTestCase):
1503 # In this config, org/project is not a member of any pipelines, so
1504 # that we may test the changes that cause it to join them.
1505
1506 tenant_config_file = 'config/in-repo-join/main.yaml'
1507
1508 def test_dynamic_dependent_pipeline(self):
1509 # Test dynamically adding a project to a
1510 # dependent pipeline for the first time
1511 self.executor_server.hold_jobs_in_build = True
1512
1513 tenant = self.sched.abide.tenants.get('tenant-one')
1514 gate_pipeline = tenant.layout.pipelines['gate']
1515
1516 in_repo_conf = textwrap.dedent(
1517 """
1518 - job:
1519 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001520 run: playbooks/project-test1.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001521
1522 - job:
1523 name: project-test2
James E. Blair2f589fe2017-10-26 12:57:41 -07001524 run: playbooks/project-test2.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001525
1526 - project:
1527 name: org/project
1528 gate:
1529 jobs:
1530 - project-test2
1531 """)
1532
1533 in_repo_playbook = textwrap.dedent(
1534 """
1535 - hosts: all
1536 tasks: []
1537 """)
1538
1539 file_dict = {'.zuul.yaml': in_repo_conf,
1540 'playbooks/project-test2.yaml': in_repo_playbook}
1541 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1542 files=file_dict)
1543 A.addApproval('Code-Review', 2)
1544 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1545 self.waitUntilSettled()
1546
1547 items = gate_pipeline.getAllItems()
1548 self.assertEqual(items[0].change.number, '1')
1549 self.assertEqual(items[0].change.patchset, '1')
1550 self.assertTrue(items[0].live)
1551
1552 self.executor_server.hold_jobs_in_build = False
1553 self.executor_server.release()
1554 self.waitUntilSettled()
1555
1556 # Make sure the dynamic queue got cleaned up
1557 self.assertEqual(gate_pipeline.queues, [])
1558
1559 def test_dynamic_dependent_pipeline_failure(self):
1560 # Test that a change behind a failing change adding a project
1561 # to a dependent pipeline is dequeued.
1562 self.executor_server.hold_jobs_in_build = True
1563
1564 in_repo_conf = textwrap.dedent(
1565 """
1566 - job:
1567 name: project-test1
James E. Blair2f589fe2017-10-26 12:57:41 -07001568 run: playbooks/project-test1.yaml
James E. Blairc9455002017-09-06 09:22:19 -07001569
1570 - project:
1571 name: org/project
1572 gate:
1573 jobs:
1574 - project-test1
1575 """)
1576
1577 file_dict = {'.zuul.yaml': in_repo_conf}
1578 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1579 files=file_dict)
1580 self.executor_server.failJob('project-test1', A)
1581 A.addApproval('Code-Review', 2)
1582 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1583 self.waitUntilSettled()
1584
1585 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1586 B.addApproval('Code-Review', 2)
1587 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1588 self.waitUntilSettled()
1589
James E. Blair3490c5d2017-09-07 08:33:23 -07001590 self.orderedRelease()
James E. Blairc9455002017-09-06 09:22:19 -07001591 self.waitUntilSettled()
1592 self.assertEqual(A.reported, 2,
1593 "A should report start and failure")
1594 self.assertEqual(A.data['status'], 'NEW')
1595 self.assertEqual(B.reported, 1,
1596 "B should report start")
1597 self.assertHistory([
1598 dict(name='project-test1', result='FAILURE', changes='1,1'),
James E. Blair3490c5d2017-09-07 08:33:23 -07001599 dict(name='project-test1', result='ABORTED', changes='1,1 2,1'),
James E. Blairc9455002017-09-06 09:22:19 -07001600 ], ordered=False)
1601
James E. Blair0af198f2017-09-06 09:52:35 -07001602 def test_dynamic_dependent_pipeline_absent(self):
1603 # Test that a series of dependent changes don't report merge
1604 # failures to a pipeline they aren't in.
1605 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1606 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1607 B.setDependsOn(A, 1)
1608
1609 A.addApproval('Code-Review', 2)
1610 A.addApproval('Approved', 1)
1611 B.addApproval('Code-Review', 2)
1612 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1613 self.waitUntilSettled()
1614 self.assertEqual(A.reported, 0,
1615 "A should not report")
1616 self.assertEqual(A.data['status'], 'NEW')
1617 self.assertEqual(B.reported, 0,
1618 "B should not report")
1619 self.assertEqual(B.data['status'], 'NEW')
1620 self.assertHistory([])
1621
James E. Blairc9455002017-09-06 09:22:19 -07001622
James E. Blairc73c73a2017-01-20 15:15:15 -08001623class TestAnsible(AnsibleZuulTestCase):
1624 # A temporary class to hold new tests while others are disabled
1625
1626 tenant_config_file = 'config/ansible/main.yaml'
1627
1628 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +11001629 # Keep the jobdir around so we can inspect contents if an
1630 # assert fails.
1631 self.executor_server.keep_jobdir = True
1632 # Output extra ansible info so we might see errors.
1633 self.executor_server.verbose = True
1634 # Add a site variables file, used by check-vars
1635 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
1636 'variables.yaml')
1637 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -08001638 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1639 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1640 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +02001641 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +11001642 with self.jobLog(build_timeout):
1643 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001644 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +11001645 with self.jobLog(build_faillocal):
1646 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001647 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +11001648 with self.jobLog(build_failpost):
1649 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001650 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +11001651 with self.jobLog(build_check_vars):
1652 self.assertEqual(build_check_vars.result, 'SUCCESS')
Monty Tayloraff8b402017-08-16 18:40:41 -05001653 build_check_secret_names = self.getJobFromHistory('check-secret-names')
1654 with self.jobLog(build_check_secret_names):
1655 self.assertEqual(build_check_secret_names.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001656 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +11001657 with self.jobLog(build_hello):
1658 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001659 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +11001660 with self.jobLog(build_python27):
1661 self.assertEqual(build_python27.result, 'SUCCESS')
1662 flag_path = os.path.join(self.test_root,
1663 build_python27.uuid + '.flag')
1664 self.assertTrue(os.path.exists(flag_path))
1665 copied_path = os.path.join(self.test_root, build_python27.uuid +
1666 '.copied')
1667 self.assertTrue(os.path.exists(copied_path))
1668 failed_path = os.path.join(self.test_root, build_python27.uuid +
1669 '.failed')
1670 self.assertFalse(os.path.exists(failed_path))
1671 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
1672 '.pre.flag')
1673 self.assertTrue(os.path.exists(pre_flag_path))
1674 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
1675 '.post.flag')
1676 self.assertTrue(os.path.exists(post_flag_path))
1677 bare_role_flag_path = os.path.join(self.test_root,
1678 build_python27.uuid +
1679 '.bare-role.flag')
1680 self.assertTrue(os.path.exists(bare_role_flag_path))
1681 secrets_path = os.path.join(self.test_root,
1682 build_python27.uuid + '.secrets')
1683 with open(secrets_path) as f:
1684 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -08001685
Jamie Lennox7655b552017-03-17 12:33:38 +11001686 msg = A.messages[0]
1687 success = "{} https://success.example.com/zuul-logs/{}"
1688 fail = "{} https://failure.example.com/zuul-logs/{}"
1689 self.assertIn(success.format("python27", build_python27.uuid), msg)
1690 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
1691 self.assertIn(success.format("check-vars",
1692 build_check_vars.uuid), msg)
1693 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
1694 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
1695 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +02001696
James E. Blairabbaa6f2017-04-06 16:11:44 -07001697 def _add_job(self, job_name):
1698 conf = textwrap.dedent(
1699 """
1700 - job:
1701 name: %s
James E. Blair2f589fe2017-10-26 12:57:41 -07001702 run: playbooks/%s.yaml
James E. Blairabbaa6f2017-04-06 16:11:44 -07001703
1704 - project:
1705 name: org/plugin-project
1706 check:
1707 jobs:
1708 - %s
James E. Blair2f589fe2017-10-26 12:57:41 -07001709 """ % (job_name, job_name, job_name))
James E. Blairabbaa6f2017-04-06 16:11:44 -07001710
1711 file_dict = {'.zuul.yaml': conf}
1712 A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A',
1713 files=file_dict)
1714 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1715 self.waitUntilSettled()
1716
1717 def test_plugins(self):
1718 # Keep the jobdir around so we can inspect contents if an
1719 # assert fails.
1720 self.executor_server.keep_jobdir = True
1721 # Output extra ansible info so we might see errors.
1722 self.executor_server.verbose = True
1723
1724 count = 0
1725 plugin_tests = [
1726 ('passwd', 'FAILURE'),
1727 ('cartesian', 'SUCCESS'),
1728 ('consul_kv', 'FAILURE'),
1729 ('credstash', 'FAILURE'),
1730 ('csvfile_good', 'SUCCESS'),
1731 ('csvfile_bad', 'FAILURE'),
Monty Taylor93ad2212017-08-02 14:59:50 -05001732 ('uri_bad_path', 'FAILURE'),
1733 ('uri_bad_scheme', 'FAILURE'),
Monty Taylor788a40e2017-08-02 16:14:05 -05001734 ('block_local_override', 'FAILURE'),
Monty Taylor8da768f2017-08-31 14:15:35 -05001735 ('file_local_good', 'SUCCESS'),
1736 ('file_local_bad', 'FAILURE'),
James E. Blairabbaa6f2017-04-06 16:11:44 -07001737 ]
1738 for job_name, result in plugin_tests:
1739 count += 1
1740 self._add_job(job_name)
1741
1742 job = self.getJobFromHistory(job_name)
1743 with self.jobLog(job):
1744 self.assertEqual(count, len(self.history))
1745 build = self.history[-1]
1746 self.assertEqual(build.result, result)
1747
1748 # TODOv3(jeblair): parse the ansible output and verify we're
1749 # getting the exception we expect.
1750
James E. Blairb9c0d772017-03-03 14:34:49 -08001751
James E. Blaira4d4eef2017-06-30 14:49:17 -07001752class TestPrePlaybooks(AnsibleZuulTestCase):
1753 # A temporary class to hold new tests while others are disabled
1754
1755 tenant_config_file = 'config/pre-playbook/main.yaml'
1756
1757 def test_pre_playbook_fail(self):
1758 # Test that we run the post playbooks (but not the actual
1759 # playbook) when a pre-playbook fails.
1760 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1761 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1762 self.waitUntilSettled()
1763 build = self.getJobFromHistory('python27')
1764 self.assertIsNone(build.result)
1765 self.assertIn('RETRY_LIMIT', A.messages[0])
1766 flag_path = os.path.join(self.test_root, build.uuid +
1767 '.main.flag')
1768 self.assertFalse(os.path.exists(flag_path))
1769 pre_flag_path = os.path.join(self.test_root, build.uuid +
1770 '.pre.flag')
1771 self.assertFalse(os.path.exists(pre_flag_path))
1772 post_flag_path = os.path.join(self.test_root, build.uuid +
1773 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -07001774 self.assertTrue(os.path.exists(post_flag_path),
1775 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -07001776
1777
James E. Blairbacbb882017-10-17 09:48:23 -07001778class TestPostPlaybooks(AnsibleZuulTestCase):
1779 tenant_config_file = 'config/post-playbook/main.yaml'
1780
1781 def test_post_playbook_abort(self):
1782 # Test that when we abort a job in the post playbook, that we
1783 # don't send back POST_FAILURE.
1784 self.executor_server.verbose = True
1785 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1786 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1787
1788 while not len(self.builds):
1789 time.sleep(0.1)
1790 build = self.builds[0]
1791
1792 post_start = os.path.join(self.test_root, build.uuid +
1793 '.post_start.flag')
1794 start = time.time()
1795 while time.time() < start + 90:
1796 if os.path.exists(post_start):
1797 break
1798 time.sleep(0.1)
1799 # The post playbook has started, abort the job
1800 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1801 self.waitUntilSettled()
1802
1803 build = self.getJobFromHistory('python27')
1804 self.assertEqual('ABORTED', build.result)
1805
1806 post_end = os.path.join(self.test_root, build.uuid +
1807 '.post_end.flag')
1808 self.assertTrue(os.path.exists(post_start))
1809 self.assertFalse(os.path.exists(post_end))
1810
1811
James E. Blairb9c0d772017-03-03 14:34:49 -08001812class TestBrokenConfig(ZuulTestCase):
1813 # Test that we get an appropriate syntax error if we start with a
1814 # broken config.
1815
1816 tenant_config_file = 'config/broken/main.yaml'
1817
1818 def setUp(self):
1819 with testtools.ExpectedException(
1820 zuul.configloader.ConfigurationSyntaxError,
1821 "\nZuul encountered a syntax error"):
1822 super(TestBrokenConfig, self).setUp()
1823
1824 def test_broken_config_on_startup(self):
1825 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001826
1827
1828class TestProjectKeys(ZuulTestCase):
1829 # Test that we can generate project keys
1830
1831 # Normally the test infrastructure copies a static key in place
1832 # for each project before starting tests. This saves time because
1833 # Zuul's automatic key-generation on startup can be slow. To make
1834 # sure we exercise that code, in this test we allow Zuul to create
1835 # keys for the project on startup.
1836 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +02001837 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001838 tenant_config_file = 'config/in-repo/main.yaml'
1839
1840 def test_key_generation(self):
1841 key_root = os.path.join(self.state_root, 'keys')
1842 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
1843 # Make sure that a proper key was created on startup
1844 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -07001845 private_key, public_key = \
1846 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001847
1848 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
1849 fixture_private_key = i.read()
1850
1851 # Make sure that we didn't just end up with the static fixture
1852 # key
1853 self.assertNotEqual(fixture_private_key, private_key)
1854
1855 # Make sure it's the right length
1856 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -07001857
1858
James E. Blairbb94dfa2017-07-11 07:45:19 -07001859class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -07001860 def _assertRolePath(self, build, playbook, content):
1861 path = os.path.join(self.test_root, build.uuid,
1862 'ansible', playbook, 'ansible.cfg')
1863 roles_paths = []
1864 with open(path) as f:
1865 for line in f:
1866 if line.startswith('roles_path'):
1867 roles_paths.append(line)
1868 print(roles_paths)
1869 if content:
1870 self.assertEqual(len(roles_paths), 1,
1871 "Should have one roles_path line in %s" %
1872 (playbook,))
1873 self.assertIn(content, roles_paths[0])
1874 else:
1875 self.assertEqual(len(roles_paths), 0,
1876 "Should have no roles_path line in %s" %
1877 (playbook,))
1878
James E. Blairbb94dfa2017-07-11 07:45:19 -07001879
1880class TestRoles(RoleTestCase):
1881 tenant_config_file = 'config/roles/main.yaml'
1882
James E. Blairbce76932017-05-04 10:03:15 -07001883 def test_role(self):
1884 # This exercises a proposed change to a role being checked out
1885 # and used.
1886 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
1887 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1888 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1889 B.subject, A.data['id'])
1890 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1891 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1892 self.waitUntilSettled()
1893 self.assertHistory([
1894 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
1895 ])
James E. Blair6459db12017-06-29 14:57:20 -07001896
James E. Blair1b27f6a2017-07-14 14:09:07 -07001897 def test_role_inheritance(self):
1898 self.executor_server.hold_jobs_in_build = True
1899 conf = textwrap.dedent(
1900 """
1901 - job:
1902 name: parent
1903 roles:
1904 - zuul: bare-role
1905 pre-run: playbooks/parent-pre
1906 post-run: playbooks/parent-post
1907
1908 - job:
1909 name: project-test
1910 parent: parent
James E. Blair2f589fe2017-10-26 12:57:41 -07001911 run: playbooks/project-test.yaml
James E. Blair1b27f6a2017-07-14 14:09:07 -07001912 roles:
1913 - zuul: org/project
1914
1915 - project:
1916 name: org/project
1917 check:
1918 jobs:
1919 - project-test
1920 """)
1921
1922 file_dict = {'.zuul.yaml': conf}
1923 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1924 files=file_dict)
1925 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1926 self.waitUntilSettled()
1927
1928 self.assertEqual(len(self.builds), 1)
1929 build = self.getBuildByName('project-test')
1930 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
1931 self._assertRolePath(build, 'playbook_0', 'role_0')
1932 self._assertRolePath(build, 'playbook_0', 'role_1')
1933 self._assertRolePath(build, 'post_playbook_0', 'role_0')
1934
1935 self.executor_server.hold_jobs_in_build = False
1936 self.executor_server.release()
1937 self.waitUntilSettled()
1938
1939 self.assertHistory([
1940 dict(name='project-test', result='SUCCESS', changes='1,1'),
1941 ])
1942
James E. Blair6f699732017-07-18 14:19:11 -07001943 def test_role_error(self):
1944 conf = textwrap.dedent(
1945 """
1946 - job:
1947 name: project-test
James E. Blair2f589fe2017-10-26 12:57:41 -07001948 run: playbooks/project-test.yaml
James E. Blair6f699732017-07-18 14:19:11 -07001949 roles:
1950 - zuul: common-config
1951
1952 - project:
1953 name: org/project
1954 check:
1955 jobs:
1956 - project-test
1957 """)
1958
1959 file_dict = {'.zuul.yaml': conf}
1960 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1961 files=file_dict)
1962 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1963 self.waitUntilSettled()
1964 self.assertIn(
1965 '- project-test project-test : ERROR Unable to find role',
1966 A.messages[-1])
1967
James E. Blair6459db12017-06-29 14:57:20 -07001968
James E. Blairbb94dfa2017-07-11 07:45:19 -07001969class TestImplicitRoles(RoleTestCase):
1970 tenant_config_file = 'config/implicit-roles/main.yaml'
1971
1972 def test_missing_roles(self):
1973 # Test implicit and explicit roles for a project which does
1974 # not have roles. The implicit role should be silently
1975 # ignored since the project doesn't supply roles, but if a
1976 # user declares an explicit role, it should error.
1977 self.executor_server.hold_jobs_in_build = True
1978 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
1979 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1980 self.waitUntilSettled()
1981
1982 self.assertEqual(len(self.builds), 2)
1983 build = self.getBuildByName('implicit-role-fail')
1984 self._assertRolePath(build, 'playbook_0', None)
1985
1986 self.executor_server.hold_jobs_in_build = False
1987 self.executor_server.release()
1988 self.waitUntilSettled()
1989 # The retry_limit doesn't get recorded
1990 self.assertHistory([
1991 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
1992 ])
1993
1994 def test_roles(self):
1995 # Test implicit and explicit roles for a project which does
1996 # have roles. In both cases, we should end up with the role
1997 # in the path. In the explicit case, ensure we end up with
1998 # the name we specified.
1999 self.executor_server.hold_jobs_in_build = True
2000 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
2001 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2002 self.waitUntilSettled()
2003
2004 self.assertEqual(len(self.builds), 2)
2005 build = self.getBuildByName('implicit-role-ok')
2006 self._assertRolePath(build, 'playbook_0', 'role_0')
2007
2008 build = self.getBuildByName('explicit-role-ok')
2009 self._assertRolePath(build, 'playbook_0', 'role_0')
2010
2011 self.executor_server.hold_jobs_in_build = False
2012 self.executor_server.release()
2013 self.waitUntilSettled()
2014 self.assertHistory([
2015 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
2016 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
2017 ], ordered=False)
2018
2019
James E. Blair6459db12017-06-29 14:57:20 -07002020class TestShadow(ZuulTestCase):
2021 tenant_config_file = 'config/shadow/main.yaml'
2022
2023 def test_shadow(self):
2024 # Test that a repo is allowed to shadow another's job definitions.
2025 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2026 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2027 self.waitUntilSettled()
2028 self.assertHistory([
2029 dict(name='test1', result='SUCCESS', changes='1,1'),
2030 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -07002031 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -07002032
2033
2034class TestDataReturn(AnsibleZuulTestCase):
2035 tenant_config_file = 'config/data-return/main.yaml'
2036
2037 def test_data_return(self):
James E. Blair196f61a2017-06-30 15:42:29 -07002038 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2039 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2040 self.waitUntilSettled()
2041 self.assertHistory([
2042 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07002043 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
James E. Blair698703c2017-09-15 20:58:30 -06002044 dict(name='child', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07002045 ], ordered=False)
2046 self.assertIn('- data-return http://example.com/test/log/url/',
2047 A.messages[-1])
2048 self.assertIn('- data-return-relative '
2049 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -07002050 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -07002051
2052
2053class TestDiskAccounting(AnsibleZuulTestCase):
2054 config_file = 'zuul-disk-accounting.conf'
2055 tenant_config_file = 'config/disk-accountant/main.yaml'
2056
2057 def test_disk_accountant_kills_job(self):
2058 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2059 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2060 self.waitUntilSettled()
2061 self.assertHistory([
2062 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002063
2064
2065class TestMaxNodesPerJob(AnsibleZuulTestCase):
2066 tenant_config_file = 'config/multi-tenant/main.yaml'
2067
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00002068 def test_max_timeout_exceeded(self):
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002069 in_repo_conf = textwrap.dedent(
2070 """
2071 - job:
2072 name: test-job
James E. Blair7e3e6882017-09-20 15:47:13 -07002073 nodeset:
2074 nodes:
2075 - name: node01
2076 label: fake
2077 - name: node02
2078 label: fake
2079 - name: node03
2080 label: fake
2081 - name: node04
2082 label: fake
2083 - name: node05
2084 label: fake
2085 - name: node06
2086 label: fake
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00002087 """)
2088 file_dict = {'.zuul.yaml': in_repo_conf}
2089 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2090 files=file_dict)
2091 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2092 self.waitUntilSettled()
2093 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
2094 A.messages[0], "A should fail because of nodes limit")
2095
2096 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2097 files=file_dict)
2098 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2099 self.waitUntilSettled()
2100 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
2101 "B should not fail because of nodes limit")
James E. Blair2bab6e72017-08-07 09:52:45 -07002102
2103
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00002104class TestMaxTimeout(AnsibleZuulTestCase):
2105 tenant_config_file = 'config/multi-tenant/main.yaml'
2106
2107 def test_max_nodes_reached(self):
2108 in_repo_conf = textwrap.dedent(
2109 """
2110 - job:
2111 name: test-job
2112 timeout: 3600
2113 """)
2114 file_dict = {'.zuul.yaml': in_repo_conf}
2115 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
2116 files=file_dict)
2117 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2118 self.waitUntilSettled()
2119 self.assertIn('The job "test-job" exceeds tenant max-job-timeout',
2120 A.messages[0], "A should fail because of timeout limit")
2121
2122 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
2123 files=file_dict)
2124 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2125 self.waitUntilSettled()
2126 self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0],
2127 "B should not fail because of timeout limit")
2128
2129
James E. Blair7edc25f2017-10-26 10:47:14 -07002130class TestPragma(ZuulTestCase):
2131 tenant_config_file = 'config/pragma/main.yaml'
2132
2133 def test_no_pragma(self):
2134 self.create_branch('org/project', 'stable')
2135 with open(os.path.join(FIXTURE_DIR,
2136 'config/pragma/git/',
2137 'org_project/nopragma.yaml')) as f:
2138 config = f.read()
2139 file_dict = {'.zuul.yaml': config}
2140 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2141 files=file_dict)
2142 A.addApproval('Code-Review', 2)
2143 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2144 self.waitUntilSettled()
2145 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2146 self.waitUntilSettled()
2147
2148 # This is an untrusted repo with 2 branches, so it should have
2149 # an implied branch matcher for the job.
2150 tenant = self.sched.abide.tenants.get('tenant-one')
2151 jobs = tenant.layout.getJobs('test-job')
2152 self.assertEqual(len(jobs), 1)
2153 for job in tenant.layout.getJobs('test-job'):
2154 self.assertIsNotNone(job.branch_matcher)
2155
2156 def test_pragma(self):
2157 self.create_branch('org/project', 'stable')
2158 with open(os.path.join(FIXTURE_DIR,
2159 'config/pragma/git/',
2160 'org_project/pragma.yaml')) as f:
2161 config = f.read()
2162 file_dict = {'.zuul.yaml': config}
2163 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2164 files=file_dict)
2165 A.addApproval('Code-Review', 2)
2166 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2167 self.waitUntilSettled()
2168 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
2169 self.waitUntilSettled()
2170
2171 # This is an untrusted repo with 2 branches, so it would
2172 # normally have an implied branch matcher, but our pragma
2173 # overrides it.
2174 tenant = self.sched.abide.tenants.get('tenant-one')
2175 jobs = tenant.layout.getJobs('test-job')
2176 self.assertEqual(len(jobs), 1)
2177 for job in tenant.layout.getJobs('test-job'):
2178 self.assertIsNone(job.branch_matcher)
2179
2180
James E. Blair2bab6e72017-08-07 09:52:45 -07002181class TestBaseJobs(ZuulTestCase):
2182 tenant_config_file = 'config/base-jobs/main.yaml'
2183
2184 def test_multiple_base_jobs(self):
2185 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2186 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2187 self.waitUntilSettled()
2188 self.assertHistory([
2189 dict(name='my-job', result='SUCCESS', changes='1,1'),
2190 dict(name='other-job', result='SUCCESS', changes='1,1'),
2191 ], ordered=False)
2192 self.assertEqual(self.getJobFromHistory('my-job').
2193 parameters['zuul']['jobtags'],
2194 ['mybase'])
2195 self.assertEqual(self.getJobFromHistory('other-job').
2196 parameters['zuul']['jobtags'],
2197 ['otherbase'])
2198
2199 def test_untrusted_base_job(self):
2200 """Test that a base job may not be defined in an untrusted repo"""
2201 in_repo_conf = textwrap.dedent(
2202 """
2203 - job:
2204 name: fail-base
2205 parent: null
2206 """)
2207
2208 file_dict = {'.zuul.yaml': in_repo_conf}
2209 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2210 files=file_dict)
2211 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2212 self.waitUntilSettled()
2213 self.assertEqual(A.reported, 1,
2214 "A should report failure")
2215 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
2216 self.assertIn('Base jobs must be defined in config projects',
2217 A.messages[0])
2218 self.assertHistory([])
James E. Blairdb089032017-08-15 13:42:12 -07002219
2220
James E. Blairdf91ab32017-10-25 17:57:13 -07002221class TestSecretInheritance(ZuulTestCase):
2222 tenant_config_file = 'config/secret-inheritance/main.yaml'
2223
2224 def _getSecrets(self, job, pbtype):
2225 secrets = []
2226 build = self.getJobFromHistory(job)
2227 for pb in build.parameters[pbtype]:
2228 secrets.append(pb['secrets'])
2229 return secrets
2230
2231 def _checkTrustedSecrets(self):
2232 secret = {'longpassword': 'test-passwordtest-password',
2233 'password': 'test-password',
2234 'username': 'test-username'}
2235 self.assertEqual(
2236 self._getSecrets('trusted-secrets', 'playbooks'),
James E. Blair2f589fe2017-10-26 12:57:41 -07002237 [{'trusted-secret': secret}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002238 self.assertEqual(
2239 self._getSecrets('trusted-secrets', 'pre_playbooks'), [])
2240 self.assertEqual(
2241 self._getSecrets('trusted-secrets', 'post_playbooks'), [])
2242
2243 self.assertEqual(
2244 self._getSecrets('trusted-secrets-trusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002245 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002246 self.assertEqual(
2247 self._getSecrets('trusted-secrets-trusted-child',
2248 'pre_playbooks'), [])
2249 self.assertEqual(
2250 self._getSecrets('trusted-secrets-trusted-child',
2251 'post_playbooks'), [])
2252
2253 self.assertEqual(
2254 self._getSecrets('trusted-secrets-untrusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002255 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002256 self.assertEqual(
2257 self._getSecrets('trusted-secrets-untrusted-child',
2258 'pre_playbooks'), [])
2259 self.assertEqual(
2260 self._getSecrets('trusted-secrets-untrusted-child',
2261 'post_playbooks'), [])
2262
2263 def _checkUntrustedSecrets(self):
2264 secret = {'longpassword': 'test-passwordtest-password',
2265 'password': 'test-password',
2266 'username': 'test-username'}
2267 self.assertEqual(
2268 self._getSecrets('untrusted-secrets', 'playbooks'),
James E. Blair2f589fe2017-10-26 12:57:41 -07002269 [{'untrusted-secret': secret}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002270 self.assertEqual(
2271 self._getSecrets('untrusted-secrets', 'pre_playbooks'), [])
2272 self.assertEqual(
2273 self._getSecrets('untrusted-secrets', 'post_playbooks'), [])
2274
2275 self.assertEqual(
2276 self._getSecrets('untrusted-secrets-trusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002277 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002278 self.assertEqual(
2279 self._getSecrets('untrusted-secrets-trusted-child',
2280 'pre_playbooks'), [])
2281 self.assertEqual(
2282 self._getSecrets('untrusted-secrets-trusted-child',
2283 'post_playbooks'), [])
2284
2285 self.assertEqual(
2286 self._getSecrets('untrusted-secrets-untrusted-child',
James E. Blair2f589fe2017-10-26 12:57:41 -07002287 'playbooks'), [{}])
James E. Blairdf91ab32017-10-25 17:57:13 -07002288 self.assertEqual(
2289 self._getSecrets('untrusted-secrets-untrusted-child',
2290 'pre_playbooks'), [])
2291 self.assertEqual(
2292 self._getSecrets('untrusted-secrets-untrusted-child',
2293 'post_playbooks'), [])
2294
2295 def test_trusted_secret_inheritance_check(self):
2296 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
2297 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2298 self.waitUntilSettled()
2299 self.assertHistory([
2300 dict(name='trusted-secrets', result='SUCCESS', changes='1,1'),
2301 dict(name='trusted-secrets-trusted-child',
2302 result='SUCCESS', changes='1,1'),
2303 dict(name='trusted-secrets-untrusted-child',
2304 result='SUCCESS', changes='1,1'),
2305 ], ordered=False)
2306
2307 self._checkTrustedSecrets()
2308
2309 def test_untrusted_secret_inheritance_gate(self):
2310 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
2311 A.addApproval('Code-Review', 2)
2312 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
2313 self.waitUntilSettled()
2314 self.assertHistory([
2315 dict(name='untrusted-secrets', result='SUCCESS', changes='1,1'),
2316 dict(name='untrusted-secrets-trusted-child',
2317 result='SUCCESS', changes='1,1'),
2318 dict(name='untrusted-secrets-untrusted-child',
2319 result='SUCCESS', changes='1,1'),
2320 ], ordered=False)
2321
2322 self._checkUntrustedSecrets()
2323
2324 def test_untrusted_secret_inheritance_check(self):
2325 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2326 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2327 self.waitUntilSettled()
2328 # This configuration tries to run untrusted secrets in an
2329 # non-post-review pipeline and should therefore run no jobs.
2330 self.assertHistory([])
2331
2332
James E. Blairdb089032017-08-15 13:42:12 -07002333class TestSecretLeaks(AnsibleZuulTestCase):
2334 tenant_config_file = 'config/secret-leaks/main.yaml'
2335
2336 def searchForContent(self, path, content):
2337 matches = []
2338 for (dirpath, dirnames, filenames) in os.walk(path):
2339 for filename in filenames:
2340 filepath = os.path.join(dirpath, filename)
2341 with open(filepath, 'rb') as f:
2342 if content in f.read():
2343 matches.append(filepath[len(path):])
2344 return matches
2345
2346 def _test_secret_file(self):
2347 # Or rather -- test that they *don't* leak.
2348 # Keep the jobdir around so we can inspect contents.
2349 self.executor_server.keep_jobdir = True
2350 conf = textwrap.dedent(
2351 """
2352 - project:
2353 name: org/project
2354 check:
2355 jobs:
2356 - secret-file
2357 """)
2358
2359 file_dict = {'.zuul.yaml': conf}
2360 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2361 files=file_dict)
2362 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2363 self.waitUntilSettled()
2364 self.assertHistory([
2365 dict(name='secret-file', result='SUCCESS', changes='1,1'),
2366 ], ordered=False)
2367 matches = self.searchForContent(self.history[0].jobdir.root,
2368 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07002369 self.assertEqual(set(['/work/secret-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07002370 set(matches))
2371
2372 def test_secret_file(self):
2373 self._test_secret_file()
2374
2375 def test_secret_file_verbose(self):
2376 # Output extra ansible info to exercise alternate logging code
2377 # paths.
2378 self.executor_server.verbose = True
2379 self._test_secret_file()
2380
2381 def _test_secret_file_fail(self):
2382 # Or rather -- test that they *don't* leak.
2383 # Keep the jobdir around so we can inspect contents.
2384 self.executor_server.keep_jobdir = True
2385 conf = textwrap.dedent(
2386 """
2387 - project:
2388 name: org/project
2389 check:
2390 jobs:
2391 - secret-file-fail
2392 """)
2393
2394 file_dict = {'.zuul.yaml': conf}
2395 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
2396 files=file_dict)
2397 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2398 self.waitUntilSettled()
2399 self.assertHistory([
2400 dict(name='secret-file-fail', result='FAILURE', changes='1,1'),
2401 ], ordered=False)
2402 matches = self.searchForContent(self.history[0].jobdir.root,
2403 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07002404 self.assertEqual(set(['/work/failure-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07002405 set(matches))
2406
2407 def test_secret_file_fail(self):
2408 self._test_secret_file_fail()
2409
2410 def test_secret_file_fail_verbose(self):
2411 # Output extra ansible info to exercise alternate logging code
2412 # paths.
2413 self.executor_server.verbose = True
2414 self._test_secret_file_fail()
James E. Blaira00910c2017-08-23 09:15:04 -07002415
2416
2417class TestJobOutput(AnsibleZuulTestCase):
2418 tenant_config_file = 'config/job-output/main.yaml'
2419
2420 def _get_file(self, build, path):
2421 p = os.path.join(build.jobdir.root, path)
2422 with open(p) as f:
2423 return f.read()
2424
2425 def test_job_output(self):
Monty Taylor0e2489a2017-10-10 11:57:29 -05002426 # Verify that command standard output appears in the job output,
2427 # and that failures in the final playbook get logged.
James E. Blaira00910c2017-08-23 09:15:04 -07002428
2429 # This currently only verifies we receive output from
2430 # localhost. Notably, it does not verify we receive output
2431 # via zuul_console streaming.
2432 self.executor_server.keep_jobdir = True
2433 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2434 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2435 self.waitUntilSettled()
2436 self.assertHistory([
2437 dict(name='job-output', result='SUCCESS', changes='1,1'),
2438 ], ordered=False)
2439
2440 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2441 j = json.loads(self._get_file(self.history[0],
2442 'work/logs/job-output.json'))
2443 self.assertEqual(token,
2444 j[0]['plays'][0]['tasks'][0]
2445 ['hosts']['localhost']['stdout'])
2446
2447 print(self._get_file(self.history[0],
2448 'work/logs/job-output.txt'))
2449 self.assertIn(token,
2450 self._get_file(self.history[0],
2451 'work/logs/job-output.txt'))
Monty Taylor0e2489a2017-10-10 11:57:29 -05002452
2453 def test_job_output_failure_log(self):
2454 logger = logging.getLogger('zuul.AnsibleJob')
2455 output = io.StringIO()
2456 logger.addHandler(logging.StreamHandler(output))
2457
2458 # Verify that a failure in the last post playbook emits the contents
2459 # of the json output to the log
2460 self.executor_server.keep_jobdir = True
2461 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
2462 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2463 self.waitUntilSettled()
2464 self.assertHistory([
2465 dict(name='job-output-failure',
2466 result='POST_FAILURE', changes='1,1'),
2467 ], ordered=False)
2468
2469 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2470 j = json.loads(self._get_file(self.history[0],
2471 'work/logs/job-output.json'))
2472 self.assertEqual(token,
2473 j[0]['plays'][0]['tasks'][0]
2474 ['hosts']['localhost']['stdout'])
2475
2476 print(self._get_file(self.history[0],
2477 'work/logs/job-output.json'))
2478 self.assertIn(token,
2479 self._get_file(self.history[0],
2480 'work/logs/job-output.txt'))
2481
2482 log_output = output.getvalue()
2483 self.assertIn('Final playbook failed', log_output)
2484 self.assertIn('Failure test', log_output)