blob: 92353fbd5edb7938e23f65cd300b7491e4480dba [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
131
132 - project:
133 name: org/project
134 check:
135 jobs:
136 - project-test
137 """)
138
139 in_repo_playbook = textwrap.dedent(
140 """
141 - hosts: all
142 tasks: []
143 """)
144
145 file_dict = {'.zuul.yaml': in_repo_conf,
146 'playbooks/project-test.yaml': in_repo_playbook}
147 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
148 files=file_dict)
149 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
150 self.waitUntilSettled()
151
152 # The second patch tried to override some variables.
153 # Thus it should fail.
154 self.assertEqual(A.reported, 1)
155 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
156 self.assertIn('Unable to inherit from final job', A.messages[0])
157
158
James E. Blair09998792017-10-15 18:02:18 -0700159class TestBranchVariants(ZuulTestCase):
160 tenant_config_file = 'config/branch-variants/main.yaml'
161
162 def test_branch_variants(self):
163 # Test branch variants of jobs with inheritance
164 self.executor_server.hold_jobs_in_build = True
165 # This creates a new branch with a copy of the config in master
166 self.create_branch('puppet-integration', 'stable')
167 self.fake_gerrit.addEvent(
168 self.fake_gerrit.getFakeBranchCreatedEvent(
169 'puppet-integration', 'stable'))
170 self.waitUntilSettled()
171
172 A = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'A')
173 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
174 self.waitUntilSettled()
175
176 self.assertEqual(len(self.builds[0].parameters['pre_playbooks']), 3)
177 self.executor_server.hold_jobs_in_build = False
178 self.executor_server.release()
179 self.waitUntilSettled()
180
James E. Blairc9e77592017-10-24 09:25:23 -0700181 def test_branch_variants_reconfigure(self):
182 # Test branch variants of jobs with inheritance
183 self.executor_server.hold_jobs_in_build = True
184 # This creates a new branch with a copy of the config in master
185 self.create_branch('puppet-integration', 'stable')
186 self.fake_gerrit.addEvent(
187 self.fake_gerrit.getFakeBranchCreatedEvent(
188 'puppet-integration', 'stable'))
189 self.waitUntilSettled()
190
191 with open(os.path.join(FIXTURE_DIR,
192 'config/branch-variants/git/',
193 'puppet-integration/.zuul.yaml')) as f:
194 config = f.read()
195
196 # Push a change that triggers a dynamic reconfiguration
197 file_dict = {'.zuul.yaml': config}
198 A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A',
199 files=file_dict)
200 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
201 self.waitUntilSettled()
202
203 ipath = self.builds[0].parameters['zuul']['_inheritance_path']
204 for i in ipath:
205 self.log.debug("inheritance path %s", i)
206 self.assertEqual(len(ipath), 5)
207 self.executor_server.hold_jobs_in_build = False
208 self.executor_server.release()
209 self.waitUntilSettled()
210
James E. Blair09998792017-10-15 18:02:18 -0700211
James E. Blairff555742017-02-19 11:34:27 -0800212class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -0800213 # A temporary class to hold new tests while others are disabled
214
Tobias Henkelabf973e2017-07-28 10:07:34 +0200215 config_file = 'zuul-connections-gerrit-and-github.conf'
James E. Blair2a629ec2015-12-22 15:32:02 -0800216 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -0800217
James E. Blair83005782015-12-11 14:46:03 -0800218 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -0800219 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200220 A.addApproval('Code-Review', 2)
221 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -0800222 self.waitUntilSettled()
223 self.assertEqual(self.getJobFromHistory('project-test1').result,
224 'SUCCESS')
225 self.assertEqual(A.data['status'], 'MERGED')
226 self.assertEqual(A.reported, 2,
227 "A should report start and success")
228 self.assertIn('tenant-one-gate', A.messages[1],
229 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -0800230
James E. Blair3a098dd2017-10-04 14:37:29 -0700231 @skip("This test is useful, but not reliable")
232 def test_full_and_dynamic_reconfig(self):
233 self.executor_server.hold_jobs_in_build = True
234 in_repo_conf = textwrap.dedent(
235 """
236 - job:
237 name: project-test1
238
239 - project:
240 name: org/project
241 tenant-one-gate:
242 jobs:
243 - project-test1
244 """)
245
246 file_dict = {'.zuul.yaml': in_repo_conf}
247 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
248 files=file_dict)
249 A.addApproval('Code-Review', 2)
250 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
251 self.waitUntilSettled()
252 self.sched.reconfigure(self.config)
253 self.waitUntilSettled()
254
255 gc.collect()
256 pipelines = [obj for obj in gc.get_objects()
257 if isinstance(obj, zuul.model.Pipeline)]
258 self.assertEqual(len(pipelines), 4)
259
260 self.executor_server.hold_jobs_in_build = False
261 self.executor_server.release()
262 self.waitUntilSettled()
263
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700264 def test_dynamic_config(self):
265 in_repo_conf = textwrap.dedent(
266 """
267 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200268 name: project-test1
269
270 - job:
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700271 name: project-test2
272
273 - project:
274 name: org/project
275 tenant-one-gate:
276 jobs:
277 - project-test2
278 """)
279
James E. Blairc73c73a2017-01-20 15:15:15 -0800280 in_repo_playbook = textwrap.dedent(
281 """
282 - hosts: all
283 tasks: []
284 """)
285
286 file_dict = {'.zuul.yaml': in_repo_conf,
287 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700288 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800289 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200290 A.addApproval('Code-Review', 2)
291 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700292 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700293 self.assertEqual(A.data['status'], 'MERGED')
294 self.assertEqual(A.reported, 2,
295 "A should report start and success")
296 self.assertIn('tenant-one-gate', A.messages[1],
297 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800298 self.assertHistory([
299 dict(name='project-test2', result='SUCCESS', changes='1,1')])
300
James E. Blairc2a5ed72017-02-20 14:12:01 -0500301 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800302 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500303
James E. Blair646322f2017-01-27 15:50:34 -0800304 # Now that the config change is landed, it should be live for
305 # subsequent changes.
306 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200307 B.addApproval('Code-Review', 2)
308 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair646322f2017-01-27 15:50:34 -0800309 self.waitUntilSettled()
310 self.assertEqual(self.getJobFromHistory('project-test2').result,
311 'SUCCESS')
312 self.assertHistory([
313 dict(name='project-test2', result='SUCCESS', changes='1,1'),
314 dict(name='project-test2', result='SUCCESS', changes='2,1')])
James E. Blairc73c73a2017-01-20 15:15:15 -0800315
James E. Blair6bc10482017-10-20 11:28:53 -0700316 def test_dynamic_template(self):
317 in_repo_conf = textwrap.dedent(
318 """
319 - job:
320 name: project-test1
321
322 - project-template:
323 name: common-config-template
324 check:
325 jobs:
326 - project-test1
327
328 - project:
329 name: org/project
330 templates: [common-config-template]
331 """)
332
333 file_dict = {'.zuul.yaml': in_repo_conf}
334 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
335 files=file_dict)
336 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
337 self.waitUntilSettled()
338 self.assertHistory([
339 dict(name='template-job', result='SUCCESS', changes='1,1')])
340
Tobias Henkelf02cf512017-07-21 22:55:34 +0200341 def test_dynamic_config_non_existing_job(self):
342 """Test that requesting a non existent job fails"""
343 in_repo_conf = textwrap.dedent(
344 """
345 - job:
346 name: project-test1
347
348 - project:
349 name: org/project
350 check:
351 jobs:
352 - non-existent-job
353 """)
354
355 in_repo_playbook = textwrap.dedent(
356 """
357 - hosts: all
358 tasks: []
359 """)
360
361 file_dict = {'.zuul.yaml': in_repo_conf,
362 'playbooks/project-test2.yaml': in_repo_playbook}
363 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
364 files=file_dict)
365 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
366 self.waitUntilSettled()
367 self.assertEqual(A.reported, 1,
368 "A should report failure")
369 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
370 self.assertIn('Job non-existent-job not defined', A.messages[0],
371 "A should have failed the check pipeline")
372 self.assertHistory([])
373
374 def test_dynamic_config_non_existing_job_in_template(self):
375 """Test that requesting a non existent job fails"""
376 in_repo_conf = textwrap.dedent(
377 """
378 - job:
379 name: project-test1
380
381 - project-template:
382 name: test-template
383 check:
384 jobs:
385 - non-existent-job
386
387 - project:
388 name: org/project
389 templates:
390 - test-template
391 """)
392
393 in_repo_playbook = textwrap.dedent(
394 """
395 - hosts: all
396 tasks: []
397 """)
398
399 file_dict = {'.zuul.yaml': in_repo_conf,
400 'playbooks/project-test2.yaml': in_repo_playbook}
401 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
402 files=file_dict)
403 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
404 self.waitUntilSettled()
405 self.assertEqual(A.reported, 1,
406 "A should report failure")
407 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
408 self.assertIn('Job non-existent-job not defined', A.messages[0],
409 "A should have failed the check pipeline")
410 self.assertHistory([])
411
Tobias Henkel0f714002017-06-30 23:30:52 +0200412 def test_dynamic_config_new_patchset(self):
413 self.executor_server.hold_jobs_in_build = True
414
415 tenant = self.sched.abide.tenants.get('tenant-one')
416 check_pipeline = tenant.layout.pipelines['check']
417
418 in_repo_conf = textwrap.dedent(
419 """
420 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200421 name: project-test1
422
423 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200424 name: project-test2
425
426 - project:
427 name: org/project
428 check:
429 jobs:
430 - project-test2
431 """)
432
433 in_repo_playbook = textwrap.dedent(
434 """
435 - hosts: all
436 tasks: []
437 """)
438
439 file_dict = {'.zuul.yaml': in_repo_conf,
440 'playbooks/project-test2.yaml': in_repo_playbook}
441 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
442 files=file_dict)
443 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
444 self.waitUntilSettled()
445
446 items = check_pipeline.getAllItems()
447 self.assertEqual(items[0].change.number, '1')
448 self.assertEqual(items[0].change.patchset, '1')
449 self.assertTrue(items[0].live)
450
451 in_repo_conf = textwrap.dedent(
452 """
453 - job:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200454 name: project-test1
455
456 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200457 name: project-test2
458
459 - project:
460 name: org/project
461 check:
462 jobs:
463 - project-test1
464 - project-test2
465 """)
466 file_dict = {'.zuul.yaml': in_repo_conf,
467 'playbooks/project-test2.yaml': in_repo_playbook}
468
469 A.addPatchset(files=file_dict)
470 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
471
472 self.waitUntilSettled()
473
474 items = check_pipeline.getAllItems()
475 self.assertEqual(items[0].change.number, '1')
476 self.assertEqual(items[0].change.patchset, '2')
477 self.assertTrue(items[0].live)
478
479 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200480 self.executor_server.release('project-test1')
481 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +0200482 self.executor_server.release()
483 self.waitUntilSettled()
484
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200485 self.assertHistory([
486 dict(name='project-test2', result='ABORTED', changes='1,1'),
487 dict(name='project-test1', result='SUCCESS', changes='1,2'),
488 dict(name='project-test2', result='SUCCESS', changes='1,2')])
489
James E. Blairff555742017-02-19 11:34:27 -0800490 def test_in_repo_branch(self):
491 in_repo_conf = textwrap.dedent(
492 """
493 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200494 name: project-test1
495
496 - job:
James E. Blairff555742017-02-19 11:34:27 -0800497 name: project-test2
498
499 - project:
500 name: org/project
501 tenant-one-gate:
502 jobs:
503 - project-test2
504 """)
505
506 in_repo_playbook = textwrap.dedent(
507 """
508 - hosts: all
509 tasks: []
510 """)
511
512 file_dict = {'.zuul.yaml': in_repo_conf,
513 'playbooks/project-test2.yaml': in_repo_playbook}
514 self.create_branch('org/project', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700515 self.fake_gerrit.addEvent(
516 self.fake_gerrit.getFakeBranchCreatedEvent(
517 'org/project', 'stable'))
James E. Blair6069f2b2017-09-26 16:34:11 -0700518 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800519 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
520 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200521 A.addApproval('Code-Review', 2)
522 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800523 self.waitUntilSettled()
524 self.assertEqual(A.data['status'], 'MERGED')
525 self.assertEqual(A.reported, 2,
526 "A should report start and success")
527 self.assertIn('tenant-one-gate', A.messages[1],
528 "A should transit tenant-one gate")
529 self.assertHistory([
530 dict(name='project-test2', result='SUCCESS', changes='1,1')])
531 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800532 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800533
534 # The config change should not affect master.
535 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200536 B.addApproval('Code-Review', 2)
537 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800538 self.waitUntilSettled()
539 self.assertHistory([
540 dict(name='project-test2', result='SUCCESS', changes='1,1'),
541 dict(name='project-test1', result='SUCCESS', changes='2,1')])
542
543 # The config change should be live for further changes on
544 # stable.
545 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200546 C.addApproval('Code-Review', 2)
547 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800548 self.waitUntilSettled()
549 self.assertHistory([
550 dict(name='project-test2', result='SUCCESS', changes='1,1'),
551 dict(name='project-test1', result='SUCCESS', changes='2,1'),
552 dict(name='project-test2', result='SUCCESS', changes='3,1')])
553
James E. Blaira5a12492017-05-03 11:40:48 -0700554 def test_crd_dynamic_config_branch(self):
555 # Test that we can create a job in one repo and be able to use
556 # it from a different branch on a different repo.
557
558 self.create_branch('org/project1', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700559 self.fake_gerrit.addEvent(
560 self.fake_gerrit.getFakeBranchCreatedEvent(
561 'org/project1', 'stable'))
James E. Blaira5a12492017-05-03 11:40:48 -0700562
563 in_repo_conf = textwrap.dedent(
564 """
565 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200566 name: project-test1
567
568 - job:
James E. Blaira5a12492017-05-03 11:40:48 -0700569 name: project-test2
570
571 - project:
572 name: org/project
573 check:
574 jobs:
575 - project-test2
576 """)
577
578 in_repo_playbook = textwrap.dedent(
579 """
580 - hosts: all
581 tasks: []
582 """)
583
584 file_dict = {'.zuul.yaml': in_repo_conf,
585 'playbooks/project-test2.yaml': in_repo_playbook}
586 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
587 files=file_dict)
588
589 second_repo_conf = textwrap.dedent(
590 """
591 - project:
592 name: org/project1
593 check:
594 jobs:
595 - project-test2
596 """)
597
598 second_file_dict = {'.zuul.yaml': second_repo_conf}
599 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
600 files=second_file_dict)
601 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
602 B.subject, A.data['id'])
603
604 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
605 self.waitUntilSettled()
606 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
607 self.waitUntilSettled()
608
609 self.assertEqual(A.reported, 1, "A should report")
610 self.assertHistory([
611 dict(name='project-test2', result='SUCCESS', changes='1,1'),
612 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
613 ])
614
James E. Blair97043882017-09-06 15:51:17 -0700615 def test_yaml_list_error(self):
616 in_repo_conf = textwrap.dedent(
617 """
618 job: foo
619 """)
620
621 file_dict = {'.zuul.yaml': in_repo_conf}
622 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
623 files=file_dict)
624 A.addApproval('Code-Review', 2)
625 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
626 self.waitUntilSettled()
627
628 self.assertEqual(A.data['status'], 'NEW')
629 self.assertEqual(A.reported, 1,
630 "A should report failure")
631 self.assertIn('not a list', A.messages[0],
632 "A should have a syntax error reported")
633
634 def test_yaml_dict_error(self):
635 in_repo_conf = textwrap.dedent(
636 """
637 - job
638 """)
639
640 file_dict = {'.zuul.yaml': in_repo_conf}
641 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
642 files=file_dict)
643 A.addApproval('Code-Review', 2)
644 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
645 self.waitUntilSettled()
646
647 self.assertEqual(A.data['status'], 'NEW')
648 self.assertEqual(A.reported, 1,
649 "A should report failure")
650 self.assertIn('not a dictionary', A.messages[0],
651 "A should have a syntax error reported")
652
653 def test_yaml_key_error(self):
654 in_repo_conf = textwrap.dedent(
655 """
656 - job:
657 name: project-test2
658 """)
659
660 file_dict = {'.zuul.yaml': in_repo_conf}
661 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
662 files=file_dict)
663 A.addApproval('Code-Review', 2)
664 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
665 self.waitUntilSettled()
666
667 self.assertEqual(A.data['status'], 'NEW')
668 self.assertEqual(A.reported, 1,
669 "A should report failure")
670 self.assertIn('has more than one key', A.messages[0],
671 "A should have a syntax error reported")
672
673 def test_yaml_unknown_error(self):
674 in_repo_conf = textwrap.dedent(
675 """
676 - foobar:
677 foo: bar
678 """)
679
680 file_dict = {'.zuul.yaml': in_repo_conf}
681 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
682 files=file_dict)
683 A.addApproval('Code-Review', 2)
684 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
685 self.waitUntilSettled()
686
687 self.assertEqual(A.data['status'], 'NEW')
688 self.assertEqual(A.reported, 1,
689 "A should report failure")
690 self.assertIn('not recognized', A.messages[0],
691 "A should have a syntax error reported")
692
James E. Blair149b69c2017-03-02 10:48:16 -0800693 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -0800694 in_repo_conf = textwrap.dedent(
695 """
696 - job:
697 name: project-test2
698 foo: error
699 """)
700
701 file_dict = {'.zuul.yaml': in_repo_conf}
702 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
703 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200704 A.addApproval('Code-Review', 2)
705 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -0800706 self.waitUntilSettled()
707
708 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200709 self.assertEqual(A.reported, 1,
710 "A should report failure")
711 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -0800712 "A should have a syntax error reported")
713
James E. Blair149b69c2017-03-02 10:48:16 -0800714 def test_trusted_syntax_error(self):
715 in_repo_conf = textwrap.dedent(
716 """
717 - job:
718 name: project-test2
719 foo: error
720 """)
721
722 file_dict = {'zuul.yaml': in_repo_conf}
723 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
724 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200725 A.addApproval('Code-Review', 2)
726 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -0800727 self.waitUntilSettled()
728
729 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200730 self.assertEqual(A.reported, 1,
731 "A should report failure")
732 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -0800733 "A should have a syntax error reported")
734
James E. Blair6f140c72017-03-03 10:32:07 -0800735 def test_untrusted_yaml_error(self):
736 in_repo_conf = textwrap.dedent(
737 """
738 - job:
739 foo: error
740 """)
741
742 file_dict = {'.zuul.yaml': in_repo_conf}
743 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
744 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200745 A.addApproval('Code-Review', 2)
746 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -0800747 self.waitUntilSettled()
748
749 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200750 self.assertEqual(A.reported, 1,
751 "A should report failure")
752 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -0800753 "A should have a syntax error reported")
754
James E. Blairdb04e6a2017-05-03 14:49:36 -0700755 def test_untrusted_shadow_error(self):
756 in_repo_conf = textwrap.dedent(
757 """
758 - job:
759 name: common-config-test
760 """)
761
762 file_dict = {'.zuul.yaml': in_repo_conf}
763 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
764 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200765 A.addApproval('Code-Review', 2)
766 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -0700767 self.waitUntilSettled()
768
769 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200770 self.assertEqual(A.reported, 1,
771 "A should report failure")
772 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -0700773 "A should have a syntax error reported")
774
James E. Blaird5656ad2017-06-02 14:29:41 -0700775 def test_untrusted_pipeline_error(self):
776 in_repo_conf = textwrap.dedent(
777 """
778 - pipeline:
779 name: test
780 """)
781
782 file_dict = {'.zuul.yaml': in_repo_conf}
783 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
784 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200785 A.addApproval('Code-Review', 2)
786 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700787 self.waitUntilSettled()
788
789 self.assertEqual(A.data['status'], 'NEW')
790 self.assertEqual(A.reported, 1,
791 "A should report failure")
792 self.assertIn('Pipelines may not be defined', A.messages[0],
793 "A should have a syntax error reported")
794
795 def test_untrusted_project_error(self):
796 in_repo_conf = textwrap.dedent(
797 """
798 - project:
799 name: org/project1
800 """)
801
802 file_dict = {'.zuul.yaml': in_repo_conf}
803 A = self.fake_gerrit.addFakeChange('org/project', 'master', '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. Blaird5656ad2017-06-02 14:29:41 -0700807 self.waitUntilSettled()
808
809 self.assertEqual(A.data['status'], 'NEW')
810 self.assertEqual(A.reported, 1,
811 "A should report failure")
812 self.assertIn('the only project definition permitted', A.messages[0],
813 "A should have a syntax error reported")
814
James E. Blairf03173b2017-10-10 10:46:43 -0700815 def test_untrusted_depends_on_trusted(self):
816 with open(os.path.join(FIXTURE_DIR,
817 'config/in-repo/git/',
818 'common-config/zuul.yaml')) as f:
819 common_config = f.read()
820
821 common_config += textwrap.dedent(
822 """
823 - job:
824 name: project-test9
825 """)
826
827 file_dict = {'zuul.yaml': common_config}
828 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
829 files=file_dict)
830 in_repo_conf = textwrap.dedent(
831 """
832 - job:
833 name: project-test1
834 - project:
835 name: org/project
836 check:
837 jobs:
838 - project-test9
839 """)
840
841 file_dict = {'zuul.yaml': in_repo_conf}
842 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
843 files=file_dict)
844 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
845 B.subject, A.data['id'])
846 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
847 self.waitUntilSettled()
848
849 self.assertEqual(B.data['status'], 'NEW')
850 self.assertEqual(B.reported, 1,
851 "B should report failure")
852 self.assertIn('depends on a change to a config project',
853 B.messages[0],
854 "A should have a syntax error reported")
855
James E. Blaire64b0e42017-06-08 11:23:34 -0700856 def test_duplicate_node_error(self):
857 in_repo_conf = textwrap.dedent(
858 """
859 - nodeset:
860 name: duplicate
861 nodes:
862 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700863 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700864 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700865 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700866 """)
867
868 file_dict = {'.zuul.yaml': in_repo_conf}
869 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
870 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200871 A.addApproval('Code-Review', 2)
872 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700873 self.waitUntilSettled()
874
875 self.assertEqual(A.data['status'], 'NEW')
876 self.assertEqual(A.reported, 1,
877 "A should report failure")
878 self.assertIn('appears multiple times', A.messages[0],
879 "A should have a syntax error reported")
880
881 def test_duplicate_group_error(self):
882 in_repo_conf = textwrap.dedent(
883 """
884 - nodeset:
885 name: duplicate
886 nodes:
887 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700888 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700889 groups:
890 - name: group
891 nodes: compute
892 - name: group
893 nodes: compute
894 """)
895
896 file_dict = {'.zuul.yaml': in_repo_conf}
897 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
898 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200899 A.addApproval('Code-Review', 2)
900 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700901 self.waitUntilSettled()
902
903 self.assertEqual(A.data['status'], 'NEW')
904 self.assertEqual(A.reported, 1,
905 "A should report failure")
906 self.assertIn('appears multiple times', A.messages[0],
907 "A should have a syntax error reported")
908
James E. Blair4ae399f2017-09-20 17:15:09 -0700909 def test_secret_not_found_error(self):
910 in_repo_conf = textwrap.dedent(
911 """
912 - job:
913 name: test
914 secrets: does-not-exist
915 """)
916
917 file_dict = {'.zuul.yaml': in_repo_conf}
918 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
919 files=file_dict)
920 A.addApproval('Code-Review', 2)
921 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
922 self.waitUntilSettled()
923
924 self.assertEqual(A.data['status'], 'NEW')
925 self.assertEqual(A.reported, 1,
926 "A should report failure")
927 self.assertIn('secret "does-not-exist" was not found', A.messages[0],
928 "A should have a syntax error reported")
929
930 def test_nodeset_not_found_error(self):
931 in_repo_conf = textwrap.dedent(
932 """
933 - job:
934 name: test
935 nodeset: does-not-exist
936 """)
937
938 file_dict = {'.zuul.yaml': in_repo_conf}
939 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
940 files=file_dict)
941 A.addApproval('Code-Review', 2)
942 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
943 self.waitUntilSettled()
944
945 self.assertEqual(A.data['status'], 'NEW')
946 self.assertEqual(A.reported, 1,
947 "A should report failure")
948 self.assertIn('nodeset "does-not-exist" was not found', A.messages[0],
949 "A should have a syntax error reported")
950
James E. Blair89e25eb2017-09-26 09:11:31 -0700951 def test_template_not_found_error(self):
952 in_repo_conf = textwrap.dedent(
953 """
954 - job:
955 name: project-test1
956 - project:
957 name: org/project
958 templates:
959 - does-not-exist
960 """)
961
962 file_dict = {'.zuul.yaml': in_repo_conf}
963 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
964 files=file_dict)
965 A.addApproval('Code-Review', 2)
966 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
967 self.waitUntilSettled()
968
969 self.assertEqual(A.data['status'], 'NEW')
970 self.assertEqual(A.reported, 1,
971 "A should report failure")
972 self.assertIn('project template "does-not-exist" was not found',
973 A.messages[0],
974 "A should have a syntax error reported")
975
Monty Taylor8be3c0c2017-10-06 10:37:37 -0500976 def test_job_list_in_project_template_not_dict_error(self):
977 in_repo_conf = textwrap.dedent(
978 """
979 - job:
980 name: project-test1
981 - project-template:
982 name: some-jobs
983 check:
984 jobs:
985 - project-test1:
986 - required-projects:
987 org/project2
988 """)
989
990 file_dict = {'.zuul.yaml': in_repo_conf}
991 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
992 files=file_dict)
993 A.addApproval('Code-Review', 2)
994 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
995 self.waitUntilSettled()
996
997 self.assertEqual(A.data['status'], 'NEW')
998 self.assertEqual(A.reported, 1,
999 "A should report failure")
1000 self.assertIn('expected str for dictionary value',
1001 A.messages[0], "A should have a syntax error reported")
1002
1003 def test_job_list_in_project_not_dict_error(self):
1004 in_repo_conf = textwrap.dedent(
1005 """
1006 - job:
1007 name: project-test1
1008 - project:
1009 name: org/project1
1010 check:
1011 jobs:
1012 - project-test1:
1013 - required-projects:
1014 org/project2
1015 """)
1016
1017 file_dict = {'.zuul.yaml': in_repo_conf}
1018 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1019 files=file_dict)
1020 A.addApproval('Code-Review', 2)
1021 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1022 self.waitUntilSettled()
1023
1024 self.assertEqual(A.data['status'], 'NEW')
1025 self.assertEqual(A.reported, 1,
1026 "A should report failure")
1027 self.assertIn('expected str for dictionary value',
1028 A.messages[0], "A should have a syntax error reported")
1029
James E. Blair1235f142017-10-07 09:11:43 -07001030 def test_project_template(self):
1031 # Tests that a project template is not modified when used, and
1032 # can therefore be used in subsequent reconfigurations.
1033 in_repo_conf = textwrap.dedent(
1034 """
1035 - job:
1036 name: project-test1
1037 - project-template:
1038 name: some-jobs
1039 tenant-one-gate:
1040 jobs:
1041 - project-test1:
1042 required-projects:
1043 - org/project1
1044 - project:
1045 name: org/project
1046 templates:
1047 - some-jobs
1048 """)
1049
1050 file_dict = {'.zuul.yaml': in_repo_conf}
1051 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1052 files=file_dict)
1053 A.addApproval('Code-Review', 2)
1054 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1055 self.waitUntilSettled()
1056 self.assertEqual(A.data['status'], 'MERGED')
1057 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1058 self.waitUntilSettled()
1059 in_repo_conf = textwrap.dedent(
1060 """
1061 - project:
1062 name: org/project1
1063 templates:
1064 - some-jobs
1065 """)
1066 file_dict = {'.zuul.yaml': in_repo_conf}
1067 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
1068 files=file_dict)
1069 B.addApproval('Code-Review', 2)
1070 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1071 self.waitUntilSettled()
1072 self.assertEqual(B.data['status'], 'MERGED')
1073
James E. Blairbccdfcf2017-10-07 13:37:26 -07001074 def test_job_remove_add(self):
1075 # Tests that a job can be removed from one repo and added in another.
1076 # First, remove the current config for project1 since it
1077 # references the job we want to remove.
1078 file_dict = {'.zuul.yaml': None}
1079 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1080 files=file_dict)
1081 A.setMerged()
1082 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1083 self.waitUntilSettled()
1084 # Then propose a change to delete the job from one repo...
1085 file_dict = {'.zuul.yaml': None}
1086 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1087 files=file_dict)
1088 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1089 self.waitUntilSettled()
1090 # ...and a second that depends on it that adds it to another repo.
1091 in_repo_conf = textwrap.dedent(
1092 """
1093 - job:
1094 name: project-test1
1095
1096 - project:
1097 name: org/project1
1098 check:
1099 jobs:
1100 - project-test1
1101 """)
1102 in_repo_playbook = textwrap.dedent(
1103 """
1104 - hosts: all
1105 tasks: []
1106 """)
1107 file_dict = {'.zuul.yaml': in_repo_conf,
1108 'playbooks/project-test1.yaml': in_repo_playbook}
1109 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C',
1110 files=file_dict,
1111 parent='refs/changes/1/1/1')
1112 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1113 C.subject, B.data['id'])
1114 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1115 self.waitUntilSettled()
1116 self.assertHistory([
1117 dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'),
1118 ], ordered=False)
1119
James E. Blair09f9ffe2017-07-11 15:30:25 -07001120 def test_multi_repo(self):
1121 downstream_repo_conf = textwrap.dedent(
1122 """
1123 - project:
1124 name: org/project1
1125 tenant-one-gate:
1126 jobs:
1127 - project-test1
1128
1129 - job:
1130 name: project1-test1
1131 parent: project-test1
1132 """)
1133
1134 file_dict = {'.zuul.yaml': downstream_repo_conf}
1135 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1136 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001137 A.addApproval('Code-Review', 2)
1138 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001139 self.waitUntilSettled()
1140
1141 self.assertEqual(A.data['status'], 'MERGED')
1142 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1143 self.waitUntilSettled()
1144
1145 upstream_repo_conf = textwrap.dedent(
1146 """
1147 - job:
1148 name: project-test1
1149
1150 - job:
1151 name: project-test2
1152
1153 - project:
1154 name: org/project
1155 tenant-one-gate:
1156 jobs:
1157 - project-test1
1158 """)
1159
1160 file_dict = {'.zuul.yaml': upstream_repo_conf}
1161 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1162 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001163 B.addApproval('Code-Review', 2)
1164 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001165 self.waitUntilSettled()
1166
1167 self.assertEqual(B.data['status'], 'MERGED')
1168 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
1169 self.waitUntilSettled()
1170
1171 tenant = self.sched.abide.tenants.get('tenant-one')
1172 # Ensure the latest change is reflected in the config; if it
1173 # isn't this will raise an exception.
1174 tenant.layout.getJob('project-test2')
1175
James E. Blair332636e2017-09-05 10:14:35 -07001176 def test_pipeline_error(self):
1177 with open(os.path.join(FIXTURE_DIR,
1178 'config/in-repo/git/',
1179 'common-config/zuul.yaml')) as f:
1180 base_common_config = f.read()
1181
1182 in_repo_conf_A = textwrap.dedent(
1183 """
1184 - pipeline:
1185 name: periodic
1186 foo: error
1187 """)
1188
1189 file_dict = {'zuul.yaml': None,
1190 'zuul.d/main.yaml': base_common_config,
1191 'zuul.d/test1.yaml': in_repo_conf_A}
1192 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1193 files=file_dict)
1194 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1195 self.waitUntilSettled()
1196 self.assertEqual(A.reported, 1,
1197 "A should report failure")
1198 self.assertIn('syntax error',
1199 A.messages[0],
1200 "A should have an error reported")
1201
1202 def test_change_series_error(self):
1203 with open(os.path.join(FIXTURE_DIR,
1204 'config/in-repo/git/',
1205 'common-config/zuul.yaml')) as f:
1206 base_common_config = f.read()
1207
1208 in_repo_conf_A = textwrap.dedent(
1209 """
1210 - pipeline:
1211 name: periodic
1212 foo: error
1213 """)
1214
1215 file_dict = {'zuul.yaml': None,
1216 'zuul.d/main.yaml': base_common_config,
1217 'zuul.d/test1.yaml': in_repo_conf_A}
1218 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1219 files=file_dict)
1220
1221 in_repo_conf_B = textwrap.dedent(
1222 """
1223 - job:
1224 name: project-test2
1225 foo: error
1226 """)
1227
1228 file_dict = {'zuul.yaml': None,
1229 'zuul.d/main.yaml': base_common_config,
1230 'zuul.d/test1.yaml': in_repo_conf_A,
1231 'zuul.d/test2.yaml': in_repo_conf_B}
1232 B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B',
1233 files=file_dict)
1234 B.setDependsOn(A, 1)
1235 C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C')
1236 C.setDependsOn(B, 1)
1237 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1238 self.waitUntilSettled()
1239
1240 self.assertEqual(C.reported, 1,
1241 "C should report failure")
1242 self.assertIn('depends on a change that failed to merge',
1243 C.messages[0],
1244 "C should have an error reported")
1245
James E. Blairc73c73a2017-01-20 15:15:15 -08001246
James E. Blairc9455002017-09-06 09:22:19 -07001247class TestInRepoJoin(ZuulTestCase):
1248 # In this config, org/project is not a member of any pipelines, so
1249 # that we may test the changes that cause it to join them.
1250
1251 tenant_config_file = 'config/in-repo-join/main.yaml'
1252
1253 def test_dynamic_dependent_pipeline(self):
1254 # Test dynamically adding a project to a
1255 # dependent pipeline for the first time
1256 self.executor_server.hold_jobs_in_build = True
1257
1258 tenant = self.sched.abide.tenants.get('tenant-one')
1259 gate_pipeline = tenant.layout.pipelines['gate']
1260
1261 in_repo_conf = textwrap.dedent(
1262 """
1263 - job:
1264 name: project-test1
1265
1266 - job:
1267 name: project-test2
1268
1269 - project:
1270 name: org/project
1271 gate:
1272 jobs:
1273 - project-test2
1274 """)
1275
1276 in_repo_playbook = textwrap.dedent(
1277 """
1278 - hosts: all
1279 tasks: []
1280 """)
1281
1282 file_dict = {'.zuul.yaml': in_repo_conf,
1283 'playbooks/project-test2.yaml': in_repo_playbook}
1284 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1285 files=file_dict)
1286 A.addApproval('Code-Review', 2)
1287 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1288 self.waitUntilSettled()
1289
1290 items = gate_pipeline.getAllItems()
1291 self.assertEqual(items[0].change.number, '1')
1292 self.assertEqual(items[0].change.patchset, '1')
1293 self.assertTrue(items[0].live)
1294
1295 self.executor_server.hold_jobs_in_build = False
1296 self.executor_server.release()
1297 self.waitUntilSettled()
1298
1299 # Make sure the dynamic queue got cleaned up
1300 self.assertEqual(gate_pipeline.queues, [])
1301
1302 def test_dynamic_dependent_pipeline_failure(self):
1303 # Test that a change behind a failing change adding a project
1304 # to a dependent pipeline is dequeued.
1305 self.executor_server.hold_jobs_in_build = True
1306
1307 in_repo_conf = textwrap.dedent(
1308 """
1309 - job:
1310 name: project-test1
1311
1312 - project:
1313 name: org/project
1314 gate:
1315 jobs:
1316 - project-test1
1317 """)
1318
1319 file_dict = {'.zuul.yaml': in_repo_conf}
1320 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1321 files=file_dict)
1322 self.executor_server.failJob('project-test1', A)
1323 A.addApproval('Code-Review', 2)
1324 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1325 self.waitUntilSettled()
1326
1327 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1328 B.addApproval('Code-Review', 2)
1329 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1330 self.waitUntilSettled()
1331
James E. Blair3490c5d2017-09-07 08:33:23 -07001332 self.orderedRelease()
James E. Blairc9455002017-09-06 09:22:19 -07001333 self.waitUntilSettled()
1334 self.assertEqual(A.reported, 2,
1335 "A should report start and failure")
1336 self.assertEqual(A.data['status'], 'NEW')
1337 self.assertEqual(B.reported, 1,
1338 "B should report start")
1339 self.assertHistory([
1340 dict(name='project-test1', result='FAILURE', changes='1,1'),
James E. Blair3490c5d2017-09-07 08:33:23 -07001341 dict(name='project-test1', result='ABORTED', changes='1,1 2,1'),
James E. Blairc9455002017-09-06 09:22:19 -07001342 ], ordered=False)
1343
James E. Blair0af198f2017-09-06 09:52:35 -07001344 def test_dynamic_dependent_pipeline_absent(self):
1345 # Test that a series of dependent changes don't report merge
1346 # failures to a pipeline they aren't in.
1347 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1348 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1349 B.setDependsOn(A, 1)
1350
1351 A.addApproval('Code-Review', 2)
1352 A.addApproval('Approved', 1)
1353 B.addApproval('Code-Review', 2)
1354 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1355 self.waitUntilSettled()
1356 self.assertEqual(A.reported, 0,
1357 "A should not report")
1358 self.assertEqual(A.data['status'], 'NEW')
1359 self.assertEqual(B.reported, 0,
1360 "B should not report")
1361 self.assertEqual(B.data['status'], 'NEW')
1362 self.assertHistory([])
1363
James E. Blairc9455002017-09-06 09:22:19 -07001364
James E. Blairc73c73a2017-01-20 15:15:15 -08001365class TestAnsible(AnsibleZuulTestCase):
1366 # A temporary class to hold new tests while others are disabled
1367
1368 tenant_config_file = 'config/ansible/main.yaml'
1369
1370 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +11001371 # Keep the jobdir around so we can inspect contents if an
1372 # assert fails.
1373 self.executor_server.keep_jobdir = True
1374 # Output extra ansible info so we might see errors.
1375 self.executor_server.verbose = True
1376 # Add a site variables file, used by check-vars
1377 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
1378 'variables.yaml')
1379 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -08001380 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1381 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1382 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +02001383 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +11001384 with self.jobLog(build_timeout):
1385 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001386 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +11001387 with self.jobLog(build_faillocal):
1388 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001389 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +11001390 with self.jobLog(build_failpost):
1391 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001392 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +11001393 with self.jobLog(build_check_vars):
1394 self.assertEqual(build_check_vars.result, 'SUCCESS')
Monty Tayloraff8b402017-08-16 18:40:41 -05001395 build_check_secret_names = self.getJobFromHistory('check-secret-names')
1396 with self.jobLog(build_check_secret_names):
1397 self.assertEqual(build_check_secret_names.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001398 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +11001399 with self.jobLog(build_hello):
1400 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001401 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +11001402 with self.jobLog(build_python27):
1403 self.assertEqual(build_python27.result, 'SUCCESS')
1404 flag_path = os.path.join(self.test_root,
1405 build_python27.uuid + '.flag')
1406 self.assertTrue(os.path.exists(flag_path))
1407 copied_path = os.path.join(self.test_root, build_python27.uuid +
1408 '.copied')
1409 self.assertTrue(os.path.exists(copied_path))
1410 failed_path = os.path.join(self.test_root, build_python27.uuid +
1411 '.failed')
1412 self.assertFalse(os.path.exists(failed_path))
1413 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
1414 '.pre.flag')
1415 self.assertTrue(os.path.exists(pre_flag_path))
1416 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
1417 '.post.flag')
1418 self.assertTrue(os.path.exists(post_flag_path))
1419 bare_role_flag_path = os.path.join(self.test_root,
1420 build_python27.uuid +
1421 '.bare-role.flag')
1422 self.assertTrue(os.path.exists(bare_role_flag_path))
1423 secrets_path = os.path.join(self.test_root,
1424 build_python27.uuid + '.secrets')
1425 with open(secrets_path) as f:
1426 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -08001427
Jamie Lennox7655b552017-03-17 12:33:38 +11001428 msg = A.messages[0]
1429 success = "{} https://success.example.com/zuul-logs/{}"
1430 fail = "{} https://failure.example.com/zuul-logs/{}"
1431 self.assertIn(success.format("python27", build_python27.uuid), msg)
1432 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
1433 self.assertIn(success.format("check-vars",
1434 build_check_vars.uuid), msg)
1435 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
1436 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
1437 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +02001438
James E. Blairabbaa6f2017-04-06 16:11:44 -07001439 def _add_job(self, job_name):
1440 conf = textwrap.dedent(
1441 """
1442 - job:
1443 name: %s
1444
1445 - project:
1446 name: org/plugin-project
1447 check:
1448 jobs:
1449 - %s
1450 """ % (job_name, job_name))
1451
1452 file_dict = {'.zuul.yaml': conf}
1453 A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A',
1454 files=file_dict)
1455 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1456 self.waitUntilSettled()
1457
1458 def test_plugins(self):
1459 # Keep the jobdir around so we can inspect contents if an
1460 # assert fails.
1461 self.executor_server.keep_jobdir = True
1462 # Output extra ansible info so we might see errors.
1463 self.executor_server.verbose = True
1464
1465 count = 0
1466 plugin_tests = [
1467 ('passwd', 'FAILURE'),
1468 ('cartesian', 'SUCCESS'),
1469 ('consul_kv', 'FAILURE'),
1470 ('credstash', 'FAILURE'),
1471 ('csvfile_good', 'SUCCESS'),
1472 ('csvfile_bad', 'FAILURE'),
Monty Taylor93ad2212017-08-02 14:59:50 -05001473 ('uri_bad_path', 'FAILURE'),
1474 ('uri_bad_scheme', 'FAILURE'),
Monty Taylor788a40e2017-08-02 16:14:05 -05001475 ('block_local_override', 'FAILURE'),
Monty Taylor8da768f2017-08-31 14:15:35 -05001476 ('file_local_good', 'SUCCESS'),
1477 ('file_local_bad', 'FAILURE'),
James E. Blairabbaa6f2017-04-06 16:11:44 -07001478 ]
1479 for job_name, result in plugin_tests:
1480 count += 1
1481 self._add_job(job_name)
1482
1483 job = self.getJobFromHistory(job_name)
1484 with self.jobLog(job):
1485 self.assertEqual(count, len(self.history))
1486 build = self.history[-1]
1487 self.assertEqual(build.result, result)
1488
1489 # TODOv3(jeblair): parse the ansible output and verify we're
1490 # getting the exception we expect.
1491
James E. Blairb9c0d772017-03-03 14:34:49 -08001492
James E. Blaira4d4eef2017-06-30 14:49:17 -07001493class TestPrePlaybooks(AnsibleZuulTestCase):
1494 # A temporary class to hold new tests while others are disabled
1495
1496 tenant_config_file = 'config/pre-playbook/main.yaml'
1497
1498 def test_pre_playbook_fail(self):
1499 # Test that we run the post playbooks (but not the actual
1500 # playbook) when a pre-playbook fails.
1501 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1502 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1503 self.waitUntilSettled()
1504 build = self.getJobFromHistory('python27')
1505 self.assertIsNone(build.result)
1506 self.assertIn('RETRY_LIMIT', A.messages[0])
1507 flag_path = os.path.join(self.test_root, build.uuid +
1508 '.main.flag')
1509 self.assertFalse(os.path.exists(flag_path))
1510 pre_flag_path = os.path.join(self.test_root, build.uuid +
1511 '.pre.flag')
1512 self.assertFalse(os.path.exists(pre_flag_path))
1513 post_flag_path = os.path.join(self.test_root, build.uuid +
1514 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -07001515 self.assertTrue(os.path.exists(post_flag_path),
1516 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -07001517
1518
James E. Blairbacbb882017-10-17 09:48:23 -07001519class TestPostPlaybooks(AnsibleZuulTestCase):
1520 tenant_config_file = 'config/post-playbook/main.yaml'
1521
1522 def test_post_playbook_abort(self):
1523 # Test that when we abort a job in the post playbook, that we
1524 # don't send back POST_FAILURE.
1525 self.executor_server.verbose = True
1526 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1527 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1528
1529 while not len(self.builds):
1530 time.sleep(0.1)
1531 build = self.builds[0]
1532
1533 post_start = os.path.join(self.test_root, build.uuid +
1534 '.post_start.flag')
1535 start = time.time()
1536 while time.time() < start + 90:
1537 if os.path.exists(post_start):
1538 break
1539 time.sleep(0.1)
1540 # The post playbook has started, abort the job
1541 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1542 self.waitUntilSettled()
1543
1544 build = self.getJobFromHistory('python27')
1545 self.assertEqual('ABORTED', build.result)
1546
1547 post_end = os.path.join(self.test_root, build.uuid +
1548 '.post_end.flag')
1549 self.assertTrue(os.path.exists(post_start))
1550 self.assertFalse(os.path.exists(post_end))
1551
1552
James E. Blairb9c0d772017-03-03 14:34:49 -08001553class TestBrokenConfig(ZuulTestCase):
1554 # Test that we get an appropriate syntax error if we start with a
1555 # broken config.
1556
1557 tenant_config_file = 'config/broken/main.yaml'
1558
1559 def setUp(self):
1560 with testtools.ExpectedException(
1561 zuul.configloader.ConfigurationSyntaxError,
1562 "\nZuul encountered a syntax error"):
1563 super(TestBrokenConfig, self).setUp()
1564
1565 def test_broken_config_on_startup(self):
1566 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001567
1568
1569class TestProjectKeys(ZuulTestCase):
1570 # Test that we can generate project keys
1571
1572 # Normally the test infrastructure copies a static key in place
1573 # for each project before starting tests. This saves time because
1574 # Zuul's automatic key-generation on startup can be slow. To make
1575 # sure we exercise that code, in this test we allow Zuul to create
1576 # keys for the project on startup.
1577 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +02001578 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001579 tenant_config_file = 'config/in-repo/main.yaml'
1580
1581 def test_key_generation(self):
1582 key_root = os.path.join(self.state_root, 'keys')
1583 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
1584 # Make sure that a proper key was created on startup
1585 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -07001586 private_key, public_key = \
1587 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001588
1589 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
1590 fixture_private_key = i.read()
1591
1592 # Make sure that we didn't just end up with the static fixture
1593 # key
1594 self.assertNotEqual(fixture_private_key, private_key)
1595
1596 # Make sure it's the right length
1597 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -07001598
1599
James E. Blairbb94dfa2017-07-11 07:45:19 -07001600class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -07001601 def _assertRolePath(self, build, playbook, content):
1602 path = os.path.join(self.test_root, build.uuid,
1603 'ansible', playbook, 'ansible.cfg')
1604 roles_paths = []
1605 with open(path) as f:
1606 for line in f:
1607 if line.startswith('roles_path'):
1608 roles_paths.append(line)
1609 print(roles_paths)
1610 if content:
1611 self.assertEqual(len(roles_paths), 1,
1612 "Should have one roles_path line in %s" %
1613 (playbook,))
1614 self.assertIn(content, roles_paths[0])
1615 else:
1616 self.assertEqual(len(roles_paths), 0,
1617 "Should have no roles_path line in %s" %
1618 (playbook,))
1619
James E. Blairbb94dfa2017-07-11 07:45:19 -07001620
1621class TestRoles(RoleTestCase):
1622 tenant_config_file = 'config/roles/main.yaml'
1623
James E. Blairbce76932017-05-04 10:03:15 -07001624 def test_role(self):
1625 # This exercises a proposed change to a role being checked out
1626 # and used.
1627 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
1628 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1629 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1630 B.subject, A.data['id'])
1631 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1632 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1633 self.waitUntilSettled()
1634 self.assertHistory([
1635 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
1636 ])
James E. Blair6459db12017-06-29 14:57:20 -07001637
James E. Blair1b27f6a2017-07-14 14:09:07 -07001638 def test_role_inheritance(self):
1639 self.executor_server.hold_jobs_in_build = True
1640 conf = textwrap.dedent(
1641 """
1642 - job:
1643 name: parent
1644 roles:
1645 - zuul: bare-role
1646 pre-run: playbooks/parent-pre
1647 post-run: playbooks/parent-post
1648
1649 - job:
1650 name: project-test
1651 parent: parent
1652 roles:
1653 - zuul: org/project
1654
1655 - project:
1656 name: org/project
1657 check:
1658 jobs:
1659 - project-test
1660 """)
1661
1662 file_dict = {'.zuul.yaml': conf}
1663 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1664 files=file_dict)
1665 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1666 self.waitUntilSettled()
1667
1668 self.assertEqual(len(self.builds), 1)
1669 build = self.getBuildByName('project-test')
1670 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
1671 self._assertRolePath(build, 'playbook_0', 'role_0')
1672 self._assertRolePath(build, 'playbook_0', 'role_1')
1673 self._assertRolePath(build, 'post_playbook_0', 'role_0')
1674
1675 self.executor_server.hold_jobs_in_build = False
1676 self.executor_server.release()
1677 self.waitUntilSettled()
1678
1679 self.assertHistory([
1680 dict(name='project-test', result='SUCCESS', changes='1,1'),
1681 ])
1682
James E. Blair6f699732017-07-18 14:19:11 -07001683 def test_role_error(self):
1684 conf = textwrap.dedent(
1685 """
1686 - job:
1687 name: project-test
1688 roles:
1689 - zuul: common-config
1690
1691 - project:
1692 name: org/project
1693 check:
1694 jobs:
1695 - project-test
1696 """)
1697
1698 file_dict = {'.zuul.yaml': conf}
1699 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1700 files=file_dict)
1701 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1702 self.waitUntilSettled()
1703 self.assertIn(
1704 '- project-test project-test : ERROR Unable to find role',
1705 A.messages[-1])
1706
James E. Blair6459db12017-06-29 14:57:20 -07001707
James E. Blairbb94dfa2017-07-11 07:45:19 -07001708class TestImplicitRoles(RoleTestCase):
1709 tenant_config_file = 'config/implicit-roles/main.yaml'
1710
1711 def test_missing_roles(self):
1712 # Test implicit and explicit roles for a project which does
1713 # not have roles. The implicit role should be silently
1714 # ignored since the project doesn't supply roles, but if a
1715 # user declares an explicit role, it should error.
1716 self.executor_server.hold_jobs_in_build = True
1717 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
1718 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1719 self.waitUntilSettled()
1720
1721 self.assertEqual(len(self.builds), 2)
1722 build = self.getBuildByName('implicit-role-fail')
1723 self._assertRolePath(build, 'playbook_0', None)
1724
1725 self.executor_server.hold_jobs_in_build = False
1726 self.executor_server.release()
1727 self.waitUntilSettled()
1728 # The retry_limit doesn't get recorded
1729 self.assertHistory([
1730 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
1731 ])
1732
1733 def test_roles(self):
1734 # Test implicit and explicit roles for a project which does
1735 # have roles. In both cases, we should end up with the role
1736 # in the path. In the explicit case, ensure we end up with
1737 # the name we specified.
1738 self.executor_server.hold_jobs_in_build = True
1739 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
1740 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1741 self.waitUntilSettled()
1742
1743 self.assertEqual(len(self.builds), 2)
1744 build = self.getBuildByName('implicit-role-ok')
1745 self._assertRolePath(build, 'playbook_0', 'role_0')
1746
1747 build = self.getBuildByName('explicit-role-ok')
1748 self._assertRolePath(build, 'playbook_0', 'role_0')
1749
1750 self.executor_server.hold_jobs_in_build = False
1751 self.executor_server.release()
1752 self.waitUntilSettled()
1753 self.assertHistory([
1754 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
1755 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
1756 ], ordered=False)
1757
1758
James E. Blair6459db12017-06-29 14:57:20 -07001759class TestShadow(ZuulTestCase):
1760 tenant_config_file = 'config/shadow/main.yaml'
1761
1762 def test_shadow(self):
1763 # Test that a repo is allowed to shadow another's job definitions.
1764 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1765 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1766 self.waitUntilSettled()
1767 self.assertHistory([
1768 dict(name='test1', result='SUCCESS', changes='1,1'),
1769 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -07001770 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -07001771
1772
1773class TestDataReturn(AnsibleZuulTestCase):
1774 tenant_config_file = 'config/data-return/main.yaml'
1775
1776 def test_data_return(self):
James E. Blair196f61a2017-06-30 15:42:29 -07001777 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1778 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1779 self.waitUntilSettled()
1780 self.assertHistory([
1781 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07001782 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
James E. Blair698703c2017-09-15 20:58:30 -06001783 dict(name='child', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07001784 ], ordered=False)
1785 self.assertIn('- data-return http://example.com/test/log/url/',
1786 A.messages[-1])
1787 self.assertIn('- data-return-relative '
1788 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -07001789 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -07001790
1791
1792class TestDiskAccounting(AnsibleZuulTestCase):
1793 config_file = 'zuul-disk-accounting.conf'
1794 tenant_config_file = 'config/disk-accountant/main.yaml'
1795
1796 def test_disk_accountant_kills_job(self):
1797 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1798 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1799 self.waitUntilSettled()
1800 self.assertHistory([
1801 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001802
1803
1804class TestMaxNodesPerJob(AnsibleZuulTestCase):
1805 tenant_config_file = 'config/multi-tenant/main.yaml'
1806
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00001807 def test_max_timeout_exceeded(self):
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001808 in_repo_conf = textwrap.dedent(
1809 """
1810 - job:
1811 name: test-job
James E. Blair7e3e6882017-09-20 15:47:13 -07001812 nodeset:
1813 nodes:
1814 - name: node01
1815 label: fake
1816 - name: node02
1817 label: fake
1818 - name: node03
1819 label: fake
1820 - name: node04
1821 label: fake
1822 - name: node05
1823 label: fake
1824 - name: node06
1825 label: fake
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001826 """)
1827 file_dict = {'.zuul.yaml': in_repo_conf}
1828 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1829 files=file_dict)
1830 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1831 self.waitUntilSettled()
1832 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
1833 A.messages[0], "A should fail because of nodes limit")
1834
1835 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
1836 files=file_dict)
1837 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1838 self.waitUntilSettled()
1839 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
1840 "B should not fail because of nodes limit")
James E. Blair2bab6e72017-08-07 09:52:45 -07001841
1842
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00001843class TestMaxTimeout(AnsibleZuulTestCase):
1844 tenant_config_file = 'config/multi-tenant/main.yaml'
1845
1846 def test_max_nodes_reached(self):
1847 in_repo_conf = textwrap.dedent(
1848 """
1849 - job:
1850 name: test-job
1851 timeout: 3600
1852 """)
1853 file_dict = {'.zuul.yaml': in_repo_conf}
1854 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1855 files=file_dict)
1856 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1857 self.waitUntilSettled()
1858 self.assertIn('The job "test-job" exceeds tenant max-job-timeout',
1859 A.messages[0], "A should fail because of timeout limit")
1860
1861 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
1862 files=file_dict)
1863 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1864 self.waitUntilSettled()
1865 self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0],
1866 "B should not fail because of timeout limit")
1867
1868
James E. Blair2bab6e72017-08-07 09:52:45 -07001869class TestBaseJobs(ZuulTestCase):
1870 tenant_config_file = 'config/base-jobs/main.yaml'
1871
1872 def test_multiple_base_jobs(self):
1873 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1874 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1875 self.waitUntilSettled()
1876 self.assertHistory([
1877 dict(name='my-job', result='SUCCESS', changes='1,1'),
1878 dict(name='other-job', result='SUCCESS', changes='1,1'),
1879 ], ordered=False)
1880 self.assertEqual(self.getJobFromHistory('my-job').
1881 parameters['zuul']['jobtags'],
1882 ['mybase'])
1883 self.assertEqual(self.getJobFromHistory('other-job').
1884 parameters['zuul']['jobtags'],
1885 ['otherbase'])
1886
1887 def test_untrusted_base_job(self):
1888 """Test that a base job may not be defined in an untrusted repo"""
1889 in_repo_conf = textwrap.dedent(
1890 """
1891 - job:
1892 name: fail-base
1893 parent: null
1894 """)
1895
1896 file_dict = {'.zuul.yaml': in_repo_conf}
1897 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1898 files=file_dict)
1899 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1900 self.waitUntilSettled()
1901 self.assertEqual(A.reported, 1,
1902 "A should report failure")
1903 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
1904 self.assertIn('Base jobs must be defined in config projects',
1905 A.messages[0])
1906 self.assertHistory([])
James E. Blairdb089032017-08-15 13:42:12 -07001907
1908
1909class TestSecretLeaks(AnsibleZuulTestCase):
1910 tenant_config_file = 'config/secret-leaks/main.yaml'
1911
1912 def searchForContent(self, path, content):
1913 matches = []
1914 for (dirpath, dirnames, filenames) in os.walk(path):
1915 for filename in filenames:
1916 filepath = os.path.join(dirpath, filename)
1917 with open(filepath, 'rb') as f:
1918 if content in f.read():
1919 matches.append(filepath[len(path):])
1920 return matches
1921
1922 def _test_secret_file(self):
1923 # Or rather -- test that they *don't* leak.
1924 # Keep the jobdir around so we can inspect contents.
1925 self.executor_server.keep_jobdir = True
1926 conf = textwrap.dedent(
1927 """
1928 - project:
1929 name: org/project
1930 check:
1931 jobs:
1932 - secret-file
1933 """)
1934
1935 file_dict = {'.zuul.yaml': conf}
1936 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1937 files=file_dict)
1938 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1939 self.waitUntilSettled()
1940 self.assertHistory([
1941 dict(name='secret-file', result='SUCCESS', changes='1,1'),
1942 ], ordered=False)
1943 matches = self.searchForContent(self.history[0].jobdir.root,
1944 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07001945 self.assertEqual(set(['/work/secret-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07001946 set(matches))
1947
1948 def test_secret_file(self):
1949 self._test_secret_file()
1950
1951 def test_secret_file_verbose(self):
1952 # Output extra ansible info to exercise alternate logging code
1953 # paths.
1954 self.executor_server.verbose = True
1955 self._test_secret_file()
1956
1957 def _test_secret_file_fail(self):
1958 # Or rather -- test that they *don't* leak.
1959 # Keep the jobdir around so we can inspect contents.
1960 self.executor_server.keep_jobdir = True
1961 conf = textwrap.dedent(
1962 """
1963 - project:
1964 name: org/project
1965 check:
1966 jobs:
1967 - secret-file-fail
1968 """)
1969
1970 file_dict = {'.zuul.yaml': conf}
1971 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1972 files=file_dict)
1973 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1974 self.waitUntilSettled()
1975 self.assertHistory([
1976 dict(name='secret-file-fail', result='FAILURE', changes='1,1'),
1977 ], ordered=False)
1978 matches = self.searchForContent(self.history[0].jobdir.root,
1979 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07001980 self.assertEqual(set(['/work/failure-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07001981 set(matches))
1982
1983 def test_secret_file_fail(self):
1984 self._test_secret_file_fail()
1985
1986 def test_secret_file_fail_verbose(self):
1987 # Output extra ansible info to exercise alternate logging code
1988 # paths.
1989 self.executor_server.verbose = True
1990 self._test_secret_file_fail()
James E. Blaira00910c2017-08-23 09:15:04 -07001991
1992
1993class TestJobOutput(AnsibleZuulTestCase):
1994 tenant_config_file = 'config/job-output/main.yaml'
1995
1996 def _get_file(self, build, path):
1997 p = os.path.join(build.jobdir.root, path)
1998 with open(p) as f:
1999 return f.read()
2000
2001 def test_job_output(self):
Monty Taylor0e2489a2017-10-10 11:57:29 -05002002 # Verify that command standard output appears in the job output,
2003 # and that failures in the final playbook get logged.
James E. Blaira00910c2017-08-23 09:15:04 -07002004
2005 # This currently only verifies we receive output from
2006 # localhost. Notably, it does not verify we receive output
2007 # via zuul_console streaming.
2008 self.executor_server.keep_jobdir = True
2009 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2010 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2011 self.waitUntilSettled()
2012 self.assertHistory([
2013 dict(name='job-output', result='SUCCESS', changes='1,1'),
2014 ], ordered=False)
2015
2016 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2017 j = json.loads(self._get_file(self.history[0],
2018 'work/logs/job-output.json'))
2019 self.assertEqual(token,
2020 j[0]['plays'][0]['tasks'][0]
2021 ['hosts']['localhost']['stdout'])
2022
2023 print(self._get_file(self.history[0],
2024 'work/logs/job-output.txt'))
2025 self.assertIn(token,
2026 self._get_file(self.history[0],
2027 'work/logs/job-output.txt'))
Monty Taylor0e2489a2017-10-10 11:57:29 -05002028
2029 def test_job_output_failure_log(self):
2030 logger = logging.getLogger('zuul.AnsibleJob')
2031 output = io.StringIO()
2032 logger.addHandler(logging.StreamHandler(output))
2033
2034 # Verify that a failure in the last post playbook emits the contents
2035 # of the json output to the log
2036 self.executor_server.keep_jobdir = True
2037 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
2038 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2039 self.waitUntilSettled()
2040 self.assertHistory([
2041 dict(name='job-output-failure',
2042 result='POST_FAILURE', changes='1,1'),
2043 ], ordered=False)
2044
2045 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2046 j = json.loads(self._get_file(self.history[0],
2047 'work/logs/job-output.json'))
2048 self.assertEqual(token,
2049 j[0]['plays'][0]['tasks'][0]
2050 ['hosts']['localhost']['stdout'])
2051
2052 print(self._get_file(self.history[0],
2053 'work/logs/job-output.json'))
2054 self.assertIn(token,
2055 self._get_file(self.history[0],
2056 'work/logs/job-output.txt'))
2057
2058 log_output = output.getvalue()
2059 self.assertIn('Final playbook failed', log_output)
2060 self.assertIn('Failure test', log_output)