blob: 99cc57f9130d8fcf8c27f86dbfe206e07aa79458 [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
30 @property
31 def job(self):
James E. Blair83005782015-12-11 14:46:03 -080032 layout = model.Layout()
33 job = configloader.JobParser.fromYaml(layout, {
34 'name': 'job',
35 'irrelevant-files': [
36 '^docs/.*$'
37 ]})
Maru Newby3fe5f852015-01-13 04:22:14 +000038 return job
39
40 def test_change_matches_returns_false_for_matched_skip_if(self):
41 change = model.Change('project')
Alexander Evseevdbe6fab2015-11-19 12:46:34 +030042 change.files = ['/COMMIT_MSG', 'docs/foo']
Maru Newby3fe5f852015-01-13 04:22:14 +000043 self.assertFalse(self.job.changeMatches(change))
44
45 def test_change_matches_returns_true_for_unmatched_skip_if(self):
46 change = model.Change('project')
Alexander Evseevdbe6fab2015-11-19 12:46:34 +030047 change.files = ['/COMMIT_MSG', 'foo']
Maru Newby3fe5f852015-01-13 04:22:14 +000048 self.assertTrue(self.job.changeMatches(change))
49
Maru Newby79427a42015-02-17 17:54:45 +000050 def test_job_sets_defaults_for_boolean_attributes(self):
James E. Blair83005782015-12-11 14:46:03 -080051 self.assertIsNotNone(self.job.voting)
52
53 def test_job_inheritance(self):
54 layout = model.Layout()
James E. Blair8b1dc3f2016-07-05 16:49:00 -070055
56 pipeline = model.Pipeline('gate', layout)
57 layout.addPipeline(pipeline)
58 queue = model.ChangeQueue(pipeline)
James E. Blair4317e9f2016-07-15 10:05:47 -070059 project = model.Project('project')
James E. Blair8b1dc3f2016-07-05 16:49:00 -070060
James E. Blair83005782015-12-11 14:46:03 -080061 base = configloader.JobParser.fromYaml(layout, {
James E. Blair4317e9f2016-07-15 10:05:47 -070062 '_source_project': project,
James E. Blair83005782015-12-11 14:46:03 -080063 'name': 'base',
64 'timeout': 30,
65 })
66 layout.addJob(base)
67 python27 = configloader.JobParser.fromYaml(layout, {
James E. Blair4317e9f2016-07-15 10:05:47 -070068 '_source_project': project,
James E. Blair83005782015-12-11 14:46:03 -080069 'name': 'python27',
70 'parent': 'base',
71 'timeout': 40,
72 })
73 layout.addJob(python27)
74 python27diablo = configloader.JobParser.fromYaml(layout, {
James E. Blair4317e9f2016-07-15 10:05:47 -070075 '_source_project': project,
James E. Blair83005782015-12-11 14:46:03 -080076 'name': 'python27',
77 'branches': [
78 'stable/diablo'
79 ],
80 'timeout': 50,
81 })
82 layout.addJob(python27diablo)
83
James E. Blair8b1dc3f2016-07-05 16:49:00 -070084 project_config = configloader.ProjectParser.fromYaml(layout, {
85 'name': 'project',
86 'gate': {
87 'jobs': [
88 'python27'
89 ]
90 }
91 })
92 layout.addProjectConfig(project_config, update_pipeline=False)
James E. Blair83005782015-12-11 14:46:03 -080093
James E. Blair83005782015-12-11 14:46:03 -080094 change = model.Change(project)
95 change.branch = 'master'
96 item = queue.enqueueChange(change)
James E. Blair8b1dc3f2016-07-05 16:49:00 -070097 item.current_build_set.layout = layout
James E. Blair83005782015-12-11 14:46:03 -080098
99 self.assertTrue(base.changeMatches(change))
100 self.assertTrue(python27.changeMatches(change))
101 self.assertFalse(python27diablo.changeMatches(change))
102
103 item.freezeJobTree()
104 self.assertEqual(len(item.getJobs()), 1)
105 job = item.getJobs()[0]
106 self.assertEqual(job.name, 'python27')
107 self.assertEqual(job.timeout, 40)
108
109 change.branch = 'stable/diablo'
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700110 item = queue.enqueueChange(change)
111 item.current_build_set.layout = layout
James E. Blair83005782015-12-11 14:46:03 -0800112
113 self.assertTrue(base.changeMatches(change))
114 self.assertTrue(python27.changeMatches(change))
115 self.assertTrue(python27diablo.changeMatches(change))
116
117 item.freezeJobTree()
118 self.assertEqual(len(item.getJobs()), 1)
119 job = item.getJobs()[0]
120 self.assertEqual(job.name, 'python27')
121 self.assertEqual(job.timeout, 50)
James E. Blairce8a2132016-05-19 15:21:52 -0700122
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700123 def test_job_inheritance_job_tree(self):
124 layout = model.Layout()
125
126 pipeline = model.Pipeline('gate', layout)
127 layout.addPipeline(pipeline)
128 queue = model.ChangeQueue(pipeline)
James E. Blair4317e9f2016-07-15 10:05:47 -0700129 project = model.Project('project')
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700130
131 base = configloader.JobParser.fromYaml(layout, {
James E. Blair4317e9f2016-07-15 10:05:47 -0700132 '_source_project': project,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700133 'name': 'base',
134 'timeout': 30,
135 })
136 layout.addJob(base)
137 python27 = configloader.JobParser.fromYaml(layout, {
James E. Blair4317e9f2016-07-15 10:05:47 -0700138 '_source_project': project,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700139 'name': 'python27',
140 'parent': 'base',
141 'timeout': 40,
142 })
143 layout.addJob(python27)
144 python27diablo = configloader.JobParser.fromYaml(layout, {
James E. Blair4317e9f2016-07-15 10:05:47 -0700145 '_source_project': project,
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700146 'name': 'python27',
147 'branches': [
148 'stable/diablo'
149 ],
150 'timeout': 50,
151 })
152 layout.addJob(python27diablo)
153
154 project_config = configloader.ProjectParser.fromYaml(layout, {
155 'name': 'project',
156 'gate': {
157 'jobs': [
158 {'python27': {'timeout': 70}}
159 ]
160 }
161 })
162 layout.addProjectConfig(project_config, update_pipeline=False)
163
James E. Blair8b1dc3f2016-07-05 16:49:00 -0700164 change = model.Change(project)
165 change.branch = 'master'
166 item = queue.enqueueChange(change)
167 item.current_build_set.layout = layout
168
169 self.assertTrue(base.changeMatches(change))
170 self.assertTrue(python27.changeMatches(change))
171 self.assertFalse(python27diablo.changeMatches(change))
172
173 item.freezeJobTree()
174 self.assertEqual(len(item.getJobs()), 1)
175 job = item.getJobs()[0]
176 self.assertEqual(job.name, 'python27')
177 self.assertEqual(job.timeout, 70)
178
179 change.branch = 'stable/diablo'
180 item = queue.enqueueChange(change)
181 item.current_build_set.layout = layout
182
183 self.assertTrue(base.changeMatches(change))
184 self.assertTrue(python27.changeMatches(change))
185 self.assertTrue(python27diablo.changeMatches(change))
186
187 item.freezeJobTree()
188 self.assertEqual(len(item.getJobs()), 1)
189 job = item.getJobs()[0]
190 self.assertEqual(job.name, 'python27')
191 self.assertEqual(job.timeout, 70)
192
James E. Blair4317e9f2016-07-15 10:05:47 -0700193 def test_job_source_project(self):
194 layout = model.Layout()
195 base_project = model.Project('base_project')
196 base = configloader.JobParser.fromYaml(layout, {
197 '_source_project': base_project,
198 'name': 'base',
199 })
200 layout.addJob(base)
201
202 other_project = model.Project('other_project')
203 base2 = configloader.JobParser.fromYaml(layout, {
204 '_source_project': other_project,
205 'name': 'base',
206 })
207 with testtools.ExpectedException(
208 Exception,
209 "Job base in other_project is not permitted "
210 "to shadow job base in base_project"):
211 layout.addJob(base2)
212
James E. Blairce8a2132016-05-19 15:21:52 -0700213
214class TestJobTimeData(BaseTestCase):
215 def setUp(self):
216 super(TestJobTimeData, self).setUp()
217 self.tmp_root = self.useFixture(fixtures.TempDir(
218 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
219 ).path
220
221 def test_empty_timedata(self):
222 path = os.path.join(self.tmp_root, 'job-name')
223 self.assertFalse(os.path.exists(path))
224 self.assertFalse(os.path.exists(path + '.tmp'))
225 td = model.JobTimeData(path)
226 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
227 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
228 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
229
230 def test_save_reload(self):
231 path = os.path.join(self.tmp_root, 'job-name')
232 self.assertFalse(os.path.exists(path))
233 self.assertFalse(os.path.exists(path + '.tmp'))
234 td = model.JobTimeData(path)
235 self.assertEqual(td.success_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
236 self.assertEqual(td.failure_times, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
237 self.assertEqual(td.results, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
238 success_times = []
239 failure_times = []
240 results = []
241 for x in range(10):
242 success_times.append(int(random.random() * 1000))
243 failure_times.append(int(random.random() * 1000))
244 results.append(0)
245 results.append(1)
246 random.shuffle(results)
247 s = f = 0
248 for result in results:
249 if result:
250 td.add(failure_times[f], 'FAILURE')
251 f += 1
252 else:
253 td.add(success_times[s], 'SUCCESS')
254 s += 1
255 self.assertEqual(td.success_times, success_times)
256 self.assertEqual(td.failure_times, failure_times)
257 self.assertEqual(td.results, results[10:])
258 td.save()
259 self.assertTrue(os.path.exists(path))
260 self.assertFalse(os.path.exists(path + '.tmp'))
261 td = model.JobTimeData(path)
262 td.load()
263 self.assertEqual(td.success_times, success_times)
264 self.assertEqual(td.failure_times, failure_times)
265 self.assertEqual(td.results, results[10:])
266
267
268class TestTimeDataBase(BaseTestCase):
269 def setUp(self):
270 super(TestTimeDataBase, self).setUp()
271 self.tmp_root = self.useFixture(fixtures.TempDir(
272 rootdir=os.environ.get("ZUUL_TEST_ROOT"))
273 ).path
274 self.db = model.TimeDataBase(self.tmp_root)
275
276 def test_timedatabase(self):
277 self.assertEqual(self.db.getEstimatedTime('job-name'), 0)
278 self.db.update('job-name', 50, 'SUCCESS')
279 self.assertEqual(self.db.getEstimatedTime('job-name'), 50)
280 self.db.update('job-name', 100, 'SUCCESS')
281 self.assertEqual(self.db.getEstimatedTime('job-name'), 75)
282 for x in range(10):
283 self.db.update('job-name', 100, 'SUCCESS')
284 self.assertEqual(self.db.getEstimatedTime('job-name'), 100)