blob: c91328e235f40325c4ecc79e6a366f2d134e93c6 [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'
61 SUITE = 'fake_suite'
62 POOL = 'fake_pool'
63 PLATFORM = '6182.0.0-rc2'
64 MILESTONE = '30'
65 NUM = 1
66 PRIORITY = 50
67 TIMEOUT = 600
68
69 def setUp(self):
70 tot_patcher = mock.patch('tot_manager.TotMilestoneManager')
71 self._mock_tot = tot_patcher.start()
72 self.addCleanup(tot_patcher.stop)
73 # Can't pass in False since storage_client is not mocked.
74 self._mock_tot.return_value = FakeTotMilestoneManager(True)
Xinan Lindf0698a2020-02-05 22:38:11 -080075
76 _mock_bq_client = mock.patch('rest_client.BigqueryRestClient')
77 mock_bq_client = _mock_bq_client.start()
78 self.addCleanup(_mock_bq_client.stop)
79 self.mock_bq_client = FakeBigqueryRestClient(
80 None, project='proj', dataset='dataset', table='foo')
81 mock_bq_client.return_value = self.mock_bq_client
82
Xinan Lin6668e0f2020-05-29 10:02:57 -070083 self.task = task.Task(
84 task_config_reader.TaskInfo(
85 name=self.NAME,
86 suite=self.SUITE,
87 branch_specs=[],
88 pool=self.POOL,
89 num=self.NUM,
90 boards=','.join(
91 [self.BOARD, self.UNIBUILD_BOARD]),
92 exclude_boards=self.EXCLUDE_BOARD,
93 priority=self.PRIORITY,
94 timeout=self.TIMEOUT))
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070095
Xixuan Wuf4a4c882019-03-15 14:48:26 -070096 self._empty_configs = config_reader.Configs(
Xinan Lin576022d2020-01-21 18:12:47 -080097 lab_config=config_reader.LabConfig(None))
Xixuan Wuf4a4c882019-03-15 14:48:26 -070098 self._fake_configs = config_reader.Configs(
Xinan Lin576022d2020-01-21 18:12:47 -080099 lab_config=FakeLabConfig())
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700100
Xinan Lin028f9582019-12-11 10:55:33 -0800101 self.firmware_dict = {
102 ('cros', 'fake_board'): ('fake_board-release/R30-6182.0.0-rc2'),
103 ('firmware', 'fake_board'): ('firmware-fake_board-12345.67.'
104 'A-firmwarebranch/RFoo-1.0.0-b1234567'
105 '/fake_board')
106 }
107
Xixuan Wu5451a662017-10-17 10:57:40 -0700108
109class TaskTestCase(TaskBaseTestCase):
110
111 def setUp(self):
112 super(TaskTestCase, self).setUp()
113
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700114 mock_push = mock.patch('task.Task._push_suite')
115 self._mock_push = mock_push.start()
116 self.addCleanup(mock_push.stop)
117
Xinan Lin6668e0f2020-05-29 10:02:57 -0700118 def tearDown(self):
119 self.task.boards = ','.join([self.BOARD, self.UNIBUILD_BOARD])
120 self.task.models = None
121
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700122 def testSetSpecCompareInfoEqual(self):
123 """Test compare info setting for specs that equals to a milestone."""
124 self.task.branch_specs = re.split(r'\s*,\s*', '==tot-2')
125 self.task._set_spec_compare_info()
126 self.assertTrue(self.task._version_equal_constraint)
127 self.assertFalse(self.task._version_gte_constraint)
128 self.assertFalse(self.task._version_lte_constraint)
129 self.assertEqual(self.task._bare_branches, [])
130
131 def testSetSpecCompareInfoLess(self):
132 """Test compare info setting for specs that is less than a milestone."""
133 self.task.branch_specs = re.split(r'\s*,\s*', '<=tot')
134 self.task._set_spec_compare_info()
135 self.assertFalse(self.task._version_equal_constraint)
136 self.assertFalse(self.task._version_gte_constraint)
137 self.assertTrue(self.task._version_lte_constraint)
138 self.assertEqual(self.task._bare_branches, [])
139
140 def testSetSpecCompareInfoGreater(self):
141 """Test compare info setting for specs that is greater than a milestone."""
142 self.task.branch_specs = re.split(r'\s*,\s*', '>=tot-2')
143 self.task._set_spec_compare_info()
144 self.assertFalse(self.task._version_equal_constraint)
145 self.assertTrue(self.task._version_gte_constraint)
146 self.assertFalse(self.task._version_lte_constraint)
147 self.assertEqual(self.task._bare_branches, [])
148
149 def testFitsSpecEqual(self):
150 """Test milestone check for specs that equals to a milestone."""
151 self.task.branch_specs = re.split(r'\s*,\s*', '==tot-1')
152 self.task._set_spec_compare_info()
153 self.assertFalse(self.task._fits_spec('40'))
154 self.assertTrue(self.task._fits_spec('39'))
155 self.assertFalse(self.task._fits_spec('38'))
156
157 def testFitsSpecLess(self):
158 """Test milestone check for specs that is less than a milestone."""
159 self.task.branch_specs = re.split(r'\s*,\s*', '<=tot-1')
160 self.task._set_spec_compare_info()
161 self.assertFalse(self.task._fits_spec('40'))
162 self.assertTrue(self.task._fits_spec('39'))
163 self.assertTrue(self.task._fits_spec('38'))
164
165 def testFitsSpecGreater(self):
166 """Test milestone check for specs that is greater than a milestone."""
167 self.task.branch_specs = re.split(r'\s*,\s*', '>=tot-2')
168 self.task._set_spec_compare_info()
169 self.assertTrue(self.task._fits_spec('39'))
170 self.assertTrue(self.task._fits_spec('38'))
171 self.assertFalse(self.task._fits_spec('37'))
172
Xinan Lin028f9582019-12-11 10:55:33 -0800173 def testGetFirmwareSuccessfully(self):
174 """Test get firmware from firmware_dict successfully."""
Xinan Lin39dcca82019-07-26 18:55:51 -0700175
176 firmware = self.task._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800177 'cros', self.BOARD, self.firmware_dict, None)
Xinan Lin39dcca82019-07-26 18:55:51 -0700178 self.assertEqual(
179 firmware,
180 '{0}-release/R{1}-{2}'.format(self.BOARD,
181 self.MILESTONE,
182 self.PLATFORM))
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700183 firmware = self.task._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800184 'firmware', self.BOARD, self.firmware_dict, None)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700185 self.assertEqual(
186 firmware,
Xinan Lin39dcca82019-07-26 18:55:51 -0700187 'firmware-{0}-12345.67.A-firmwarebranch/'
188 'RFoo-1.0.0-b1234567/{0}'.format(self.BOARD))
189
Xinan Lin028f9582019-12-11 10:55:33 -0800190 def testGetNonExistentBoard(self):
191 """Test get firmware for non-existent board from firmware_dict."""
192 self.assertIsNone(self.task._get_firmware_build(
193 'firmware', 'non-existent', self.firmware_dict, None))
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700194
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700195 def testScheduleCrosSuccessfully(self):
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700196 """test schedule cros builds successfully."""
197 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700198 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800199 self.firmware_dict,
200 self._fake_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700201 self.assertEqual(self._mock_push.call_count, 1)
202
203 def testScheduleCrosNonvalidBoard(self):
204 """Test schedule no cros builds due to non-allowed board."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700205 branch_builds = {('%s_2' % self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700206 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800207 self.firmware_dict,
208 self._empty_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700209 self.assertEqual(self._mock_push.call_count, 0)
210
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700211 def testScheduleCrosExcludeBoard(self):
212 """Test schedule no cros builds due to board is excluded."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700213 branch_builds = {(self.EXCLUDE_BOARD, None, 'release', '56'): '0000.00.00'}
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700214 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800215 self.firmware_dict,
216 self._empty_configs)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700217 self.assertEqual(self._mock_push.call_count, 0)
218
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700219 def testScheduleCrosSuccessfullyWithSpecifiedModel(self):
220 """Test schedule unibuild with specific model."""
221 self.task.board = self.UNIBUILD_BOARD
222 branch_builds = {(self.UNIBUILD_BOARD, 'robo', 'release', '56'):
223 '0000.00.00',
224 (self.UNIBUILD_BOARD, 'lava', 'release', '56'):
225 '0000.00.00'}
226 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800227 self.firmware_dict,
228 self._fake_configs)
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700229 self.assertEqual(self._mock_push.call_count, 2)
230
Xinan Lin6668e0f2020-05-29 10:02:57 -0700231 def testScheduleCrosSuccessfullyForBoardWithSuffix(self):
232 """Test schedule board with suffix and specific model."""
233 branch_builds = {
234 ('hatch-kernelnext', None, 'release', '56'): '0000.00.00'
235 }
236 self.task.boards = 'hatch-kernelnext'
237 self.task.models = 'hatch_akemi'
238 self.task._schedule_cros_builds(branch_builds, self.firmware_dict,
239 self._fake_configs)
240 self.assertEqual(self._mock_push.call_count, 1)
241
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700242 def testScheduleCrosNonValidSpec(self):
243 """Test schedule no cros builds due to non-allowed branch milestone."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700244 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700245 # Only run tasks whose milestone = tot (R40)
246 self.task.branch_specs = re.split(r'\s*,\s*', '==tot')
247 self.task._set_spec_compare_info()
248 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800249 self.firmware_dict,
250 self._empty_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700251 self.assertEqual(self._mock_push.call_count, 0)
252
253 def testScheduleCrosSuccessfullyWithValidFirmware(self):
254 """Test schedule cros builds successfully with valid firmware."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700255 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700256 self.task.firmware_ro_build_spec = 'firmware'
257 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800258 self.firmware_dict,
259 self._fake_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700260 self.assertEqual(self._mock_push.call_count, 1)
261
262 def testScheduleCrosWithNonValidFirmware(self):
263 """Test schedule no cros builds due to non-existent firmware."""
Xinan Lin028f9582019-12-11 10:55:33 -0800264 branch_builds = {('foo-board', None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700265 self.task.firmware_ro_build_spec = 'firmware'
266 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800267 self.firmware_dict,
268 self._empty_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700269 self.assertEqual(self._mock_push.call_count, 0)
270
271 def testScheduleLaunchControlWithFullBranches(self):
272 """Test schedule all launch control builds successfully."""
273 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
274 'git_nyc-mr1-release/shamu-userdebug/3783920']}
275 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
276 self.task.launch_control_branches = [
277 t.lstrip() for t in lc_branches.split(',')]
278 self.task._schedule_launch_control_builds(lc_builds)
279 self.assertEqual(self._mock_push.call_count, 2)
280
281 def testScheduleLaunchControlWithPartlyBranches(self):
282 """Test schedule part of launch control builds due to branch check."""
283 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
284 'git_nyc-mr1-release/shamu-userdebug/3783920']}
285 lc_branches = 'git_nyc-mr1-release'
286 self.task.launch_control_branches = [
287 t.lstrip() for t in lc_branches.split(',')]
288 self.task._schedule_launch_control_builds(lc_builds)
289 self.assertEqual(self._mock_push.call_count, 1)
290
291 def testScheduleLaunchControlWithNoBranches(self):
292 """Test schedule none of launch control builds due to branch check."""
293 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
294 'git_nyc-mr1-release/shamu-userdebug/3783920']}
295 self.task.launch_control_branches = []
296 self.task._schedule_launch_control_builds(lc_builds)
297 self.assertEqual(self._mock_push.call_count, 0)
298
299 def testScheduleLaunchControlNonvalidBoard(self):
300 """Test schedule none of launch control builds due to board check."""
301 lc_builds = {'%s_2' % self.BOARD:
302 ['git_nyc-mr2-release/shamu-userdebug/3844975',
303 'git_nyc-mr1-release/shamu-userdebug/3783920']}
304 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
305 self.task.launch_control_branches = [
306 t.lstrip() for t in lc_branches.split(',')]
307 self.task._schedule_launch_control_builds(lc_builds)
308 self.assertEqual(self._mock_push.call_count, 0)
Xixuan Wu5451a662017-10-17 10:57:40 -0700309
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700310 def testScheduleLaunchControlExcludeBoard(self):
311 """Test schedule none of launch control builds due to board check."""
312 lc_builds = {self.EXCLUDE_BOARD:
313 ['git_nyc-mr2-release/shamu-userdebug/3844975',
314 'git_nyc-mr1-release/shamu-userdebug/3783920']}
315 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
316 self.task.launch_control_branches = [
317 t.lstrip() for t in lc_branches.split(',')]
318 self.task._schedule_launch_control_builds(lc_builds)
319 self.assertEqual(self._mock_push.call_count, 0)
320
Xixuan Wu5451a662017-10-17 10:57:40 -0700321
322class TaskPushTestCase(TaskBaseTestCase):
323
324 def setUp(self):
325 super(TaskPushTestCase, self).setUp()
326 mock_push = mock.patch('task_executor.push')
327 self._mock_push = mock_push.start()
328 self.addCleanup(mock_push.stop)
329
330 def testScheduleCrOSIsPushSuccessfully(self):
331 """Test IS_PUSHED is changed if some CrOS suites are scheduled."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700332 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu5451a662017-10-17 10:57:40 -0700333 self.task.os_type = build_lib.OS_TYPE_CROS
334 self.assertTrue(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800335 [], (branch_builds, []), self.firmware_dict, self._fake_configs))
Xixuan Wu5451a662017-10-17 10:57:40 -0700336
337 def testScheduleLaunchControlIsPushSuccessfully(self):
338 """Test IS_PUSHED is changed if some launch control suites are scheduled."""
339 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
340 'git_nyc-mr1-release/shamu-userdebug/3783920']}
341 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
342 self.task.launch_control_branches = [
343 t.lstrip() for t in lc_branches.split(',')]
344 self.task.os_type = build_lib.OS_TYPES_LAUNCH_CONTROL
345 self.assertTrue(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800346 lc_builds, ([], []), self.firmware_dict,
347 self._empty_configs))
Xixuan Wu5451a662017-10-17 10:57:40 -0700348
349 def testScheduleCrosIsPushInvalidBoard(self):
350 """Test schedule no cros builds due to non-allowed board."""
Craig Bergstrom58263d32018-04-26 14:11:35 -0600351 branch_builds = (
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700352 {('%s_2' % self.BOARD, None, 'release', '56'): '0000.00.00'}, {},
Craig Bergstrom58263d32018-04-26 14:11:35 -0600353 )
Xixuan Wu5451a662017-10-17 10:57:40 -0700354 self.task.os_type = build_lib.OS_TYPE_CROS
355 self.assertFalse(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800356 [], branch_builds, self.firmware_dict, self._empty_configs))
Xixuan Wu5451a662017-10-17 10:57:40 -0700357
358 def testScheduleLaunchControlIsPushInvalidBoard(self):
359 """Test schedule none of launch control builds due to board check."""
360 lc_builds = {'%s_2' % self.BOARD:
361 ['git_nyc-mr2-release/shamu-userdebug/3844975',
362 'git_nyc-mr1-release/shamu-userdebug/3783920']}
363 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
364 self.task.launch_control_branches = [
365 t.lstrip() for t in lc_branches.split(',')]
366 self.task.os_type = build_lib.OS_TYPES_LAUNCH_CONTROL
367 self.task._schedule_launch_control_builds(lc_builds)
368 self.assertFalse(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800369 lc_builds, ([], []), self.firmware_dict,
370 self._empty_configs))
Xinan Lindf0698a2020-02-05 22:38:11 -0800371
372
373class TaskJobSectionTestCase(TaskBaseTestCase):
374
375 def setUp(self):
376 super(TaskJobSectionTestCase, self).setUp()
377 mock_push = mock.patch('task_executor.push')
378 self._mock_push = mock_push.start()
379 self.addCleanup(mock_push.stop)
380
381 def testJobSectionName(self):
382 """Test the job section name if recorded."""
383 self.task.schedule(
384 [], ([], []), self.firmware_dict, self._fake_configs)
385 self.assertEqual(self._mock_push.call_count, 0)
386 job_sec = json_format.Parse(
387 json.dumps(self.mock_bq_client.rows[0]['json']),
388 analytics_pb2.ScheduleJobSection())
389 self.assertEqual(job_sec.job_name, 'fake_name')
390
391 def testAddBoard(self):
392 """Test the configured board is recorded."""
393 new_task = task.Task(task_config_reader.TaskInfo(
394 name=self.NAME,
395 suite=self.SUITE,
396 branch_specs=[],
397 boards='coral'))
398 new_task.schedule(
399 [], ([], []), self.firmware_dict, self._fake_configs)
400 job_sec = json_format.Parse(
401 json.dumps(self.mock_bq_client.rows[0]['json']),
402 analytics_pb2.ScheduleJobSection())
403 self.assertEqual(len(job_sec.build_targets), 1)
404 self.assertEqual(job_sec.build_targets[0].name, 'coral')
405
406 def testAddModel(self):
407 """Test the configured model is recorded."""
408 new_task = task.Task(task_config_reader.TaskInfo(
409 name=self.NAME,
410 suite=self.SUITE,
411 branch_specs=[],
412 boards='coral',
413 exclude_models='coral_robo,coral_nasher'))
414 new_task.schedule(
415 [], ([], []), self.firmware_dict, self._fake_configs)
416 job_sec = json_format.Parse(
417 json.dumps(self.mock_bq_client.rows[0]['json']),
418 analytics_pb2.ScheduleJobSection())
419 # lava is the only coral model that was not excluded.
420 self.assertEqual(len(job_sec.models), 1)
421 self.assertEqual(job_sec.models[0].value, 'lava')
422
423 def testAddMatchedBuild(self):
424 """Test the matched build is recorded."""
425 branch_builds = {('coral', '', 'release', '40'):
426 '0000.00.00',
427 ('hatch', '', 'release', '37'):
428 '0000.00.00'}
429 new_task = task.Task(task_config_reader.TaskInfo(
430 name=self.NAME,
431 suite=self.SUITE,
432 branch_specs=['>=tot-2'],
433 boards='coral,hatch',
434 os_type=build_lib.OS_TYPE_CROS))
435 new_task.schedule(
436 [], (branch_builds, []), self.firmware_dict, self._fake_configs)
437 job_sec = json_format.Parse(
438 json.dumps(self.mock_bq_client.rows[0]['json']),
439 analytics_pb2.ScheduleJobSection())
440 self.assertEqual(len(job_sec.matched_builds), 1)
441 build = job_sec.matched_builds[0].release_build
442 # hatch should not be recorded as its build is too old.
443 self.assertEqual(build.build_target.name, 'coral')
444 self.assertEqual(build.milestone, 40)
445 self.assertEqual(build.chrome_os_version, '0000.00.00')
446 self.assertEqual(build.type, branch_pb2.Branch.RELEASE)
447
448 def testAddMatchedRelaxBuild(self):
449 """Test the matched relax build is recorded."""
450 relax_builds = {('coral', '', 'release', '40'):
451 '0000.00.00',
452 ('hatch', '', 'release', '37'):
453 '0000.00.00'}
454 new_task = task.Task(task_config_reader.TaskInfo(
455 name=self.NAME,
456 suite=self.SUITE,
457 branch_specs=['>=tot-2'],
458 boards='coral,hatch',
459 only_hwtest_sanity_required=True,
460 os_type=build_lib.OS_TYPE_CROS))
461 new_task.schedule(
462 [], ([], relax_builds), self.firmware_dict, self._fake_configs)
463 job_sec = json_format.Parse(
464 json.dumps(self.mock_bq_client.rows[0]['json']),
465 analytics_pb2.ScheduleJobSection())
466 self.assertEqual(len(job_sec.matched_builds), 1)
467 build = job_sec.matched_builds[0].relax_build
468 # hatch should not be recorded as its build is too old.
469 self.assertEqual(build.build_target.name, 'coral')
470 self.assertEqual(build.milestone, 40)
471 self.assertEqual(build.chrome_os_version, '0000.00.00')
472 self.assertEqual(build.type, branch_pb2.Branch.RELEASE)
473
474 def testAddMatchedFirmwareBuild(self):
475 """Test the matched firmware build is recorded."""
476 branch_builds = {('fake_board', '', 'release', '40'):
477 '0000.00.00'}
478 new_task = task.Task(task_config_reader.TaskInfo(
479 name=self.NAME,
480 suite=self.SUITE,
481 branch_specs=['>=tot-2'],
482 boards='fake_board',
483 firmware_rw_build_spec='firmware',
484 os_type=build_lib.OS_TYPE_CROS))
485 new_task.schedule(
486 [], (branch_builds, []), self.firmware_dict, self._fake_configs)
487 job_sec = json_format.Parse(
488 json.dumps(self.mock_bq_client.rows[0]['json']),
489 analytics_pb2.ScheduleJobSection())
490 self.assertEqual(len(job_sec.matched_builds), 2)
491 build = job_sec.matched_builds[1].firmware_rw_build
492 self.assertEqual(build.build_target.name, 'fake_board')
493 self.assertEqual(build.type, branch_pb2.Branch.FIRMWARE)
494 self.assertEqual(build.artifact.path,
495 self.firmware_dict['firmware', 'fake_board'])
496
497 def testScheduleJobSuccessfully(self):
498 """Test the scheduled job is recorded."""
499 branch_builds = {('coral', 'lava', 'release', '40'):
500 '0000.00.00'}
501 new_task = task.Task(task_config_reader.TaskInfo(
502 name=self.NAME,
503 suite=self.SUITE,
504 branch_specs=['>=tot-2'],
505 boards='coral',
506 os_type=build_lib.OS_TYPE_CROS))
507 with mock.patch('uuid.uuid1', return_value=FAKE_UUID):
508 new_task.schedule(
509 [], (branch_builds, []), self.firmware_dict, self._fake_configs)
510 job_sec = json_format.Parse(
511 json.dumps(self.mock_bq_client.rows[0]['json']),
512 analytics_pb2.ScheduleJobSection())
513 self.assertEqual(len(job_sec.schedule_jobs), 1)
514 job = job_sec.schedule_jobs[0]
515 self.assertEqual(job.build_target.name, 'coral')
516 self.assertEqual(job.model.value, 'lava')
517 self.assertEqual(job.queued_task_id, FAKE_UUID)
518
519 def testScheduleJobFailedforFirmwareRO(self):
520 """Test the dropped job due to firmware absence is recorded."""
521 branch_builds = {('coral', 'lava', 'release', '40'):
522 '0000.00.00'}
523 new_task = task.Task(task_config_reader.TaskInfo(
524 name=self.NAME,
525 suite=self.SUITE,
526 branch_specs=['>=tot-2'],
527 boards='coral',
528 firmware_ro_build_spec='firmware',
529 os_type=build_lib.OS_TYPE_CROS))
530 new_task.schedule(
531 [], (branch_builds, []), {}, self._fake_configs)
532 job_sec = json_format.Parse(
533 json.dumps(self.mock_bq_client.rows[0]['json']),
534 analytics_pb2.ScheduleJobSection())
535 self.assertEqual(len(job_sec.schedule_jobs), 1)
536 job = job_sec.schedule_jobs[0]
537 self.assertEqual(job.build_target.name, 'coral')
538 self.assertEqual(job.model.value, 'lava')
539 self.assertIn('No RO firmware ro build to run', job.justification)
540
541 def testScheduleJobFailedforBranchNotMaching(self):
542 """Test the dropped job due to branch spec is recorded."""
543 branch_builds = {('coral', 'lava', 'release', '38'):
544 '0000.00.00'}
545 new_task = task.Task(task_config_reader.TaskInfo(
546 name=self.NAME,
547 suite=self.SUITE,
548 branch_specs=['>=tot-1'],
549 boards='coral',
550 os_type=build_lib.OS_TYPE_CROS))
551 new_task.schedule(
552 [], (branch_builds, []), {}, self._fake_configs)
553 job_sec = json_format.Parse(
554 json.dumps(self.mock_bq_client.rows[0]['json']),
555 analytics_pb2.ScheduleJobSection())
556 self.assertEqual(len(job_sec.schedule_jobs), 1)
557 job = job_sec.schedule_jobs[0]
558 self.assertEqual(job.build_target.name, 'coral')
559 self.assertEqual(job.model.value, 'lava')
560 self.assertIn('branch_build spec', job.justification)
561
562 def testScheduleJobFailedforAnyModel(self):
563 """Test the dropped job due to any_model is recorded."""
564 branch_builds = {('coral', None, 'release', '38'):
565 '0000.00.00'}
566 new_task = task.Task(task_config_reader.TaskInfo(
567 name=self.NAME,
568 suite=self.SUITE,
569 branch_specs=['>=tot-2'],
570 boards='coral',
571 any_model=True,
572 exclude_models='coral_nasher',
573 os_type=build_lib.OS_TYPE_CROS))
574 new_task.schedule(
575 [], (branch_builds, []), {}, self._fake_configs)
576 job_sec = json_format.Parse(
577 json.dumps(self.mock_bq_client.rows[0]['json']),
578 analytics_pb2.ScheduleJobSection())
579 jobs = job_sec.schedule_jobs
Xinan Lin0673a182020-04-14 15:09:35 -0700580 # 'nasher' is excluded, hence there should be two jobs for the rest models
581 # 'robo', 'lava'.
582 self.assertEqual(2, len(jobs))
583 # The first job should be scheduled with empty model, as any_model is True.
584 self.assertEqual(jobs[0].build_target.name, 'coral')
585 self.assertEqual(jobs[0].model.value, '')
586 # The second job should be skipped and the justification is recorded.
Xinan Lindf0698a2020-02-05 22:38:11 -0800587 self.assertEqual(jobs[1].build_target.name, 'coral')
588 self.assertEqual(jobs[1].model.value, 'lava')
589 self.assertIn('Skip model lava as any_model enabled', jobs[1].justification)
Xinan Lin6668e0f2020-05-29 10:02:57 -0700590
591 def testScheduleJobForBoardWithSuffix(self):
592 """Test record a schedule job with board plus suffix and model specified."""
593 branch_builds = {('hatch-kernelnext', None, 'release', '38'): '0000.00.00'}
594 new_task = task.Task(
595 task_config_reader.TaskInfo(
596 name=self.NAME,
597 suite=self.SUITE,
598 branch_specs=['>=tot-2'],
599 boards='hatch-kernelnext',
600 models='hatch_akemi',
601 os_type=build_lib.OS_TYPE_CROS))
602 new_task.schedule([], (branch_builds, []), {}, self._fake_configs)
603 job_sec = json_format.Parse(
604 json.dumps(self.mock_bq_client.rows[0]['json']),
605 analytics_pb2.ScheduleJobSection())
606 jobs = job_sec.schedule_jobs
607 # Only the specified model should appear in the scheduled jobs.
608 self.assertEqual(1, len(jobs))
609 self.assertEqual(jobs[0].build_target.name, 'hatch-kernelnext')
610 self.assertEqual(jobs[0].model.value, 'akemi')