blob: 38615a9475ab6c023fcad9024c6f18f48bf5069c [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)
James E. Blair6f140c72017-03-03 10:32:07 -080033 self.context = model.SourceContext(self.project, 'master',
34 'test', True)
James E. Blaira7f51ca2017-02-07 16:01:26 -080035
Maru Newby3fe5f852015-01-13 04:22:14 +000036 @property
37 def job(self):
James E. Blair5ac93842017-01-20 06:47:34 -080038 tenant = model.Tenant('tenant')
James E. Blair83005782015-12-11 14:46:03 -080039 layout = model.Layout()
James E. Blaircdab2032017-02-01 09:09:29 -080040 project = model.Project('project', None)
James E. Blair6f140c72017-03-03 10:32:07 -080041 context = model.SourceContext(project, 'master', 'test', True)
James E. Blair5ac93842017-01-20 06:47:34 -080042 job = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -080043 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -080044 'name': 'job',
45 'irrelevant-files': [
46 '^docs/.*$'
47 ]})
Maru Newby3fe5f852015-01-13 04:22:14 +000048 return job
49
50 def test_change_matches_returns_false_for_matched_skip_if(self):
51 change = model.Change('project')
Alexander Evseevdbe6fab2015-11-19 12:46:34 +030052 change.files = ['/COMMIT_MSG', 'docs/foo']
Maru Newby3fe5f852015-01-13 04:22:14 +000053 self.assertFalse(self.job.changeMatches(change))
54
55 def test_change_matches_returns_true_for_unmatched_skip_if(self):
56 change = model.Change('project')
Alexander Evseevdbe6fab2015-11-19 12:46:34 +030057 change.files = ['/COMMIT_MSG', 'foo']
Maru Newby3fe5f852015-01-13 04:22:14 +000058 self.assertTrue(self.job.changeMatches(change))
59
Maru Newby79427a42015-02-17 17:54:45 +000060 def test_job_sets_defaults_for_boolean_attributes(self):
James E. Blair83005782015-12-11 14:46:03 -080061 self.assertIsNotNone(self.job.voting)
62
63 def test_job_inheritance(self):
James E. Blaira7f51ca2017-02-07 16:01:26 -080064 # This is standard job inheritance.
65
66 base_pre = model.PlaybookContext(self.context, 'base-pre')
67 base_run = model.PlaybookContext(self.context, 'base-run')
68 base_post = model.PlaybookContext(self.context, 'base-post')
69
70 base = model.Job('base')
71 base.timeout = 30
72 base.pre_run = [base_pre]
73 base.run = [base_run]
74 base.post_run = [base_post]
75 base.auth = dict(foo='bar', inherit=False)
76
77 py27 = model.Job('py27')
78 self.assertEqual(None, py27.timeout)
79 py27.inheritFrom(base)
80 self.assertEqual(30, py27.timeout)
81 self.assertEqual(['base-pre'],
82 [x.path for x in py27.pre_run])
83 self.assertEqual(['base-run'],
84 [x.path for x in py27.run])
85 self.assertEqual(['base-post'],
86 [x.path for x in py27.post_run])
87 self.assertEqual({}, py27.auth)
88
89 def test_job_variants(self):
90 # This simulates freezing a job.
91
92 py27_pre = model.PlaybookContext(self.context, 'py27-pre')
93 py27_run = model.PlaybookContext(self.context, 'py27-run')
94 py27_post = model.PlaybookContext(self.context, 'py27-post')
95
96 py27 = model.Job('py27')
97 py27.timeout = 30
98 py27.pre_run = [py27_pre]
99 py27.run = [py27_run]
100 py27.post_run = [py27_post]
101 auth = dict(foo='bar', inherit=False)
102 py27.auth = auth
103
104 job = py27.copy()
105 self.assertEqual(30, job.timeout)
106
107 # Apply the diablo variant
108 diablo = model.Job('py27')
109 diablo.timeout = 40
110 job.applyVariant(diablo)
111
112 self.assertEqual(40, job.timeout)
113 self.assertEqual(['py27-pre'],
114 [x.path for x in job.pre_run])
115 self.assertEqual(['py27-run'],
116 [x.path for x in job.run])
117 self.assertEqual(['py27-post'],
118 [x.path for x in job.post_run])
119 self.assertEqual(auth, job.auth)
120
121 # Set the job to final for the following checks
122 job.final = True
123 self.assertTrue(job.voting)
124
125 good_final = model.Job('py27')
126 good_final.voting = False
127 job.applyVariant(good_final)
128 self.assertFalse(job.voting)
129
130 bad_final = model.Job('py27')
131 bad_final.timeout = 600
132 with testtools.ExpectedException(
133 Exception,
134 "Unable to modify final job"):
135 job.applyVariant(bad_final)
136
137 def test_job_inheritance_configloader(self):
138 # TODO(jeblair): move this to a configloader test
James E. Blair5ac93842017-01-20 06:47:34 -0800139 tenant = model.Tenant('tenant')
James E. Blair83005782015-12-11 14:46:03 -0800140 layout = model.Layout()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700141
142 pipeline = model.Pipeline('gate', layout)
143 layout.addPipeline(pipeline)
144 queue = model.ChangeQueue(pipeline)
James E. Blairc73c73a2017-01-20 15:15:15 -0800145 project = model.Project('project', None)
James E. Blair6f140c72017-03-03 10:32:07 -0800146 context = model.SourceContext(project, 'master', 'test', True)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700147
James E. Blair5ac93842017-01-20 06:47:34 -0800148 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800149 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -0800150 'name': 'base',
151 'timeout': 30,
James E. Blaira7f51ca2017-02-07 16:01:26 -0800152 'pre-run': 'base-pre',
153 'post-run': 'base-post',
James E. Blair1774dd52017-02-03 10:52:32 -0800154 'nodes': [{
155 'name': 'controller',
156 'image': 'base',
157 }],
James E. Blair83005782015-12-11 14:46:03 -0800158 })
159 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800160 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800161 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -0800162 'name': 'python27',
163 'parent': 'base',
James E. Blaira7f51ca2017-02-07 16:01:26 -0800164 'pre-run': 'py27-pre',
165 'post-run': 'py27-post',
James E. Blair1774dd52017-02-03 10:52:32 -0800166 'nodes': [{
167 'name': 'controller',
168 'image': 'new',
169 }],
James E. Blair83005782015-12-11 14:46:03 -0800170 'timeout': 40,
171 })
172 layout.addJob(python27)
James E. Blair5ac93842017-01-20 06:47:34 -0800173 python27diablo = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800174 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -0800175 'name': 'python27',
176 'branches': [
177 'stable/diablo'
178 ],
James E. Blaira7f51ca2017-02-07 16:01:26 -0800179 'pre-run': 'py27-diablo-pre',
180 'run': 'py27-diablo',
181 'post-run': 'py27-diablo-post',
James E. Blair1774dd52017-02-03 10:52:32 -0800182 'nodes': [{
183 'name': 'controller',
184 'image': 'old',
185 }],
James E. Blair83005782015-12-11 14:46:03 -0800186 'timeout': 50,
187 })
188 layout.addJob(python27diablo)
189
James E. Blair5ac93842017-01-20 06:47:34 -0800190 python27essex = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaira7f51ca2017-02-07 16:01:26 -0800191 '_source_context': context,
192 'name': 'python27',
193 'branches': [
194 'stable/essex'
195 ],
196 'pre-run': 'py27-essex-pre',
197 'post-run': 'py27-essex-post',
198 })
199 layout.addJob(python27essex)
200
James E. Blairff555742017-02-19 11:34:27 -0800201 project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
James E. Blaircdab2032017-02-01 09:09:29 -0800202 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700203 'name': 'project',
204 'gate': {
205 'jobs': [
206 'python27'
207 ]
208 }
James E. Blairff555742017-02-19 11:34:27 -0800209 }])
James E. Blairf59f3cf2017-02-19 14:50:26 -0800210 layout.addProjectConfig(project_config)
James E. Blair83005782015-12-11 14:46:03 -0800211
James E. Blair83005782015-12-11 14:46:03 -0800212 change = model.Change(project)
James E. Blair1774dd52017-02-03 10:52:32 -0800213 # Test master
James E. Blair83005782015-12-11 14:46:03 -0800214 change.branch = 'master'
215 item = queue.enqueueChange(change)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700216 item.current_build_set.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800217
218 self.assertTrue(base.changeMatches(change))
219 self.assertTrue(python27.changeMatches(change))
220 self.assertFalse(python27diablo.changeMatches(change))
James E. Blaira7f51ca2017-02-07 16:01:26 -0800221 self.assertFalse(python27essex.changeMatches(change))
James E. Blair83005782015-12-11 14:46:03 -0800222
223 item.freezeJobTree()
224 self.assertEqual(len(item.getJobs()), 1)
225 job = item.getJobs()[0]
226 self.assertEqual(job.name, 'python27')
227 self.assertEqual(job.timeout, 40)
James E. Blair1774dd52017-02-03 10:52:32 -0800228 nodes = job.nodeset.getNodes()
229 self.assertEqual(len(nodes), 1)
230 self.assertEqual(nodes[0].image, 'new')
James E. Blaira7f51ca2017-02-07 16:01:26 -0800231 self.assertEqual([x.path for x in job.pre_run],
232 ['playbooks/base-pre',
233 'playbooks/py27-pre'])
234 self.assertEqual([x.path for x in job.post_run],
235 ['playbooks/py27-post',
236 'playbooks/base-post'])
237 self.assertEqual([x.path for x in job.run],
238 ['playbooks/python27',
239 'playbooks/base'])
James E. Blair83005782015-12-11 14:46:03 -0800240
James E. Blair1774dd52017-02-03 10:52:32 -0800241 # Test diablo
James E. Blair83005782015-12-11 14:46:03 -0800242 change.branch = 'stable/diablo'
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700243 item = queue.enqueueChange(change)
244 item.current_build_set.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800245
246 self.assertTrue(base.changeMatches(change))
247 self.assertTrue(python27.changeMatches(change))
248 self.assertTrue(python27diablo.changeMatches(change))
James E. Blaira7f51ca2017-02-07 16:01:26 -0800249 self.assertFalse(python27essex.changeMatches(change))
James E. Blair83005782015-12-11 14:46:03 -0800250
251 item.freezeJobTree()
252 self.assertEqual(len(item.getJobs()), 1)
253 job = item.getJobs()[0]
254 self.assertEqual(job.name, 'python27')
255 self.assertEqual(job.timeout, 50)
James E. Blair1774dd52017-02-03 10:52:32 -0800256 nodes = job.nodeset.getNodes()
257 self.assertEqual(len(nodes), 1)
258 self.assertEqual(nodes[0].image, 'old')
James E. Blaira7f51ca2017-02-07 16:01:26 -0800259 self.assertEqual([x.path for x in job.pre_run],
260 ['playbooks/base-pre',
261 'playbooks/py27-pre',
262 'playbooks/py27-diablo-pre'])
263 self.assertEqual([x.path for x in job.post_run],
264 ['playbooks/py27-diablo-post',
265 'playbooks/py27-post',
266 'playbooks/base-post'])
267 self.assertEqual([x.path for x in job.run],
268 ['playbooks/py27-diablo']),
269
270 # Test essex
271 change.branch = 'stable/essex'
272 item = queue.enqueueChange(change)
273 item.current_build_set.layout = layout
274
275 self.assertTrue(base.changeMatches(change))
276 self.assertTrue(python27.changeMatches(change))
277 self.assertFalse(python27diablo.changeMatches(change))
278 self.assertTrue(python27essex.changeMatches(change))
279
280 item.freezeJobTree()
281 self.assertEqual(len(item.getJobs()), 1)
282 job = item.getJobs()[0]
283 self.assertEqual(job.name, 'python27')
284 self.assertEqual([x.path for x in job.pre_run],
285 ['playbooks/base-pre',
286 'playbooks/py27-pre',
287 'playbooks/py27-essex-pre'])
288 self.assertEqual([x.path for x in job.post_run],
289 ['playbooks/py27-essex-post',
290 'playbooks/py27-post',
291 'playbooks/base-post'])
292 self.assertEqual([x.path for x in job.run],
293 ['playbooks/python27',
294 'playbooks/base'])
James E. Blairce8a2132016-05-19 15:21:52 -0700295
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000296 def test_job_auth_inheritance(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800297 tenant = model.Tenant('tenant')
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000298 layout = model.Layout()
James E. Blairc73c73a2017-01-20 15:15:15 -0800299 project = model.Project('project', None)
James E. Blair6f140c72017-03-03 10:32:07 -0800300 context = model.SourceContext(project, 'master', 'test', True)
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000301
James E. Blair5ac93842017-01-20 06:47:34 -0800302 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800303 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000304 'name': 'base',
305 'timeout': 30,
306 })
307 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800308 pypi_upload_without_inherit = configloader.JobParser.fromYaml(
309 tenant, layout, {
310 '_source_context': context,
311 'name': 'pypi-upload-without-inherit',
312 'parent': 'base',
313 'timeout': 40,
314 'auth': {
315 'secrets': [
316 'pypi-credentials',
317 ]
318 }
319 })
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000320 layout.addJob(pypi_upload_without_inherit)
James E. Blair5ac93842017-01-20 06:47:34 -0800321 pypi_upload_with_inherit = configloader.JobParser.fromYaml(
322 tenant, layout, {
323 '_source_context': context,
324 'name': 'pypi-upload-with-inherit',
325 'parent': 'base',
326 'timeout': 40,
327 'auth': {
328 'inherit': True,
329 'secrets': [
330 'pypi-credentials',
331 ]
332 }
333 })
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000334 layout.addJob(pypi_upload_with_inherit)
335 pypi_upload_with_inherit_false = configloader.JobParser.fromYaml(
James E. Blair5ac93842017-01-20 06:47:34 -0800336 tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800337 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000338 'name': 'pypi-upload-with-inherit-false',
339 'parent': 'base',
340 'timeout': 40,
341 'auth': {
342 'inherit': False,
Ricardo Carrillo Cruz12c892b2016-11-18 15:35:49 +0000343 'secrets': [
344 'pypi-credentials',
345 ]
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000346 }
347 })
348 layout.addJob(pypi_upload_with_inherit_false)
James E. Blair5ac93842017-01-20 06:47:34 -0800349 in_repo_job_without_inherit = configloader.JobParser.fromYaml(
350 tenant, layout, {
351 '_source_context': context,
352 'name': 'in-repo-job-without-inherit',
353 'parent': 'pypi-upload-without-inherit',
354 })
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000355 layout.addJob(in_repo_job_without_inherit)
James E. Blair5ac93842017-01-20 06:47:34 -0800356 in_repo_job_with_inherit = configloader.JobParser.fromYaml(
357 tenant, layout, {
358 '_source_context': context,
359 'name': 'in-repo-job-with-inherit',
360 'parent': 'pypi-upload-with-inherit',
361 })
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000362 layout.addJob(in_repo_job_with_inherit)
363 in_repo_job_with_inherit_false = configloader.JobParser.fromYaml(
James E. Blair5ac93842017-01-20 06:47:34 -0800364 tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800365 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000366 'name': 'in-repo-job-with-inherit-false',
367 'parent': 'pypi-upload-with-inherit-false',
368 })
369 layout.addJob(in_repo_job_with_inherit_false)
370
371 self.assertNotIn('auth', in_repo_job_without_inherit.auth)
Ricardo Carrillo Cruz12c892b2016-11-18 15:35:49 +0000372 self.assertIn('secrets', in_repo_job_with_inherit.auth)
373 self.assertEquals(in_repo_job_with_inherit.auth['secrets'],
374 ['pypi-credentials'])
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000375 self.assertNotIn('auth', in_repo_job_with_inherit_false.auth)
376
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700377 def test_job_inheritance_job_tree(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800378 tenant = model.Tenant('tenant')
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700379 layout = model.Layout()
380
381 pipeline = model.Pipeline('gate', layout)
382 layout.addPipeline(pipeline)
383 queue = model.ChangeQueue(pipeline)
James E. Blairc73c73a2017-01-20 15:15:15 -0800384 project = model.Project('project', None)
James E. Blair6f140c72017-03-03 10:32:07 -0800385 context = model.SourceContext(project, 'master', 'test', True)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700386
James E. Blair5ac93842017-01-20 06:47:34 -0800387 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800388 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700389 'name': 'base',
390 'timeout': 30,
391 })
392 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800393 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800394 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700395 'name': 'python27',
396 'parent': 'base',
397 'timeout': 40,
398 })
399 layout.addJob(python27)
James E. Blair5ac93842017-01-20 06:47:34 -0800400 python27diablo = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800401 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700402 'name': 'python27',
403 'branches': [
404 'stable/diablo'
405 ],
406 'timeout': 50,
407 })
408 layout.addJob(python27diablo)
409
James E. Blairff555742017-02-19 11:34:27 -0800410 project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
James E. Blaircdab2032017-02-01 09:09:29 -0800411 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700412 'name': 'project',
413 'gate': {
414 'jobs': [
415 {'python27': {'timeout': 70}}
416 ]
417 }
James E. Blairff555742017-02-19 11:34:27 -0800418 }])
James E. Blairf59f3cf2017-02-19 14:50:26 -0800419 layout.addProjectConfig(project_config)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700420
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700421 change = model.Change(project)
422 change.branch = 'master'
423 item = queue.enqueueChange(change)
424 item.current_build_set.layout = layout
425
426 self.assertTrue(base.changeMatches(change))
427 self.assertTrue(python27.changeMatches(change))
428 self.assertFalse(python27diablo.changeMatches(change))
429
430 item.freezeJobTree()
431 self.assertEqual(len(item.getJobs()), 1)
432 job = item.getJobs()[0]
433 self.assertEqual(job.name, 'python27')
434 self.assertEqual(job.timeout, 70)
435
436 change.branch = 'stable/diablo'
437 item = queue.enqueueChange(change)
438 item.current_build_set.layout = layout
439
440 self.assertTrue(base.changeMatches(change))
441 self.assertTrue(python27.changeMatches(change))
442 self.assertTrue(python27diablo.changeMatches(change))
443
444 item.freezeJobTree()
445 self.assertEqual(len(item.getJobs()), 1)
446 job = item.getJobs()[0]
447 self.assertEqual(job.name, 'python27')
448 self.assertEqual(job.timeout, 70)
449
Clint Byrum85493602016-11-18 11:59:47 -0800450 def test_inheritance_keeps_matchers(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800451 tenant = model.Tenant('tenant')
Clint Byrum85493602016-11-18 11:59:47 -0800452 layout = model.Layout()
453
454 pipeline = model.Pipeline('gate', layout)
455 layout.addPipeline(pipeline)
456 queue = model.ChangeQueue(pipeline)
James E. Blairc73c73a2017-01-20 15:15:15 -0800457 project = model.Project('project', None)
James E. Blair6f140c72017-03-03 10:32:07 -0800458 context = model.SourceContext(project, 'master', 'test', True)
Clint Byrum85493602016-11-18 11:59:47 -0800459
James E. Blair5ac93842017-01-20 06:47:34 -0800460 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800461 '_source_context': context,
Clint Byrum85493602016-11-18 11:59:47 -0800462 'name': 'base',
463 'timeout': 30,
464 })
465 layout.addJob(base)
James E. Blair5ac93842017-01-20 06:47:34 -0800466 python27 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800467 '_source_context': context,
Clint Byrum85493602016-11-18 11:59:47 -0800468 'name': 'python27',
469 'parent': 'base',
470 'timeout': 40,
471 'irrelevant-files': ['^ignored-file$'],
472 })
473 layout.addJob(python27)
474
James E. Blairff555742017-02-19 11:34:27 -0800475 project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
James E. Blaircdab2032017-02-01 09:09:29 -0800476 '_source_context': context,
Clint Byrum85493602016-11-18 11:59:47 -0800477 'name': 'project',
478 'gate': {
479 'jobs': [
480 'python27',
481 ]
482 }
James E. Blairff555742017-02-19 11:34:27 -0800483 }])
James E. Blairf59f3cf2017-02-19 14:50:26 -0800484 layout.addProjectConfig(project_config)
Clint Byrum85493602016-11-18 11:59:47 -0800485
486 change = model.Change(project)
487 change.branch = 'master'
488 change.files = ['/COMMIT_MSG', 'ignored-file']
489 item = queue.enqueueChange(change)
490 item.current_build_set.layout = layout
491
492 self.assertTrue(base.changeMatches(change))
493 self.assertFalse(python27.changeMatches(change))
494
495 item.freezeJobTree()
496 self.assertEqual([], item.getJobs())
497
James E. Blair4317e9f2016-07-15 10:05:47 -0700498 def test_job_source_project(self):
James E. Blair5ac93842017-01-20 06:47:34 -0800499 tenant = model.Tenant('tenant')
James E. Blair4317e9f2016-07-15 10:05:47 -0700500 layout = model.Layout()
James E. Blairc73c73a2017-01-20 15:15:15 -0800501 base_project = model.Project('base_project', None)
James E. Blair6f140c72017-03-03 10:32:07 -0800502 base_context = model.SourceContext(base_project, 'master',
503 'test', True)
James E. Blaircdab2032017-02-01 09:09:29 -0800504
James E. Blair5ac93842017-01-20 06:47:34 -0800505 base = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800506 '_source_context': base_context,
James E. Blair4317e9f2016-07-15 10:05:47 -0700507 'name': 'base',
508 })
509 layout.addJob(base)
510
James E. Blairc73c73a2017-01-20 15:15:15 -0800511 other_project = model.Project('other_project', None)
James E. Blair6f140c72017-03-03 10:32:07 -0800512 other_context = model.SourceContext(other_project, 'master',
513 'test', True)
James E. Blair5ac93842017-01-20 06:47:34 -0800514 base2 = configloader.JobParser.fromYaml(tenant, layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800515 '_source_context': other_context,
James E. Blair4317e9f2016-07-15 10:05:47 -0700516 'name': 'base',
517 })
518 with testtools.ExpectedException(
519 Exception,
520 "Job base in other_project is not permitted "
521 "to shadow job base in base_project"):
522 layout.addJob(base2)
523
James E. Blairce8a2132016-05-19 15:21:52 -0700524
525class TestJobTimeData(BaseTestCase):
526 def setUp(self):
527 super(TestJobTimeData, self).setUp()
528 self.tmp_root = self.useFixture(fixtures.TempDir(
529 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
530 ).path
531
532 def test_empty_timedata(self):
533 path = os.path.join(self.tmp_root, 'job-name')
534 self.assertFalse(os.path.exists(path))
535 self.assertFalse(os.path.exists(path + '.tmp'))
536 td = model.JobTimeData(path)
537 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
538 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
539 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
540
541 def test_save_reload(self):
542 path = os.path.join(self.tmp_root, 'job-name')
543 self.assertFalse(os.path.exists(path))
544 self.assertFalse(os.path.exists(path + '.tmp'))
545 td = model.JobTimeData(path)
546 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
547 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
548 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
549 success_times = []
550 failure_times = []
551 results = []
552 for x in range(10):
553 success_times.append(int(random.random() * 1000))
554 failure_times.append(int(random.random() * 1000))
555 results.append(0)
556 results.append(1)
557 random.shuffle(results)
558 s = f = 0
559 for result in results:
560 if result:
561 td.add(failure_times[f], 'FAILURE')
562 f += 1
563 else:
564 td.add(success_times[s], 'SUCCESS')
565 s += 1
566 self.assertEqual(td.success_times, success_times)
567 self.assertEqual(td.failure_times, failure_times)
568 self.assertEqual(td.results, results[10:])
569 td.save()
570 self.assertTrue(os.path.exists(path))
571 self.assertFalse(os.path.exists(path + '.tmp'))
572 td = model.JobTimeData(path)
573 td.load()
574 self.assertEqual(td.success_times, success_times)
575 self.assertEqual(td.failure_times, failure_times)
576 self.assertEqual(td.results, results[10:])
577
578
579class TestTimeDataBase(BaseTestCase):
580 def setUp(self):
581 super(TestTimeDataBase, self).setUp()
582 self.tmp_root = self.useFixture(fixtures.TempDir(
583 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
584 ).path
585 self.db = model.TimeDataBase(self.tmp_root)
586
587 def test_timedatabase(self):
588 self.assertEqual(self.db.getEstimatedTime('job-name'), 0)
589 self.db.update('job-name', 50, 'SUCCESS')
590 self.assertEqual(self.db.getEstimatedTime('job-name'), 50)
591 self.db.update('job-name', 100, 'SUCCESS')
592 self.assertEqual(self.db.getEstimatedTime('job-name'), 75)
593 for x in range(10):
594 self.db.update('job-name', 100, 'SUCCESS')
595 self.assertEqual(self.db.getEstimatedTime('job-name'), 100)