blob: 97816ea0f4dcc2e05cf1f2b91d7305bf989a7d1e [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
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +000020from cryptography.hazmat.primitives import serialization
21from cryptography.hazmat.backends import default_backend
James E. Blairb9c0d772017-03-03 14:34:49 -080022import testtools
23
24import zuul.configloader
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +000025from tests.base import AnsibleZuulTestCase, ZuulTestCase, FIXTURE_DIR
James E. Blair59fdbac2015-12-07 17:08:06 -080026
James E. Blair59fdbac2015-12-07 17:08:06 -080027
James E. Blair3f876d52016-07-22 13:07:14 -070028class TestMultipleTenants(AnsibleZuulTestCase):
James E. Blair59fdbac2015-12-07 17:08:06 -080029 # A temporary class to hold new tests while others are disabled
30
James E. Blair2a629ec2015-12-22 15:32:02 -080031 tenant_config_file = 'config/multi-tenant/main.yaml'
James E. Blair59fdbac2015-12-07 17:08:06 -080032
James E. Blair83005782015-12-11 14:46:03 -080033 def test_multiple_tenants(self):
James E. Blair96f26942015-12-09 10:15:59 -080034 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
James E. Blair8b5408c2016-08-08 15:37:46 -070035 A.addApproval('code-review', 2)
36 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
James E. Blair59fdbac2015-12-07 17:08:06 -080037 self.waitUntilSettled()
James E. Blair96f26942015-12-09 10:15:59 -080038 self.assertEqual(self.getJobFromHistory('project1-test1').result,
James E. Blair59fdbac2015-12-07 17:08:06 -080039 'SUCCESS')
James E. Blair96c6bf82016-01-15 16:20:40 -080040 self.assertEqual(self.getJobFromHistory('python27').result,
41 'SUCCESS')
James E. Blair59fdbac2015-12-07 17:08:06 -080042 self.assertEqual(A.data['status'], 'MERGED')
James E. Blair96f26942015-12-09 10:15:59 -080043 self.assertEqual(A.reported, 2,
44 "A should report start and success")
45 self.assertIn('tenant-one-gate', A.messages[1],
46 "A should transit tenant-one gate")
47 self.assertNotIn('tenant-two-gate', A.messages[1],
48 "A should *not* transit tenant-two gate")
James E. Blair59fdbac2015-12-07 17:08:06 -080049
James E. Blair96f26942015-12-09 10:15:59 -080050 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
James E. Blair8b5408c2016-08-08 15:37:46 -070051 B.addApproval('code-review', 2)
52 self.fake_gerrit.addEvent(B.addApproval('approved', 1))
James E. Blair96f26942015-12-09 10:15:59 -080053 self.waitUntilSettled()
James E. Blair96c6bf82016-01-15 16:20:40 -080054 self.assertEqual(self.getJobFromHistory('python27',
55 'org/project2').result,
56 'SUCCESS')
James E. Blair96f26942015-12-09 10:15:59 -080057 self.assertEqual(self.getJobFromHistory('project2-test1').result,
58 'SUCCESS')
59 self.assertEqual(B.data['status'], 'MERGED')
60 self.assertEqual(B.reported, 2,
61 "B should report start and success")
62 self.assertIn('tenant-two-gate', B.messages[1],
63 "B should transit tenant-two gate")
64 self.assertNotIn('tenant-one-gate', B.messages[1],
65 "B should *not* transit tenant-one gate")
James E. Blair59fdbac2015-12-07 17:08:06 -080066
James E. Blair96f26942015-12-09 10:15:59 -080067 self.assertEqual(A.reported, 2, "Activity in tenant two should"
68 "not affect tenant one")
James E. Blair14abdf42015-12-09 16:11:53 -080069
James E. Blair83005782015-12-11 14:46:03 -080070
James E. Blairff555742017-02-19 11:34:27 -080071class TestInRepoConfig(ZuulTestCase):
James E. Blair83005782015-12-11 14:46:03 -080072 # A temporary class to hold new tests while others are disabled
73
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')
James E. Blair8b5408c2016-08-08 15:37:46 -070078 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)
James E. Blair8b5408c2016-08-08 15:37:46 -0700112 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')
129 B.addApproval('code-review', 2)
130 self.fake_gerrit.addEvent(B.addApproval('approved', 1))
131 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
James E. Blairff555742017-02-19 11:34:27 -0800138 def test_in_repo_branch(self):
139 in_repo_conf = textwrap.dedent(
140 """
141 - job:
142 name: project-test2
143
144 - project:
145 name: org/project
146 tenant-one-gate:
147 jobs:
148 - project-test2
149 """)
150
151 in_repo_playbook = textwrap.dedent(
152 """
153 - hosts: all
154 tasks: []
155 """)
156
157 file_dict = {'.zuul.yaml': in_repo_conf,
158 'playbooks/project-test2.yaml': in_repo_playbook}
159 self.create_branch('org/project', 'stable')
160 A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A',
161 files=file_dict)
162 A.addApproval('code-review', 2)
163 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
164 self.waitUntilSettled()
165 self.assertEqual(A.data['status'], 'MERGED')
166 self.assertEqual(A.reported, 2,
167 "A should report start and success")
168 self.assertIn('tenant-one-gate', A.messages[1],
169 "A should transit tenant-one gate")
170 self.assertHistory([
171 dict(name='project-test2', result='SUCCESS', changes='1,1')])
172 self.fake_gerrit.addEvent(A.getChangeMergedEvent())
James E. Blair7bbd7a32017-03-06 11:36:13 -0800173 self.waitUntilSettled()
James E. Blairff555742017-02-19 11:34:27 -0800174
175 # The config change should not affect master.
176 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
177 B.addApproval('code-review', 2)
178 self.fake_gerrit.addEvent(B.addApproval('approved', 1))
179 self.waitUntilSettled()
180 self.assertHistory([
181 dict(name='project-test2', result='SUCCESS', changes='1,1'),
182 dict(name='project-test1', result='SUCCESS', changes='2,1')])
183
184 # The config change should be live for further changes on
185 # stable.
186 C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C')
187 C.addApproval('code-review', 2)
188 self.fake_gerrit.addEvent(C.addApproval('approved', 1))
189 self.waitUntilSettled()
190 self.assertHistory([
191 dict(name='project-test2', result='SUCCESS', changes='1,1'),
192 dict(name='project-test1', result='SUCCESS', changes='2,1'),
193 dict(name='project-test2', result='SUCCESS', changes='3,1')])
194
James E. Blair149b69c2017-03-02 10:48:16 -0800195 def test_untrusted_syntax_error(self):
James E. Blaire53250c2017-03-01 14:34:36 -0800196 in_repo_conf = textwrap.dedent(
197 """
198 - job:
199 name: project-test2
200 foo: error
201 """)
202
203 file_dict = {'.zuul.yaml': in_repo_conf}
204 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
205 files=file_dict)
206 A.addApproval('code-review', 2)
207 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
208 self.waitUntilSettled()
209
210 self.assertEqual(A.data['status'], 'NEW')
211 self.assertEqual(A.reported, 2,
212 "A should report start and failure")
213 self.assertIn('syntax error', A.messages[1],
214 "A should have a syntax error reported")
215
James E. Blair149b69c2017-03-02 10:48:16 -0800216 def test_trusted_syntax_error(self):
217 in_repo_conf = textwrap.dedent(
218 """
219 - job:
220 name: project-test2
221 foo: error
222 """)
223
224 file_dict = {'zuul.yaml': in_repo_conf}
225 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
226 files=file_dict)
227 A.addApproval('code-review', 2)
228 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
229 self.waitUntilSettled()
230
231 self.assertEqual(A.data['status'], 'NEW')
232 self.assertEqual(A.reported, 2,
233 "A should report start and failure")
234 self.assertIn('syntax error', A.messages[1],
235 "A should have a syntax error reported")
236
James E. Blair6f140c72017-03-03 10:32:07 -0800237 def test_untrusted_yaml_error(self):
238 in_repo_conf = textwrap.dedent(
239 """
240 - job:
241 foo: error
242 """)
243
244 file_dict = {'.zuul.yaml': in_repo_conf}
245 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
246 files=file_dict)
247 A.addApproval('code-review', 2)
248 self.fake_gerrit.addEvent(A.addApproval('approved', 1))
249 self.waitUntilSettled()
250
251 self.assertEqual(A.data['status'], 'NEW')
252 self.assertEqual(A.reported, 2,
253 "A should report start and failure")
254 self.assertIn('syntax error', A.messages[1],
255 "A should have a syntax error reported")
256
James E. Blairc73c73a2017-01-20 15:15:15 -0800257
258class TestAnsible(AnsibleZuulTestCase):
259 # A temporary class to hold new tests while others are disabled
260
261 tenant_config_file = 'config/ansible/main.yaml'
262
263 def test_playbook(self):
264 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
265 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
266 self.waitUntilSettled()
Paul Belanger96618ed2017-03-01 09:42:33 -0500267 build = self.getJobFromHistory('timeout')
268 self.assertEqual(build.result, 'ABORTED')
Monty Taylorc231d932017-02-03 09:57:15 -0600269 build = self.getJobFromHistory('faillocal')
270 self.assertEqual(build.result, 'FAILURE')
Paul Belanger30ba93a2017-03-16 16:28:10 -0400271 build = self.getJobFromHistory('nodepool')
272 self.assertEqual(build.result, 'SUCCESS')
James E. Blaira92cbc82017-01-23 14:56:49 -0800273 build = self.getJobFromHistory('python27')
274 self.assertEqual(build.result, 'SUCCESS')
275 flag_path = os.path.join(self.test_root, build.uuid + '.flag')
276 self.assertTrue(os.path.exists(flag_path))
Monty Taylorc231d932017-02-03 09:57:15 -0600277 copied_path = os.path.join(self.test_root, build.uuid +
278 '.copied')
279 self.assertTrue(os.path.exists(copied_path))
280 failed_path = os.path.join(self.test_root, build.uuid +
281 '.failed')
282 self.assertFalse(os.path.exists(failed_path))
James E. Blair66b274e2017-01-31 14:47:52 -0800283 pre_flag_path = os.path.join(self.test_root, build.uuid +
284 '.pre.flag')
285 self.assertTrue(os.path.exists(pre_flag_path))
286 post_flag_path = os.path.join(self.test_root, build.uuid +
287 '.post.flag')
288 self.assertTrue(os.path.exists(post_flag_path))
James E. Blair5ac93842017-01-20 06:47:34 -0800289 bare_role_flag_path = os.path.join(self.test_root,
290 build.uuid + '.bare-role.flag')
291 self.assertTrue(os.path.exists(bare_role_flag_path))
James E. Blairb9c0d772017-03-03 14:34:49 -0800292
James E. Blair18f86a32017-03-15 14:43:26 -0700293 secrets_path = os.path.join(self.test_root,
294 build.uuid + '.secrets')
295 with open(secrets_path) as f:
296 self.assertEqual(f.read(), "test-username test-password")
297
James E. Blairb9c0d772017-03-03 14:34:49 -0800298
299class TestBrokenConfig(ZuulTestCase):
300 # Test that we get an appropriate syntax error if we start with a
301 # broken config.
302
303 tenant_config_file = 'config/broken/main.yaml'
304
305 def setUp(self):
306 with testtools.ExpectedException(
307 zuul.configloader.ConfigurationSyntaxError,
308 "\nZuul encountered a syntax error"):
309 super(TestBrokenConfig, self).setUp()
310
311 def test_broken_config_on_startup(self):
312 pass
Ricardo Carrillo Cruz22994f92016-12-02 11:41:58 +0000313
314
315class TestProjectKeys(ZuulTestCase):
316 # Test that we can generate project keys
317
318 # Normally the test infrastructure copies a static key in place
319 # for each project before starting tests. This saves time because
320 # Zuul's automatic key-generation on startup can be slow. To make
321 # sure we exercise that code, in this test we allow Zuul to create
322 # keys for the project on startup.
323 create_project_keys = True
324 tenant_config_file = 'config/in-repo/main.yaml'
325
326 def test_key_generation(self):
327 key_root = os.path.join(self.state_root, 'keys')
328 private_key_file = os.path.join(key_root, 'gerrit/org/project.pem')
329 # Make sure that a proper key was created on startup
330 with open(private_key_file, "rb") as f:
331 private_key = serialization.load_pem_private_key(
332 f.read(),
333 password=None,
334 backend=default_backend()
335 )
336
337 with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i:
338 fixture_private_key = i.read()
339
340 # Make sure that we didn't just end up with the static fixture
341 # key
342 self.assertNotEqual(fixture_private_key, private_key)
343
344 # Make sure it's the right length
345 self.assertEqual(4096, private_key.key_size)