blob: 628a45cb4a47cefbc4c331abd40d714c2518a791 [file] [log] [blame]
Maru Newby3fe5f852015-01-13 04:22:14 +00001# Copyright 2015 Red Hat, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
Joshua Hesketh0aa7e8b2016-07-14 00:12:25 +100015
James E. Blairce8a2132016-05-19 15:21:52 -070016import os
17import random
18
19import fixtures
James E. Blair4317e9f2016-07-15 10:05:47 -070020import testtools
James E. Blairce8a2132016-05-19 15:21:52 -070021
Maru Newby3fe5f852015-01-13 04:22:14 +000022from zuul import model
James E. Blair83005782015-12-11 14:46:03 -080023from zuul import configloader
James E. Blairbf1a4f22017-03-17 10:59:37 -070024from zuul.lib import encryption
Clint Byrum88fdfde2017-03-28 16:22:42 -070025from zuul.lib import yamlutil as yaml
Maru Newby3fe5f852015-01-13 04:22:14 +000026
James E. Blair18f86a32017-03-15 14:43:26 -070027from tests.base import BaseTestCase, FIXTURE_DIR
Maru Newby3fe5f852015-01-13 04:22:14 +000028
29
James E. Blair0a899752017-03-29 13:22:16 -070030class Dummy(object):
31 def __init__(self, **kw):
32 for k, v in kw.items():
33 setattr(self, k, v)
James E. Blairb3f5db12017-03-17 12:57:39 -070034
35
Maru Newby3fe5f852015-01-13 04:22:14 +000036class TestJob(BaseTestCase):
James E. Blaira7f51ca2017-02-07 16:01:26 -080037 def setUp(self):
38 super(TestJob, self).setUp()
James E. Blair0a899752017-03-29 13:22:16 -070039 self.connection = Dummy(connection_name='dummy_connection')
40 self.source = Dummy(canonical_hostname='git.example.com',
James E. Blair0a899752017-03-29 13:22:16 -070041 connection=self.connection)
James E. Blairb3f5db12017-03-17 12:57:39 -070042 self.tenant = model.Tenant('tenant')
James E. Blair6459db12017-06-29 14:57:20 -070043 self.layout = model.Layout(self.tenant)
James E. Blair0a899752017-03-29 13:22:16 -070044 self.project = model.Project('project', self.source)
James E. Blair08d9b782017-06-29 14:22:48 -070045 self.tpc = model.TenantProjectConfig(self.project)
46 self.tenant.addUntrustedProject(self.tpc)
James E. Blairb3f5db12017-03-17 12:57:39 -070047 self.pipeline = model.Pipeline('gate', self.layout)
48 self.layout.addPipeline(self.pipeline)
49 self.queue = model.ChangeQueue(self.pipeline)
50
James E. Blair18f86a32017-03-15 14:43:26 -070051 private_key_file = os.path.join(FIXTURE_DIR, 'private.pem')
52 with open(private_key_file, "rb") as f:
James E. Blairbf1a4f22017-03-17 10:59:37 -070053 self.project.private_key, self.project.public_key = \
54 encryption.deserialize_rsa_keypair(f.read())
James E. Blair6f140c72017-03-03 10:32:07 -080055 self.context = model.SourceContext(self.project, 'master',
56 'test', True)
James E. Blair892cca62017-08-09 11:36:58 -070057 self.untrusted_context = model.SourceContext(self.project, 'master',
58 'test', False)
James E. Blair1cebebf2017-07-14 11:39:03 -070059 m = yaml.Mark('name', 0, 0, 0, '', 0)
60 self.start_mark = configloader.ZuulMark(m, m, '')
James E. Blaira7f51ca2017-02-07 16:01:26 -080061
Maru Newby3fe5f852015-01-13 04:22:14 +000062 @property
63 def job(self):
James E. Blair5ac93842017-01-20 06:47:34 -080064 tenant = model.Tenant('tenant')
James E. Blair6459db12017-06-29 14:57:20 -070065 layout = model.Layout(tenant)
James E. Blair5ac93842017-01-20 06:47:34 -080066 job = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -080067 '_source_context': self.context,
68 '_start_mark': self.start_mark,
James E. Blair83005782015-12-11 14:46:03 -080069 'name': 'job',
James E. Blair2bab6e72017-08-07 09:52:45 -070070 'parent': None,
James E. Blair83005782015-12-11 14:46:03 -080071 'irrelevant-files': [
72 '^docs/.*$'
73 ]})
Maru Newby3fe5f852015-01-13 04:22:14 +000074 return job
75
76 def test_change_matches_returns_false_for_matched_skip_if(self):
77 change = model.Change('project')
Alexander Evseevdbe6fab2015-11-19 12:46:34 +030078 change.files = ['/COMMIT_MSG', 'docs/foo']
Maru Newby3fe5f852015-01-13 04:22:14 +000079 self.assertFalse(self.job.changeMatches(change))
80
Jan Hruban570d01c2016-03-10 21:51:32 +010081 def test_change_matches_returns_false_for_single_matched_skip_if(self):
82 change = model.Change('project')
83 change.files = ['docs/foo']
84 self.assertFalse(self.job.changeMatches(change))
85
Maru Newby3fe5f852015-01-13 04:22:14 +000086 def test_change_matches_returns_true_for_unmatched_skip_if(self):
87 change = model.Change('project')
Alexander Evseevdbe6fab2015-11-19 12:46:34 +030088 change.files = ['/COMMIT_MSG', 'foo']
Maru Newby3fe5f852015-01-13 04:22:14 +000089 self.assertTrue(self.job.changeMatches(change))
90
Jan Hruban570d01c2016-03-10 21:51:32 +010091 def test_change_matches_returns_true_for_single_unmatched_skip_if(self):
92 change = model.Change('project')
93 change.files = ['foo']
94 self.assertTrue(self.job.changeMatches(change))
95
Maru Newby79427a42015-02-17 17:54:45 +000096 def test_job_sets_defaults_for_boolean_attributes(self):
James E. Blair83005782015-12-11 14:46:03 -080097 self.assertIsNotNone(self.job.voting)
98
99 def test_job_inheritance(self):
James E. Blaira7f51ca2017-02-07 16:01:26 -0800100 # This is standard job inheritance.
101
James E. Blair892cca62017-08-09 11:36:58 -0700102 base_pre = model.PlaybookContext(self.context, 'base-pre', [], [])
103 base_run = model.PlaybookContext(self.context, 'base-run', [], [])
104 base_post = model.PlaybookContext(self.context, 'base-post', [], [])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800105
106 base = model.Job('base')
107 base.timeout = 30
108 base.pre_run = [base_pre]
109 base.run = [base_run]
110 base.post_run = [base_post]
James E. Blaira7f51ca2017-02-07 16:01:26 -0800111
112 py27 = model.Job('py27')
Monty Taylor38b553a2017-06-05 13:06:10 -0500113 self.assertIsNone(py27.timeout)
James E. Blaira7f51ca2017-02-07 16:01:26 -0800114 py27.inheritFrom(base)
115 self.assertEqual(30, py27.timeout)
116 self.assertEqual(['base-pre'],
117 [x.path for x in py27.pre_run])
118 self.assertEqual(['base-run'],
119 [x.path for x in py27.run])
120 self.assertEqual(['base-post'],
121 [x.path for x in py27.post_run])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800122
123 def test_job_variants(self):
124 # This simulates freezing a job.
125
James E. Blair892cca62017-08-09 11:36:58 -0700126 secrets = ['foo']
127 py27_pre = model.PlaybookContext(self.context, 'py27-pre', [], secrets)
128 py27_run = model.PlaybookContext(self.context, 'py27-run', [], secrets)
129 py27_post = model.PlaybookContext(self.context, 'py27-post', [],
130 secrets)
James E. Blaira7f51ca2017-02-07 16:01:26 -0800131
132 py27 = model.Job('py27')
133 py27.timeout = 30
134 py27.pre_run = [py27_pre]
135 py27.run = [py27_run]
136 py27.post_run = [py27_post]
James E. Blaira7f51ca2017-02-07 16:01:26 -0800137
138 job = py27.copy()
139 self.assertEqual(30, job.timeout)
140
141 # Apply the diablo variant
142 diablo = model.Job('py27')
143 diablo.timeout = 40
144 job.applyVariant(diablo)
145
146 self.assertEqual(40, job.timeout)
147 self.assertEqual(['py27-pre'],
148 [x.path for x in job.pre_run])
149 self.assertEqual(['py27-run'],
150 [x.path for x in job.run])
151 self.assertEqual(['py27-post'],
152 [x.path for x in job.post_run])
James E. Blair892cca62017-08-09 11:36:58 -0700153 self.assertEqual(secrets, job.pre_run[0].secrets)
154 self.assertEqual(secrets, job.run[0].secrets)
155 self.assertEqual(secrets, job.post_run[0].secrets)
James E. Blaira7f51ca2017-02-07 16:01:26 -0800156
157 # Set the job to final for the following checks
158 job.final = True
159 self.assertTrue(job.voting)
160
161 good_final = model.Job('py27')
162 good_final.voting = False
163 job.applyVariant(good_final)
164 self.assertFalse(job.voting)
165
166 bad_final = model.Job('py27')
167 bad_final.timeout = 600
168 with testtools.ExpectedException(
169 Exception,
170 "Unable to modify final job"):
171 job.applyVariant(bad_final)
172
173 def test_job_inheritance_configloader(self):
174 # TODO(jeblair): move this to a configloader test
James E. Blair5ac93842017-01-20 06:47:34 -0800175 tenant = model.Tenant('tenant')
James E. Blair6459db12017-06-29 14:57:20 -0700176 layout = model.Layout(tenant)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700177
178 pipeline = model.Pipeline('gate', layout)
179 layout.addPipeline(pipeline)
180 queue = model.ChangeQueue(pipeline)
James E. Blair0a899752017-03-29 13:22:16 -0700181 project = model.Project('project', self.source)
James E. Blair08d9b782017-06-29 14:22:48 -0700182 tpc = model.TenantProjectConfig(project)
183 tenant.addUntrustedProject(tpc)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700184
James E. Blair5ac93842017-01-20 06:47:34 -0800185 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800186 '_source_context': self.context,
187 '_start_mark': self.start_mark,
James E. Blair83005782015-12-11 14:46:03 -0800188 'name': 'base',
James E. Blair2bab6e72017-08-07 09:52:45 -0700189 'parent': None,
James E. Blair83005782015-12-11 14:46:03 -0800190 'timeout': 30,
James E. Blaira7f51ca2017-02-07 16:01:26 -0800191 'pre-run': 'base-pre',
192 'post-run': 'base-post',
James E. Blair7e3e6882017-09-20 15:47:13 -0700193 'nodeset': {
194 'nodes': [{
195 'name': 'controller',
196 'label': 'base',
197 }],
198 },
James E. Blair83005782015-12-11 14:46:03 -0800199 })
200 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800201 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800202 '_source_context': self.context,
203 '_start_mark': self.start_mark,
James E. Blair83005782015-12-11 14:46:03 -0800204 'name': 'python27',
205 'parent': 'base',
James E. Blaira7f51ca2017-02-07 16:01:26 -0800206 'pre-run': 'py27-pre',
Paul Belanger3ae0eee2017-08-23 13:12:00 -0400207 'post-run': ['py27-post-a', 'py27-post-b'],
James E. Blair7e3e6882017-09-20 15:47:13 -0700208 'nodeset': {
209 'nodes': [{
210 'name': 'controller',
211 'label': 'new',
212 }],
213 },
James E. Blair83005782015-12-11 14:46:03 -0800214 'timeout': 40,
215 })
216 layout.addJob(python27)
James E. Blair5ac93842017-01-20 06:47:34 -0800217 python27diablo = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800218 '_source_context': self.context,
219 '_start_mark': self.start_mark,
James E. Blair83005782015-12-11 14:46:03 -0800220 'name': 'python27',
221 'branches': [
222 'stable/diablo'
223 ],
James E. Blaira7f51ca2017-02-07 16:01:26 -0800224 'pre-run': 'py27-diablo-pre',
225 'run': 'py27-diablo',
226 'post-run': 'py27-diablo-post',
James E. Blair7e3e6882017-09-20 15:47:13 -0700227 'nodeset': {
228 'nodes': [{
229 'name': 'controller',
230 'label': 'old',
231 }],
232 },
James E. Blair83005782015-12-11 14:46:03 -0800233 'timeout': 50,
234 })
235 layout.addJob(python27diablo)
236
James E. Blair5ac93842017-01-20 06:47:34 -0800237 python27essex = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800238 '_source_context': self.context,
239 '_start_mark': self.start_mark,
James E. Blaira7f51ca2017-02-07 16:01:26 -0800240 'name': 'python27',
241 'branches': [
242 'stable/essex'
243 ],
244 'pre-run': 'py27-essex-pre',
245 'post-run': 'py27-essex-post',
246 })
247 layout.addJob(python27essex)
248
James E. Blairaf8b2082017-10-03 15:38:27 -0700249 project_template_parser = configloader.ProjectTemplateParser(
250 tenant, layout)
251 project_parser = configloader.ProjectParser(
252 tenant, layout, project_template_parser)
253 project_config = project_parser.fromYaml([{
James E. Blairec7ff302017-03-04 07:31:32 -0800254 '_source_context': self.context,
255 '_start_mark': self.start_mark,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700256 'name': 'project',
257 'gate': {
258 'jobs': [
259 'python27'
260 ]
261 }
James E. Blairff555742017-02-19 11:34:27 -0800262 }])
James E. Blairf59f3cf2017-02-19 14:50:26 -0800263 layout.addProjectConfig(project_config)
James E. Blair83005782015-12-11 14:46:03 -0800264
James E. Blair83005782015-12-11 14:46:03 -0800265 change = model.Change(project)
James E. Blair1774dd52017-02-03 10:52:32 -0800266 # Test master
James E. Blair83005782015-12-11 14:46:03 -0800267 change.branch = 'master'
268 item = queue.enqueueChange(change)
James E. Blair29a24fd2017-10-02 15:04:56 -0700269 item.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800270
271 self.assertTrue(base.changeMatches(change))
272 self.assertTrue(python27.changeMatches(change))
273 self.assertFalse(python27diablo.changeMatches(change))
James E. Blaira7f51ca2017-02-07 16:01:26 -0800274 self.assertFalse(python27essex.changeMatches(change))
James E. Blair83005782015-12-11 14:46:03 -0800275
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200276 item.freezeJobGraph()
James E. Blair83005782015-12-11 14:46:03 -0800277 self.assertEqual(len(item.getJobs()), 1)
278 job = item.getJobs()[0]
279 self.assertEqual(job.name, 'python27')
280 self.assertEqual(job.timeout, 40)
James E. Blair1774dd52017-02-03 10:52:32 -0800281 nodes = job.nodeset.getNodes()
282 self.assertEqual(len(nodes), 1)
James E. Blair16d96a02017-06-08 11:32:56 -0700283 self.assertEqual(nodes[0].label, 'new')
James E. Blaira7f51ca2017-02-07 16:01:26 -0800284 self.assertEqual([x.path for x in job.pre_run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200285 ['base-pre',
286 'py27-pre'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800287 self.assertEqual([x.path for x in job.post_run],
Paul Belanger3ae0eee2017-08-23 13:12:00 -0400288 ['py27-post-a',
289 'py27-post-b',
Tobias Henkel165450e2017-06-26 22:53:45 +0200290 'base-post'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800291 self.assertEqual([x.path for x in job.run],
292 ['playbooks/python27',
293 'playbooks/base'])
James E. Blair83005782015-12-11 14:46:03 -0800294
James E. Blair1774dd52017-02-03 10:52:32 -0800295 # Test diablo
James E. Blair83005782015-12-11 14:46:03 -0800296 change.branch = 'stable/diablo'
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700297 item = queue.enqueueChange(change)
James E. Blair29a24fd2017-10-02 15:04:56 -0700298 item.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800299
300 self.assertTrue(base.changeMatches(change))
301 self.assertTrue(python27.changeMatches(change))
302 self.assertTrue(python27diablo.changeMatches(change))
James E. Blaira7f51ca2017-02-07 16:01:26 -0800303 self.assertFalse(python27essex.changeMatches(change))
James E. Blair83005782015-12-11 14:46:03 -0800304
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200305 item.freezeJobGraph()
James E. Blair83005782015-12-11 14:46:03 -0800306 self.assertEqual(len(item.getJobs()), 1)
307 job = item.getJobs()[0]
308 self.assertEqual(job.name, 'python27')
309 self.assertEqual(job.timeout, 50)
James E. Blair1774dd52017-02-03 10:52:32 -0800310 nodes = job.nodeset.getNodes()
311 self.assertEqual(len(nodes), 1)
James E. Blair16d96a02017-06-08 11:32:56 -0700312 self.assertEqual(nodes[0].label, 'old')
James E. Blaira7f51ca2017-02-07 16:01:26 -0800313 self.assertEqual([x.path for x in job.pre_run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200314 ['base-pre',
315 'py27-pre',
316 'py27-diablo-pre'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800317 self.assertEqual([x.path for x in job.post_run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200318 ['py27-diablo-post',
Paul Belanger3ae0eee2017-08-23 13:12:00 -0400319 'py27-post-a',
320 'py27-post-b',
Tobias Henkel165450e2017-06-26 22:53:45 +0200321 'base-post'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800322 self.assertEqual([x.path for x in job.run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200323 ['py27-diablo']),
James E. Blaira7f51ca2017-02-07 16:01:26 -0800324
325 # Test essex
326 change.branch = 'stable/essex'
327 item = queue.enqueueChange(change)
James E. Blair29a24fd2017-10-02 15:04:56 -0700328 item.layout = layout
James E. Blaira7f51ca2017-02-07 16:01:26 -0800329
330 self.assertTrue(base.changeMatches(change))
331 self.assertTrue(python27.changeMatches(change))
332 self.assertFalse(python27diablo.changeMatches(change))
333 self.assertTrue(python27essex.changeMatches(change))
334
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200335 item.freezeJobGraph()
James E. Blaira7f51ca2017-02-07 16:01:26 -0800336 self.assertEqual(len(item.getJobs()), 1)
337 job = item.getJobs()[0]
338 self.assertEqual(job.name, 'python27')
339 self.assertEqual([x.path for x in job.pre_run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200340 ['base-pre',
341 'py27-pre',
342 'py27-essex-pre'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800343 self.assertEqual([x.path for x in job.post_run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200344 ['py27-essex-post',
Paul Belanger3ae0eee2017-08-23 13:12:00 -0400345 'py27-post-a',
346 'py27-post-b',
Tobias Henkel165450e2017-06-26 22:53:45 +0200347 'base-post'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800348 self.assertEqual([x.path for x in job.run],
349 ['playbooks/python27',
350 'playbooks/base'])
James E. Blairce8a2132016-05-19 15:21:52 -0700351
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000352 def test_job_auth_inheritance(self):
James E. Blair6459db12017-06-29 14:57:20 -0700353 tenant = self.tenant
354 layout = self.layout
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000355
James E. Blair01f83b72017-03-15 13:03:40 -0700356 conf = yaml.safe_load('''
357- secret:
James E. Blair892cca62017-08-09 11:36:58 -0700358 name: trusted-secret
James E. Blair01f83b72017-03-15 13:03:40 -0700359 data:
360 username: test-username
James E. Blair9118c012017-08-03 11:19:16 -0700361 longpassword: !encrypted/pkcs1-oaep
362 - BFhtdnm8uXx7kn79RFL/zJywmzLkT1GY78P3bOtp4WghUFWobkifSu7ZpaV4NeO0s71Y
363 Usi1wGZZL0LveZjUN0t6OU1VZKSG8R5Ly7urjaSo1pPVIq5Rtt/H7W14Lecd+cUeKb4j
364 oeusC9drN3AA8a4oykcVpt1wVqUnTbMGC9ARMCQP6eopcs1l7tzMseprW4RDNhIuz3CR
365 gd0QBMPl6VDoFgBPB8vxtJw+3m0rqBYZCLZgCXekqlny8s2s92nJMuUABbJOEcDRarzi
366 bDsSXsfJt1y+5n7yOURsC7lovMg4GF/vCl/0YMKjBO5bpv9EM5fToeKYyPGSKQoHOnCY
367 ceb3cAVcv5UawcCic8XjhEhp4K7WPdYf2HVAC/qtxhbpjTxG4U5Q/SoppOJ60WqEkQvb
368 Xs6n5Dvy7xmph6GWmU/bAv3eUK3pdD3xa2Ue1lHWz3U+rsYraI+AKYsMYx3RBlfAmCeC
369 1ve2BXPrqnOo7G8tnUvfdYPbK4Aakk0ds/AVqFHEZN+S6hRBmBjLaRFWZ3QSO1NjbBxW
370 naHKZYT7nkrJm8AMCgZU0ZArFLpaufKCeiK5ECSsDxic4FIsY1OkWT42qEUfL0Wd+150
371 AKGNZpPJnnP3QYY4W/MWcKH/zdO400+zWN52WevbSqZy90tqKDJrBkMl1ydqbuw1E4ZH
372 vIs=
373 - BFhtdnm8uXx7kn79RFL/zJywmzLkT1GY78P3bOtp4WghUFWobkifSu7ZpaV4NeO0s71Y
374 Usi1wGZZL0LveZjUN0t6OU1VZKSG8R5Ly7urjaSo1pPVIq5Rtt/H7W14Lecd+cUeKb4j
375 oeusC9drN3AA8a4oykcVpt1wVqUnTbMGC9ARMCQP6eopcs1l7tzMseprW4RDNhIuz3CR
376 gd0QBMPl6VDoFgBPB8vxtJw+3m0rqBYZCLZgCXekqlny8s2s92nJMuUABbJOEcDRarzi
377 bDsSXsfJt1y+5n7yOURsC7lovMg4GF/vCl/0YMKjBO5bpv9EM5fToeKYyPGSKQoHOnCY
378 ceb3cAVcv5UawcCic8XjhEhp4K7WPdYf2HVAC/qtxhbpjTxG4U5Q/SoppOJ60WqEkQvb
379 Xs6n5Dvy7xmph6GWmU/bAv3eUK3pdD3xa2Ue1lHWz3U+rsYraI+AKYsMYx3RBlfAmCeC
380 1ve2BXPrqnOo7G8tnUvfdYPbK4Aakk0ds/AVqFHEZN+S6hRBmBjLaRFWZ3QSO1NjbBxW
381 naHKZYT7nkrJm8AMCgZU0ZArFLpaufKCeiK5ECSsDxic4FIsY1OkWT42qEUfL0Wd+150
382 AKGNZpPJnnP3QYY4W/MWcKH/zdO400+zWN52WevbSqZy90tqKDJrBkMl1ydqbuw1E4ZH
383 vIs=
James E. Blair717e8e92017-03-17 11:03:27 -0700384 password: !encrypted/pkcs1-oaep |
James E. Blair9118c012017-08-03 11:19:16 -0700385 BFhtdnm8uXx7kn79RFL/zJywmzLkT1GY78P3bOtp4WghUFWobkifSu7ZpaV4NeO0s71Y
386 Usi1wGZZL0LveZjUN0t6OU1VZKSG8R5Ly7urjaSo1pPVIq5Rtt/H7W14Lecd+cUeKb4j
387 oeusC9drN3AA8a4oykcVpt1wVqUnTbMGC9ARMCQP6eopcs1l7tzMseprW4RDNhIuz3CR
388 gd0QBMPl6VDoFgBPB8vxtJw+3m0rqBYZCLZgCXekqlny8s2s92nJMuUABbJOEcDRarzi
389 bDsSXsfJt1y+5n7yOURsC7lovMg4GF/vCl/0YMKjBO5bpv9EM5fToeKYyPGSKQoHOnCY
390 ceb3cAVcv5UawcCic8XjhEhp4K7WPdYf2HVAC/qtxhbpjTxG4U5Q/SoppOJ60WqEkQvb
391 Xs6n5Dvy7xmph6GWmU/bAv3eUK3pdD3xa2Ue1lHWz3U+rsYraI+AKYsMYx3RBlfAmCeC
392 1ve2BXPrqnOo7G8tnUvfdYPbK4Aakk0ds/AVqFHEZN+S6hRBmBjLaRFWZ3QSO1NjbBxW
393 naHKZYT7nkrJm8AMCgZU0ZArFLpaufKCeiK5ECSsDxic4FIsY1OkWT42qEUfL0Wd+150
394 AKGNZpPJnnP3QYY4W/MWcKH/zdO400+zWN52WevbSqZy90tqKDJrBkMl1ydqbuw1E4ZH
395 vIs=
James E. Blair01f83b72017-03-15 13:03:40 -0700396''')[0]['secret']
397
398 conf['_source_context'] = self.context
399 conf['_start_mark'] = self.start_mark
400
James E. Blair892cca62017-08-09 11:36:58 -0700401 trusted_secret = configloader.SecretParser.fromYaml(layout, conf)
402 layout.addSecret(trusted_secret)
403
404 conf['name'] = 'untrusted-secret'
405 conf['_source_context'] = self.untrusted_context
406
407 untrusted_secret = configloader.SecretParser.fromYaml(layout, conf)
408 layout.addSecret(untrusted_secret)
James E. Blair01f83b72017-03-15 13:03:40 -0700409
James E. Blair6459db12017-06-29 14:57:20 -0700410 base = configloader.JobParser.fromYaml(self.tenant, self.layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800411 '_source_context': self.context,
412 '_start_mark': self.start_mark,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000413 'name': 'base',
James E. Blair2bab6e72017-08-07 09:52:45 -0700414 'parent': None,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000415 'timeout': 30,
416 })
417 layout.addJob(base)
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000418
James E. Blair892cca62017-08-09 11:36:58 -0700419 trusted_secrets_job = configloader.JobParser.fromYaml(
420 tenant, layout, {
421 '_source_context': self.context,
422 '_start_mark': self.start_mark,
423 'name': 'trusted-secrets',
424 'parent': 'base',
425 'timeout': 40,
James E. Blaire19e88a2017-08-09 15:14:29 -0700426 'secrets': [
427 'trusted-secret',
428 ]
James E. Blair892cca62017-08-09 11:36:58 -0700429 })
430 layout.addJob(trusted_secrets_job)
431 untrusted_secrets_job = configloader.JobParser.fromYaml(
432 tenant, layout, {
433 '_source_context': self.untrusted_context,
434 '_start_mark': self.start_mark,
435 'name': 'untrusted-secrets',
436 'parent': 'base',
437 'timeout': 40,
James E. Blaire19e88a2017-08-09 15:14:29 -0700438 'secrets': [
439 'untrusted-secret',
440 ]
James E. Blair892cca62017-08-09 11:36:58 -0700441 })
442 layout.addJob(untrusted_secrets_job)
443 trusted_secrets_trusted_child_job = configloader.JobParser.fromYaml(
444 tenant, layout, {
445 '_source_context': self.context,
446 '_start_mark': self.start_mark,
447 'name': 'trusted-secrets-trusted-child',
448 'parent': 'trusted-secrets',
449 })
450 layout.addJob(trusted_secrets_trusted_child_job)
451 trusted_secrets_untrusted_child_job = configloader.JobParser.fromYaml(
452 tenant, layout, {
453 '_source_context': self.untrusted_context,
454 '_start_mark': self.start_mark,
455 'name': 'trusted-secrets-untrusted-child',
456 'parent': 'trusted-secrets',
457 })
458 layout.addJob(trusted_secrets_untrusted_child_job)
459 untrusted_secrets_trusted_child_job = configloader.JobParser.fromYaml(
460 tenant, layout, {
461 '_source_context': self.context,
462 '_start_mark': self.start_mark,
463 'name': 'untrusted-secrets-trusted-child',
464 'parent': 'untrusted-secrets',
465 })
466 layout.addJob(untrusted_secrets_trusted_child_job)
467 untrusted_secrets_untrusted_child_job = \
468 configloader.JobParser.fromYaml(
469 tenant, layout, {
470 '_source_context': self.untrusted_context,
471 '_start_mark': self.start_mark,
472 'name': 'untrusted-secrets-untrusted-child',
473 'parent': 'untrusted-secrets',
474 })
475 layout.addJob(untrusted_secrets_untrusted_child_job)
476
James E. Blair8eb564a2017-08-10 09:21:41 -0700477 self.assertIsNone(trusted_secrets_job.post_review)
478 self.assertTrue(untrusted_secrets_job.post_review)
James E. Blair892cca62017-08-09 11:36:58 -0700479 self.assertIsNone(
James E. Blair8eb564a2017-08-10 09:21:41 -0700480 trusted_secrets_trusted_child_job.post_review)
James E. Blair892cca62017-08-09 11:36:58 -0700481 self.assertIsNone(
James E. Blair8eb564a2017-08-10 09:21:41 -0700482 trusted_secrets_untrusted_child_job.post_review)
James E. Blair892cca62017-08-09 11:36:58 -0700483 self.assertTrue(
James E. Blair8eb564a2017-08-10 09:21:41 -0700484 untrusted_secrets_trusted_child_job.post_review)
James E. Blair892cca62017-08-09 11:36:58 -0700485 self.assertTrue(
James E. Blair8eb564a2017-08-10 09:21:41 -0700486 untrusted_secrets_untrusted_child_job.post_review)
James E. Blair892cca62017-08-09 11:36:58 -0700487
488 self.assertEqual(trusted_secrets_job.implied_run[0].secrets[0].name,
489 'trusted-secret')
490 self.assertEqual(trusted_secrets_job.implied_run[0].secrets[0].
James E. Blair9118c012017-08-03 11:19:16 -0700491 secret_data['longpassword'],
492 'test-passwordtest-password')
James E. Blair892cca62017-08-09 11:36:58 -0700493 self.assertEqual(trusted_secrets_job.implied_run[0].secrets[0].
James E. Blair9118c012017-08-03 11:19:16 -0700494 secret_data['password'],
495 'test-password')
James E. Blair892cca62017-08-09 11:36:58 -0700496 self.assertEqual(
497 len(trusted_secrets_trusted_child_job.implied_run[0].secrets), 0)
498 self.assertEqual(
499 len(trusted_secrets_untrusted_child_job.implied_run[0].secrets), 0)
500
501 self.assertEqual(untrusted_secrets_job.implied_run[0].secrets[0].name,
502 'untrusted-secret')
503 self.assertEqual(
504 len(untrusted_secrets_trusted_child_job.implied_run[0].secrets), 0)
505 self.assertEqual(
506 len(untrusted_secrets_untrusted_child_job.implied_run[0].secrets),
507 0)
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000508
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700509 def test_job_inheritance_job_tree(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800510 tenant = model.Tenant('tenant')
James E. Blair6459db12017-06-29 14:57:20 -0700511 layout = model.Layout(tenant)
James E. Blairaf8b2082017-10-03 15:38:27 -0700512
James E. Blair08d9b782017-06-29 14:22:48 -0700513 tpc = model.TenantProjectConfig(self.project)
514 tenant.addUntrustedProject(tpc)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700515
516 pipeline = model.Pipeline('gate', layout)
517 layout.addPipeline(pipeline)
518 queue = model.ChangeQueue(pipeline)
519
James E. Blair5ac93842017-01-20 06:47:34 -0800520 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800521 '_source_context': self.context,
522 '_start_mark': self.start_mark,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700523 'name': 'base',
James E. Blair2bab6e72017-08-07 09:52:45 -0700524 'parent': None,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700525 'timeout': 30,
526 })
527 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800528 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800529 '_source_context': self.context,
530 '_start_mark': self.start_mark,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700531 'name': 'python27',
532 'parent': 'base',
533 'timeout': 40,
534 })
535 layout.addJob(python27)
James E. Blair5ac93842017-01-20 06:47:34 -0800536 python27diablo = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800537 '_source_context': self.context,
538 '_start_mark': self.start_mark,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700539 'name': 'python27',
540 'branches': [
541 'stable/diablo'
542 ],
543 'timeout': 50,
544 })
545 layout.addJob(python27diablo)
546
James E. Blairaf8b2082017-10-03 15:38:27 -0700547 project_template_parser = configloader.ProjectTemplateParser(
548 tenant, layout)
549 project_parser = configloader.ProjectParser(
550 tenant, layout, project_template_parser)
551 project_config = project_parser.fromYaml([{
James E. Blairec7ff302017-03-04 07:31:32 -0800552 '_source_context': self.context,
553 '_start_mark': self.start_mark,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700554 'name': 'project',
555 'gate': {
556 'jobs': [
557 {'python27': {'timeout': 70}}
558 ]
559 }
James E. Blairff555742017-02-19 11:34:27 -0800560 }])
James E. Blairf59f3cf2017-02-19 14:50:26 -0800561 layout.addProjectConfig(project_config)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700562
James E. Blairec7ff302017-03-04 07:31:32 -0800563 change = model.Change(self.project)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700564 change.branch = 'master'
565 item = queue.enqueueChange(change)
James E. Blair29a24fd2017-10-02 15:04:56 -0700566 item.layout = layout
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700567
568 self.assertTrue(base.changeMatches(change))
569 self.assertTrue(python27.changeMatches(change))
570 self.assertFalse(python27diablo.changeMatches(change))
571
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200572 item.freezeJobGraph()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700573 self.assertEqual(len(item.getJobs()), 1)
574 job = item.getJobs()[0]
575 self.assertEqual(job.name, 'python27')
576 self.assertEqual(job.timeout, 70)
577
578 change.branch = 'stable/diablo'
579 item = queue.enqueueChange(change)
James E. Blair29a24fd2017-10-02 15:04:56 -0700580 item.layout = layout
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700581
582 self.assertTrue(base.changeMatches(change))
583 self.assertTrue(python27.changeMatches(change))
584 self.assertTrue(python27diablo.changeMatches(change))
585
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200586 item.freezeJobGraph()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700587 self.assertEqual(len(item.getJobs()), 1)
588 job = item.getJobs()[0]
589 self.assertEqual(job.name, 'python27')
590 self.assertEqual(job.timeout, 70)
591
Clint Byrum85493602016-11-18 11:59:47 -0800592 def test_inheritance_keeps_matchers(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800593 tenant = model.Tenant('tenant')
James E. Blair6459db12017-06-29 14:57:20 -0700594 layout = model.Layout(tenant)
Clint Byrum85493602016-11-18 11:59:47 -0800595
596 pipeline = model.Pipeline('gate', layout)
597 layout.addPipeline(pipeline)
598 queue = model.ChangeQueue(pipeline)
James E. Blair0a899752017-03-29 13:22:16 -0700599 project = model.Project('project', self.source)
James E. Blair08d9b782017-06-29 14:22:48 -0700600 tpc = model.TenantProjectConfig(project)
601 tenant.addUntrustedProject(tpc)
Clint Byrum85493602016-11-18 11:59:47 -0800602
James E. Blair5ac93842017-01-20 06:47:34 -0800603 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800604 '_source_context': self.context,
605 '_start_mark': self.start_mark,
Clint Byrum85493602016-11-18 11:59:47 -0800606 'name': 'base',
James E. Blair2bab6e72017-08-07 09:52:45 -0700607 'parent': None,
Clint Byrum85493602016-11-18 11:59:47 -0800608 'timeout': 30,
609 })
610 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800611 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800612 '_source_context': self.context,
613 '_start_mark': self.start_mark,
Clint Byrum85493602016-11-18 11:59:47 -0800614 'name': 'python27',
615 'parent': 'base',
616 'timeout': 40,
617 'irrelevant-files': ['^ignored-file$'],
618 })
619 layout.addJob(python27)
620
James E. Blairaf8b2082017-10-03 15:38:27 -0700621 project_template_parser = configloader.ProjectTemplateParser(
622 tenant, layout)
623 project_parser = configloader.ProjectParser(
624 tenant, layout, project_template_parser)
625 project_config = project_parser.fromYaml([{
James E. Blairec7ff302017-03-04 07:31:32 -0800626 '_source_context': self.context,
627 '_start_mark': self.start_mark,
Clint Byrum85493602016-11-18 11:59:47 -0800628 'name': 'project',
629 'gate': {
630 'jobs': [
631 'python27',
632 ]
633 }
James E. Blairff555742017-02-19 11:34:27 -0800634 }])
James E. Blairf59f3cf2017-02-19 14:50:26 -0800635 layout.addProjectConfig(project_config)
Clint Byrum85493602016-11-18 11:59:47 -0800636
637 change = model.Change(project)
638 change.branch = 'master'
639 change.files = ['/COMMIT_MSG', 'ignored-file']
640 item = queue.enqueueChange(change)
James E. Blair29a24fd2017-10-02 15:04:56 -0700641 item.layout = layout
Clint Byrum85493602016-11-18 11:59:47 -0800642
643 self.assertTrue(base.changeMatches(change))
644 self.assertFalse(python27.changeMatches(change))
645
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200646 item.freezeJobGraph()
Clint Byrum85493602016-11-18 11:59:47 -0800647 self.assertEqual([], item.getJobs())
648
James E. Blair4317e9f2016-07-15 10:05:47 -0700649 def test_job_source_project(self):
James E. Blair6459db12017-06-29 14:57:20 -0700650 tenant = self.tenant
651 layout = self.layout
James E. Blair0a899752017-03-29 13:22:16 -0700652 base_project = model.Project('base_project', self.source)
James E. Blair6f140c72017-03-03 10:32:07 -0800653 base_context = model.SourceContext(base_project, 'master',
654 'test', True)
James E. Blair6459db12017-06-29 14:57:20 -0700655 tpc = model.TenantProjectConfig(base_project)
656 tenant.addUntrustedProject(tpc)
James E. Blaircdab2032017-02-01 09:09:29 -0800657
James E. Blair5ac93842017-01-20 06:47:34 -0800658 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800659 '_source_context': base_context,
James E. Blairec7ff302017-03-04 07:31:32 -0800660 '_start_mark': self.start_mark,
James E. Blair2bab6e72017-08-07 09:52:45 -0700661 'parent': None,
James E. Blair4317e9f2016-07-15 10:05:47 -0700662 'name': 'base',
663 })
664 layout.addJob(base)
665
James E. Blair0a899752017-03-29 13:22:16 -0700666 other_project = model.Project('other_project', self.source)
James E. Blair6f140c72017-03-03 10:32:07 -0800667 other_context = model.SourceContext(other_project, 'master',
668 'test', True)
James E. Blair6459db12017-06-29 14:57:20 -0700669 tpc = model.TenantProjectConfig(other_project)
670 tenant.addUntrustedProject(tpc)
James E. Blair5ac93842017-01-20 06:47:34 -0800671 base2 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800672 '_source_context': other_context,
James E. Blairec7ff302017-03-04 07:31:32 -0800673 '_start_mark': self.start_mark,
James E. Blair4317e9f2016-07-15 10:05:47 -0700674 'name': 'base',
675 })
676 with testtools.ExpectedException(
677 Exception,
678 "Job base in other_project is not permitted "
679 "to shadow job base in base_project"):
680 layout.addJob(base2)
681
James E. Blairb3f5db12017-03-17 12:57:39 -0700682 def test_job_allowed_projects(self):
683 job = configloader.JobParser.fromYaml(self.tenant, self.layout, {
684 '_source_context': self.context,
685 '_start_mark': self.start_mark,
686 'name': 'job',
James E. Blair2bab6e72017-08-07 09:52:45 -0700687 'parent': None,
James E. Blairb3f5db12017-03-17 12:57:39 -0700688 'allowed-projects': ['project'],
689 })
690 self.layout.addJob(job)
691
James E. Blair0a899752017-03-29 13:22:16 -0700692 project2 = model.Project('project2', self.source)
James E. Blair08d9b782017-06-29 14:22:48 -0700693 tpc2 = model.TenantProjectConfig(project2)
694 self.tenant.addUntrustedProject(tpc2)
James E. Blairb3f5db12017-03-17 12:57:39 -0700695 context2 = model.SourceContext(project2, 'master',
696 'test', True)
697
James E. Blairaf8b2082017-10-03 15:38:27 -0700698 project_template_parser = configloader.ProjectTemplateParser(
699 self.tenant, self.layout)
700 project_parser = configloader.ProjectParser(
701 self.tenant, self.layout, project_template_parser)
702 project2_config = project_parser.fromYaml(
703 [{
James E. Blairb3f5db12017-03-17 12:57:39 -0700704 '_source_context': context2,
705 '_start_mark': self.start_mark,
706 'name': 'project2',
707 'gate': {
708 'jobs': [
709 'job'
710 ]
711 }
712 }]
713 )
714 self.layout.addProjectConfig(project2_config)
715
716 change = model.Change(project2)
717 # Test master
718 change.branch = 'master'
719 item = self.queue.enqueueChange(change)
James E. Blair29a24fd2017-10-02 15:04:56 -0700720 item.layout = self.layout
James E. Blairb3f5db12017-03-17 12:57:39 -0700721 with testtools.ExpectedException(
722 Exception,
723 "Project project2 is not allowed to run job job"):
724 item.freezeJobGraph()
725
James E. Blair8eb564a2017-08-10 09:21:41 -0700726 def test_job_pipeline_allow_untrusted_secrets(self):
727 self.pipeline.post_review = False
James E. Blaird2348362017-03-17 13:59:35 -0700728 job = configloader.JobParser.fromYaml(self.tenant, self.layout, {
729 '_source_context': self.context,
730 '_start_mark': self.start_mark,
731 'name': 'job',
James E. Blair2bab6e72017-08-07 09:52:45 -0700732 'parent': None,
James E. Blaird2348362017-03-17 13:59:35 -0700733 })
James E. Blair8eb564a2017-08-10 09:21:41 -0700734 job.post_review = True
James E. Blaird2348362017-03-17 13:59:35 -0700735
736 self.layout.addJob(job)
737
James E. Blairaf8b2082017-10-03 15:38:27 -0700738 project_template_parser = configloader.ProjectTemplateParser(
739 self.tenant, self.layout)
740 project_parser = configloader.ProjectParser(
741 self.tenant, self.layout, project_template_parser)
742 project_config = project_parser.fromYaml(
743 [{
James E. Blaird2348362017-03-17 13:59:35 -0700744 '_source_context': self.context,
745 '_start_mark': self.start_mark,
746 'name': 'project',
747 'gate': {
748 'jobs': [
749 'job'
750 ]
751 }
752 }]
753 )
754 self.layout.addProjectConfig(project_config)
755
756 change = model.Change(self.project)
757 # Test master
758 change.branch = 'master'
759 item = self.queue.enqueueChange(change)
James E. Blair29a24fd2017-10-02 15:04:56 -0700760 item.layout = self.layout
James E. Blaird2348362017-03-17 13:59:35 -0700761 with testtools.ExpectedException(
762 Exception,
James E. Blair8eb564a2017-08-10 09:21:41 -0700763 "Pre-review pipeline gate does not allow post-review job"):
James E. Blaird2348362017-03-17 13:59:35 -0700764 item.freezeJobGraph()
765
James E. Blairce8a2132016-05-19 15:21:52 -0700766
767class TestJobTimeData(BaseTestCase):
768 def setUp(self):
769 super(TestJobTimeData, self).setUp()
770 self.tmp_root = self.useFixture(fixtures.TempDir(
771 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
772 ).path
773
774 def test_empty_timedata(self):
775 path = os.path.join(self.tmp_root, 'job-name')
776 self.assertFalse(os.path.exists(path))
777 self.assertFalse(os.path.exists(path + '.tmp'))
778 td = model.JobTimeData(path)
779 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
780 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
781 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
782
783 def test_save_reload(self):
784 path = os.path.join(self.tmp_root, 'job-name')
785 self.assertFalse(os.path.exists(path))
786 self.assertFalse(os.path.exists(path + '.tmp'))
787 td = model.JobTimeData(path)
788 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
789 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
790 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
791 success_times = []
792 failure_times = []
793 results = []
794 for x in range(10):
795 success_times.append(int(random.random() * 1000))
796 failure_times.append(int(random.random() * 1000))
797 results.append(0)
798 results.append(1)
799 random.shuffle(results)
800 s = f = 0
801 for result in results:
802 if result:
803 td.add(failure_times[f], 'FAILURE')
804 f += 1
805 else:
806 td.add(success_times[s], 'SUCCESS')
807 s += 1
808 self.assertEqual(td.success_times, success_times)
809 self.assertEqual(td.failure_times, failure_times)
810 self.assertEqual(td.results, results[10:])
811 td.save()
812 self.assertTrue(os.path.exists(path))
813 self.assertFalse(os.path.exists(path + '.tmp'))
814 td = model.JobTimeData(path)
815 td.load()
816 self.assertEqual(td.success_times, success_times)
817 self.assertEqual(td.failure_times, failure_times)
818 self.assertEqual(td.results, results[10:])
819
820
821class TestTimeDataBase(BaseTestCase):
822 def setUp(self):
823 super(TestTimeDataBase, self).setUp()
824 self.tmp_root = self.useFixture(fixtures.TempDir(
825 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
826 ).path
827 self.db = model.TimeDataBase(self.tmp_root)
828
829 def test_timedatabase(self):
James E. Blairae0f23c2017-09-13 10:55:15 -0600830 pipeline = Dummy(layout=Dummy(tenant=Dummy(name='test-tenant')))
831 change = Dummy(project=Dummy(canonical_name='git.example.com/foo/bar'))
832 job = Dummy(name='job-name')
833 item = Dummy(pipeline=pipeline,
834 change=change)
835 build = Dummy(build_set=Dummy(item=item),
836 job=job)
837
838 self.assertEqual(self.db.getEstimatedTime(build), 0)
839 self.db.update(build, 50, 'SUCCESS')
840 self.assertEqual(self.db.getEstimatedTime(build), 50)
841 self.db.update(build, 100, 'SUCCESS')
842 self.assertEqual(self.db.getEstimatedTime(build), 75)
James E. Blairce8a2132016-05-19 15:21:52 -0700843 for x in range(10):
James E. Blairae0f23c2017-09-13 10:55:15 -0600844 self.db.update(build, 100, 'SUCCESS')
845 self.assertEqual(self.db.getEstimatedTime(build), 100)
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200846
847
848class TestGraph(BaseTestCase):
849 def test_job_graph_disallows_multiple_jobs_with_same_name(self):
850 graph = model.JobGraph()
851 job1 = model.Job('job')
852 job2 = model.Job('job')
853 graph.addJob(job1)
854 with testtools.ExpectedException(Exception,
855 "Job job already added"):
856 graph.addJob(job2)
857
858 def test_job_graph_disallows_circular_dependencies(self):
859 graph = model.JobGraph()
860 jobs = [model.Job('job%d' % i) for i in range(0, 10)]
861 prevjob = None
862 for j in jobs[:3]:
863 if prevjob:
864 j.dependencies = frozenset([prevjob.name])
865 graph.addJob(j)
866 prevjob = j
867 # 0 triggers 1 triggers 2 triggers 3...
868
869 # Cannot depend on itself
870 with testtools.ExpectedException(
871 Exception,
872 "Dependency cycle detected in job jobX"):
873 j = model.Job('jobX')
874 j.dependencies = frozenset([j.name])
875 graph.addJob(j)
876
877 # Disallow circular dependencies
878 with testtools.ExpectedException(
879 Exception,
880 "Dependency cycle detected in job job3"):
881 jobs[4].dependencies = frozenset([jobs[3].name])
882 graph.addJob(jobs[4])
883 jobs[3].dependencies = frozenset([jobs[4].name])
884 graph.addJob(jobs[3])
885
886 jobs[5].dependencies = frozenset([jobs[4].name])
887 graph.addJob(jobs[5])
888
889 with testtools.ExpectedException(
890 Exception,
891 "Dependency cycle detected in job job3"):
892 jobs[3].dependencies = frozenset([jobs[5].name])
893 graph.addJob(jobs[3])
894
895 jobs[3].dependencies = frozenset([jobs[2].name])
896 graph.addJob(jobs[3])
897 jobs[6].dependencies = frozenset([jobs[2].name])
898 graph.addJob(jobs[6])
James E. Blairc2a54fd2017-03-29 15:19:26 -0700899
900
901class TestTenant(BaseTestCase):
902 def test_add_project(self):
903 tenant = model.Tenant('tenant')
904 connection1 = Dummy(connection_name='dummy_connection1')
905 source1 = Dummy(canonical_hostname='git1.example.com',
906 name='dummy', # TODOv3(jeblair): remove
907 connection=connection1)
908
909 source1_project1 = model.Project('project1', source1)
James E. Blair08d9b782017-06-29 14:22:48 -0700910 source1_project1_tpc = model.TenantProjectConfig(source1_project1)
911 tenant.addConfigProject(source1_project1_tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700912 d = {'project1':
913 {'git1.example.com': source1_project1}}
914 self.assertEqual(d, tenant.projects)
915 self.assertEqual((True, source1_project1),
916 tenant.getProject('project1'))
917 self.assertEqual((True, source1_project1),
918 tenant.getProject('git1.example.com/project1'))
919
920 source1_project2 = model.Project('project2', source1)
James E. Blair08d9b782017-06-29 14:22:48 -0700921 tpc = model.TenantProjectConfig(source1_project2)
922 tenant.addUntrustedProject(tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700923 d = {'project1':
924 {'git1.example.com': source1_project1},
925 'project2':
926 {'git1.example.com': source1_project2}}
927 self.assertEqual(d, tenant.projects)
928 self.assertEqual((False, source1_project2),
929 tenant.getProject('project2'))
930 self.assertEqual((False, source1_project2),
931 tenant.getProject('git1.example.com/project2'))
932
933 connection2 = Dummy(connection_name='dummy_connection2')
934 source2 = Dummy(canonical_hostname='git2.example.com',
935 name='dummy', # TODOv3(jeblair): remove
936 connection=connection2)
937
938 source2_project1 = model.Project('project1', source2)
James E. Blair08d9b782017-06-29 14:22:48 -0700939 tpc = model.TenantProjectConfig(source2_project1)
940 tenant.addUntrustedProject(tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700941 d = {'project1':
942 {'git1.example.com': source1_project1,
943 'git2.example.com': source2_project1},
944 'project2':
945 {'git1.example.com': source1_project2}}
946 self.assertEqual(d, tenant.projects)
947 with testtools.ExpectedException(
948 Exception,
949 "Project name 'project1' is ambiguous"):
950 tenant.getProject('project1')
951 self.assertEqual((False, source1_project2),
952 tenant.getProject('project2'))
953 self.assertEqual((True, source1_project1),
954 tenant.getProject('git1.example.com/project1'))
955 self.assertEqual((False, source2_project1),
956 tenant.getProject('git2.example.com/project1'))
957
958 source2_project2 = model.Project('project2', source2)
James E. Blair08d9b782017-06-29 14:22:48 -0700959 tpc = model.TenantProjectConfig(source2_project2)
960 tenant.addConfigProject(tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700961 d = {'project1':
962 {'git1.example.com': source1_project1,
963 'git2.example.com': source2_project1},
964 'project2':
965 {'git1.example.com': source1_project2,
966 'git2.example.com': source2_project2}}
967 self.assertEqual(d, tenant.projects)
968 with testtools.ExpectedException(
969 Exception,
970 "Project name 'project1' is ambiguous"):
971 tenant.getProject('project1')
972 with testtools.ExpectedException(
973 Exception,
974 "Project name 'project2' is ambiguous"):
975 tenant.getProject('project2')
976 self.assertEqual((True, source1_project1),
977 tenant.getProject('git1.example.com/project1'))
978 self.assertEqual((False, source2_project1),
979 tenant.getProject('git2.example.com/project1'))
980 self.assertEqual((False, source1_project2),
981 tenant.getProject('git1.example.com/project2'))
982 self.assertEqual((True, source2_project2),
983 tenant.getProject('git2.example.com/project2'))
984
985 source1_project2b = model.Project('subpath/project2', source1)
James E. Blair08d9b782017-06-29 14:22:48 -0700986 tpc = model.TenantProjectConfig(source1_project2b)
987 tenant.addConfigProject(tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700988 d = {'project1':
989 {'git1.example.com': source1_project1,
990 'git2.example.com': source2_project1},
991 'project2':
992 {'git1.example.com': source1_project2,
993 'git2.example.com': source2_project2},
994 'subpath/project2':
995 {'git1.example.com': source1_project2b}}
996 self.assertEqual(d, tenant.projects)
997 self.assertEqual((False, source1_project2),
998 tenant.getProject('git1.example.com/project2'))
999 self.assertEqual((True, source2_project2),
1000 tenant.getProject('git2.example.com/project2'))
1001 self.assertEqual((True, source1_project2b),
1002 tenant.getProject('subpath/project2'))
1003 self.assertEqual(
1004 (True, source1_project2b),
1005 tenant.getProject('git1.example.com/subpath/project2'))
1006
1007 source2_project2b = model.Project('subpath/project2', source2)
James E. Blair08d9b782017-06-29 14:22:48 -07001008 tpc = model.TenantProjectConfig(source2_project2b)
1009 tenant.addConfigProject(tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -07001010 d = {'project1':
1011 {'git1.example.com': source1_project1,
1012 'git2.example.com': source2_project1},
1013 'project2':
1014 {'git1.example.com': source1_project2,
1015 'git2.example.com': source2_project2},
1016 'subpath/project2':
1017 {'git1.example.com': source1_project2b,
1018 'git2.example.com': source2_project2b}}
1019 self.assertEqual(d, tenant.projects)
1020 self.assertEqual((False, source1_project2),
1021 tenant.getProject('git1.example.com/project2'))
1022 self.assertEqual((True, source2_project2),
1023 tenant.getProject('git2.example.com/project2'))
1024 with testtools.ExpectedException(
1025 Exception,
1026 "Project name 'subpath/project2' is ambiguous"):
1027 tenant.getProject('subpath/project2')
1028 self.assertEqual(
1029 (True, source1_project2b),
1030 tenant.getProject('git1.example.com/subpath/project2'))
1031 self.assertEqual(
1032 (True, source2_project2b),
1033 tenant.getProject('git2.example.com/subpath/project2'))
1034
1035 with testtools.ExpectedException(
1036 Exception,
1037 "Project project1 is already in project index"):
James E. Blair08d9b782017-06-29 14:22:48 -07001038 tenant._addProject(source1_project1_tpc)