blob: bfb908873c55c1f5b7299f244cc2ef686bba7566 [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
23from unittest import skip
James E. Blair59fdbac2015-12-07 17:08:06 -080024
James E. Blairb9c0d772017-03-03 14:34:49 -080025import testtools
26
27import zuul.configloader
James E. Blairbf1a4f22017-03-17 10:59:37 -070028from zuul.lib import encryption
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +000029from tests.base import AnsibleZuulTestCase, ZuulTestCase, FIXTURE_DIR
James E. Blair59fdbac2015-12-07 17:08:06 -080030
James E. Blair59fdbac2015-12-07 17:08:06 -080031
James E. Blair3f876d52016-07-22 13:07:14 -070032class TestMultipleTenants(AnsibleZuulTestCase):
James E. Blair59fdbac2015-12-07 17:08:06 -080033 # A temporary class to hold new tests while others are disabled
34
James E. Blair2a629ec2015-12-22 15:32:02 -080035 tenant_config_file = 'config/multi-tenant/main.yaml'
James E. Blair59fdbac2015-12-07 17:08:06 -080036
James E. Blair83005782015-12-11 14:46:03 -080037 def test_multiple_tenants(self):
James E. Blair96f26942015-12-09 10:15:59 -080038 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +020039 A.addApproval('Code-Review', 2)
40 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair59fdbac2015-12-07 17:08:06 -080041 self.waitUntilSettled()
James E. Blair96f26942015-12-09 10:15:59 -080042 self.assertEqual(self.getJobFromHistory('project1-test1').result,
James E. Blair59fdbac2015-12-07 17:08:06 -080043 'SUCCESS')
James E. Blair96c6bf82016-01-15 16:20:40 -080044 self.assertEqual(self.getJobFromHistory('python27').result,
45 'SUCCESS')
James E. Blair59fdbac2015-12-07 17:08:06 -080046 self.assertEqual(A.data['status'], 'MERGED')
James E. Blair96f26942015-12-09 10:15:59 -080047 self.assertEqual(A.reported, 2,
48 "A should report start and success")
49 self.assertIn('tenant-one-gate', A.messages[1],
50 "A should transit tenant-one gate")
51 self.assertNotIn('tenant-two-gate', A.messages[1],
52 "A should *not* transit tenant-two gate")
James E. Blair59fdbac2015-12-07 17:08:06 -080053
James E. Blair96f26942015-12-09 10:15:59 -080054 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +020055 B.addApproval('Code-Review', 2)
56 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair96f26942015-12-09 10:15:59 -080057 self.waitUntilSettled()
James E. Blair96c6bf82016-01-15 16:20:40 -080058 self.assertEqual(self.getJobFromHistory('python27',
59 'org/project2').result,
60 'SUCCESS')
James E. Blair96f26942015-12-09 10:15:59 -080061 self.assertEqual(self.getJobFromHistory('project2-test1').result,
62 'SUCCESS')
63 self.assertEqual(B.data['status'], 'MERGED')
64 self.assertEqual(B.reported, 2,
65 "B should report start and success")
66 self.assertIn('tenant-two-gate', B.messages[1],
67 "B should transit tenant-two gate")
68 self.assertNotIn('tenant-one-gate', B.messages[1],
69 "B should *not* transit tenant-one gate")
James E. Blair59fdbac2015-12-07 17:08:06 -080070
James E. Blair96f26942015-12-09 10:15:59 -080071 self.assertEqual(A.reported, 2, "Activity in tenant two should"
72 "not affect tenant one")
James E. Blair14abdf42015-12-09 16:11:53 -080073
James E. Blair83005782015-12-11 14:46:03 -080074
Tobias Henkel83167622017-06-30 19:45:03 +020075class TestFinal(ZuulTestCase):
76
77 tenant_config_file = 'config/final/main.yaml'
78
79 def test_final_variant_ok(self):
80 # test clean usage of final parent job
81 in_repo_conf = textwrap.dedent(
82 """
83 - project:
84 name: org/project
85 check:
86 jobs:
87 - job-final
88 """)
89
90 file_dict = {'.zuul.yaml': in_repo_conf}
91 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
92 files=file_dict)
93 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
94 self.waitUntilSettled()
95
96 self.assertEqual(A.reported, 1)
97 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1')
98
99 def test_final_variant_error(self):
100 # test misuse of final parent job
101 in_repo_conf = textwrap.dedent(
102 """
103 - project:
104 name: org/project
105 check:
106 jobs:
107 - job-final:
108 vars:
109 dont_override_this: bar
110 """)
111 file_dict = {'.zuul.yaml': in_repo_conf}
112 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
113 files=file_dict)
114 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
115 self.waitUntilSettled()
116
117 # The second patch tried to override some variables.
118 # Thus it should fail.
119 self.assertEqual(A.reported, 1)
120 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
121 self.assertIn('Unable to modify final job', A.messages[0])
122
123 def test_final_inheritance(self):
124 # test misuse of final parent job
125 in_repo_conf = textwrap.dedent(
126 """
127 - job:
128 name: project-test
129 parent: job-final
130
131 - project:
132 name: org/project
133 check:
134 jobs:
135 - project-test
136 """)
137
138 in_repo_playbook = textwrap.dedent(
139 """
140 - hosts: all
141 tasks: []
142 """)
143
144 file_dict = {'.zuul.yaml': in_repo_conf,
145 'playbooks/project-test.yaml': in_repo_playbook}
146 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
147 files=file_dict)
148 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
149 self.waitUntilSettled()
150
151 # The second patch tried to override some variables.
152 # Thus it should fail.
153 self.assertEqual(A.reported, 1)
154 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
155 self.assertIn('Unable to inherit from final job', A.messages[0])
156
157
James E. Blair09998792017-10-15 18:02:18 -0700158class TestBranchVariants(ZuulTestCase):
159 tenant_config_file = 'config/branch-variants/main.yaml'
160
161 def test_branch_variants(self):
162 # Test branch variants of jobs with inheritance
163 self.executor_server.hold_jobs_in_build = True
164 # This creates a new branch with a copy of the config in master
165 self.create_branch('puppet-integration', 'stable')
166 self.fake_gerrit.addEvent(
167 self.fake_gerrit.getFakeBranchCreatedEvent(
168 'puppet-integration', 'stable'))
169 self.waitUntilSettled()
170
171 A = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'A')
172 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
173 self.waitUntilSettled()
174
175 self.assertEqual(len(self.builds[0].parameters['pre_playbooks']), 3)
176 self.executor_server.hold_jobs_in_build = False
177 self.executor_server.release()
178 self.waitUntilSettled()
179
180
James E. Blairff555742017-02-19 11:34:27 -0800181class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -0800182 # A temporary class to hold new tests while others are disabled
183
Tobias Henkelabf973e2017-07-28 10:07:34 +0200184 config_file = 'zuul-connections-gerrit-and-github.conf'
James E. Blair2a629ec2015-12-22 15:32:02 -0800185 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -0800186
James E. Blair83005782015-12-11 14:46:03 -0800187 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -0800188 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200189 A.addApproval('Code-Review', 2)
190 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -0800191 self.waitUntilSettled()
192 self.assertEqual(self.getJobFromHistory('project-test1').result,
193 'SUCCESS')
194 self.assertEqual(A.data['status'], 'MERGED')
195 self.assertEqual(A.reported, 2,
196 "A should report start and success")
197 self.assertIn('tenant-one-gate', A.messages[1],
198 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -0800199
James E. Blair3a098dd2017-10-04 14:37:29 -0700200 @skip("This test is useful, but not reliable")
201 def test_full_and_dynamic_reconfig(self):
202 self.executor_server.hold_jobs_in_build = True
203 in_repo_conf = textwrap.dedent(
204 """
205 - job:
206 name: project-test1
207
208 - project:
209 name: org/project
210 tenant-one-gate:
211 jobs:
212 - project-test1
213 """)
214
215 file_dict = {'.zuul.yaml': in_repo_conf}
216 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
217 files=file_dict)
218 A.addApproval('Code-Review', 2)
219 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
220 self.waitUntilSettled()
221 self.sched.reconfigure(self.config)
222 self.waitUntilSettled()
223
224 gc.collect()
225 pipelines = [obj for obj in gc.get_objects()
226 if isinstance(obj, zuul.model.Pipeline)]
227 self.assertEqual(len(pipelines), 4)
228
229 self.executor_server.hold_jobs_in_build = False
230 self.executor_server.release()
231 self.waitUntilSettled()
232
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700233 def test_dynamic_config(self):
234 in_repo_conf = textwrap.dedent(
235 """
236 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200237 name: project-test1
238
239 - job:
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700240 name: project-test2
241
242 - project:
243 name: org/project
244 tenant-one-gate:
245 jobs:
246 - project-test2
247 """)
248
James E. Blairc73c73a2017-01-20 15:15:15 -0800249 in_repo_playbook = textwrap.dedent(
250 """
251 - hosts: all
252 tasks: []
253 """)
254
255 file_dict = {'.zuul.yaml': in_repo_conf,
256 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700257 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800258 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200259 A.addApproval('Code-Review', 2)
260 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700261 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700262 self.assertEqual(A.data['status'], 'MERGED')
263 self.assertEqual(A.reported, 2,
264 "A should report start and success")
265 self.assertIn('tenant-one-gate', A.messages[1],
266 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800267 self.assertHistory([
268 dict(name='project-test2', result='SUCCESS', changes='1,1')])
269
James E. Blairc2a5ed72017-02-20 14:12:01 -0500270 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800271 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500272
James E. Blair646322f2017-01-27 15:50:34 -0800273 # Now that the config change is landed, it should be live for
274 # subsequent changes.
275 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200276 B.addApproval('Code-Review', 2)
277 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair646322f2017-01-27 15:50:34 -0800278 self.waitUntilSettled()
279 self.assertEqual(self.getJobFromHistory('project-test2').result,
280 'SUCCESS')
281 self.assertHistory([
282 dict(name='project-test2', result='SUCCESS', changes='1,1'),
283 dict(name='project-test2', result='SUCCESS', changes='2,1')])
James E. Blairc73c73a2017-01-20 15:15:15 -0800284
Tobias Henkelf02cf512017-07-21 22:55:34 +0200285 def test_dynamic_config_non_existing_job(self):
286 """Test that requesting a non existent job fails"""
287 in_repo_conf = textwrap.dedent(
288 """
289 - job:
290 name: project-test1
291
292 - project:
293 name: org/project
294 check:
295 jobs:
296 - non-existent-job
297 """)
298
299 in_repo_playbook = textwrap.dedent(
300 """
301 - hosts: all
302 tasks: []
303 """)
304
305 file_dict = {'.zuul.yaml': in_repo_conf,
306 'playbooks/project-test2.yaml': in_repo_playbook}
307 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
308 files=file_dict)
309 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
310 self.waitUntilSettled()
311 self.assertEqual(A.reported, 1,
312 "A should report failure")
313 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
314 self.assertIn('Job non-existent-job not defined', A.messages[0],
315 "A should have failed the check pipeline")
316 self.assertHistory([])
317
318 def test_dynamic_config_non_existing_job_in_template(self):
319 """Test that requesting a non existent job fails"""
320 in_repo_conf = textwrap.dedent(
321 """
322 - job:
323 name: project-test1
324
325 - project-template:
326 name: test-template
327 check:
328 jobs:
329 - non-existent-job
330
331 - project:
332 name: org/project
333 templates:
334 - test-template
335 """)
336
337 in_repo_playbook = textwrap.dedent(
338 """
339 - hosts: all
340 tasks: []
341 """)
342
343 file_dict = {'.zuul.yaml': in_repo_conf,
344 'playbooks/project-test2.yaml': in_repo_playbook}
345 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
346 files=file_dict)
347 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
348 self.waitUntilSettled()
349 self.assertEqual(A.reported, 1,
350 "A should report failure")
351 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
352 self.assertIn('Job non-existent-job not defined', A.messages[0],
353 "A should have failed the check pipeline")
354 self.assertHistory([])
355
Tobias Henkel0f714002017-06-30 23:30:52 +0200356 def test_dynamic_config_new_patchset(self):
357 self.executor_server.hold_jobs_in_build = True
358
359 tenant = self.sched.abide.tenants.get('tenant-one')
360 check_pipeline = tenant.layout.pipelines['check']
361
362 in_repo_conf = textwrap.dedent(
363 """
364 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200365 name: project-test1
366
367 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200368 name: project-test2
369
370 - project:
371 name: org/project
372 check:
373 jobs:
374 - project-test2
375 """)
376
377 in_repo_playbook = textwrap.dedent(
378 """
379 - hosts: all
380 tasks: []
381 """)
382
383 file_dict = {'.zuul.yaml': in_repo_conf,
384 'playbooks/project-test2.yaml': in_repo_playbook}
385 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
386 files=file_dict)
387 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
388 self.waitUntilSettled()
389
390 items = check_pipeline.getAllItems()
391 self.assertEqual(items[0].change.number, '1')
392 self.assertEqual(items[0].change.patchset, '1')
393 self.assertTrue(items[0].live)
394
395 in_repo_conf = textwrap.dedent(
396 """
397 - job:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200398 name: project-test1
399
400 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200401 name: project-test2
402
403 - project:
404 name: org/project
405 check:
406 jobs:
407 - project-test1
408 - project-test2
409 """)
410 file_dict = {'.zuul.yaml': in_repo_conf,
411 'playbooks/project-test2.yaml': in_repo_playbook}
412
413 A.addPatchset(files=file_dict)
414 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
415
416 self.waitUntilSettled()
417
418 items = check_pipeline.getAllItems()
419 self.assertEqual(items[0].change.number, '1')
420 self.assertEqual(items[0].change.patchset, '2')
421 self.assertTrue(items[0].live)
422
423 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200424 self.executor_server.release('project-test1')
425 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +0200426 self.executor_server.release()
427 self.waitUntilSettled()
428
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200429 self.assertHistory([
430 dict(name='project-test2', result='ABORTED', changes='1,1'),
431 dict(name='project-test1', result='SUCCESS', changes='1,2'),
432 dict(name='project-test2', result='SUCCESS', changes='1,2')])
433
James E. Blairff555742017-02-19 11:34:27 -0800434 def test_in_repo_branch(self):
435 in_repo_conf = textwrap.dedent(
436 """
437 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200438 name: project-test1
439
440 - job:
James E. Blairff555742017-02-19 11:34:27 -0800441 name: project-test2
442
443 - project:
444 name: org/project
445 tenant-one-gate:
446 jobs:
447 - project-test2
448 """)
449
450 in_repo_playbook = textwrap.dedent(
451 """
452 - hosts: all
453 tasks: []
454 """)
455
456 file_dict = {'.zuul.yaml': in_repo_conf,
457 'playbooks/project-test2.yaml': in_repo_playbook}
458 self.create_branch('org/project', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700459 self.fake_gerrit.addEvent(
460 self.fake_gerrit.getFakeBranchCreatedEvent(
461 'org/project', 'stable'))
James E. Blair6069f2b2017-09-26 16:34:11 -0700462 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800463 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
464 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200465 A.addApproval('Code-Review', 2)
466 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800467 self.waitUntilSettled()
468 self.assertEqual(A.data['status'], 'MERGED')
469 self.assertEqual(A.reported, 2,
470 "A should report start and success")
471 self.assertIn('tenant-one-gate', A.messages[1],
472 "A should transit tenant-one gate")
473 self.assertHistory([
474 dict(name='project-test2', result='SUCCESS', changes='1,1')])
475 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800476 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800477
478 # The config change should not affect master.
479 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200480 B.addApproval('Code-Review', 2)
481 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800482 self.waitUntilSettled()
483 self.assertHistory([
484 dict(name='project-test2', result='SUCCESS', changes='1,1'),
485 dict(name='project-test1', result='SUCCESS', changes='2,1')])
486
487 # The config change should be live for further changes on
488 # stable.
489 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200490 C.addApproval('Code-Review', 2)
491 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800492 self.waitUntilSettled()
493 self.assertHistory([
494 dict(name='project-test2', result='SUCCESS', changes='1,1'),
495 dict(name='project-test1', result='SUCCESS', changes='2,1'),
496 dict(name='project-test2', result='SUCCESS', changes='3,1')])
497
James E. Blaira5a12492017-05-03 11:40:48 -0700498 def test_crd_dynamic_config_branch(self):
499 # Test that we can create a job in one repo and be able to use
500 # it from a different branch on a different repo.
501
502 self.create_branch('org/project1', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700503 self.fake_gerrit.addEvent(
504 self.fake_gerrit.getFakeBranchCreatedEvent(
505 'org/project1', 'stable'))
James E. Blaira5a12492017-05-03 11:40:48 -0700506
507 in_repo_conf = textwrap.dedent(
508 """
509 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200510 name: project-test1
511
512 - job:
James E. Blaira5a12492017-05-03 11:40:48 -0700513 name: project-test2
514
515 - project:
516 name: org/project
517 check:
518 jobs:
519 - project-test2
520 """)
521
522 in_repo_playbook = textwrap.dedent(
523 """
524 - hosts: all
525 tasks: []
526 """)
527
528 file_dict = {'.zuul.yaml': in_repo_conf,
529 'playbooks/project-test2.yaml': in_repo_playbook}
530 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
531 files=file_dict)
532
533 second_repo_conf = textwrap.dedent(
534 """
535 - project:
536 name: org/project1
537 check:
538 jobs:
539 - project-test2
540 """)
541
542 second_file_dict = {'.zuul.yaml': second_repo_conf}
543 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
544 files=second_file_dict)
545 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
546 B.subject, A.data['id'])
547
548 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
549 self.waitUntilSettled()
550 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
551 self.waitUntilSettled()
552
553 self.assertEqual(A.reported, 1, "A should report")
554 self.assertHistory([
555 dict(name='project-test2', result='SUCCESS', changes='1,1'),
556 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
557 ])
558
James E. Blair97043882017-09-06 15:51:17 -0700559 def test_yaml_list_error(self):
560 in_repo_conf = textwrap.dedent(
561 """
562 job: foo
563 """)
564
565 file_dict = {'.zuul.yaml': in_repo_conf}
566 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
567 files=file_dict)
568 A.addApproval('Code-Review', 2)
569 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
570 self.waitUntilSettled()
571
572 self.assertEqual(A.data['status'], 'NEW')
573 self.assertEqual(A.reported, 1,
574 "A should report failure")
575 self.assertIn('not a list', A.messages[0],
576 "A should have a syntax error reported")
577
578 def test_yaml_dict_error(self):
579 in_repo_conf = textwrap.dedent(
580 """
581 - job
582 """)
583
584 file_dict = {'.zuul.yaml': in_repo_conf}
585 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
586 files=file_dict)
587 A.addApproval('Code-Review', 2)
588 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
589 self.waitUntilSettled()
590
591 self.assertEqual(A.data['status'], 'NEW')
592 self.assertEqual(A.reported, 1,
593 "A should report failure")
594 self.assertIn('not a dictionary', A.messages[0],
595 "A should have a syntax error reported")
596
597 def test_yaml_key_error(self):
598 in_repo_conf = textwrap.dedent(
599 """
600 - job:
601 name: project-test2
602 """)
603
604 file_dict = {'.zuul.yaml': in_repo_conf}
605 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
606 files=file_dict)
607 A.addApproval('Code-Review', 2)
608 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
609 self.waitUntilSettled()
610
611 self.assertEqual(A.data['status'], 'NEW')
612 self.assertEqual(A.reported, 1,
613 "A should report failure")
614 self.assertIn('has more than one key', A.messages[0],
615 "A should have a syntax error reported")
616
617 def test_yaml_unknown_error(self):
618 in_repo_conf = textwrap.dedent(
619 """
620 - foobar:
621 foo: bar
622 """)
623
624 file_dict = {'.zuul.yaml': in_repo_conf}
625 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
626 files=file_dict)
627 A.addApproval('Code-Review', 2)
628 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
629 self.waitUntilSettled()
630
631 self.assertEqual(A.data['status'], 'NEW')
632 self.assertEqual(A.reported, 1,
633 "A should report failure")
634 self.assertIn('not recognized', A.messages[0],
635 "A should have a syntax error reported")
636
James E. Blair149b69c2017-03-02 10:48:16 -0800637 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -0800638 in_repo_conf = textwrap.dedent(
639 """
640 - job:
641 name: project-test2
642 foo: error
643 """)
644
645 file_dict = {'.zuul.yaml': in_repo_conf}
646 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
647 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200648 A.addApproval('Code-Review', 2)
649 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -0800650 self.waitUntilSettled()
651
652 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200653 self.assertEqual(A.reported, 1,
654 "A should report failure")
655 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -0800656 "A should have a syntax error reported")
657
James E. Blair149b69c2017-03-02 10:48:16 -0800658 def test_trusted_syntax_error(self):
659 in_repo_conf = textwrap.dedent(
660 """
661 - job:
662 name: project-test2
663 foo: error
664 """)
665
666 file_dict = {'zuul.yaml': in_repo_conf}
667 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
668 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200669 A.addApproval('Code-Review', 2)
670 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -0800671 self.waitUntilSettled()
672
673 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200674 self.assertEqual(A.reported, 1,
675 "A should report failure")
676 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -0800677 "A should have a syntax error reported")
678
James E. Blair6f140c72017-03-03 10:32:07 -0800679 def test_untrusted_yaml_error(self):
680 in_repo_conf = textwrap.dedent(
681 """
682 - job:
683 foo: error
684 """)
685
686 file_dict = {'.zuul.yaml': in_repo_conf}
687 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
688 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200689 A.addApproval('Code-Review', 2)
690 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -0800691 self.waitUntilSettled()
692
693 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200694 self.assertEqual(A.reported, 1,
695 "A should report failure")
696 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -0800697 "A should have a syntax error reported")
698
James E. Blairdb04e6a2017-05-03 14:49:36 -0700699 def test_untrusted_shadow_error(self):
700 in_repo_conf = textwrap.dedent(
701 """
702 - job:
703 name: common-config-test
704 """)
705
706 file_dict = {'.zuul.yaml': in_repo_conf}
707 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
708 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200709 A.addApproval('Code-Review', 2)
710 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -0700711 self.waitUntilSettled()
712
713 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200714 self.assertEqual(A.reported, 1,
715 "A should report failure")
716 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -0700717 "A should have a syntax error reported")
718
James E. Blaird5656ad2017-06-02 14:29:41 -0700719 def test_untrusted_pipeline_error(self):
720 in_repo_conf = textwrap.dedent(
721 """
722 - pipeline:
723 name: test
724 """)
725
726 file_dict = {'.zuul.yaml': in_repo_conf}
727 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
728 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200729 A.addApproval('Code-Review', 2)
730 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700731 self.waitUntilSettled()
732
733 self.assertEqual(A.data['status'], 'NEW')
734 self.assertEqual(A.reported, 1,
735 "A should report failure")
736 self.assertIn('Pipelines may not be defined', A.messages[0],
737 "A should have a syntax error reported")
738
739 def test_untrusted_project_error(self):
740 in_repo_conf = textwrap.dedent(
741 """
742 - project:
743 name: org/project1
744 """)
745
746 file_dict = {'.zuul.yaml': in_repo_conf}
747 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
748 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200749 A.addApproval('Code-Review', 2)
750 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700751 self.waitUntilSettled()
752
753 self.assertEqual(A.data['status'], 'NEW')
754 self.assertEqual(A.reported, 1,
755 "A should report failure")
756 self.assertIn('the only project definition permitted', A.messages[0],
757 "A should have a syntax error reported")
758
James E. Blairf03173b2017-10-10 10:46:43 -0700759 def test_untrusted_depends_on_trusted(self):
760 with open(os.path.join(FIXTURE_DIR,
761 'config/in-repo/git/',
762 'common-config/zuul.yaml')) as f:
763 common_config = f.read()
764
765 common_config += textwrap.dedent(
766 """
767 - job:
768 name: project-test9
769 """)
770
771 file_dict = {'zuul.yaml': common_config}
772 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
773 files=file_dict)
774 in_repo_conf = textwrap.dedent(
775 """
776 - job:
777 name: project-test1
778 - project:
779 name: org/project
780 check:
781 jobs:
782 - project-test9
783 """)
784
785 file_dict = {'zuul.yaml': in_repo_conf}
786 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
787 files=file_dict)
788 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
789 B.subject, A.data['id'])
790 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
791 self.waitUntilSettled()
792
793 self.assertEqual(B.data['status'], 'NEW')
794 self.assertEqual(B.reported, 1,
795 "B should report failure")
796 self.assertIn('depends on a change to a config project',
797 B.messages[0],
798 "A should have a syntax error reported")
799
James E. Blaire64b0e42017-06-08 11:23:34 -0700800 def test_duplicate_node_error(self):
801 in_repo_conf = textwrap.dedent(
802 """
803 - nodeset:
804 name: duplicate
805 nodes:
806 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700807 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700808 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700809 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700810 """)
811
812 file_dict = {'.zuul.yaml': in_repo_conf}
813 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
814 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200815 A.addApproval('Code-Review', 2)
816 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700817 self.waitUntilSettled()
818
819 self.assertEqual(A.data['status'], 'NEW')
820 self.assertEqual(A.reported, 1,
821 "A should report failure")
822 self.assertIn('appears multiple times', A.messages[0],
823 "A should have a syntax error reported")
824
825 def test_duplicate_group_error(self):
826 in_repo_conf = textwrap.dedent(
827 """
828 - nodeset:
829 name: duplicate
830 nodes:
831 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700832 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700833 groups:
834 - name: group
835 nodes: compute
836 - name: group
837 nodes: compute
838 """)
839
840 file_dict = {'.zuul.yaml': in_repo_conf}
841 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
842 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200843 A.addApproval('Code-Review', 2)
844 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700845 self.waitUntilSettled()
846
847 self.assertEqual(A.data['status'], 'NEW')
848 self.assertEqual(A.reported, 1,
849 "A should report failure")
850 self.assertIn('appears multiple times', A.messages[0],
851 "A should have a syntax error reported")
852
James E. Blair4ae399f2017-09-20 17:15:09 -0700853 def test_secret_not_found_error(self):
854 in_repo_conf = textwrap.dedent(
855 """
856 - job:
857 name: test
858 secrets: does-not-exist
859 """)
860
861 file_dict = {'.zuul.yaml': in_repo_conf}
862 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
863 files=file_dict)
864 A.addApproval('Code-Review', 2)
865 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
866 self.waitUntilSettled()
867
868 self.assertEqual(A.data['status'], 'NEW')
869 self.assertEqual(A.reported, 1,
870 "A should report failure")
871 self.assertIn('secret "does-not-exist" was not found', A.messages[0],
872 "A should have a syntax error reported")
873
874 def test_nodeset_not_found_error(self):
875 in_repo_conf = textwrap.dedent(
876 """
877 - job:
878 name: test
879 nodeset: does-not-exist
880 """)
881
882 file_dict = {'.zuul.yaml': in_repo_conf}
883 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
884 files=file_dict)
885 A.addApproval('Code-Review', 2)
886 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
887 self.waitUntilSettled()
888
889 self.assertEqual(A.data['status'], 'NEW')
890 self.assertEqual(A.reported, 1,
891 "A should report failure")
892 self.assertIn('nodeset "does-not-exist" was not found', A.messages[0],
893 "A should have a syntax error reported")
894
James E. Blair89e25eb2017-09-26 09:11:31 -0700895 def test_template_not_found_error(self):
896 in_repo_conf = textwrap.dedent(
897 """
898 - job:
899 name: project-test1
900 - project:
901 name: org/project
902 templates:
903 - does-not-exist
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('project template "does-not-exist" was not found',
917 A.messages[0],
918 "A should have a syntax error reported")
919
Monty Taylor8be3c0c2017-10-06 10:37:37 -0500920 def test_job_list_in_project_template_not_dict_error(self):
921 in_repo_conf = textwrap.dedent(
922 """
923 - job:
924 name: project-test1
925 - project-template:
926 name: some-jobs
927 check:
928 jobs:
929 - project-test1:
930 - required-projects:
931 org/project2
932 """)
933
934 file_dict = {'.zuul.yaml': in_repo_conf}
935 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
936 files=file_dict)
937 A.addApproval('Code-Review', 2)
938 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
939 self.waitUntilSettled()
940
941 self.assertEqual(A.data['status'], 'NEW')
942 self.assertEqual(A.reported, 1,
943 "A should report failure")
944 self.assertIn('expected str for dictionary value',
945 A.messages[0], "A should have a syntax error reported")
946
947 def test_job_list_in_project_not_dict_error(self):
948 in_repo_conf = textwrap.dedent(
949 """
950 - job:
951 name: project-test1
952 - project:
953 name: org/project1
954 check:
955 jobs:
956 - project-test1:
957 - required-projects:
958 org/project2
959 """)
960
961 file_dict = {'.zuul.yaml': in_repo_conf}
962 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
963 files=file_dict)
964 A.addApproval('Code-Review', 2)
965 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
966 self.waitUntilSettled()
967
968 self.assertEqual(A.data['status'], 'NEW')
969 self.assertEqual(A.reported, 1,
970 "A should report failure")
971 self.assertIn('expected str for dictionary value',
972 A.messages[0], "A should have a syntax error reported")
973
James E. Blair1235f142017-10-07 09:11:43 -0700974 def test_project_template(self):
975 # Tests that a project template is not modified when used, and
976 # can therefore be used in subsequent reconfigurations.
977 in_repo_conf = textwrap.dedent(
978 """
979 - job:
980 name: project-test1
981 - project-template:
982 name: some-jobs
983 tenant-one-gate:
984 jobs:
985 - project-test1:
986 required-projects:
987 - org/project1
988 - project:
989 name: org/project
990 templates:
991 - some-jobs
992 """)
993
994 file_dict = {'.zuul.yaml': in_repo_conf}
995 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
996 files=file_dict)
997 A.addApproval('Code-Review', 2)
998 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
999 self.waitUntilSettled()
1000 self.assertEqual(A.data['status'], 'MERGED')
1001 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1002 self.waitUntilSettled()
1003 in_repo_conf = textwrap.dedent(
1004 """
1005 - project:
1006 name: org/project1
1007 templates:
1008 - some-jobs
1009 """)
1010 file_dict = {'.zuul.yaml': in_repo_conf}
1011 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
1012 files=file_dict)
1013 B.addApproval('Code-Review', 2)
1014 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1015 self.waitUntilSettled()
1016 self.assertEqual(B.data['status'], 'MERGED')
1017
James E. Blairbccdfcf2017-10-07 13:37:26 -07001018 def test_job_remove_add(self):
1019 # Tests that a job can be removed from one repo and added in another.
1020 # First, remove the current config for project1 since it
1021 # references the job we want to remove.
1022 file_dict = {'.zuul.yaml': None}
1023 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1024 files=file_dict)
1025 A.setMerged()
1026 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1027 self.waitUntilSettled()
1028 # Then propose a change to delete the job from one repo...
1029 file_dict = {'.zuul.yaml': None}
1030 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1031 files=file_dict)
1032 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1033 self.waitUntilSettled()
1034 # ...and a second that depends on it that adds it to another repo.
1035 in_repo_conf = textwrap.dedent(
1036 """
1037 - job:
1038 name: project-test1
1039
1040 - project:
1041 name: org/project1
1042 check:
1043 jobs:
1044 - project-test1
1045 """)
1046 in_repo_playbook = textwrap.dedent(
1047 """
1048 - hosts: all
1049 tasks: []
1050 """)
1051 file_dict = {'.zuul.yaml': in_repo_conf,
1052 'playbooks/project-test1.yaml': in_repo_playbook}
1053 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C',
1054 files=file_dict,
1055 parent='refs/changes/1/1/1')
1056 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1057 C.subject, B.data['id'])
1058 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1059 self.waitUntilSettled()
1060 self.assertHistory([
1061 dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'),
1062 ], ordered=False)
1063
James E. Blair09f9ffe2017-07-11 15:30:25 -07001064 def test_multi_repo(self):
1065 downstream_repo_conf = textwrap.dedent(
1066 """
1067 - project:
1068 name: org/project1
1069 tenant-one-gate:
1070 jobs:
1071 - project-test1
1072
1073 - job:
1074 name: project1-test1
1075 parent: project-test1
1076 """)
1077
1078 file_dict = {'.zuul.yaml': downstream_repo_conf}
1079 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1080 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001081 A.addApproval('Code-Review', 2)
1082 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001083 self.waitUntilSettled()
1084
1085 self.assertEqual(A.data['status'], 'MERGED')
1086 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1087 self.waitUntilSettled()
1088
1089 upstream_repo_conf = textwrap.dedent(
1090 """
1091 - job:
1092 name: project-test1
1093
1094 - job:
1095 name: project-test2
1096
1097 - project:
1098 name: org/project
1099 tenant-one-gate:
1100 jobs:
1101 - project-test1
1102 """)
1103
1104 file_dict = {'.zuul.yaml': upstream_repo_conf}
1105 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1106 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001107 B.addApproval('Code-Review', 2)
1108 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001109 self.waitUntilSettled()
1110
1111 self.assertEqual(B.data['status'], 'MERGED')
1112 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
1113 self.waitUntilSettled()
1114
1115 tenant = self.sched.abide.tenants.get('tenant-one')
1116 # Ensure the latest change is reflected in the config; if it
1117 # isn't this will raise an exception.
1118 tenant.layout.getJob('project-test2')
1119
James E. Blair332636e2017-09-05 10:14:35 -07001120 def test_pipeline_error(self):
1121 with open(os.path.join(FIXTURE_DIR,
1122 'config/in-repo/git/',
1123 'common-config/zuul.yaml')) as f:
1124 base_common_config = f.read()
1125
1126 in_repo_conf_A = textwrap.dedent(
1127 """
1128 - pipeline:
1129 name: periodic
1130 foo: error
1131 """)
1132
1133 file_dict = {'zuul.yaml': None,
1134 'zuul.d/main.yaml': base_common_config,
1135 'zuul.d/test1.yaml': in_repo_conf_A}
1136 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1137 files=file_dict)
1138 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1139 self.waitUntilSettled()
1140 self.assertEqual(A.reported, 1,
1141 "A should report failure")
1142 self.assertIn('syntax error',
1143 A.messages[0],
1144 "A should have an error reported")
1145
1146 def test_change_series_error(self):
1147 with open(os.path.join(FIXTURE_DIR,
1148 'config/in-repo/git/',
1149 'common-config/zuul.yaml')) as f:
1150 base_common_config = f.read()
1151
1152 in_repo_conf_A = textwrap.dedent(
1153 """
1154 - pipeline:
1155 name: periodic
1156 foo: error
1157 """)
1158
1159 file_dict = {'zuul.yaml': None,
1160 'zuul.d/main.yaml': base_common_config,
1161 'zuul.d/test1.yaml': in_repo_conf_A}
1162 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1163 files=file_dict)
1164
1165 in_repo_conf_B = textwrap.dedent(
1166 """
1167 - job:
1168 name: project-test2
1169 foo: error
1170 """)
1171
1172 file_dict = {'zuul.yaml': None,
1173 'zuul.d/main.yaml': base_common_config,
1174 'zuul.d/test1.yaml': in_repo_conf_A,
1175 'zuul.d/test2.yaml': in_repo_conf_B}
1176 B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B',
1177 files=file_dict)
1178 B.setDependsOn(A, 1)
1179 C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C')
1180 C.setDependsOn(B, 1)
1181 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1182 self.waitUntilSettled()
1183
1184 self.assertEqual(C.reported, 1,
1185 "C should report failure")
1186 self.assertIn('depends on a change that failed to merge',
1187 C.messages[0],
1188 "C should have an error reported")
1189
James E. Blairc73c73a2017-01-20 15:15:15 -08001190
James E. Blairc9455002017-09-06 09:22:19 -07001191class TestInRepoJoin(ZuulTestCase):
1192 # In this config, org/project is not a member of any pipelines, so
1193 # that we may test the changes that cause it to join them.
1194
1195 tenant_config_file = 'config/in-repo-join/main.yaml'
1196
1197 def test_dynamic_dependent_pipeline(self):
1198 # Test dynamically adding a project to a
1199 # dependent pipeline for the first time
1200 self.executor_server.hold_jobs_in_build = True
1201
1202 tenant = self.sched.abide.tenants.get('tenant-one')
1203 gate_pipeline = tenant.layout.pipelines['gate']
1204
1205 in_repo_conf = textwrap.dedent(
1206 """
1207 - job:
1208 name: project-test1
1209
1210 - job:
1211 name: project-test2
1212
1213 - project:
1214 name: org/project
1215 gate:
1216 jobs:
1217 - project-test2
1218 """)
1219
1220 in_repo_playbook = textwrap.dedent(
1221 """
1222 - hosts: all
1223 tasks: []
1224 """)
1225
1226 file_dict = {'.zuul.yaml': in_repo_conf,
1227 'playbooks/project-test2.yaml': in_repo_playbook}
1228 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1229 files=file_dict)
1230 A.addApproval('Code-Review', 2)
1231 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1232 self.waitUntilSettled()
1233
1234 items = gate_pipeline.getAllItems()
1235 self.assertEqual(items[0].change.number, '1')
1236 self.assertEqual(items[0].change.patchset, '1')
1237 self.assertTrue(items[0].live)
1238
1239 self.executor_server.hold_jobs_in_build = False
1240 self.executor_server.release()
1241 self.waitUntilSettled()
1242
1243 # Make sure the dynamic queue got cleaned up
1244 self.assertEqual(gate_pipeline.queues, [])
1245
1246 def test_dynamic_dependent_pipeline_failure(self):
1247 # Test that a change behind a failing change adding a project
1248 # to a dependent pipeline is dequeued.
1249 self.executor_server.hold_jobs_in_build = True
1250
1251 in_repo_conf = textwrap.dedent(
1252 """
1253 - job:
1254 name: project-test1
1255
1256 - project:
1257 name: org/project
1258 gate:
1259 jobs:
1260 - project-test1
1261 """)
1262
1263 file_dict = {'.zuul.yaml': in_repo_conf}
1264 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1265 files=file_dict)
1266 self.executor_server.failJob('project-test1', A)
1267 A.addApproval('Code-Review', 2)
1268 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1269 self.waitUntilSettled()
1270
1271 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1272 B.addApproval('Code-Review', 2)
1273 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1274 self.waitUntilSettled()
1275
James E. Blair3490c5d2017-09-07 08:33:23 -07001276 self.orderedRelease()
James E. Blairc9455002017-09-06 09:22:19 -07001277 self.waitUntilSettled()
1278 self.assertEqual(A.reported, 2,
1279 "A should report start and failure")
1280 self.assertEqual(A.data['status'], 'NEW')
1281 self.assertEqual(B.reported, 1,
1282 "B should report start")
1283 self.assertHistory([
1284 dict(name='project-test1', result='FAILURE', changes='1,1'),
James E. Blair3490c5d2017-09-07 08:33:23 -07001285 dict(name='project-test1', result='ABORTED', changes='1,1 2,1'),
James E. Blairc9455002017-09-06 09:22:19 -07001286 ], ordered=False)
1287
James E. Blair0af198f2017-09-06 09:52:35 -07001288 def test_dynamic_dependent_pipeline_absent(self):
1289 # Test that a series of dependent changes don't report merge
1290 # failures to a pipeline they aren't in.
1291 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1292 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1293 B.setDependsOn(A, 1)
1294
1295 A.addApproval('Code-Review', 2)
1296 A.addApproval('Approved', 1)
1297 B.addApproval('Code-Review', 2)
1298 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1299 self.waitUntilSettled()
1300 self.assertEqual(A.reported, 0,
1301 "A should not report")
1302 self.assertEqual(A.data['status'], 'NEW')
1303 self.assertEqual(B.reported, 0,
1304 "B should not report")
1305 self.assertEqual(B.data['status'], 'NEW')
1306 self.assertHistory([])
1307
James E. Blairc9455002017-09-06 09:22:19 -07001308
James E. Blairc73c73a2017-01-20 15:15:15 -08001309class TestAnsible(AnsibleZuulTestCase):
1310 # A temporary class to hold new tests while others are disabled
1311
1312 tenant_config_file = 'config/ansible/main.yaml'
1313
1314 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +11001315 # Keep the jobdir around so we can inspect contents if an
1316 # assert fails.
1317 self.executor_server.keep_jobdir = True
1318 # Output extra ansible info so we might see errors.
1319 self.executor_server.verbose = True
1320 # Add a site variables file, used by check-vars
1321 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
1322 'variables.yaml')
1323 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -08001324 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1325 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1326 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +02001327 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +11001328 with self.jobLog(build_timeout):
1329 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001330 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +11001331 with self.jobLog(build_faillocal):
1332 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001333 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +11001334 with self.jobLog(build_failpost):
1335 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001336 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +11001337 with self.jobLog(build_check_vars):
1338 self.assertEqual(build_check_vars.result, 'SUCCESS')
Monty Tayloraff8b402017-08-16 18:40:41 -05001339 build_check_secret_names = self.getJobFromHistory('check-secret-names')
1340 with self.jobLog(build_check_secret_names):
1341 self.assertEqual(build_check_secret_names.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001342 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +11001343 with self.jobLog(build_hello):
1344 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001345 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +11001346 with self.jobLog(build_python27):
1347 self.assertEqual(build_python27.result, 'SUCCESS')
1348 flag_path = os.path.join(self.test_root,
1349 build_python27.uuid + '.flag')
1350 self.assertTrue(os.path.exists(flag_path))
1351 copied_path = os.path.join(self.test_root, build_python27.uuid +
1352 '.copied')
1353 self.assertTrue(os.path.exists(copied_path))
1354 failed_path = os.path.join(self.test_root, build_python27.uuid +
1355 '.failed')
1356 self.assertFalse(os.path.exists(failed_path))
1357 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
1358 '.pre.flag')
1359 self.assertTrue(os.path.exists(pre_flag_path))
1360 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
1361 '.post.flag')
1362 self.assertTrue(os.path.exists(post_flag_path))
1363 bare_role_flag_path = os.path.join(self.test_root,
1364 build_python27.uuid +
1365 '.bare-role.flag')
1366 self.assertTrue(os.path.exists(bare_role_flag_path))
1367 secrets_path = os.path.join(self.test_root,
1368 build_python27.uuid + '.secrets')
1369 with open(secrets_path) as f:
1370 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -08001371
Jamie Lennox7655b552017-03-17 12:33:38 +11001372 msg = A.messages[0]
1373 success = "{} https://success.example.com/zuul-logs/{}"
1374 fail = "{} https://failure.example.com/zuul-logs/{}"
1375 self.assertIn(success.format("python27", build_python27.uuid), msg)
1376 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
1377 self.assertIn(success.format("check-vars",
1378 build_check_vars.uuid), msg)
1379 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
1380 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
1381 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +02001382
James E. Blairabbaa6f2017-04-06 16:11:44 -07001383 def _add_job(self, job_name):
1384 conf = textwrap.dedent(
1385 """
1386 - job:
1387 name: %s
1388
1389 - project:
1390 name: org/plugin-project
1391 check:
1392 jobs:
1393 - %s
1394 """ % (job_name, job_name))
1395
1396 file_dict = {'.zuul.yaml': conf}
1397 A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A',
1398 files=file_dict)
1399 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1400 self.waitUntilSettled()
1401
1402 def test_plugins(self):
1403 # Keep the jobdir around so we can inspect contents if an
1404 # assert fails.
1405 self.executor_server.keep_jobdir = True
1406 # Output extra ansible info so we might see errors.
1407 self.executor_server.verbose = True
1408
1409 count = 0
1410 plugin_tests = [
1411 ('passwd', 'FAILURE'),
1412 ('cartesian', 'SUCCESS'),
1413 ('consul_kv', 'FAILURE'),
1414 ('credstash', 'FAILURE'),
1415 ('csvfile_good', 'SUCCESS'),
1416 ('csvfile_bad', 'FAILURE'),
Monty Taylor93ad2212017-08-02 14:59:50 -05001417 ('uri_bad_path', 'FAILURE'),
1418 ('uri_bad_scheme', 'FAILURE'),
Monty Taylor788a40e2017-08-02 16:14:05 -05001419 ('block_local_override', 'FAILURE'),
Monty Taylor8da768f2017-08-31 14:15:35 -05001420 ('file_local_good', 'SUCCESS'),
1421 ('file_local_bad', 'FAILURE'),
James E. Blairabbaa6f2017-04-06 16:11:44 -07001422 ]
1423 for job_name, result in plugin_tests:
1424 count += 1
1425 self._add_job(job_name)
1426
1427 job = self.getJobFromHistory(job_name)
1428 with self.jobLog(job):
1429 self.assertEqual(count, len(self.history))
1430 build = self.history[-1]
1431 self.assertEqual(build.result, result)
1432
1433 # TODOv3(jeblair): parse the ansible output and verify we're
1434 # getting the exception we expect.
1435
James E. Blairb9c0d772017-03-03 14:34:49 -08001436
James E. Blaira4d4eef2017-06-30 14:49:17 -07001437class TestPrePlaybooks(AnsibleZuulTestCase):
1438 # A temporary class to hold new tests while others are disabled
1439
1440 tenant_config_file = 'config/pre-playbook/main.yaml'
1441
1442 def test_pre_playbook_fail(self):
1443 # Test that we run the post playbooks (but not the actual
1444 # playbook) when a pre-playbook fails.
1445 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1446 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1447 self.waitUntilSettled()
1448 build = self.getJobFromHistory('python27')
1449 self.assertIsNone(build.result)
1450 self.assertIn('RETRY_LIMIT', A.messages[0])
1451 flag_path = os.path.join(self.test_root, build.uuid +
1452 '.main.flag')
1453 self.assertFalse(os.path.exists(flag_path))
1454 pre_flag_path = os.path.join(self.test_root, build.uuid +
1455 '.pre.flag')
1456 self.assertFalse(os.path.exists(pre_flag_path))
1457 post_flag_path = os.path.join(self.test_root, build.uuid +
1458 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -07001459 self.assertTrue(os.path.exists(post_flag_path),
1460 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -07001461
1462
James E. Blairb9c0d772017-03-03 14:34:49 -08001463class TestBrokenConfig(ZuulTestCase):
1464 # Test that we get an appropriate syntax error if we start with a
1465 # broken config.
1466
1467 tenant_config_file = 'config/broken/main.yaml'
1468
1469 def setUp(self):
1470 with testtools.ExpectedException(
1471 zuul.configloader.ConfigurationSyntaxError,
1472 "\nZuul encountered a syntax error"):
1473 super(TestBrokenConfig, self).setUp()
1474
1475 def test_broken_config_on_startup(self):
1476 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001477
1478
1479class TestProjectKeys(ZuulTestCase):
1480 # Test that we can generate project keys
1481
1482 # Normally the test infrastructure copies a static key in place
1483 # for each project before starting tests. This saves time because
1484 # Zuul's automatic key-generation on startup can be slow. To make
1485 # sure we exercise that code, in this test we allow Zuul to create
1486 # keys for the project on startup.
1487 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +02001488 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001489 tenant_config_file = 'config/in-repo/main.yaml'
1490
1491 def test_key_generation(self):
1492 key_root = os.path.join(self.state_root, 'keys')
1493 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
1494 # Make sure that a proper key was created on startup
1495 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -07001496 private_key, public_key = \
1497 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001498
1499 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
1500 fixture_private_key = i.read()
1501
1502 # Make sure that we didn't just end up with the static fixture
1503 # key
1504 self.assertNotEqual(fixture_private_key, private_key)
1505
1506 # Make sure it's the right length
1507 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -07001508
1509
James E. Blairbb94dfa2017-07-11 07:45:19 -07001510class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -07001511 def _assertRolePath(self, build, playbook, content):
1512 path = os.path.join(self.test_root, build.uuid,
1513 'ansible', playbook, 'ansible.cfg')
1514 roles_paths = []
1515 with open(path) as f:
1516 for line in f:
1517 if line.startswith('roles_path'):
1518 roles_paths.append(line)
1519 print(roles_paths)
1520 if content:
1521 self.assertEqual(len(roles_paths), 1,
1522 "Should have one roles_path line in %s" %
1523 (playbook,))
1524 self.assertIn(content, roles_paths[0])
1525 else:
1526 self.assertEqual(len(roles_paths), 0,
1527 "Should have no roles_path line in %s" %
1528 (playbook,))
1529
James E. Blairbb94dfa2017-07-11 07:45:19 -07001530
1531class TestRoles(RoleTestCase):
1532 tenant_config_file = 'config/roles/main.yaml'
1533
James E. Blairbce76932017-05-04 10:03:15 -07001534 def test_role(self):
1535 # This exercises a proposed change to a role being checked out
1536 # and used.
1537 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
1538 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1539 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1540 B.subject, A.data['id'])
1541 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1542 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1543 self.waitUntilSettled()
1544 self.assertHistory([
1545 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
1546 ])
James E. Blair6459db12017-06-29 14:57:20 -07001547
James E. Blair1b27f6a2017-07-14 14:09:07 -07001548 def test_role_inheritance(self):
1549 self.executor_server.hold_jobs_in_build = True
1550 conf = textwrap.dedent(
1551 """
1552 - job:
1553 name: parent
1554 roles:
1555 - zuul: bare-role
1556 pre-run: playbooks/parent-pre
1557 post-run: playbooks/parent-post
1558
1559 - job:
1560 name: project-test
1561 parent: parent
1562 roles:
1563 - zuul: org/project
1564
1565 - project:
1566 name: org/project
1567 check:
1568 jobs:
1569 - project-test
1570 """)
1571
1572 file_dict = {'.zuul.yaml': conf}
1573 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1574 files=file_dict)
1575 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1576 self.waitUntilSettled()
1577
1578 self.assertEqual(len(self.builds), 1)
1579 build = self.getBuildByName('project-test')
1580 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
1581 self._assertRolePath(build, 'playbook_0', 'role_0')
1582 self._assertRolePath(build, 'playbook_0', 'role_1')
1583 self._assertRolePath(build, 'post_playbook_0', 'role_0')
1584
1585 self.executor_server.hold_jobs_in_build = False
1586 self.executor_server.release()
1587 self.waitUntilSettled()
1588
1589 self.assertHistory([
1590 dict(name='project-test', result='SUCCESS', changes='1,1'),
1591 ])
1592
James E. Blair6f699732017-07-18 14:19:11 -07001593 def test_role_error(self):
1594 conf = textwrap.dedent(
1595 """
1596 - job:
1597 name: project-test
1598 roles:
1599 - zuul: common-config
1600
1601 - project:
1602 name: org/project
1603 check:
1604 jobs:
1605 - project-test
1606 """)
1607
1608 file_dict = {'.zuul.yaml': conf}
1609 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1610 files=file_dict)
1611 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1612 self.waitUntilSettled()
1613 self.assertIn(
1614 '- project-test project-test : ERROR Unable to find role',
1615 A.messages[-1])
1616
James E. Blair6459db12017-06-29 14:57:20 -07001617
James E. Blairbb94dfa2017-07-11 07:45:19 -07001618class TestImplicitRoles(RoleTestCase):
1619 tenant_config_file = 'config/implicit-roles/main.yaml'
1620
1621 def test_missing_roles(self):
1622 # Test implicit and explicit roles for a project which does
1623 # not have roles. The implicit role should be silently
1624 # ignored since the project doesn't supply roles, but if a
1625 # user declares an explicit role, it should error.
1626 self.executor_server.hold_jobs_in_build = True
1627 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
1628 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1629 self.waitUntilSettled()
1630
1631 self.assertEqual(len(self.builds), 2)
1632 build = self.getBuildByName('implicit-role-fail')
1633 self._assertRolePath(build, 'playbook_0', None)
1634
1635 self.executor_server.hold_jobs_in_build = False
1636 self.executor_server.release()
1637 self.waitUntilSettled()
1638 # The retry_limit doesn't get recorded
1639 self.assertHistory([
1640 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
1641 ])
1642
1643 def test_roles(self):
1644 # Test implicit and explicit roles for a project which does
1645 # have roles. In both cases, we should end up with the role
1646 # in the path. In the explicit case, ensure we end up with
1647 # the name we specified.
1648 self.executor_server.hold_jobs_in_build = True
1649 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
1650 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1651 self.waitUntilSettled()
1652
1653 self.assertEqual(len(self.builds), 2)
1654 build = self.getBuildByName('implicit-role-ok')
1655 self._assertRolePath(build, 'playbook_0', 'role_0')
1656
1657 build = self.getBuildByName('explicit-role-ok')
1658 self._assertRolePath(build, 'playbook_0', 'role_0')
1659
1660 self.executor_server.hold_jobs_in_build = False
1661 self.executor_server.release()
1662 self.waitUntilSettled()
1663 self.assertHistory([
1664 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
1665 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
1666 ], ordered=False)
1667
1668
James E. Blair6459db12017-06-29 14:57:20 -07001669class TestShadow(ZuulTestCase):
1670 tenant_config_file = 'config/shadow/main.yaml'
1671
1672 def test_shadow(self):
1673 # Test that a repo is allowed to shadow another's job definitions.
1674 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1675 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1676 self.waitUntilSettled()
1677 self.assertHistory([
1678 dict(name='test1', result='SUCCESS', changes='1,1'),
1679 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -07001680 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -07001681
1682
1683class TestDataReturn(AnsibleZuulTestCase):
1684 tenant_config_file = 'config/data-return/main.yaml'
1685
1686 def test_data_return(self):
1687 # This exercises a proposed change to a role being checked out
1688 # and used.
1689 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1690 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1691 self.waitUntilSettled()
1692 self.assertHistory([
1693 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07001694 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
1695 ], ordered=False)
1696 self.assertIn('- data-return http://example.com/test/log/url/',
1697 A.messages[-1])
1698 self.assertIn('- data-return-relative '
1699 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -07001700 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -07001701
1702
1703class TestDiskAccounting(AnsibleZuulTestCase):
1704 config_file = 'zuul-disk-accounting.conf'
1705 tenant_config_file = 'config/disk-accountant/main.yaml'
1706
1707 def test_disk_accountant_kills_job(self):
1708 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1709 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1710 self.waitUntilSettled()
1711 self.assertHistory([
1712 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001713
1714
1715class TestMaxNodesPerJob(AnsibleZuulTestCase):
1716 tenant_config_file = 'config/multi-tenant/main.yaml'
1717
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00001718 def test_max_timeout_exceeded(self):
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001719 in_repo_conf = textwrap.dedent(
1720 """
1721 - job:
1722 name: test-job
James E. Blair7e3e6882017-09-20 15:47:13 -07001723 nodeset:
1724 nodes:
1725 - name: node01
1726 label: fake
1727 - name: node02
1728 label: fake
1729 - name: node03
1730 label: fake
1731 - name: node04
1732 label: fake
1733 - name: node05
1734 label: fake
1735 - name: node06
1736 label: fake
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001737 """)
1738 file_dict = {'.zuul.yaml': in_repo_conf}
1739 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1740 files=file_dict)
1741 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1742 self.waitUntilSettled()
1743 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
1744 A.messages[0], "A should fail because of nodes limit")
1745
1746 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
1747 files=file_dict)
1748 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1749 self.waitUntilSettled()
1750 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
1751 "B should not fail because of nodes limit")
James E. Blair2bab6e72017-08-07 09:52:45 -07001752
1753
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00001754class TestMaxTimeout(AnsibleZuulTestCase):
1755 tenant_config_file = 'config/multi-tenant/main.yaml'
1756
1757 def test_max_nodes_reached(self):
1758 in_repo_conf = textwrap.dedent(
1759 """
1760 - job:
1761 name: test-job
1762 timeout: 3600
1763 """)
1764 file_dict = {'.zuul.yaml': in_repo_conf}
1765 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1766 files=file_dict)
1767 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1768 self.waitUntilSettled()
1769 self.assertIn('The job "test-job" exceeds tenant max-job-timeout',
1770 A.messages[0], "A should fail because of timeout limit")
1771
1772 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
1773 files=file_dict)
1774 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1775 self.waitUntilSettled()
1776 self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0],
1777 "B should not fail because of timeout limit")
1778
1779
James E. Blair2bab6e72017-08-07 09:52:45 -07001780class TestBaseJobs(ZuulTestCase):
1781 tenant_config_file = 'config/base-jobs/main.yaml'
1782
1783 def test_multiple_base_jobs(self):
1784 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1785 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1786 self.waitUntilSettled()
1787 self.assertHistory([
1788 dict(name='my-job', result='SUCCESS', changes='1,1'),
1789 dict(name='other-job', result='SUCCESS', changes='1,1'),
1790 ], ordered=False)
1791 self.assertEqual(self.getJobFromHistory('my-job').
1792 parameters['zuul']['jobtags'],
1793 ['mybase'])
1794 self.assertEqual(self.getJobFromHistory('other-job').
1795 parameters['zuul']['jobtags'],
1796 ['otherbase'])
1797
1798 def test_untrusted_base_job(self):
1799 """Test that a base job may not be defined in an untrusted repo"""
1800 in_repo_conf = textwrap.dedent(
1801 """
1802 - job:
1803 name: fail-base
1804 parent: null
1805 """)
1806
1807 file_dict = {'.zuul.yaml': in_repo_conf}
1808 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1809 files=file_dict)
1810 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1811 self.waitUntilSettled()
1812 self.assertEqual(A.reported, 1,
1813 "A should report failure")
1814 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
1815 self.assertIn('Base jobs must be defined in config projects',
1816 A.messages[0])
1817 self.assertHistory([])
James E. Blairdb089032017-08-15 13:42:12 -07001818
1819
1820class TestSecretLeaks(AnsibleZuulTestCase):
1821 tenant_config_file = 'config/secret-leaks/main.yaml'
1822
1823 def searchForContent(self, path, content):
1824 matches = []
1825 for (dirpath, dirnames, filenames) in os.walk(path):
1826 for filename in filenames:
1827 filepath = os.path.join(dirpath, filename)
1828 with open(filepath, 'rb') as f:
1829 if content in f.read():
1830 matches.append(filepath[len(path):])
1831 return matches
1832
1833 def _test_secret_file(self):
1834 # Or rather -- test that they *don't* leak.
1835 # Keep the jobdir around so we can inspect contents.
1836 self.executor_server.keep_jobdir = True
1837 conf = textwrap.dedent(
1838 """
1839 - project:
1840 name: org/project
1841 check:
1842 jobs:
1843 - secret-file
1844 """)
1845
1846 file_dict = {'.zuul.yaml': conf}
1847 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1848 files=file_dict)
1849 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1850 self.waitUntilSettled()
1851 self.assertHistory([
1852 dict(name='secret-file', result='SUCCESS', changes='1,1'),
1853 ], ordered=False)
1854 matches = self.searchForContent(self.history[0].jobdir.root,
1855 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07001856 self.assertEqual(set(['/work/secret-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07001857 set(matches))
1858
1859 def test_secret_file(self):
1860 self._test_secret_file()
1861
1862 def test_secret_file_verbose(self):
1863 # Output extra ansible info to exercise alternate logging code
1864 # paths.
1865 self.executor_server.verbose = True
1866 self._test_secret_file()
1867
1868 def _test_secret_file_fail(self):
1869 # Or rather -- test that they *don't* leak.
1870 # Keep the jobdir around so we can inspect contents.
1871 self.executor_server.keep_jobdir = True
1872 conf = textwrap.dedent(
1873 """
1874 - project:
1875 name: org/project
1876 check:
1877 jobs:
1878 - secret-file-fail
1879 """)
1880
1881 file_dict = {'.zuul.yaml': conf}
1882 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1883 files=file_dict)
1884 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1885 self.waitUntilSettled()
1886 self.assertHistory([
1887 dict(name='secret-file-fail', result='FAILURE', changes='1,1'),
1888 ], ordered=False)
1889 matches = self.searchForContent(self.history[0].jobdir.root,
1890 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07001891 self.assertEqual(set(['/work/failure-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07001892 set(matches))
1893
1894 def test_secret_file_fail(self):
1895 self._test_secret_file_fail()
1896
1897 def test_secret_file_fail_verbose(self):
1898 # Output extra ansible info to exercise alternate logging code
1899 # paths.
1900 self.executor_server.verbose = True
1901 self._test_secret_file_fail()
James E. Blaira00910c2017-08-23 09:15:04 -07001902
1903
1904class TestJobOutput(AnsibleZuulTestCase):
1905 tenant_config_file = 'config/job-output/main.yaml'
1906
1907 def _get_file(self, build, path):
1908 p = os.path.join(build.jobdir.root, path)
1909 with open(p) as f:
1910 return f.read()
1911
1912 def test_job_output(self):
Monty Taylor0e2489a2017-10-10 11:57:29 -05001913 # Verify that command standard output appears in the job output,
1914 # and that failures in the final playbook get logged.
James E. Blaira00910c2017-08-23 09:15:04 -07001915
1916 # This currently only verifies we receive output from
1917 # localhost. Notably, it does not verify we receive output
1918 # via zuul_console streaming.
1919 self.executor_server.keep_jobdir = True
1920 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1921 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1922 self.waitUntilSettled()
1923 self.assertHistory([
1924 dict(name='job-output', result='SUCCESS', changes='1,1'),
1925 ], ordered=False)
1926
1927 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
1928 j = json.loads(self._get_file(self.history[0],
1929 'work/logs/job-output.json'))
1930 self.assertEqual(token,
1931 j[0]['plays'][0]['tasks'][0]
1932 ['hosts']['localhost']['stdout'])
1933
1934 print(self._get_file(self.history[0],
1935 'work/logs/job-output.txt'))
1936 self.assertIn(token,
1937 self._get_file(self.history[0],
1938 'work/logs/job-output.txt'))
Monty Taylor0e2489a2017-10-10 11:57:29 -05001939
1940 def test_job_output_failure_log(self):
1941 logger = logging.getLogger('zuul.AnsibleJob')
1942 output = io.StringIO()
1943 logger.addHandler(logging.StreamHandler(output))
1944
1945 # Verify that a failure in the last post playbook emits the contents
1946 # of the json output to the log
1947 self.executor_server.keep_jobdir = True
1948 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
1949 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1950 self.waitUntilSettled()
1951 self.assertHistory([
1952 dict(name='job-output-failure',
1953 result='POST_FAILURE', changes='1,1'),
1954 ], ordered=False)
1955
1956 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
1957 j = json.loads(self._get_file(self.history[0],
1958 'work/logs/job-output.json'))
1959 self.assertEqual(token,
1960 j[0]['plays'][0]['tasks'][0]
1961 ['hosts']['localhost']['stdout'])
1962
1963 print(self._get_file(self.history[0],
1964 'work/logs/job-output.json'))
1965 self.assertIn(token,
1966 self._get_file(self.history[0],
1967 'work/logs/job-output.txt'))
1968
1969 log_output = output.getvalue()
1970 self.assertIn('Final playbook failed', log_output)
1971 self.assertIn('Failure test', log_output)