blob: 6f0576ddc194e29217a45433d178bb90b19b1787 [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 tasks triggered by suite scheduler."""
Xixuan Wu244e0ec2018-05-23 14:49:55 -07006# pylint: disable=dangerous-default-value
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07007
8from distutils import version
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07009import logging
Xinan Lindf0698a2020-02-05 22:38:11 -080010import uuid
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070011
Xinan Lindf0698a2020-02-05 22:38:11 -080012import analytics
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070013import build_lib
14import task_executor
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070015import tot_manager
16
17# The max lifetime of a suite scheduled by suite scheduler
18_JOB_MAX_RUNTIME_MINS_DEFAULT = 72 * 60
19
20# One kind of formats for RO firmware spec.
21_RELEASE_RO_FIRMWARE_SPEC = 'released_ro_'
22
23
24class SchedulingError(Exception):
25 """Raised to indicate a failure in scheduling a task."""
26
27
28class Task(object):
29 """Represents an entry from the suite_scheduler config file.
30
31 Each entry from the suite_scheduler config file maps one-to-one to a
32 Task. Each instance has enough information to schedule itself.
33 """
34
Xinan Lin33937d62020-04-14 14:41:23 -070035 def __init__(self,
36 task_info,
37 board_family_config={},
38 tot=None,
39 is_sanity=False):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070040 """Initialize a task instance.
41
42 Args:
43 task_info: a config_reader.TaskInfo object, which includes:
44 name, name of this task, e.g. 'NightlyPower'
45 suite, the name of the suite to run, e.g. 'graphics_per-day'
46 branch_specs, a pre-vetted iterable of branch specifiers,
47 e.g. ['>=R18', 'factory']
48 pool, the pool of machines to schedule tasks. Default is None.
49 num, the number of devices to shard the test suite. It could
50 be an Integer or None. By default it's None.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070051 board_families, a common separated list of board family to run this
52 task on. Boards belong to one of the board family in this list
53 would be added to task_info.boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070054 boards, a comma separated list of boards to run this task on. Default
Po-Hsien Wangdd833072018-08-16 18:09:20 -070055 is None, which allows this task to run on all boards. If same board
56 is specified in 'boards' and 'exclude_boards', we exclude this
57 board.
Xinan Linc8647112020-02-04 16:45:56 -080058 dimensions, a comma separated lists of labels. Each label is in
59 the form of 'key:value'.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070060 exclude_board_families, a common separated list of board family not to
61 run task on. Boards belong to one of the board family in this list
62 would be added to task_info.exclude_boards.
Po-Hsien Wang6d589732018-05-15 17:19:34 -070063 exclude_boards, a comma separated list of boards not to run this task
64 on. Default is None, which allows this task to run on all boards.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070065 If same board is specified in 'boards' and 'exclude_boards', we
66 exclude this board.
Xixuan Wu89897182019-01-03 15:28:01 -080067 models, a comma separated list of models to run this task on. Default
68 is None, which allows this task to run on all models. If same model
69 is specified in 'models' and 'exclude_models', we exclude this
70 model.
71 exclude_models, a comma separated list of models not to run this task
72 on. Default is None, which allows this task to run on all models.
C Shapiro09108252019-08-01 14:52:52 -050073 any_model, set to True to not pass the model parameter and allow
74 a test suite to run any/all models available for testing.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070075 priority, the string name of a priority from constants.Priorities.
76 timeout, the max lifetime of the suite in hours.
77 cros_build_spec, spec used to determine the ChromeOS build to test
78 with a firmware build, e.g., tot, R41 etc.
79 firmware_rw_build_spec, spec used to determine the firmware RW build
80 test with a ChromeOS build.
81 firmware_ro_build_spec, spec used to determine the firmware RO build
82 test with a ChromeOS build.
83 test_source, the source of test code when firmware will be updated in
84 the test. The value can be 'firmware_rw', 'firmware_ro' or 'cros'.
85 job_retry, set to True to enable job-level retry. Default is False.
Xixuan Wu80531932017-10-12 17:26:51 -070086 no_delay, set to True to raise the priority of this task in task.
87 force, set to True to schedule this suite no matter whether there's
88 duplicate jobs before.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070089 queue, so the suite jobs can start running tests with no waiting.
90 hour, an integer specifying the hour that a nightly run should be
91 triggered, default is set to 21.
92 day, an integer specifying the day of a week that a weekly run should
93 be triggered, default is set to 5 (Saturday).
94 os_type, type of OS, e.g., cros, brillo, android. Default is cros.
95 The argument is required for android/brillo builds.
96 launch_control_branches, comma separated string of launch control
97 branches. The argument is required and only applicable for
98 android/brillo builds.
99 launch_control_targets, comma separated string of build targets for
100 launch control builds. The argument is required and only
101 applicable for android/brillo builds.
102 testbed_dut_count, number of duts to test when using a testbed.
Xinan Lin4757d6f2020-03-24 22:20:31 -0700103 qs_account, quota account for the unmanaged pool which has enabled
104 Quota Scheduler.
Xixuan Wu83118dd2018-08-27 12:11:35 -0700105 board_family_config: A board family dictionary mapping board_family name
106 to its corresponding boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700107 tot: The tot manager for checking ToT. If it's None, a new tot_manager
108 instance will be initialized.
Xinan Lin33937d62020-04-14 14:41:23 -0700109 is_sanity: A boolean; true if we are running in sanity env.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700110 """
Xixuan Wu5451a662017-10-17 10:57:40 -0700111 # Indicate whether there're suites get pushed into taskqueue for this task.
112 self.is_pushed = False
113
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700114 self.name = task_info.name
115 self.suite = task_info.suite
116 self.branch_specs = task_info.branch_specs
117 self.pool = task_info.pool
118 self.num = task_info.num
119 self.priority = task_info.priority
120 self.timeout = task_info.timeout
121 self.cros_build_spec = task_info.cros_build_spec
122 self.firmware_rw_build_spec = task_info.firmware_rw_build_spec
123 self.firmware_ro_build_spec = task_info.firmware_ro_build_spec
124 self.test_source = task_info.test_source
125 self.job_retry = task_info.job_retry
126 self.no_delay = task_info.no_delay
Xixuan Wu80531932017-10-12 17:26:51 -0700127 self.force = task_info.force
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700128 self.os_type = task_info.os_type
Xinan Lin3ba18a02019-08-13 15:44:55 -0700129 self.frontdoor = task_info.frontdoor
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700130 self.testbed_dut_count = task_info.testbed_dut_count
Xixuan Wu008ee832017-10-12 16:59:34 -0700131 self.hour = task_info.hour
132 self.day = task_info.day
Craig Bergstrom58263d32018-04-26 14:11:35 -0600133 self.only_hwtest_sanity_required = task_info.only_hwtest_sanity_required
Xinan Lin4757d6f2020-03-24 22:20:31 -0700134 self.qs_account = task_info.qs_account
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700135
136 if task_info.lc_branches:
137 self.launch_control_branches = [
138 t.strip() for t in task_info.lc_branches.split(',')]
139 else:
140 self.launch_control_branches = []
141
142 if task_info.lc_targets:
143 self.launch_control_targets = [
144 t.strip() for t in task_info.lc_targets.split(',')]
145 else:
146 self.launch_control_targets = []
147
148 if task_info.boards:
149 self.boards = [t.strip() for t in task_info.boards.split(',')]
150 else:
151 self.boards = []
152
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700153 if task_info.exclude_boards:
154 self.exclude_boards = [
155 t.strip() for t in task_info.exclude_boards.split(',')]
156 else:
157 self.exclude_boards = []
158
Xixuan Wu89897182019-01-03 15:28:01 -0800159 if task_info.models:
160 self.models = [t.strip() for t in task_info.models.split(',')]
161 else:
162 self.models = []
163
164 if task_info.exclude_models:
165 self.exclude_models = [
166 t.strip() for t in task_info.exclude_models.split(',')]
167 else:
168 self.exclude_models = []
169
C Shapiro09108252019-08-01 14:52:52 -0500170 self.any_model = task_info.any_model
171
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700172 if task_info.board_families:
173 # Finetune the allowed boards list with board_families & boards.
174 families = [family.strip()
175 for family in task_info.board_families.split(',')]
176 for family in families:
177 self.boards += board_family_config.get(family, [])
Xixuan Wu89897182019-01-03 15:28:01 -0800178
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700179 if task_info.exclude_board_families:
180 # Finetune the disallowed boards list with exclude_board_families
181 # & exclude_boards.
182 families = [family.strip()
183 for family in task_info.exclude_board_families.split(',')]
184 for family in families:
185 self.exclude_boards += board_family_config.get(family, [])
186
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700187 if tot is None:
188 self.tot_manager = tot_manager.TotMilestoneManager()
189 else:
190 self.tot_manager = tot
191
Xinan Linc8647112020-02-04 16:45:56 -0800192 self.dimensions = task_info.dimensions
193
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700194 self._set_spec_compare_info()
Xinan Lin33937d62020-04-14 14:41:23 -0700195 # Sanity test does not have to upload metrics.
196 if not is_sanity:
197 self.job_section = analytics.ScheduleJobSection(task_info)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700198
Xinan Lin028f9582019-12-11 10:55:33 -0800199 def schedule(self, launch_control_builds, cros_builds_tuple,
200 firmware_builds, configs):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700201 """Schedule the task by its settings.
202
203 Args:
204 launch_control_builds: the build dict for Android boards, see
205 return value of |get_launch_control_builds|.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600206 cros_builds_tuple: the two-tuple of build dicts for ChromeOS boards,
207 see return value of |get_cros_builds|.
Xinan Lin028f9582019-12-11 10:55:33 -0800208 firmware_builds: a dict of firmware artifact, see return value of
209 |base_event.get_firmware_builds|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700210 configs: a config_reader.Configs object.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700211
212 Raises:
213 SchedulingError: if tasks that should be scheduled fail to schedule.
Xixuan Wu5451a662017-10-17 10:57:40 -0700214
215 Returns:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700216 A boolean indicator; true if there were any suites related to this
217 task which got pushed into the suites queue.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700218 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700219 assert configs.lab_config is not None
Xixuan Wu5451a662017-10-17 10:57:40 -0700220 self.is_pushed = False
221
Craig Bergstrom58263d32018-04-26 14:11:35 -0600222 branch_builds, relaxed_builds = cros_builds_tuple
223 builds_dict = branch_builds
224 if self.only_hwtest_sanity_required:
Xinan Linae7d6372019-09-12 14:42:10 -0700225 builds_dict = _split_unibuilds(relaxed_builds, configs)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600226
Xinan Lindf0698a2020-02-05 22:38:11 -0800227 # Record all target boards and models into job section.
228 lab_config = configs.lab_config
229 models_by_board = lab_config.get_cros_model_map() if lab_config else {}
230 boards = self.boards if self.boards else lab_config.get_cros_board_list()
231 for b in boards:
232 if self.exclude_boards and b in self.exclude_boards:
233 continue
234 self.job_section.add_board(b)
235 models = self.models or models_by_board.get(b, [])
236 for m in models:
237 if m and '%s_%s' % (b, m) not in self.exclude_models:
238 self.job_section.add_model(m)
239
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700240 logging.info('######## Scheduling task %s ########', self.name)
241 if self.os_type == build_lib.OS_TYPE_CROS:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600242 if not builds_dict:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700243 logging.info('No CrOS build to run, skip running.')
244 else:
Xinan Lin028f9582019-12-11 10:55:33 -0800245 self._schedule_cros_builds(builds_dict, firmware_builds, configs)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700246 else:
247 if not launch_control_builds:
248 logging.info('No Android build to run, skip running.')
249 else:
250 self._schedule_launch_control_builds(launch_control_builds)
Xinan Lindf0698a2020-02-05 22:38:11 -0800251 upload_result = False
252 try:
253 upload_result = self.job_section.upload()
254 # For any exceptions from BQ, only log it and move on.
255 except Exception as e: #pylint: disable=broad-except
256 logging.exception(str(e))
257 if not upload_result:
258 logging.warning('Failed to insert row: %r', self.job_section)
Xixuan Wu5451a662017-10-17 10:57:40 -0700259 return self.is_pushed
260
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700261 def _set_spec_compare_info(self):
262 """Set branch spec compare info for task for further check."""
263 self._bare_branches = []
264 self._version_equal_constraint = False
265 self._version_gte_constraint = False
266 self._version_lte_constraint = False
267
268 if not self.branch_specs:
269 # Any milestone is OK.
270 self._numeric_constraint = version.LooseVersion('0')
271 else:
272 self._numeric_constraint = None
273 for spec in self.branch_specs:
274 if 'tot' in spec.lower():
275 # Convert spec >=tot-1 to >=RXX.
276 tot_str = spec[spec.index('tot'):]
277 spec = spec.replace(
278 tot_str, self.tot_manager.convert_tot_spec(tot_str))
279
280 if spec.startswith('>='):
281 self._numeric_constraint = version.LooseVersion(
282 spec.lstrip('>=R'))
283 self._version_gte_constraint = True
284 elif spec.startswith('<='):
285 self._numeric_constraint = version.LooseVersion(
286 spec.lstrip('<=R'))
287 self._version_lte_constraint = True
288 elif spec.startswith('=='):
289 self._version_equal_constraint = True
290 self._numeric_constraint = version.LooseVersion(
291 spec.lstrip('==R'))
292 else:
293 self._bare_branches.append(spec)
294
295 def _fits_spec(self, branch):
296 """Check if a branch is deemed OK by this task's branch specs.
297
298 Will return whether a branch 'fits' the specifications stored in this task.
299
300 Examples:
301 Assuming tot=R40
302 t = Task('Name', 'suite', ['factory', '>=tot-1'])
303 t._fits_spec('factory') # True
304 t._fits_spec('40') # True
305 t._fits_spec('38') # False
306 t._fits_spec('firmware') # False
307
308 Args:
309 branch: the branch to check.
310
311 Returns:
312 True if branch 'fits' with stored specs, False otherwise.
313 """
314 if branch in build_lib.BARE_BRANCHES:
315 return branch in self._bare_branches
316
317 if self._numeric_constraint:
318 if self._version_equal_constraint:
319 return version.LooseVersion(branch) == self._numeric_constraint
320 elif self._version_gte_constraint:
321 return version.LooseVersion(branch) >= self._numeric_constraint
322 elif self._version_lte_constraint:
323 return version.LooseVersion(branch) <= self._numeric_constraint
324 else:
325 return version.LooseVersion(branch) >= self._numeric_constraint
326 else:
327 return False
328
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700329 def _get_latest_firmware_build_from_lab_config(self, spec, board,
330 lab_config):
331 """Get latest firmware from lab config file.
332
333 Args:
334 spec: a string build spec for RO or RW firmware, eg. firmware,
335 cros. For RO firmware, the value can also be released_ro_X.
336 board: a string board against which this task will run suite job.
337 lab_config: a config.LabConfig object, to read lab config file.
338
339 Returns:
340 A string latest firmware build.
341
342 Raises:
343 ValueError: if no firmware build list is found in lab config file.
344 """
345 index = int(spec[len(_RELEASE_RO_FIRMWARE_SPEC):])
346 released_ro_builds = lab_config.get_firmware_ro_build_list(
347 'RELEASED_RO_BUILDS_%s' % board).split(',')
348 if len(released_ro_builds) < index:
349 raise ValueError('No %dth ro_builds in the lab_config firmware '
350 'list %r' % (index, released_ro_builds))
351
352 logging.debug('Get ro_build: %s', released_ro_builds[index - 1])
353 return released_ro_builds[index - 1]
354
Xinan Lin028f9582019-12-11 10:55:33 -0800355 def _get_firmware_build(self, spec, board, firmware_build_dict, lab_config):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700356 """Get the firmware build name to test with ChromeOS build.
357
358 Args:
359 spec: a string build spec for RO or RW firmware, eg. firmware,
360 cros. For RO firmware, the value can also be released_ro_X.
361 board: a string board against which this task will run suite job.
Xinan Lin028f9582019-12-11 10:55:33 -0800362 firmware_build_dict: a dict of firmware artifacts, see return value of
363 |base_event.get_firmware_builds|.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700364 lab_config: a config.LabConfig object, to read lab config file.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700365
366 Returns:
367 A string firmware build name.
368
369 Raises:
370 ValueError: if failing to get firmware from lab config file;
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700371 """
372 if not spec or spec == 'stable':
373 # TODO(crbug.com/577316): Query stable RO firmware.
374 logging.debug('%s RO firmware build is not supported.', spec)
375 return None
376
377 try:
378 if spec.startswith(_RELEASE_RO_FIRMWARE_SPEC):
379 # For RO firmware whose value is released_ro_X, where X is the index of
380 # the list defined in lab config file:
381 # CROS/RELEASED_RO_BUILDS_[board].
382 # For example, for spec 'released_ro_2', and lab config file
383 # CROS/RELEASED_RO_BUILDS_veyron_jerry: build1,build2,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600384 # return firmware RO build should be 'build2'.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700385 return self._get_latest_firmware_build_from_lab_config(
386 spec, board, lab_config)
Xinan Lin028f9582019-12-11 10:55:33 -0800387 elif firmware_build_dict:
388 return firmware_build_dict.get((spec, board), None)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700389 else:
Xinan Lin028f9582019-12-11 10:55:33 -0800390 return None
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700391 except ValueError as e:
392 logging.warning('Failed to get firmware from lab config file'
393 'for spec %s, board %s: %s', spec, board, str(e))
394 return None
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700395
C Shapiro7f24a002017-12-05 14:25:09 -0700396 def _push_suite(
397 self,
Xinan Lindf0698a2020-02-05 22:38:11 -0800398 task_id=None,
C Shapiro7f24a002017-12-05 14:25:09 -0700399 board=None,
400 model=None,
401 cros_build=None,
402 firmware_rw_build=None,
403 firmware_ro_build=None,
404 test_source_build=None,
405 launch_control_build=None,
Xinan Lin4757d6f2020-03-24 22:20:31 -0700406 run_prod_code=False):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700407 """Schedule suite job for the task by pushing suites to SuiteQueue.
408
409 Args:
Xinan Lindf0698a2020-02-05 22:38:11 -0800410 task_id: the id to track this task in exectuion.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700411 board: the board against which this suite job run.
C Shapiro7f24a002017-12-05 14:25:09 -0700412 model: the model name for unibuild.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700413 cros_build: the CrOS build of this suite job.
414 firmware_rw_build: Firmware RW build to run this suite job with.
415 firmware_ro_build: Firmware RO build to run this suite job with.
416 test_source_build: Test source build, used for server-side
417 packaging of this suite job.
418 launch_control_build: the launch control build of this suite job.
419 run_prod_code: If True, the suite will run the test code that lives
420 in prod aka the test code currently on the lab servers. If
421 False, the control files and test code for this suite run will
422 be retrieved from the build artifacts. Default is False.
423 """
424 android_build = None
425 testbed_build = None
426
427 if self.testbed_dut_count:
428 launch_control_build = '%s#%d' % (launch_control_build,
429 self.testbed_dut_count)
430 test_source_build = launch_control_build
431 board = '%s-%d' % (board, self.testbed_dut_count)
432
433 if launch_control_build:
434 if not self.testbed_dut_count:
435 android_build = launch_control_build
436 else:
437 testbed_build = launch_control_build
438
439 suite_job_parameters = {
440 'suite': self.suite,
Xinan Lindf0698a2020-02-05 22:38:11 -0800441 'task_id': task_id,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700442 'board': board,
C Shapiro7f24a002017-12-05 14:25:09 -0700443 'model': model,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700444 build_lib.BuildVersionKey.CROS_VERSION: cros_build,
445 build_lib.BuildVersionKey.FW_RW_VERSION: firmware_rw_build,
446 build_lib.BuildVersionKey.FW_RO_VERSION: firmware_ro_build,
447 build_lib.BuildVersionKey.ANDROID_BUILD_VERSION: android_build,
448 build_lib.BuildVersionKey.TESTBED_BUILD_VERSION: testbed_build,
449 'num': self.num,
450 'pool': self.pool,
451 'priority': self.priority,
452 'timeout': self.timeout,
453 'timeout_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
454 'max_runtime_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
Xixuan Wu2ba72652017-09-15 15:49:42 -0700455 'no_wait_for_results': not self.job_retry,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700456 'test_source_build': test_source_build,
457 'job_retry': self.job_retry,
458 'no_delay': self.no_delay,
Xixuan Wu80531932017-10-12 17:26:51 -0700459 'force': self.force,
Xinan Linc8647112020-02-04 16:45:56 -0800460 'dimensions': self.dimensions,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700461 'run_prod_code': run_prod_code,
Xinan Lin4757d6f2020-03-24 22:20:31 -0700462 'qs_account': self.qs_account,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700463 }
464
Xinan Lin9e4917d2019-11-04 10:58:47 -0800465 task_executor.push(task_executor.SUITES_QUEUE,
466 tag=self.suite,
467 **suite_job_parameters)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700468 logging.info('Pushing task %r into taskqueue', suite_job_parameters)
Xixuan Wu5451a662017-10-17 10:57:40 -0700469 self.is_pushed = True
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700470
Xinan Lin028f9582019-12-11 10:55:33 -0800471 def _schedule_cros_builds(self, build_dict, firmware_build_dict, configs):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700472 """Schedule tasks with branch builds.
473
474 Args:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600475 build_dict: the build dict for ChromeOS boards, see return
Xinan Linea1efcb2019-12-30 23:46:42 -0800476 value of |build_lib.get_cros_builds|.
Xinan Lin028f9582019-12-11 10:55:33 -0800477 firmware_build_dict: a dict of firmware artifact, see return value of
478 |base_event.get_firmware_builds|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700479 configs: A config_reader.Configs object.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700480 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700481 lab_config = configs.lab_config
C Shapiro7f24a002017-12-05 14:25:09 -0700482 models_by_board = lab_config.get_cros_model_map() if lab_config else {}
C Shapiro09108252019-08-01 14:52:52 -0500483 model_agnostic_cros_builds = set()
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700484 for (board, passed_model, build_type,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600485 milestone), manifest in build_dict.iteritems():
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700486 cros_build = str(build_lib.CrOSBuild(board, build_type, milestone,
487 manifest))
488 logging.info('Running %s on %s', self.name, cros_build)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700489 if self.exclude_boards and board in self.exclude_boards:
490 logging.debug('Board %s is in excluded board list: %s',
491 board, self.exclude_boards)
492 continue
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700493
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700494 if self.boards and board not in self.boards:
495 logging.debug('Board %s is not in supported board list: %s',
496 board, self.boards)
497 continue
498
499 # Check the fitness of the build's branch for task
500 branch_build_spec = _pick_branch(build_type, milestone)
501 if not self._fits_spec(branch_build_spec):
Xinan Lindf0698a2020-02-05 22:38:11 -0800502 msg = ("branch_build spec %s doesn't fit this task's "
503 "requirement: %s") % (branch_build_spec,
504 ",".join(self.branch_specs))
505 logging.debug(msg)
506 self.job_section.add_schedule_job(board, passed_model, msg=msg)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700507 continue
508
Xinan Lindf0698a2020-02-05 22:38:11 -0800509 # Record this build as it matches both board and branch specs.
510 if self.only_hwtest_sanity_required:
511 self.job_section.add_matched_relax_build(
512 board, build_type, milestone, manifest)
513 else:
514 self.job_section.add_matched_build(
515 board, build_type, milestone, manifest)
516
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700517 firmware_rw_build = None
518 firmware_ro_build = None
519 if self.firmware_rw_build_spec or self.firmware_ro_build_spec:
520 firmware_rw_build = self._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800521 self.firmware_rw_build_spec, board, firmware_build_dict, lab_config)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700522 firmware_ro_build = self._get_firmware_build(
Xinan Lin028f9582019-12-11 10:55:33 -0800523 self.firmware_ro_build_spec, board, firmware_build_dict, lab_config)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700524
525 if not firmware_ro_build and self.firmware_ro_build_spec:
Xinan Lindf0698a2020-02-05 22:38:11 -0800526 msg = 'No RO firmware ro build to run, skip running'
527 logging.debug(msg)
528 self.job_section.add_schedule_job(board, passed_model, msg=msg)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700529 continue
530
531 if self.test_source == build_lib.BuildType.FIRMWARE_RW:
532 test_source_build = firmware_rw_build
533 else:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700534 # Default test source build to CrOS build if it's not specified.
535 # Past versions chose based on run_prod_code, but we no longer respect
536 # that option and scheduler settings should always set it to False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700537 test_source_build = cros_build
538
Xinan Lindf0698a2020-02-05 22:38:11 -0800539 # Record the matched firwmare build.
540 if firmware_rw_build:
541 self.job_section.add_matched_fw_build(
542 board,
543 self.firmware_rw_build_spec,
544 firmware_rw_build,
545 read_only=False)
546 if firmware_ro_build:
547 self.job_section.add_matched_fw_build(
548 board,
549 self.firmware_ro_build_spec,
550 firmware_ro_build,
551 read_only=True)
552
Xixuan Wub4b2f412019-05-03 11:22:31 -0700553 hwtest_board = build_lib.reshape_board(board)
Xinan Lin0550f492020-01-21 16:25:53 -0800554
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000555 models = models_by_board.get(board, [None])
C Shapiro7f24a002017-12-05 14:25:09 -0700556
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000557 for model in models:
558 if ((passed_model is not None and model == passed_model) or
559 passed_model is None):
Xixuan Wua41efa22019-05-17 14:28:04 -0700560 full_model_name = '%s_%s' % (board, model)
561 # Respect exclude first.
562 if self.exclude_models and full_model_name in self.exclude_models:
563 logging.debug("Skip model %s as it's in exclude model list %s",
564 model, self.exclude_models)
565 continue
566
567 if self.models and full_model_name not in self.models:
568 logging.debug("Skip model %s as it's not in support model list %s",
569 model, self.models)
570 continue
571
C Shapiro09108252019-08-01 14:52:52 -0500572 explicit_model = model
573
574 if self.any_model:
Xinan Lin3ba18a02019-08-13 15:44:55 -0700575 explicit_model = None
C Shapiro09108252019-08-01 14:52:52 -0500576 unique_build = str(cros_build)
577 if unique_build in model_agnostic_cros_builds:
578 # Skip since we've already run with no explicit model set.
Xinan Lindf0698a2020-02-05 22:38:11 -0800579 msg = "Skip model %s as any_model enabled for this job." % model
580 self.job_section.add_schedule_job(board, model, msg=msg)
C Shapiro09108252019-08-01 14:52:52 -0500581 continue
582 model_agnostic_cros_builds.add(unique_build)
583
Xinan Lindf0698a2020-02-05 22:38:11 -0800584 task_id = str(uuid.uuid1())
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000585 self._push_suite(
Xinan Lindf0698a2020-02-05 22:38:11 -0800586 task_id=task_id,
Xixuan Wub4b2f412019-05-03 11:22:31 -0700587 board=hwtest_board,
C Shapiro09108252019-08-01 14:52:52 -0500588 model=explicit_model,
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000589 cros_build=cros_build,
590 firmware_rw_build=firmware_rw_build,
591 firmware_ro_build=firmware_ro_build,
Xinan Lin0550f492020-01-21 16:25:53 -0800592 test_source_build=test_source_build)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700593
Xinan Lindf0698a2020-02-05 22:38:11 -0800594 self.job_section.add_schedule_job(board, model, task_id=task_id)
595
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700596 def _schedule_launch_control_builds(self, launch_control_builds):
597 """Schedule tasks with launch control builds.
598
599 Args:
600 launch_control_builds: the build dict for Android boards.
601 """
602 for board, launch_control_build in launch_control_builds.iteritems():
603 logging.debug('Running %s on %s', self.name, board)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700604 if self.exclude_boards and board in self.exclude_boards:
605 logging.debug('Board %s is in excluded board list: %s',
606 board, self.exclude_boards)
607 continue
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700608 if self.boards and board not in self.boards:
609 logging.debug('Board %s is not in supported board list: %s',
610 board, self.boards)
611 continue
612
613 for android_build in launch_control_build:
614 if not any([branch in android_build
615 for branch in self.launch_control_branches]):
616 logging.debug('Branch %s is not required to run for task '
617 '%s', android_build, self.name)
618 continue
619
620 self._push_suite(board=board,
621 test_source_build=android_build,
622 launch_control_build=android_build)
623
624
625def _pick_branch(build_type, milestone):
626 """Select branch based on build type.
627
628 If the build_type is a bare branch, return build_type as the build spec.
629 If the build_type is a normal CrOS branch, return milestone as the build
630 spec.
631
632 Args:
633 build_type: a string builder name, like 'release'.
634 milestone: a string milestone, like '55'.
635
636 Returns:
637 A string milestone if build_type represents CrOS build, otherwise
638 return build_type.
639 """
640 return build_type if build_type in build_lib.BARE_BRANCHES else milestone
Xinan Linae7d6372019-09-12 14:42:10 -0700641
642
643def _split_unibuilds(build_dict, configs):
644 """Split the uni-builds to all models under a board.
645
646 Args:
647 build_dict: the build dict for ChromeOS boards, see return
Xinan Linea1efcb2019-12-30 23:46:42 -0800648 value of |build_lib.get_cros_builds|.
Xinan Linae7d6372019-09-12 14:42:10 -0700649 configs: a config_reader.Configs object.
650
651 Returns:
652 A build dict.
653 """
654 models_by_board = configs.lab_config.get_cros_model_map()
655 if not models_by_board:
656 return build_dict
657 all_branch_build_dict = {}
658 for (board, model, config, milestone), platform in build_dict.iteritems():
659 uni_build_models = models_by_board.get(board)
660 if uni_build_models is not None and model is None:
661 for uni_build_model in uni_build_models:
662 model_key = (board, uni_build_model, config, milestone)
663 _add_build_dict(all_branch_build_dict, model_key, platform)
664 continue
665 build_key = (board, model, config, milestone)
666 _add_build_dict(all_branch_build_dict, build_key, platform)
667
668 return all_branch_build_dict
669
670
671def _add_build_dict(build_dict, key, value):
672 """A wrapper to add or update an item in build_dict."""
673 cur_manifest = build_dict.get(key)
674 if cur_manifest is None:
675 build_dict[key] = value
676 return
677 build_dict[key] = max(
678 [cur_manifest, value], key=version.LooseVersion)