blob: 2168a7f0ceb251cf87357b3825b2de771fe00d26 [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')
James E. Blair8b5408c2016-08-08 15:37:46 -070034 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')
James E. Blair8b5408c2016-08-08 15:37:46 -070050 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
James E. Blair2a629ec2015-12-22 15:32:02 -080073 tenant_config_file = 'config/in-repo/main.yaml'
James E. Blair83005782015-12-11 14:46:03 -080074
James E. Blair83005782015-12-11 14:46:03 -080075 def test_in_repo_config(self):
James E. Blair14abdf42015-12-09 16:11:53 -080076 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8b5408c2016-08-08 15:37:46 -070077 A.addApproval('code-review', 2)
78 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
James E. Blair14abdf42015-12-09 16:11:53 -080079 self.waitUntilSettled()
80 self.assertEqual(self.getJobFromHistory('project-test1').result,
81 'SUCCESS')
82 self.assertEqual(A.data['status'], 'MERGED')
83 self.assertEqual(A.reported, 2,
84 "A should report start and success")
85 self.assertIn('tenant-one-gate', A.messages[1],
86 "A should transit tenant-one gate")
James E. Blairb97ed802015-12-21 15:55:35 -080087
James E. Blair8b1dc3f2016-07-05 16:49:00 -070088 def test_dynamic_config(self):
89 in_repo_conf = textwrap.dedent(
90 """
91 - job:
92 name: project-test2
93
94 - project:
95 name: org/project
96 tenant-one-gate:
97 jobs:
98 - project-test2
99 """)
100
James E. Blairc73c73a2017-01-20 15:15:15 -0800101 in_repo_playbook = textwrap.dedent(
102 """
103 - hosts: all
104 tasks: []
105 """)
106
107 file_dict = {'.zuul.yaml': in_repo_conf,
108 'playbooks/project-test2.yaml': in_repo_playbook}
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700109 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
James E. Blairc73c73a2017-01-20 15:15:15 -0800110 files=file_dict)
James E. Blair8b5408c2016-08-08 15:37:46 -0700111 A.addApproval('code-review', 2)
112 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700113 self.waitUntilSettled()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700114 self.assertEqual(A.data['status'], 'MERGED')
115 self.assertEqual(A.reported, 2,
116 "A should report start and success")
117 self.assertIn('tenant-one-gate', A.messages[1],
118 "A should transit tenant-one gate")
James E. Blair646322f2017-01-27 15:50:34 -0800119 self.assertHistory([
120 dict(name='project-test2', result='SUCCESS', changes='1,1')])
121
James E. Blairc2a5ed72017-02-20 14:12:01 -0500122 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800123 self.waitUntilSettled()
James E. Blairc2a5ed72017-02-20 14:12:01 -0500124
James E. Blair646322f2017-01-27 15:50:34 -0800125 # Now that the config change is landed, it should be live for
126 # subsequent changes.
127 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
128 B.addApproval('code-review', 2)
129 self.fake_gerrit.addEvent(B.addApproval('approved', 1))
130 self.waitUntilSettled()
131 self.assertEqual(self.getJobFromHistory('project-test2').result,
132 'SUCCESS')
133 self.assertHistory([
134 dict(name='project-test2', result='SUCCESS', changes='1,1'),
135 dict(name='project-test2', result='SUCCESS', changes='2,1')])
James E. Blairc73c73a2017-01-20 15:15:15 -0800136
James E. Blairff555742017-02-19 11:34:27 -0800137 def test_in_repo_branch(self):
138 in_repo_conf = textwrap.dedent(
139 """
140 - job:
141 name: project-test2
142
143 - project:
144 name: org/project
145 tenant-one-gate:
146 jobs:
147 - project-test2
148 """)
149
150 in_repo_playbook = textwrap.dedent(
151 """
152 - hosts: all
153 tasks: []
154 """)
155
156 file_dict = {'.zuul.yaml': in_repo_conf,
157 'playbooks/project-test2.yaml': in_repo_playbook}
158 self.create_branch('org/project', 'stable')
159 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
160 files=file_dict)
161 A.addApproval('code-review', 2)
162 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
163 self.waitUntilSettled()
164 self.assertEqual(A.data['status'], 'MERGED')
165 self.assertEqual(A.reported, 2,
166 "A should report start and success")
167 self.assertIn('tenant-one-gate', A.messages[1],
168 "A should transit tenant-one gate")
169 self.assertHistory([
170 dict(name='project-test2', result='SUCCESS', changes='1,1')])
171 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800172 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800173
174 # The config change should not affect master.
175 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
176 B.addApproval('code-review', 2)
177 self.fake_gerrit.addEvent(B.addApproval('approved', 1))
178 self.waitUntilSettled()
179 self.assertHistory([
180 dict(name='project-test2', result='SUCCESS', changes='1,1'),
181 dict(name='project-test1', result='SUCCESS', changes='2,1')])
182
183 # The config change should be live for further changes on
184 # stable.
185 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
186 C.addApproval('code-review', 2)
187 self.fake_gerrit.addEvent(C.addApproval('approved', 1))
188 self.waitUntilSettled()
189 self.assertHistory([
190 dict(name='project-test2', result='SUCCESS', changes='1,1'),
191 dict(name='project-test1', result='SUCCESS', changes='2,1'),
192 dict(name='project-test2', result='SUCCESS', changes='3,1')])
193
James E. Blaira5a12492017-05-03 11:40:48 -0700194 def test_crd_dynamic_config_branch(self):
195 # Test that we can create a job in one repo and be able to use
196 # it from a different branch on a different repo.
197
198 self.create_branch('org/project1', 'stable')
199
200 in_repo_conf = textwrap.dedent(
201 """
202 - job:
203 name: project-test2
204
205 - project:
206 name: org/project
207 check:
208 jobs:
209 - project-test2
210 """)
211
212 in_repo_playbook = textwrap.dedent(
213 """
214 - hosts: all
215 tasks: []
216 """)
217
218 file_dict = {'.zuul.yaml': in_repo_conf,
219 'playbooks/project-test2.yaml': in_repo_playbook}
220 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
221 files=file_dict)
222
223 second_repo_conf = textwrap.dedent(
224 """
225 - project:
226 name: org/project1
227 check:
228 jobs:
229 - project-test2
230 """)
231
232 second_file_dict = {'.zuul.yaml': second_repo_conf}
233 B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B',
234 files=second_file_dict)
235 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
236 B.subject, A.data['id'])
237
238 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
239 self.waitUntilSettled()
240 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
241 self.waitUntilSettled()
242
243 self.assertEqual(A.reported, 1, "A should report")
244 self.assertHistory([
245 dict(name='project-test2', result='SUCCESS', changes='1,1'),
246 dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'),
247 ])
248
James E. Blair149b69c2017-03-02 10:48:16 -0800249 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -0800250 in_repo_conf = textwrap.dedent(
251 """
252 - job:
253 name: project-test2
254 foo: error
255 """)
256
257 file_dict = {'.zuul.yaml': in_repo_conf}
258 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
259 files=file_dict)
260 A.addApproval('code-review', 2)
261 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
262 self.waitUntilSettled()
263
264 self.assertEqual(A.data['status'], 'NEW')
265 self.assertEqual(A.reported, 2,
266 "A should report start and failure")
267 self.assertIn('syntax error', A.messages[1],
268 "A should have a syntax error reported")
269
James E. Blair149b69c2017-03-02 10:48:16 -0800270 def test_trusted_syntax_error(self):
271 in_repo_conf = textwrap.dedent(
272 """
273 - job:
274 name: project-test2
275 foo: error
276 """)
277
278 file_dict = {'zuul.yaml': in_repo_conf}
279 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
280 files=file_dict)
281 A.addApproval('code-review', 2)
282 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
283 self.waitUntilSettled()
284
285 self.assertEqual(A.data['status'], 'NEW')
286 self.assertEqual(A.reported, 2,
287 "A should report start and failure")
288 self.assertIn('syntax error', A.messages[1],
289 "A should have a syntax error reported")
290
James E. Blair6f140c72017-03-03 10:32:07 -0800291 def test_untrusted_yaml_error(self):
292 in_repo_conf = textwrap.dedent(
293 """
294 - job:
295 foo: error
296 """)
297
298 file_dict = {'.zuul.yaml': in_repo_conf}
299 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
300 files=file_dict)
301 A.addApproval('code-review', 2)
302 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
303 self.waitUntilSettled()
304
305 self.assertEqual(A.data['status'], 'NEW')
306 self.assertEqual(A.reported, 2,
307 "A should report start and failure")
308 self.assertIn('syntax error', A.messages[1],
309 "A should have a syntax error reported")
310
James E. Blairdb04e6a2017-05-03 14:49:36 -0700311 def test_untrusted_shadow_error(self):
312 in_repo_conf = textwrap.dedent(
313 """
314 - job:
315 name: common-config-test
316 """)
317
318 file_dict = {'.zuul.yaml': in_repo_conf}
319 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
320 files=file_dict)
321 A.addApproval('code-review', 2)
322 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
323 self.waitUntilSettled()
324
325 self.assertEqual(A.data['status'], 'NEW')
326 self.assertEqual(A.reported, 2,
327 "A should report start and failure")
328 self.assertIn('not permitted to shadow', A.messages[1],
329 "A should have a syntax error reported")
330
James E. Blairc73c73a2017-01-20 15:15:15 -0800331
332class TestAnsible(AnsibleZuulTestCase):
333 # A temporary class to hold new tests while others are disabled
334
335 tenant_config_file = 'config/ansible/main.yaml'
336
337 def test_playbook(self):
338 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
339 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
340 self.waitUntilSettled()
Paul Belanger96618ed2017-03-01 09:42:33 -0500341 build = self.getJobFromHistory('timeout')
Clark Boylan53fb1262017-04-25 08:37:56 -0700342 self.assertEqual(build.result, 'TIMED_OUT')
Monty Taylorc231d932017-02-03 09:57:15 -0600343 build = self.getJobFromHistory('faillocal')
344 self.assertEqual(build.result, 'FAILURE')
Paul Belangere2b8d492017-03-22 18:57:40 -0400345 build = self.getJobFromHistory('check-vars')
Paul Belanger30ba93a2017-03-16 16:28:10 -0400346 self.assertEqual(build.result, 'SUCCESS')
James E. Blaira92cbc82017-01-23 14:56:49 -0800347 build = self.getJobFromHistory('python27')
348 self.assertEqual(build.result, 'SUCCESS')
349 flag_path = os.path.join(self.test_root, build.uuid + '.flag')
350 self.assertTrue(os.path.exists(flag_path))
Monty Taylorc231d932017-02-03 09:57:15 -0600351 copied_path = os.path.join(self.test_root, build.uuid +
352 '.copied')
353 self.assertTrue(os.path.exists(copied_path))
354 failed_path = os.path.join(self.test_root, build.uuid +
355 '.failed')
356 self.assertFalse(os.path.exists(failed_path))
James E. Blair66b274e2017-01-31 14:47:52 -0800357 pre_flag_path = os.path.join(self.test_root, build.uuid +
358 '.pre.flag')
359 self.assertTrue(os.path.exists(pre_flag_path))
360 post_flag_path = os.path.join(self.test_root, build.uuid +
361 '.post.flag')
362 self.assertTrue(os.path.exists(post_flag_path))
James E. Blair5ac93842017-01-20 06:47:34 -0800363 bare_role_flag_path = os.path.join(self.test_root,
364 build.uuid + '.bare-role.flag')
365 self.assertTrue(os.path.exists(bare_role_flag_path))
James E. Blairb9c0d772017-03-03 14:34:49 -0800366
James E. Blair18f86a32017-03-15 14:43:26 -0700367 secrets_path = os.path.join(self.test_root,
368 build.uuid + '.secrets')
369 with open(secrets_path) as f:
370 self.assertEqual(f.read(), "test-username test-password")
371
James E. Blairb9c0d772017-03-03 14:34:49 -0800372
373class TestBrokenConfig(ZuulTestCase):
374 # Test that we get an appropriate syntax error if we start with a
375 # broken config.
376
377 tenant_config_file = 'config/broken/main.yaml'
378
379 def setUp(self):
380 with testtools.ExpectedException(
381 zuul.configloader.ConfigurationSyntaxError,
382 "\nZuul encountered a syntax error"):
383 super(TestBrokenConfig, self).setUp()
384
385 def test_broken_config_on_startup(self):
386 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +0000387
388
389class TestProjectKeys(ZuulTestCase):
390 # Test that we can generate project keys
391
392 # Normally the test infrastructure copies a static key in place
393 # for each project before starting tests. This saves time because
394 # Zuul's automatic key-generation on startup can be slow. To make
395 # sure we exercise that code, in this test we allow Zuul to create
396 # keys for the project on startup.
397 create_project_keys = True
398 tenant_config_file = 'config/in-repo/main.yaml'
399
400 def test_key_generation(self):
401 key_root = os.path.join(self.state_root, 'keys')
402 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
403 # Make sure that a proper key was created on startup
404 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -0700405 private_key, public_key = \
406 encryption.deserialize_rsa_keypair(f.read())
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +0000407
408 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
409 fixture_private_key = i.read()
410
411 # Make sure that we didn't just end up with the static fixture
412 # key
413 self.assertNotEqual(fixture_private_key, private_key)
414
415 # Make sure it's the right length
416 self.assertEqual(4096, private_key.key_size)