blob: b30d710651faa9bb04310f766082f1d456b7d0ef [file] [log] [blame]
James E. Blair59fdbac2015-12-07 17:08:06 -08001#!/usr/bin/env python
2
3# Copyright 2012 Hewlett-Packard Development Company, L.P.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
Monty Taylor0e2489a2017-10-10 11:57:29 -050017import io
James E. Blaira00910c2017-08-23 09:15:04 -070018import json
Monty Taylor0e2489a2017-10-10 11:57:29 -050019import logging
James E. Blaira92cbc82017-01-23 14:56:49 -080020import os
James E. Blair14abdf42015-12-09 16:11:53 -080021import textwrap
James E. Blair3a098dd2017-10-04 14:37:29 -070022import gc
James E. Blairbacbb882017-10-17 09:48:23 -070023import time
James E. Blair3a098dd2017-10-04 14:37:29 -070024from unittest import skip
James E. Blair59fdbac2015-12-07 17:08:06 -080025
James E. Blairb9c0d772017-03-03 14:34:49 -080026import testtools
27
28import zuul.configloader
James E. Blairbf1a4f22017-03-17 10:59:37 -070029from zuul.lib import encryption
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +000030from tests.base import AnsibleZuulTestCase, ZuulTestCase, FIXTURE_DIR
James E. Blair59fdbac2015-12-07 17:08:06 -080031
James E. Blair59fdbac2015-12-07 17:08:06 -080032
James E. Blair3f876d52016-07-22 13:07:14 -070033class TestMultipleTenants(AnsibleZuulTestCase):
James E. Blair59fdbac2015-12-07 17:08:06 -080034 # A temporary class to hold new tests while others are disabled
35
James E. Blair2a629ec2015-12-22 15:32:02 -080036 tenant_config_file = 'config/multi-tenant/main.yaml'
James E. Blair59fdbac2015-12-07 17:08:06 -080037
James E. Blair83005782015-12-11 14:46:03 -080038 def test_multiple_tenants(self):
James E. Blair96f26942015-12-09 10:15:59 -080039 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +020040 A.addApproval('Code-Review', 2)
41 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair59fdbac2015-12-07 17:08:06 -080042 self.waitUntilSettled()
James E. Blair96f26942015-12-09 10:15:59 -080043 self.assertEqual(self.getJobFromHistory('project1-test1').result,
James E. Blair59fdbac2015-12-07 17:08:06 -080044 'SUCCESS')
James E. Blair96c6bf82016-01-15 16:20:40 -080045 self.assertEqual(self.getJobFromHistory('python27').result,
46 'SUCCESS')
James E. Blair59fdbac2015-12-07 17:08:06 -080047 self.assertEqual(A.data['status'], 'MERGED')
James E. Blair96f26942015-12-09 10:15:59 -080048 self.assertEqual(A.reported, 2,
49 "A should report start and success")
50 self.assertIn('tenant-one-gate', A.messages[1],
51 "A should transit tenant-one gate")
52 self.assertNotIn('tenant-two-gate', A.messages[1],
53 "A should *not* transit tenant-two gate")
James E. Blair59fdbac2015-12-07 17:08:06 -080054
James E. Blair96f26942015-12-09 10:15:59 -080055 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +020056 B.addApproval('Code-Review', 2)
57 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair96f26942015-12-09 10:15:59 -080058 self.waitUntilSettled()
James E. Blair96c6bf82016-01-15 16:20:40 -080059 self.assertEqual(self.getJobFromHistory('python27',
60 'org/project2').result,
61 'SUCCESS')
James E. Blair96f26942015-12-09 10:15:59 -080062 self.assertEqual(self.getJobFromHistory('project2-test1').result,
63 'SUCCESS')
64 self.assertEqual(B.data['status'], 'MERGED')
65 self.assertEqual(B.reported, 2,
66 "B should report start and success")
67 self.assertIn('tenant-two-gate', B.messages[1],
68 "B should transit tenant-two gate")
69 self.assertNotIn('tenant-one-gate', B.messages[1],
70 "B should *not* transit tenant-one gate")
James E. Blair59fdbac2015-12-07 17:08:06 -080071
James E. Blair96f26942015-12-09 10:15:59 -080072 self.assertEqual(A.reported, 2, "Activity in tenant two should"
73 "not affect tenant one")
James E. Blair14abdf42015-12-09 16:11:53 -080074
James E. Blair83005782015-12-11 14:46:03 -080075
Tobias Henkel83167622017-06-30 19:45:03 +020076class TestFinal(ZuulTestCase):
77
78 tenant_config_file = 'config/final/main.yaml'
79
80 def test_final_variant_ok(self):
81 # test clean usage of final parent job
82 in_repo_conf = textwrap.dedent(
83 """
84 - project:
85 name: org/project
86 check:
87 jobs:
88 - job-final
89 """)
90
91 file_dict = {'.zuul.yaml': in_repo_conf}
92 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
93 files=file_dict)
94 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
95 self.waitUntilSettled()
96
97 self.assertEqual(A.reported, 1)
98 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1')
99
100 def test_final_variant_error(self):
101 # test misuse of final parent job
102 in_repo_conf = textwrap.dedent(
103 """
104 - project:
105 name: org/project
106 check:
107 jobs:
108 - job-final:
109 vars:
110 dont_override_this: bar
111 """)
112 file_dict = {'.zuul.yaml': in_repo_conf}
113 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
114 files=file_dict)
115 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
116 self.waitUntilSettled()
117
118 # The second patch tried to override some variables.
119 # Thus it should fail.
120 self.assertEqual(A.reported, 1)
121 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
122 self.assertIn('Unable to modify final job', A.messages[0])
123
124 def test_final_inheritance(self):
125 # test misuse of final parent job
126 in_repo_conf = textwrap.dedent(
127 """
128 - job:
129 name: project-test
130 parent: job-final
131
132 - project:
133 name: org/project
134 check:
135 jobs:
136 - project-test
137 """)
138
139 in_repo_playbook = textwrap.dedent(
140 """
141 - hosts: all
142 tasks: []
143 """)
144
145 file_dict = {'.zuul.yaml': in_repo_conf,
146 'playbooks/project-test.yaml': in_repo_playbook}
147 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
148 files=file_dict)
149 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
150 self.waitUntilSettled()
151
152 # The second patch tried to override some variables.
153 # Thus it should fail.
154 self.assertEqual(A.reported, 1)
155 self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1')
156 self.assertIn('Unable to inherit from final job', A.messages[0])
157
158
James E. Blair09998792017-10-15 18:02:18 -0700159class TestBranchVariants(ZuulTestCase):
160 tenant_config_file = 'config/branch-variants/main.yaml'
161
162 def test_branch_variants(self):
163 # Test branch variants of jobs with inheritance
164 self.executor_server.hold_jobs_in_build = True
165 # This creates a new branch with a copy of the config in master
166 self.create_branch('puppet-integration', 'stable')
167 self.fake_gerrit.addEvent(
168 self.fake_gerrit.getFakeBranchCreatedEvent(
169 'puppet-integration', 'stable'))
170 self.waitUntilSettled()
171
172 A = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'A')
173 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
174 self.waitUntilSettled()
175
176 self.assertEqual(len(self.builds[0].parameters['pre_playbooks']), 3)
177 self.executor_server.hold_jobs_in_build = False
178 self.executor_server.release()
179 self.waitUntilSettled()
180
181
James E. Blairff555742017-02-19 11:34:27 -0800182class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -0800183 # A temporary class to hold new tests while others are disabled
184
Tobias Henkelabf973e2017-07-28 10:07:34 +0200185 config_file = 'zuul-connections-gerrit-and-github.conf'
James E. Blair2a629ec2015-12-22 15:32:02 -0800186 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -0800187
James E. Blair83005782015-12-11 14:46:03 -0800188 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -0800189 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200190 A.addApproval('Code-Review', 2)
191 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -0800192 self.waitUntilSettled()
193 self.assertEqual(self.getJobFromHistory('project-test1').result,
194 'SUCCESS')
195 self.assertEqual(A.data['status'], 'MERGED')
196 self.assertEqual(A.reported, 2,
197 "A should report start and success")
198 self.assertIn('tenant-one-gate', A.messages[1],
199 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -0800200
James E. Blair3a098dd2017-10-04 14:37:29 -0700201 @skip("This test is useful, but not reliable")
202 def test_full_and_dynamic_reconfig(self):
203 self.executor_server.hold_jobs_in_build = True
204 in_repo_conf = textwrap.dedent(
205 """
206 - job:
207 name: project-test1
208
209 - project:
210 name: org/project
211 tenant-one-gate:
212 jobs:
213 - project-test1
214 """)
215
216 file_dict = {'.zuul.yaml': in_repo_conf}
217 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
218 files=file_dict)
219 A.addApproval('Code-Review', 2)
220 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
221 self.waitUntilSettled()
222 self.sched.reconfigure(self.config)
223 self.waitUntilSettled()
224
225 gc.collect()
226 pipelines = [obj for obj in gc.get_objects()
227 if isinstance(obj, zuul.model.Pipeline)]
228 self.assertEqual(len(pipelines), 4)
229
230 self.executor_server.hold_jobs_in_build = False
231 self.executor_server.release()
232 self.waitUntilSettled()
233
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700234 def test_dynamic_config(self):
235 in_repo_conf = textwrap.dedent(
236 """
237 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200238 name: project-test1
239
240 - job:
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700241 name: project-test2
242
243 - project:
244 name: org/project
245 tenant-one-gate:
246 jobs:
247 - project-test2
248 """)
249
James E. Blairc73c73a2017-01-20 15:15:15 -0800250 in_repo_playbook = textwrap.dedent(
251 """
252 - hosts: all
253 tasks: []
254 """)
255
256 file_dict = {'.zuul.yaml': in_repo_conf,
257 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700258 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800259 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200260 A.addApproval('Code-Review', 2)
261 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700262 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700263 self.assertEqual(A.data['status'], 'MERGED')
264 self.assertEqual(A.reported, 2,
265 "A should report start and success")
266 self.assertIn('tenant-one-gate', A.messages[1],
267 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800268 self.assertHistory([
269 dict(name='project-test2', result='SUCCESS', changes='1,1')])
270
James E. Blairc2a5ed72017-02-20 14:12:01 -0500271 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800272 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500273
James E. Blair646322f2017-01-27 15:50:34 -0800274 # Now that the config change is landed, it should be live for
275 # subsequent changes.
276 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200277 B.addApproval('Code-Review', 2)
278 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair646322f2017-01-27 15:50:34 -0800279 self.waitUntilSettled()
280 self.assertEqual(self.getJobFromHistory('project-test2').result,
281 'SUCCESS')
282 self.assertHistory([
283 dict(name='project-test2', result='SUCCESS', changes='1,1'),
284 dict(name='project-test2', result='SUCCESS', changes='2,1')])
James E. Blairc73c73a2017-01-20 15:15:15 -0800285
Tobias Henkelf02cf512017-07-21 22:55:34 +0200286 def test_dynamic_config_non_existing_job(self):
287 """Test that requesting a non existent job fails"""
288 in_repo_conf = textwrap.dedent(
289 """
290 - job:
291 name: project-test1
292
293 - project:
294 name: org/project
295 check:
296 jobs:
297 - non-existent-job
298 """)
299
300 in_repo_playbook = textwrap.dedent(
301 """
302 - hosts: all
303 tasks: []
304 """)
305
306 file_dict = {'.zuul.yaml': in_repo_conf,
307 'playbooks/project-test2.yaml': in_repo_playbook}
308 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
309 files=file_dict)
310 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
311 self.waitUntilSettled()
312 self.assertEqual(A.reported, 1,
313 "A should report failure")
314 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
315 self.assertIn('Job non-existent-job not defined', A.messages[0],
316 "A should have failed the check pipeline")
317 self.assertHistory([])
318
319 def test_dynamic_config_non_existing_job_in_template(self):
320 """Test that requesting a non existent job fails"""
321 in_repo_conf = textwrap.dedent(
322 """
323 - job:
324 name: project-test1
325
326 - project-template:
327 name: test-template
328 check:
329 jobs:
330 - non-existent-job
331
332 - project:
333 name: org/project
334 templates:
335 - test-template
336 """)
337
338 in_repo_playbook = textwrap.dedent(
339 """
340 - hosts: all
341 tasks: []
342 """)
343
344 file_dict = {'.zuul.yaml': in_repo_conf,
345 'playbooks/project-test2.yaml': in_repo_playbook}
346 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
347 files=file_dict)
348 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
349 self.waitUntilSettled()
350 self.assertEqual(A.reported, 1,
351 "A should report failure")
352 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
353 self.assertIn('Job non-existent-job not defined', A.messages[0],
354 "A should have failed the check pipeline")
355 self.assertHistory([])
356
Tobias Henkel0f714002017-06-30 23:30:52 +0200357 def test_dynamic_config_new_patchset(self):
358 self.executor_server.hold_jobs_in_build = True
359
360 tenant = self.sched.abide.tenants.get('tenant-one')
361 check_pipeline = tenant.layout.pipelines['check']
362
363 in_repo_conf = textwrap.dedent(
364 """
365 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200366 name: project-test1
367
368 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200369 name: project-test2
370
371 - project:
372 name: org/project
373 check:
374 jobs:
375 - project-test2
376 """)
377
378 in_repo_playbook = textwrap.dedent(
379 """
380 - hosts: all
381 tasks: []
382 """)
383
384 file_dict = {'.zuul.yaml': in_repo_conf,
385 'playbooks/project-test2.yaml': in_repo_playbook}
386 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
387 files=file_dict)
388 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
389 self.waitUntilSettled()
390
391 items = check_pipeline.getAllItems()
392 self.assertEqual(items[0].change.number, '1')
393 self.assertEqual(items[0].change.patchset, '1')
394 self.assertTrue(items[0].live)
395
396 in_repo_conf = textwrap.dedent(
397 """
398 - job:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200399 name: project-test1
400
401 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200402 name: project-test2
403
404 - project:
405 name: org/project
406 check:
407 jobs:
408 - project-test1
409 - project-test2
410 """)
411 file_dict = {'.zuul.yaml': in_repo_conf,
412 'playbooks/project-test2.yaml': in_repo_playbook}
413
414 A.addPatchset(files=file_dict)
415 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
416
417 self.waitUntilSettled()
418
419 items = check_pipeline.getAllItems()
420 self.assertEqual(items[0].change.number, '1')
421 self.assertEqual(items[0].change.patchset, '2')
422 self.assertTrue(items[0].live)
423
424 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200425 self.executor_server.release('project-test1')
426 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +0200427 self.executor_server.release()
428 self.waitUntilSettled()
429
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200430 self.assertHistory([
431 dict(name='project-test2', result='ABORTED', changes='1,1'),
432 dict(name='project-test1', result='SUCCESS', changes='1,2'),
433 dict(name='project-test2', result='SUCCESS', changes='1,2')])
434
James E. Blairff555742017-02-19 11:34:27 -0800435 def test_in_repo_branch(self):
436 in_repo_conf = textwrap.dedent(
437 """
438 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200439 name: project-test1
440
441 - job:
James E. Blairff555742017-02-19 11:34:27 -0800442 name: project-test2
443
444 - project:
445 name: org/project
446 tenant-one-gate:
447 jobs:
448 - project-test2
449 """)
450
451 in_repo_playbook = textwrap.dedent(
452 """
453 - hosts: all
454 tasks: []
455 """)
456
457 file_dict = {'.zuul.yaml': in_repo_conf,
458 'playbooks/project-test2.yaml': in_repo_playbook}
459 self.create_branch('org/project', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700460 self.fake_gerrit.addEvent(
461 self.fake_gerrit.getFakeBranchCreatedEvent(
462 'org/project', 'stable'))
James E. Blair6069f2b2017-09-26 16:34:11 -0700463 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800464 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
465 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200466 A.addApproval('Code-Review', 2)
467 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800468 self.waitUntilSettled()
469 self.assertEqual(A.data['status'], 'MERGED')
470 self.assertEqual(A.reported, 2,
471 "A should report start and success")
472 self.assertIn('tenant-one-gate', A.messages[1],
473 "A should transit tenant-one gate")
474 self.assertHistory([
475 dict(name='project-test2', result='SUCCESS', changes='1,1')])
476 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800477 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800478
479 # The config change should not affect master.
480 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200481 B.addApproval('Code-Review', 2)
482 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800483 self.waitUntilSettled()
484 self.assertHistory([
485 dict(name='project-test2', result='SUCCESS', changes='1,1'),
486 dict(name='project-test1', result='SUCCESS', changes='2,1')])
487
488 # The config change should be live for further changes on
489 # stable.
490 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200491 C.addApproval('Code-Review', 2)
492 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800493 self.waitUntilSettled()
494 self.assertHistory([
495 dict(name='project-test2', result='SUCCESS', changes='1,1'),
496 dict(name='project-test1', result='SUCCESS', changes='2,1'),
497 dict(name='project-test2', result='SUCCESS', changes='3,1')])
498
James E. Blaira5a12492017-05-03 11:40:48 -0700499 def test_crd_dynamic_config_branch(self):
500 # Test that we can create a job in one repo and be able to use
501 # it from a different branch on a different repo.
502
503 self.create_branch('org/project1', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700504 self.fake_gerrit.addEvent(
505 self.fake_gerrit.getFakeBranchCreatedEvent(
506 'org/project1', 'stable'))
James E. Blaira5a12492017-05-03 11:40:48 -0700507
508 in_repo_conf = textwrap.dedent(
509 """
510 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200511 name: project-test1
512
513 - job:
James E. Blaira5a12492017-05-03 11:40:48 -0700514 name: project-test2
515
516 - project:
517 name: org/project
518 check:
519 jobs:
520 - project-test2
521 """)
522
523 in_repo_playbook = textwrap.dedent(
524 """
525 - hosts: all
526 tasks: []
527 """)
528
529 file_dict = {'.zuul.yaml': in_repo_conf,
530 'playbooks/project-test2.yaml': in_repo_playbook}
531 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
532 files=file_dict)
533
534 second_repo_conf = textwrap.dedent(
535 """
536 - project:
537 name: org/project1
538 check:
539 jobs:
540 - project-test2
541 """)
542
543 second_file_dict = {'.zuul.yaml': second_repo_conf}
544 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
545 files=second_file_dict)
546 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
547 B.subject, A.data['id'])
548
549 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
550 self.waitUntilSettled()
551 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
552 self.waitUntilSettled()
553
554 self.assertEqual(A.reported, 1, "A should report")
555 self.assertHistory([
556 dict(name='project-test2', result='SUCCESS', changes='1,1'),
557 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
558 ])
559
James E. Blair97043882017-09-06 15:51:17 -0700560 def test_yaml_list_error(self):
561 in_repo_conf = textwrap.dedent(
562 """
563 job: foo
564 """)
565
566 file_dict = {'.zuul.yaml': in_repo_conf}
567 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
568 files=file_dict)
569 A.addApproval('Code-Review', 2)
570 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
571 self.waitUntilSettled()
572
573 self.assertEqual(A.data['status'], 'NEW')
574 self.assertEqual(A.reported, 1,
575 "A should report failure")
576 self.assertIn('not a list', A.messages[0],
577 "A should have a syntax error reported")
578
579 def test_yaml_dict_error(self):
580 in_repo_conf = textwrap.dedent(
581 """
582 - job
583 """)
584
585 file_dict = {'.zuul.yaml': in_repo_conf}
586 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
587 files=file_dict)
588 A.addApproval('Code-Review', 2)
589 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
590 self.waitUntilSettled()
591
592 self.assertEqual(A.data['status'], 'NEW')
593 self.assertEqual(A.reported, 1,
594 "A should report failure")
595 self.assertIn('not a dictionary', A.messages[0],
596 "A should have a syntax error reported")
597
598 def test_yaml_key_error(self):
599 in_repo_conf = textwrap.dedent(
600 """
601 - job:
602 name: project-test2
603 """)
604
605 file_dict = {'.zuul.yaml': in_repo_conf}
606 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
607 files=file_dict)
608 A.addApproval('Code-Review', 2)
609 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
610 self.waitUntilSettled()
611
612 self.assertEqual(A.data['status'], 'NEW')
613 self.assertEqual(A.reported, 1,
614 "A should report failure")
615 self.assertIn('has more than one key', A.messages[0],
616 "A should have a syntax error reported")
617
618 def test_yaml_unknown_error(self):
619 in_repo_conf = textwrap.dedent(
620 """
621 - foobar:
622 foo: bar
623 """)
624
625 file_dict = {'.zuul.yaml': in_repo_conf}
626 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
627 files=file_dict)
628 A.addApproval('Code-Review', 2)
629 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
630 self.waitUntilSettled()
631
632 self.assertEqual(A.data['status'], 'NEW')
633 self.assertEqual(A.reported, 1,
634 "A should report failure")
635 self.assertIn('not recognized', A.messages[0],
636 "A should have a syntax error reported")
637
James E. Blair149b69c2017-03-02 10:48:16 -0800638 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -0800639 in_repo_conf = textwrap.dedent(
640 """
641 - job:
642 name: project-test2
643 foo: error
644 """)
645
646 file_dict = {'.zuul.yaml': in_repo_conf}
647 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
648 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200649 A.addApproval('Code-Review', 2)
650 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -0800651 self.waitUntilSettled()
652
653 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200654 self.assertEqual(A.reported, 1,
655 "A should report failure")
656 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -0800657 "A should have a syntax error reported")
658
James E. Blair149b69c2017-03-02 10:48:16 -0800659 def test_trusted_syntax_error(self):
660 in_repo_conf = textwrap.dedent(
661 """
662 - job:
663 name: project-test2
664 foo: error
665 """)
666
667 file_dict = {'zuul.yaml': in_repo_conf}
668 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
669 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200670 A.addApproval('Code-Review', 2)
671 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -0800672 self.waitUntilSettled()
673
674 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200675 self.assertEqual(A.reported, 1,
676 "A should report failure")
677 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -0800678 "A should have a syntax error reported")
679
James E. Blair6f140c72017-03-03 10:32:07 -0800680 def test_untrusted_yaml_error(self):
681 in_repo_conf = textwrap.dedent(
682 """
683 - job:
684 foo: error
685 """)
686
687 file_dict = {'.zuul.yaml': in_repo_conf}
688 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
689 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200690 A.addApproval('Code-Review', 2)
691 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -0800692 self.waitUntilSettled()
693
694 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200695 self.assertEqual(A.reported, 1,
696 "A should report failure")
697 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -0800698 "A should have a syntax error reported")
699
James E. Blairdb04e6a2017-05-03 14:49:36 -0700700 def test_untrusted_shadow_error(self):
701 in_repo_conf = textwrap.dedent(
702 """
703 - job:
704 name: common-config-test
705 """)
706
707 file_dict = {'.zuul.yaml': in_repo_conf}
708 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
709 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200710 A.addApproval('Code-Review', 2)
711 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -0700712 self.waitUntilSettled()
713
714 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200715 self.assertEqual(A.reported, 1,
716 "A should report failure")
717 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -0700718 "A should have a syntax error reported")
719
James E. Blaird5656ad2017-06-02 14:29:41 -0700720 def test_untrusted_pipeline_error(self):
721 in_repo_conf = textwrap.dedent(
722 """
723 - pipeline:
724 name: test
725 """)
726
727 file_dict = {'.zuul.yaml': in_repo_conf}
728 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
729 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200730 A.addApproval('Code-Review', 2)
731 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700732 self.waitUntilSettled()
733
734 self.assertEqual(A.data['status'], 'NEW')
735 self.assertEqual(A.reported, 1,
736 "A should report failure")
737 self.assertIn('Pipelines may not be defined', A.messages[0],
738 "A should have a syntax error reported")
739
740 def test_untrusted_project_error(self):
741 in_repo_conf = textwrap.dedent(
742 """
743 - project:
744 name: org/project1
745 """)
746
747 file_dict = {'.zuul.yaml': in_repo_conf}
748 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
749 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200750 A.addApproval('Code-Review', 2)
751 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700752 self.waitUntilSettled()
753
754 self.assertEqual(A.data['status'], 'NEW')
755 self.assertEqual(A.reported, 1,
756 "A should report failure")
757 self.assertIn('the only project definition permitted', A.messages[0],
758 "A should have a syntax error reported")
759
James E. Blairf03173b2017-10-10 10:46:43 -0700760 def test_untrusted_depends_on_trusted(self):
761 with open(os.path.join(FIXTURE_DIR,
762 'config/in-repo/git/',
763 'common-config/zuul.yaml')) as f:
764 common_config = f.read()
765
766 common_config += textwrap.dedent(
767 """
768 - job:
769 name: project-test9
770 """)
771
772 file_dict = {'zuul.yaml': common_config}
773 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
774 files=file_dict)
775 in_repo_conf = textwrap.dedent(
776 """
777 - job:
778 name: project-test1
779 - project:
780 name: org/project
781 check:
782 jobs:
783 - project-test9
784 """)
785
786 file_dict = {'zuul.yaml': in_repo_conf}
787 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
788 files=file_dict)
789 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
790 B.subject, A.data['id'])
791 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
792 self.waitUntilSettled()
793
794 self.assertEqual(B.data['status'], 'NEW')
795 self.assertEqual(B.reported, 1,
796 "B should report failure")
797 self.assertIn('depends on a change to a config project',
798 B.messages[0],
799 "A should have a syntax error reported")
800
James E. Blaire64b0e42017-06-08 11:23:34 -0700801 def test_duplicate_node_error(self):
802 in_repo_conf = textwrap.dedent(
803 """
804 - nodeset:
805 name: duplicate
806 nodes:
807 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700808 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700809 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700810 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700811 """)
812
813 file_dict = {'.zuul.yaml': in_repo_conf}
814 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
815 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200816 A.addApproval('Code-Review', 2)
817 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700818 self.waitUntilSettled()
819
820 self.assertEqual(A.data['status'], 'NEW')
821 self.assertEqual(A.reported, 1,
822 "A should report failure")
823 self.assertIn('appears multiple times', A.messages[0],
824 "A should have a syntax error reported")
825
826 def test_duplicate_group_error(self):
827 in_repo_conf = textwrap.dedent(
828 """
829 - nodeset:
830 name: duplicate
831 nodes:
832 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700833 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700834 groups:
835 - name: group
836 nodes: compute
837 - name: group
838 nodes: compute
839 """)
840
841 file_dict = {'.zuul.yaml': in_repo_conf}
842 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
843 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200844 A.addApproval('Code-Review', 2)
845 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700846 self.waitUntilSettled()
847
848 self.assertEqual(A.data['status'], 'NEW')
849 self.assertEqual(A.reported, 1,
850 "A should report failure")
851 self.assertIn('appears multiple times', A.messages[0],
852 "A should have a syntax error reported")
853
James E. Blair4ae399f2017-09-20 17:15:09 -0700854 def test_secret_not_found_error(self):
855 in_repo_conf = textwrap.dedent(
856 """
857 - job:
858 name: test
859 secrets: does-not-exist
860 """)
861
862 file_dict = {'.zuul.yaml': in_repo_conf}
863 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
864 files=file_dict)
865 A.addApproval('Code-Review', 2)
866 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
867 self.waitUntilSettled()
868
869 self.assertEqual(A.data['status'], 'NEW')
870 self.assertEqual(A.reported, 1,
871 "A should report failure")
872 self.assertIn('secret "does-not-exist" was not found', A.messages[0],
873 "A should have a syntax error reported")
874
875 def test_nodeset_not_found_error(self):
876 in_repo_conf = textwrap.dedent(
877 """
878 - job:
879 name: test
880 nodeset: does-not-exist
881 """)
882
883 file_dict = {'.zuul.yaml': in_repo_conf}
884 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
885 files=file_dict)
886 A.addApproval('Code-Review', 2)
887 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
888 self.waitUntilSettled()
889
890 self.assertEqual(A.data['status'], 'NEW')
891 self.assertEqual(A.reported, 1,
892 "A should report failure")
893 self.assertIn('nodeset "does-not-exist" was not found', A.messages[0],
894 "A should have a syntax error reported")
895
James E. Blair89e25eb2017-09-26 09:11:31 -0700896 def test_template_not_found_error(self):
897 in_repo_conf = textwrap.dedent(
898 """
899 - job:
900 name: project-test1
901 - project:
902 name: org/project
903 templates:
904 - does-not-exist
905 """)
906
907 file_dict = {'.zuul.yaml': in_repo_conf}
908 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
909 files=file_dict)
910 A.addApproval('Code-Review', 2)
911 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
912 self.waitUntilSettled()
913
914 self.assertEqual(A.data['status'], 'NEW')
915 self.assertEqual(A.reported, 1,
916 "A should report failure")
917 self.assertIn('project template "does-not-exist" was not found',
918 A.messages[0],
919 "A should have a syntax error reported")
920
Monty Taylor8be3c0c2017-10-06 10:37:37 -0500921 def test_job_list_in_project_template_not_dict_error(self):
922 in_repo_conf = textwrap.dedent(
923 """
924 - job:
925 name: project-test1
926 - project-template:
927 name: some-jobs
928 check:
929 jobs:
930 - project-test1:
931 - required-projects:
932 org/project2
933 """)
934
935 file_dict = {'.zuul.yaml': in_repo_conf}
936 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
937 files=file_dict)
938 A.addApproval('Code-Review', 2)
939 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
940 self.waitUntilSettled()
941
942 self.assertEqual(A.data['status'], 'NEW')
943 self.assertEqual(A.reported, 1,
944 "A should report failure")
945 self.assertIn('expected str for dictionary value',
946 A.messages[0], "A should have a syntax error reported")
947
948 def test_job_list_in_project_not_dict_error(self):
949 in_repo_conf = textwrap.dedent(
950 """
951 - job:
952 name: project-test1
953 - project:
954 name: org/project1
955 check:
956 jobs:
957 - project-test1:
958 - required-projects:
959 org/project2
960 """)
961
962 file_dict = {'.zuul.yaml': in_repo_conf}
963 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
964 files=file_dict)
965 A.addApproval('Code-Review', 2)
966 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
967 self.waitUntilSettled()
968
969 self.assertEqual(A.data['status'], 'NEW')
970 self.assertEqual(A.reported, 1,
971 "A should report failure")
972 self.assertIn('expected str for dictionary value',
973 A.messages[0], "A should have a syntax error reported")
974
James E. Blair1235f142017-10-07 09:11:43 -0700975 def test_project_template(self):
976 # Tests that a project template is not modified when used, and
977 # can therefore be used in subsequent reconfigurations.
978 in_repo_conf = textwrap.dedent(
979 """
980 - job:
981 name: project-test1
982 - project-template:
983 name: some-jobs
984 tenant-one-gate:
985 jobs:
986 - project-test1:
987 required-projects:
988 - org/project1
989 - project:
990 name: org/project
991 templates:
992 - some-jobs
993 """)
994
995 file_dict = {'.zuul.yaml': in_repo_conf}
996 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
997 files=file_dict)
998 A.addApproval('Code-Review', 2)
999 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1000 self.waitUntilSettled()
1001 self.assertEqual(A.data['status'], 'MERGED')
1002 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1003 self.waitUntilSettled()
1004 in_repo_conf = textwrap.dedent(
1005 """
1006 - project:
1007 name: org/project1
1008 templates:
1009 - some-jobs
1010 """)
1011 file_dict = {'.zuul.yaml': in_repo_conf}
1012 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
1013 files=file_dict)
1014 B.addApproval('Code-Review', 2)
1015 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1016 self.waitUntilSettled()
1017 self.assertEqual(B.data['status'], 'MERGED')
1018
James E. Blairbccdfcf2017-10-07 13:37:26 -07001019 def test_job_remove_add(self):
1020 # Tests that a job can be removed from one repo and added in another.
1021 # First, remove the current config for project1 since it
1022 # references the job we want to remove.
1023 file_dict = {'.zuul.yaml': None}
1024 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1025 files=file_dict)
1026 A.setMerged()
1027 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1028 self.waitUntilSettled()
1029 # Then propose a change to delete the job from one repo...
1030 file_dict = {'.zuul.yaml': None}
1031 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1032 files=file_dict)
1033 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1034 self.waitUntilSettled()
1035 # ...and a second that depends on it that adds it to another repo.
1036 in_repo_conf = textwrap.dedent(
1037 """
1038 - job:
1039 name: project-test1
1040
1041 - project:
1042 name: org/project1
1043 check:
1044 jobs:
1045 - project-test1
1046 """)
1047 in_repo_playbook = textwrap.dedent(
1048 """
1049 - hosts: all
1050 tasks: []
1051 """)
1052 file_dict = {'.zuul.yaml': in_repo_conf,
1053 'playbooks/project-test1.yaml': in_repo_playbook}
1054 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C',
1055 files=file_dict,
1056 parent='refs/changes/1/1/1')
1057 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1058 C.subject, B.data['id'])
1059 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1060 self.waitUntilSettled()
1061 self.assertHistory([
1062 dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'),
1063 ], ordered=False)
1064
James E. Blair09f9ffe2017-07-11 15:30:25 -07001065 def test_multi_repo(self):
1066 downstream_repo_conf = textwrap.dedent(
1067 """
1068 - project:
1069 name: org/project1
1070 tenant-one-gate:
1071 jobs:
1072 - project-test1
1073
1074 - job:
1075 name: project1-test1
1076 parent: project-test1
1077 """)
1078
1079 file_dict = {'.zuul.yaml': downstream_repo_conf}
1080 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1081 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001082 A.addApproval('Code-Review', 2)
1083 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001084 self.waitUntilSettled()
1085
1086 self.assertEqual(A.data['status'], 'MERGED')
1087 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1088 self.waitUntilSettled()
1089
1090 upstream_repo_conf = textwrap.dedent(
1091 """
1092 - job:
1093 name: project-test1
1094
1095 - job:
1096 name: project-test2
1097
1098 - project:
1099 name: org/project
1100 tenant-one-gate:
1101 jobs:
1102 - project-test1
1103 """)
1104
1105 file_dict = {'.zuul.yaml': upstream_repo_conf}
1106 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1107 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001108 B.addApproval('Code-Review', 2)
1109 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001110 self.waitUntilSettled()
1111
1112 self.assertEqual(B.data['status'], 'MERGED')
1113 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
1114 self.waitUntilSettled()
1115
1116 tenant = self.sched.abide.tenants.get('tenant-one')
1117 # Ensure the latest change is reflected in the config; if it
1118 # isn't this will raise an exception.
1119 tenant.layout.getJob('project-test2')
1120
James E. Blair332636e2017-09-05 10:14:35 -07001121 def test_pipeline_error(self):
1122 with open(os.path.join(FIXTURE_DIR,
1123 'config/in-repo/git/',
1124 'common-config/zuul.yaml')) as f:
1125 base_common_config = f.read()
1126
1127 in_repo_conf_A = textwrap.dedent(
1128 """
1129 - pipeline:
1130 name: periodic
1131 foo: error
1132 """)
1133
1134 file_dict = {'zuul.yaml': None,
1135 'zuul.d/main.yaml': base_common_config,
1136 'zuul.d/test1.yaml': in_repo_conf_A}
1137 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1138 files=file_dict)
1139 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1140 self.waitUntilSettled()
1141 self.assertEqual(A.reported, 1,
1142 "A should report failure")
1143 self.assertIn('syntax error',
1144 A.messages[0],
1145 "A should have an error reported")
1146
1147 def test_change_series_error(self):
1148 with open(os.path.join(FIXTURE_DIR,
1149 'config/in-repo/git/',
1150 'common-config/zuul.yaml')) as f:
1151 base_common_config = f.read()
1152
1153 in_repo_conf_A = textwrap.dedent(
1154 """
1155 - pipeline:
1156 name: periodic
1157 foo: error
1158 """)
1159
1160 file_dict = {'zuul.yaml': None,
1161 'zuul.d/main.yaml': base_common_config,
1162 'zuul.d/test1.yaml': in_repo_conf_A}
1163 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1164 files=file_dict)
1165
1166 in_repo_conf_B = textwrap.dedent(
1167 """
1168 - job:
1169 name: project-test2
1170 foo: error
1171 """)
1172
1173 file_dict = {'zuul.yaml': None,
1174 'zuul.d/main.yaml': base_common_config,
1175 'zuul.d/test1.yaml': in_repo_conf_A,
1176 'zuul.d/test2.yaml': in_repo_conf_B}
1177 B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B',
1178 files=file_dict)
1179 B.setDependsOn(A, 1)
1180 C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C')
1181 C.setDependsOn(B, 1)
1182 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1183 self.waitUntilSettled()
1184
1185 self.assertEqual(C.reported, 1,
1186 "C should report failure")
1187 self.assertIn('depends on a change that failed to merge',
1188 C.messages[0],
1189 "C should have an error reported")
1190
James E. Blairc73c73a2017-01-20 15:15:15 -08001191
James E. Blairc9455002017-09-06 09:22:19 -07001192class TestInRepoJoin(ZuulTestCase):
1193 # In this config, org/project is not a member of any pipelines, so
1194 # that we may test the changes that cause it to join them.
1195
1196 tenant_config_file = 'config/in-repo-join/main.yaml'
1197
1198 def test_dynamic_dependent_pipeline(self):
1199 # Test dynamically adding a project to a
1200 # dependent pipeline for the first time
1201 self.executor_server.hold_jobs_in_build = True
1202
1203 tenant = self.sched.abide.tenants.get('tenant-one')
1204 gate_pipeline = tenant.layout.pipelines['gate']
1205
1206 in_repo_conf = textwrap.dedent(
1207 """
1208 - job:
1209 name: project-test1
1210
1211 - job:
1212 name: project-test2
1213
1214 - project:
1215 name: org/project
1216 gate:
1217 jobs:
1218 - project-test2
1219 """)
1220
1221 in_repo_playbook = textwrap.dedent(
1222 """
1223 - hosts: all
1224 tasks: []
1225 """)
1226
1227 file_dict = {'.zuul.yaml': in_repo_conf,
1228 'playbooks/project-test2.yaml': in_repo_playbook}
1229 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1230 files=file_dict)
1231 A.addApproval('Code-Review', 2)
1232 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1233 self.waitUntilSettled()
1234
1235 items = gate_pipeline.getAllItems()
1236 self.assertEqual(items[0].change.number, '1')
1237 self.assertEqual(items[0].change.patchset, '1')
1238 self.assertTrue(items[0].live)
1239
1240 self.executor_server.hold_jobs_in_build = False
1241 self.executor_server.release()
1242 self.waitUntilSettled()
1243
1244 # Make sure the dynamic queue got cleaned up
1245 self.assertEqual(gate_pipeline.queues, [])
1246
1247 def test_dynamic_dependent_pipeline_failure(self):
1248 # Test that a change behind a failing change adding a project
1249 # to a dependent pipeline is dequeued.
1250 self.executor_server.hold_jobs_in_build = True
1251
1252 in_repo_conf = textwrap.dedent(
1253 """
1254 - job:
1255 name: project-test1
1256
1257 - project:
1258 name: org/project
1259 gate:
1260 jobs:
1261 - project-test1
1262 """)
1263
1264 file_dict = {'.zuul.yaml': in_repo_conf}
1265 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1266 files=file_dict)
1267 self.executor_server.failJob('project-test1', A)
1268 A.addApproval('Code-Review', 2)
1269 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1270 self.waitUntilSettled()
1271
1272 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1273 B.addApproval('Code-Review', 2)
1274 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1275 self.waitUntilSettled()
1276
James E. Blair3490c5d2017-09-07 08:33:23 -07001277 self.orderedRelease()
James E. Blairc9455002017-09-06 09:22:19 -07001278 self.waitUntilSettled()
1279 self.assertEqual(A.reported, 2,
1280 "A should report start and failure")
1281 self.assertEqual(A.data['status'], 'NEW')
1282 self.assertEqual(B.reported, 1,
1283 "B should report start")
1284 self.assertHistory([
1285 dict(name='project-test1', result='FAILURE', changes='1,1'),
James E. Blair3490c5d2017-09-07 08:33:23 -07001286 dict(name='project-test1', result='ABORTED', changes='1,1 2,1'),
James E. Blairc9455002017-09-06 09:22:19 -07001287 ], ordered=False)
1288
James E. Blair0af198f2017-09-06 09:52:35 -07001289 def test_dynamic_dependent_pipeline_absent(self):
1290 # Test that a series of dependent changes don't report merge
1291 # failures to a pipeline they aren't in.
1292 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1293 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1294 B.setDependsOn(A, 1)
1295
1296 A.addApproval('Code-Review', 2)
1297 A.addApproval('Approved', 1)
1298 B.addApproval('Code-Review', 2)
1299 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1300 self.waitUntilSettled()
1301 self.assertEqual(A.reported, 0,
1302 "A should not report")
1303 self.assertEqual(A.data['status'], 'NEW')
1304 self.assertEqual(B.reported, 0,
1305 "B should not report")
1306 self.assertEqual(B.data['status'], 'NEW')
1307 self.assertHistory([])
1308
James E. Blairc9455002017-09-06 09:22:19 -07001309
James E. Blairc73c73a2017-01-20 15:15:15 -08001310class TestAnsible(AnsibleZuulTestCase):
1311 # A temporary class to hold new tests while others are disabled
1312
1313 tenant_config_file = 'config/ansible/main.yaml'
1314
1315 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +11001316 # Keep the jobdir around so we can inspect contents if an
1317 # assert fails.
1318 self.executor_server.keep_jobdir = True
1319 # Output extra ansible info so we might see errors.
1320 self.executor_server.verbose = True
1321 # Add a site variables file, used by check-vars
1322 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
1323 'variables.yaml')
1324 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -08001325 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1326 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1327 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +02001328 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +11001329 with self.jobLog(build_timeout):
1330 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001331 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +11001332 with self.jobLog(build_faillocal):
1333 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001334 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +11001335 with self.jobLog(build_failpost):
1336 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001337 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +11001338 with self.jobLog(build_check_vars):
1339 self.assertEqual(build_check_vars.result, 'SUCCESS')
Monty Tayloraff8b402017-08-16 18:40:41 -05001340 build_check_secret_names = self.getJobFromHistory('check-secret-names')
1341 with self.jobLog(build_check_secret_names):
1342 self.assertEqual(build_check_secret_names.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001343 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +11001344 with self.jobLog(build_hello):
1345 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001346 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +11001347 with self.jobLog(build_python27):
1348 self.assertEqual(build_python27.result, 'SUCCESS')
1349 flag_path = os.path.join(self.test_root,
1350 build_python27.uuid + '.flag')
1351 self.assertTrue(os.path.exists(flag_path))
1352 copied_path = os.path.join(self.test_root, build_python27.uuid +
1353 '.copied')
1354 self.assertTrue(os.path.exists(copied_path))
1355 failed_path = os.path.join(self.test_root, build_python27.uuid +
1356 '.failed')
1357 self.assertFalse(os.path.exists(failed_path))
1358 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
1359 '.pre.flag')
1360 self.assertTrue(os.path.exists(pre_flag_path))
1361 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
1362 '.post.flag')
1363 self.assertTrue(os.path.exists(post_flag_path))
1364 bare_role_flag_path = os.path.join(self.test_root,
1365 build_python27.uuid +
1366 '.bare-role.flag')
1367 self.assertTrue(os.path.exists(bare_role_flag_path))
1368 secrets_path = os.path.join(self.test_root,
1369 build_python27.uuid + '.secrets')
1370 with open(secrets_path) as f:
1371 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -08001372
Jamie Lennox7655b552017-03-17 12:33:38 +11001373 msg = A.messages[0]
1374 success = "{} https://success.example.com/zuul-logs/{}"
1375 fail = "{} https://failure.example.com/zuul-logs/{}"
1376 self.assertIn(success.format("python27", build_python27.uuid), msg)
1377 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
1378 self.assertIn(success.format("check-vars",
1379 build_check_vars.uuid), msg)
1380 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
1381 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
1382 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +02001383
James E. Blairabbaa6f2017-04-06 16:11:44 -07001384 def _add_job(self, job_name):
1385 conf = textwrap.dedent(
1386 """
1387 - job:
1388 name: %s
1389
1390 - project:
1391 name: org/plugin-project
1392 check:
1393 jobs:
1394 - %s
1395 """ % (job_name, job_name))
1396
1397 file_dict = {'.zuul.yaml': conf}
1398 A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A',
1399 files=file_dict)
1400 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1401 self.waitUntilSettled()
1402
1403 def test_plugins(self):
1404 # Keep the jobdir around so we can inspect contents if an
1405 # assert fails.
1406 self.executor_server.keep_jobdir = True
1407 # Output extra ansible info so we might see errors.
1408 self.executor_server.verbose = True
1409
1410 count = 0
1411 plugin_tests = [
1412 ('passwd', 'FAILURE'),
1413 ('cartesian', 'SUCCESS'),
1414 ('consul_kv', 'FAILURE'),
1415 ('credstash', 'FAILURE'),
1416 ('csvfile_good', 'SUCCESS'),
1417 ('csvfile_bad', 'FAILURE'),
Monty Taylor93ad2212017-08-02 14:59:50 -05001418 ('uri_bad_path', 'FAILURE'),
1419 ('uri_bad_scheme', 'FAILURE'),
Monty Taylor788a40e2017-08-02 16:14:05 -05001420 ('block_local_override', 'FAILURE'),
Monty Taylor8da768f2017-08-31 14:15:35 -05001421 ('file_local_good', 'SUCCESS'),
1422 ('file_local_bad', 'FAILURE'),
James E. Blairabbaa6f2017-04-06 16:11:44 -07001423 ]
1424 for job_name, result in plugin_tests:
1425 count += 1
1426 self._add_job(job_name)
1427
1428 job = self.getJobFromHistory(job_name)
1429 with self.jobLog(job):
1430 self.assertEqual(count, len(self.history))
1431 build = self.history[-1]
1432 self.assertEqual(build.result, result)
1433
1434 # TODOv3(jeblair): parse the ansible output and verify we're
1435 # getting the exception we expect.
1436
James E. Blairb9c0d772017-03-03 14:34:49 -08001437
James E. Blaira4d4eef2017-06-30 14:49:17 -07001438class TestPrePlaybooks(AnsibleZuulTestCase):
1439 # A temporary class to hold new tests while others are disabled
1440
1441 tenant_config_file = 'config/pre-playbook/main.yaml'
1442
1443 def test_pre_playbook_fail(self):
1444 # Test that we run the post playbooks (but not the actual
1445 # playbook) when a pre-playbook fails.
1446 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1447 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1448 self.waitUntilSettled()
1449 build = self.getJobFromHistory('python27')
1450 self.assertIsNone(build.result)
1451 self.assertIn('RETRY_LIMIT', A.messages[0])
1452 flag_path = os.path.join(self.test_root, build.uuid +
1453 '.main.flag')
1454 self.assertFalse(os.path.exists(flag_path))
1455 pre_flag_path = os.path.join(self.test_root, build.uuid +
1456 '.pre.flag')
1457 self.assertFalse(os.path.exists(pre_flag_path))
1458 post_flag_path = os.path.join(self.test_root, build.uuid +
1459 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -07001460 self.assertTrue(os.path.exists(post_flag_path),
1461 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -07001462
1463
James E. Blairbacbb882017-10-17 09:48:23 -07001464class TestPostPlaybooks(AnsibleZuulTestCase):
1465 tenant_config_file = 'config/post-playbook/main.yaml'
1466
1467 def test_post_playbook_abort(self):
1468 # Test that when we abort a job in the post playbook, that we
1469 # don't send back POST_FAILURE.
1470 self.executor_server.verbose = True
1471 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1472 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1473
1474 while not len(self.builds):
1475 time.sleep(0.1)
1476 build = self.builds[0]
1477
1478 post_start = os.path.join(self.test_root, build.uuid +
1479 '.post_start.flag')
1480 start = time.time()
1481 while time.time() < start + 90:
1482 if os.path.exists(post_start):
1483 break
1484 time.sleep(0.1)
1485 # The post playbook has started, abort the job
1486 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1487 self.waitUntilSettled()
1488
1489 build = self.getJobFromHistory('python27')
1490 self.assertEqual('ABORTED', build.result)
1491
1492 post_end = os.path.join(self.test_root, build.uuid +
1493 '.post_end.flag')
1494 self.assertTrue(os.path.exists(post_start))
1495 self.assertFalse(os.path.exists(post_end))
1496
1497
James E. Blairb9c0d772017-03-03 14:34:49 -08001498class TestBrokenConfig(ZuulTestCase):
1499 # Test that we get an appropriate syntax error if we start with a
1500 # broken config.
1501
1502 tenant_config_file = 'config/broken/main.yaml'
1503
1504 def setUp(self):
1505 with testtools.ExpectedException(
1506 zuul.configloader.ConfigurationSyntaxError,
1507 "\nZuul encountered a syntax error"):
1508 super(TestBrokenConfig, self).setUp()
1509
1510 def test_broken_config_on_startup(self):
1511 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001512
1513
1514class TestProjectKeys(ZuulTestCase):
1515 # Test that we can generate project keys
1516
1517 # Normally the test infrastructure copies a static key in place
1518 # for each project before starting tests. This saves time because
1519 # Zuul's automatic key-generation on startup can be slow. To make
1520 # sure we exercise that code, in this test we allow Zuul to create
1521 # keys for the project on startup.
1522 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +02001523 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001524 tenant_config_file = 'config/in-repo/main.yaml'
1525
1526 def test_key_generation(self):
1527 key_root = os.path.join(self.state_root, 'keys')
1528 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
1529 # Make sure that a proper key was created on startup
1530 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -07001531 private_key, public_key = \
1532 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001533
1534 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
1535 fixture_private_key = i.read()
1536
1537 # Make sure that we didn't just end up with the static fixture
1538 # key
1539 self.assertNotEqual(fixture_private_key, private_key)
1540
1541 # Make sure it's the right length
1542 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -07001543
1544
James E. Blairbb94dfa2017-07-11 07:45:19 -07001545class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -07001546 def _assertRolePath(self, build, playbook, content):
1547 path = os.path.join(self.test_root, build.uuid,
1548 'ansible', playbook, 'ansible.cfg')
1549 roles_paths = []
1550 with open(path) as f:
1551 for line in f:
1552 if line.startswith('roles_path'):
1553 roles_paths.append(line)
1554 print(roles_paths)
1555 if content:
1556 self.assertEqual(len(roles_paths), 1,
1557 "Should have one roles_path line in %s" %
1558 (playbook,))
1559 self.assertIn(content, roles_paths[0])
1560 else:
1561 self.assertEqual(len(roles_paths), 0,
1562 "Should have no roles_path line in %s" %
1563 (playbook,))
1564
James E. Blairbb94dfa2017-07-11 07:45:19 -07001565
1566class TestRoles(RoleTestCase):
1567 tenant_config_file = 'config/roles/main.yaml'
1568
James E. Blairbce76932017-05-04 10:03:15 -07001569 def test_role(self):
1570 # This exercises a proposed change to a role being checked out
1571 # and used.
1572 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
1573 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1574 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1575 B.subject, A.data['id'])
1576 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1577 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1578 self.waitUntilSettled()
1579 self.assertHistory([
1580 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
1581 ])
James E. Blair6459db12017-06-29 14:57:20 -07001582
James E. Blair1b27f6a2017-07-14 14:09:07 -07001583 def test_role_inheritance(self):
1584 self.executor_server.hold_jobs_in_build = True
1585 conf = textwrap.dedent(
1586 """
1587 - job:
1588 name: parent
1589 roles:
1590 - zuul: bare-role
1591 pre-run: playbooks/parent-pre
1592 post-run: playbooks/parent-post
1593
1594 - job:
1595 name: project-test
1596 parent: parent
1597 roles:
1598 - zuul: org/project
1599
1600 - project:
1601 name: org/project
1602 check:
1603 jobs:
1604 - project-test
1605 """)
1606
1607 file_dict = {'.zuul.yaml': conf}
1608 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1609 files=file_dict)
1610 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1611 self.waitUntilSettled()
1612
1613 self.assertEqual(len(self.builds), 1)
1614 build = self.getBuildByName('project-test')
1615 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
1616 self._assertRolePath(build, 'playbook_0', 'role_0')
1617 self._assertRolePath(build, 'playbook_0', 'role_1')
1618 self._assertRolePath(build, 'post_playbook_0', 'role_0')
1619
1620 self.executor_server.hold_jobs_in_build = False
1621 self.executor_server.release()
1622 self.waitUntilSettled()
1623
1624 self.assertHistory([
1625 dict(name='project-test', result='SUCCESS', changes='1,1'),
1626 ])
1627
James E. Blair6f699732017-07-18 14:19:11 -07001628 def test_role_error(self):
1629 conf = textwrap.dedent(
1630 """
1631 - job:
1632 name: project-test
1633 roles:
1634 - zuul: common-config
1635
1636 - project:
1637 name: org/project
1638 check:
1639 jobs:
1640 - project-test
1641 """)
1642
1643 file_dict = {'.zuul.yaml': conf}
1644 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1645 files=file_dict)
1646 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1647 self.waitUntilSettled()
1648 self.assertIn(
1649 '- project-test project-test : ERROR Unable to find role',
1650 A.messages[-1])
1651
James E. Blair6459db12017-06-29 14:57:20 -07001652
James E. Blairbb94dfa2017-07-11 07:45:19 -07001653class TestImplicitRoles(RoleTestCase):
1654 tenant_config_file = 'config/implicit-roles/main.yaml'
1655
1656 def test_missing_roles(self):
1657 # Test implicit and explicit roles for a project which does
1658 # not have roles. The implicit role should be silently
1659 # ignored since the project doesn't supply roles, but if a
1660 # user declares an explicit role, it should error.
1661 self.executor_server.hold_jobs_in_build = True
1662 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
1663 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1664 self.waitUntilSettled()
1665
1666 self.assertEqual(len(self.builds), 2)
1667 build = self.getBuildByName('implicit-role-fail')
1668 self._assertRolePath(build, 'playbook_0', None)
1669
1670 self.executor_server.hold_jobs_in_build = False
1671 self.executor_server.release()
1672 self.waitUntilSettled()
1673 # The retry_limit doesn't get recorded
1674 self.assertHistory([
1675 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
1676 ])
1677
1678 def test_roles(self):
1679 # Test implicit and explicit roles for a project which does
1680 # have roles. In both cases, we should end up with the role
1681 # in the path. In the explicit case, ensure we end up with
1682 # the name we specified.
1683 self.executor_server.hold_jobs_in_build = True
1684 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
1685 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1686 self.waitUntilSettled()
1687
1688 self.assertEqual(len(self.builds), 2)
1689 build = self.getBuildByName('implicit-role-ok')
1690 self._assertRolePath(build, 'playbook_0', 'role_0')
1691
1692 build = self.getBuildByName('explicit-role-ok')
1693 self._assertRolePath(build, 'playbook_0', 'role_0')
1694
1695 self.executor_server.hold_jobs_in_build = False
1696 self.executor_server.release()
1697 self.waitUntilSettled()
1698 self.assertHistory([
1699 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
1700 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
1701 ], ordered=False)
1702
1703
James E. Blair6459db12017-06-29 14:57:20 -07001704class TestShadow(ZuulTestCase):
1705 tenant_config_file = 'config/shadow/main.yaml'
1706
1707 def test_shadow(self):
1708 # Test that a repo is allowed to shadow another's job definitions.
1709 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1710 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1711 self.waitUntilSettled()
1712 self.assertHistory([
1713 dict(name='test1', result='SUCCESS', changes='1,1'),
1714 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -07001715 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -07001716
1717
1718class TestDataReturn(AnsibleZuulTestCase):
1719 tenant_config_file = 'config/data-return/main.yaml'
1720
1721 def test_data_return(self):
1722 # This exercises a proposed change to a role being checked out
1723 # and used.
1724 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1725 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1726 self.waitUntilSettled()
1727 self.assertHistory([
1728 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07001729 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
1730 ], ordered=False)
1731 self.assertIn('- data-return http://example.com/test/log/url/',
1732 A.messages[-1])
1733 self.assertIn('- data-return-relative '
1734 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -07001735 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -07001736
1737
1738class TestDiskAccounting(AnsibleZuulTestCase):
1739 config_file = 'zuul-disk-accounting.conf'
1740 tenant_config_file = 'config/disk-accountant/main.yaml'
1741
1742 def test_disk_accountant_kills_job(self):
1743 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1744 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1745 self.waitUntilSettled()
1746 self.assertHistory([
1747 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001748
1749
1750class TestMaxNodesPerJob(AnsibleZuulTestCase):
1751 tenant_config_file = 'config/multi-tenant/main.yaml'
1752
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00001753 def test_max_timeout_exceeded(self):
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001754 in_repo_conf = textwrap.dedent(
1755 """
1756 - job:
1757 name: test-job
James E. Blair7e3e6882017-09-20 15:47:13 -07001758 nodeset:
1759 nodes:
1760 - name: node01
1761 label: fake
1762 - name: node02
1763 label: fake
1764 - name: node03
1765 label: fake
1766 - name: node04
1767 label: fake
1768 - name: node05
1769 label: fake
1770 - name: node06
1771 label: fake
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001772 """)
1773 file_dict = {'.zuul.yaml': in_repo_conf}
1774 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1775 files=file_dict)
1776 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1777 self.waitUntilSettled()
1778 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
1779 A.messages[0], "A should fail because of nodes limit")
1780
1781 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
1782 files=file_dict)
1783 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1784 self.waitUntilSettled()
1785 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
1786 "B should not fail because of nodes limit")
James E. Blair2bab6e72017-08-07 09:52:45 -07001787
1788
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00001789class TestMaxTimeout(AnsibleZuulTestCase):
1790 tenant_config_file = 'config/multi-tenant/main.yaml'
1791
1792 def test_max_nodes_reached(self):
1793 in_repo_conf = textwrap.dedent(
1794 """
1795 - job:
1796 name: test-job
1797 timeout: 3600
1798 """)
1799 file_dict = {'.zuul.yaml': in_repo_conf}
1800 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1801 files=file_dict)
1802 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1803 self.waitUntilSettled()
1804 self.assertIn('The job "test-job" exceeds tenant max-job-timeout',
1805 A.messages[0], "A should fail because of timeout limit")
1806
1807 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
1808 files=file_dict)
1809 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1810 self.waitUntilSettled()
1811 self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0],
1812 "B should not fail because of timeout limit")
1813
1814
James E. Blair2bab6e72017-08-07 09:52:45 -07001815class TestBaseJobs(ZuulTestCase):
1816 tenant_config_file = 'config/base-jobs/main.yaml'
1817
1818 def test_multiple_base_jobs(self):
1819 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1820 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1821 self.waitUntilSettled()
1822 self.assertHistory([
1823 dict(name='my-job', result='SUCCESS', changes='1,1'),
1824 dict(name='other-job', result='SUCCESS', changes='1,1'),
1825 ], ordered=False)
1826 self.assertEqual(self.getJobFromHistory('my-job').
1827 parameters['zuul']['jobtags'],
1828 ['mybase'])
1829 self.assertEqual(self.getJobFromHistory('other-job').
1830 parameters['zuul']['jobtags'],
1831 ['otherbase'])
1832
1833 def test_untrusted_base_job(self):
1834 """Test that a base job may not be defined in an untrusted repo"""
1835 in_repo_conf = textwrap.dedent(
1836 """
1837 - job:
1838 name: fail-base
1839 parent: null
1840 """)
1841
1842 file_dict = {'.zuul.yaml': in_repo_conf}
1843 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1844 files=file_dict)
1845 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1846 self.waitUntilSettled()
1847 self.assertEqual(A.reported, 1,
1848 "A should report failure")
1849 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
1850 self.assertIn('Base jobs must be defined in config projects',
1851 A.messages[0])
1852 self.assertHistory([])
James E. Blairdb089032017-08-15 13:42:12 -07001853
1854
1855class TestSecretLeaks(AnsibleZuulTestCase):
1856 tenant_config_file = 'config/secret-leaks/main.yaml'
1857
1858 def searchForContent(self, path, content):
1859 matches = []
1860 for (dirpath, dirnames, filenames) in os.walk(path):
1861 for filename in filenames:
1862 filepath = os.path.join(dirpath, filename)
1863 with open(filepath, 'rb') as f:
1864 if content in f.read():
1865 matches.append(filepath[len(path):])
1866 return matches
1867
1868 def _test_secret_file(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
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', result='SUCCESS', 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/secret-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07001892 set(matches))
1893
1894 def test_secret_file(self):
1895 self._test_secret_file()
1896
1897 def test_secret_file_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()
1902
1903 def _test_secret_file_fail(self):
1904 # Or rather -- test that they *don't* leak.
1905 # Keep the jobdir around so we can inspect contents.
1906 self.executor_server.keep_jobdir = True
1907 conf = textwrap.dedent(
1908 """
1909 - project:
1910 name: org/project
1911 check:
1912 jobs:
1913 - secret-file-fail
1914 """)
1915
1916 file_dict = {'.zuul.yaml': conf}
1917 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1918 files=file_dict)
1919 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1920 self.waitUntilSettled()
1921 self.assertHistory([
1922 dict(name='secret-file-fail', result='FAILURE', changes='1,1'),
1923 ], ordered=False)
1924 matches = self.searchForContent(self.history[0].jobdir.root,
1925 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07001926 self.assertEqual(set(['/work/failure-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07001927 set(matches))
1928
1929 def test_secret_file_fail(self):
1930 self._test_secret_file_fail()
1931
1932 def test_secret_file_fail_verbose(self):
1933 # Output extra ansible info to exercise alternate logging code
1934 # paths.
1935 self.executor_server.verbose = True
1936 self._test_secret_file_fail()
James E. Blaira00910c2017-08-23 09:15:04 -07001937
1938
1939class TestJobOutput(AnsibleZuulTestCase):
1940 tenant_config_file = 'config/job-output/main.yaml'
1941
1942 def _get_file(self, build, path):
1943 p = os.path.join(build.jobdir.root, path)
1944 with open(p) as f:
1945 return f.read()
1946
1947 def test_job_output(self):
Monty Taylor0e2489a2017-10-10 11:57:29 -05001948 # Verify that command standard output appears in the job output,
1949 # and that failures in the final playbook get logged.
James E. Blaira00910c2017-08-23 09:15:04 -07001950
1951 # This currently only verifies we receive output from
1952 # localhost. Notably, it does not verify we receive output
1953 # via zuul_console streaming.
1954 self.executor_server.keep_jobdir = True
1955 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1956 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1957 self.waitUntilSettled()
1958 self.assertHistory([
1959 dict(name='job-output', result='SUCCESS', changes='1,1'),
1960 ], ordered=False)
1961
1962 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
1963 j = json.loads(self._get_file(self.history[0],
1964 'work/logs/job-output.json'))
1965 self.assertEqual(token,
1966 j[0]['plays'][0]['tasks'][0]
1967 ['hosts']['localhost']['stdout'])
1968
1969 print(self._get_file(self.history[0],
1970 'work/logs/job-output.txt'))
1971 self.assertIn(token,
1972 self._get_file(self.history[0],
1973 'work/logs/job-output.txt'))
Monty Taylor0e2489a2017-10-10 11:57:29 -05001974
1975 def test_job_output_failure_log(self):
1976 logger = logging.getLogger('zuul.AnsibleJob')
1977 output = io.StringIO()
1978 logger.addHandler(logging.StreamHandler(output))
1979
1980 # Verify that a failure in the last post playbook emits the contents
1981 # of the json output to the log
1982 self.executor_server.keep_jobdir = True
1983 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
1984 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1985 self.waitUntilSettled()
1986 self.assertHistory([
1987 dict(name='job-output-failure',
1988 result='POST_FAILURE', changes='1,1'),
1989 ], ordered=False)
1990
1991 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
1992 j = json.loads(self._get_file(self.history[0],
1993 'work/logs/job-output.json'))
1994 self.assertEqual(token,
1995 j[0]['plays'][0]['tasks'][0]
1996 ['hosts']['localhost']['stdout'])
1997
1998 print(self._get_file(self.history[0],
1999 'work/logs/job-output.json'))
2000 self.assertIn(token,
2001 self._get_file(self.history[0],
2002 'work/logs/job-output.txt'))
2003
2004 log_output = output.getvalue()
2005 self.assertIn('Final playbook failed', log_output)
2006 self.assertIn('Failure test', log_output)