blob: b54eb5f02cd33bcc7fdee7c703f99a9801239f04 [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. Blair83005782015-12-11 14:46:03 -080037 layout = model.Layout()
James E. Blaircdab2032017-02-01 09:09:29 -080038 project = model.Project('project', None)
39 context = model.SourceContext(project, 'master', True)
James E. Blair83005782015-12-11 14:46:03 -080040 job = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -080041 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -080042 'name': 'job',
43 'irrelevant-files': [
44 '^docs/.*$'
45 ]})
Maru Newby3fe5f852015-01-13 04:22:14 +000046 return job
47
48 def test_change_matches_returns_false_for_matched_skip_if(self):
49 change = model.Change('project')
Alexander Evseevdbe6fab2015-11-19 12:46:34 +030050 change.files = ['/COMMIT_MSG', 'docs/foo']
Maru Newby3fe5f852015-01-13 04:22:14 +000051 self.assertFalse(self.job.changeMatches(change))
52
53 def test_change_matches_returns_true_for_unmatched_skip_if(self):
54 change = model.Change('project')
Alexander Evseevdbe6fab2015-11-19 12:46:34 +030055 change.files = ['/COMMIT_MSG', 'foo']
Maru Newby3fe5f852015-01-13 04:22:14 +000056 self.assertTrue(self.job.changeMatches(change))
57
Maru Newby79427a42015-02-17 17:54:45 +000058 def test_job_sets_defaults_for_boolean_attributes(self):
James E. Blair83005782015-12-11 14:46:03 -080059 self.assertIsNotNone(self.job.voting)
60
61 def test_job_inheritance(self):
James E. Blaira7f51ca2017-02-07 16:01:26 -080062 # This is standard job inheritance.
63
64 base_pre = model.PlaybookContext(self.context, 'base-pre')
65 base_run = model.PlaybookContext(self.context, 'base-run')
66 base_post = model.PlaybookContext(self.context, 'base-post')
67
68 base = model.Job('base')
69 base.timeout = 30
70 base.pre_run = [base_pre]
71 base.run = [base_run]
72 base.post_run = [base_post]
73 base.auth = dict(foo='bar', inherit=False)
74
75 py27 = model.Job('py27')
76 self.assertEqual(None, py27.timeout)
77 py27.inheritFrom(base)
78 self.assertEqual(30, py27.timeout)
79 self.assertEqual(['base-pre'],
80 [x.path for x in py27.pre_run])
81 self.assertEqual(['base-run'],
82 [x.path for x in py27.run])
83 self.assertEqual(['base-post'],
84 [x.path for x in py27.post_run])
85 self.assertEqual({}, py27.auth)
86
87 def test_job_variants(self):
88 # This simulates freezing a job.
89
90 py27_pre = model.PlaybookContext(self.context, 'py27-pre')
91 py27_run = model.PlaybookContext(self.context, 'py27-run')
92 py27_post = model.PlaybookContext(self.context, 'py27-post')
93
94 py27 = model.Job('py27')
95 py27.timeout = 30
96 py27.pre_run = [py27_pre]
97 py27.run = [py27_run]
98 py27.post_run = [py27_post]
99 auth = dict(foo='bar', inherit=False)
100 py27.auth = auth
101
102 job = py27.copy()
103 self.assertEqual(30, job.timeout)
104
105 # Apply the diablo variant
106 diablo = model.Job('py27')
107 diablo.timeout = 40
108 job.applyVariant(diablo)
109
110 self.assertEqual(40, job.timeout)
111 self.assertEqual(['py27-pre'],
112 [x.path for x in job.pre_run])
113 self.assertEqual(['py27-run'],
114 [x.path for x in job.run])
115 self.assertEqual(['py27-post'],
116 [x.path for x in job.post_run])
117 self.assertEqual(auth, job.auth)
118
119 # Set the job to final for the following checks
120 job.final = True
121 self.assertTrue(job.voting)
122
123 good_final = model.Job('py27')
124 good_final.voting = False
125 job.applyVariant(good_final)
126 self.assertFalse(job.voting)
127
128 bad_final = model.Job('py27')
129 bad_final.timeout = 600
130 with testtools.ExpectedException(
131 Exception,
132 "Unable to modify final job"):
133 job.applyVariant(bad_final)
134
135 def test_job_inheritance_configloader(self):
136 # TODO(jeblair): move this to a configloader test
James E. Blair83005782015-12-11 14:46:03 -0800137 layout = model.Layout()
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700138
139 pipeline = model.Pipeline('gate', layout)
140 layout.addPipeline(pipeline)
141 queue = model.ChangeQueue(pipeline)
James E. Blairc73c73a2017-01-20 15:15:15 -0800142 project = model.Project('project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800143 context = model.SourceContext(project, 'master', True)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700144
James E. Blair83005782015-12-11 14:46:03 -0800145 base = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800146 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -0800147 'name': 'base',
148 'timeout': 30,
James E. Blaira7f51ca2017-02-07 16:01:26 -0800149 'pre-run': 'base-pre',
150 'post-run': 'base-post',
James E. Blair1774dd52017-02-03 10:52:32 -0800151 'nodes': [{
152 'name': 'controller',
153 'image': 'base',
154 }],
James E. Blair83005782015-12-11 14:46:03 -0800155 })
156 layout.addJob(base)
157 python27 = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800158 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -0800159 'name': 'python27',
160 'parent': 'base',
James E. Blaira7f51ca2017-02-07 16:01:26 -0800161 'pre-run': 'py27-pre',
162 'post-run': 'py27-post',
James E. Blair1774dd52017-02-03 10:52:32 -0800163 'nodes': [{
164 'name': 'controller',
165 'image': 'new',
166 }],
James E. Blair83005782015-12-11 14:46:03 -0800167 'timeout': 40,
168 })
169 layout.addJob(python27)
170 python27diablo = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800171 '_source_context': context,
James E. Blair83005782015-12-11 14:46:03 -0800172 'name': 'python27',
173 'branches': [
174 'stable/diablo'
175 ],
James E. Blaira7f51ca2017-02-07 16:01:26 -0800176 'pre-run': 'py27-diablo-pre',
177 'run': 'py27-diablo',
178 'post-run': 'py27-diablo-post',
James E. Blair1774dd52017-02-03 10:52:32 -0800179 'nodes': [{
180 'name': 'controller',
181 'image': 'old',
182 }],
James E. Blair83005782015-12-11 14:46:03 -0800183 'timeout': 50,
184 })
185 layout.addJob(python27diablo)
186
James E. Blaira7f51ca2017-02-07 16:01:26 -0800187 python27essex = configloader.JobParser.fromYaml(layout, {
188 '_source_context': context,
189 'name': 'python27',
190 'branches': [
191 'stable/essex'
192 ],
193 'pre-run': 'py27-essex-pre',
194 'post-run': 'py27-essex-post',
195 })
196 layout.addJob(python27essex)
197
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700198 project_config = configloader.ProjectParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800199 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700200 'name': 'project',
201 'gate': {
202 'jobs': [
203 'python27'
204 ]
205 }
206 })
207 layout.addProjectConfig(project_config, update_pipeline=False)
James E. Blair83005782015-12-11 14:46:03 -0800208
James E. Blair83005782015-12-11 14:46:03 -0800209 change = model.Change(project)
James E. Blair1774dd52017-02-03 10:52:32 -0800210 # Test master
James E. Blair83005782015-12-11 14:46:03 -0800211 change.branch = 'master'
212 item = queue.enqueueChange(change)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700213 item.current_build_set.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800214
215 self.assertTrue(base.changeMatches(change))
216 self.assertTrue(python27.changeMatches(change))
217 self.assertFalse(python27diablo.changeMatches(change))
James E. Blaira7f51ca2017-02-07 16:01:26 -0800218 self.assertFalse(python27essex.changeMatches(change))
James E. Blair83005782015-12-11 14:46:03 -0800219
220 item.freezeJobTree()
221 self.assertEqual(len(item.getJobs()), 1)
222 job = item.getJobs()[0]
223 self.assertEqual(job.name, 'python27')
224 self.assertEqual(job.timeout, 40)
James E. Blair1774dd52017-02-03 10:52:32 -0800225 nodes = job.nodeset.getNodes()
226 self.assertEqual(len(nodes), 1)
227 self.assertEqual(nodes[0].image, 'new')
James E. Blaira7f51ca2017-02-07 16:01:26 -0800228 self.assertEqual([x.path for x in job.pre_run],
229 ['playbooks/base-pre',
230 'playbooks/py27-pre'])
231 self.assertEqual([x.path for x in job.post_run],
232 ['playbooks/py27-post',
233 'playbooks/base-post'])
234 self.assertEqual([x.path for x in job.run],
235 ['playbooks/python27',
236 'playbooks/base'])
James E. Blair83005782015-12-11 14:46:03 -0800237
James E. Blair1774dd52017-02-03 10:52:32 -0800238 # Test diablo
James E. Blair83005782015-12-11 14:46:03 -0800239 change.branch = 'stable/diablo'
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700240 item = queue.enqueueChange(change)
241 item.current_build_set.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800242
243 self.assertTrue(base.changeMatches(change))
244 self.assertTrue(python27.changeMatches(change))
245 self.assertTrue(python27diablo.changeMatches(change))
James E. Blaira7f51ca2017-02-07 16:01:26 -0800246 self.assertFalse(python27essex.changeMatches(change))
James E. Blair83005782015-12-11 14:46:03 -0800247
248 item.freezeJobTree()
249 self.assertEqual(len(item.getJobs()), 1)
250 job = item.getJobs()[0]
251 self.assertEqual(job.name, 'python27')
252 self.assertEqual(job.timeout, 50)
James E. Blair1774dd52017-02-03 10:52:32 -0800253 nodes = job.nodeset.getNodes()
254 self.assertEqual(len(nodes), 1)
255 self.assertEqual(nodes[0].image, 'old')
James E. Blaira7f51ca2017-02-07 16:01:26 -0800256 self.assertEqual([x.path for x in job.pre_run],
257 ['playbooks/base-pre',
258 'playbooks/py27-pre',
259 'playbooks/py27-diablo-pre'])
260 self.assertEqual([x.path for x in job.post_run],
261 ['playbooks/py27-diablo-post',
262 'playbooks/py27-post',
263 'playbooks/base-post'])
264 self.assertEqual([x.path for x in job.run],
265 ['playbooks/py27-diablo']),
266
267 # Test essex
268 change.branch = 'stable/essex'
269 item = queue.enqueueChange(change)
270 item.current_build_set.layout = layout
271
272 self.assertTrue(base.changeMatches(change))
273 self.assertTrue(python27.changeMatches(change))
274 self.assertFalse(python27diablo.changeMatches(change))
275 self.assertTrue(python27essex.changeMatches(change))
276
277 item.freezeJobTree()
278 self.assertEqual(len(item.getJobs()), 1)
279 job = item.getJobs()[0]
280 self.assertEqual(job.name, 'python27')
281 self.assertEqual([x.path for x in job.pre_run],
282 ['playbooks/base-pre',
283 'playbooks/py27-pre',
284 'playbooks/py27-essex-pre'])
285 self.assertEqual([x.path for x in job.post_run],
286 ['playbooks/py27-essex-post',
287 'playbooks/py27-post',
288 'playbooks/base-post'])
289 self.assertEqual([x.path for x in job.run],
290 ['playbooks/python27',
291 'playbooks/base'])
James E. Blairce8a2132016-05-19 15:21:52 -0700292
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000293 def test_job_auth_inheritance(self):
294 layout = model.Layout()
James E. Blairc73c73a2017-01-20 15:15:15 -0800295 project = model.Project('project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800296 context = model.SourceContext(project, 'master', True)
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000297
298 base = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800299 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000300 'name': 'base',
301 'timeout': 30,
302 })
303 layout.addJob(base)
304 pypi_upload_without_inherit = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800305 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000306 'name': 'pypi-upload-without-inherit',
307 'parent': 'base',
308 'timeout': 40,
309 'auth': {
Ricardo Carrillo Cruz12c892b2016-11-18 15:35:49 +0000310 'secrets': [
311 'pypi-credentials',
312 ]
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000313 }
314 })
315 layout.addJob(pypi_upload_without_inherit)
316 pypi_upload_with_inherit = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800317 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000318 'name': 'pypi-upload-with-inherit',
319 'parent': 'base',
320 'timeout': 40,
321 'auth': {
322 'inherit': True,
Ricardo Carrillo Cruz12c892b2016-11-18 15:35:49 +0000323 'secrets': [
324 'pypi-credentials',
325 ]
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000326 }
327 })
328 layout.addJob(pypi_upload_with_inherit)
329 pypi_upload_with_inherit_false = configloader.JobParser.fromYaml(
330 layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800331 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000332 'name': 'pypi-upload-with-inherit-false',
333 'parent': 'base',
334 'timeout': 40,
335 'auth': {
336 'inherit': False,
Ricardo Carrillo Cruz12c892b2016-11-18 15:35:49 +0000337 'secrets': [
338 'pypi-credentials',
339 ]
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000340 }
341 })
342 layout.addJob(pypi_upload_with_inherit_false)
343 in_repo_job_without_inherit = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800344 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000345 'name': 'in-repo-job-without-inherit',
346 'parent': 'pypi-upload-without-inherit',
347 })
348 layout.addJob(in_repo_job_without_inherit)
349 in_repo_job_with_inherit = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800350 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000351 'name': 'in-repo-job-with-inherit',
352 'parent': 'pypi-upload-with-inherit',
353 })
354 layout.addJob(in_repo_job_with_inherit)
355 in_repo_job_with_inherit_false = configloader.JobParser.fromYaml(
356 layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800357 '_source_context': context,
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000358 'name': 'in-repo-job-with-inherit-false',
359 'parent': 'pypi-upload-with-inherit-false',
360 })
361 layout.addJob(in_repo_job_with_inherit_false)
362
363 self.assertNotIn('auth', in_repo_job_without_inherit.auth)
Ricardo Carrillo Cruz12c892b2016-11-18 15:35:49 +0000364 self.assertIn('secrets', in_repo_job_with_inherit.auth)
365 self.assertEquals(in_repo_job_with_inherit.auth['secrets'],
366 ['pypi-credentials'])
Ricardo Carrillo Cruz4e94f612016-07-25 16:11:56 +0000367 self.assertNotIn('auth', in_repo_job_with_inherit_false.auth)
368
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700369 def test_job_inheritance_job_tree(self):
370 layout = model.Layout()
371
372 pipeline = model.Pipeline('gate', layout)
373 layout.addPipeline(pipeline)
374 queue = model.ChangeQueue(pipeline)
James E. Blairc73c73a2017-01-20 15:15:15 -0800375 project = model.Project('project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800376 context = model.SourceContext(project, 'master', True)
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700377
378 base = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800379 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700380 'name': 'base',
381 'timeout': 30,
382 })
383 layout.addJob(base)
384 python27 = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800385 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700386 'name': 'python27',
387 'parent': 'base',
388 'timeout': 40,
389 })
390 layout.addJob(python27)
391 python27diablo = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800392 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700393 'name': 'python27',
394 'branches': [
395 'stable/diablo'
396 ],
397 'timeout': 50,
398 })
399 layout.addJob(python27diablo)
400
401 project_config = configloader.ProjectParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800402 '_source_context': context,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700403 'name': 'project',
404 'gate': {
405 'jobs': [
406 {'python27': {'timeout': 70}}
407 ]
408 }
409 })
410 layout.addProjectConfig(project_config, update_pipeline=False)
411
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700412 change = model.Change(project)
413 change.branch = 'master'
414 item = queue.enqueueChange(change)
415 item.current_build_set.layout = layout
416
417 self.assertTrue(base.changeMatches(change))
418 self.assertTrue(python27.changeMatches(change))
419 self.assertFalse(python27diablo.changeMatches(change))
420
421 item.freezeJobTree()
422 self.assertEqual(len(item.getJobs()), 1)
423 job = item.getJobs()[0]
424 self.assertEqual(job.name, 'python27')
425 self.assertEqual(job.timeout, 70)
426
427 change.branch = 'stable/diablo'
428 item = queue.enqueueChange(change)
429 item.current_build_set.layout = layout
430
431 self.assertTrue(base.changeMatches(change))
432 self.assertTrue(python27.changeMatches(change))
433 self.assertTrue(python27diablo.changeMatches(change))
434
435 item.freezeJobTree()
436 self.assertEqual(len(item.getJobs()), 1)
437 job = item.getJobs()[0]
438 self.assertEqual(job.name, 'python27')
439 self.assertEqual(job.timeout, 70)
440
Clint Byrum85493602016-11-18 11:59:47 -0800441 def test_inheritance_keeps_matchers(self):
442 layout = model.Layout()
443
444 pipeline = model.Pipeline('gate', layout)
445 layout.addPipeline(pipeline)
446 queue = model.ChangeQueue(pipeline)
James E. Blairc73c73a2017-01-20 15:15:15 -0800447 project = model.Project('project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800448 context = model.SourceContext(project, 'master', True)
Clint Byrum85493602016-11-18 11:59:47 -0800449
450 base = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800451 '_source_context': context,
Clint Byrum85493602016-11-18 11:59:47 -0800452 'name': 'base',
453 'timeout': 30,
454 })
455 layout.addJob(base)
456 python27 = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800457 '_source_context': context,
Clint Byrum85493602016-11-18 11:59:47 -0800458 'name': 'python27',
459 'parent': 'base',
460 'timeout': 40,
461 'irrelevant-files': ['^ignored-file$'],
462 })
463 layout.addJob(python27)
464
465 project_config = configloader.ProjectParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800466 '_source_context': context,
Clint Byrum85493602016-11-18 11:59:47 -0800467 'name': 'project',
468 'gate': {
469 'jobs': [
470 'python27',
471 ]
472 }
473 })
474 layout.addProjectConfig(project_config, update_pipeline=False)
475
476 change = model.Change(project)
477 change.branch = 'master'
478 change.files = ['/COMMIT_MSG', 'ignored-file']
479 item = queue.enqueueChange(change)
480 item.current_build_set.layout = layout
481
482 self.assertTrue(base.changeMatches(change))
483 self.assertFalse(python27.changeMatches(change))
484
485 item.freezeJobTree()
486 self.assertEqual([], item.getJobs())
487
James E. Blair4317e9f2016-07-15 10:05:47 -0700488 def test_job_source_project(self):
489 layout = model.Layout()
James E. Blairc73c73a2017-01-20 15:15:15 -0800490 base_project = model.Project('base_project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800491 base_context = model.SourceContext(base_project, 'master', True)
492
James E. Blair4317e9f2016-07-15 10:05:47 -0700493 base = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800494 '_source_context': base_context,
James E. Blair4317e9f2016-07-15 10:05:47 -0700495 'name': 'base',
496 })
497 layout.addJob(base)
498
James E. Blairc73c73a2017-01-20 15:15:15 -0800499 other_project = model.Project('other_project', None)
James E. Blaircdab2032017-02-01 09:09:29 -0800500 other_context = model.SourceContext(other_project, 'master', True)
James E. Blair4317e9f2016-07-15 10:05:47 -0700501 base2 = configloader.JobParser.fromYaml(layout, {
James E. Blaircdab2032017-02-01 09:09:29 -0800502 '_source_context': other_context,
James E. Blair4317e9f2016-07-15 10:05:47 -0700503 'name': 'base',
504 })
505 with testtools.ExpectedException(
506 Exception,
507 "Job base in other_project is not permitted "
508 "to shadow job base in base_project"):
509 layout.addJob(base2)
510
James E. Blairce8a2132016-05-19 15:21:52 -0700511
512class TestJobTimeData(BaseTestCase):
513 def setUp(self):
514 super(TestJobTimeData, self).setUp()
515 self.tmp_root = self.useFixture(fixtures.TempDir(
516 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
517 ).path
518
519 def test_empty_timedata(self):
520 path = os.path.join(self.tmp_root, 'job-name')
521 self.assertFalse(os.path.exists(path))
522 self.assertFalse(os.path.exists(path + '.tmp'))
523 td = model.JobTimeData(path)
524 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
525 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
526 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
527
528 def test_save_reload(self):
529 path = os.path.join(self.tmp_root, 'job-name')
530 self.assertFalse(os.path.exists(path))
531 self.assertFalse(os.path.exists(path + '.tmp'))
532 td = model.JobTimeData(path)
533 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
534 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
535 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
536 success_times = []
537 failure_times = []
538 results = []
539 for x in range(10):
540 success_times.append(int(random.random() * 1000))
541 failure_times.append(int(random.random() * 1000))
542 results.append(0)
543 results.append(1)
544 random.shuffle(results)
545 s = f = 0
546 for result in results:
547 if result:
548 td.add(failure_times[f], 'FAILURE')
549 f += 1
550 else:
551 td.add(success_times[s], 'SUCCESS')
552 s += 1
553 self.assertEqual(td.success_times, success_times)
554 self.assertEqual(td.failure_times, failure_times)
555 self.assertEqual(td.results, results[10:])
556 td.save()
557 self.assertTrue(os.path.exists(path))
558 self.assertFalse(os.path.exists(path + '.tmp'))
559 td = model.JobTimeData(path)
560 td.load()
561 self.assertEqual(td.success_times, success_times)
562 self.assertEqual(td.failure_times, failure_times)
563 self.assertEqual(td.results, results[10:])
564
565
566class TestTimeDataBase(BaseTestCase):
567 def setUp(self):
568 super(TestTimeDataBase, self).setUp()
569 self.tmp_root = self.useFixture(fixtures.TempDir(
570 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
571 ).path
572 self.db = model.TimeDataBase(self.tmp_root)
573
574 def test_timedatabase(self):
575 self.assertEqual(self.db.getEstimatedTime('job-name'), 0)
576 self.db.update('job-name', 50, 'SUCCESS')
577 self.assertEqual(self.db.getEstimatedTime('job-name'), 50)
578 self.db.update('job-name', 100, 'SUCCESS')
579 self.assertEqual(self.db.getEstimatedTime('job-name'), 75)
580 for x in range(10):
581 self.db.update('job-name', 100, 'SUCCESS')
582 self.assertEqual(self.db.getEstimatedTime('job-name'), 100)