blob: 77c73dd304855960495496692e9e757077b6bd83 [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
James E. Blairdaaf3262017-10-23 13:51:48 -0700162 @skip("This is broken until the next change")
James E. Blair09998792017-10-15 18:02:18 -0700163 def test_branch_variants(self):
164 # Test branch variants of jobs with inheritance
165 self.executor_server.hold_jobs_in_build = True
166 # This creates a new branch with a copy of the config in master
167 self.create_branch('puppet-integration', 'stable')
168 self.fake_gerrit.addEvent(
169 self.fake_gerrit.getFakeBranchCreatedEvent(
170 'puppet-integration', 'stable'))
171 self.waitUntilSettled()
172
173 A = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'A')
174 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
175 self.waitUntilSettled()
176
177 self.assertEqual(len(self.builds[0].parameters['pre_playbooks']), 3)
178 self.executor_server.hold_jobs_in_build = False
179 self.executor_server.release()
180 self.waitUntilSettled()
181
James E. Blairc9e77592017-10-24 09:25:23 -0700182 def test_branch_variants_reconfigure(self):
183 # Test branch variants of jobs with inheritance
184 self.executor_server.hold_jobs_in_build = True
185 # This creates a new branch with a copy of the config in master
186 self.create_branch('puppet-integration', 'stable')
187 self.fake_gerrit.addEvent(
188 self.fake_gerrit.getFakeBranchCreatedEvent(
189 'puppet-integration', 'stable'))
190 self.waitUntilSettled()
191
192 with open(os.path.join(FIXTURE_DIR,
193 'config/branch-variants/git/',
194 'puppet-integration/.zuul.yaml')) as f:
195 config = f.read()
196
197 # Push a change that triggers a dynamic reconfiguration
198 file_dict = {'.zuul.yaml': config}
199 A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A',
200 files=file_dict)
201 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
202 self.waitUntilSettled()
203
204 ipath = self.builds[0].parameters['zuul']['_inheritance_path']
205 for i in ipath:
206 self.log.debug("inheritance path %s", i)
207 self.assertEqual(len(ipath), 5)
208 self.executor_server.hold_jobs_in_build = False
209 self.executor_server.release()
210 self.waitUntilSettled()
211
James E. Blair09998792017-10-15 18:02:18 -0700212
James E. Blairff555742017-02-19 11:34:27 -0800213class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -0800214 # A temporary class to hold new tests while others are disabled
215
Tobias Henkelabf973e2017-07-28 10:07:34 +0200216 config_file = 'zuul-connections-gerrit-and-github.conf'
James E. Blair2a629ec2015-12-22 15:32:02 -0800217 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -0800218
James E. Blair83005782015-12-11 14:46:03 -0800219 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -0800220 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200221 A.addApproval('Code-Review', 2)
222 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -0800223 self.waitUntilSettled()
224 self.assertEqual(self.getJobFromHistory('project-test1').result,
225 'SUCCESS')
226 self.assertEqual(A.data['status'], 'MERGED')
227 self.assertEqual(A.reported, 2,
228 "A should report start and success")
229 self.assertIn('tenant-one-gate', A.messages[1],
230 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -0800231
James E. Blair3a098dd2017-10-04 14:37:29 -0700232 @skip("This test is useful, but not reliable")
233 def test_full_and_dynamic_reconfig(self):
234 self.executor_server.hold_jobs_in_build = True
235 in_repo_conf = textwrap.dedent(
236 """
237 - job:
238 name: project-test1
239
240 - project:
241 name: org/project
242 tenant-one-gate:
243 jobs:
244 - project-test1
245 """)
246
247 file_dict = {'.zuul.yaml': in_repo_conf}
248 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
249 files=file_dict)
250 A.addApproval('Code-Review', 2)
251 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
252 self.waitUntilSettled()
253 self.sched.reconfigure(self.config)
254 self.waitUntilSettled()
255
256 gc.collect()
257 pipelines = [obj for obj in gc.get_objects()
258 if isinstance(obj, zuul.model.Pipeline)]
259 self.assertEqual(len(pipelines), 4)
260
261 self.executor_server.hold_jobs_in_build = False
262 self.executor_server.release()
263 self.waitUntilSettled()
264
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700265 def test_dynamic_config(self):
266 in_repo_conf = textwrap.dedent(
267 """
268 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200269 name: project-test1
270
271 - job:
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700272 name: project-test2
273
274 - project:
275 name: org/project
276 tenant-one-gate:
277 jobs:
278 - project-test2
279 """)
280
James E. Blairc73c73a2017-01-20 15:15:15 -0800281 in_repo_playbook = textwrap.dedent(
282 """
283 - hosts: all
284 tasks: []
285 """)
286
287 file_dict = {'.zuul.yaml': in_repo_conf,
288 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700289 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800290 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200291 A.addApproval('Code-Review', 2)
292 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700293 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700294 self.assertEqual(A.data['status'], 'MERGED')
295 self.assertEqual(A.reported, 2,
296 "A should report start and success")
297 self.assertIn('tenant-one-gate', A.messages[1],
298 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800299 self.assertHistory([
300 dict(name='project-test2', result='SUCCESS', changes='1,1')])
301
James E. Blairc2a5ed72017-02-20 14:12:01 -0500302 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800303 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500304
James E. Blair646322f2017-01-27 15:50:34 -0800305 # Now that the config change is landed, it should be live for
306 # subsequent changes.
307 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200308 B.addApproval('Code-Review', 2)
309 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair646322f2017-01-27 15:50:34 -0800310 self.waitUntilSettled()
311 self.assertEqual(self.getJobFromHistory('project-test2').result,
312 'SUCCESS')
313 self.assertHistory([
314 dict(name='project-test2', result='SUCCESS', changes='1,1'),
315 dict(name='project-test2', result='SUCCESS', changes='2,1')])
James E. Blairc73c73a2017-01-20 15:15:15 -0800316
James E. Blair6bc10482017-10-20 11:28:53 -0700317 def test_dynamic_template(self):
318 in_repo_conf = textwrap.dedent(
319 """
320 - job:
321 name: project-test1
322
323 - project-template:
324 name: common-config-template
325 check:
326 jobs:
327 - project-test1
328
329 - project:
330 name: org/project
331 templates: [common-config-template]
332 """)
333
334 file_dict = {'.zuul.yaml': in_repo_conf}
335 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
336 files=file_dict)
337 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
338 self.waitUntilSettled()
339 self.assertHistory([
340 dict(name='template-job', result='SUCCESS', changes='1,1')])
341
Tobias Henkelf02cf512017-07-21 22:55:34 +0200342 def test_dynamic_config_non_existing_job(self):
343 """Test that requesting a non existent job fails"""
344 in_repo_conf = textwrap.dedent(
345 """
346 - job:
347 name: project-test1
348
349 - project:
350 name: org/project
351 check:
352 jobs:
353 - non-existent-job
354 """)
355
356 in_repo_playbook = textwrap.dedent(
357 """
358 - hosts: all
359 tasks: []
360 """)
361
362 file_dict = {'.zuul.yaml': in_repo_conf,
363 'playbooks/project-test2.yaml': in_repo_playbook}
364 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
365 files=file_dict)
366 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
367 self.waitUntilSettled()
368 self.assertEqual(A.reported, 1,
369 "A should report failure")
370 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
371 self.assertIn('Job non-existent-job not defined', A.messages[0],
372 "A should have failed the check pipeline")
373 self.assertHistory([])
374
375 def test_dynamic_config_non_existing_job_in_template(self):
376 """Test that requesting a non existent job fails"""
377 in_repo_conf = textwrap.dedent(
378 """
379 - job:
380 name: project-test1
381
382 - project-template:
383 name: test-template
384 check:
385 jobs:
386 - non-existent-job
387
388 - project:
389 name: org/project
390 templates:
391 - test-template
392 """)
393
394 in_repo_playbook = textwrap.dedent(
395 """
396 - hosts: all
397 tasks: []
398 """)
399
400 file_dict = {'.zuul.yaml': in_repo_conf,
401 'playbooks/project-test2.yaml': in_repo_playbook}
402 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
403 files=file_dict)
404 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
405 self.waitUntilSettled()
406 self.assertEqual(A.reported, 1,
407 "A should report failure")
408 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
409 self.assertIn('Job non-existent-job not defined', A.messages[0],
410 "A should have failed the check pipeline")
411 self.assertHistory([])
412
Tobias Henkel0f714002017-06-30 23:30:52 +0200413 def test_dynamic_config_new_patchset(self):
414 self.executor_server.hold_jobs_in_build = True
415
416 tenant = self.sched.abide.tenants.get('tenant-one')
417 check_pipeline = tenant.layout.pipelines['check']
418
419 in_repo_conf = textwrap.dedent(
420 """
421 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200422 name: project-test1
423
424 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200425 name: project-test2
426
427 - project:
428 name: org/project
429 check:
430 jobs:
431 - project-test2
432 """)
433
434 in_repo_playbook = textwrap.dedent(
435 """
436 - hosts: all
437 tasks: []
438 """)
439
440 file_dict = {'.zuul.yaml': in_repo_conf,
441 'playbooks/project-test2.yaml': in_repo_playbook}
442 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
443 files=file_dict)
444 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
445 self.waitUntilSettled()
446
447 items = check_pipeline.getAllItems()
448 self.assertEqual(items[0].change.number, '1')
449 self.assertEqual(items[0].change.patchset, '1')
450 self.assertTrue(items[0].live)
451
452 in_repo_conf = textwrap.dedent(
453 """
454 - job:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200455 name: project-test1
456
457 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200458 name: project-test2
459
460 - project:
461 name: org/project
462 check:
463 jobs:
464 - project-test1
465 - project-test2
466 """)
467 file_dict = {'.zuul.yaml': in_repo_conf,
468 'playbooks/project-test2.yaml': in_repo_playbook}
469
470 A.addPatchset(files=file_dict)
471 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
472
473 self.waitUntilSettled()
474
475 items = check_pipeline.getAllItems()
476 self.assertEqual(items[0].change.number, '1')
477 self.assertEqual(items[0].change.patchset, '2')
478 self.assertTrue(items[0].live)
479
480 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200481 self.executor_server.release('project-test1')
482 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +0200483 self.executor_server.release()
484 self.waitUntilSettled()
485
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200486 self.assertHistory([
487 dict(name='project-test2', result='ABORTED', changes='1,1'),
488 dict(name='project-test1', result='SUCCESS', changes='1,2'),
489 dict(name='project-test2', result='SUCCESS', changes='1,2')])
490
James E. Blairff555742017-02-19 11:34:27 -0800491 def test_in_repo_branch(self):
492 in_repo_conf = textwrap.dedent(
493 """
494 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200495 name: project-test1
496
497 - job:
James E. Blairff555742017-02-19 11:34:27 -0800498 name: project-test2
499
500 - project:
501 name: org/project
502 tenant-one-gate:
503 jobs:
504 - project-test2
505 """)
506
507 in_repo_playbook = textwrap.dedent(
508 """
509 - hosts: all
510 tasks: []
511 """)
512
513 file_dict = {'.zuul.yaml': in_repo_conf,
514 'playbooks/project-test2.yaml': in_repo_playbook}
515 self.create_branch('org/project', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700516 self.fake_gerrit.addEvent(
517 self.fake_gerrit.getFakeBranchCreatedEvent(
518 'org/project', 'stable'))
James E. Blair6069f2b2017-09-26 16:34:11 -0700519 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800520 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
521 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200522 A.addApproval('Code-Review', 2)
523 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800524 self.waitUntilSettled()
525 self.assertEqual(A.data['status'], 'MERGED')
526 self.assertEqual(A.reported, 2,
527 "A should report start and success")
528 self.assertIn('tenant-one-gate', A.messages[1],
529 "A should transit tenant-one gate")
530 self.assertHistory([
531 dict(name='project-test2', result='SUCCESS', changes='1,1')])
532 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800533 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800534
535 # The config change should not affect master.
536 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200537 B.addApproval('Code-Review', 2)
538 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800539 self.waitUntilSettled()
540 self.assertHistory([
541 dict(name='project-test2', result='SUCCESS', changes='1,1'),
542 dict(name='project-test1', result='SUCCESS', changes='2,1')])
543
544 # The config change should be live for further changes on
545 # stable.
546 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200547 C.addApproval('Code-Review', 2)
548 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800549 self.waitUntilSettled()
550 self.assertHistory([
551 dict(name='project-test2', result='SUCCESS', changes='1,1'),
552 dict(name='project-test1', result='SUCCESS', changes='2,1'),
553 dict(name='project-test2', result='SUCCESS', changes='3,1')])
554
James E. Blaira5a12492017-05-03 11:40:48 -0700555 def test_crd_dynamic_config_branch(self):
556 # Test that we can create a job in one repo and be able to use
557 # it from a different branch on a different repo.
558
559 self.create_branch('org/project1', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700560 self.fake_gerrit.addEvent(
561 self.fake_gerrit.getFakeBranchCreatedEvent(
562 'org/project1', 'stable'))
James E. Blaira5a12492017-05-03 11:40:48 -0700563
564 in_repo_conf = textwrap.dedent(
565 """
566 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200567 name: project-test1
568
569 - job:
James E. Blaira5a12492017-05-03 11:40:48 -0700570 name: project-test2
571
572 - project:
573 name: org/project
574 check:
575 jobs:
576 - project-test2
577 """)
578
579 in_repo_playbook = textwrap.dedent(
580 """
581 - hosts: all
582 tasks: []
583 """)
584
585 file_dict = {'.zuul.yaml': in_repo_conf,
586 'playbooks/project-test2.yaml': in_repo_playbook}
587 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
588 files=file_dict)
589
590 second_repo_conf = textwrap.dedent(
591 """
592 - project:
593 name: org/project1
594 check:
595 jobs:
596 - project-test2
597 """)
598
599 second_file_dict = {'.zuul.yaml': second_repo_conf}
600 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
601 files=second_file_dict)
602 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
603 B.subject, A.data['id'])
604
605 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
606 self.waitUntilSettled()
607 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
608 self.waitUntilSettled()
609
610 self.assertEqual(A.reported, 1, "A should report")
611 self.assertHistory([
612 dict(name='project-test2', result='SUCCESS', changes='1,1'),
613 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
614 ])
615
James E. Blair97043882017-09-06 15:51:17 -0700616 def test_yaml_list_error(self):
617 in_repo_conf = textwrap.dedent(
618 """
619 job: foo
620 """)
621
622 file_dict = {'.zuul.yaml': in_repo_conf}
623 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
624 files=file_dict)
625 A.addApproval('Code-Review', 2)
626 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
627 self.waitUntilSettled()
628
629 self.assertEqual(A.data['status'], 'NEW')
630 self.assertEqual(A.reported, 1,
631 "A should report failure")
632 self.assertIn('not a list', A.messages[0],
633 "A should have a syntax error reported")
634
635 def test_yaml_dict_error(self):
636 in_repo_conf = textwrap.dedent(
637 """
638 - job
639 """)
640
641 file_dict = {'.zuul.yaml': in_repo_conf}
642 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
643 files=file_dict)
644 A.addApproval('Code-Review', 2)
645 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
646 self.waitUntilSettled()
647
648 self.assertEqual(A.data['status'], 'NEW')
649 self.assertEqual(A.reported, 1,
650 "A should report failure")
651 self.assertIn('not a dictionary', A.messages[0],
652 "A should have a syntax error reported")
653
654 def test_yaml_key_error(self):
655 in_repo_conf = textwrap.dedent(
656 """
657 - job:
658 name: project-test2
659 """)
660
661 file_dict = {'.zuul.yaml': in_repo_conf}
662 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
663 files=file_dict)
664 A.addApproval('Code-Review', 2)
665 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
666 self.waitUntilSettled()
667
668 self.assertEqual(A.data['status'], 'NEW')
669 self.assertEqual(A.reported, 1,
670 "A should report failure")
671 self.assertIn('has more than one key', A.messages[0],
672 "A should have a syntax error reported")
673
674 def test_yaml_unknown_error(self):
675 in_repo_conf = textwrap.dedent(
676 """
677 - foobar:
678 foo: bar
679 """)
680
681 file_dict = {'.zuul.yaml': in_repo_conf}
682 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
683 files=file_dict)
684 A.addApproval('Code-Review', 2)
685 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
686 self.waitUntilSettled()
687
688 self.assertEqual(A.data['status'], 'NEW')
689 self.assertEqual(A.reported, 1,
690 "A should report failure")
691 self.assertIn('not recognized', A.messages[0],
692 "A should have a syntax error reported")
693
James E. Blair149b69c2017-03-02 10:48:16 -0800694 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -0800695 in_repo_conf = textwrap.dedent(
696 """
697 - job:
698 name: project-test2
699 foo: error
700 """)
701
702 file_dict = {'.zuul.yaml': in_repo_conf}
703 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
704 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200705 A.addApproval('Code-Review', 2)
706 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -0800707 self.waitUntilSettled()
708
709 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200710 self.assertEqual(A.reported, 1,
711 "A should report failure")
712 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -0800713 "A should have a syntax error reported")
714
James E. Blair149b69c2017-03-02 10:48:16 -0800715 def test_trusted_syntax_error(self):
716 in_repo_conf = textwrap.dedent(
717 """
718 - job:
719 name: project-test2
720 foo: error
721 """)
722
723 file_dict = {'zuul.yaml': in_repo_conf}
724 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
725 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200726 A.addApproval('Code-Review', 2)
727 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -0800728 self.waitUntilSettled()
729
730 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200731 self.assertEqual(A.reported, 1,
732 "A should report failure")
733 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -0800734 "A should have a syntax error reported")
735
James E. Blair6f140c72017-03-03 10:32:07 -0800736 def test_untrusted_yaml_error(self):
737 in_repo_conf = textwrap.dedent(
738 """
739 - job:
740 foo: error
741 """)
742
743 file_dict = {'.zuul.yaml': in_repo_conf}
744 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
745 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200746 A.addApproval('Code-Review', 2)
747 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -0800748 self.waitUntilSettled()
749
750 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200751 self.assertEqual(A.reported, 1,
752 "A should report failure")
753 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -0800754 "A should have a syntax error reported")
755
James E. Blairdb04e6a2017-05-03 14:49:36 -0700756 def test_untrusted_shadow_error(self):
757 in_repo_conf = textwrap.dedent(
758 """
759 - job:
760 name: common-config-test
761 """)
762
763 file_dict = {'.zuul.yaml': in_repo_conf}
764 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
765 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200766 A.addApproval('Code-Review', 2)
767 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -0700768 self.waitUntilSettled()
769
770 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200771 self.assertEqual(A.reported, 1,
772 "A should report failure")
773 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -0700774 "A should have a syntax error reported")
775
James E. Blaird5656ad2017-06-02 14:29:41 -0700776 def test_untrusted_pipeline_error(self):
777 in_repo_conf = textwrap.dedent(
778 """
779 - pipeline:
780 name: test
781 """)
782
783 file_dict = {'.zuul.yaml': in_repo_conf}
784 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
785 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200786 A.addApproval('Code-Review', 2)
787 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700788 self.waitUntilSettled()
789
790 self.assertEqual(A.data['status'], 'NEW')
791 self.assertEqual(A.reported, 1,
792 "A should report failure")
793 self.assertIn('Pipelines may not be defined', A.messages[0],
794 "A should have a syntax error reported")
795
796 def test_untrusted_project_error(self):
797 in_repo_conf = textwrap.dedent(
798 """
799 - project:
800 name: org/project1
801 """)
802
803 file_dict = {'.zuul.yaml': in_repo_conf}
804 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
805 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200806 A.addApproval('Code-Review', 2)
807 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700808 self.waitUntilSettled()
809
810 self.assertEqual(A.data['status'], 'NEW')
811 self.assertEqual(A.reported, 1,
812 "A should report failure")
813 self.assertIn('the only project definition permitted', A.messages[0],
814 "A should have a syntax error reported")
815
James E. Blairf03173b2017-10-10 10:46:43 -0700816 def test_untrusted_depends_on_trusted(self):
817 with open(os.path.join(FIXTURE_DIR,
818 'config/in-repo/git/',
819 'common-config/zuul.yaml')) as f:
820 common_config = f.read()
821
822 common_config += textwrap.dedent(
823 """
824 - job:
825 name: project-test9
826 """)
827
828 file_dict = {'zuul.yaml': common_config}
829 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
830 files=file_dict)
831 in_repo_conf = textwrap.dedent(
832 """
833 - job:
834 name: project-test1
835 - project:
836 name: org/project
837 check:
838 jobs:
839 - project-test9
840 """)
841
842 file_dict = {'zuul.yaml': in_repo_conf}
843 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
844 files=file_dict)
845 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
846 B.subject, A.data['id'])
847 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
848 self.waitUntilSettled()
849
850 self.assertEqual(B.data['status'], 'NEW')
851 self.assertEqual(B.reported, 1,
852 "B should report failure")
853 self.assertIn('depends on a change to a config project',
854 B.messages[0],
855 "A should have a syntax error reported")
856
James E. Blaire64b0e42017-06-08 11:23:34 -0700857 def test_duplicate_node_error(self):
858 in_repo_conf = textwrap.dedent(
859 """
860 - nodeset:
861 name: duplicate
862 nodes:
863 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700864 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700865 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700866 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700867 """)
868
869 file_dict = {'.zuul.yaml': in_repo_conf}
870 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
871 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200872 A.addApproval('Code-Review', 2)
873 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700874 self.waitUntilSettled()
875
876 self.assertEqual(A.data['status'], 'NEW')
877 self.assertEqual(A.reported, 1,
878 "A should report failure")
879 self.assertIn('appears multiple times', A.messages[0],
880 "A should have a syntax error reported")
881
882 def test_duplicate_group_error(self):
883 in_repo_conf = textwrap.dedent(
884 """
885 - nodeset:
886 name: duplicate
887 nodes:
888 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700889 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700890 groups:
891 - name: group
892 nodes: compute
893 - name: group
894 nodes: compute
895 """)
896
897 file_dict = {'.zuul.yaml': in_repo_conf}
898 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
899 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200900 A.addApproval('Code-Review', 2)
901 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700902 self.waitUntilSettled()
903
904 self.assertEqual(A.data['status'], 'NEW')
905 self.assertEqual(A.reported, 1,
906 "A should report failure")
907 self.assertIn('appears multiple times', A.messages[0],
908 "A should have a syntax error reported")
909
James E. Blair4ae399f2017-09-20 17:15:09 -0700910 def test_secret_not_found_error(self):
911 in_repo_conf = textwrap.dedent(
912 """
913 - job:
914 name: test
915 secrets: does-not-exist
916 """)
917
918 file_dict = {'.zuul.yaml': in_repo_conf}
919 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
920 files=file_dict)
921 A.addApproval('Code-Review', 2)
922 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
923 self.waitUntilSettled()
924
925 self.assertEqual(A.data['status'], 'NEW')
926 self.assertEqual(A.reported, 1,
927 "A should report failure")
928 self.assertIn('secret "does-not-exist" was not found', A.messages[0],
929 "A should have a syntax error reported")
930
931 def test_nodeset_not_found_error(self):
932 in_repo_conf = textwrap.dedent(
933 """
934 - job:
935 name: test
936 nodeset: does-not-exist
937 """)
938
939 file_dict = {'.zuul.yaml': in_repo_conf}
940 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
941 files=file_dict)
942 A.addApproval('Code-Review', 2)
943 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
944 self.waitUntilSettled()
945
946 self.assertEqual(A.data['status'], 'NEW')
947 self.assertEqual(A.reported, 1,
948 "A should report failure")
949 self.assertIn('nodeset "does-not-exist" was not found', A.messages[0],
950 "A should have a syntax error reported")
951
James E. Blair89e25eb2017-09-26 09:11:31 -0700952 def test_template_not_found_error(self):
953 in_repo_conf = textwrap.dedent(
954 """
955 - job:
956 name: project-test1
957 - project:
958 name: org/project
959 templates:
960 - does-not-exist
961 """)
962
963 file_dict = {'.zuul.yaml': in_repo_conf}
964 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
965 files=file_dict)
966 A.addApproval('Code-Review', 2)
967 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
968 self.waitUntilSettled()
969
970 self.assertEqual(A.data['status'], 'NEW')
971 self.assertEqual(A.reported, 1,
972 "A should report failure")
973 self.assertIn('project template "does-not-exist" was not found',
974 A.messages[0],
975 "A should have a syntax error reported")
976
Monty Taylor8be3c0c2017-10-06 10:37:37 -0500977 def test_job_list_in_project_template_not_dict_error(self):
978 in_repo_conf = textwrap.dedent(
979 """
980 - job:
981 name: project-test1
982 - project-template:
983 name: some-jobs
984 check:
985 jobs:
986 - project-test1:
987 - required-projects:
988 org/project2
989 """)
990
991 file_dict = {'.zuul.yaml': in_repo_conf}
992 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
993 files=file_dict)
994 A.addApproval('Code-Review', 2)
995 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
996 self.waitUntilSettled()
997
998 self.assertEqual(A.data['status'], 'NEW')
999 self.assertEqual(A.reported, 1,
1000 "A should report failure")
1001 self.assertIn('expected str for dictionary value',
1002 A.messages[0], "A should have a syntax error reported")
1003
1004 def test_job_list_in_project_not_dict_error(self):
1005 in_repo_conf = textwrap.dedent(
1006 """
1007 - job:
1008 name: project-test1
1009 - project:
1010 name: org/project1
1011 check:
1012 jobs:
1013 - project-test1:
1014 - required-projects:
1015 org/project2
1016 """)
1017
1018 file_dict = {'.zuul.yaml': in_repo_conf}
1019 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1020 files=file_dict)
1021 A.addApproval('Code-Review', 2)
1022 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1023 self.waitUntilSettled()
1024
1025 self.assertEqual(A.data['status'], 'NEW')
1026 self.assertEqual(A.reported, 1,
1027 "A should report failure")
1028 self.assertIn('expected str for dictionary value',
1029 A.messages[0], "A should have a syntax error reported")
1030
James E. Blair1235f142017-10-07 09:11:43 -07001031 def test_project_template(self):
1032 # Tests that a project template is not modified when used, and
1033 # can therefore be used in subsequent reconfigurations.
1034 in_repo_conf = textwrap.dedent(
1035 """
1036 - job:
1037 name: project-test1
1038 - project-template:
1039 name: some-jobs
1040 tenant-one-gate:
1041 jobs:
1042 - project-test1:
1043 required-projects:
1044 - org/project1
1045 - project:
1046 name: org/project
1047 templates:
1048 - some-jobs
1049 """)
1050
1051 file_dict = {'.zuul.yaml': in_repo_conf}
1052 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1053 files=file_dict)
1054 A.addApproval('Code-Review', 2)
1055 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1056 self.waitUntilSettled()
1057 self.assertEqual(A.data['status'], 'MERGED')
1058 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1059 self.waitUntilSettled()
1060 in_repo_conf = textwrap.dedent(
1061 """
1062 - project:
1063 name: org/project1
1064 templates:
1065 - some-jobs
1066 """)
1067 file_dict = {'.zuul.yaml': in_repo_conf}
1068 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
1069 files=file_dict)
1070 B.addApproval('Code-Review', 2)
1071 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1072 self.waitUntilSettled()
1073 self.assertEqual(B.data['status'], 'MERGED')
1074
James E. Blairbccdfcf2017-10-07 13:37:26 -07001075 def test_job_remove_add(self):
1076 # Tests that a job can be removed from one repo and added in another.
1077 # First, remove the current config for project1 since it
1078 # references the job we want to remove.
1079 file_dict = {'.zuul.yaml': None}
1080 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1081 files=file_dict)
1082 A.setMerged()
1083 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1084 self.waitUntilSettled()
1085 # Then propose a change to delete the job from one repo...
1086 file_dict = {'.zuul.yaml': None}
1087 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1088 files=file_dict)
1089 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1090 self.waitUntilSettled()
1091 # ...and a second that depends on it that adds it to another repo.
1092 in_repo_conf = textwrap.dedent(
1093 """
1094 - job:
1095 name: project-test1
1096
1097 - project:
1098 name: org/project1
1099 check:
1100 jobs:
1101 - project-test1
1102 """)
1103 in_repo_playbook = textwrap.dedent(
1104 """
1105 - hosts: all
1106 tasks: []
1107 """)
1108 file_dict = {'.zuul.yaml': in_repo_conf,
1109 'playbooks/project-test1.yaml': in_repo_playbook}
1110 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C',
1111 files=file_dict,
1112 parent='refs/changes/1/1/1')
1113 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1114 C.subject, B.data['id'])
1115 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1116 self.waitUntilSettled()
1117 self.assertHistory([
1118 dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'),
1119 ], ordered=False)
1120
James E. Blair09f9ffe2017-07-11 15:30:25 -07001121 def test_multi_repo(self):
1122 downstream_repo_conf = textwrap.dedent(
1123 """
1124 - project:
1125 name: org/project1
1126 tenant-one-gate:
1127 jobs:
1128 - project-test1
1129
1130 - job:
1131 name: project1-test1
1132 parent: project-test1
1133 """)
1134
1135 file_dict = {'.zuul.yaml': downstream_repo_conf}
1136 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1137 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001138 A.addApproval('Code-Review', 2)
1139 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001140 self.waitUntilSettled()
1141
1142 self.assertEqual(A.data['status'], 'MERGED')
1143 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1144 self.waitUntilSettled()
1145
1146 upstream_repo_conf = textwrap.dedent(
1147 """
1148 - job:
1149 name: project-test1
1150
1151 - job:
1152 name: project-test2
1153
1154 - project:
1155 name: org/project
1156 tenant-one-gate:
1157 jobs:
1158 - project-test1
1159 """)
1160
1161 file_dict = {'.zuul.yaml': upstream_repo_conf}
1162 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1163 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001164 B.addApproval('Code-Review', 2)
1165 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001166 self.waitUntilSettled()
1167
1168 self.assertEqual(B.data['status'], 'MERGED')
1169 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
1170 self.waitUntilSettled()
1171
1172 tenant = self.sched.abide.tenants.get('tenant-one')
1173 # Ensure the latest change is reflected in the config; if it
1174 # isn't this will raise an exception.
1175 tenant.layout.getJob('project-test2')
1176
James E. Blair332636e2017-09-05 10:14:35 -07001177 def test_pipeline_error(self):
1178 with open(os.path.join(FIXTURE_DIR,
1179 'config/in-repo/git/',
1180 'common-config/zuul.yaml')) as f:
1181 base_common_config = f.read()
1182
1183 in_repo_conf_A = textwrap.dedent(
1184 """
1185 - pipeline:
1186 name: periodic
1187 foo: error
1188 """)
1189
1190 file_dict = {'zuul.yaml': None,
1191 'zuul.d/main.yaml': base_common_config,
1192 'zuul.d/test1.yaml': in_repo_conf_A}
1193 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1194 files=file_dict)
1195 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1196 self.waitUntilSettled()
1197 self.assertEqual(A.reported, 1,
1198 "A should report failure")
1199 self.assertIn('syntax error',
1200 A.messages[0],
1201 "A should have an error reported")
1202
1203 def test_change_series_error(self):
1204 with open(os.path.join(FIXTURE_DIR,
1205 'config/in-repo/git/',
1206 'common-config/zuul.yaml')) as f:
1207 base_common_config = f.read()
1208
1209 in_repo_conf_A = textwrap.dedent(
1210 """
1211 - pipeline:
1212 name: periodic
1213 foo: error
1214 """)
1215
1216 file_dict = {'zuul.yaml': None,
1217 'zuul.d/main.yaml': base_common_config,
1218 'zuul.d/test1.yaml': in_repo_conf_A}
1219 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1220 files=file_dict)
1221
1222 in_repo_conf_B = textwrap.dedent(
1223 """
1224 - job:
1225 name: project-test2
1226 foo: error
1227 """)
1228
1229 file_dict = {'zuul.yaml': None,
1230 'zuul.d/main.yaml': base_common_config,
1231 'zuul.d/test1.yaml': in_repo_conf_A,
1232 'zuul.d/test2.yaml': in_repo_conf_B}
1233 B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B',
1234 files=file_dict)
1235 B.setDependsOn(A, 1)
1236 C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C')
1237 C.setDependsOn(B, 1)
1238 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1239 self.waitUntilSettled()
1240
1241 self.assertEqual(C.reported, 1,
1242 "C should report failure")
1243 self.assertIn('depends on a change that failed to merge',
1244 C.messages[0],
1245 "C should have an error reported")
1246
James E. Blairc73c73a2017-01-20 15:15:15 -08001247
James E. Blairc9455002017-09-06 09:22:19 -07001248class TestInRepoJoin(ZuulTestCase):
1249 # In this config, org/project is not a member of any pipelines, so
1250 # that we may test the changes that cause it to join them.
1251
1252 tenant_config_file = 'config/in-repo-join/main.yaml'
1253
1254 def test_dynamic_dependent_pipeline(self):
1255 # Test dynamically adding a project to a
1256 # dependent pipeline for the first time
1257 self.executor_server.hold_jobs_in_build = True
1258
1259 tenant = self.sched.abide.tenants.get('tenant-one')
1260 gate_pipeline = tenant.layout.pipelines['gate']
1261
1262 in_repo_conf = textwrap.dedent(
1263 """
1264 - job:
1265 name: project-test1
1266
1267 - job:
1268 name: project-test2
1269
1270 - project:
1271 name: org/project
1272 gate:
1273 jobs:
1274 - project-test2
1275 """)
1276
1277 in_repo_playbook = textwrap.dedent(
1278 """
1279 - hosts: all
1280 tasks: []
1281 """)
1282
1283 file_dict = {'.zuul.yaml': in_repo_conf,
1284 'playbooks/project-test2.yaml': in_repo_playbook}
1285 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1286 files=file_dict)
1287 A.addApproval('Code-Review', 2)
1288 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1289 self.waitUntilSettled()
1290
1291 items = gate_pipeline.getAllItems()
1292 self.assertEqual(items[0].change.number, '1')
1293 self.assertEqual(items[0].change.patchset, '1')
1294 self.assertTrue(items[0].live)
1295
1296 self.executor_server.hold_jobs_in_build = False
1297 self.executor_server.release()
1298 self.waitUntilSettled()
1299
1300 # Make sure the dynamic queue got cleaned up
1301 self.assertEqual(gate_pipeline.queues, [])
1302
1303 def test_dynamic_dependent_pipeline_failure(self):
1304 # Test that a change behind a failing change adding a project
1305 # to a dependent pipeline is dequeued.
1306 self.executor_server.hold_jobs_in_build = True
1307
1308 in_repo_conf = textwrap.dedent(
1309 """
1310 - job:
1311 name: project-test1
1312
1313 - project:
1314 name: org/project
1315 gate:
1316 jobs:
1317 - project-test1
1318 """)
1319
1320 file_dict = {'.zuul.yaml': in_repo_conf}
1321 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1322 files=file_dict)
1323 self.executor_server.failJob('project-test1', A)
1324 A.addApproval('Code-Review', 2)
1325 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1326 self.waitUntilSettled()
1327
1328 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1329 B.addApproval('Code-Review', 2)
1330 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1331 self.waitUntilSettled()
1332
James E. Blair3490c5d2017-09-07 08:33:23 -07001333 self.orderedRelease()
James E. Blairc9455002017-09-06 09:22:19 -07001334 self.waitUntilSettled()
1335 self.assertEqual(A.reported, 2,
1336 "A should report start and failure")
1337 self.assertEqual(A.data['status'], 'NEW')
1338 self.assertEqual(B.reported, 1,
1339 "B should report start")
1340 self.assertHistory([
1341 dict(name='project-test1', result='FAILURE', changes='1,1'),
James E. Blair3490c5d2017-09-07 08:33:23 -07001342 dict(name='project-test1', result='ABORTED', changes='1,1 2,1'),
James E. Blairc9455002017-09-06 09:22:19 -07001343 ], ordered=False)
1344
James E. Blair0af198f2017-09-06 09:52:35 -07001345 def test_dynamic_dependent_pipeline_absent(self):
1346 # Test that a series of dependent changes don't report merge
1347 # failures to a pipeline they aren't in.
1348 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1349 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1350 B.setDependsOn(A, 1)
1351
1352 A.addApproval('Code-Review', 2)
1353 A.addApproval('Approved', 1)
1354 B.addApproval('Code-Review', 2)
1355 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1356 self.waitUntilSettled()
1357 self.assertEqual(A.reported, 0,
1358 "A should not report")
1359 self.assertEqual(A.data['status'], 'NEW')
1360 self.assertEqual(B.reported, 0,
1361 "B should not report")
1362 self.assertEqual(B.data['status'], 'NEW')
1363 self.assertHistory([])
1364
James E. Blairc9455002017-09-06 09:22:19 -07001365
James E. Blairc73c73a2017-01-20 15:15:15 -08001366class TestAnsible(AnsibleZuulTestCase):
1367 # A temporary class to hold new tests while others are disabled
1368
1369 tenant_config_file = 'config/ansible/main.yaml'
1370
1371 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +11001372 # Keep the jobdir around so we can inspect contents if an
1373 # assert fails.
1374 self.executor_server.keep_jobdir = True
1375 # Output extra ansible info so we might see errors.
1376 self.executor_server.verbose = True
1377 # Add a site variables file, used by check-vars
1378 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
1379 'variables.yaml')
1380 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -08001381 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1382 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1383 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +02001384 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +11001385 with self.jobLog(build_timeout):
1386 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001387 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +11001388 with self.jobLog(build_faillocal):
1389 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001390 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +11001391 with self.jobLog(build_failpost):
1392 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001393 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +11001394 with self.jobLog(build_check_vars):
1395 self.assertEqual(build_check_vars.result, 'SUCCESS')
Monty Tayloraff8b402017-08-16 18:40:41 -05001396 build_check_secret_names = self.getJobFromHistory('check-secret-names')
1397 with self.jobLog(build_check_secret_names):
1398 self.assertEqual(build_check_secret_names.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001399 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +11001400 with self.jobLog(build_hello):
1401 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001402 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +11001403 with self.jobLog(build_python27):
1404 self.assertEqual(build_python27.result, 'SUCCESS')
1405 flag_path = os.path.join(self.test_root,
1406 build_python27.uuid + '.flag')
1407 self.assertTrue(os.path.exists(flag_path))
1408 copied_path = os.path.join(self.test_root, build_python27.uuid +
1409 '.copied')
1410 self.assertTrue(os.path.exists(copied_path))
1411 failed_path = os.path.join(self.test_root, build_python27.uuid +
1412 '.failed')
1413 self.assertFalse(os.path.exists(failed_path))
1414 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
1415 '.pre.flag')
1416 self.assertTrue(os.path.exists(pre_flag_path))
1417 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
1418 '.post.flag')
1419 self.assertTrue(os.path.exists(post_flag_path))
1420 bare_role_flag_path = os.path.join(self.test_root,
1421 build_python27.uuid +
1422 '.bare-role.flag')
1423 self.assertTrue(os.path.exists(bare_role_flag_path))
1424 secrets_path = os.path.join(self.test_root,
1425 build_python27.uuid + '.secrets')
1426 with open(secrets_path) as f:
1427 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -08001428
Jamie Lennox7655b552017-03-17 12:33:38 +11001429 msg = A.messages[0]
1430 success = "{} https://success.example.com/zuul-logs/{}"
1431 fail = "{} https://failure.example.com/zuul-logs/{}"
1432 self.assertIn(success.format("python27", build_python27.uuid), msg)
1433 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
1434 self.assertIn(success.format("check-vars",
1435 build_check_vars.uuid), msg)
1436 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
1437 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
1438 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +02001439
James E. Blairabbaa6f2017-04-06 16:11:44 -07001440 def _add_job(self, job_name):
1441 conf = textwrap.dedent(
1442 """
1443 - job:
1444 name: %s
1445
1446 - project:
1447 name: org/plugin-project
1448 check:
1449 jobs:
1450 - %s
1451 """ % (job_name, job_name))
1452
1453 file_dict = {'.zuul.yaml': conf}
1454 A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A',
1455 files=file_dict)
1456 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1457 self.waitUntilSettled()
1458
1459 def test_plugins(self):
1460 # Keep the jobdir around so we can inspect contents if an
1461 # assert fails.
1462 self.executor_server.keep_jobdir = True
1463 # Output extra ansible info so we might see errors.
1464 self.executor_server.verbose = True
1465
1466 count = 0
1467 plugin_tests = [
1468 ('passwd', 'FAILURE'),
1469 ('cartesian', 'SUCCESS'),
1470 ('consul_kv', 'FAILURE'),
1471 ('credstash', 'FAILURE'),
1472 ('csvfile_good', 'SUCCESS'),
1473 ('csvfile_bad', 'FAILURE'),
Monty Taylor93ad2212017-08-02 14:59:50 -05001474 ('uri_bad_path', 'FAILURE'),
1475 ('uri_bad_scheme', 'FAILURE'),
Monty Taylor788a40e2017-08-02 16:14:05 -05001476 ('block_local_override', 'FAILURE'),
Monty Taylor8da768f2017-08-31 14:15:35 -05001477 ('file_local_good', 'SUCCESS'),
1478 ('file_local_bad', 'FAILURE'),
James E. Blairabbaa6f2017-04-06 16:11:44 -07001479 ]
1480 for job_name, result in plugin_tests:
1481 count += 1
1482 self._add_job(job_name)
1483
1484 job = self.getJobFromHistory(job_name)
1485 with self.jobLog(job):
1486 self.assertEqual(count, len(self.history))
1487 build = self.history[-1]
1488 self.assertEqual(build.result, result)
1489
1490 # TODOv3(jeblair): parse the ansible output and verify we're
1491 # getting the exception we expect.
1492
James E. Blairb9c0d772017-03-03 14:34:49 -08001493
James E. Blaira4d4eef2017-06-30 14:49:17 -07001494class TestPrePlaybooks(AnsibleZuulTestCase):
1495 # A temporary class to hold new tests while others are disabled
1496
1497 tenant_config_file = 'config/pre-playbook/main.yaml'
1498
1499 def test_pre_playbook_fail(self):
1500 # Test that we run the post playbooks (but not the actual
1501 # playbook) when a pre-playbook fails.
1502 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1503 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1504 self.waitUntilSettled()
1505 build = self.getJobFromHistory('python27')
1506 self.assertIsNone(build.result)
1507 self.assertIn('RETRY_LIMIT', A.messages[0])
1508 flag_path = os.path.join(self.test_root, build.uuid +
1509 '.main.flag')
1510 self.assertFalse(os.path.exists(flag_path))
1511 pre_flag_path = os.path.join(self.test_root, build.uuid +
1512 '.pre.flag')
1513 self.assertFalse(os.path.exists(pre_flag_path))
1514 post_flag_path = os.path.join(self.test_root, build.uuid +
1515 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -07001516 self.assertTrue(os.path.exists(post_flag_path),
1517 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -07001518
1519
James E. Blairbacbb882017-10-17 09:48:23 -07001520class TestPostPlaybooks(AnsibleZuulTestCase):
1521 tenant_config_file = 'config/post-playbook/main.yaml'
1522
1523 def test_post_playbook_abort(self):
1524 # Test that when we abort a job in the post playbook, that we
1525 # don't send back POST_FAILURE.
1526 self.executor_server.verbose = True
1527 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1528 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1529
1530 while not len(self.builds):
1531 time.sleep(0.1)
1532 build = self.builds[0]
1533
1534 post_start = os.path.join(self.test_root, build.uuid +
1535 '.post_start.flag')
1536 start = time.time()
1537 while time.time() < start + 90:
1538 if os.path.exists(post_start):
1539 break
1540 time.sleep(0.1)
1541 # The post playbook has started, abort the job
1542 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1543 self.waitUntilSettled()
1544
1545 build = self.getJobFromHistory('python27')
1546 self.assertEqual('ABORTED', build.result)
1547
1548 post_end = os.path.join(self.test_root, build.uuid +
1549 '.post_end.flag')
1550 self.assertTrue(os.path.exists(post_start))
1551 self.assertFalse(os.path.exists(post_end))
1552
1553
James E. Blairb9c0d772017-03-03 14:34:49 -08001554class TestBrokenConfig(ZuulTestCase):
1555 # Test that we get an appropriate syntax error if we start with a
1556 # broken config.
1557
1558 tenant_config_file = 'config/broken/main.yaml'
1559
1560 def setUp(self):
1561 with testtools.ExpectedException(
1562 zuul.configloader.ConfigurationSyntaxError,
1563 "\nZuul encountered a syntax error"):
1564 super(TestBrokenConfig, self).setUp()
1565
1566 def test_broken_config_on_startup(self):
1567 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001568
1569
1570class TestProjectKeys(ZuulTestCase):
1571 # Test that we can generate project keys
1572
1573 # Normally the test infrastructure copies a static key in place
1574 # for each project before starting tests. This saves time because
1575 # Zuul's automatic key-generation on startup can be slow. To make
1576 # sure we exercise that code, in this test we allow Zuul to create
1577 # keys for the project on startup.
1578 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +02001579 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001580 tenant_config_file = 'config/in-repo/main.yaml'
1581
1582 def test_key_generation(self):
1583 key_root = os.path.join(self.state_root, 'keys')
1584 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
1585 # Make sure that a proper key was created on startup
1586 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -07001587 private_key, public_key = \
1588 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001589
1590 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
1591 fixture_private_key = i.read()
1592
1593 # Make sure that we didn't just end up with the static fixture
1594 # key
1595 self.assertNotEqual(fixture_private_key, private_key)
1596
1597 # Make sure it's the right length
1598 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -07001599
1600
James E. Blairbb94dfa2017-07-11 07:45:19 -07001601class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -07001602 def _assertRolePath(self, build, playbook, content):
1603 path = os.path.join(self.test_root, build.uuid,
1604 'ansible', playbook, 'ansible.cfg')
1605 roles_paths = []
1606 with open(path) as f:
1607 for line in f:
1608 if line.startswith('roles_path'):
1609 roles_paths.append(line)
1610 print(roles_paths)
1611 if content:
1612 self.assertEqual(len(roles_paths), 1,
1613 "Should have one roles_path line in %s" %
1614 (playbook,))
1615 self.assertIn(content, roles_paths[0])
1616 else:
1617 self.assertEqual(len(roles_paths), 0,
1618 "Should have no roles_path line in %s" %
1619 (playbook,))
1620
James E. Blairbb94dfa2017-07-11 07:45:19 -07001621
1622class TestRoles(RoleTestCase):
1623 tenant_config_file = 'config/roles/main.yaml'
1624
James E. Blairbce76932017-05-04 10:03:15 -07001625 def test_role(self):
1626 # This exercises a proposed change to a role being checked out
1627 # and used.
1628 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
1629 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1630 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1631 B.subject, A.data['id'])
1632 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1633 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1634 self.waitUntilSettled()
1635 self.assertHistory([
1636 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
1637 ])
James E. Blair6459db12017-06-29 14:57:20 -07001638
James E. Blair1b27f6a2017-07-14 14:09:07 -07001639 def test_role_inheritance(self):
1640 self.executor_server.hold_jobs_in_build = True
1641 conf = textwrap.dedent(
1642 """
1643 - job:
1644 name: parent
1645 roles:
1646 - zuul: bare-role
1647 pre-run: playbooks/parent-pre
1648 post-run: playbooks/parent-post
1649
1650 - job:
1651 name: project-test
1652 parent: parent
1653 roles:
1654 - zuul: org/project
1655
1656 - project:
1657 name: org/project
1658 check:
1659 jobs:
1660 - project-test
1661 """)
1662
1663 file_dict = {'.zuul.yaml': conf}
1664 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1665 files=file_dict)
1666 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1667 self.waitUntilSettled()
1668
1669 self.assertEqual(len(self.builds), 1)
1670 build = self.getBuildByName('project-test')
1671 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
1672 self._assertRolePath(build, 'playbook_0', 'role_0')
1673 self._assertRolePath(build, 'playbook_0', 'role_1')
1674 self._assertRolePath(build, 'post_playbook_0', 'role_0')
1675
1676 self.executor_server.hold_jobs_in_build = False
1677 self.executor_server.release()
1678 self.waitUntilSettled()
1679
1680 self.assertHistory([
1681 dict(name='project-test', result='SUCCESS', changes='1,1'),
1682 ])
1683
James E. Blair6f699732017-07-18 14:19:11 -07001684 def test_role_error(self):
1685 conf = textwrap.dedent(
1686 """
1687 - job:
1688 name: project-test
1689 roles:
1690 - zuul: common-config
1691
1692 - project:
1693 name: org/project
1694 check:
1695 jobs:
1696 - project-test
1697 """)
1698
1699 file_dict = {'.zuul.yaml': conf}
1700 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1701 files=file_dict)
1702 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1703 self.waitUntilSettled()
1704 self.assertIn(
1705 '- project-test project-test : ERROR Unable to find role',
1706 A.messages[-1])
1707
James E. Blair6459db12017-06-29 14:57:20 -07001708
James E. Blairbb94dfa2017-07-11 07:45:19 -07001709class TestImplicitRoles(RoleTestCase):
1710 tenant_config_file = 'config/implicit-roles/main.yaml'
1711
1712 def test_missing_roles(self):
1713 # Test implicit and explicit roles for a project which does
1714 # not have roles. The implicit role should be silently
1715 # ignored since the project doesn't supply roles, but if a
1716 # user declares an explicit role, it should error.
1717 self.executor_server.hold_jobs_in_build = True
1718 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
1719 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1720 self.waitUntilSettled()
1721
1722 self.assertEqual(len(self.builds), 2)
1723 build = self.getBuildByName('implicit-role-fail')
1724 self._assertRolePath(build, 'playbook_0', None)
1725
1726 self.executor_server.hold_jobs_in_build = False
1727 self.executor_server.release()
1728 self.waitUntilSettled()
1729 # The retry_limit doesn't get recorded
1730 self.assertHistory([
1731 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
1732 ])
1733
1734 def test_roles(self):
1735 # Test implicit and explicit roles for a project which does
1736 # have roles. In both cases, we should end up with the role
1737 # in the path. In the explicit case, ensure we end up with
1738 # the name we specified.
1739 self.executor_server.hold_jobs_in_build = True
1740 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
1741 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1742 self.waitUntilSettled()
1743
1744 self.assertEqual(len(self.builds), 2)
1745 build = self.getBuildByName('implicit-role-ok')
1746 self._assertRolePath(build, 'playbook_0', 'role_0')
1747
1748 build = self.getBuildByName('explicit-role-ok')
1749 self._assertRolePath(build, 'playbook_0', 'role_0')
1750
1751 self.executor_server.hold_jobs_in_build = False
1752 self.executor_server.release()
1753 self.waitUntilSettled()
1754 self.assertHistory([
1755 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
1756 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
1757 ], ordered=False)
1758
1759
James E. Blair6459db12017-06-29 14:57:20 -07001760class TestShadow(ZuulTestCase):
1761 tenant_config_file = 'config/shadow/main.yaml'
1762
1763 def test_shadow(self):
1764 # Test that a repo is allowed to shadow another's job definitions.
1765 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1766 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1767 self.waitUntilSettled()
1768 self.assertHistory([
1769 dict(name='test1', result='SUCCESS', changes='1,1'),
1770 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -07001771 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -07001772
1773
1774class TestDataReturn(AnsibleZuulTestCase):
1775 tenant_config_file = 'config/data-return/main.yaml'
1776
1777 def test_data_return(self):
James E. Blair196f61a2017-06-30 15:42:29 -07001778 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1779 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1780 self.waitUntilSettled()
1781 self.assertHistory([
1782 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07001783 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
James E. Blair698703c2017-09-15 20:58:30 -06001784 dict(name='child', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07001785 ], ordered=False)
1786 self.assertIn('- data-return http://example.com/test/log/url/',
1787 A.messages[-1])
1788 self.assertIn('- data-return-relative '
1789 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -07001790 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -07001791
1792
1793class TestDiskAccounting(AnsibleZuulTestCase):
1794 config_file = 'zuul-disk-accounting.conf'
1795 tenant_config_file = 'config/disk-accountant/main.yaml'
1796
1797 def test_disk_accountant_kills_job(self):
1798 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1799 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1800 self.waitUntilSettled()
1801 self.assertHistory([
1802 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001803
1804
1805class TestMaxNodesPerJob(AnsibleZuulTestCase):
1806 tenant_config_file = 'config/multi-tenant/main.yaml'
1807
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00001808 def test_max_timeout_exceeded(self):
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001809 in_repo_conf = textwrap.dedent(
1810 """
1811 - job:
1812 name: test-job
James E. Blair7e3e6882017-09-20 15:47:13 -07001813 nodeset:
1814 nodes:
1815 - name: node01
1816 label: fake
1817 - name: node02
1818 label: fake
1819 - name: node03
1820 label: fake
1821 - name: node04
1822 label: fake
1823 - name: node05
1824 label: fake
1825 - name: node06
1826 label: fake
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001827 """)
1828 file_dict = {'.zuul.yaml': in_repo_conf}
1829 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1830 files=file_dict)
1831 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1832 self.waitUntilSettled()
1833 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
1834 A.messages[0], "A should fail because of nodes limit")
1835
1836 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
1837 files=file_dict)
1838 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1839 self.waitUntilSettled()
1840 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
1841 "B should not fail because of nodes limit")
James E. Blair2bab6e72017-08-07 09:52:45 -07001842
1843
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00001844class TestMaxTimeout(AnsibleZuulTestCase):
1845 tenant_config_file = 'config/multi-tenant/main.yaml'
1846
1847 def test_max_nodes_reached(self):
1848 in_repo_conf = textwrap.dedent(
1849 """
1850 - job:
1851 name: test-job
1852 timeout: 3600
1853 """)
1854 file_dict = {'.zuul.yaml': in_repo_conf}
1855 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1856 files=file_dict)
1857 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1858 self.waitUntilSettled()
1859 self.assertIn('The job "test-job" exceeds tenant max-job-timeout',
1860 A.messages[0], "A should fail because of timeout limit")
1861
1862 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
1863 files=file_dict)
1864 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1865 self.waitUntilSettled()
1866 self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0],
1867 "B should not fail because of timeout limit")
1868
1869
James E. Blair2bab6e72017-08-07 09:52:45 -07001870class TestBaseJobs(ZuulTestCase):
1871 tenant_config_file = 'config/base-jobs/main.yaml'
1872
1873 def test_multiple_base_jobs(self):
1874 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1875 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1876 self.waitUntilSettled()
1877 self.assertHistory([
1878 dict(name='my-job', result='SUCCESS', changes='1,1'),
1879 dict(name='other-job', result='SUCCESS', changes='1,1'),
1880 ], ordered=False)
1881 self.assertEqual(self.getJobFromHistory('my-job').
1882 parameters['zuul']['jobtags'],
1883 ['mybase'])
1884 self.assertEqual(self.getJobFromHistory('other-job').
1885 parameters['zuul']['jobtags'],
1886 ['otherbase'])
1887
1888 def test_untrusted_base_job(self):
1889 """Test that a base job may not be defined in an untrusted repo"""
1890 in_repo_conf = textwrap.dedent(
1891 """
1892 - job:
1893 name: fail-base
1894 parent: null
1895 """)
1896
1897 file_dict = {'.zuul.yaml': in_repo_conf}
1898 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1899 files=file_dict)
1900 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1901 self.waitUntilSettled()
1902 self.assertEqual(A.reported, 1,
1903 "A should report failure")
1904 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
1905 self.assertIn('Base jobs must be defined in config projects',
1906 A.messages[0])
1907 self.assertHistory([])
James E. Blairdb089032017-08-15 13:42:12 -07001908
1909
1910class TestSecretLeaks(AnsibleZuulTestCase):
1911 tenant_config_file = 'config/secret-leaks/main.yaml'
1912
1913 def searchForContent(self, path, content):
1914 matches = []
1915 for (dirpath, dirnames, filenames) in os.walk(path):
1916 for filename in filenames:
1917 filepath = os.path.join(dirpath, filename)
1918 with open(filepath, 'rb') as f:
1919 if content in f.read():
1920 matches.append(filepath[len(path):])
1921 return matches
1922
1923 def _test_secret_file(self):
1924 # Or rather -- test that they *don't* leak.
1925 # Keep the jobdir around so we can inspect contents.
1926 self.executor_server.keep_jobdir = True
1927 conf = textwrap.dedent(
1928 """
1929 - project:
1930 name: org/project
1931 check:
1932 jobs:
1933 - secret-file
1934 """)
1935
1936 file_dict = {'.zuul.yaml': conf}
1937 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1938 files=file_dict)
1939 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1940 self.waitUntilSettled()
1941 self.assertHistory([
1942 dict(name='secret-file', result='SUCCESS', changes='1,1'),
1943 ], ordered=False)
1944 matches = self.searchForContent(self.history[0].jobdir.root,
1945 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07001946 self.assertEqual(set(['/work/secret-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07001947 set(matches))
1948
1949 def test_secret_file(self):
1950 self._test_secret_file()
1951
1952 def test_secret_file_verbose(self):
1953 # Output extra ansible info to exercise alternate logging code
1954 # paths.
1955 self.executor_server.verbose = True
1956 self._test_secret_file()
1957
1958 def _test_secret_file_fail(self):
1959 # Or rather -- test that they *don't* leak.
1960 # Keep the jobdir around so we can inspect contents.
1961 self.executor_server.keep_jobdir = True
1962 conf = textwrap.dedent(
1963 """
1964 - project:
1965 name: org/project
1966 check:
1967 jobs:
1968 - secret-file-fail
1969 """)
1970
1971 file_dict = {'.zuul.yaml': conf}
1972 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1973 files=file_dict)
1974 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1975 self.waitUntilSettled()
1976 self.assertHistory([
1977 dict(name='secret-file-fail', result='FAILURE', changes='1,1'),
1978 ], ordered=False)
1979 matches = self.searchForContent(self.history[0].jobdir.root,
1980 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07001981 self.assertEqual(set(['/work/failure-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07001982 set(matches))
1983
1984 def test_secret_file_fail(self):
1985 self._test_secret_file_fail()
1986
1987 def test_secret_file_fail_verbose(self):
1988 # Output extra ansible info to exercise alternate logging code
1989 # paths.
1990 self.executor_server.verbose = True
1991 self._test_secret_file_fail()
James E. Blaira00910c2017-08-23 09:15:04 -07001992
1993
1994class TestJobOutput(AnsibleZuulTestCase):
1995 tenant_config_file = 'config/job-output/main.yaml'
1996
1997 def _get_file(self, build, path):
1998 p = os.path.join(build.jobdir.root, path)
1999 with open(p) as f:
2000 return f.read()
2001
2002 def test_job_output(self):
Monty Taylor0e2489a2017-10-10 11:57:29 -05002003 # Verify that command standard output appears in the job output,
2004 # and that failures in the final playbook get logged.
James E. Blaira00910c2017-08-23 09:15:04 -07002005
2006 # This currently only verifies we receive output from
2007 # localhost. Notably, it does not verify we receive output
2008 # via zuul_console streaming.
2009 self.executor_server.keep_jobdir = True
2010 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2011 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2012 self.waitUntilSettled()
2013 self.assertHistory([
2014 dict(name='job-output', result='SUCCESS', changes='1,1'),
2015 ], ordered=False)
2016
2017 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2018 j = json.loads(self._get_file(self.history[0],
2019 'work/logs/job-output.json'))
2020 self.assertEqual(token,
2021 j[0]['plays'][0]['tasks'][0]
2022 ['hosts']['localhost']['stdout'])
2023
2024 print(self._get_file(self.history[0],
2025 'work/logs/job-output.txt'))
2026 self.assertIn(token,
2027 self._get_file(self.history[0],
2028 'work/logs/job-output.txt'))
Monty Taylor0e2489a2017-10-10 11:57:29 -05002029
2030 def test_job_output_failure_log(self):
2031 logger = logging.getLogger('zuul.AnsibleJob')
2032 output = io.StringIO()
2033 logger.addHandler(logging.StreamHandler(output))
2034
2035 # Verify that a failure in the last post playbook emits the contents
2036 # of the json output to the log
2037 self.executor_server.keep_jobdir = True
2038 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
2039 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2040 self.waitUntilSettled()
2041 self.assertHistory([
2042 dict(name='job-output-failure',
2043 result='POST_FAILURE', changes='1,1'),
2044 ], ordered=False)
2045
2046 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2047 j = json.loads(self._get_file(self.history[0],
2048 'work/logs/job-output.json'))
2049 self.assertEqual(token,
2050 j[0]['plays'][0]['tasks'][0]
2051 ['hosts']['localhost']['stdout'])
2052
2053 print(self._get_file(self.history[0],
2054 'work/logs/job-output.json'))
2055 self.assertIn(token,
2056 self._get_file(self.history[0],
2057 'work/logs/job-output.txt'))
2058
2059 log_output = output.getvalue()
2060 self.assertIn('Final playbook failed', log_output)
2061 self.assertIn('Failure test', log_output)