blob: b4702f915a68bfb35a163cd1b8aaf5526fb39553 [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
James E. Blair6bc10482017-10-20 11:28:53 -0700286 def test_dynamic_template(self):
287 in_repo_conf = textwrap.dedent(
288 """
289 - job:
290 name: project-test1
291
292 - project-template:
293 name: common-config-template
294 check:
295 jobs:
296 - project-test1
297
298 - project:
299 name: org/project
300 templates: [common-config-template]
301 """)
302
303 file_dict = {'.zuul.yaml': in_repo_conf}
304 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
305 files=file_dict)
306 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
307 self.waitUntilSettled()
308 self.assertHistory([
309 dict(name='template-job', result='SUCCESS', changes='1,1')])
310
Tobias Henkelf02cf512017-07-21 22:55:34 +0200311 def test_dynamic_config_non_existing_job(self):
312 """Test that requesting a non existent job fails"""
313 in_repo_conf = textwrap.dedent(
314 """
315 - job:
316 name: project-test1
317
318 - project:
319 name: org/project
320 check:
321 jobs:
322 - non-existent-job
323 """)
324
325 in_repo_playbook = textwrap.dedent(
326 """
327 - hosts: all
328 tasks: []
329 """)
330
331 file_dict = {'.zuul.yaml': in_repo_conf,
332 'playbooks/project-test2.yaml': in_repo_playbook}
333 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
334 files=file_dict)
335 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
336 self.waitUntilSettled()
337 self.assertEqual(A.reported, 1,
338 "A should report failure")
339 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
340 self.assertIn('Job non-existent-job not defined', A.messages[0],
341 "A should have failed the check pipeline")
342 self.assertHistory([])
343
344 def test_dynamic_config_non_existing_job_in_template(self):
345 """Test that requesting a non existent job fails"""
346 in_repo_conf = textwrap.dedent(
347 """
348 - job:
349 name: project-test1
350
351 - project-template:
352 name: test-template
353 check:
354 jobs:
355 - non-existent-job
356
357 - project:
358 name: org/project
359 templates:
360 - test-template
361 """)
362
363 in_repo_playbook = textwrap.dedent(
364 """
365 - hosts: all
366 tasks: []
367 """)
368
369 file_dict = {'.zuul.yaml': in_repo_conf,
370 'playbooks/project-test2.yaml': in_repo_playbook}
371 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
372 files=file_dict)
373 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
374 self.waitUntilSettled()
375 self.assertEqual(A.reported, 1,
376 "A should report failure")
377 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
378 self.assertIn('Job non-existent-job not defined', A.messages[0],
379 "A should have failed the check pipeline")
380 self.assertHistory([])
381
Tobias Henkel0f714002017-06-30 23:30:52 +0200382 def test_dynamic_config_new_patchset(self):
383 self.executor_server.hold_jobs_in_build = True
384
385 tenant = self.sched.abide.tenants.get('tenant-one')
386 check_pipeline = tenant.layout.pipelines['check']
387
388 in_repo_conf = textwrap.dedent(
389 """
390 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200391 name: project-test1
392
393 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200394 name: project-test2
395
396 - project:
397 name: org/project
398 check:
399 jobs:
400 - project-test2
401 """)
402
403 in_repo_playbook = textwrap.dedent(
404 """
405 - hosts: all
406 tasks: []
407 """)
408
409 file_dict = {'.zuul.yaml': in_repo_conf,
410 'playbooks/project-test2.yaml': in_repo_playbook}
411 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
412 files=file_dict)
413 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
414 self.waitUntilSettled()
415
416 items = check_pipeline.getAllItems()
417 self.assertEqual(items[0].change.number, '1')
418 self.assertEqual(items[0].change.patchset, '1')
419 self.assertTrue(items[0].live)
420
421 in_repo_conf = textwrap.dedent(
422 """
423 - job:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200424 name: project-test1
425
426 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200427 name: project-test2
428
429 - project:
430 name: org/project
431 check:
432 jobs:
433 - project-test1
434 - project-test2
435 """)
436 file_dict = {'.zuul.yaml': in_repo_conf,
437 'playbooks/project-test2.yaml': in_repo_playbook}
438
439 A.addPatchset(files=file_dict)
440 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
441
442 self.waitUntilSettled()
443
444 items = check_pipeline.getAllItems()
445 self.assertEqual(items[0].change.number, '1')
446 self.assertEqual(items[0].change.patchset, '2')
447 self.assertTrue(items[0].live)
448
449 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200450 self.executor_server.release('project-test1')
451 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +0200452 self.executor_server.release()
453 self.waitUntilSettled()
454
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200455 self.assertHistory([
456 dict(name='project-test2', result='ABORTED', changes='1,1'),
457 dict(name='project-test1', result='SUCCESS', changes='1,2'),
458 dict(name='project-test2', result='SUCCESS', changes='1,2')])
459
James E. Blairff555742017-02-19 11:34:27 -0800460 def test_in_repo_branch(self):
461 in_repo_conf = textwrap.dedent(
462 """
463 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200464 name: project-test1
465
466 - job:
James E. Blairff555742017-02-19 11:34:27 -0800467 name: project-test2
468
469 - project:
470 name: org/project
471 tenant-one-gate:
472 jobs:
473 - project-test2
474 """)
475
476 in_repo_playbook = textwrap.dedent(
477 """
478 - hosts: all
479 tasks: []
480 """)
481
482 file_dict = {'.zuul.yaml': in_repo_conf,
483 'playbooks/project-test2.yaml': in_repo_playbook}
484 self.create_branch('org/project', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700485 self.fake_gerrit.addEvent(
486 self.fake_gerrit.getFakeBranchCreatedEvent(
487 'org/project', 'stable'))
James E. Blair6069f2b2017-09-26 16:34:11 -0700488 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800489 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
490 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200491 A.addApproval('Code-Review', 2)
492 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800493 self.waitUntilSettled()
494 self.assertEqual(A.data['status'], 'MERGED')
495 self.assertEqual(A.reported, 2,
496 "A should report start and success")
497 self.assertIn('tenant-one-gate', A.messages[1],
498 "A should transit tenant-one gate")
499 self.assertHistory([
500 dict(name='project-test2', result='SUCCESS', changes='1,1')])
501 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800502 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800503
504 # The config change should not affect master.
505 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200506 B.addApproval('Code-Review', 2)
507 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800508 self.waitUntilSettled()
509 self.assertHistory([
510 dict(name='project-test2', result='SUCCESS', changes='1,1'),
511 dict(name='project-test1', result='SUCCESS', changes='2,1')])
512
513 # The config change should be live for further changes on
514 # stable.
515 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200516 C.addApproval('Code-Review', 2)
517 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800518 self.waitUntilSettled()
519 self.assertHistory([
520 dict(name='project-test2', result='SUCCESS', changes='1,1'),
521 dict(name='project-test1', result='SUCCESS', changes='2,1'),
522 dict(name='project-test2', result='SUCCESS', changes='3,1')])
523
James E. Blaira5a12492017-05-03 11:40:48 -0700524 def test_crd_dynamic_config_branch(self):
525 # Test that we can create a job in one repo and be able to use
526 # it from a different branch on a different repo.
527
528 self.create_branch('org/project1', 'stable')
James E. Blair72facdc2017-08-17 10:29:12 -0700529 self.fake_gerrit.addEvent(
530 self.fake_gerrit.getFakeBranchCreatedEvent(
531 'org/project1', 'stable'))
James E. Blaira5a12492017-05-03 11:40:48 -0700532
533 in_repo_conf = textwrap.dedent(
534 """
535 - job:
Tobias Henkelf02cf512017-07-21 22:55:34 +0200536 name: project-test1
537
538 - job:
James E. Blaira5a12492017-05-03 11:40:48 -0700539 name: project-test2
540
541 - project:
542 name: org/project
543 check:
544 jobs:
545 - project-test2
546 """)
547
548 in_repo_playbook = textwrap.dedent(
549 """
550 - hosts: all
551 tasks: []
552 """)
553
554 file_dict = {'.zuul.yaml': in_repo_conf,
555 'playbooks/project-test2.yaml': in_repo_playbook}
556 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
557 files=file_dict)
558
559 second_repo_conf = textwrap.dedent(
560 """
561 - project:
562 name: org/project1
563 check:
564 jobs:
565 - project-test2
566 """)
567
568 second_file_dict = {'.zuul.yaml': second_repo_conf}
569 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
570 files=second_file_dict)
571 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
572 B.subject, A.data['id'])
573
574 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
575 self.waitUntilSettled()
576 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
577 self.waitUntilSettled()
578
579 self.assertEqual(A.reported, 1, "A should report")
580 self.assertHistory([
581 dict(name='project-test2', result='SUCCESS', changes='1,1'),
582 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
583 ])
584
James E. Blair97043882017-09-06 15:51:17 -0700585 def test_yaml_list_error(self):
586 in_repo_conf = textwrap.dedent(
587 """
588 job: foo
589 """)
590
591 file_dict = {'.zuul.yaml': in_repo_conf}
592 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
593 files=file_dict)
594 A.addApproval('Code-Review', 2)
595 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
596 self.waitUntilSettled()
597
598 self.assertEqual(A.data['status'], 'NEW')
599 self.assertEqual(A.reported, 1,
600 "A should report failure")
601 self.assertIn('not a list', A.messages[0],
602 "A should have a syntax error reported")
603
604 def test_yaml_dict_error(self):
605 in_repo_conf = textwrap.dedent(
606 """
607 - job
608 """)
609
610 file_dict = {'.zuul.yaml': in_repo_conf}
611 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
612 files=file_dict)
613 A.addApproval('Code-Review', 2)
614 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
615 self.waitUntilSettled()
616
617 self.assertEqual(A.data['status'], 'NEW')
618 self.assertEqual(A.reported, 1,
619 "A should report failure")
620 self.assertIn('not a dictionary', A.messages[0],
621 "A should have a syntax error reported")
622
623 def test_yaml_key_error(self):
624 in_repo_conf = textwrap.dedent(
625 """
626 - job:
627 name: project-test2
628 """)
629
630 file_dict = {'.zuul.yaml': in_repo_conf}
631 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
632 files=file_dict)
633 A.addApproval('Code-Review', 2)
634 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
635 self.waitUntilSettled()
636
637 self.assertEqual(A.data['status'], 'NEW')
638 self.assertEqual(A.reported, 1,
639 "A should report failure")
640 self.assertIn('has more than one key', A.messages[0],
641 "A should have a syntax error reported")
642
643 def test_yaml_unknown_error(self):
644 in_repo_conf = textwrap.dedent(
645 """
646 - foobar:
647 foo: bar
648 """)
649
650 file_dict = {'.zuul.yaml': in_repo_conf}
651 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
652 files=file_dict)
653 A.addApproval('Code-Review', 2)
654 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
655 self.waitUntilSettled()
656
657 self.assertEqual(A.data['status'], 'NEW')
658 self.assertEqual(A.reported, 1,
659 "A should report failure")
660 self.assertIn('not recognized', A.messages[0],
661 "A should have a syntax error reported")
662
James E. Blair149b69c2017-03-02 10:48:16 -0800663 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -0800664 in_repo_conf = textwrap.dedent(
665 """
666 - job:
667 name: project-test2
668 foo: error
669 """)
670
671 file_dict = {'.zuul.yaml': in_repo_conf}
672 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
673 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200674 A.addApproval('Code-Review', 2)
675 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -0800676 self.waitUntilSettled()
677
678 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200679 self.assertEqual(A.reported, 1,
680 "A should report failure")
681 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -0800682 "A should have a syntax error reported")
683
James E. Blair149b69c2017-03-02 10:48:16 -0800684 def test_trusted_syntax_error(self):
685 in_repo_conf = textwrap.dedent(
686 """
687 - job:
688 name: project-test2
689 foo: error
690 """)
691
692 file_dict = {'zuul.yaml': in_repo_conf}
693 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
694 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200695 A.addApproval('Code-Review', 2)
696 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -0800697 self.waitUntilSettled()
698
699 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200700 self.assertEqual(A.reported, 1,
701 "A should report failure")
702 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -0800703 "A should have a syntax error reported")
704
James E. Blair6f140c72017-03-03 10:32:07 -0800705 def test_untrusted_yaml_error(self):
706 in_repo_conf = textwrap.dedent(
707 """
708 - job:
709 foo: error
710 """)
711
712 file_dict = {'.zuul.yaml': in_repo_conf}
713 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
714 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200715 A.addApproval('Code-Review', 2)
716 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -0800717 self.waitUntilSettled()
718
719 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200720 self.assertEqual(A.reported, 1,
721 "A should report failure")
722 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -0800723 "A should have a syntax error reported")
724
James E. Blairdb04e6a2017-05-03 14:49:36 -0700725 def test_untrusted_shadow_error(self):
726 in_repo_conf = textwrap.dedent(
727 """
728 - job:
729 name: common-config-test
730 """)
731
732 file_dict = {'.zuul.yaml': in_repo_conf}
733 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
734 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200735 A.addApproval('Code-Review', 2)
736 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -0700737 self.waitUntilSettled()
738
739 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200740 self.assertEqual(A.reported, 1,
741 "A should report failure")
742 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -0700743 "A should have a syntax error reported")
744
James E. Blaird5656ad2017-06-02 14:29:41 -0700745 def test_untrusted_pipeline_error(self):
746 in_repo_conf = textwrap.dedent(
747 """
748 - pipeline:
749 name: test
750 """)
751
752 file_dict = {'.zuul.yaml': in_repo_conf}
753 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
754 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200755 A.addApproval('Code-Review', 2)
756 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700757 self.waitUntilSettled()
758
759 self.assertEqual(A.data['status'], 'NEW')
760 self.assertEqual(A.reported, 1,
761 "A should report failure")
762 self.assertIn('Pipelines may not be defined', A.messages[0],
763 "A should have a syntax error reported")
764
765 def test_untrusted_project_error(self):
766 in_repo_conf = textwrap.dedent(
767 """
768 - project:
769 name: org/project1
770 """)
771
772 file_dict = {'.zuul.yaml': in_repo_conf}
773 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
774 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200775 A.addApproval('Code-Review', 2)
776 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700777 self.waitUntilSettled()
778
779 self.assertEqual(A.data['status'], 'NEW')
780 self.assertEqual(A.reported, 1,
781 "A should report failure")
782 self.assertIn('the only project definition permitted', A.messages[0],
783 "A should have a syntax error reported")
784
James E. Blairf03173b2017-10-10 10:46:43 -0700785 def test_untrusted_depends_on_trusted(self):
786 with open(os.path.join(FIXTURE_DIR,
787 'config/in-repo/git/',
788 'common-config/zuul.yaml')) as f:
789 common_config = f.read()
790
791 common_config += textwrap.dedent(
792 """
793 - job:
794 name: project-test9
795 """)
796
797 file_dict = {'zuul.yaml': common_config}
798 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
799 files=file_dict)
800 in_repo_conf = textwrap.dedent(
801 """
802 - job:
803 name: project-test1
804 - project:
805 name: org/project
806 check:
807 jobs:
808 - project-test9
809 """)
810
811 file_dict = {'zuul.yaml': in_repo_conf}
812 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
813 files=file_dict)
814 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
815 B.subject, A.data['id'])
816 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
817 self.waitUntilSettled()
818
819 self.assertEqual(B.data['status'], 'NEW')
820 self.assertEqual(B.reported, 1,
821 "B should report failure")
822 self.assertIn('depends on a change to a config project',
823 B.messages[0],
824 "A should have a syntax error reported")
825
James E. Blaire64b0e42017-06-08 11:23:34 -0700826 def test_duplicate_node_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 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700835 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700836 """)
837
838 file_dict = {'.zuul.yaml': in_repo_conf}
839 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
840 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200841 A.addApproval('Code-Review', 2)
842 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700843 self.waitUntilSettled()
844
845 self.assertEqual(A.data['status'], 'NEW')
846 self.assertEqual(A.reported, 1,
847 "A should report failure")
848 self.assertIn('appears multiple times', A.messages[0],
849 "A should have a syntax error reported")
850
851 def test_duplicate_group_error(self):
852 in_repo_conf = textwrap.dedent(
853 """
854 - nodeset:
855 name: duplicate
856 nodes:
857 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700858 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700859 groups:
860 - name: group
861 nodes: compute
862 - name: group
863 nodes: compute
864 """)
865
866 file_dict = {'.zuul.yaml': in_repo_conf}
867 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
868 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200869 A.addApproval('Code-Review', 2)
870 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700871 self.waitUntilSettled()
872
873 self.assertEqual(A.data['status'], 'NEW')
874 self.assertEqual(A.reported, 1,
875 "A should report failure")
876 self.assertIn('appears multiple times', A.messages[0],
877 "A should have a syntax error reported")
878
James E. Blair4ae399f2017-09-20 17:15:09 -0700879 def test_secret_not_found_error(self):
880 in_repo_conf = textwrap.dedent(
881 """
882 - job:
883 name: test
884 secrets: does-not-exist
885 """)
886
887 file_dict = {'.zuul.yaml': in_repo_conf}
888 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
889 files=file_dict)
890 A.addApproval('Code-Review', 2)
891 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
892 self.waitUntilSettled()
893
894 self.assertEqual(A.data['status'], 'NEW')
895 self.assertEqual(A.reported, 1,
896 "A should report failure")
897 self.assertIn('secret "does-not-exist" was not found', A.messages[0],
898 "A should have a syntax error reported")
899
900 def test_nodeset_not_found_error(self):
901 in_repo_conf = textwrap.dedent(
902 """
903 - job:
904 name: test
905 nodeset: does-not-exist
906 """)
907
908 file_dict = {'.zuul.yaml': in_repo_conf}
909 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
910 files=file_dict)
911 A.addApproval('Code-Review', 2)
912 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
913 self.waitUntilSettled()
914
915 self.assertEqual(A.data['status'], 'NEW')
916 self.assertEqual(A.reported, 1,
917 "A should report failure")
918 self.assertIn('nodeset "does-not-exist" was not found', A.messages[0],
919 "A should have a syntax error reported")
920
James E. Blair89e25eb2017-09-26 09:11:31 -0700921 def test_template_not_found_error(self):
922 in_repo_conf = textwrap.dedent(
923 """
924 - job:
925 name: project-test1
926 - project:
927 name: org/project
928 templates:
929 - does-not-exist
930 """)
931
932 file_dict = {'.zuul.yaml': in_repo_conf}
933 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
934 files=file_dict)
935 A.addApproval('Code-Review', 2)
936 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
937 self.waitUntilSettled()
938
939 self.assertEqual(A.data['status'], 'NEW')
940 self.assertEqual(A.reported, 1,
941 "A should report failure")
942 self.assertIn('project template "does-not-exist" was not found',
943 A.messages[0],
944 "A should have a syntax error reported")
945
Monty Taylor8be3c0c2017-10-06 10:37:37 -0500946 def test_job_list_in_project_template_not_dict_error(self):
947 in_repo_conf = textwrap.dedent(
948 """
949 - job:
950 name: project-test1
951 - project-template:
952 name: some-jobs
953 check:
954 jobs:
955 - project-test1:
956 - required-projects:
957 org/project2
958 """)
959
960 file_dict = {'.zuul.yaml': in_repo_conf}
961 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
962 files=file_dict)
963 A.addApproval('Code-Review', 2)
964 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
965 self.waitUntilSettled()
966
967 self.assertEqual(A.data['status'], 'NEW')
968 self.assertEqual(A.reported, 1,
969 "A should report failure")
970 self.assertIn('expected str for dictionary value',
971 A.messages[0], "A should have a syntax error reported")
972
973 def test_job_list_in_project_not_dict_error(self):
974 in_repo_conf = textwrap.dedent(
975 """
976 - job:
977 name: project-test1
978 - project:
979 name: org/project1
980 check:
981 jobs:
982 - project-test1:
983 - required-projects:
984 org/project2
985 """)
986
987 file_dict = {'.zuul.yaml': in_repo_conf}
988 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
989 files=file_dict)
990 A.addApproval('Code-Review', 2)
991 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
992 self.waitUntilSettled()
993
994 self.assertEqual(A.data['status'], 'NEW')
995 self.assertEqual(A.reported, 1,
996 "A should report failure")
997 self.assertIn('expected str for dictionary value',
998 A.messages[0], "A should have a syntax error reported")
999
James E. Blair1235f142017-10-07 09:11:43 -07001000 def test_project_template(self):
1001 # Tests that a project template is not modified when used, and
1002 # can therefore be used in subsequent reconfigurations.
1003 in_repo_conf = textwrap.dedent(
1004 """
1005 - job:
1006 name: project-test1
1007 - project-template:
1008 name: some-jobs
1009 tenant-one-gate:
1010 jobs:
1011 - project-test1:
1012 required-projects:
1013 - org/project1
1014 - project:
1015 name: org/project
1016 templates:
1017 - some-jobs
1018 """)
1019
1020 file_dict = {'.zuul.yaml': in_repo_conf}
1021 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1022 files=file_dict)
1023 A.addApproval('Code-Review', 2)
1024 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1025 self.waitUntilSettled()
1026 self.assertEqual(A.data['status'], 'MERGED')
1027 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1028 self.waitUntilSettled()
1029 in_repo_conf = textwrap.dedent(
1030 """
1031 - project:
1032 name: org/project1
1033 templates:
1034 - some-jobs
1035 """)
1036 file_dict = {'.zuul.yaml': in_repo_conf}
1037 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
1038 files=file_dict)
1039 B.addApproval('Code-Review', 2)
1040 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1041 self.waitUntilSettled()
1042 self.assertEqual(B.data['status'], 'MERGED')
1043
James E. Blairbccdfcf2017-10-07 13:37:26 -07001044 def test_job_remove_add(self):
1045 # Tests that a job can be removed from one repo and added in another.
1046 # First, remove the current config for project1 since it
1047 # references the job we want to remove.
1048 file_dict = {'.zuul.yaml': None}
1049 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1050 files=file_dict)
1051 A.setMerged()
1052 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1053 self.waitUntilSettled()
1054 # Then propose a change to delete the job from one repo...
1055 file_dict = {'.zuul.yaml': None}
1056 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1057 files=file_dict)
1058 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1059 self.waitUntilSettled()
1060 # ...and a second that depends on it that adds it to another repo.
1061 in_repo_conf = textwrap.dedent(
1062 """
1063 - job:
1064 name: project-test1
1065
1066 - project:
1067 name: org/project1
1068 check:
1069 jobs:
1070 - project-test1
1071 """)
1072 in_repo_playbook = textwrap.dedent(
1073 """
1074 - hosts: all
1075 tasks: []
1076 """)
1077 file_dict = {'.zuul.yaml': in_repo_conf,
1078 'playbooks/project-test1.yaml': in_repo_playbook}
1079 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C',
1080 files=file_dict,
1081 parent='refs/changes/1/1/1')
1082 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1083 C.subject, B.data['id'])
1084 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1085 self.waitUntilSettled()
1086 self.assertHistory([
1087 dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'),
1088 ], ordered=False)
1089
James E. Blair09f9ffe2017-07-11 15:30:25 -07001090 def test_multi_repo(self):
1091 downstream_repo_conf = textwrap.dedent(
1092 """
1093 - project:
1094 name: org/project1
1095 tenant-one-gate:
1096 jobs:
1097 - project-test1
1098
1099 - job:
1100 name: project1-test1
1101 parent: project-test1
1102 """)
1103
1104 file_dict = {'.zuul.yaml': downstream_repo_conf}
1105 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1106 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001107 A.addApproval('Code-Review', 2)
1108 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001109 self.waitUntilSettled()
1110
1111 self.assertEqual(A.data['status'], 'MERGED')
1112 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
1113 self.waitUntilSettled()
1114
1115 upstream_repo_conf = textwrap.dedent(
1116 """
1117 - job:
1118 name: project-test1
1119
1120 - job:
1121 name: project-test2
1122
1123 - project:
1124 name: org/project
1125 tenant-one-gate:
1126 jobs:
1127 - project-test1
1128 """)
1129
1130 file_dict = {'.zuul.yaml': upstream_repo_conf}
1131 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
1132 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +02001133 B.addApproval('Code-Review', 2)
1134 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -07001135 self.waitUntilSettled()
1136
1137 self.assertEqual(B.data['status'], 'MERGED')
1138 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
1139 self.waitUntilSettled()
1140
1141 tenant = self.sched.abide.tenants.get('tenant-one')
1142 # Ensure the latest change is reflected in the config; if it
1143 # isn't this will raise an exception.
1144 tenant.layout.getJob('project-test2')
1145
James E. Blair332636e2017-09-05 10:14:35 -07001146 def test_pipeline_error(self):
1147 with open(os.path.join(FIXTURE_DIR,
1148 'config/in-repo/git/',
1149 'common-config/zuul.yaml')) as f:
1150 base_common_config = f.read()
1151
1152 in_repo_conf_A = textwrap.dedent(
1153 """
1154 - pipeline:
1155 name: periodic
1156 foo: error
1157 """)
1158
1159 file_dict = {'zuul.yaml': None,
1160 'zuul.d/main.yaml': base_common_config,
1161 'zuul.d/test1.yaml': in_repo_conf_A}
1162 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1163 files=file_dict)
1164 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1165 self.waitUntilSettled()
1166 self.assertEqual(A.reported, 1,
1167 "A should report failure")
1168 self.assertIn('syntax error',
1169 A.messages[0],
1170 "A should have an error reported")
1171
1172 def test_change_series_error(self):
1173 with open(os.path.join(FIXTURE_DIR,
1174 'config/in-repo/git/',
1175 'common-config/zuul.yaml')) as f:
1176 base_common_config = f.read()
1177
1178 in_repo_conf_A = textwrap.dedent(
1179 """
1180 - pipeline:
1181 name: periodic
1182 foo: error
1183 """)
1184
1185 file_dict = {'zuul.yaml': None,
1186 'zuul.d/main.yaml': base_common_config,
1187 'zuul.d/test1.yaml': in_repo_conf_A}
1188 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
1189 files=file_dict)
1190
1191 in_repo_conf_B = textwrap.dedent(
1192 """
1193 - job:
1194 name: project-test2
1195 foo: error
1196 """)
1197
1198 file_dict = {'zuul.yaml': None,
1199 'zuul.d/main.yaml': base_common_config,
1200 'zuul.d/test1.yaml': in_repo_conf_A,
1201 'zuul.d/test2.yaml': in_repo_conf_B}
1202 B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B',
1203 files=file_dict)
1204 B.setDependsOn(A, 1)
1205 C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C')
1206 C.setDependsOn(B, 1)
1207 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1208 self.waitUntilSettled()
1209
1210 self.assertEqual(C.reported, 1,
1211 "C should report failure")
1212 self.assertIn('depends on a change that failed to merge',
1213 C.messages[0],
1214 "C should have an error reported")
1215
James E. Blairc73c73a2017-01-20 15:15:15 -08001216
James E. Blairc9455002017-09-06 09:22:19 -07001217class TestInRepoJoin(ZuulTestCase):
1218 # In this config, org/project is not a member of any pipelines, so
1219 # that we may test the changes that cause it to join them.
1220
1221 tenant_config_file = 'config/in-repo-join/main.yaml'
1222
1223 def test_dynamic_dependent_pipeline(self):
1224 # Test dynamically adding a project to a
1225 # dependent pipeline for the first time
1226 self.executor_server.hold_jobs_in_build = True
1227
1228 tenant = self.sched.abide.tenants.get('tenant-one')
1229 gate_pipeline = tenant.layout.pipelines['gate']
1230
1231 in_repo_conf = textwrap.dedent(
1232 """
1233 - job:
1234 name: project-test1
1235
1236 - job:
1237 name: project-test2
1238
1239 - project:
1240 name: org/project
1241 gate:
1242 jobs:
1243 - project-test2
1244 """)
1245
1246 in_repo_playbook = textwrap.dedent(
1247 """
1248 - hosts: all
1249 tasks: []
1250 """)
1251
1252 file_dict = {'.zuul.yaml': in_repo_conf,
1253 'playbooks/project-test2.yaml': in_repo_playbook}
1254 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1255 files=file_dict)
1256 A.addApproval('Code-Review', 2)
1257 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1258 self.waitUntilSettled()
1259
1260 items = gate_pipeline.getAllItems()
1261 self.assertEqual(items[0].change.number, '1')
1262 self.assertEqual(items[0].change.patchset, '1')
1263 self.assertTrue(items[0].live)
1264
1265 self.executor_server.hold_jobs_in_build = False
1266 self.executor_server.release()
1267 self.waitUntilSettled()
1268
1269 # Make sure the dynamic queue got cleaned up
1270 self.assertEqual(gate_pipeline.queues, [])
1271
1272 def test_dynamic_dependent_pipeline_failure(self):
1273 # Test that a change behind a failing change adding a project
1274 # to a dependent pipeline is dequeued.
1275 self.executor_server.hold_jobs_in_build = True
1276
1277 in_repo_conf = textwrap.dedent(
1278 """
1279 - job:
1280 name: project-test1
1281
1282 - project:
1283 name: org/project
1284 gate:
1285 jobs:
1286 - project-test1
1287 """)
1288
1289 file_dict = {'.zuul.yaml': in_repo_conf}
1290 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1291 files=file_dict)
1292 self.executor_server.failJob('project-test1', A)
1293 A.addApproval('Code-Review', 2)
1294 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
1295 self.waitUntilSettled()
1296
1297 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1298 B.addApproval('Code-Review', 2)
1299 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1300 self.waitUntilSettled()
1301
James E. Blair3490c5d2017-09-07 08:33:23 -07001302 self.orderedRelease()
James E. Blairc9455002017-09-06 09:22:19 -07001303 self.waitUntilSettled()
1304 self.assertEqual(A.reported, 2,
1305 "A should report start and failure")
1306 self.assertEqual(A.data['status'], 'NEW')
1307 self.assertEqual(B.reported, 1,
1308 "B should report start")
1309 self.assertHistory([
1310 dict(name='project-test1', result='FAILURE', changes='1,1'),
James E. Blair3490c5d2017-09-07 08:33:23 -07001311 dict(name='project-test1', result='ABORTED', changes='1,1 2,1'),
James E. Blairc9455002017-09-06 09:22:19 -07001312 ], ordered=False)
1313
James E. Blair0af198f2017-09-06 09:52:35 -07001314 def test_dynamic_dependent_pipeline_absent(self):
1315 # Test that a series of dependent changes don't report merge
1316 # failures to a pipeline they aren't in.
1317 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1318 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1319 B.setDependsOn(A, 1)
1320
1321 A.addApproval('Code-Review', 2)
1322 A.addApproval('Approved', 1)
1323 B.addApproval('Code-Review', 2)
1324 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
1325 self.waitUntilSettled()
1326 self.assertEqual(A.reported, 0,
1327 "A should not report")
1328 self.assertEqual(A.data['status'], 'NEW')
1329 self.assertEqual(B.reported, 0,
1330 "B should not report")
1331 self.assertEqual(B.data['status'], 'NEW')
1332 self.assertHistory([])
1333
James E. Blairc9455002017-09-06 09:22:19 -07001334
James E. Blairc73c73a2017-01-20 15:15:15 -08001335class TestAnsible(AnsibleZuulTestCase):
1336 # A temporary class to hold new tests while others are disabled
1337
1338 tenant_config_file = 'config/ansible/main.yaml'
1339
1340 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +11001341 # Keep the jobdir around so we can inspect contents if an
1342 # assert fails.
1343 self.executor_server.keep_jobdir = True
1344 # Output extra ansible info so we might see errors.
1345 self.executor_server.verbose = True
1346 # Add a site variables file, used by check-vars
1347 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
1348 'variables.yaml')
1349 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -08001350 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1351 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1352 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +02001353 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +11001354 with self.jobLog(build_timeout):
1355 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001356 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +11001357 with self.jobLog(build_faillocal):
1358 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001359 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +11001360 with self.jobLog(build_failpost):
1361 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001362 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +11001363 with self.jobLog(build_check_vars):
1364 self.assertEqual(build_check_vars.result, 'SUCCESS')
Monty Tayloraff8b402017-08-16 18:40:41 -05001365 build_check_secret_names = self.getJobFromHistory('check-secret-names')
1366 with self.jobLog(build_check_secret_names):
1367 self.assertEqual(build_check_secret_names.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001368 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +11001369 with self.jobLog(build_hello):
1370 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +02001371 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +11001372 with self.jobLog(build_python27):
1373 self.assertEqual(build_python27.result, 'SUCCESS')
1374 flag_path = os.path.join(self.test_root,
1375 build_python27.uuid + '.flag')
1376 self.assertTrue(os.path.exists(flag_path))
1377 copied_path = os.path.join(self.test_root, build_python27.uuid +
1378 '.copied')
1379 self.assertTrue(os.path.exists(copied_path))
1380 failed_path = os.path.join(self.test_root, build_python27.uuid +
1381 '.failed')
1382 self.assertFalse(os.path.exists(failed_path))
1383 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
1384 '.pre.flag')
1385 self.assertTrue(os.path.exists(pre_flag_path))
1386 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
1387 '.post.flag')
1388 self.assertTrue(os.path.exists(post_flag_path))
1389 bare_role_flag_path = os.path.join(self.test_root,
1390 build_python27.uuid +
1391 '.bare-role.flag')
1392 self.assertTrue(os.path.exists(bare_role_flag_path))
1393 secrets_path = os.path.join(self.test_root,
1394 build_python27.uuid + '.secrets')
1395 with open(secrets_path) as f:
1396 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -08001397
Jamie Lennox7655b552017-03-17 12:33:38 +11001398 msg = A.messages[0]
1399 success = "{} https://success.example.com/zuul-logs/{}"
1400 fail = "{} https://failure.example.com/zuul-logs/{}"
1401 self.assertIn(success.format("python27", build_python27.uuid), msg)
1402 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
1403 self.assertIn(success.format("check-vars",
1404 build_check_vars.uuid), msg)
1405 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
1406 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
1407 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +02001408
James E. Blairabbaa6f2017-04-06 16:11:44 -07001409 def _add_job(self, job_name):
1410 conf = textwrap.dedent(
1411 """
1412 - job:
1413 name: %s
1414
1415 - project:
1416 name: org/plugin-project
1417 check:
1418 jobs:
1419 - %s
1420 """ % (job_name, job_name))
1421
1422 file_dict = {'.zuul.yaml': conf}
1423 A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A',
1424 files=file_dict)
1425 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1426 self.waitUntilSettled()
1427
1428 def test_plugins(self):
1429 # Keep the jobdir around so we can inspect contents if an
1430 # assert fails.
1431 self.executor_server.keep_jobdir = True
1432 # Output extra ansible info so we might see errors.
1433 self.executor_server.verbose = True
1434
1435 count = 0
1436 plugin_tests = [
1437 ('passwd', 'FAILURE'),
1438 ('cartesian', 'SUCCESS'),
1439 ('consul_kv', 'FAILURE'),
1440 ('credstash', 'FAILURE'),
1441 ('csvfile_good', 'SUCCESS'),
1442 ('csvfile_bad', 'FAILURE'),
Monty Taylor93ad2212017-08-02 14:59:50 -05001443 ('uri_bad_path', 'FAILURE'),
1444 ('uri_bad_scheme', 'FAILURE'),
Monty Taylor788a40e2017-08-02 16:14:05 -05001445 ('block_local_override', 'FAILURE'),
Monty Taylor8da768f2017-08-31 14:15:35 -05001446 ('file_local_good', 'SUCCESS'),
1447 ('file_local_bad', 'FAILURE'),
James E. Blairabbaa6f2017-04-06 16:11:44 -07001448 ]
1449 for job_name, result in plugin_tests:
1450 count += 1
1451 self._add_job(job_name)
1452
1453 job = self.getJobFromHistory(job_name)
1454 with self.jobLog(job):
1455 self.assertEqual(count, len(self.history))
1456 build = self.history[-1]
1457 self.assertEqual(build.result, result)
1458
1459 # TODOv3(jeblair): parse the ansible output and verify we're
1460 # getting the exception we expect.
1461
James E. Blairb9c0d772017-03-03 14:34:49 -08001462
James E. Blaira4d4eef2017-06-30 14:49:17 -07001463class TestPrePlaybooks(AnsibleZuulTestCase):
1464 # A temporary class to hold new tests while others are disabled
1465
1466 tenant_config_file = 'config/pre-playbook/main.yaml'
1467
1468 def test_pre_playbook_fail(self):
1469 # Test that we run the post playbooks (but not the actual
1470 # playbook) when a pre-playbook fails.
1471 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1472 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1473 self.waitUntilSettled()
1474 build = self.getJobFromHistory('python27')
1475 self.assertIsNone(build.result)
1476 self.assertIn('RETRY_LIMIT', A.messages[0])
1477 flag_path = os.path.join(self.test_root, build.uuid +
1478 '.main.flag')
1479 self.assertFalse(os.path.exists(flag_path))
1480 pre_flag_path = os.path.join(self.test_root, build.uuid +
1481 '.pre.flag')
1482 self.assertFalse(os.path.exists(pre_flag_path))
1483 post_flag_path = os.path.join(self.test_root, build.uuid +
1484 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -07001485 self.assertTrue(os.path.exists(post_flag_path),
1486 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -07001487
1488
James E. Blairbacbb882017-10-17 09:48:23 -07001489class TestPostPlaybooks(AnsibleZuulTestCase):
1490 tenant_config_file = 'config/post-playbook/main.yaml'
1491
1492 def test_post_playbook_abort(self):
1493 # Test that when we abort a job in the post playbook, that we
1494 # don't send back POST_FAILURE.
1495 self.executor_server.verbose = True
1496 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1497 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1498
1499 while not len(self.builds):
1500 time.sleep(0.1)
1501 build = self.builds[0]
1502
1503 post_start = os.path.join(self.test_root, build.uuid +
1504 '.post_start.flag')
1505 start = time.time()
1506 while time.time() < start + 90:
1507 if os.path.exists(post_start):
1508 break
1509 time.sleep(0.1)
1510 # The post playbook has started, abort the job
1511 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1512 self.waitUntilSettled()
1513
1514 build = self.getJobFromHistory('python27')
1515 self.assertEqual('ABORTED', build.result)
1516
1517 post_end = os.path.join(self.test_root, build.uuid +
1518 '.post_end.flag')
1519 self.assertTrue(os.path.exists(post_start))
1520 self.assertFalse(os.path.exists(post_end))
1521
1522
James E. Blairb9c0d772017-03-03 14:34:49 -08001523class TestBrokenConfig(ZuulTestCase):
1524 # Test that we get an appropriate syntax error if we start with a
1525 # broken config.
1526
1527 tenant_config_file = 'config/broken/main.yaml'
1528
1529 def setUp(self):
1530 with testtools.ExpectedException(
1531 zuul.configloader.ConfigurationSyntaxError,
1532 "\nZuul encountered a syntax error"):
1533 super(TestBrokenConfig, self).setUp()
1534
1535 def test_broken_config_on_startup(self):
1536 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001537
1538
1539class TestProjectKeys(ZuulTestCase):
1540 # Test that we can generate project keys
1541
1542 # Normally the test infrastructure copies a static key in place
1543 # for each project before starting tests. This saves time because
1544 # Zuul's automatic key-generation on startup can be slow. To make
1545 # sure we exercise that code, in this test we allow Zuul to create
1546 # keys for the project on startup.
1547 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +02001548 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001549 tenant_config_file = 'config/in-repo/main.yaml'
1550
1551 def test_key_generation(self):
1552 key_root = os.path.join(self.state_root, 'keys')
1553 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
1554 # Make sure that a proper key was created on startup
1555 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -07001556 private_key, public_key = \
1557 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +00001558
1559 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
1560 fixture_private_key = i.read()
1561
1562 # Make sure that we didn't just end up with the static fixture
1563 # key
1564 self.assertNotEqual(fixture_private_key, private_key)
1565
1566 # Make sure it's the right length
1567 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -07001568
1569
James E. Blairbb94dfa2017-07-11 07:45:19 -07001570class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -07001571 def _assertRolePath(self, build, playbook, content):
1572 path = os.path.join(self.test_root, build.uuid,
1573 'ansible', playbook, 'ansible.cfg')
1574 roles_paths = []
1575 with open(path) as f:
1576 for line in f:
1577 if line.startswith('roles_path'):
1578 roles_paths.append(line)
1579 print(roles_paths)
1580 if content:
1581 self.assertEqual(len(roles_paths), 1,
1582 "Should have one roles_path line in %s" %
1583 (playbook,))
1584 self.assertIn(content, roles_paths[0])
1585 else:
1586 self.assertEqual(len(roles_paths), 0,
1587 "Should have no roles_path line in %s" %
1588 (playbook,))
1589
James E. Blairbb94dfa2017-07-11 07:45:19 -07001590
1591class TestRoles(RoleTestCase):
1592 tenant_config_file = 'config/roles/main.yaml'
1593
James E. Blairbce76932017-05-04 10:03:15 -07001594 def test_role(self):
1595 # This exercises a proposed change to a role being checked out
1596 # and used.
1597 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
1598 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1599 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
1600 B.subject, A.data['id'])
1601 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1602 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1603 self.waitUntilSettled()
1604 self.assertHistory([
1605 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
1606 ])
James E. Blair6459db12017-06-29 14:57:20 -07001607
James E. Blair1b27f6a2017-07-14 14:09:07 -07001608 def test_role_inheritance(self):
1609 self.executor_server.hold_jobs_in_build = True
1610 conf = textwrap.dedent(
1611 """
1612 - job:
1613 name: parent
1614 roles:
1615 - zuul: bare-role
1616 pre-run: playbooks/parent-pre
1617 post-run: playbooks/parent-post
1618
1619 - job:
1620 name: project-test
1621 parent: parent
1622 roles:
1623 - zuul: org/project
1624
1625 - project:
1626 name: org/project
1627 check:
1628 jobs:
1629 - project-test
1630 """)
1631
1632 file_dict = {'.zuul.yaml': conf}
1633 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1634 files=file_dict)
1635 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1636 self.waitUntilSettled()
1637
1638 self.assertEqual(len(self.builds), 1)
1639 build = self.getBuildByName('project-test')
1640 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
1641 self._assertRolePath(build, 'playbook_0', 'role_0')
1642 self._assertRolePath(build, 'playbook_0', 'role_1')
1643 self._assertRolePath(build, 'post_playbook_0', 'role_0')
1644
1645 self.executor_server.hold_jobs_in_build = False
1646 self.executor_server.release()
1647 self.waitUntilSettled()
1648
1649 self.assertHistory([
1650 dict(name='project-test', result='SUCCESS', changes='1,1'),
1651 ])
1652
James E. Blair6f699732017-07-18 14:19:11 -07001653 def test_role_error(self):
1654 conf = textwrap.dedent(
1655 """
1656 - job:
1657 name: project-test
1658 roles:
1659 - zuul: common-config
1660
1661 - project:
1662 name: org/project
1663 check:
1664 jobs:
1665 - project-test
1666 """)
1667
1668 file_dict = {'.zuul.yaml': conf}
1669 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1670 files=file_dict)
1671 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1672 self.waitUntilSettled()
1673 self.assertIn(
1674 '- project-test project-test : ERROR Unable to find role',
1675 A.messages[-1])
1676
James E. Blair6459db12017-06-29 14:57:20 -07001677
James E. Blairbb94dfa2017-07-11 07:45:19 -07001678class TestImplicitRoles(RoleTestCase):
1679 tenant_config_file = 'config/implicit-roles/main.yaml'
1680
1681 def test_missing_roles(self):
1682 # Test implicit and explicit roles for a project which does
1683 # not have roles. The implicit role should be silently
1684 # ignored since the project doesn't supply roles, but if a
1685 # user declares an explicit role, it should error.
1686 self.executor_server.hold_jobs_in_build = True
1687 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
1688 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1689 self.waitUntilSettled()
1690
1691 self.assertEqual(len(self.builds), 2)
1692 build = self.getBuildByName('implicit-role-fail')
1693 self._assertRolePath(build, 'playbook_0', None)
1694
1695 self.executor_server.hold_jobs_in_build = False
1696 self.executor_server.release()
1697 self.waitUntilSettled()
1698 # The retry_limit doesn't get recorded
1699 self.assertHistory([
1700 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
1701 ])
1702
1703 def test_roles(self):
1704 # Test implicit and explicit roles for a project which does
1705 # have roles. In both cases, we should end up with the role
1706 # in the path. In the explicit case, ensure we end up with
1707 # the name we specified.
1708 self.executor_server.hold_jobs_in_build = True
1709 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
1710 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1711 self.waitUntilSettled()
1712
1713 self.assertEqual(len(self.builds), 2)
1714 build = self.getBuildByName('implicit-role-ok')
1715 self._assertRolePath(build, 'playbook_0', 'role_0')
1716
1717 build = self.getBuildByName('explicit-role-ok')
1718 self._assertRolePath(build, 'playbook_0', 'role_0')
1719
1720 self.executor_server.hold_jobs_in_build = False
1721 self.executor_server.release()
1722 self.waitUntilSettled()
1723 self.assertHistory([
1724 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
1725 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
1726 ], ordered=False)
1727
1728
James E. Blair6459db12017-06-29 14:57:20 -07001729class TestShadow(ZuulTestCase):
1730 tenant_config_file = 'config/shadow/main.yaml'
1731
1732 def test_shadow(self):
1733 # Test that a repo is allowed to shadow another's job definitions.
1734 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1735 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1736 self.waitUntilSettled()
1737 self.assertHistory([
1738 dict(name='test1', result='SUCCESS', changes='1,1'),
1739 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -07001740 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -07001741
1742
1743class TestDataReturn(AnsibleZuulTestCase):
1744 tenant_config_file = 'config/data-return/main.yaml'
1745
1746 def test_data_return(self):
James E. Blair196f61a2017-06-30 15:42:29 -07001747 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1748 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1749 self.waitUntilSettled()
1750 self.assertHistory([
1751 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07001752 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
James E. Blair698703c2017-09-15 20:58:30 -06001753 dict(name='child', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -07001754 ], ordered=False)
1755 self.assertIn('- data-return http://example.com/test/log/url/',
1756 A.messages[-1])
1757 self.assertIn('- data-return-relative '
1758 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -07001759 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -07001760
1761
1762class TestDiskAccounting(AnsibleZuulTestCase):
1763 config_file = 'zuul-disk-accounting.conf'
1764 tenant_config_file = 'config/disk-accountant/main.yaml'
1765
1766 def test_disk_accountant_kills_job(self):
1767 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1768 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1769 self.waitUntilSettled()
1770 self.assertHistory([
1771 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001772
1773
1774class TestMaxNodesPerJob(AnsibleZuulTestCase):
1775 tenant_config_file = 'config/multi-tenant/main.yaml'
1776
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00001777 def test_max_timeout_exceeded(self):
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001778 in_repo_conf = textwrap.dedent(
1779 """
1780 - job:
1781 name: test-job
James E. Blair7e3e6882017-09-20 15:47:13 -07001782 nodeset:
1783 nodes:
1784 - name: node01
1785 label: fake
1786 - name: node02
1787 label: fake
1788 - name: node03
1789 label: fake
1790 - name: node04
1791 label: fake
1792 - name: node05
1793 label: fake
1794 - name: node06
1795 label: fake
Tristan Cacqueray82f864b2017-08-01 05:54:42 +00001796 """)
1797 file_dict = {'.zuul.yaml': in_repo_conf}
1798 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1799 files=file_dict)
1800 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1801 self.waitUntilSettled()
1802 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
1803 A.messages[0], "A should fail because of nodes limit")
1804
1805 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
1806 files=file_dict)
1807 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1808 self.waitUntilSettled()
1809 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
1810 "B should not fail because of nodes limit")
James E. Blair2bab6e72017-08-07 09:52:45 -07001811
1812
Tristan Cacquerayc98bff72017-09-10 15:25:26 +00001813class TestMaxTimeout(AnsibleZuulTestCase):
1814 tenant_config_file = 'config/multi-tenant/main.yaml'
1815
1816 def test_max_nodes_reached(self):
1817 in_repo_conf = textwrap.dedent(
1818 """
1819 - job:
1820 name: test-job
1821 timeout: 3600
1822 """)
1823 file_dict = {'.zuul.yaml': in_repo_conf}
1824 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
1825 files=file_dict)
1826 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1827 self.waitUntilSettled()
1828 self.assertIn('The job "test-job" exceeds tenant max-job-timeout',
1829 A.messages[0], "A should fail because of timeout limit")
1830
1831 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
1832 files=file_dict)
1833 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1834 self.waitUntilSettled()
1835 self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0],
1836 "B should not fail because of timeout limit")
1837
1838
James E. Blair2bab6e72017-08-07 09:52:45 -07001839class TestBaseJobs(ZuulTestCase):
1840 tenant_config_file = 'config/base-jobs/main.yaml'
1841
1842 def test_multiple_base_jobs(self):
1843 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1844 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1845 self.waitUntilSettled()
1846 self.assertHistory([
1847 dict(name='my-job', result='SUCCESS', changes='1,1'),
1848 dict(name='other-job', result='SUCCESS', changes='1,1'),
1849 ], ordered=False)
1850 self.assertEqual(self.getJobFromHistory('my-job').
1851 parameters['zuul']['jobtags'],
1852 ['mybase'])
1853 self.assertEqual(self.getJobFromHistory('other-job').
1854 parameters['zuul']['jobtags'],
1855 ['otherbase'])
1856
1857 def test_untrusted_base_job(self):
1858 """Test that a base job may not be defined in an untrusted repo"""
1859 in_repo_conf = textwrap.dedent(
1860 """
1861 - job:
1862 name: fail-base
1863 parent: null
1864 """)
1865
1866 file_dict = {'.zuul.yaml': in_repo_conf}
1867 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1868 files=file_dict)
1869 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1870 self.waitUntilSettled()
1871 self.assertEqual(A.reported, 1,
1872 "A should report failure")
1873 self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1")
1874 self.assertIn('Base jobs must be defined in config projects',
1875 A.messages[0])
1876 self.assertHistory([])
James E. Blairdb089032017-08-15 13:42:12 -07001877
1878
1879class TestSecretLeaks(AnsibleZuulTestCase):
1880 tenant_config_file = 'config/secret-leaks/main.yaml'
1881
1882 def searchForContent(self, path, content):
1883 matches = []
1884 for (dirpath, dirnames, filenames) in os.walk(path):
1885 for filename in filenames:
1886 filepath = os.path.join(dirpath, filename)
1887 with open(filepath, 'rb') as f:
1888 if content in f.read():
1889 matches.append(filepath[len(path):])
1890 return matches
1891
1892 def _test_secret_file(self):
1893 # Or rather -- test that they *don't* leak.
1894 # Keep the jobdir around so we can inspect contents.
1895 self.executor_server.keep_jobdir = True
1896 conf = textwrap.dedent(
1897 """
1898 - project:
1899 name: org/project
1900 check:
1901 jobs:
1902 - secret-file
1903 """)
1904
1905 file_dict = {'.zuul.yaml': conf}
1906 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1907 files=file_dict)
1908 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1909 self.waitUntilSettled()
1910 self.assertHistory([
1911 dict(name='secret-file', result='SUCCESS', changes='1,1'),
1912 ], ordered=False)
1913 matches = self.searchForContent(self.history[0].jobdir.root,
1914 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07001915 self.assertEqual(set(['/work/secret-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07001916 set(matches))
1917
1918 def test_secret_file(self):
1919 self._test_secret_file()
1920
1921 def test_secret_file_verbose(self):
1922 # Output extra ansible info to exercise alternate logging code
1923 # paths.
1924 self.executor_server.verbose = True
1925 self._test_secret_file()
1926
1927 def _test_secret_file_fail(self):
1928 # Or rather -- test that they *don't* leak.
1929 # Keep the jobdir around so we can inspect contents.
1930 self.executor_server.keep_jobdir = True
1931 conf = textwrap.dedent(
1932 """
1933 - project:
1934 name: org/project
1935 check:
1936 jobs:
1937 - secret-file-fail
1938 """)
1939
1940 file_dict = {'.zuul.yaml': conf}
1941 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
1942 files=file_dict)
1943 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1944 self.waitUntilSettled()
1945 self.assertHistory([
1946 dict(name='secret-file-fail', result='FAILURE', changes='1,1'),
1947 ], ordered=False)
1948 matches = self.searchForContent(self.history[0].jobdir.root,
1949 b'test-password')
James E. Blaird6a71ca2017-08-18 14:15:05 -07001950 self.assertEqual(set(['/work/failure-file.txt']),
James E. Blairdb089032017-08-15 13:42:12 -07001951 set(matches))
1952
1953 def test_secret_file_fail(self):
1954 self._test_secret_file_fail()
1955
1956 def test_secret_file_fail_verbose(self):
1957 # Output extra ansible info to exercise alternate logging code
1958 # paths.
1959 self.executor_server.verbose = True
1960 self._test_secret_file_fail()
James E. Blaira00910c2017-08-23 09:15:04 -07001961
1962
1963class TestJobOutput(AnsibleZuulTestCase):
1964 tenant_config_file = 'config/job-output/main.yaml'
1965
1966 def _get_file(self, build, path):
1967 p = os.path.join(build.jobdir.root, path)
1968 with open(p) as f:
1969 return f.read()
1970
1971 def test_job_output(self):
Monty Taylor0e2489a2017-10-10 11:57:29 -05001972 # Verify that command standard output appears in the job output,
1973 # and that failures in the final playbook get logged.
James E. Blaira00910c2017-08-23 09:15:04 -07001974
1975 # This currently only verifies we receive output from
1976 # localhost. Notably, it does not verify we receive output
1977 # via zuul_console streaming.
1978 self.executor_server.keep_jobdir = True
1979 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1980 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1981 self.waitUntilSettled()
1982 self.assertHistory([
1983 dict(name='job-output', result='SUCCESS', changes='1,1'),
1984 ], ordered=False)
1985
1986 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
1987 j = json.loads(self._get_file(self.history[0],
1988 'work/logs/job-output.json'))
1989 self.assertEqual(token,
1990 j[0]['plays'][0]['tasks'][0]
1991 ['hosts']['localhost']['stdout'])
1992
1993 print(self._get_file(self.history[0],
1994 'work/logs/job-output.txt'))
1995 self.assertIn(token,
1996 self._get_file(self.history[0],
1997 'work/logs/job-output.txt'))
Monty Taylor0e2489a2017-10-10 11:57:29 -05001998
1999 def test_job_output_failure_log(self):
2000 logger = logging.getLogger('zuul.AnsibleJob')
2001 output = io.StringIO()
2002 logger.addHandler(logging.StreamHandler(output))
2003
2004 # Verify that a failure in the last post playbook emits the contents
2005 # of the json output to the log
2006 self.executor_server.keep_jobdir = True
2007 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
2008 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2009 self.waitUntilSettled()
2010 self.assertHistory([
2011 dict(name='job-output-failure',
2012 result='POST_FAILURE', changes='1,1'),
2013 ], ordered=False)
2014
2015 token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
2016 j = json.loads(self._get_file(self.history[0],
2017 'work/logs/job-output.json'))
2018 self.assertEqual(token,
2019 j[0]['plays'][0]['tasks'][0]
2020 ['hosts']['localhost']['stdout'])
2021
2022 print(self._get_file(self.history[0],
2023 'work/logs/job-output.json'))
2024 self.assertIn(token,
2025 self._get_file(self.history[0],
2026 'work/logs/job-output.txt'))
2027
2028 log_output = output.getvalue()
2029 self.assertIn('Final playbook failed', log_output)
2030 self.assertIn('Failure test', log_output)