blob: 9bd405e2da2191fc8ddc02c7561c3f7ab1071ce9 [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
Maru Newby3fe5f852015-01-13 04:22:14 +000024
25from tests.base import BaseTestCase
26
27
28class TestJob(BaseTestCase):
29
James E. Blaira7f51ca2017-02-07 16:01:26 -080030 def setUp(self):
31 super(TestJob, self).setUp()
32 self.project = model.Project('project', None)
33 self.context = model.SourceContext(self.project, 'master', True)
34
Maru Newby3fe5f852015-01-13 04:22:14 +000035 @property
36 def job(self):
James E. Blair5ac93842017-01-20 06:47:34 -080037 tenant = model.Tenant('tenant')
James E. Blair83005782015-12-11 14:46:03 -080038 layout = model.Layout()
James E. Blaircdab2032017-02-01 09:09:29 -080039 project = model.Project('project', None)
40 context = model.SourceContext(project, 'master', True)
James E. Blair5ac93842017-01-20 06:47:34 -080041 job = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -080042 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -080043 'name': 'job',
44 'irrelevant-files': [
45 '^docs/.*$'
46 ]})
Maru Newby3fe5f852015-01-13 04:22:14 +000047 return job
48
49 def test_change_matches_returns_false_for_matched_skip_if(self):
50 change = model.Change('project')
Alexander Evseevdbe6fab2015-11-19 12:46:34 +030051 change.files = ['/COMMIT_MSG', 'docs/foo']
Maru Newby3fe5f852015-01-13 04:22:14 +000052 self.assertFalse(self.job.changeMatches(change))
53
54 def test_change_matches_returns_true_for_unmatched_skip_if(self):
55 change = model.Change('project')
Alexander Evseevdbe6fab2015-11-19 12:46:34 +030056 change.files = ['/COMMIT_MSG', 'foo']
Maru Newby3fe5f852015-01-13 04:22:14 +000057 self.assertTrue(self.job.changeMatches(change))
58
Maru Newby79427a42015-02-17 17:54:45 +000059 def test_job_sets_defaults_for_boolean_attributes(self):
James E. Blair83005782015-12-11 14:46:03 -080060 self.assertIsNotNone(self.job.voting)
61
62 def test_job_inheritance(self):
James E. Blaira7f51ca2017-02-07 16:01:26 -080063 # This is standard job inheritance.
64
65 base_pre = model.PlaybookContext(self.context, 'base-pre')
66 base_run = model.PlaybookContext(self.context, 'base-run')
67 base_post = model.PlaybookContext(self.context, 'base-post')
68
69 base = model.Job('base')
70 base.timeout = 30
71 base.pre_run = [base_pre]
72 base.run = [base_run]
73 base.post_run = [base_post]
74 base.auth = dict(foo='bar', inherit=False)
75
76 py27 = model.Job('py27')
77 self.assertEqual(None, py27.timeout)
78 py27.inheritFrom(base)
79 self.assertEqual(30, py27.timeout)
80 self.assertEqual(['base-pre'],
81 [x.path for x in py27.pre_run])
82 self.assertEqual(['base-run'],
83 [x.path for x in py27.run])
84 self.assertEqual(['base-post'],
85 [x.path for x in py27.post_run])
86 self.assertEqual({}, py27.auth)
87
88 def test_job_variants(self):
89 # This simulates freezing a job.
90
91 py27_pre = model.PlaybookContext(self.context, 'py27-pre')
92 py27_run = model.PlaybookContext(self.context, 'py27-run')
93 py27_post = model.PlaybookContext(self.context, 'py27-post')
94
95 py27 = model.Job('py27')
96 py27.timeout = 30
97 py27.pre_run = [py27_pre]
98 py27.run = [py27_run]
99 py27.post_run = [py27_post]
100 auth = dict(foo='bar', inherit=False)
101 py27.auth = auth
102
103 job = py27.copy()
104 self.assertEqual(30, job.timeout)
105
106 # Apply the diablo variant
107 diablo = model.Job('py27')
108 diablo.timeout = 40
109 job.applyVariant(diablo)
110
111 self.assertEqual(40, job.timeout)
112 self.assertEqual(['py27-pre'],
113 [x.path for x in job.pre_run])
114 self.assertEqual(['py27-run'],
115 [x.path for x in job.run])
116 self.assertEqual(['py27-post'],
117 [x.path for x in job.post_run])
118 self.assertEqual(auth, job.auth)
119
120 # Set the job to final for the following checks
121 job.final = True
122 self.assertTrue(job.voting)
123
124 good_final = model.Job('py27')
125 good_final.voting = False
126 job.applyVariant(good_final)
127 self.assertFalse(job.voting)
128
129 bad_final = model.Job('py27')
130 bad_final.timeout = 600
131 with testtools.ExpectedException(
132 Exception,
133 "Unable to modify final job"):
134 job.applyVariant(bad_final)
135
136 def test_job_inheritance_configloader(self):
137 # TODO(jeblair): move this to a configloader test
James E. Blair5ac93842017-01-20 06:47:34 -0800138 tenant = model.Tenant('tenant')
James E. Blair83005782015-12-11 14:46:03 -0800139 layout = model.Layout()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700140
141 pipeline = model.Pipeline('gate', layout)
142 layout.addPipeline(pipeline)
143 queue = model.ChangeQueue(pipeline)
James E. Blairc73c73a2017-01-20 15:15:15 -0800144 project = model.Project('project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800145 context = model.SourceContext(project, 'master', True)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700146
James E. Blair5ac93842017-01-20 06:47:34 -0800147 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800148 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -0800149 'name': 'base',
150 'timeout': 30,
James E. Blaira7f51ca2017-02-07 16:01:26 -0800151 'pre-run': 'base-pre',
152 'post-run': 'base-post',
James E. Blair1774dd52017-02-03 10:52:32 -0800153 'nodes': [{
154 'name': 'controller',
155 'image': 'base',
156 }],
James E. Blair83005782015-12-11 14:46:03 -0800157 })
158 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800159 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800160 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -0800161 'name': 'python27',
162 'parent': 'base',
James E. Blaira7f51ca2017-02-07 16:01:26 -0800163 'pre-run': 'py27-pre',
164 'post-run': 'py27-post',
James E. Blair1774dd52017-02-03 10:52:32 -0800165 'nodes': [{
166 'name': 'controller',
167 'image': 'new',
168 }],
James E. Blair83005782015-12-11 14:46:03 -0800169 'timeout': 40,
170 })
171 layout.addJob(python27)
James E. Blair5ac93842017-01-20 06:47:34 -0800172 python27diablo = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800173 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -0800174 'name': 'python27',
175 'branches': [
176 'stable/diablo'
177 ],
James E. Blaira7f51ca2017-02-07 16:01:26 -0800178 'pre-run': 'py27-diablo-pre',
179 'run': 'py27-diablo',
180 'post-run': 'py27-diablo-post',
James E. Blair1774dd52017-02-03 10:52:32 -0800181 'nodes': [{
182 'name': 'controller',
183 'image': 'old',
184 }],
James E. Blair83005782015-12-11 14:46:03 -0800185 'timeout': 50,
186 })
187 layout.addJob(python27diablo)
188
James E. Blair5ac93842017-01-20 06:47:34 -0800189 python27essex = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaira7f51ca2017-02-07 16:01:26 -0800190 '_source_context': context,
191 'name': 'python27',
192 'branches': [
193 'stable/essex'
194 ],
195 'pre-run': 'py27-essex-pre',
196 'post-run': 'py27-essex-post',
197 })
198 layout.addJob(python27essex)
199
James E. Blairff555742017-02-19 11:34:27 -0800200 project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
James E. Blaircdab2032017-02-01 09:09:29 -0800201 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700202 'name': 'project',
203 'gate': {
204 'jobs': [
205 'python27'
206 ]
207 }
James E. Blairff555742017-02-19 11:34:27 -0800208 }])
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700209 layout.addProjectConfig(project_config, update_pipeline=False)
James E. Blair83005782015-12-11 14:46:03 -0800210
James E. Blair83005782015-12-11 14:46:03 -0800211 change = model.Change(project)
James E. Blair1774dd52017-02-03 10:52:32 -0800212 # Test master
James E. Blair83005782015-12-11 14:46:03 -0800213 change.branch = 'master'
214 item = queue.enqueueChange(change)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700215 item.current_build_set.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800216
217 self.assertTrue(base.changeMatches(change))
218 self.assertTrue(python27.changeMatches(change))
219 self.assertFalse(python27diablo.changeMatches(change))
James E. Blaira7f51ca2017-02-07 16:01:26 -0800220 self.assertFalse(python27essex.changeMatches(change))
James E. Blair83005782015-12-11 14:46:03 -0800221
222 item.freezeJobTree()
223 self.assertEqual(len(item.getJobs()), 1)
224 job = item.getJobs()[0]
225 self.assertEqual(job.name, 'python27')
226 self.assertEqual(job.timeout, 40)
James E. Blair1774dd52017-02-03 10:52:32 -0800227 nodes = job.nodeset.getNodes()
228 self.assertEqual(len(nodes), 1)
229 self.assertEqual(nodes[0].image, 'new')
James E. Blaira7f51ca2017-02-07 16:01:26 -0800230 self.assertEqual([x.path for x in job.pre_run],
231 ['playbooks/base-pre',
232 'playbooks/py27-pre'])
233 self.assertEqual([x.path for x in job.post_run],
234 ['playbooks/py27-post',
235 'playbooks/base-post'])
236 self.assertEqual([x.path for x in job.run],
237 ['playbooks/python27',
238 'playbooks/base'])
James E. Blair83005782015-12-11 14:46:03 -0800239
James E. Blair1774dd52017-02-03 10:52:32 -0800240 # Test diablo
James E. Blair83005782015-12-11 14:46:03 -0800241 change.branch = 'stable/diablo'
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700242 item = queue.enqueueChange(change)
243 item.current_build_set.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800244
245 self.assertTrue(base.changeMatches(change))
246 self.assertTrue(python27.changeMatches(change))
247 self.assertTrue(python27diablo.changeMatches(change))
James E. Blaira7f51ca2017-02-07 16:01:26 -0800248 self.assertFalse(python27essex.changeMatches(change))
James E. Blair83005782015-12-11 14:46:03 -0800249
250 item.freezeJobTree()
251 self.assertEqual(len(item.getJobs()), 1)
252 job = item.getJobs()[0]
253 self.assertEqual(job.name, 'python27')
254 self.assertEqual(job.timeout, 50)
James E. Blair1774dd52017-02-03 10:52:32 -0800255 nodes = job.nodeset.getNodes()
256 self.assertEqual(len(nodes), 1)
257 self.assertEqual(nodes[0].image, 'old')
James E. Blaira7f51ca2017-02-07 16:01:26 -0800258 self.assertEqual([x.path for x in job.pre_run],
259 ['playbooks/base-pre',
260 'playbooks/py27-pre',
261 'playbooks/py27-diablo-pre'])
262 self.assertEqual([x.path for x in job.post_run],
263 ['playbooks/py27-diablo-post',
264 'playbooks/py27-post',
265 'playbooks/base-post'])
266 self.assertEqual([x.path for x in job.run],
267 ['playbooks/py27-diablo']),
268
269 # Test essex
270 change.branch = 'stable/essex'
271 item = queue.enqueueChange(change)
272 item.current_build_set.layout = layout
273
274 self.assertTrue(base.changeMatches(change))
275 self.assertTrue(python27.changeMatches(change))
276 self.assertFalse(python27diablo.changeMatches(change))
277 self.assertTrue(python27essex.changeMatches(change))
278
279 item.freezeJobTree()
280 self.assertEqual(len(item.getJobs()), 1)
281 job = item.getJobs()[0]
282 self.assertEqual(job.name, 'python27')
283 self.assertEqual([x.path for x in job.pre_run],
284 ['playbooks/base-pre',
285 'playbooks/py27-pre',
286 'playbooks/py27-essex-pre'])
287 self.assertEqual([x.path for x in job.post_run],
288 ['playbooks/py27-essex-post',
289 'playbooks/py27-post',
290 'playbooks/base-post'])
291 self.assertEqual([x.path for x in job.run],
292 ['playbooks/python27',
293 'playbooks/base'])
James E. Blairce8a2132016-05-19 15:21:52 -0700294
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000295 def test_job_auth_inheritance(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800296 tenant = model.Tenant('tenant')
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000297 layout = model.Layout()
James E. Blairc73c73a2017-01-20 15:15:15 -0800298 project = model.Project('project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800299 context = model.SourceContext(project, 'master', True)
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000300
James E. Blair5ac93842017-01-20 06:47:34 -0800301 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800302 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000303 'name': 'base',
304 'timeout': 30,
305 })
306 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800307 pypi_upload_without_inherit = configloader.JobParser.fromYaml(
308 tenant, layout, {
309 '_source_context': context,
310 'name': 'pypi-upload-without-inherit',
311 'parent': 'base',
312 'timeout': 40,
313 'auth': {
314 'secrets': [
315 'pypi-credentials',
316 ]
317 }
318 })
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000319 layout.addJob(pypi_upload_without_inherit)
James E. Blair5ac93842017-01-20 06:47:34 -0800320 pypi_upload_with_inherit = configloader.JobParser.fromYaml(
321 tenant, layout, {
322 '_source_context': context,
323 'name': 'pypi-upload-with-inherit',
324 'parent': 'base',
325 'timeout': 40,
326 'auth': {
327 'inherit': True,
328 'secrets': [
329 'pypi-credentials',
330 ]
331 }
332 })
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000333 layout.addJob(pypi_upload_with_inherit)
334 pypi_upload_with_inherit_false = configloader.JobParser.fromYaml(
James E. Blair5ac93842017-01-20 06:47:34 -0800335 tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800336 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000337 'name': 'pypi-upload-with-inherit-false',
338 'parent': 'base',
339 'timeout': 40,
340 'auth': {
341 'inherit': False,
Ricardo Carrillo Cruz12c892b2016-11-18 15:35:49 +0000342 'secrets': [
343 'pypi-credentials',
344 ]
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000345 }
346 })
347 layout.addJob(pypi_upload_with_inherit_false)
James E. Blair5ac93842017-01-20 06:47:34 -0800348 in_repo_job_without_inherit = configloader.JobParser.fromYaml(
349 tenant, layout, {
350 '_source_context': context,
351 'name': 'in-repo-job-without-inherit',
352 'parent': 'pypi-upload-without-inherit',
353 })
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000354 layout.addJob(in_repo_job_without_inherit)
James E. Blair5ac93842017-01-20 06:47:34 -0800355 in_repo_job_with_inherit = configloader.JobParser.fromYaml(
356 tenant, layout, {
357 '_source_context': context,
358 'name': 'in-repo-job-with-inherit',
359 'parent': 'pypi-upload-with-inherit',
360 })
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000361 layout.addJob(in_repo_job_with_inherit)
362 in_repo_job_with_inherit_false = configloader.JobParser.fromYaml(
James E. Blair5ac93842017-01-20 06:47:34 -0800363 tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800364 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000365 'name': 'in-repo-job-with-inherit-false',
366 'parent': 'pypi-upload-with-inherit-false',
367 })
368 layout.addJob(in_repo_job_with_inherit_false)
369
370 self.assertNotIn('auth', in_repo_job_without_inherit.auth)
Ricardo Carrillo Cruz12c892b2016-11-18 15:35:49 +0000371 self.assertIn('secrets', in_repo_job_with_inherit.auth)
372 self.assertEquals(in_repo_job_with_inherit.auth['secrets'],
373 ['pypi-credentials'])
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000374 self.assertNotIn('auth', in_repo_job_with_inherit_false.auth)
375
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700376 def test_job_inheritance_job_tree(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800377 tenant = model.Tenant('tenant')
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700378 layout = model.Layout()
379
380 pipeline = model.Pipeline('gate', layout)
381 layout.addPipeline(pipeline)
382 queue = model.ChangeQueue(pipeline)
James E. Blairc73c73a2017-01-20 15:15:15 -0800383 project = model.Project('project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800384 context = model.SourceContext(project, 'master', True)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700385
James E. Blair5ac93842017-01-20 06:47:34 -0800386 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800387 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700388 'name': 'base',
389 'timeout': 30,
390 })
391 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800392 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800393 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700394 'name': 'python27',
395 'parent': 'base',
396 'timeout': 40,
397 })
398 layout.addJob(python27)
James E. Blair5ac93842017-01-20 06:47:34 -0800399 python27diablo = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800400 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700401 'name': 'python27',
402 'branches': [
403 'stable/diablo'
404 ],
405 'timeout': 50,
406 })
407 layout.addJob(python27diablo)
408
James E. Blairff555742017-02-19 11:34:27 -0800409 project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
James E. Blaircdab2032017-02-01 09:09:29 -0800410 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700411 'name': 'project',
412 'gate': {
413 'jobs': [
414 {'python27': {'timeout': 70}}
415 ]
416 }
James E. Blairff555742017-02-19 11:34:27 -0800417 }])
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700418 layout.addProjectConfig(project_config, update_pipeline=False)
419
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700420 change = model.Change(project)
421 change.branch = 'master'
422 item = queue.enqueueChange(change)
423 item.current_build_set.layout = layout
424
425 self.assertTrue(base.changeMatches(change))
426 self.assertTrue(python27.changeMatches(change))
427 self.assertFalse(python27diablo.changeMatches(change))
428
429 item.freezeJobTree()
430 self.assertEqual(len(item.getJobs()), 1)
431 job = item.getJobs()[0]
432 self.assertEqual(job.name, 'python27')
433 self.assertEqual(job.timeout, 70)
434
435 change.branch = 'stable/diablo'
436 item = queue.enqueueChange(change)
437 item.current_build_set.layout = layout
438
439 self.assertTrue(base.changeMatches(change))
440 self.assertTrue(python27.changeMatches(change))
441 self.assertTrue(python27diablo.changeMatches(change))
442
443 item.freezeJobTree()
444 self.assertEqual(len(item.getJobs()), 1)
445 job = item.getJobs()[0]
446 self.assertEqual(job.name, 'python27')
447 self.assertEqual(job.timeout, 70)
448
Clint Byrum85493602016-11-18 11:59:47 -0800449 def test_inheritance_keeps_matchers(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800450 tenant = model.Tenant('tenant')
Clint Byrum85493602016-11-18 11:59:47 -0800451 layout = model.Layout()
452
453 pipeline = model.Pipeline('gate', layout)
454 layout.addPipeline(pipeline)
455 queue = model.ChangeQueue(pipeline)
James E. Blairc73c73a2017-01-20 15:15:15 -0800456 project = model.Project('project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800457 context = model.SourceContext(project, 'master', True)
Clint Byrum85493602016-11-18 11:59:47 -0800458
James E. Blair5ac93842017-01-20 06:47:34 -0800459 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800460 '_source_context': context,
Clint Byrum85493602016-11-18 11:59:47 -0800461 'name': 'base',
462 'timeout': 30,
463 })
464 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800465 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800466 '_source_context': context,
Clint Byrum85493602016-11-18 11:59:47 -0800467 'name': 'python27',
468 'parent': 'base',
469 'timeout': 40,
470 'irrelevant-files': ['^ignored-file$'],
471 })
472 layout.addJob(python27)
473
James E. Blairff555742017-02-19 11:34:27 -0800474 project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
James E. Blaircdab2032017-02-01 09:09:29 -0800475 '_source_context': context,
Clint Byrum85493602016-11-18 11:59:47 -0800476 'name': 'project',
477 'gate': {
478 'jobs': [
479 'python27',
480 ]
481 }
James E. Blairff555742017-02-19 11:34:27 -0800482 }])
Clint Byrum85493602016-11-18 11:59:47 -0800483 layout.addProjectConfig(project_config, update_pipeline=False)
484
485 change = model.Change(project)
486 change.branch = 'master'
487 change.files = ['/COMMIT_MSG', 'ignored-file']
488 item = queue.enqueueChange(change)
489 item.current_build_set.layout = layout
490
491 self.assertTrue(base.changeMatches(change))
492 self.assertFalse(python27.changeMatches(change))
493
494 item.freezeJobTree()
495 self.assertEqual([], item.getJobs())
496
James E. Blair4317e9f2016-07-15 10:05:47 -0700497 def test_job_source_project(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800498 tenant = model.Tenant('tenant')
James E. Blair4317e9f2016-07-15 10:05:47 -0700499 layout = model.Layout()
James E. Blairc73c73a2017-01-20 15:15:15 -0800500 base_project = model.Project('base_project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800501 base_context = model.SourceContext(base_project, 'master', True)
502
James E. Blair5ac93842017-01-20 06:47:34 -0800503 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800504 '_source_context': base_context,
James E. Blair4317e9f2016-07-15 10:05:47 -0700505 'name': 'base',
506 })
507 layout.addJob(base)
508
James E. Blairc73c73a2017-01-20 15:15:15 -0800509 other_project = model.Project('other_project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800510 other_context = model.SourceContext(other_project, 'master', True)
James E. Blair5ac93842017-01-20 06:47:34 -0800511 base2 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800512 '_source_context': other_context,
James E. Blair4317e9f2016-07-15 10:05:47 -0700513 'name': 'base',
514 })
515 with testtools.ExpectedException(
516 Exception,
517 "Job base in other_project is not permitted "
518 "to shadow job base in base_project"):
519 layout.addJob(base2)
520
James E. Blairce8a2132016-05-19 15:21:52 -0700521
522class TestJobTimeData(BaseTestCase):
523 def setUp(self):
524 super(TestJobTimeData, self).setUp()
525 self.tmp_root = self.useFixture(fixtures.TempDir(
526 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
527 ).path
528
529 def test_empty_timedata(self):
530 path = os.path.join(self.tmp_root, 'job-name')
531 self.assertFalse(os.path.exists(path))
532 self.assertFalse(os.path.exists(path + '.tmp'))
533 td = model.JobTimeData(path)
534 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
535 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
536 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
537
538 def test_save_reload(self):
539 path = os.path.join(self.tmp_root, 'job-name')
540 self.assertFalse(os.path.exists(path))
541 self.assertFalse(os.path.exists(path + '.tmp'))
542 td = model.JobTimeData(path)
543 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
544 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
545 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
546 success_times = []
547 failure_times = []
548 results = []
549 for x in range(10):
550 success_times.append(int(random.random() * 1000))
551 failure_times.append(int(random.random() * 1000))
552 results.append(0)
553 results.append(1)
554 random.shuffle(results)
555 s = f = 0
556 for result in results:
557 if result:
558 td.add(failure_times[f], 'FAILURE')
559 f += 1
560 else:
561 td.add(success_times[s], 'SUCCESS')
562 s += 1
563 self.assertEqual(td.success_times, success_times)
564 self.assertEqual(td.failure_times, failure_times)
565 self.assertEqual(td.results, results[10:])
566 td.save()
567 self.assertTrue(os.path.exists(path))
568 self.assertFalse(os.path.exists(path + '.tmp'))
569 td = model.JobTimeData(path)
570 td.load()
571 self.assertEqual(td.success_times, success_times)
572 self.assertEqual(td.failure_times, failure_times)
573 self.assertEqual(td.results, results[10:])
574
575
576class TestTimeDataBase(BaseTestCase):
577 def setUp(self):
578 super(TestTimeDataBase, self).setUp()
579 self.tmp_root = self.useFixture(fixtures.TempDir(
580 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
581 ).path
582 self.db = model.TimeDataBase(self.tmp_root)
583
584 def test_timedatabase(self):
585 self.assertEqual(self.db.getEstimatedTime('job-name'), 0)
586 self.db.update('job-name', 50, 'SUCCESS')
587 self.assertEqual(self.db.getEstimatedTime('job-name'), 50)
588 self.db.update('job-name', 100, 'SUCCESS')
589 self.assertEqual(self.db.getEstimatedTime('job-name'), 75)
590 for x in range(10):
591 self.db.update('job-name', 100, 'SUCCESS')
592 self.assertEqual(self.db.getEstimatedTime('job-name'), 100)