blob: aa091e58e94adc42ce8a14f17c60e7636da6611f [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
James E. Blaira92cbc82017-01-23 14:56:49 -080017import os
James E. Blair14abdf42015-12-09 16:11:53 -080018import textwrap
James E. Blair59fdbac2015-12-07 17:08:06 -080019
James E. Blairb9c0d772017-03-03 14:34:49 -080020import testtools
21
22import zuul.configloader
James E. Blairbf1a4f22017-03-17 10:59:37 -070023from zuul.lib import encryption
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +000024from tests.base import AnsibleZuulTestCase, ZuulTestCase, FIXTURE_DIR
James E. Blair59fdbac2015-12-07 17:08:06 -080025
James E. Blair59fdbac2015-12-07 17:08:06 -080026
James E. Blair3f876d52016-07-22 13:07:14 -070027class TestMultipleTenants(AnsibleZuulTestCase):
James E. Blair59fdbac2015-12-07 17:08:06 -080028 # A temporary class to hold new tests while others are disabled
29
James E. Blair2a629ec2015-12-22 15:32:02 -080030 tenant_config_file = 'config/multi-tenant/main.yaml'
James E. Blair59fdbac2015-12-07 17:08:06 -080031
James E. Blair83005782015-12-11 14:46:03 -080032 def test_multiple_tenants(self):
James E. Blair96f26942015-12-09 10:15:59 -080033 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +020034 A.addApproval('Code-Review', 2)
35 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair59fdbac2015-12-07 17:08:06 -080036 self.waitUntilSettled()
James E. Blair96f26942015-12-09 10:15:59 -080037 self.assertEqual(self.getJobFromHistory('project1-test1').result,
James E. Blair59fdbac2015-12-07 17:08:06 -080038 'SUCCESS')
James E. Blair96c6bf82016-01-15 16:20:40 -080039 self.assertEqual(self.getJobFromHistory('python27').result,
40 'SUCCESS')
James E. Blair59fdbac2015-12-07 17:08:06 -080041 self.assertEqual(A.data['status'], 'MERGED')
James E. Blair96f26942015-12-09 10:15:59 -080042 self.assertEqual(A.reported, 2,
43 "A should report start and success")
44 self.assertIn('tenant-one-gate', A.messages[1],
45 "A should transit tenant-one gate")
46 self.assertNotIn('tenant-two-gate', A.messages[1],
47 "A should *not* transit tenant-two gate")
James E. Blair59fdbac2015-12-07 17:08:06 -080048
James E. Blair96f26942015-12-09 10:15:59 -080049 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +020050 B.addApproval('Code-Review', 2)
51 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair96f26942015-12-09 10:15:59 -080052 self.waitUntilSettled()
James E. Blair96c6bf82016-01-15 16:20:40 -080053 self.assertEqual(self.getJobFromHistory('python27',
54 'org/project2').result,
55 'SUCCESS')
James E. Blair96f26942015-12-09 10:15:59 -080056 self.assertEqual(self.getJobFromHistory('project2-test1').result,
57 'SUCCESS')
58 self.assertEqual(B.data['status'], 'MERGED')
59 self.assertEqual(B.reported, 2,
60 "B should report start and success")
61 self.assertIn('tenant-two-gate', B.messages[1],
62 "B should transit tenant-two gate")
63 self.assertNotIn('tenant-one-gate', B.messages[1],
64 "B should *not* transit tenant-one gate")
James E. Blair59fdbac2015-12-07 17:08:06 -080065
James E. Blair96f26942015-12-09 10:15:59 -080066 self.assertEqual(A.reported, 2, "Activity in tenant two should"
67 "not affect tenant one")
James E. Blair14abdf42015-12-09 16:11:53 -080068
James E. Blair83005782015-12-11 14:46:03 -080069
James E. Blairff555742017-02-19 11:34:27 -080070class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -080071 # A temporary class to hold new tests while others are disabled
72
Tobias Henkelabf973e2017-07-28 10:07:34 +020073 config_file = 'zuul-connections-gerrit-and-github.conf'
James E. Blair2a629ec2015-12-22 15:32:02 -080074 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -080075
James E. Blair83005782015-12-11 14:46:03 -080076 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -080077 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
Tobias Henkelbf24fd12017-07-27 06:13:07 +020078 A.addApproval('Code-Review', 2)
79 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -080080 self.waitUntilSettled()
81 self.assertEqual(self.getJobFromHistory('project-test1').result,
82 'SUCCESS')
83 self.assertEqual(A.data['status'], 'MERGED')
84 self.assertEqual(A.reported, 2,
85 "A should report start and success")
86 self.assertIn('tenant-one-gate', A.messages[1],
87 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -080088
James E. Blair8b1dc3f2016-07-05 16:49:00 -070089 def test_dynamic_config(self):
90 in_repo_conf = textwrap.dedent(
91 """
92 - job:
93 name: project-test2
94
95 - project:
96 name: org/project
97 tenant-one-gate:
98 jobs:
99 - project-test2
100 """)
101
James E. Blairc73c73a2017-01-20 15:15:15 -0800102 in_repo_playbook = textwrap.dedent(
103 """
104 - hosts: all
105 tasks: []
106 """)
107
108 file_dict = {'.zuul.yaml': in_repo_conf,
109 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700110 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800111 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200112 A.addApproval('Code-Review', 2)
113 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700114 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700115 self.assertEqual(A.data['status'], 'MERGED')
116 self.assertEqual(A.reported, 2,
117 "A should report start and success")
118 self.assertIn('tenant-one-gate', A.messages[1],
119 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800120 self.assertHistory([
121 dict(name='project-test2', result='SUCCESS', changes='1,1')])
122
James E. Blairc2a5ed72017-02-20 14:12:01 -0500123 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800124 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500125
James E. Blair646322f2017-01-27 15:50:34 -0800126 # Now that the config change is landed, it should be live for
127 # subsequent changes.
128 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200129 B.addApproval('Code-Review', 2)
130 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair646322f2017-01-27 15:50:34 -0800131 self.waitUntilSettled()
132 self.assertEqual(self.getJobFromHistory('project-test2').result,
133 'SUCCESS')
134 self.assertHistory([
135 dict(name='project-test2', result='SUCCESS', changes='1,1'),
136 dict(name='project-test2', result='SUCCESS', changes='2,1')])
James E. Blairc73c73a2017-01-20 15:15:15 -0800137
Tobias Henkel0f714002017-06-30 23:30:52 +0200138 def test_dynamic_config_new_patchset(self):
139 self.executor_server.hold_jobs_in_build = True
140
141 tenant = self.sched.abide.tenants.get('tenant-one')
142 check_pipeline = tenant.layout.pipelines['check']
143
144 in_repo_conf = textwrap.dedent(
145 """
146 - job:
147 name: project-test2
148
149 - project:
150 name: org/project
151 check:
152 jobs:
153 - project-test2
154 """)
155
156 in_repo_playbook = textwrap.dedent(
157 """
158 - hosts: all
159 tasks: []
160 """)
161
162 file_dict = {'.zuul.yaml': in_repo_conf,
163 'playbooks/project-test2.yaml': in_repo_playbook}
164 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
165 files=file_dict)
166 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
167 self.waitUntilSettled()
168
169 items = check_pipeline.getAllItems()
170 self.assertEqual(items[0].change.number, '1')
171 self.assertEqual(items[0].change.patchset, '1')
172 self.assertTrue(items[0].live)
173
174 in_repo_conf = textwrap.dedent(
175 """
176 - job:
177 name: project-test2
178
179 - project:
180 name: org/project
181 check:
182 jobs:
183 - project-test1
184 - project-test2
185 """)
186 file_dict = {'.zuul.yaml': in_repo_conf,
187 'playbooks/project-test2.yaml': in_repo_playbook}
188
189 A.addPatchset(files=file_dict)
190 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
191
192 self.waitUntilSettled()
193
194 items = check_pipeline.getAllItems()
195 self.assertEqual(items[0].change.number, '1')
196 self.assertEqual(items[0].change.patchset, '2')
197 self.assertTrue(items[0].live)
198
199 self.executor_server.hold_jobs_in_build = False
200 self.executor_server.release()
201 self.waitUntilSettled()
202
Jesse Keating78f544a2017-07-13 14:27:40 -0700203 def test_dynamic_dependent_pipeline(self):
204 # Test dynamically adding a project to a
205 # dependent pipeline for the first time
206 self.executor_server.hold_jobs_in_build = True
207
208 tenant = self.sched.abide.tenants.get('tenant-one')
209 gate_pipeline = tenant.layout.pipelines['gate']
210
211 in_repo_conf = textwrap.dedent(
212 """
213 - job:
214 name: project-test2
215
216 - project:
217 name: org/project
218 gate:
219 jobs:
220 - project-test2
221 """)
222
223 in_repo_playbook = textwrap.dedent(
224 """
225 - hosts: all
226 tasks: []
227 """)
228
229 file_dict = {'.zuul.yaml': in_repo_conf,
230 'playbooks/project-test2.yaml': in_repo_playbook}
231 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
232 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200233 A.addApproval('Approved', 1)
234 self.fake_gerrit.addEvent(A.addApproval('Code-Review', 2))
Jesse Keating78f544a2017-07-13 14:27:40 -0700235 self.waitUntilSettled()
236
237 items = gate_pipeline.getAllItems()
238 self.assertEqual(items[0].change.number, '1')
239 self.assertEqual(items[0].change.patchset, '1')
240 self.assertTrue(items[0].live)
241
242 self.executor_server.hold_jobs_in_build = False
243 self.executor_server.release()
244 self.waitUntilSettled()
245
246 # Make sure the dynamic queue got cleaned up
247 self.assertEqual(gate_pipeline.queues, [])
248
James E. Blairff555742017-02-19 11:34:27 -0800249 def test_in_repo_branch(self):
250 in_repo_conf = textwrap.dedent(
251 """
252 - job:
253 name: project-test2
254
255 - project:
256 name: org/project
257 tenant-one-gate:
258 jobs:
259 - project-test2
260 """)
261
262 in_repo_playbook = textwrap.dedent(
263 """
264 - hosts: all
265 tasks: []
266 """)
267
268 file_dict = {'.zuul.yaml': in_repo_conf,
269 'playbooks/project-test2.yaml': in_repo_playbook}
270 self.create_branch('org/project', 'stable')
271 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
272 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200273 A.addApproval('Code-Review', 2)
274 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800275 self.waitUntilSettled()
276 self.assertEqual(A.data['status'], 'MERGED')
277 self.assertEqual(A.reported, 2,
278 "A should report start and success")
279 self.assertIn('tenant-one-gate', A.messages[1],
280 "A should transit tenant-one gate")
281 self.assertHistory([
282 dict(name='project-test2', result='SUCCESS', changes='1,1')])
283 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800284 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800285
286 # The config change should not affect master.
287 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200288 B.addApproval('Code-Review', 2)
289 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800290 self.waitUntilSettled()
291 self.assertHistory([
292 dict(name='project-test2', result='SUCCESS', changes='1,1'),
293 dict(name='project-test1', result='SUCCESS', changes='2,1')])
294
295 # The config change should be live for further changes on
296 # stable.
297 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200298 C.addApproval('Code-Review', 2)
299 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800300 self.waitUntilSettled()
301 self.assertHistory([
302 dict(name='project-test2', result='SUCCESS', changes='1,1'),
303 dict(name='project-test1', result='SUCCESS', changes='2,1'),
304 dict(name='project-test2', result='SUCCESS', changes='3,1')])
305
James E. Blaira5a12492017-05-03 11:40:48 -0700306 def test_crd_dynamic_config_branch(self):
307 # Test that we can create a job in one repo and be able to use
308 # it from a different branch on a different repo.
309
310 self.create_branch('org/project1', 'stable')
311
312 in_repo_conf = textwrap.dedent(
313 """
314 - job:
315 name: project-test2
316
317 - project:
318 name: org/project
319 check:
320 jobs:
321 - project-test2
322 """)
323
324 in_repo_playbook = textwrap.dedent(
325 """
326 - hosts: all
327 tasks: []
328 """)
329
330 file_dict = {'.zuul.yaml': in_repo_conf,
331 'playbooks/project-test2.yaml': in_repo_playbook}
332 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
333 files=file_dict)
334
335 second_repo_conf = textwrap.dedent(
336 """
337 - project:
338 name: org/project1
339 check:
340 jobs:
341 - project-test2
342 """)
343
344 second_file_dict = {'.zuul.yaml': second_repo_conf}
345 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
346 files=second_file_dict)
347 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
348 B.subject, A.data['id'])
349
350 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
351 self.waitUntilSettled()
352 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
353 self.waitUntilSettled()
354
355 self.assertEqual(A.reported, 1, "A should report")
356 self.assertHistory([
357 dict(name='project-test2', result='SUCCESS', changes='1,1'),
358 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
359 ])
360
James E. Blair149b69c2017-03-02 10:48:16 -0800361 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -0800362 in_repo_conf = textwrap.dedent(
363 """
364 - job:
365 name: project-test2
366 foo: error
367 """)
368
369 file_dict = {'.zuul.yaml': in_repo_conf}
370 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
371 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200372 A.addApproval('Code-Review', 2)
373 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -0800374 self.waitUntilSettled()
375
376 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200377 self.assertEqual(A.reported, 1,
378 "A should report failure")
379 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -0800380 "A should have a syntax error reported")
381
James E. Blair149b69c2017-03-02 10:48:16 -0800382 def test_trusted_syntax_error(self):
383 in_repo_conf = textwrap.dedent(
384 """
385 - job:
386 name: project-test2
387 foo: error
388 """)
389
390 file_dict = {'zuul.yaml': in_repo_conf}
391 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
392 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200393 A.addApproval('Code-Review', 2)
394 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -0800395 self.waitUntilSettled()
396
397 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200398 self.assertEqual(A.reported, 1,
399 "A should report failure")
400 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -0800401 "A should have a syntax error reported")
402
James E. Blair6f140c72017-03-03 10:32:07 -0800403 def test_untrusted_yaml_error(self):
404 in_repo_conf = textwrap.dedent(
405 """
406 - job:
407 foo: error
408 """)
409
410 file_dict = {'.zuul.yaml': in_repo_conf}
411 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
412 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200413 A.addApproval('Code-Review', 2)
414 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -0800415 self.waitUntilSettled()
416
417 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200418 self.assertEqual(A.reported, 1,
419 "A should report failure")
420 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -0800421 "A should have a syntax error reported")
422
James E. Blairdb04e6a2017-05-03 14:49:36 -0700423 def test_untrusted_shadow_error(self):
424 in_repo_conf = textwrap.dedent(
425 """
426 - job:
427 name: common-config-test
428 """)
429
430 file_dict = {'.zuul.yaml': in_repo_conf}
431 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
432 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200433 A.addApproval('Code-Review', 2)
434 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -0700435 self.waitUntilSettled()
436
437 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200438 self.assertEqual(A.reported, 1,
439 "A should report failure")
440 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -0700441 "A should have a syntax error reported")
442
James E. Blaird5656ad2017-06-02 14:29:41 -0700443 def test_untrusted_pipeline_error(self):
444 in_repo_conf = textwrap.dedent(
445 """
446 - pipeline:
447 name: test
448 """)
449
450 file_dict = {'.zuul.yaml': in_repo_conf}
451 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
452 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200453 A.addApproval('Code-Review', 2)
454 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700455 self.waitUntilSettled()
456
457 self.assertEqual(A.data['status'], 'NEW')
458 self.assertEqual(A.reported, 1,
459 "A should report failure")
460 self.assertIn('Pipelines may not be defined', A.messages[0],
461 "A should have a syntax error reported")
462
463 def test_untrusted_project_error(self):
464 in_repo_conf = textwrap.dedent(
465 """
466 - project:
467 name: org/project1
468 """)
469
470 file_dict = {'.zuul.yaml': in_repo_conf}
471 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
472 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200473 A.addApproval('Code-Review', 2)
474 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700475 self.waitUntilSettled()
476
477 self.assertEqual(A.data['status'], 'NEW')
478 self.assertEqual(A.reported, 1,
479 "A should report failure")
480 self.assertIn('the only project definition permitted', A.messages[0],
481 "A should have a syntax error reported")
482
James E. Blaire64b0e42017-06-08 11:23:34 -0700483 def test_duplicate_node_error(self):
484 in_repo_conf = textwrap.dedent(
485 """
486 - nodeset:
487 name: duplicate
488 nodes:
489 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700490 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700491 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700492 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700493 """)
494
495 file_dict = {'.zuul.yaml': in_repo_conf}
496 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
497 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200498 A.addApproval('Code-Review', 2)
499 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700500 self.waitUntilSettled()
501
502 self.assertEqual(A.data['status'], 'NEW')
503 self.assertEqual(A.reported, 1,
504 "A should report failure")
505 self.assertIn('appears multiple times', A.messages[0],
506 "A should have a syntax error reported")
507
508 def test_duplicate_group_error(self):
509 in_repo_conf = textwrap.dedent(
510 """
511 - nodeset:
512 name: duplicate
513 nodes:
514 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700515 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700516 groups:
517 - name: group
518 nodes: compute
519 - name: group
520 nodes: compute
521 """)
522
523 file_dict = {'.zuul.yaml': in_repo_conf}
524 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
525 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200526 A.addApproval('Code-Review', 2)
527 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700528 self.waitUntilSettled()
529
530 self.assertEqual(A.data['status'], 'NEW')
531 self.assertEqual(A.reported, 1,
532 "A should report failure")
533 self.assertIn('appears multiple times', A.messages[0],
534 "A should have a syntax error reported")
535
James E. Blair09f9ffe2017-07-11 15:30:25 -0700536 def test_multi_repo(self):
537 downstream_repo_conf = textwrap.dedent(
538 """
539 - project:
540 name: org/project1
541 tenant-one-gate:
542 jobs:
543 - project-test1
544
545 - job:
546 name: project1-test1
547 parent: project-test1
548 """)
549
550 file_dict = {'.zuul.yaml': downstream_repo_conf}
551 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
552 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200553 A.addApproval('Code-Review', 2)
554 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -0700555 self.waitUntilSettled()
556
557 self.assertEqual(A.data['status'], 'MERGED')
558 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
559 self.waitUntilSettled()
560
561 upstream_repo_conf = textwrap.dedent(
562 """
563 - job:
564 name: project-test1
565
566 - job:
567 name: project-test2
568
569 - project:
570 name: org/project
571 tenant-one-gate:
572 jobs:
573 - project-test1
574 """)
575
576 file_dict = {'.zuul.yaml': upstream_repo_conf}
577 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
578 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200579 B.addApproval('Code-Review', 2)
580 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -0700581 self.waitUntilSettled()
582
583 self.assertEqual(B.data['status'], 'MERGED')
584 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
585 self.waitUntilSettled()
586
587 tenant = self.sched.abide.tenants.get('tenant-one')
588 # Ensure the latest change is reflected in the config; if it
589 # isn't this will raise an exception.
590 tenant.layout.getJob('project-test2')
591
James E. Blairc73c73a2017-01-20 15:15:15 -0800592
593class TestAnsible(AnsibleZuulTestCase):
594 # A temporary class to hold new tests while others are disabled
595
596 tenant_config_file = 'config/ansible/main.yaml'
597
598 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +1100599 # Keep the jobdir around so we can inspect contents if an
600 # assert fails.
601 self.executor_server.keep_jobdir = True
602 # Output extra ansible info so we might see errors.
603 self.executor_server.verbose = True
604 # Add a site variables file, used by check-vars
605 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
606 'variables.yaml')
607 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -0800608 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
609 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
610 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +0200611 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +1100612 with self.jobLog(build_timeout):
613 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +0200614 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +1100615 with self.jobLog(build_faillocal):
616 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +0200617 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +1100618 with self.jobLog(build_failpost):
619 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +0200620 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +1100621 with self.jobLog(build_check_vars):
622 self.assertEqual(build_check_vars.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +0200623 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +1100624 with self.jobLog(build_hello):
625 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +0200626 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +1100627 with self.jobLog(build_python27):
628 self.assertEqual(build_python27.result, 'SUCCESS')
629 flag_path = os.path.join(self.test_root,
630 build_python27.uuid + '.flag')
631 self.assertTrue(os.path.exists(flag_path))
632 copied_path = os.path.join(self.test_root, build_python27.uuid +
633 '.copied')
634 self.assertTrue(os.path.exists(copied_path))
635 failed_path = os.path.join(self.test_root, build_python27.uuid +
636 '.failed')
637 self.assertFalse(os.path.exists(failed_path))
638 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
639 '.pre.flag')
640 self.assertTrue(os.path.exists(pre_flag_path))
641 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
642 '.post.flag')
643 self.assertTrue(os.path.exists(post_flag_path))
644 bare_role_flag_path = os.path.join(self.test_root,
645 build_python27.uuid +
646 '.bare-role.flag')
647 self.assertTrue(os.path.exists(bare_role_flag_path))
648 secrets_path = os.path.join(self.test_root,
649 build_python27.uuid + '.secrets')
650 with open(secrets_path) as f:
651 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -0800652
Jamie Lennox7655b552017-03-17 12:33:38 +1100653 msg = A.messages[0]
654 success = "{} https://success.example.com/zuul-logs/{}"
655 fail = "{} https://failure.example.com/zuul-logs/{}"
656 self.assertIn(success.format("python27", build_python27.uuid), msg)
657 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
658 self.assertIn(success.format("check-vars",
659 build_check_vars.uuid), msg)
660 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
661 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
662 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +0200663
James E. Blairb9c0d772017-03-03 14:34:49 -0800664
James E. Blaira4d4eef2017-06-30 14:49:17 -0700665class TestPrePlaybooks(AnsibleZuulTestCase):
666 # A temporary class to hold new tests while others are disabled
667
668 tenant_config_file = 'config/pre-playbook/main.yaml'
669
670 def test_pre_playbook_fail(self):
671 # Test that we run the post playbooks (but not the actual
672 # playbook) when a pre-playbook fails.
673 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
674 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
675 self.waitUntilSettled()
676 build = self.getJobFromHistory('python27')
677 self.assertIsNone(build.result)
678 self.assertIn('RETRY_LIMIT', A.messages[0])
679 flag_path = os.path.join(self.test_root, build.uuid +
680 '.main.flag')
681 self.assertFalse(os.path.exists(flag_path))
682 pre_flag_path = os.path.join(self.test_root, build.uuid +
683 '.pre.flag')
684 self.assertFalse(os.path.exists(pre_flag_path))
685 post_flag_path = os.path.join(self.test_root, build.uuid +
686 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -0700687 self.assertTrue(os.path.exists(post_flag_path),
688 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -0700689
690
James E. Blairb9c0d772017-03-03 14:34:49 -0800691class TestBrokenConfig(ZuulTestCase):
692 # Test that we get an appropriate syntax error if we start with a
693 # broken config.
694
695 tenant_config_file = 'config/broken/main.yaml'
696
697 def setUp(self):
698 with testtools.ExpectedException(
699 zuul.configloader.ConfigurationSyntaxError,
700 "\nZuul encountered a syntax error"):
701 super(TestBrokenConfig, self).setUp()
702
703 def test_broken_config_on_startup(self):
704 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +0000705
706
707class TestProjectKeys(ZuulTestCase):
708 # Test that we can generate project keys
709
710 # Normally the test infrastructure copies a static key in place
711 # for each project before starting tests. This saves time because
712 # Zuul's automatic key-generation on startup can be slow. To make
713 # sure we exercise that code, in this test we allow Zuul to create
714 # keys for the project on startup.
715 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +0200716 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +0000717 tenant_config_file = 'config/in-repo/main.yaml'
718
719 def test_key_generation(self):
720 key_root = os.path.join(self.state_root, 'keys')
721 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
722 # Make sure that a proper key was created on startup
723 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -0700724 private_key, public_key = \
725 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +0000726
727 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
728 fixture_private_key = i.read()
729
730 # Make sure that we didn't just end up with the static fixture
731 # key
732 self.assertNotEqual(fixture_private_key, private_key)
733
734 # Make sure it's the right length
735 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -0700736
737
James E. Blairbb94dfa2017-07-11 07:45:19 -0700738class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -0700739 def _assertRolePath(self, build, playbook, content):
740 path = os.path.join(self.test_root, build.uuid,
741 'ansible', playbook, 'ansible.cfg')
742 roles_paths = []
743 with open(path) as f:
744 for line in f:
745 if line.startswith('roles_path'):
746 roles_paths.append(line)
747 print(roles_paths)
748 if content:
749 self.assertEqual(len(roles_paths), 1,
750 "Should have one roles_path line in %s" %
751 (playbook,))
752 self.assertIn(content, roles_paths[0])
753 else:
754 self.assertEqual(len(roles_paths), 0,
755 "Should have no roles_path line in %s" %
756 (playbook,))
757
James E. Blairbb94dfa2017-07-11 07:45:19 -0700758
759class TestRoles(RoleTestCase):
760 tenant_config_file = 'config/roles/main.yaml'
761
James E. Blairbce76932017-05-04 10:03:15 -0700762 def test_role(self):
763 # This exercises a proposed change to a role being checked out
764 # and used.
765 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
766 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
767 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
768 B.subject, A.data['id'])
769 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
770 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
771 self.waitUntilSettled()
772 self.assertHistory([
773 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
774 ])
James E. Blair6459db12017-06-29 14:57:20 -0700775
James E. Blair1b27f6a2017-07-14 14:09:07 -0700776 def test_role_inheritance(self):
777 self.executor_server.hold_jobs_in_build = True
778 conf = textwrap.dedent(
779 """
780 - job:
781 name: parent
782 roles:
783 - zuul: bare-role
784 pre-run: playbooks/parent-pre
785 post-run: playbooks/parent-post
786
787 - job:
788 name: project-test
789 parent: parent
790 roles:
791 - zuul: org/project
792
793 - project:
794 name: org/project
795 check:
796 jobs:
797 - project-test
798 """)
799
800 file_dict = {'.zuul.yaml': conf}
801 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
802 files=file_dict)
803 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
804 self.waitUntilSettled()
805
806 self.assertEqual(len(self.builds), 1)
807 build = self.getBuildByName('project-test')
808 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
809 self._assertRolePath(build, 'playbook_0', 'role_0')
810 self._assertRolePath(build, 'playbook_0', 'role_1')
811 self._assertRolePath(build, 'post_playbook_0', 'role_0')
812
813 self.executor_server.hold_jobs_in_build = False
814 self.executor_server.release()
815 self.waitUntilSettled()
816
817 self.assertHistory([
818 dict(name='project-test', result='SUCCESS', changes='1,1'),
819 ])
820
James E. Blair6f699732017-07-18 14:19:11 -0700821 def test_role_error(self):
822 conf = textwrap.dedent(
823 """
824 - job:
825 name: project-test
826 roles:
827 - zuul: common-config
828
829 - project:
830 name: org/project
831 check:
832 jobs:
833 - project-test
834 """)
835
836 file_dict = {'.zuul.yaml': conf}
837 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
838 files=file_dict)
839 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
840 self.waitUntilSettled()
841 self.assertIn(
842 '- project-test project-test : ERROR Unable to find role',
843 A.messages[-1])
844
James E. Blair6459db12017-06-29 14:57:20 -0700845
James E. Blairbb94dfa2017-07-11 07:45:19 -0700846class TestImplicitRoles(RoleTestCase):
847 tenant_config_file = 'config/implicit-roles/main.yaml'
848
849 def test_missing_roles(self):
850 # Test implicit and explicit roles for a project which does
851 # not have roles. The implicit role should be silently
852 # ignored since the project doesn't supply roles, but if a
853 # user declares an explicit role, it should error.
854 self.executor_server.hold_jobs_in_build = True
855 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
856 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
857 self.waitUntilSettled()
858
859 self.assertEqual(len(self.builds), 2)
860 build = self.getBuildByName('implicit-role-fail')
861 self._assertRolePath(build, 'playbook_0', None)
862
863 self.executor_server.hold_jobs_in_build = False
864 self.executor_server.release()
865 self.waitUntilSettled()
866 # The retry_limit doesn't get recorded
867 self.assertHistory([
868 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
869 ])
870
871 def test_roles(self):
872 # Test implicit and explicit roles for a project which does
873 # have roles. In both cases, we should end up with the role
874 # in the path. In the explicit case, ensure we end up with
875 # the name we specified.
876 self.executor_server.hold_jobs_in_build = True
877 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
878 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
879 self.waitUntilSettled()
880
881 self.assertEqual(len(self.builds), 2)
882 build = self.getBuildByName('implicit-role-ok')
883 self._assertRolePath(build, 'playbook_0', 'role_0')
884
885 build = self.getBuildByName('explicit-role-ok')
886 self._assertRolePath(build, 'playbook_0', 'role_0')
887
888 self.executor_server.hold_jobs_in_build = False
889 self.executor_server.release()
890 self.waitUntilSettled()
891 self.assertHistory([
892 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
893 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
894 ], ordered=False)
895
896
James E. Blair6459db12017-06-29 14:57:20 -0700897class TestShadow(ZuulTestCase):
898 tenant_config_file = 'config/shadow/main.yaml'
899
900 def test_shadow(self):
901 # Test that a repo is allowed to shadow another's job definitions.
902 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
903 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
904 self.waitUntilSettled()
905 self.assertHistory([
906 dict(name='test1', result='SUCCESS', changes='1,1'),
907 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -0700908 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -0700909
910
911class TestDataReturn(AnsibleZuulTestCase):
912 tenant_config_file = 'config/data-return/main.yaml'
913
914 def test_data_return(self):
915 # This exercises a proposed change to a role being checked out
916 # and used.
917 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
918 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
919 self.waitUntilSettled()
920 self.assertHistory([
921 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -0700922 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
923 ], ordered=False)
924 self.assertIn('- data-return http://example.com/test/log/url/',
925 A.messages[-1])
926 self.assertIn('- data-return-relative '
927 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -0700928 A.messages[-1])