blob: ef806f1f329f091cd023d2ffa0ff2c4317ce7aa2 [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
173 def testGetFirmwareFromLabConfig(self):
174 """Test get firmware from lab config successfully."""
175 with mock.patch('config_reader.LabConfig.get_firmware_ro_build_list',
176 return_value='build1,build2'):
177 firmware = self.task._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800178 'released_ro_2', self.BOARD, self.firmware_dict,
179 config_reader.LabConfig(None))
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700180 self.assertEqual(firmware, 'build2')
181
182 def testGetFirmwareFromLabConfigOutofIndex(self):
183 """Test get firmware from lab config when firmware index is invalid."""
184 with mock.patch('config_reader.LabConfig.get_firmware_ro_build_list',
185 return_value='build1,build2'):
186 self.assertRaises(ValueError,
187 self.task._get_latest_firmware_build_from_lab_config,
188 'released_ro_3',
189 self.BOARD,
190 config_reader.LabConfig(None))
191 self.assertIsNone(self.task._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800192 'released_ro_3', self.BOARD, self.firmware_dict,
193 config_reader.LabConfig(None)))
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700194
Xinan Lin028f9582019-12-11 10:55:33 -0800195 def testGetFirmwareSuccessfully(self):
196 """Test get firmware from firmware_dict successfully."""
Xinan Lin39dcca82019-07-26 18:55:51 -0700197
198 firmware = self.task._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800199 'cros', self.BOARD, self.firmware_dict, None)
Xinan Lin39dcca82019-07-26 18:55:51 -0700200 self.assertEqual(
201 firmware,
202 '{0}-release/R{1}-{2}'.format(self.BOARD,
203 self.MILESTONE,
204 self.PLATFORM))
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700205 firmware = self.task._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800206 'firmware', self.BOARD, self.firmware_dict, None)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700207 self.assertEqual(
208 firmware,
Xinan Lin39dcca82019-07-26 18:55:51 -0700209 'firmware-{0}-12345.67.A-firmwarebranch/'
210 'RFoo-1.0.0-b1234567/{0}'.format(self.BOARD))
211
Xinan Lin028f9582019-12-11 10:55:33 -0800212 def testGetNonExistentBoard(self):
213 """Test get firmware for non-existent board from firmware_dict."""
214 self.assertIsNone(self.task._get_firmware_build(
215 'firmware', 'non-existent', self.firmware_dict, None))
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700216
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700217 def testScheduleCrosSuccessfully(self):
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700218 """test schedule cros builds successfully."""
219 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700220 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800221 self.firmware_dict,
222 self._fake_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700223 self.assertEqual(self._mock_push.call_count, 1)
224
225 def testScheduleCrosNonvalidBoard(self):
226 """Test schedule no cros builds due to non-allowed board."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700227 branch_builds = {('%s_2' % self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700228 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800229 self.firmware_dict,
230 self._empty_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700231 self.assertEqual(self._mock_push.call_count, 0)
232
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700233 def testScheduleCrosExcludeBoard(self):
234 """Test schedule no cros builds due to board is excluded."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700235 branch_builds = {(self.EXCLUDE_BOARD, None, 'release', '56'): '0000.00.00'}
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700236 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800237 self.firmware_dict,
238 self._empty_configs)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700239 self.assertEqual(self._mock_push.call_count, 0)
240
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700241 def testScheduleCrosSuccessfullyWithSpecifiedModel(self):
242 """Test schedule unibuild with specific model."""
243 self.task.board = self.UNIBUILD_BOARD
244 branch_builds = {(self.UNIBUILD_BOARD, 'robo', 'release', '56'):
245 '0000.00.00',
246 (self.UNIBUILD_BOARD, 'lava', 'release', '56'):
247 '0000.00.00'}
248 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800249 self.firmware_dict,
250 self._fake_configs)
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700251 self.assertEqual(self._mock_push.call_count, 2)
252
Xinan Lin6668e0f2020-05-29 10:02:57 -0700253 def testScheduleCrosSuccessfullyForBoardWithSuffix(self):
254 """Test schedule board with suffix and specific model."""
255 branch_builds = {
256 ('hatch-kernelnext', None, 'release', '56'): '0000.00.00'
257 }
258 self.task.boards = 'hatch-kernelnext'
259 self.task.models = 'hatch_akemi'
260 self.task._schedule_cros_builds(branch_builds, self.firmware_dict,
261 self._fake_configs)
262 self.assertEqual(self._mock_push.call_count, 1)
263
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700264 def testScheduleCrosNonValidSpec(self):
265 """Test schedule no cros builds due to non-allowed branch milestone."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700266 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700267 # Only run tasks whose milestone = tot (R40)
268 self.task.branch_specs = re.split(r'\s*,\s*', '==tot')
269 self.task._set_spec_compare_info()
270 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800271 self.firmware_dict,
272 self._empty_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700273 self.assertEqual(self._mock_push.call_count, 0)
274
275 def testScheduleCrosSuccessfullyWithValidFirmware(self):
276 """Test schedule cros builds successfully with valid firmware."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700277 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700278 self.task.firmware_ro_build_spec = 'firmware'
279 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800280 self.firmware_dict,
281 self._fake_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700282 self.assertEqual(self._mock_push.call_count, 1)
283
284 def testScheduleCrosWithNonValidFirmware(self):
285 """Test schedule no cros builds due to non-existent firmware."""
Xinan Lin028f9582019-12-11 10:55:33 -0800286 branch_builds = {('foo-board', None, 'release', '56'): '0000.00.00'}
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700287 self.task.firmware_ro_build_spec = 'firmware'
288 self.task._schedule_cros_builds(branch_builds,
Xinan Lin028f9582019-12-11 10:55:33 -0800289 self.firmware_dict,
290 self._empty_configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700291 self.assertEqual(self._mock_push.call_count, 0)
292
293 def testScheduleLaunchControlWithFullBranches(self):
294 """Test schedule all launch control builds successfully."""
295 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
296 'git_nyc-mr1-release/shamu-userdebug/3783920']}
297 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
298 self.task.launch_control_branches = [
299 t.lstrip() for t in lc_branches.split(',')]
300 self.task._schedule_launch_control_builds(lc_builds)
301 self.assertEqual(self._mock_push.call_count, 2)
302
303 def testScheduleLaunchControlWithPartlyBranches(self):
304 """Test schedule part of launch control builds due to branch check."""
305 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
306 'git_nyc-mr1-release/shamu-userdebug/3783920']}
307 lc_branches = 'git_nyc-mr1-release'
308 self.task.launch_control_branches = [
309 t.lstrip() for t in lc_branches.split(',')]
310 self.task._schedule_launch_control_builds(lc_builds)
311 self.assertEqual(self._mock_push.call_count, 1)
312
313 def testScheduleLaunchControlWithNoBranches(self):
314 """Test schedule none of launch control builds due to branch check."""
315 lc_builds = {self.BOARD: ['git_nyc-mr2-release/shamu-userdebug/3844975',
316 'git_nyc-mr1-release/shamu-userdebug/3783920']}
317 self.task.launch_control_branches = []
318 self.task._schedule_launch_control_builds(lc_builds)
319 self.assertEqual(self._mock_push.call_count, 0)
320
321 def testScheduleLaunchControlNonvalidBoard(self):
322 """Test schedule none of launch control builds due to board check."""
323 lc_builds = {'%s_2' % self.BOARD:
324 ['git_nyc-mr2-release/shamu-userdebug/3844975',
325 'git_nyc-mr1-release/shamu-userdebug/3783920']}
326 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
327 self.task.launch_control_branches = [
328 t.lstrip() for t in lc_branches.split(',')]
329 self.task._schedule_launch_control_builds(lc_builds)
330 self.assertEqual(self._mock_push.call_count, 0)
Xixuan Wu5451a662017-10-17 10:57:40 -0700331
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700332 def testScheduleLaunchControlExcludeBoard(self):
333 """Test schedule none of launch control builds due to board check."""
334 lc_builds = {self.EXCLUDE_BOARD:
335 ['git_nyc-mr2-release/shamu-userdebug/3844975',
336 'git_nyc-mr1-release/shamu-userdebug/3783920']}
337 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
338 self.task.launch_control_branches = [
339 t.lstrip() for t in lc_branches.split(',')]
340 self.task._schedule_launch_control_builds(lc_builds)
341 self.assertEqual(self._mock_push.call_count, 0)
342
Xixuan Wu5451a662017-10-17 10:57:40 -0700343
344class TaskPushTestCase(TaskBaseTestCase):
345
346 def setUp(self):
347 super(TaskPushTestCase, self).setUp()
348 mock_push = mock.patch('task_executor.push')
349 self._mock_push = mock_push.start()
350 self.addCleanup(mock_push.stop)
351
352 def testScheduleCrOSIsPushSuccessfully(self):
353 """Test IS_PUSHED is changed if some CrOS suites are scheduled."""
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700354 branch_builds = {(self.BOARD, None, 'release', '56'): '0000.00.00'}
Xixuan Wu5451a662017-10-17 10:57:40 -0700355 self.task.os_type = build_lib.OS_TYPE_CROS
356 self.assertTrue(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800357 [], (branch_builds, []), self.firmware_dict, self._fake_configs))
Xixuan Wu5451a662017-10-17 10:57:40 -0700358
359 def testScheduleLaunchControlIsPushSuccessfully(self):
360 """Test IS_PUSHED is changed if some launch control suites are scheduled."""
361 lc_builds = {self.BOARD: ['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.assertTrue(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800368 lc_builds, ([], []), self.firmware_dict,
369 self._empty_configs))
Xixuan Wu5451a662017-10-17 10:57:40 -0700370
371 def testScheduleCrosIsPushInvalidBoard(self):
372 """Test schedule no cros builds due to non-allowed board."""
Craig Bergstrom58263d32018-04-26 14:11:35 -0600373 branch_builds = (
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700374 {('%s_2' % self.BOARD, None, 'release', '56'): '0000.00.00'}, {},
Craig Bergstrom58263d32018-04-26 14:11:35 -0600375 )
Xixuan Wu5451a662017-10-17 10:57:40 -0700376 self.task.os_type = build_lib.OS_TYPE_CROS
377 self.assertFalse(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800378 [], branch_builds, self.firmware_dict, self._empty_configs))
Xixuan Wu5451a662017-10-17 10:57:40 -0700379
380 def testScheduleLaunchControlIsPushInvalidBoard(self):
381 """Test schedule none of launch control builds due to board check."""
382 lc_builds = {'%s_2' % self.BOARD:
383 ['git_nyc-mr2-release/shamu-userdebug/3844975',
384 'git_nyc-mr1-release/shamu-userdebug/3783920']}
385 lc_branches = 'git_nyc-mr1-release,git_nyc-mr2-release'
386 self.task.launch_control_branches = [
387 t.lstrip() for t in lc_branches.split(',')]
388 self.task.os_type = build_lib.OS_TYPES_LAUNCH_CONTROL
389 self.task._schedule_launch_control_builds(lc_builds)
390 self.assertFalse(self.task.schedule(
Xinan Lin028f9582019-12-11 10:55:33 -0800391 lc_builds, ([], []), self.firmware_dict,
392 self._empty_configs))
Xinan Lindf0698a2020-02-05 22:38:11 -0800393
394
395class TaskJobSectionTestCase(TaskBaseTestCase):
396
397 def setUp(self):
398 super(TaskJobSectionTestCase, self).setUp()
399 mock_push = mock.patch('task_executor.push')
400 self._mock_push = mock_push.start()
401 self.addCleanup(mock_push.stop)
402
403 def testJobSectionName(self):
404 """Test the job section name if recorded."""
405 self.task.schedule(
406 [], ([], []), self.firmware_dict, self._fake_configs)
407 self.assertEqual(self._mock_push.call_count, 0)
408 job_sec = json_format.Parse(
409 json.dumps(self.mock_bq_client.rows[0]['json']),
410 analytics_pb2.ScheduleJobSection())
411 self.assertEqual(job_sec.job_name, 'fake_name')
412
413 def testAddBoard(self):
414 """Test the configured board is recorded."""
415 new_task = task.Task(task_config_reader.TaskInfo(
416 name=self.NAME,
417 suite=self.SUITE,
418 branch_specs=[],
419 boards='coral'))
420 new_task.schedule(
421 [], ([], []), self.firmware_dict, self._fake_configs)
422 job_sec = json_format.Parse(
423 json.dumps(self.mock_bq_client.rows[0]['json']),
424 analytics_pb2.ScheduleJobSection())
425 self.assertEqual(len(job_sec.build_targets), 1)
426 self.assertEqual(job_sec.build_targets[0].name, 'coral')
427
428 def testAddModel(self):
429 """Test the configured model is recorded."""
430 new_task = task.Task(task_config_reader.TaskInfo(
431 name=self.NAME,
432 suite=self.SUITE,
433 branch_specs=[],
434 boards='coral',
435 exclude_models='coral_robo,coral_nasher'))
436 new_task.schedule(
437 [], ([], []), self.firmware_dict, self._fake_configs)
438 job_sec = json_format.Parse(
439 json.dumps(self.mock_bq_client.rows[0]['json']),
440 analytics_pb2.ScheduleJobSection())
441 # lava is the only coral model that was not excluded.
442 self.assertEqual(len(job_sec.models), 1)
443 self.assertEqual(job_sec.models[0].value, 'lava')
444
445 def testAddMatchedBuild(self):
446 """Test the matched build is recorded."""
447 branch_builds = {('coral', '', 'release', '40'):
448 '0000.00.00',
449 ('hatch', '', 'release', '37'):
450 '0000.00.00'}
451 new_task = task.Task(task_config_reader.TaskInfo(
452 name=self.NAME,
453 suite=self.SUITE,
454 branch_specs=['>=tot-2'],
455 boards='coral,hatch',
456 os_type=build_lib.OS_TYPE_CROS))
457 new_task.schedule(
458 [], (branch_builds, []), self.firmware_dict, self._fake_configs)
459 job_sec = json_format.Parse(
460 json.dumps(self.mock_bq_client.rows[0]['json']),
461 analytics_pb2.ScheduleJobSection())
462 self.assertEqual(len(job_sec.matched_builds), 1)
463 build = job_sec.matched_builds[0].release_build
464 # hatch should not be recorded as its build is too old.
465 self.assertEqual(build.build_target.name, 'coral')
466 self.assertEqual(build.milestone, 40)
467 self.assertEqual(build.chrome_os_version, '0000.00.00')
468 self.assertEqual(build.type, branch_pb2.Branch.RELEASE)
469
470 def testAddMatchedRelaxBuild(self):
471 """Test the matched relax build is recorded."""
472 relax_builds = {('coral', '', 'release', '40'):
473 '0000.00.00',
474 ('hatch', '', 'release', '37'):
475 '0000.00.00'}
476 new_task = task.Task(task_config_reader.TaskInfo(
477 name=self.NAME,
478 suite=self.SUITE,
479 branch_specs=['>=tot-2'],
480 boards='coral,hatch',
481 only_hwtest_sanity_required=True,
482 os_type=build_lib.OS_TYPE_CROS))
483 new_task.schedule(
484 [], ([], relax_builds), self.firmware_dict, self._fake_configs)
485 job_sec = json_format.Parse(
486 json.dumps(self.mock_bq_client.rows[0]['json']),
487 analytics_pb2.ScheduleJobSection())
488 self.assertEqual(len(job_sec.matched_builds), 1)
489 build = job_sec.matched_builds[0].relax_build
490 # hatch should not be recorded as its build is too old.
491 self.assertEqual(build.build_target.name, 'coral')
492 self.assertEqual(build.milestone, 40)
493 self.assertEqual(build.chrome_os_version, '0000.00.00')
494 self.assertEqual(build.type, branch_pb2.Branch.RELEASE)
495
496 def testAddMatchedFirmwareBuild(self):
497 """Test the matched firmware build is recorded."""
498 branch_builds = {('fake_board', '', 'release', '40'):
499 '0000.00.00'}
500 new_task = task.Task(task_config_reader.TaskInfo(
501 name=self.NAME,
502 suite=self.SUITE,
503 branch_specs=['>=tot-2'],
504 boards='fake_board',
505 firmware_rw_build_spec='firmware',
506 os_type=build_lib.OS_TYPE_CROS))
507 new_task.schedule(
508 [], (branch_builds, []), self.firmware_dict, self._fake_configs)
509 job_sec = json_format.Parse(
510 json.dumps(self.mock_bq_client.rows[0]['json']),
511 analytics_pb2.ScheduleJobSection())
512 self.assertEqual(len(job_sec.matched_builds), 2)
513 build = job_sec.matched_builds[1].firmware_rw_build
514 self.assertEqual(build.build_target.name, 'fake_board')
515 self.assertEqual(build.type, branch_pb2.Branch.FIRMWARE)
516 self.assertEqual(build.artifact.path,
517 self.firmware_dict['firmware', 'fake_board'])
518
519 def testScheduleJobSuccessfully(self):
520 """Test the scheduled job 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 os_type=build_lib.OS_TYPE_CROS))
529 with mock.patch('uuid.uuid1', return_value=FAKE_UUID):
530 new_task.schedule(
531 [], (branch_builds, []), self.firmware_dict, 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.assertEqual(job.queued_task_id, FAKE_UUID)
540
541 def testScheduleJobFailedforFirmwareRO(self):
542 """Test the dropped job due to firmware absence is recorded."""
543 branch_builds = {('coral', 'lava', 'release', '40'):
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-2'],
549 boards='coral',
550 firmware_ro_build_spec='firmware',
551 os_type=build_lib.OS_TYPE_CROS))
552 new_task.schedule(
553 [], (branch_builds, []), {}, self._fake_configs)
554 job_sec = json_format.Parse(
555 json.dumps(self.mock_bq_client.rows[0]['json']),
556 analytics_pb2.ScheduleJobSection())
557 self.assertEqual(len(job_sec.schedule_jobs), 1)
558 job = job_sec.schedule_jobs[0]
559 self.assertEqual(job.build_target.name, 'coral')
560 self.assertEqual(job.model.value, 'lava')
561 self.assertIn('No RO firmware ro build to run', job.justification)
562
563 def testScheduleJobFailedforBranchNotMaching(self):
564 """Test the dropped job due to branch spec is recorded."""
565 branch_builds = {('coral', 'lava', 'release', '38'):
566 '0000.00.00'}
567 new_task = task.Task(task_config_reader.TaskInfo(
568 name=self.NAME,
569 suite=self.SUITE,
570 branch_specs=['>=tot-1'],
571 boards='coral',
572 os_type=build_lib.OS_TYPE_CROS))
573 new_task.schedule(
574 [], (branch_builds, []), {}, self._fake_configs)
575 job_sec = json_format.Parse(
576 json.dumps(self.mock_bq_client.rows[0]['json']),
577 analytics_pb2.ScheduleJobSection())
578 self.assertEqual(len(job_sec.schedule_jobs), 1)
579 job = job_sec.schedule_jobs[0]
580 self.assertEqual(job.build_target.name, 'coral')
581 self.assertEqual(job.model.value, 'lava')
582 self.assertIn('branch_build spec', job.justification)
583
584 def testScheduleJobFailedforAnyModel(self):
585 """Test the dropped job due to any_model is recorded."""
586 branch_builds = {('coral', None, 'release', '38'):
587 '0000.00.00'}
588 new_task = task.Task(task_config_reader.TaskInfo(
589 name=self.NAME,
590 suite=self.SUITE,
591 branch_specs=['>=tot-2'],
592 boards='coral',
593 any_model=True,
594 exclude_models='coral_nasher',
595 os_type=build_lib.OS_TYPE_CROS))
596 new_task.schedule(
597 [], (branch_builds, []), {}, self._fake_configs)
598 job_sec = json_format.Parse(
599 json.dumps(self.mock_bq_client.rows[0]['json']),
600 analytics_pb2.ScheduleJobSection())
601 jobs = job_sec.schedule_jobs
Xinan Lin0673a182020-04-14 15:09:35 -0700602 # 'nasher' is excluded, hence there should be two jobs for the rest models
603 # 'robo', 'lava'.
604 self.assertEqual(2, len(jobs))
605 # The first job should be scheduled with empty model, as any_model is True.
606 self.assertEqual(jobs[0].build_target.name, 'coral')
607 self.assertEqual(jobs[0].model.value, '')
608 # The second job should be skipped and the justification is recorded.
Xinan Lindf0698a2020-02-05 22:38:11 -0800609 self.assertEqual(jobs[1].build_target.name, 'coral')
610 self.assertEqual(jobs[1].model.value, 'lava')
611 self.assertIn('Skip model lava as any_model enabled', jobs[1].justification)
Xinan Lin6668e0f2020-05-29 10:02:57 -0700612
613 def testScheduleJobForBoardWithSuffix(self):
614 """Test record a schedule job with board plus suffix and model specified."""
615 branch_builds = {('hatch-kernelnext', None, 'release', '38'): '0000.00.00'}
616 new_task = task.Task(
617 task_config_reader.TaskInfo(
618 name=self.NAME,
619 suite=self.SUITE,
620 branch_specs=['>=tot-2'],
621 boards='hatch-kernelnext',
622 models='hatch_akemi',
623 os_type=build_lib.OS_TYPE_CROS))
624 new_task.schedule([], (branch_builds, []), {}, self._fake_configs)
625 job_sec = json_format.Parse(
626 json.dumps(self.mock_bq_client.rows[0]['json']),
627 analytics_pb2.ScheduleJobSection())
628 jobs = job_sec.schedule_jobs
629 # Only the specified model should appear in the scheduled jobs.
630 self.assertEqual(1, len(jobs))
631 self.assertEqual(jobs[0].build_target.name, 'hatch-kernelnext')
632 self.assertEqual(jobs[0].model.value, 'akemi')