blob: 59df5d519dc874807a8def8a0f7ae3bf998810c9 [file] [log] [blame]
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07001# Copyright 2017 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Module for task unittests."""
Xixuan Wu5ff0fac2019-01-07 10:06:35 -08006# pylint: disable=g-missing-super-call
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07007
Xinan Lindf0698a2020-02-05 22:38:11 -08008import json
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07009import re
10import unittest
11
Xixuan Wu5451a662017-10-17 10:57:40 -070012import build_lib
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070013import config_reader
14import mock
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070015import task
Xixuan Wu51bb7102019-03-18 14:51:44 -070016import task_config_reader
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070017import tot_manager
18
Xinan Lindf0698a2020-02-05 22:38:11 -080019from chromite.api.gen.test_platform.suite_scheduler import analytics_pb2
20from chromite.api.gen.chromiumos import branch_pb2
21
22from google.protobuf import json_format
23
24FAKE_UUID = 'c78e0bf3-4142-11ea-bc66-88e9fe4c5349'
25
26
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070027class FakeTotMilestoneManager(tot_manager.TotMilestoneManager):
28 """Mock class for tot_manager.TotMilestoneManager."""
29
30 def __init__(self, is_sanity):
31 self.is_sanity = is_sanity
32 self.storage_client = None
33 self.tot = self._tot_milestone()
34
35
Xixuan Wu8d2f2862018-08-28 16:48:04 -070036class FakeLabConfig(object):
Xixuan Wuf4a4c882019-03-15 14:48:26 -070037 """Mock class for config_reader.LabConfig."""
38
39 def get_cros_model_map(self):
Xinan Lin6668e0f2020-05-29 10:02:57 -070040 return {'coral': ['robo', 'nasher', 'lava'], 'hatch': ['akemi', 'kled']}
Xixuan Wuf4a4c882019-03-15 14:48:26 -070041
42
Xinan Lindf0698a2020-02-05 22:38:11 -080043class FakeBigqueryRestClient(object):
44
45 def __init__(self, rest_client, project=None, dataset=None, table=None):
46 """Initialize the mock class."""
47 self.table = table
48 self.rows = []
49
50 def insert(self, rows):
51 self.rows = rows
52 return True
53
54
Xixuan Wu5451a662017-10-17 10:57:40 -070055class TaskBaseTestCase(unittest.TestCase):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070056
57 BOARD = 'fake_board'
Xixuan Wu8d2f2862018-08-28 16:48:04 -070058 UNIBUILD_BOARD = 'coral'
Po-Hsien Wang6d589732018-05-15 17:19:34 -070059 EXCLUDE_BOARD = 'exclude_fake_board'
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070060 NAME = 'fake_name'
Brigit Rossbach6a8eea12021-01-11 09:35:31 -070061 ANALYTICS_NAME='fake_name'
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070062 SUITE = 'fake_suite'
63 POOL = 'fake_pool'
64 PLATFORM = '6182.0.0-rc2'
65 MILESTONE = '30'
66 NUM = 1
67 PRIORITY = 50
68 TIMEOUT = 600
69
70 def setUp(self):
71 tot_patcher = mock.patch('tot_manager.TotMilestoneManager')
72 self._mock_tot = tot_patcher.start()
73 self.addCleanup(tot_patcher.stop)
74 # Can't pass in False since storage_client is not mocked.
75 self._mock_tot.return_value = FakeTotMilestoneManager(True)
Xinan Lindf0698a2020-02-05 22:38:11 -080076
77 _mock_bq_client = mock.patch('rest_client.BigqueryRestClient')
78 mock_bq_client = _mock_bq_client.start()
79 self.addCleanup(_mock_bq_client.stop)
80 self.mock_bq_client = FakeBigqueryRestClient(
81 None, project='proj', dataset='dataset', table='foo')
82 mock_bq_client.return_value = self.mock_bq_client
83
Xinan Lin6668e0f2020-05-29 10:02:57 -070084 self.task = task.Task(
85 task_config_reader.TaskInfo(
86 name=self.NAME,
87 suite=self.SUITE,
88 branch_specs=[],
Brigit Rossbach6a8eea12021-01-11 09:35:31 -070089 analytics_name=self.ANALYTICS_NAME,
Xinan Lin6668e0f2020-05-29 10:02:57 -070090 pool=self.POOL,
91 num=self.NUM,
92 boards=','.join(
93 [self.BOARD, self.UNIBUILD_BOARD]),
94 exclude_boards=self.EXCLUDE_BOARD,
95 priority=self.PRIORITY,
96 timeout=self.TIMEOUT))
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070097
Xixuan Wuf4a4c882019-03-15 14:48:26 -070098 self._empty_configs = config_reader.Configs(
Brigit Rossbachbb080912020-11-18 13:52:17 -070099 lab_config=config_reader.LabConfig(None))
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700100 self._fake_configs = config_reader.Configs(
Xinan Lin576022d2020-01-21 18:12:47 -0800101 lab_config=FakeLabConfig())
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700102
Xinan Lin028f9582019-12-11 10:55:33 -0800103 self.firmware_dict = {
104 ('cros', 'fake_board'): ('fake_board-release/R30-6182.0.0-rc2'),
105 ('firmware', 'fake_board'): ('firmware-fake_board-12345.67.'
106 'A-firmwarebranch/RFoo-1.0.0-b1234567'
107 '/fake_board')
108 }
109
Xixuan Wu5451a662017-10-17 10:57:40 -0700110
111class TaskTestCase(TaskBaseTestCase):
112
113 def setUp(self):
114 super(TaskTestCase, self).setUp()
115
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700116 mock_push = mock.patch('task.Task._push_suite')
117 self._mock_push = mock_push.start()
118 self.addCleanup(mock_push.stop)
119
Xinan Lin6668e0f2020-05-29 10:02:57 -0700120 def tearDown(self):
121 self.task.boards = ','.join([self.BOARD, self.UNIBUILD_BOARD])
122 self.task.models = None
123
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700124 def testSetSpecCompareInfoEqual(self):
125 """Test compare info setting for specs that equals to a milestone."""
126 self.task.branch_specs = re.split(r'\s*,\s*', '==tot-2')
127 self.task._set_spec_compare_info()
128 self.assertTrue(self.task._version_equal_constraint)
129 self.assertFalse(self.task._version_gte_constraint)
130 self.assertFalse(self.task._version_lte_constraint)
131 self.assertEqual(self.task._bare_branches, [])
132
133 def testSetSpecCompareInfoLess(self):
134 """Test compare info setting for specs that is less than a milestone."""
135 self.task.branch_specs = re.split(r'\s*,\s*', '<=tot')
136 self.task._set_spec_compare_info()
137 self.assertFalse(self.task._version_equal_constraint)
138 self.assertFalse(self.task._version_gte_constraint)
139 self.assertTrue(self.task._version_lte_constraint)
140 self.assertEqual(self.task._bare_branches, [])
141
142 def testSetSpecCompareInfoGreater(self):
143 """Test compare info setting for specs that is greater than a milestone."""
144 self.task.branch_specs = re.split(r'\s*,\s*', '>=tot-2')
145 self.task._set_spec_compare_info()
146 self.assertFalse(self.task._version_equal_constraint)
147 self.assertTrue(self.task._version_gte_constraint)
148 self.assertFalse(self.task._version_lte_constraint)
149 self.assertEqual(self.task._bare_branches, [])
150
151 def testFitsSpecEqual(self):
152 """Test milestone check for specs that equals to a milestone."""
153 self.task.branch_specs = re.split(r'\s*,\s*', '==tot-1')
154 self.task._set_spec_compare_info()
155 self.assertFalse(self.task._fits_spec('40'))
156 self.assertTrue(self.task._fits_spec('39'))
157 self.assertFalse(self.task._fits_spec('38'))
158
159 def testFitsSpecLess(self):
160 """Test milestone check for specs that is less than a milestone."""
161 self.task.branch_specs = re.split(r'\s*,\s*', '<=tot-1')
162 self.task._set_spec_compare_info()
163 self.assertFalse(self.task._fits_spec('40'))
164 self.assertTrue(self.task._fits_spec('39'))
165 self.assertTrue(self.task._fits_spec('38'))
166
167 def testFitsSpecGreater(self):
168 """Test milestone check for specs that is greater than a milestone."""
169 self.task.branch_specs = re.split(r'\s*,\s*', '>=tot-2')
170 self.task._set_spec_compare_info()
171 self.assertTrue(self.task._fits_spec('39'))
172 self.assertTrue(self.task._fits_spec('38'))
173 self.assertFalse(self.task._fits_spec('37'))
174
Xinan Lin028f9582019-12-11 10:55:33 -0800175 def testGetFirmwareSuccessfully(self):
176 """Test get firmware from firmware_dict successfully."""
Xinan Lin39dcca82019-07-26 18:55:51 -0700177
178 firmware = self.task._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800179 'cros', self.BOARD, self.firmware_dict, None)
Xinan Lin39dcca82019-07-26 18:55:51 -0700180 self.assertEqual(
181 firmware,
182 '{0}-release/R{1}-{2}'.format(self.BOARD,
183 self.MILESTONE,
184 self.PLATFORM))
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700185 firmware = self.task._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800186 'firmware', self.BOARD, self.firmware_dict, None)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700187 self.assertEqual(
188 firmware,
Xinan Lin39dcca82019-07-26 18:55:51 -0700189 'firmware-{0}-12345.67.A-firmwarebranch/'
190 'RFoo-1.0.0-b1234567/{0}'.format(self.BOARD))
191
Xinan Lin028f9582019-12-11 10:55:33 -0800192 def testGetNonExistentBoard(self):
193 """Test get firmware for non-existent board from firmware_dict."""
194 self.assertIsNone(self.task._get_firmware_build(
195 'firmware', 'non-existent', self.firmware_dict, None))
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700196
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700197 def testScheduleCrosSuccessfully(self):
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700198 """test schedule cros builds successfully."""
199 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700200 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800201 self.firmware_dict,
202 self._fake_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700203 self.assertEqual(self._mock_push.call_count, 1)
204
205 def testScheduleCrosNonvalidBoard(self):
206 """Test schedule no cros builds due to non-allowed board."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700207 branch_builds = {('%s_2' % self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700208 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800209 self.firmware_dict,
210 self._empty_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700211 self.assertEqual(self._mock_push.call_count, 0)
212
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700213 def testScheduleCrosExcludeBoard(self):
214 """Test schedule no cros builds due to board is excluded."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700215 branch_builds = {(self.EXCLUDE_BOARD, None, 'release', '56'): '0000.00.00'}
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700216 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800217 self.firmware_dict,
218 self._empty_configs)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700219 self.assertEqual(self._mock_push.call_count, 0)
220
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700221 def testScheduleCrosSuccessfullyWithSpecifiedModel(self):
222 """Test schedule unibuild with specific model."""
223 self.task.board = self.UNIBUILD_BOARD
224 branch_builds = {(self.UNIBUILD_BOARD, 'robo', 'release', '56'):
225 '0000.00.00',
226 (self.UNIBUILD_BOARD, 'lava', 'release', '56'):
227 '0000.00.00'}
228 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800229 self.firmware_dict,
230 self._fake_configs)
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700231 self.assertEqual(self._mock_push.call_count, 2)
232
Xinan Lin6668e0f2020-05-29 10:02:57 -0700233 def testScheduleCrosSuccessfullyForBoardWithSuffix(self):
234 """Test schedule board with suffix and specific model."""
235 branch_builds = {
236 ('hatch-kernelnext', None, 'release', '56'): '0000.00.00'
237 }
238 self.task.boards = 'hatch-kernelnext'
239 self.task.models = 'hatch_akemi'
240 self.task._schedule_cros_builds(branch_builds, self.firmware_dict,
241 self._fake_configs)
242 self.assertEqual(self._mock_push.call_count, 1)
243
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700244 def testScheduleCrosNonValidSpec(self):
245 """Test schedule no cros builds due to non-allowed branch milestone."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700246 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700247 # Only run tasks whose milestone = tot (R40)
248 self.task.branch_specs = re.split(r'\s*,\s*', '==tot')
249 self.task._set_spec_compare_info()
250 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800251 self.firmware_dict,
252 self._empty_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700253 self.assertEqual(self._mock_push.call_count, 0)
254
255 def testScheduleCrosSuccessfullyWithValidFirmware(self):
256 """Test schedule cros builds successfully with valid firmware."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700257 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700258 self.task.firmware_ro_build_spec = 'firmware'
259 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800260 self.firmware_dict,
261 self._fake_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700262 self.assertEqual(self._mock_push.call_count, 1)
263
264 def testScheduleCrosWithNonValidFirmware(self):
265 """Test schedule no cros builds due to non-existent firmware."""
Xinan Lin028f9582019-12-11 10:55:33 -0800266 branch_builds = {('foo-board', None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700267 self.task.firmware_ro_build_spec = 'firmware'
268 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800269 self.firmware_dict,
270 self._empty_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700271 self.assertEqual(self._mock_push.call_count, 0)
272
273 def testScheduleLaunchControlWithFullBranches(self):
274 """Test schedule all launch control builds successfully."""
275 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
276 'git_nyc-mr1-release/shamu-userdebug/3783920']}
277 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
278 self.task.launch_control_branches = [
279 t.lstrip() for t in lc_branches.split(',')]
280 self.task._schedule_launch_control_builds(lc_builds)
281 self.assertEqual(self._mock_push.call_count, 2)
282
283 def testScheduleLaunchControlWithPartlyBranches(self):
284 """Test schedule part of launch control builds due to branch check."""
285 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
286 'git_nyc-mr1-release/shamu-userdebug/3783920']}
287 lc_branches = 'git_nyc-mr1-release'
288 self.task.launch_control_branches = [
289 t.lstrip() for t in lc_branches.split(',')]
290 self.task._schedule_launch_control_builds(lc_builds)
291 self.assertEqual(self._mock_push.call_count, 1)
292
293 def testScheduleLaunchControlWithNoBranches(self):
294 """Test schedule none of launch control builds due to branch check."""
295 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
296 'git_nyc-mr1-release/shamu-userdebug/3783920']}
297 self.task.launch_control_branches = []
298 self.task._schedule_launch_control_builds(lc_builds)
299 self.assertEqual(self._mock_push.call_count, 0)
300
301 def testScheduleLaunchControlNonvalidBoard(self):
302 """Test schedule none of launch control builds due to board check."""
303 lc_builds = {'%s_2' % self.BOARD:
304 ['git_nyc-mr2-release/shamu-userdebug/3844975',
305 'git_nyc-mr1-release/shamu-userdebug/3783920']}
306 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
307 self.task.launch_control_branches = [
308 t.lstrip() for t in lc_branches.split(',')]
309 self.task._schedule_launch_control_builds(lc_builds)
310 self.assertEqual(self._mock_push.call_count, 0)
Xixuan Wu5451a662017-10-17 10:57:40 -0700311
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700312 def testScheduleLaunchControlExcludeBoard(self):
313 """Test schedule none of launch control builds due to board check."""
314 lc_builds = {self.EXCLUDE_BOARD:
315 ['git_nyc-mr2-release/shamu-userdebug/3844975',
316 'git_nyc-mr1-release/shamu-userdebug/3783920']}
317 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
318 self.task.launch_control_branches = [
319 t.lstrip() for t in lc_branches.split(',')]
320 self.task._schedule_launch_control_builds(lc_builds)
321 self.assertEqual(self._mock_push.call_count, 0)
322
Xixuan Wu5451a662017-10-17 10:57:40 -0700323
324class TaskPushTestCase(TaskBaseTestCase):
325
326 def setUp(self):
327 super(TaskPushTestCase, self).setUp()
328 mock_push = mock.patch('task_executor.push')
329 self._mock_push = mock_push.start()
330 self.addCleanup(mock_push.stop)
331
332 def testScheduleCrOSIsPushSuccessfully(self):
333 """Test IS_PUSHED is changed if some CrOS suites are scheduled."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700334 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu5451a662017-10-17 10:57:40 -0700335 self.task.os_type = build_lib.OS_TYPE_CROS
336 self.assertTrue(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800337 [], (branch_builds, []), self.firmware_dict, self._fake_configs))
Xixuan Wu5451a662017-10-17 10:57:40 -0700338
339 def testScheduleLaunchControlIsPushSuccessfully(self):
340 """Test IS_PUSHED is changed if some launch control suites are scheduled."""
341 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
342 'git_nyc-mr1-release/shamu-userdebug/3783920']}
343 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
344 self.task.launch_control_branches = [
345 t.lstrip() for t in lc_branches.split(',')]
346 self.task.os_type = build_lib.OS_TYPES_LAUNCH_CONTROL
347 self.assertTrue(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800348 lc_builds, ([], []), self.firmware_dict,
349 self._empty_configs))
Xixuan Wu5451a662017-10-17 10:57:40 -0700350
351 def testScheduleCrosIsPushInvalidBoard(self):
352 """Test schedule no cros builds due to non-allowed board."""
Craig Bergstrom58263d32018-04-26 14:11:35 -0600353 branch_builds = (
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700354 {('%s_2' % self.BOARD, None, 'release', '56'): '0000.00.00'}, {},
Craig Bergstrom58263d32018-04-26 14:11:35 -0600355 )
Xixuan Wu5451a662017-10-17 10:57:40 -0700356 self.task.os_type = build_lib.OS_TYPE_CROS
357 self.assertFalse(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800358 [], branch_builds, self.firmware_dict, self._empty_configs))
Xixuan Wu5451a662017-10-17 10:57:40 -0700359
360 def testScheduleLaunchControlIsPushInvalidBoard(self):
361 """Test schedule none of launch control builds due to board check."""
362 lc_builds = {'%s_2' % self.BOARD:
363 ['git_nyc-mr2-release/shamu-userdebug/3844975',
364 'git_nyc-mr1-release/shamu-userdebug/3783920']}
365 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
366 self.task.launch_control_branches = [
367 t.lstrip() for t in lc_branches.split(',')]
368 self.task.os_type = build_lib.OS_TYPES_LAUNCH_CONTROL
369 self.task._schedule_launch_control_builds(lc_builds)
370 self.assertFalse(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800371 lc_builds, ([], []), self.firmware_dict,
372 self._empty_configs))
Xinan Lindf0698a2020-02-05 22:38:11 -0800373
374
375class TaskJobSectionTestCase(TaskBaseTestCase):
376
377 def setUp(self):
378 super(TaskJobSectionTestCase, self).setUp()
379 mock_push = mock.patch('task_executor.push')
380 self._mock_push = mock_push.start()
381 self.addCleanup(mock_push.stop)
382
383 def testJobSectionName(self):
384 """Test the job section name if recorded."""
385 self.task.schedule(
386 [], ([], []), self.firmware_dict, self._fake_configs)
387 self.assertEqual(self._mock_push.call_count, 0)
388 job_sec = json_format.Parse(
389 json.dumps(self.mock_bq_client.rows[0]['json']),
390 analytics_pb2.ScheduleJobSection())
391 self.assertEqual(job_sec.job_name, 'fake_name')
392
393 def testAddBoard(self):
394 """Test the configured board is recorded."""
395 new_task = task.Task(task_config_reader.TaskInfo(
396 name=self.NAME,
397 suite=self.SUITE,
398 branch_specs=[],
399 boards='coral'))
400 new_task.schedule(
401 [], ([], []), self.firmware_dict, self._fake_configs)
402 job_sec = json_format.Parse(
403 json.dumps(self.mock_bq_client.rows[0]['json']),
404 analytics_pb2.ScheduleJobSection())
405 self.assertEqual(len(job_sec.build_targets), 1)
406 self.assertEqual(job_sec.build_targets[0].name, 'coral')
407
408 def testAddModel(self):
409 """Test the configured model is recorded."""
410 new_task = task.Task(task_config_reader.TaskInfo(
411 name=self.NAME,
412 suite=self.SUITE,
413 branch_specs=[],
414 boards='coral',
415 exclude_models='coral_robo,coral_nasher'))
416 new_task.schedule(
417 [], ([], []), self.firmware_dict, self._fake_configs)
418 job_sec = json_format.Parse(
419 json.dumps(self.mock_bq_client.rows[0]['json']),
420 analytics_pb2.ScheduleJobSection())
421 # lava is the only coral model that was not excluded.
422 self.assertEqual(len(job_sec.models), 1)
423 self.assertEqual(job_sec.models[0].value, 'lava')
424
425 def testAddMatchedBuild(self):
426 """Test the matched build is recorded."""
427 branch_builds = {('coral', '', 'release', '40'):
428 '0000.00.00',
429 ('hatch', '', 'release', '37'):
430 '0000.00.00'}
431 new_task = task.Task(task_config_reader.TaskInfo(
432 name=self.NAME,
433 suite=self.SUITE,
434 branch_specs=['>=tot-2'],
435 boards='coral,hatch',
436 os_type=build_lib.OS_TYPE_CROS))
437 new_task.schedule(
438 [], (branch_builds, []), self.firmware_dict, self._fake_configs)
439 job_sec = json_format.Parse(
440 json.dumps(self.mock_bq_client.rows[0]['json']),
441 analytics_pb2.ScheduleJobSection())
442 self.assertEqual(len(job_sec.matched_builds), 1)
443 build = job_sec.matched_builds[0].release_build
444 # hatch should not be recorded as its build is too old.
445 self.assertEqual(build.build_target.name, 'coral')
446 self.assertEqual(build.milestone, 40)
447 self.assertEqual(build.chrome_os_version, '0000.00.00')
448 self.assertEqual(build.type, branch_pb2.Branch.RELEASE)
449
450 def testAddMatchedRelaxBuild(self):
451 """Test the matched relax build is recorded."""
452 relax_builds = {('coral', '', 'release', '40'):
453 '0000.00.00',
454 ('hatch', '', 'release', '37'):
455 '0000.00.00'}
456 new_task = task.Task(task_config_reader.TaskInfo(
457 name=self.NAME,
458 suite=self.SUITE,
459 branch_specs=['>=tot-2'],
460 boards='coral,hatch',
461 only_hwtest_sanity_required=True,
462 os_type=build_lib.OS_TYPE_CROS))
463 new_task.schedule(
464 [], ([], relax_builds), self.firmware_dict, self._fake_configs)
465 job_sec = json_format.Parse(
466 json.dumps(self.mock_bq_client.rows[0]['json']),
467 analytics_pb2.ScheduleJobSection())
468 self.assertEqual(len(job_sec.matched_builds), 1)
469 build = job_sec.matched_builds[0].relax_build
470 # hatch should not be recorded as its build is too old.
471 self.assertEqual(build.build_target.name, 'coral')
472 self.assertEqual(build.milestone, 40)
473 self.assertEqual(build.chrome_os_version, '0000.00.00')
474 self.assertEqual(build.type, branch_pb2.Branch.RELEASE)
475
476 def testAddMatchedFirmwareBuild(self):
477 """Test the matched firmware build is recorded."""
478 branch_builds = {('fake_board', '', 'release', '40'):
479 '0000.00.00'}
480 new_task = task.Task(task_config_reader.TaskInfo(
481 name=self.NAME,
482 suite=self.SUITE,
483 branch_specs=['>=tot-2'],
484 boards='fake_board',
485 firmware_rw_build_spec='firmware',
486 os_type=build_lib.OS_TYPE_CROS))
487 new_task.schedule(
488 [], (branch_builds, []), self.firmware_dict, self._fake_configs)
489 job_sec = json_format.Parse(
490 json.dumps(self.mock_bq_client.rows[0]['json']),
491 analytics_pb2.ScheduleJobSection())
492 self.assertEqual(len(job_sec.matched_builds), 2)
493 build = job_sec.matched_builds[1].firmware_rw_build
494 self.assertEqual(build.build_target.name, 'fake_board')
495 self.assertEqual(build.type, branch_pb2.Branch.FIRMWARE)
496 self.assertEqual(build.artifact.path,
497 self.firmware_dict['firmware', 'fake_board'])
498
499 def testScheduleJobSuccessfully(self):
500 """Test the scheduled job is recorded."""
501 branch_builds = {('coral', 'lava', 'release', '40'):
502 '0000.00.00'}
503 new_task = task.Task(task_config_reader.TaskInfo(
504 name=self.NAME,
505 suite=self.SUITE,
506 branch_specs=['>=tot-2'],
507 boards='coral',
508 os_type=build_lib.OS_TYPE_CROS))
509 with mock.patch('uuid.uuid1', return_value=FAKE_UUID):
510 new_task.schedule(
511 [], (branch_builds, []), self.firmware_dict, self._fake_configs)
512 job_sec = json_format.Parse(
513 json.dumps(self.mock_bq_client.rows[0]['json']),
514 analytics_pb2.ScheduleJobSection())
515 self.assertEqual(len(job_sec.schedule_jobs), 1)
516 job = job_sec.schedule_jobs[0]
517 self.assertEqual(job.build_target.name, 'coral')
518 self.assertEqual(job.model.value, 'lava')
519 self.assertEqual(job.queued_task_id, FAKE_UUID)
520
521 def testScheduleJobFailedforFirmwareRO(self):
522 """Test the dropped job due to firmware absence is recorded."""
523 branch_builds = {('coral', 'lava', 'release', '40'):
524 '0000.00.00'}
525 new_task = task.Task(task_config_reader.TaskInfo(
526 name=self.NAME,
527 suite=self.SUITE,
528 branch_specs=['>=tot-2'],
529 boards='coral',
530 firmware_ro_build_spec='firmware',
Brigit Rossbachbb080912020-11-18 13:52:17 -0700531 firmware_ro_version=None,
Xinan Lindf0698a2020-02-05 22:38:11 -0800532 os_type=build_lib.OS_TYPE_CROS))
533 new_task.schedule(
534 [], (branch_builds, []), {}, self._fake_configs)
535 job_sec = json_format.Parse(
536 json.dumps(self.mock_bq_client.rows[0]['json']),
537 analytics_pb2.ScheduleJobSection())
538 self.assertEqual(len(job_sec.schedule_jobs), 1)
539 job = job_sec.schedule_jobs[0]
540 self.assertEqual(job.build_target.name, 'coral')
541 self.assertEqual(job.model.value, 'lava')
Sean McAllisterb9289cd2021-06-04 09:40:29 -0600542 self.assertIn('No RO firmware build to run', job.justification)
543
544 def testScheduleJobFailedforFirmwareRW(self):
545 """Test the dropped job due to firmware absence is recorded."""
546 branch_builds = {('coral', 'lava', 'release', '40'):
547 '0000.00.00'}
548 new_task = task.Task(task_config_reader.TaskInfo(
549 name=self.NAME,
550 suite=self.SUITE,
551 branch_specs=['>=tot-2'],
552 boards='coral',
553 firmware_rw_build_spec='firmware',
554 firmware_rw_version=None,
555 os_type=build_lib.OS_TYPE_CROS))
556 new_task.schedule(
557 [], (branch_builds, []), {}, self._fake_configs)
558 job_sec = json_format.Parse(
559 json.dumps(self.mock_bq_client.rows[0]['json']),
560 analytics_pb2.ScheduleJobSection())
561 self.assertEqual(len(job_sec.schedule_jobs), 1)
562 job = job_sec.schedule_jobs[0]
563 self.assertEqual(job.build_target.name, 'coral')
564 self.assertEqual(job.model.value, 'lava')
565 self.assertIn('No RW firmware build to run', job.justification)
Xinan Lindf0698a2020-02-05 22:38:11 -0800566
567 def testScheduleJobFailedforBranchNotMaching(self):
568 """Test the dropped job due to branch spec is recorded."""
569 branch_builds = {('coral', 'lava', 'release', '38'):
570 '0000.00.00'}
571 new_task = task.Task(task_config_reader.TaskInfo(
572 name=self.NAME,
573 suite=self.SUITE,
574 branch_specs=['>=tot-1'],
575 boards='coral',
576 os_type=build_lib.OS_TYPE_CROS))
577 new_task.schedule(
578 [], (branch_builds, []), {}, self._fake_configs)
579 job_sec = json_format.Parse(
580 json.dumps(self.mock_bq_client.rows[0]['json']),
581 analytics_pb2.ScheduleJobSection())
582 self.assertEqual(len(job_sec.schedule_jobs), 1)
583 job = job_sec.schedule_jobs[0]
584 self.assertEqual(job.build_target.name, 'coral')
585 self.assertEqual(job.model.value, 'lava')
586 self.assertIn('branch_build spec', job.justification)
587
588 def testScheduleJobFailedforAnyModel(self):
589 """Test the dropped job due to any_model is recorded."""
590 branch_builds = {('coral', None, 'release', '38'):
591 '0000.00.00'}
592 new_task = task.Task(task_config_reader.TaskInfo(
593 name=self.NAME,
594 suite=self.SUITE,
595 branch_specs=['>=tot-2'],
596 boards='coral',
597 any_model=True,
598 exclude_models='coral_nasher',
599 os_type=build_lib.OS_TYPE_CROS))
600 new_task.schedule(
601 [], (branch_builds, []), {}, self._fake_configs)
602 job_sec = json_format.Parse(
603 json.dumps(self.mock_bq_client.rows[0]['json']),
604 analytics_pb2.ScheduleJobSection())
605 jobs = job_sec.schedule_jobs
Xinan Lin0673a182020-04-14 15:09:35 -0700606 # 'nasher' is excluded, hence there should be two jobs for the rest models
607 # 'robo', 'lava'.
608 self.assertEqual(2, len(jobs))
609 # The first job should be scheduled with empty model, as any_model is True.
610 self.assertEqual(jobs[0].build_target.name, 'coral')
611 self.assertEqual(jobs[0].model.value, '')
612 # The second job should be skipped and the justification is recorded.
Xinan Lindf0698a2020-02-05 22:38:11 -0800613 self.assertEqual(jobs[1].build_target.name, 'coral')
614 self.assertEqual(jobs[1].model.value, 'lava')
615 self.assertIn('Skip model lava as any_model enabled', jobs[1].justification)
Xinan Lin6668e0f2020-05-29 10:02:57 -0700616
617 def testScheduleJobForBoardWithSuffix(self):
618 """Test record a schedule job with board plus suffix and model specified."""
619 branch_builds = {('hatch-kernelnext', None, 'release', '38'): '0000.00.00'}
620 new_task = task.Task(
621 task_config_reader.TaskInfo(
622 name=self.NAME,
623 suite=self.SUITE,
624 branch_specs=['>=tot-2'],
625 boards='hatch-kernelnext',
626 models='hatch_akemi',
627 os_type=build_lib.OS_TYPE_CROS))
628 new_task.schedule([], (branch_builds, []), {}, self._fake_configs)
629 job_sec = json_format.Parse(
630 json.dumps(self.mock_bq_client.rows[0]['json']),
631 analytics_pb2.ScheduleJobSection())
632 jobs = job_sec.schedule_jobs
633 # Only the specified model should appear in the scheduled jobs.
634 self.assertEqual(1, len(jobs))
635 self.assertEqual(jobs[0].build_target.name, 'hatch-kernelnext')
636 self.assertEqual(jobs[0].model.value, 'akemi')