blob: 6dd83337c33ac24e55c4f0bc4cfed1a6a407e0ed [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. Blair1774dd52017-02-03 10:52:32 -0800193 'nodes': [{
194 'name': 'controller',
James E. Blair16d96a02017-06-08 11:32:56 -0700195 'label': 'base',
James E. Blair1774dd52017-02-03 10:52:32 -0800196 }],
James E. Blair83005782015-12-11 14:46:03 -0800197 })
198 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800199 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800200 '_source_context': self.context,
201 '_start_mark': self.start_mark,
James E. Blair83005782015-12-11 14:46:03 -0800202 'name': 'python27',
203 'parent': 'base',
James E. Blaira7f51ca2017-02-07 16:01:26 -0800204 'pre-run': 'py27-pre',
Paul Belanger3ae0eee2017-08-23 13:12:00 -0400205 'post-run': ['py27-post-a', 'py27-post-b'],
James E. Blair1774dd52017-02-03 10:52:32 -0800206 'nodes': [{
207 'name': 'controller',
James E. Blair16d96a02017-06-08 11:32:56 -0700208 'label': 'new',
James E. Blair1774dd52017-02-03 10:52:32 -0800209 }],
James E. Blair83005782015-12-11 14:46:03 -0800210 'timeout': 40,
211 })
212 layout.addJob(python27)
James E. Blair5ac93842017-01-20 06:47:34 -0800213 python27diablo = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800214 '_source_context': self.context,
215 '_start_mark': self.start_mark,
James E. Blair83005782015-12-11 14:46:03 -0800216 'name': 'python27',
217 'branches': [
218 'stable/diablo'
219 ],
James E. Blaira7f51ca2017-02-07 16:01:26 -0800220 'pre-run': 'py27-diablo-pre',
221 'run': 'py27-diablo',
222 'post-run': 'py27-diablo-post',
James E. Blair1774dd52017-02-03 10:52:32 -0800223 'nodes': [{
224 'name': 'controller',
James E. Blair16d96a02017-06-08 11:32:56 -0700225 'label': 'old',
James E. Blair1774dd52017-02-03 10:52:32 -0800226 }],
James E. Blair83005782015-12-11 14:46:03 -0800227 'timeout': 50,
228 })
229 layout.addJob(python27diablo)
230
James E. Blair5ac93842017-01-20 06:47:34 -0800231 python27essex = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800232 '_source_context': self.context,
233 '_start_mark': self.start_mark,
James E. Blaira7f51ca2017-02-07 16:01:26 -0800234 'name': 'python27',
235 'branches': [
236 'stable/essex'
237 ],
238 'pre-run': 'py27-essex-pre',
239 'post-run': 'py27-essex-post',
240 })
241 layout.addJob(python27essex)
242
James E. Blairff555742017-02-19 11:34:27 -0800243 project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
James E. Blairec7ff302017-03-04 07:31:32 -0800244 '_source_context': self.context,
245 '_start_mark': self.start_mark,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700246 'name': 'project',
247 'gate': {
248 'jobs': [
249 'python27'
250 ]
251 }
James E. Blairff555742017-02-19 11:34:27 -0800252 }])
James E. Blairf59f3cf2017-02-19 14:50:26 -0800253 layout.addProjectConfig(project_config)
James E. Blair83005782015-12-11 14:46:03 -0800254
James E. Blair83005782015-12-11 14:46:03 -0800255 change = model.Change(project)
James E. Blair1774dd52017-02-03 10:52:32 -0800256 # Test master
James E. Blair83005782015-12-11 14:46:03 -0800257 change.branch = 'master'
258 item = queue.enqueueChange(change)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700259 item.current_build_set.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800260
261 self.assertTrue(base.changeMatches(change))
262 self.assertTrue(python27.changeMatches(change))
263 self.assertFalse(python27diablo.changeMatches(change))
James E. Blaira7f51ca2017-02-07 16:01:26 -0800264 self.assertFalse(python27essex.changeMatches(change))
James E. Blair83005782015-12-11 14:46:03 -0800265
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200266 item.freezeJobGraph()
James E. Blair83005782015-12-11 14:46:03 -0800267 self.assertEqual(len(item.getJobs()), 1)
268 job = item.getJobs()[0]
269 self.assertEqual(job.name, 'python27')
270 self.assertEqual(job.timeout, 40)
James E. Blair1774dd52017-02-03 10:52:32 -0800271 nodes = job.nodeset.getNodes()
272 self.assertEqual(len(nodes), 1)
James E. Blair16d96a02017-06-08 11:32:56 -0700273 self.assertEqual(nodes[0].label, 'new')
James E. Blaira7f51ca2017-02-07 16:01:26 -0800274 self.assertEqual([x.path for x in job.pre_run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200275 ['base-pre',
276 'py27-pre'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800277 self.assertEqual([x.path for x in job.post_run],
Paul Belanger3ae0eee2017-08-23 13:12:00 -0400278 ['py27-post-a',
279 'py27-post-b',
Tobias Henkel165450e2017-06-26 22:53:45 +0200280 'base-post'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800281 self.assertEqual([x.path for x in job.run],
282 ['playbooks/python27',
283 'playbooks/base'])
James E. Blair83005782015-12-11 14:46:03 -0800284
James E. Blair1774dd52017-02-03 10:52:32 -0800285 # Test diablo
James E. Blair83005782015-12-11 14:46:03 -0800286 change.branch = 'stable/diablo'
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700287 item = queue.enqueueChange(change)
288 item.current_build_set.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800289
290 self.assertTrue(base.changeMatches(change))
291 self.assertTrue(python27.changeMatches(change))
292 self.assertTrue(python27diablo.changeMatches(change))
James E. Blaira7f51ca2017-02-07 16:01:26 -0800293 self.assertFalse(python27essex.changeMatches(change))
James E. Blair83005782015-12-11 14:46:03 -0800294
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200295 item.freezeJobGraph()
James E. Blair83005782015-12-11 14:46:03 -0800296 self.assertEqual(len(item.getJobs()), 1)
297 job = item.getJobs()[0]
298 self.assertEqual(job.name, 'python27')
299 self.assertEqual(job.timeout, 50)
James E. Blair1774dd52017-02-03 10:52:32 -0800300 nodes = job.nodeset.getNodes()
301 self.assertEqual(len(nodes), 1)
James E. Blair16d96a02017-06-08 11:32:56 -0700302 self.assertEqual(nodes[0].label, 'old')
James E. Blaira7f51ca2017-02-07 16:01:26 -0800303 self.assertEqual([x.path for x in job.pre_run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200304 ['base-pre',
305 'py27-pre',
306 'py27-diablo-pre'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800307 self.assertEqual([x.path for x in job.post_run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200308 ['py27-diablo-post',
Paul Belanger3ae0eee2017-08-23 13:12:00 -0400309 'py27-post-a',
310 'py27-post-b',
Tobias Henkel165450e2017-06-26 22:53:45 +0200311 'base-post'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800312 self.assertEqual([x.path for x in job.run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200313 ['py27-diablo']),
James E. Blaira7f51ca2017-02-07 16:01:26 -0800314
315 # Test essex
316 change.branch = 'stable/essex'
317 item = queue.enqueueChange(change)
318 item.current_build_set.layout = layout
319
320 self.assertTrue(base.changeMatches(change))
321 self.assertTrue(python27.changeMatches(change))
322 self.assertFalse(python27diablo.changeMatches(change))
323 self.assertTrue(python27essex.changeMatches(change))
324
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200325 item.freezeJobGraph()
James E. Blaira7f51ca2017-02-07 16:01:26 -0800326 self.assertEqual(len(item.getJobs()), 1)
327 job = item.getJobs()[0]
328 self.assertEqual(job.name, 'python27')
329 self.assertEqual([x.path for x in job.pre_run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200330 ['base-pre',
331 'py27-pre',
332 'py27-essex-pre'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800333 self.assertEqual([x.path for x in job.post_run],
Tobias Henkel165450e2017-06-26 22:53:45 +0200334 ['py27-essex-post',
Paul Belanger3ae0eee2017-08-23 13:12:00 -0400335 'py27-post-a',
336 'py27-post-b',
Tobias Henkel165450e2017-06-26 22:53:45 +0200337 'base-post'])
James E. Blaira7f51ca2017-02-07 16:01:26 -0800338 self.assertEqual([x.path for x in job.run],
339 ['playbooks/python27',
340 'playbooks/base'])
James E. Blairce8a2132016-05-19 15:21:52 -0700341
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000342 def test_job_auth_inheritance(self):
James E. Blair6459db12017-06-29 14:57:20 -0700343 tenant = self.tenant
344 layout = self.layout
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000345
James E. Blair01f83b72017-03-15 13:03:40 -0700346 conf = yaml.safe_load('''
347- secret:
James E. Blair892cca62017-08-09 11:36:58 -0700348 name: trusted-secret
James E. Blair01f83b72017-03-15 13:03:40 -0700349 data:
350 username: test-username
James E. Blair9118c012017-08-03 11:19:16 -0700351 longpassword: !encrypted/pkcs1-oaep
352 - BFhtdnm8uXx7kn79RFL/zJywmzLkT1GY78P3bOtp4WghUFWobkifSu7ZpaV4NeO0s71Y
353 Usi1wGZZL0LveZjUN0t6OU1VZKSG8R5Ly7urjaSo1pPVIq5Rtt/H7W14Lecd+cUeKb4j
354 oeusC9drN3AA8a4oykcVpt1wVqUnTbMGC9ARMCQP6eopcs1l7tzMseprW4RDNhIuz3CR
355 gd0QBMPl6VDoFgBPB8vxtJw+3m0rqBYZCLZgCXekqlny8s2s92nJMuUABbJOEcDRarzi
356 bDsSXsfJt1y+5n7yOURsC7lovMg4GF/vCl/0YMKjBO5bpv9EM5fToeKYyPGSKQoHOnCY
357 ceb3cAVcv5UawcCic8XjhEhp4K7WPdYf2HVAC/qtxhbpjTxG4U5Q/SoppOJ60WqEkQvb
358 Xs6n5Dvy7xmph6GWmU/bAv3eUK3pdD3xa2Ue1lHWz3U+rsYraI+AKYsMYx3RBlfAmCeC
359 1ve2BXPrqnOo7G8tnUvfdYPbK4Aakk0ds/AVqFHEZN+S6hRBmBjLaRFWZ3QSO1NjbBxW
360 naHKZYT7nkrJm8AMCgZU0ZArFLpaufKCeiK5ECSsDxic4FIsY1OkWT42qEUfL0Wd+150
361 AKGNZpPJnnP3QYY4W/MWcKH/zdO400+zWN52WevbSqZy90tqKDJrBkMl1ydqbuw1E4ZH
362 vIs=
363 - BFhtdnm8uXx7kn79RFL/zJywmzLkT1GY78P3bOtp4WghUFWobkifSu7ZpaV4NeO0s71Y
364 Usi1wGZZL0LveZjUN0t6OU1VZKSG8R5Ly7urjaSo1pPVIq5Rtt/H7W14Lecd+cUeKb4j
365 oeusC9drN3AA8a4oykcVpt1wVqUnTbMGC9ARMCQP6eopcs1l7tzMseprW4RDNhIuz3CR
366 gd0QBMPl6VDoFgBPB8vxtJw+3m0rqBYZCLZgCXekqlny8s2s92nJMuUABbJOEcDRarzi
367 bDsSXsfJt1y+5n7yOURsC7lovMg4GF/vCl/0YMKjBO5bpv9EM5fToeKYyPGSKQoHOnCY
368 ceb3cAVcv5UawcCic8XjhEhp4K7WPdYf2HVAC/qtxhbpjTxG4U5Q/SoppOJ60WqEkQvb
369 Xs6n5Dvy7xmph6GWmU/bAv3eUK3pdD3xa2Ue1lHWz3U+rsYraI+AKYsMYx3RBlfAmCeC
370 1ve2BXPrqnOo7G8tnUvfdYPbK4Aakk0ds/AVqFHEZN+S6hRBmBjLaRFWZ3QSO1NjbBxW
371 naHKZYT7nkrJm8AMCgZU0ZArFLpaufKCeiK5ECSsDxic4FIsY1OkWT42qEUfL0Wd+150
372 AKGNZpPJnnP3QYY4W/MWcKH/zdO400+zWN52WevbSqZy90tqKDJrBkMl1ydqbuw1E4ZH
373 vIs=
James E. Blair717e8e92017-03-17 11:03:27 -0700374 password: !encrypted/pkcs1-oaep |
James E. Blair9118c012017-08-03 11:19:16 -0700375 BFhtdnm8uXx7kn79RFL/zJywmzLkT1GY78P3bOtp4WghUFWobkifSu7ZpaV4NeO0s71Y
376 Usi1wGZZL0LveZjUN0t6OU1VZKSG8R5Ly7urjaSo1pPVIq5Rtt/H7W14Lecd+cUeKb4j
377 oeusC9drN3AA8a4oykcVpt1wVqUnTbMGC9ARMCQP6eopcs1l7tzMseprW4RDNhIuz3CR
378 gd0QBMPl6VDoFgBPB8vxtJw+3m0rqBYZCLZgCXekqlny8s2s92nJMuUABbJOEcDRarzi
379 bDsSXsfJt1y+5n7yOURsC7lovMg4GF/vCl/0YMKjBO5bpv9EM5fToeKYyPGSKQoHOnCY
380 ceb3cAVcv5UawcCic8XjhEhp4K7WPdYf2HVAC/qtxhbpjTxG4U5Q/SoppOJ60WqEkQvb
381 Xs6n5Dvy7xmph6GWmU/bAv3eUK3pdD3xa2Ue1lHWz3U+rsYraI+AKYsMYx3RBlfAmCeC
382 1ve2BXPrqnOo7G8tnUvfdYPbK4Aakk0ds/AVqFHEZN+S6hRBmBjLaRFWZ3QSO1NjbBxW
383 naHKZYT7nkrJm8AMCgZU0ZArFLpaufKCeiK5ECSsDxic4FIsY1OkWT42qEUfL0Wd+150
384 AKGNZpPJnnP3QYY4W/MWcKH/zdO400+zWN52WevbSqZy90tqKDJrBkMl1ydqbuw1E4ZH
385 vIs=
James E. Blair01f83b72017-03-15 13:03:40 -0700386''')[0]['secret']
387
388 conf['_source_context'] = self.context
389 conf['_start_mark'] = self.start_mark
390
James E. Blair892cca62017-08-09 11:36:58 -0700391 trusted_secret = configloader.SecretParser.fromYaml(layout, conf)
392 layout.addSecret(trusted_secret)
393
394 conf['name'] = 'untrusted-secret'
395 conf['_source_context'] = self.untrusted_context
396
397 untrusted_secret = configloader.SecretParser.fromYaml(layout, conf)
398 layout.addSecret(untrusted_secret)
James E. Blair01f83b72017-03-15 13:03:40 -0700399
James E. Blair6459db12017-06-29 14:57:20 -0700400 base = configloader.JobParser.fromYaml(self.tenant, self.layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800401 '_source_context': self.context,
402 '_start_mark': self.start_mark,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000403 'name': 'base',
James E. Blair2bab6e72017-08-07 09:52:45 -0700404 'parent': None,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000405 'timeout': 30,
406 })
407 layout.addJob(base)
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000408
James E. Blair892cca62017-08-09 11:36:58 -0700409 trusted_secrets_job = configloader.JobParser.fromYaml(
410 tenant, layout, {
411 '_source_context': self.context,
412 '_start_mark': self.start_mark,
413 'name': 'trusted-secrets',
414 'parent': 'base',
415 'timeout': 40,
James E. Blaire19e88a2017-08-09 15:14:29 -0700416 'secrets': [
417 'trusted-secret',
418 ]
James E. Blair892cca62017-08-09 11:36:58 -0700419 })
420 layout.addJob(trusted_secrets_job)
421 untrusted_secrets_job = configloader.JobParser.fromYaml(
422 tenant, layout, {
423 '_source_context': self.untrusted_context,
424 '_start_mark': self.start_mark,
425 'name': 'untrusted-secrets',
426 'parent': 'base',
427 'timeout': 40,
James E. Blaire19e88a2017-08-09 15:14:29 -0700428 'secrets': [
429 'untrusted-secret',
430 ]
James E. Blair892cca62017-08-09 11:36:58 -0700431 })
432 layout.addJob(untrusted_secrets_job)
433 trusted_secrets_trusted_child_job = configloader.JobParser.fromYaml(
434 tenant, layout, {
435 '_source_context': self.context,
436 '_start_mark': self.start_mark,
437 'name': 'trusted-secrets-trusted-child',
438 'parent': 'trusted-secrets',
439 })
440 layout.addJob(trusted_secrets_trusted_child_job)
441 trusted_secrets_untrusted_child_job = configloader.JobParser.fromYaml(
442 tenant, layout, {
443 '_source_context': self.untrusted_context,
444 '_start_mark': self.start_mark,
445 'name': 'trusted-secrets-untrusted-child',
446 'parent': 'trusted-secrets',
447 })
448 layout.addJob(trusted_secrets_untrusted_child_job)
449 untrusted_secrets_trusted_child_job = configloader.JobParser.fromYaml(
450 tenant, layout, {
451 '_source_context': self.context,
452 '_start_mark': self.start_mark,
453 'name': 'untrusted-secrets-trusted-child',
454 'parent': 'untrusted-secrets',
455 })
456 layout.addJob(untrusted_secrets_trusted_child_job)
457 untrusted_secrets_untrusted_child_job = \
458 configloader.JobParser.fromYaml(
459 tenant, layout, {
460 '_source_context': self.untrusted_context,
461 '_start_mark': self.start_mark,
462 'name': 'untrusted-secrets-untrusted-child',
463 'parent': 'untrusted-secrets',
464 })
465 layout.addJob(untrusted_secrets_untrusted_child_job)
466
James E. Blair8eb564a2017-08-10 09:21:41 -0700467 self.assertIsNone(trusted_secrets_job.post_review)
468 self.assertTrue(untrusted_secrets_job.post_review)
James E. Blair892cca62017-08-09 11:36:58 -0700469 self.assertIsNone(
James E. Blair8eb564a2017-08-10 09:21:41 -0700470 trusted_secrets_trusted_child_job.post_review)
James E. Blair892cca62017-08-09 11:36:58 -0700471 self.assertIsNone(
James E. Blair8eb564a2017-08-10 09:21:41 -0700472 trusted_secrets_untrusted_child_job.post_review)
James E. Blair892cca62017-08-09 11:36:58 -0700473 self.assertTrue(
James E. Blair8eb564a2017-08-10 09:21:41 -0700474 untrusted_secrets_trusted_child_job.post_review)
James E. Blair892cca62017-08-09 11:36:58 -0700475 self.assertTrue(
James E. Blair8eb564a2017-08-10 09:21:41 -0700476 untrusted_secrets_untrusted_child_job.post_review)
James E. Blair892cca62017-08-09 11:36:58 -0700477
478 self.assertEqual(trusted_secrets_job.implied_run[0].secrets[0].name,
479 'trusted-secret')
480 self.assertEqual(trusted_secrets_job.implied_run[0].secrets[0].
James E. Blair9118c012017-08-03 11:19:16 -0700481 secret_data['longpassword'],
482 'test-passwordtest-password')
James E. Blair892cca62017-08-09 11:36:58 -0700483 self.assertEqual(trusted_secrets_job.implied_run[0].secrets[0].
James E. Blair9118c012017-08-03 11:19:16 -0700484 secret_data['password'],
485 'test-password')
James E. Blair892cca62017-08-09 11:36:58 -0700486 self.assertEqual(
487 len(trusted_secrets_trusted_child_job.implied_run[0].secrets), 0)
488 self.assertEqual(
489 len(trusted_secrets_untrusted_child_job.implied_run[0].secrets), 0)
490
491 self.assertEqual(untrusted_secrets_job.implied_run[0].secrets[0].name,
492 'untrusted-secret')
493 self.assertEqual(
494 len(untrusted_secrets_trusted_child_job.implied_run[0].secrets), 0)
495 self.assertEqual(
496 len(untrusted_secrets_untrusted_child_job.implied_run[0].secrets),
497 0)
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000498
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700499 def test_job_inheritance_job_tree(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800500 tenant = model.Tenant('tenant')
James E. Blair6459db12017-06-29 14:57:20 -0700501 layout = model.Layout(tenant)
James E. Blair08d9b782017-06-29 14:22:48 -0700502 tpc = model.TenantProjectConfig(self.project)
503 tenant.addUntrustedProject(tpc)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700504
505 pipeline = model.Pipeline('gate', layout)
506 layout.addPipeline(pipeline)
507 queue = model.ChangeQueue(pipeline)
508
James E. Blair5ac93842017-01-20 06:47:34 -0800509 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800510 '_source_context': self.context,
511 '_start_mark': self.start_mark,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700512 'name': 'base',
James E. Blair2bab6e72017-08-07 09:52:45 -0700513 'parent': None,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700514 'timeout': 30,
515 })
516 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800517 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800518 '_source_context': self.context,
519 '_start_mark': self.start_mark,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700520 'name': 'python27',
521 'parent': 'base',
522 'timeout': 40,
523 })
524 layout.addJob(python27)
James E. Blair5ac93842017-01-20 06:47:34 -0800525 python27diablo = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800526 '_source_context': self.context,
527 '_start_mark': self.start_mark,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700528 'name': 'python27',
529 'branches': [
530 'stable/diablo'
531 ],
532 'timeout': 50,
533 })
534 layout.addJob(python27diablo)
535
James E. Blairff555742017-02-19 11:34:27 -0800536 project_config = configloader.ProjectParser.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': 'project',
540 'gate': {
541 'jobs': [
542 {'python27': {'timeout': 70}}
543 ]
544 }
James E. Blairff555742017-02-19 11:34:27 -0800545 }])
James E. Blairf59f3cf2017-02-19 14:50:26 -0800546 layout.addProjectConfig(project_config)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700547
James E. Blairec7ff302017-03-04 07:31:32 -0800548 change = model.Change(self.project)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700549 change.branch = 'master'
550 item = queue.enqueueChange(change)
551 item.current_build_set.layout = layout
552
553 self.assertTrue(base.changeMatches(change))
554 self.assertTrue(python27.changeMatches(change))
555 self.assertFalse(python27diablo.changeMatches(change))
556
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200557 item.freezeJobGraph()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700558 self.assertEqual(len(item.getJobs()), 1)
559 job = item.getJobs()[0]
560 self.assertEqual(job.name, 'python27')
561 self.assertEqual(job.timeout, 70)
562
563 change.branch = 'stable/diablo'
564 item = queue.enqueueChange(change)
565 item.current_build_set.layout = layout
566
567 self.assertTrue(base.changeMatches(change))
568 self.assertTrue(python27.changeMatches(change))
569 self.assertTrue(python27diablo.changeMatches(change))
570
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200571 item.freezeJobGraph()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700572 self.assertEqual(len(item.getJobs()), 1)
573 job = item.getJobs()[0]
574 self.assertEqual(job.name, 'python27')
575 self.assertEqual(job.timeout, 70)
576
Clint Byrum85493602016-11-18 11:59:47 -0800577 def test_inheritance_keeps_matchers(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800578 tenant = model.Tenant('tenant')
James E. Blair6459db12017-06-29 14:57:20 -0700579 layout = model.Layout(tenant)
Clint Byrum85493602016-11-18 11:59:47 -0800580
581 pipeline = model.Pipeline('gate', layout)
582 layout.addPipeline(pipeline)
583 queue = model.ChangeQueue(pipeline)
James E. Blair0a899752017-03-29 13:22:16 -0700584 project = model.Project('project', self.source)
James E. Blair08d9b782017-06-29 14:22:48 -0700585 tpc = model.TenantProjectConfig(project)
586 tenant.addUntrustedProject(tpc)
Clint Byrum85493602016-11-18 11:59:47 -0800587
James E. Blair5ac93842017-01-20 06:47:34 -0800588 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800589 '_source_context': self.context,
590 '_start_mark': self.start_mark,
Clint Byrum85493602016-11-18 11:59:47 -0800591 'name': 'base',
James E. Blair2bab6e72017-08-07 09:52:45 -0700592 'parent': None,
Clint Byrum85493602016-11-18 11:59:47 -0800593 'timeout': 30,
594 })
595 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800596 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blairec7ff302017-03-04 07:31:32 -0800597 '_source_context': self.context,
598 '_start_mark': self.start_mark,
Clint Byrum85493602016-11-18 11:59:47 -0800599 'name': 'python27',
600 'parent': 'base',
601 'timeout': 40,
602 'irrelevant-files': ['^ignored-file$'],
603 })
604 layout.addJob(python27)
605
James E. Blairff555742017-02-19 11:34:27 -0800606 project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
James E. Blairec7ff302017-03-04 07:31:32 -0800607 '_source_context': self.context,
608 '_start_mark': self.start_mark,
Clint Byrum85493602016-11-18 11:59:47 -0800609 'name': 'project',
610 'gate': {
611 'jobs': [
612 'python27',
613 ]
614 }
James E. Blairff555742017-02-19 11:34:27 -0800615 }])
James E. Blairf59f3cf2017-02-19 14:50:26 -0800616 layout.addProjectConfig(project_config)
Clint Byrum85493602016-11-18 11:59:47 -0800617
618 change = model.Change(project)
619 change.branch = 'master'
620 change.files = ['/COMMIT_MSG', 'ignored-file']
621 item = queue.enqueueChange(change)
622 item.current_build_set.layout = layout
623
624 self.assertTrue(base.changeMatches(change))
625 self.assertFalse(python27.changeMatches(change))
626
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200627 item.freezeJobGraph()
Clint Byrum85493602016-11-18 11:59:47 -0800628 self.assertEqual([], item.getJobs())
629
James E. Blair4317e9f2016-07-15 10:05:47 -0700630 def test_job_source_project(self):
James E. Blair6459db12017-06-29 14:57:20 -0700631 tenant = self.tenant
632 layout = self.layout
James E. Blair0a899752017-03-29 13:22:16 -0700633 base_project = model.Project('base_project', self.source)
James E. Blair6f140c72017-03-03 10:32:07 -0800634 base_context = model.SourceContext(base_project, 'master',
635 'test', True)
James E. Blair6459db12017-06-29 14:57:20 -0700636 tpc = model.TenantProjectConfig(base_project)
637 tenant.addUntrustedProject(tpc)
James E. Blaircdab2032017-02-01 09:09:29 -0800638
James E. Blair5ac93842017-01-20 06:47:34 -0800639 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800640 '_source_context': base_context,
James E. Blairec7ff302017-03-04 07:31:32 -0800641 '_start_mark': self.start_mark,
James E. Blair2bab6e72017-08-07 09:52:45 -0700642 'parent': None,
James E. Blair4317e9f2016-07-15 10:05:47 -0700643 'name': 'base',
644 })
645 layout.addJob(base)
646
James E. Blair0a899752017-03-29 13:22:16 -0700647 other_project = model.Project('other_project', self.source)
James E. Blair6f140c72017-03-03 10:32:07 -0800648 other_context = model.SourceContext(other_project, 'master',
649 'test', True)
James E. Blair6459db12017-06-29 14:57:20 -0700650 tpc = model.TenantProjectConfig(other_project)
651 tenant.addUntrustedProject(tpc)
James E. Blair5ac93842017-01-20 06:47:34 -0800652 base2 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800653 '_source_context': other_context,
James E. Blairec7ff302017-03-04 07:31:32 -0800654 '_start_mark': self.start_mark,
James E. Blair4317e9f2016-07-15 10:05:47 -0700655 'name': 'base',
656 })
657 with testtools.ExpectedException(
658 Exception,
659 "Job base in other_project is not permitted "
660 "to shadow job base in base_project"):
661 layout.addJob(base2)
662
James E. Blairb3f5db12017-03-17 12:57:39 -0700663 def test_job_allowed_projects(self):
664 job = configloader.JobParser.fromYaml(self.tenant, self.layout, {
665 '_source_context': self.context,
666 '_start_mark': self.start_mark,
667 'name': 'job',
James E. Blair2bab6e72017-08-07 09:52:45 -0700668 'parent': None,
James E. Blairb3f5db12017-03-17 12:57:39 -0700669 'allowed-projects': ['project'],
670 })
671 self.layout.addJob(job)
672
James E. Blair0a899752017-03-29 13:22:16 -0700673 project2 = model.Project('project2', self.source)
James E. Blair08d9b782017-06-29 14:22:48 -0700674 tpc2 = model.TenantProjectConfig(project2)
675 self.tenant.addUntrustedProject(tpc2)
James E. Blairb3f5db12017-03-17 12:57:39 -0700676 context2 = model.SourceContext(project2, 'master',
677 'test', True)
678
679 project2_config = configloader.ProjectParser.fromYaml(
680 self.tenant, self.layout, [{
681 '_source_context': context2,
682 '_start_mark': self.start_mark,
683 'name': 'project2',
684 'gate': {
685 'jobs': [
686 'job'
687 ]
688 }
689 }]
690 )
691 self.layout.addProjectConfig(project2_config)
692
693 change = model.Change(project2)
694 # Test master
695 change.branch = 'master'
696 item = self.queue.enqueueChange(change)
697 item.current_build_set.layout = self.layout
698 with testtools.ExpectedException(
699 Exception,
700 "Project project2 is not allowed to run job job"):
701 item.freezeJobGraph()
702
James E. Blair8eb564a2017-08-10 09:21:41 -0700703 def test_job_pipeline_allow_untrusted_secrets(self):
704 self.pipeline.post_review = False
James E. Blaird2348362017-03-17 13:59:35 -0700705 job = configloader.JobParser.fromYaml(self.tenant, self.layout, {
706 '_source_context': self.context,
707 '_start_mark': self.start_mark,
708 'name': 'job',
James E. Blair2bab6e72017-08-07 09:52:45 -0700709 'parent': None,
James E. Blaird2348362017-03-17 13:59:35 -0700710 })
James E. Blair8eb564a2017-08-10 09:21:41 -0700711 job.post_review = True
James E. Blaird2348362017-03-17 13:59:35 -0700712
713 self.layout.addJob(job)
714
715 project_config = configloader.ProjectParser.fromYaml(
716 self.tenant, self.layout, [{
717 '_source_context': self.context,
718 '_start_mark': self.start_mark,
719 'name': 'project',
720 'gate': {
721 'jobs': [
722 'job'
723 ]
724 }
725 }]
726 )
727 self.layout.addProjectConfig(project_config)
728
729 change = model.Change(self.project)
730 # Test master
731 change.branch = 'master'
732 item = self.queue.enqueueChange(change)
733 item.current_build_set.layout = self.layout
734 with testtools.ExpectedException(
735 Exception,
James E. Blair8eb564a2017-08-10 09:21:41 -0700736 "Pre-review pipeline gate does not allow post-review job"):
James E. Blaird2348362017-03-17 13:59:35 -0700737 item.freezeJobGraph()
738
James E. Blairce8a2132016-05-19 15:21:52 -0700739
740class TestJobTimeData(BaseTestCase):
741 def setUp(self):
742 super(TestJobTimeData, self).setUp()
743 self.tmp_root = self.useFixture(fixtures.TempDir(
744 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
745 ).path
746
747 def test_empty_timedata(self):
748 path = os.path.join(self.tmp_root, 'job-name')
749 self.assertFalse(os.path.exists(path))
750 self.assertFalse(os.path.exists(path + '.tmp'))
751 td = model.JobTimeData(path)
752 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
753 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
754 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
755
756 def test_save_reload(self):
757 path = os.path.join(self.tmp_root, 'job-name')
758 self.assertFalse(os.path.exists(path))
759 self.assertFalse(os.path.exists(path + '.tmp'))
760 td = model.JobTimeData(path)
761 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
762 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
763 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
764 success_times = []
765 failure_times = []
766 results = []
767 for x in range(10):
768 success_times.append(int(random.random() * 1000))
769 failure_times.append(int(random.random() * 1000))
770 results.append(0)
771 results.append(1)
772 random.shuffle(results)
773 s = f = 0
774 for result in results:
775 if result:
776 td.add(failure_times[f], 'FAILURE')
777 f += 1
778 else:
779 td.add(success_times[s], 'SUCCESS')
780 s += 1
781 self.assertEqual(td.success_times, success_times)
782 self.assertEqual(td.failure_times, failure_times)
783 self.assertEqual(td.results, results[10:])
784 td.save()
785 self.assertTrue(os.path.exists(path))
786 self.assertFalse(os.path.exists(path + '.tmp'))
787 td = model.JobTimeData(path)
788 td.load()
789 self.assertEqual(td.success_times, success_times)
790 self.assertEqual(td.failure_times, failure_times)
791 self.assertEqual(td.results, results[10:])
792
793
794class TestTimeDataBase(BaseTestCase):
795 def setUp(self):
796 super(TestTimeDataBase, self).setUp()
797 self.tmp_root = self.useFixture(fixtures.TempDir(
798 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
799 ).path
800 self.db = model.TimeDataBase(self.tmp_root)
801
802 def test_timedatabase(self):
803 self.assertEqual(self.db.getEstimatedTime('job-name'), 0)
804 self.db.update('job-name', 50, 'SUCCESS')
805 self.assertEqual(self.db.getEstimatedTime('job-name'), 50)
806 self.db.update('job-name', 100, 'SUCCESS')
807 self.assertEqual(self.db.getEstimatedTime('job-name'), 75)
808 for x in range(10):
809 self.db.update('job-name', 100, 'SUCCESS')
810 self.assertEqual(self.db.getEstimatedTime('job-name'), 100)
Fredrik Medleyf8aec832015-09-28 13:40:20 +0200811
812
813class TestGraph(BaseTestCase):
814 def test_job_graph_disallows_multiple_jobs_with_same_name(self):
815 graph = model.JobGraph()
816 job1 = model.Job('job')
817 job2 = model.Job('job')
818 graph.addJob(job1)
819 with testtools.ExpectedException(Exception,
820 "Job job already added"):
821 graph.addJob(job2)
822
823 def test_job_graph_disallows_circular_dependencies(self):
824 graph = model.JobGraph()
825 jobs = [model.Job('job%d' % i) for i in range(0, 10)]
826 prevjob = None
827 for j in jobs[:3]:
828 if prevjob:
829 j.dependencies = frozenset([prevjob.name])
830 graph.addJob(j)
831 prevjob = j
832 # 0 triggers 1 triggers 2 triggers 3...
833
834 # Cannot depend on itself
835 with testtools.ExpectedException(
836 Exception,
837 "Dependency cycle detected in job jobX"):
838 j = model.Job('jobX')
839 j.dependencies = frozenset([j.name])
840 graph.addJob(j)
841
842 # Disallow circular dependencies
843 with testtools.ExpectedException(
844 Exception,
845 "Dependency cycle detected in job job3"):
846 jobs[4].dependencies = frozenset([jobs[3].name])
847 graph.addJob(jobs[4])
848 jobs[3].dependencies = frozenset([jobs[4].name])
849 graph.addJob(jobs[3])
850
851 jobs[5].dependencies = frozenset([jobs[4].name])
852 graph.addJob(jobs[5])
853
854 with testtools.ExpectedException(
855 Exception,
856 "Dependency cycle detected in job job3"):
857 jobs[3].dependencies = frozenset([jobs[5].name])
858 graph.addJob(jobs[3])
859
860 jobs[3].dependencies = frozenset([jobs[2].name])
861 graph.addJob(jobs[3])
862 jobs[6].dependencies = frozenset([jobs[2].name])
863 graph.addJob(jobs[6])
James E. Blairc2a54fd2017-03-29 15:19:26 -0700864
865
866class TestTenant(BaseTestCase):
867 def test_add_project(self):
868 tenant = model.Tenant('tenant')
869 connection1 = Dummy(connection_name='dummy_connection1')
870 source1 = Dummy(canonical_hostname='git1.example.com',
871 name='dummy', # TODOv3(jeblair): remove
872 connection=connection1)
873
874 source1_project1 = model.Project('project1', source1)
James E. Blair08d9b782017-06-29 14:22:48 -0700875 source1_project1_tpc = model.TenantProjectConfig(source1_project1)
876 tenant.addConfigProject(source1_project1_tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700877 d = {'project1':
878 {'git1.example.com': source1_project1}}
879 self.assertEqual(d, tenant.projects)
880 self.assertEqual((True, source1_project1),
881 tenant.getProject('project1'))
882 self.assertEqual((True, source1_project1),
883 tenant.getProject('git1.example.com/project1'))
884
885 source1_project2 = model.Project('project2', source1)
James E. Blair08d9b782017-06-29 14:22:48 -0700886 tpc = model.TenantProjectConfig(source1_project2)
887 tenant.addUntrustedProject(tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700888 d = {'project1':
889 {'git1.example.com': source1_project1},
890 'project2':
891 {'git1.example.com': source1_project2}}
892 self.assertEqual(d, tenant.projects)
893 self.assertEqual((False, source1_project2),
894 tenant.getProject('project2'))
895 self.assertEqual((False, source1_project2),
896 tenant.getProject('git1.example.com/project2'))
897
898 connection2 = Dummy(connection_name='dummy_connection2')
899 source2 = Dummy(canonical_hostname='git2.example.com',
900 name='dummy', # TODOv3(jeblair): remove
901 connection=connection2)
902
903 source2_project1 = model.Project('project1', source2)
James E. Blair08d9b782017-06-29 14:22:48 -0700904 tpc = model.TenantProjectConfig(source2_project1)
905 tenant.addUntrustedProject(tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700906 d = {'project1':
907 {'git1.example.com': source1_project1,
908 'git2.example.com': source2_project1},
909 'project2':
910 {'git1.example.com': source1_project2}}
911 self.assertEqual(d, tenant.projects)
912 with testtools.ExpectedException(
913 Exception,
914 "Project name 'project1' is ambiguous"):
915 tenant.getProject('project1')
916 self.assertEqual((False, source1_project2),
917 tenant.getProject('project2'))
918 self.assertEqual((True, source1_project1),
919 tenant.getProject('git1.example.com/project1'))
920 self.assertEqual((False, source2_project1),
921 tenant.getProject('git2.example.com/project1'))
922
923 source2_project2 = model.Project('project2', source2)
James E. Blair08d9b782017-06-29 14:22:48 -0700924 tpc = model.TenantProjectConfig(source2_project2)
925 tenant.addConfigProject(tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700926 d = {'project1':
927 {'git1.example.com': source1_project1,
928 'git2.example.com': source2_project1},
929 'project2':
930 {'git1.example.com': source1_project2,
931 'git2.example.com': source2_project2}}
932 self.assertEqual(d, tenant.projects)
933 with testtools.ExpectedException(
934 Exception,
935 "Project name 'project1' is ambiguous"):
936 tenant.getProject('project1')
937 with testtools.ExpectedException(
938 Exception,
939 "Project name 'project2' is ambiguous"):
940 tenant.getProject('project2')
941 self.assertEqual((True, source1_project1),
942 tenant.getProject('git1.example.com/project1'))
943 self.assertEqual((False, source2_project1),
944 tenant.getProject('git2.example.com/project1'))
945 self.assertEqual((False, source1_project2),
946 tenant.getProject('git1.example.com/project2'))
947 self.assertEqual((True, source2_project2),
948 tenant.getProject('git2.example.com/project2'))
949
950 source1_project2b = model.Project('subpath/project2', source1)
James E. Blair08d9b782017-06-29 14:22:48 -0700951 tpc = model.TenantProjectConfig(source1_project2b)
952 tenant.addConfigProject(tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700953 d = {'project1':
954 {'git1.example.com': source1_project1,
955 'git2.example.com': source2_project1},
956 'project2':
957 {'git1.example.com': source1_project2,
958 'git2.example.com': source2_project2},
959 'subpath/project2':
960 {'git1.example.com': source1_project2b}}
961 self.assertEqual(d, tenant.projects)
962 self.assertEqual((False, source1_project2),
963 tenant.getProject('git1.example.com/project2'))
964 self.assertEqual((True, source2_project2),
965 tenant.getProject('git2.example.com/project2'))
966 self.assertEqual((True, source1_project2b),
967 tenant.getProject('subpath/project2'))
968 self.assertEqual(
969 (True, source1_project2b),
970 tenant.getProject('git1.example.com/subpath/project2'))
971
972 source2_project2b = model.Project('subpath/project2', source2)
James E. Blair08d9b782017-06-29 14:22:48 -0700973 tpc = model.TenantProjectConfig(source2_project2b)
974 tenant.addConfigProject(tpc)
James E. Blairc2a54fd2017-03-29 15:19:26 -0700975 d = {'project1':
976 {'git1.example.com': source1_project1,
977 'git2.example.com': source2_project1},
978 'project2':
979 {'git1.example.com': source1_project2,
980 'git2.example.com': source2_project2},
981 'subpath/project2':
982 {'git1.example.com': source1_project2b,
983 'git2.example.com': source2_project2b}}
984 self.assertEqual(d, tenant.projects)
985 self.assertEqual((False, source1_project2),
986 tenant.getProject('git1.example.com/project2'))
987 self.assertEqual((True, source2_project2),
988 tenant.getProject('git2.example.com/project2'))
989 with testtools.ExpectedException(
990 Exception,
991 "Project name 'subpath/project2' is ambiguous"):
992 tenant.getProject('subpath/project2')
993 self.assertEqual(
994 (True, source1_project2b),
995 tenant.getProject('git1.example.com/subpath/project2'))
996 self.assertEqual(
997 (True, source2_project2b),
998 tenant.getProject('git2.example.com/subpath/project2'))
999
1000 with testtools.ExpectedException(
1001 Exception,
1002 "Project project1 is already in project index"):
James E. Blair08d9b782017-06-29 14:22:48 -07001003 tenant._addProject(source1_project1_tpc)