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