blob: 44cd5f6e8116d4d5d5f574965fdfc5087ce81bee [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:
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200177 name: project-test1
178
179 - job:
Tobias Henkel0f714002017-06-30 23:30:52 +0200180 name: project-test2
181
182 - project:
183 name: org/project
184 check:
185 jobs:
186 - project-test1
187 - project-test2
188 """)
189 file_dict = {'.zuul.yaml': in_repo_conf,
190 'playbooks/project-test2.yaml': in_repo_playbook}
191
192 A.addPatchset(files=file_dict)
193 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
194
195 self.waitUntilSettled()
196
197 items = check_pipeline.getAllItems()
198 self.assertEqual(items[0].change.number, '1')
199 self.assertEqual(items[0].change.patchset, '2')
200 self.assertTrue(items[0].live)
201
202 self.executor_server.hold_jobs_in_build = False
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200203 self.executor_server.release('project-test1')
204 self.waitUntilSettled()
Tobias Henkel0f714002017-06-30 23:30:52 +0200205 self.executor_server.release()
206 self.waitUntilSettled()
207
Tobias Henkel0ce7ec62017-07-21 22:50:17 +0200208 self.assertHistory([
209 dict(name='project-test2', result='ABORTED', changes='1,1'),
210 dict(name='project-test1', result='SUCCESS', changes='1,2'),
211 dict(name='project-test2', result='SUCCESS', changes='1,2')])
212
Jesse Keating78f544a2017-07-13 14:27:40 -0700213 def test_dynamic_dependent_pipeline(self):
214 # Test dynamically adding a project to a
215 # dependent pipeline for the first time
216 self.executor_server.hold_jobs_in_build = True
217
218 tenant = self.sched.abide.tenants.get('tenant-one')
219 gate_pipeline = tenant.layout.pipelines['gate']
220
221 in_repo_conf = textwrap.dedent(
222 """
223 - job:
224 name: project-test2
225
226 - project:
227 name: org/project
228 gate:
229 jobs:
230 - project-test2
231 """)
232
233 in_repo_playbook = textwrap.dedent(
234 """
235 - hosts: all
236 tasks: []
237 """)
238
239 file_dict = {'.zuul.yaml': in_repo_conf,
240 'playbooks/project-test2.yaml': in_repo_playbook}
241 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
242 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200243 A.addApproval('Approved', 1)
244 self.fake_gerrit.addEvent(A.addApproval('Code-Review', 2))
Jesse Keating78f544a2017-07-13 14:27:40 -0700245 self.waitUntilSettled()
246
247 items = gate_pipeline.getAllItems()
248 self.assertEqual(items[0].change.number, '1')
249 self.assertEqual(items[0].change.patchset, '1')
250 self.assertTrue(items[0].live)
251
252 self.executor_server.hold_jobs_in_build = False
253 self.executor_server.release()
254 self.waitUntilSettled()
255
256 # Make sure the dynamic queue got cleaned up
257 self.assertEqual(gate_pipeline.queues, [])
258
James E. Blairff555742017-02-19 11:34:27 -0800259 def test_in_repo_branch(self):
260 in_repo_conf = textwrap.dedent(
261 """
262 - job:
263 name: project-test2
264
265 - project:
266 name: org/project
267 tenant-one-gate:
268 jobs:
269 - project-test2
270 """)
271
272 in_repo_playbook = textwrap.dedent(
273 """
274 - hosts: all
275 tasks: []
276 """)
277
278 file_dict = {'.zuul.yaml': in_repo_conf,
279 'playbooks/project-test2.yaml': in_repo_playbook}
280 self.create_branch('org/project', 'stable')
281 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
282 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200283 A.addApproval('Code-Review', 2)
284 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800285 self.waitUntilSettled()
286 self.assertEqual(A.data['status'], 'MERGED')
287 self.assertEqual(A.reported, 2,
288 "A should report start and success")
289 self.assertIn('tenant-one-gate', A.messages[1],
290 "A should transit tenant-one gate")
291 self.assertHistory([
292 dict(name='project-test2', result='SUCCESS', changes='1,1')])
293 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800294 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800295
296 # The config change should not affect master.
297 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200298 B.addApproval('Code-Review', 2)
299 self.fake_gerrit.addEvent(B.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
305 # The config change should be live for further changes on
306 # stable.
307 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200308 C.addApproval('Code-Review', 2)
309 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blairff555742017-02-19 11:34:27 -0800310 self.waitUntilSettled()
311 self.assertHistory([
312 dict(name='project-test2', result='SUCCESS', changes='1,1'),
313 dict(name='project-test1', result='SUCCESS', changes='2,1'),
314 dict(name='project-test2', result='SUCCESS', changes='3,1')])
315
James E. Blaira5a12492017-05-03 11:40:48 -0700316 def test_crd_dynamic_config_branch(self):
317 # Test that we can create a job in one repo and be able to use
318 # it from a different branch on a different repo.
319
320 self.create_branch('org/project1', 'stable')
321
322 in_repo_conf = textwrap.dedent(
323 """
324 - job:
325 name: project-test2
326
327 - project:
328 name: org/project
329 check:
330 jobs:
331 - project-test2
332 """)
333
334 in_repo_playbook = textwrap.dedent(
335 """
336 - hosts: all
337 tasks: []
338 """)
339
340 file_dict = {'.zuul.yaml': in_repo_conf,
341 'playbooks/project-test2.yaml': in_repo_playbook}
342 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
343 files=file_dict)
344
345 second_repo_conf = textwrap.dedent(
346 """
347 - project:
348 name: org/project1
349 check:
350 jobs:
351 - project-test2
352 """)
353
354 second_file_dict = {'.zuul.yaml': second_repo_conf}
355 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
356 files=second_file_dict)
357 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
358 B.subject, A.data['id'])
359
360 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
361 self.waitUntilSettled()
362 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
363 self.waitUntilSettled()
364
365 self.assertEqual(A.reported, 1, "A should report")
366 self.assertHistory([
367 dict(name='project-test2', result='SUCCESS', changes='1,1'),
368 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
369 ])
370
James E. Blair149b69c2017-03-02 10:48:16 -0800371 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -0800372 in_repo_conf = textwrap.dedent(
373 """
374 - job:
375 name: project-test2
376 foo: error
377 """)
378
379 file_dict = {'.zuul.yaml': in_repo_conf}
380 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
381 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200382 A.addApproval('Code-Review', 2)
383 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire53250c2017-03-01 14:34:36 -0800384 self.waitUntilSettled()
385
386 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200387 self.assertEqual(A.reported, 1,
388 "A should report failure")
389 self.assertIn('syntax error', A.messages[0],
James E. Blaire53250c2017-03-01 14:34:36 -0800390 "A should have a syntax error reported")
391
James E. Blair149b69c2017-03-02 10:48:16 -0800392 def test_trusted_syntax_error(self):
393 in_repo_conf = textwrap.dedent(
394 """
395 - job:
396 name: project-test2
397 foo: error
398 """)
399
400 file_dict = {'zuul.yaml': in_repo_conf}
401 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
402 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200403 A.addApproval('Code-Review', 2)
404 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair149b69c2017-03-02 10:48:16 -0800405 self.waitUntilSettled()
406
407 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200408 self.assertEqual(A.reported, 1,
409 "A should report failure")
410 self.assertIn('syntax error', A.messages[0],
James E. Blair149b69c2017-03-02 10:48:16 -0800411 "A should have a syntax error reported")
412
James E. Blair6f140c72017-03-03 10:32:07 -0800413 def test_untrusted_yaml_error(self):
414 in_repo_conf = textwrap.dedent(
415 """
416 - job:
417 foo: error
418 """)
419
420 file_dict = {'.zuul.yaml': in_repo_conf}
421 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
422 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200423 A.addApproval('Code-Review', 2)
424 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair6f140c72017-03-03 10:32:07 -0800425 self.waitUntilSettled()
426
427 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200428 self.assertEqual(A.reported, 1,
429 "A should report failure")
430 self.assertIn('syntax error', A.messages[0],
James E. Blair6f140c72017-03-03 10:32:07 -0800431 "A should have a syntax error reported")
432
James E. Blairdb04e6a2017-05-03 14:49:36 -0700433 def test_untrusted_shadow_error(self):
434 in_repo_conf = textwrap.dedent(
435 """
436 - job:
437 name: common-config-test
438 """)
439
440 file_dict = {'.zuul.yaml': in_repo_conf}
441 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
442 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200443 A.addApproval('Code-Review', 2)
444 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blairdb04e6a2017-05-03 14:49:36 -0700445 self.waitUntilSettled()
446
447 self.assertEqual(A.data['status'], 'NEW')
Tobias Henkel9842bd72017-05-16 13:40:03 +0200448 self.assertEqual(A.reported, 1,
449 "A should report failure")
450 self.assertIn('not permitted to shadow', A.messages[0],
James E. Blairdb04e6a2017-05-03 14:49:36 -0700451 "A should have a syntax error reported")
452
James E. Blaird5656ad2017-06-02 14:29:41 -0700453 def test_untrusted_pipeline_error(self):
454 in_repo_conf = textwrap.dedent(
455 """
456 - pipeline:
457 name: test
458 """)
459
460 file_dict = {'.zuul.yaml': in_repo_conf}
461 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
462 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200463 A.addApproval('Code-Review', 2)
464 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700465 self.waitUntilSettled()
466
467 self.assertEqual(A.data['status'], 'NEW')
468 self.assertEqual(A.reported, 1,
469 "A should report failure")
470 self.assertIn('Pipelines may not be defined', A.messages[0],
471 "A should have a syntax error reported")
472
473 def test_untrusted_project_error(self):
474 in_repo_conf = textwrap.dedent(
475 """
476 - project:
477 name: org/project1
478 """)
479
480 file_dict = {'.zuul.yaml': in_repo_conf}
481 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
482 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200483 A.addApproval('Code-Review', 2)
484 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaird5656ad2017-06-02 14:29:41 -0700485 self.waitUntilSettled()
486
487 self.assertEqual(A.data['status'], 'NEW')
488 self.assertEqual(A.reported, 1,
489 "A should report failure")
490 self.assertIn('the only project definition permitted', A.messages[0],
491 "A should have a syntax error reported")
492
James E. Blaire64b0e42017-06-08 11:23:34 -0700493 def test_duplicate_node_error(self):
494 in_repo_conf = textwrap.dedent(
495 """
496 - nodeset:
497 name: duplicate
498 nodes:
499 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700500 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700501 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700502 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700503 """)
504
505 file_dict = {'.zuul.yaml': in_repo_conf}
506 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
507 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200508 A.addApproval('Code-Review', 2)
509 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700510 self.waitUntilSettled()
511
512 self.assertEqual(A.data['status'], 'NEW')
513 self.assertEqual(A.reported, 1,
514 "A should report failure")
515 self.assertIn('appears multiple times', A.messages[0],
516 "A should have a syntax error reported")
517
518 def test_duplicate_group_error(self):
519 in_repo_conf = textwrap.dedent(
520 """
521 - nodeset:
522 name: duplicate
523 nodes:
524 - name: compute
James E. Blair16d96a02017-06-08 11:32:56 -0700525 label: foo
James E. Blaire64b0e42017-06-08 11:23:34 -0700526 groups:
527 - name: group
528 nodes: compute
529 - name: group
530 nodes: compute
531 """)
532
533 file_dict = {'.zuul.yaml': in_repo_conf}
534 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
535 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200536 A.addApproval('Code-Review', 2)
537 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blaire64b0e42017-06-08 11:23:34 -0700538 self.waitUntilSettled()
539
540 self.assertEqual(A.data['status'], 'NEW')
541 self.assertEqual(A.reported, 1,
542 "A should report failure")
543 self.assertIn('appears multiple times', A.messages[0],
544 "A should have a syntax error reported")
545
James E. Blair09f9ffe2017-07-11 15:30:25 -0700546 def test_multi_repo(self):
547 downstream_repo_conf = textwrap.dedent(
548 """
549 - project:
550 name: org/project1
551 tenant-one-gate:
552 jobs:
553 - project-test1
554
555 - job:
556 name: project1-test1
557 parent: project-test1
558 """)
559
560 file_dict = {'.zuul.yaml': downstream_repo_conf}
561 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
562 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200563 A.addApproval('Code-Review', 2)
564 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -0700565 self.waitUntilSettled()
566
567 self.assertEqual(A.data['status'], 'MERGED')
568 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
569 self.waitUntilSettled()
570
571 upstream_repo_conf = textwrap.dedent(
572 """
573 - job:
574 name: project-test1
575
576 - job:
577 name: project-test2
578
579 - project:
580 name: org/project
581 tenant-one-gate:
582 jobs:
583 - project-test1
584 """)
585
586 file_dict = {'.zuul.yaml': upstream_repo_conf}
587 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B',
588 files=file_dict)
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200589 B.addApproval('Code-Review', 2)
590 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
James E. Blair09f9ffe2017-07-11 15:30:25 -0700591 self.waitUntilSettled()
592
593 self.assertEqual(B.data['status'], 'MERGED')
594 self.fake_gerrit.addEvent(B.getChangeMergedEvent())
595 self.waitUntilSettled()
596
597 tenant = self.sched.abide.tenants.get('tenant-one')
598 # Ensure the latest change is reflected in the config; if it
599 # isn't this will raise an exception.
600 tenant.layout.getJob('project-test2')
601
James E. Blairc73c73a2017-01-20 15:15:15 -0800602
603class TestAnsible(AnsibleZuulTestCase):
604 # A temporary class to hold new tests while others are disabled
605
606 tenant_config_file = 'config/ansible/main.yaml'
607
608 def test_playbook(self):
Jamie Lennox7655b552017-03-17 12:33:38 +1100609 # Keep the jobdir around so we can inspect contents if an
610 # assert fails.
611 self.executor_server.keep_jobdir = True
612 # Output extra ansible info so we might see errors.
613 self.executor_server.verbose = True
614 # Add a site variables file, used by check-vars
615 path = os.path.join(FIXTURE_DIR, 'config', 'ansible',
616 'variables.yaml')
617 self.config.set('executor', 'variables', path)
James E. Blairc73c73a2017-01-20 15:15:15 -0800618 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
619 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
620 self.waitUntilSettled()
Tobias Henkel077f2f32017-05-30 20:16:46 +0200621 build_timeout = self.getJobFromHistory('timeout')
Jamie Lennox7655b552017-03-17 12:33:38 +1100622 with self.jobLog(build_timeout):
623 self.assertEqual(build_timeout.result, 'TIMED_OUT')
Tobias Henkel077f2f32017-05-30 20:16:46 +0200624 build_faillocal = self.getJobFromHistory('faillocal')
Jamie Lennox7655b552017-03-17 12:33:38 +1100625 with self.jobLog(build_faillocal):
626 self.assertEqual(build_faillocal.result, 'FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +0200627 build_failpost = self.getJobFromHistory('failpost')
Jamie Lennox7655b552017-03-17 12:33:38 +1100628 with self.jobLog(build_failpost):
629 self.assertEqual(build_failpost.result, 'POST_FAILURE')
Tobias Henkel077f2f32017-05-30 20:16:46 +0200630 build_check_vars = self.getJobFromHistory('check-vars')
Jamie Lennox7655b552017-03-17 12:33:38 +1100631 with self.jobLog(build_check_vars):
632 self.assertEqual(build_check_vars.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +0200633 build_hello = self.getJobFromHistory('hello-world')
Jamie Lennox7655b552017-03-17 12:33:38 +1100634 with self.jobLog(build_hello):
635 self.assertEqual(build_hello.result, 'SUCCESS')
Tobias Henkel077f2f32017-05-30 20:16:46 +0200636 build_python27 = self.getJobFromHistory('python27')
Jamie Lennox7655b552017-03-17 12:33:38 +1100637 with self.jobLog(build_python27):
638 self.assertEqual(build_python27.result, 'SUCCESS')
639 flag_path = os.path.join(self.test_root,
640 build_python27.uuid + '.flag')
641 self.assertTrue(os.path.exists(flag_path))
642 copied_path = os.path.join(self.test_root, build_python27.uuid +
643 '.copied')
644 self.assertTrue(os.path.exists(copied_path))
645 failed_path = os.path.join(self.test_root, build_python27.uuid +
646 '.failed')
647 self.assertFalse(os.path.exists(failed_path))
648 pre_flag_path = os.path.join(self.test_root, build_python27.uuid +
649 '.pre.flag')
650 self.assertTrue(os.path.exists(pre_flag_path))
651 post_flag_path = os.path.join(self.test_root, build_python27.uuid +
652 '.post.flag')
653 self.assertTrue(os.path.exists(post_flag_path))
654 bare_role_flag_path = os.path.join(self.test_root,
655 build_python27.uuid +
656 '.bare-role.flag')
657 self.assertTrue(os.path.exists(bare_role_flag_path))
658 secrets_path = os.path.join(self.test_root,
659 build_python27.uuid + '.secrets')
660 with open(secrets_path) as f:
661 self.assertEqual(f.read(), "test-username test-password")
James E. Blairb9c0d772017-03-03 14:34:49 -0800662
Jamie Lennox7655b552017-03-17 12:33:38 +1100663 msg = A.messages[0]
664 success = "{} https://success.example.com/zuul-logs/{}"
665 fail = "{} https://failure.example.com/zuul-logs/{}"
666 self.assertIn(success.format("python27", build_python27.uuid), msg)
667 self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg)
668 self.assertIn(success.format("check-vars",
669 build_check_vars.uuid), msg)
670 self.assertIn(success.format("hello-world", build_hello.uuid), msg)
671 self.assertIn(fail.format("timeout", build_timeout.uuid), msg)
672 self.assertIn(fail.format("failpost", build_failpost.uuid), msg)
Tobias Henkel077f2f32017-05-30 20:16:46 +0200673
James E. Blairb9c0d772017-03-03 14:34:49 -0800674
James E. Blaira4d4eef2017-06-30 14:49:17 -0700675class TestPrePlaybooks(AnsibleZuulTestCase):
676 # A temporary class to hold new tests while others are disabled
677
678 tenant_config_file = 'config/pre-playbook/main.yaml'
679
680 def test_pre_playbook_fail(self):
681 # Test that we run the post playbooks (but not the actual
682 # playbook) when a pre-playbook fails.
683 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
684 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
685 self.waitUntilSettled()
686 build = self.getJobFromHistory('python27')
687 self.assertIsNone(build.result)
688 self.assertIn('RETRY_LIMIT', A.messages[0])
689 flag_path = os.path.join(self.test_root, build.uuid +
690 '.main.flag')
691 self.assertFalse(os.path.exists(flag_path))
692 pre_flag_path = os.path.join(self.test_root, build.uuid +
693 '.pre.flag')
694 self.assertFalse(os.path.exists(pre_flag_path))
695 post_flag_path = os.path.join(self.test_root, build.uuid +
696 '.post.flag')
James E. Blair21037782017-07-19 11:56:55 -0700697 self.assertTrue(os.path.exists(post_flag_path),
698 "The file %s should exist" % post_flag_path)
James E. Blaira4d4eef2017-06-30 14:49:17 -0700699
700
James E. Blairb9c0d772017-03-03 14:34:49 -0800701class TestBrokenConfig(ZuulTestCase):
702 # Test that we get an appropriate syntax error if we start with a
703 # broken config.
704
705 tenant_config_file = 'config/broken/main.yaml'
706
707 def setUp(self):
708 with testtools.ExpectedException(
709 zuul.configloader.ConfigurationSyntaxError,
710 "\nZuul encountered a syntax error"):
711 super(TestBrokenConfig, self).setUp()
712
713 def test_broken_config_on_startup(self):
714 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +0000715
716
717class TestProjectKeys(ZuulTestCase):
718 # Test that we can generate project keys
719
720 # Normally the test infrastructure copies a static key in place
721 # for each project before starting tests. This saves time because
722 # Zuul's automatic key-generation on startup can be slow. To make
723 # sure we exercise that code, in this test we allow Zuul to create
724 # keys for the project on startup.
725 create_project_keys = True
Tobias Henkelabf973e2017-07-28 10:07:34 +0200726 config_file = 'zuul-connections-gerrit-and-github.conf'
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +0000727 tenant_config_file = 'config/in-repo/main.yaml'
728
729 def test_key_generation(self):
730 key_root = os.path.join(self.state_root, 'keys')
731 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
732 # Make sure that a proper key was created on startup
733 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -0700734 private_key, public_key = \
735 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +0000736
737 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
738 fixture_private_key = i.read()
739
740 # Make sure that we didn't just end up with the static fixture
741 # key
742 self.assertNotEqual(fixture_private_key, private_key)
743
744 # Make sure it's the right length
745 self.assertEqual(4096, private_key.key_size)
James E. Blairbce76932017-05-04 10:03:15 -0700746
747
James E. Blairbb94dfa2017-07-11 07:45:19 -0700748class RoleTestCase(ZuulTestCase):
James E. Blair1b27f6a2017-07-14 14:09:07 -0700749 def _assertRolePath(self, build, playbook, content):
750 path = os.path.join(self.test_root, build.uuid,
751 'ansible', playbook, 'ansible.cfg')
752 roles_paths = []
753 with open(path) as f:
754 for line in f:
755 if line.startswith('roles_path'):
756 roles_paths.append(line)
757 print(roles_paths)
758 if content:
759 self.assertEqual(len(roles_paths), 1,
760 "Should have one roles_path line in %s" %
761 (playbook,))
762 self.assertIn(content, roles_paths[0])
763 else:
764 self.assertEqual(len(roles_paths), 0,
765 "Should have no roles_path line in %s" %
766 (playbook,))
767
James E. Blairbb94dfa2017-07-11 07:45:19 -0700768
769class TestRoles(RoleTestCase):
770 tenant_config_file = 'config/roles/main.yaml'
771
James E. Blairbce76932017-05-04 10:03:15 -0700772 def test_role(self):
773 # This exercises a proposed change to a role being checked out
774 # and used.
775 A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A')
776 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
777 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
778 B.subject, A.data['id'])
779 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
780 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
781 self.waitUntilSettled()
782 self.assertHistory([
783 dict(name='project-test', result='SUCCESS', changes='1,1 2,1'),
784 ])
James E. Blair6459db12017-06-29 14:57:20 -0700785
James E. Blair1b27f6a2017-07-14 14:09:07 -0700786 def test_role_inheritance(self):
787 self.executor_server.hold_jobs_in_build = True
788 conf = textwrap.dedent(
789 """
790 - job:
791 name: parent
792 roles:
793 - zuul: bare-role
794 pre-run: playbooks/parent-pre
795 post-run: playbooks/parent-post
796
797 - job:
798 name: project-test
799 parent: parent
800 roles:
801 - zuul: org/project
802
803 - project:
804 name: org/project
805 check:
806 jobs:
807 - project-test
808 """)
809
810 file_dict = {'.zuul.yaml': conf}
811 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
812 files=file_dict)
813 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
814 self.waitUntilSettled()
815
816 self.assertEqual(len(self.builds), 1)
817 build = self.getBuildByName('project-test')
818 self._assertRolePath(build, 'pre_playbook_0', 'role_0')
819 self._assertRolePath(build, 'playbook_0', 'role_0')
820 self._assertRolePath(build, 'playbook_0', 'role_1')
821 self._assertRolePath(build, 'post_playbook_0', 'role_0')
822
823 self.executor_server.hold_jobs_in_build = False
824 self.executor_server.release()
825 self.waitUntilSettled()
826
827 self.assertHistory([
828 dict(name='project-test', result='SUCCESS', changes='1,1'),
829 ])
830
James E. Blair6f699732017-07-18 14:19:11 -0700831 def test_role_error(self):
832 conf = textwrap.dedent(
833 """
834 - job:
835 name: project-test
836 roles:
837 - zuul: common-config
838
839 - project:
840 name: org/project
841 check:
842 jobs:
843 - project-test
844 """)
845
846 file_dict = {'.zuul.yaml': conf}
847 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
848 files=file_dict)
849 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
850 self.waitUntilSettled()
851 self.assertIn(
852 '- project-test project-test : ERROR Unable to find role',
853 A.messages[-1])
854
James E. Blair6459db12017-06-29 14:57:20 -0700855
James E. Blairbb94dfa2017-07-11 07:45:19 -0700856class TestImplicitRoles(RoleTestCase):
857 tenant_config_file = 'config/implicit-roles/main.yaml'
858
859 def test_missing_roles(self):
860 # Test implicit and explicit roles for a project which does
861 # not have roles. The implicit role should be silently
862 # ignored since the project doesn't supply roles, but if a
863 # user declares an explicit role, it should error.
864 self.executor_server.hold_jobs_in_build = True
865 A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A')
866 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
867 self.waitUntilSettled()
868
869 self.assertEqual(len(self.builds), 2)
870 build = self.getBuildByName('implicit-role-fail')
871 self._assertRolePath(build, 'playbook_0', None)
872
873 self.executor_server.hold_jobs_in_build = False
874 self.executor_server.release()
875 self.waitUntilSettled()
876 # The retry_limit doesn't get recorded
877 self.assertHistory([
878 dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'),
879 ])
880
881 def test_roles(self):
882 # Test implicit and explicit roles for a project which does
883 # have roles. In both cases, we should end up with the role
884 # in the path. In the explicit case, ensure we end up with
885 # the name we specified.
886 self.executor_server.hold_jobs_in_build = True
887 A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A')
888 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
889 self.waitUntilSettled()
890
891 self.assertEqual(len(self.builds), 2)
892 build = self.getBuildByName('implicit-role-ok')
893 self._assertRolePath(build, 'playbook_0', 'role_0')
894
895 build = self.getBuildByName('explicit-role-ok')
896 self._assertRolePath(build, 'playbook_0', 'role_0')
897
898 self.executor_server.hold_jobs_in_build = False
899 self.executor_server.release()
900 self.waitUntilSettled()
901 self.assertHistory([
902 dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'),
903 dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'),
904 ], ordered=False)
905
906
James E. Blair6459db12017-06-29 14:57:20 -0700907class TestShadow(ZuulTestCase):
908 tenant_config_file = 'config/shadow/main.yaml'
909
910 def test_shadow(self):
911 # Test that a repo is allowed to shadow another's job definitions.
912 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
913 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
914 self.waitUntilSettled()
915 self.assertHistory([
916 dict(name='test1', result='SUCCESS', changes='1,1'),
917 dict(name='test2', result='SUCCESS', changes='1,1'),
James E. Blairadafa6c2017-07-12 08:50:56 -0700918 ], ordered=False)
James E. Blair196f61a2017-06-30 15:42:29 -0700919
920
921class TestDataReturn(AnsibleZuulTestCase):
922 tenant_config_file = 'config/data-return/main.yaml'
923
924 def test_data_return(self):
925 # This exercises a proposed change to a role being checked out
926 # and used.
927 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
928 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
929 self.waitUntilSettled()
930 self.assertHistory([
931 dict(name='data-return', result='SUCCESS', changes='1,1'),
James E. Blair88e79c02017-07-07 13:36:54 -0700932 dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
933 ], ordered=False)
934 self.assertIn('- data-return http://example.com/test/log/url/',
935 A.messages[-1])
936 self.assertIn('- data-return-relative '
937 'http://example.com/test/log/url/docs/index.html',
James E. Blair196f61a2017-06-30 15:42:29 -0700938 A.messages[-1])
Clint Byrumdc8a0902017-07-20 16:36:27 -0700939
940
941class TestDiskAccounting(AnsibleZuulTestCase):
942 config_file = 'zuul-disk-accounting.conf'
943 tenant_config_file = 'config/disk-accountant/main.yaml'
944
945 def test_disk_accountant_kills_job(self):
946 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
947 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
948 self.waitUntilSettled()
949 self.assertHistory([
950 dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')])
Tristan Cacqueray82f864b2017-08-01 05:54:42 +0000951
952
953class TestMaxNodesPerJob(AnsibleZuulTestCase):
954 tenant_config_file = 'config/multi-tenant/main.yaml'
955
956 def test_max_nodes_reached(self):
957 in_repo_conf = textwrap.dedent(
958 """
959 - job:
960 name: test-job
961 nodes:
962 - name: node01
963 label: fake
964 - name: node02
965 label: fake
966 - name: node03
967 label: fake
968 - name: node04
969 label: fake
970 - name: node05
971 label: fake
972 - name: node06
973 label: fake
974 """)
975 file_dict = {'.zuul.yaml': in_repo_conf}
976 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A',
977 files=file_dict)
978 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
979 self.waitUntilSettled()
980 self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.',
981 A.messages[0], "A should fail because of nodes limit")
982
983 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A',
984 files=file_dict)
985 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
986 self.waitUntilSettled()
987 self.assertNotIn("exceeds tenant max-nodes", B.messages[0],
988 "B should not fail because of nodes limit")