blob: 4156f9a0f08afb8d988ab9d9c7fdc8300524bbae [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."""
6# pylint: disable=g-bad-import-order
Xixuan Wu244e0ec2018-05-23 14:49:55 -07007# pylint: disable=dangerous-default-value
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07008
9from distutils import version
10import MySQLdb
11import logging
12
13import build_lib
Xixuan Wued878ea2019-03-18 15:32:16 -070014import skylab
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070015import task_executor
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070016import tot_manager
17
18# The max lifetime of a suite scheduled by suite scheduler
19_JOB_MAX_RUNTIME_MINS_DEFAULT = 72 * 60
20
21# One kind of formats for RO firmware spec.
22_RELEASE_RO_FIRMWARE_SPEC = 'released_ro_'
23
24
25class SchedulingError(Exception):
26 """Raised to indicate a failure in scheduling a task."""
27
28
29class Task(object):
30 """Represents an entry from the suite_scheduler config file.
31
32 Each entry from the suite_scheduler config file maps one-to-one to a
33 Task. Each instance has enough information to schedule itself.
34 """
35
Po-Hsien Wangdd833072018-08-16 18:09:20 -070036 def __init__(self, task_info, board_family_config={}, tot=None):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070037 """Initialize a task instance.
38
39 Args:
40 task_info: a config_reader.TaskInfo object, which includes:
41 name, name of this task, e.g. 'NightlyPower'
42 suite, the name of the suite to run, e.g. 'graphics_per-day'
43 branch_specs, a pre-vetted iterable of branch specifiers,
44 e.g. ['>=R18', 'factory']
45 pool, the pool of machines to schedule tasks. Default is None.
46 num, the number of devices to shard the test suite. It could
47 be an Integer or None. By default it's None.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070048 board_families, a common separated list of board family to run this
49 task on. Boards belong to one of the board family in this list
50 would be added to task_info.boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070051 boards, a comma separated list of boards to run this task on. Default
Po-Hsien Wangdd833072018-08-16 18:09:20 -070052 is None, which allows this task to run on all boards. If same board
53 is specified in 'boards' and 'exclude_boards', we exclude this
54 board.
55 exclude_board_families, a common separated list of board family not to
56 run task on. Boards belong to one of the board family in this list
57 would be added to task_info.exclude_boards.
Po-Hsien Wang6d589732018-05-15 17:19:34 -070058 exclude_boards, a comma separated list of boards not to run this task
59 on. Default is None, which allows this task to run on all boards.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070060 If same board is specified in 'boards' and 'exclude_boards', we
61 exclude this board.
Xixuan Wu89897182019-01-03 15:28:01 -080062 models, a comma separated list of models to run this task on. Default
63 is None, which allows this task to run on all models. If same model
64 is specified in 'models' and 'exclude_models', we exclude this
65 model.
66 exclude_models, a comma separated list of models not to run this task
67 on. Default is None, which allows this task to run on all models.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070068 priority, the string name of a priority from constants.Priorities.
69 timeout, the max lifetime of the suite in hours.
70 cros_build_spec, spec used to determine the ChromeOS build to test
71 with a firmware build, e.g., tot, R41 etc.
72 firmware_rw_build_spec, spec used to determine the firmware RW build
73 test with a ChromeOS build.
74 firmware_ro_build_spec, spec used to determine the firmware RO build
75 test with a ChromeOS build.
76 test_source, the source of test code when firmware will be updated in
77 the test. The value can be 'firmware_rw', 'firmware_ro' or 'cros'.
78 job_retry, set to True to enable job-level retry. Default is False.
Xixuan Wu80531932017-10-12 17:26:51 -070079 no_delay, set to True to raise the priority of this task in task.
80 force, set to True to schedule this suite no matter whether there's
81 duplicate jobs before.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070082 queue, so the suite jobs can start running tests with no waiting.
83 hour, an integer specifying the hour that a nightly run should be
84 triggered, default is set to 21.
85 day, an integer specifying the day of a week that a weekly run should
86 be triggered, default is set to 5 (Saturday).
87 os_type, type of OS, e.g., cros, brillo, android. Default is cros.
88 The argument is required for android/brillo builds.
89 launch_control_branches, comma separated string of launch control
90 branches. The argument is required and only applicable for
91 android/brillo builds.
92 launch_control_targets, comma separated string of build targets for
93 launch control builds. The argument is required and only
94 applicable for android/brillo builds.
95 testbed_dut_count, number of duts to test when using a testbed.
Xixuan Wu83118dd2018-08-27 12:11:35 -070096 board_family_config: A board family dictionary mapping board_family name
97 to its corresponding boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070098 tot: The tot manager for checking ToT. If it's None, a new tot_manager
99 instance will be initialized.
100 """
Xixuan Wu5451a662017-10-17 10:57:40 -0700101 # Indicate whether there're suites get pushed into taskqueue for this task.
102 self.is_pushed = False
103
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700104 self.name = task_info.name
105 self.suite = task_info.suite
106 self.branch_specs = task_info.branch_specs
107 self.pool = task_info.pool
108 self.num = task_info.num
109 self.priority = task_info.priority
110 self.timeout = task_info.timeout
111 self.cros_build_spec = task_info.cros_build_spec
112 self.firmware_rw_build_spec = task_info.firmware_rw_build_spec
113 self.firmware_ro_build_spec = task_info.firmware_ro_build_spec
114 self.test_source = task_info.test_source
115 self.job_retry = task_info.job_retry
116 self.no_delay = task_info.no_delay
Xixuan Wu80531932017-10-12 17:26:51 -0700117 self.force = task_info.force
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700118 self.os_type = task_info.os_type
119 self.testbed_dut_count = task_info.testbed_dut_count
Xixuan Wu008ee832017-10-12 16:59:34 -0700120 self.hour = task_info.hour
121 self.day = task_info.day
Craig Bergstrom58263d32018-04-26 14:11:35 -0600122 self.only_hwtest_sanity_required = task_info.only_hwtest_sanity_required
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700123
124 if task_info.lc_branches:
125 self.launch_control_branches = [
126 t.strip() for t in task_info.lc_branches.split(',')]
127 else:
128 self.launch_control_branches = []
129
130 if task_info.lc_targets:
131 self.launch_control_targets = [
132 t.strip() for t in task_info.lc_targets.split(',')]
133 else:
134 self.launch_control_targets = []
135
136 if task_info.boards:
137 self.boards = [t.strip() for t in task_info.boards.split(',')]
138 else:
139 self.boards = []
140
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700141 if task_info.exclude_boards:
142 self.exclude_boards = [
143 t.strip() for t in task_info.exclude_boards.split(',')]
144 else:
145 self.exclude_boards = []
146
Xixuan Wu89897182019-01-03 15:28:01 -0800147 if task_info.models:
148 self.models = [t.strip() for t in task_info.models.split(',')]
149 else:
150 self.models = []
151
152 if task_info.exclude_models:
153 self.exclude_models = [
154 t.strip() for t in task_info.exclude_models.split(',')]
155 else:
156 self.exclude_models = []
157
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700158 if task_info.board_families:
159 # Finetune the allowed boards list with board_families & boards.
160 families = [family.strip()
161 for family in task_info.board_families.split(',')]
162 for family in families:
163 self.boards += board_family_config.get(family, [])
Xixuan Wu89897182019-01-03 15:28:01 -0800164
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700165 if task_info.exclude_board_families:
166 # Finetune the disallowed boards list with exclude_board_families
167 # & exclude_boards.
168 families = [family.strip()
169 for family in task_info.exclude_board_families.split(',')]
170 for family in families:
171 self.exclude_boards += board_family_config.get(family, [])
172
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700173 if tot is None:
174 self.tot_manager = tot_manager.TotMilestoneManager()
175 else:
176 self.tot_manager = tot
177
178 self._set_spec_compare_info()
179
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700180 def schedule(self, launch_control_builds, cros_builds_tuple, configs,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700181 db_client):
182 """Schedule the task by its settings.
183
184 Args:
185 launch_control_builds: the build dict for Android boards, see
186 return value of |get_launch_control_builds|.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600187 cros_builds_tuple: the two-tuple of build dicts for ChromeOS boards,
188 see return value of |get_cros_builds|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700189 configs: a config_reader.Configs object.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700190 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
191
192 Raises:
193 SchedulingError: if tasks that should be scheduled fail to schedule.
Xixuan Wu5451a662017-10-17 10:57:40 -0700194
195 Returns:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700196 A boolean indicator; true if there were any suites related to this
197 task which got pushed into the suites queue.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700198 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700199 assert configs.lab_config is not None
Xixuan Wu5451a662017-10-17 10:57:40 -0700200 self.is_pushed = False
201
Craig Bergstrom58263d32018-04-26 14:11:35 -0600202 branch_builds, relaxed_builds = cros_builds_tuple
203 builds_dict = branch_builds
204 if self.only_hwtest_sanity_required:
205 builds_dict = relaxed_builds
206
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700207 logging.info('######## Scheduling task %s ########', self.name)
208 if self.os_type == build_lib.OS_TYPE_CROS:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600209 if not builds_dict:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700210 logging.info('No CrOS build to run, skip running.')
211 else:
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700212 self._schedule_cros_builds(builds_dict, configs, db_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700213 else:
214 if not launch_control_builds:
215 logging.info('No Android build to run, skip running.')
216 else:
217 self._schedule_launch_control_builds(launch_control_builds)
218
Xixuan Wu5451a662017-10-17 10:57:40 -0700219 return self.is_pushed
220
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700221 def _set_spec_compare_info(self):
222 """Set branch spec compare info for task for further check."""
223 self._bare_branches = []
224 self._version_equal_constraint = False
225 self._version_gte_constraint = False
226 self._version_lte_constraint = False
227
228 if not self.branch_specs:
229 # Any milestone is OK.
230 self._numeric_constraint = version.LooseVersion('0')
231 else:
232 self._numeric_constraint = None
233 for spec in self.branch_specs:
234 if 'tot' in spec.lower():
235 # Convert spec >=tot-1 to >=RXX.
236 tot_str = spec[spec.index('tot'):]
237 spec = spec.replace(
238 tot_str, self.tot_manager.convert_tot_spec(tot_str))
239
240 if spec.startswith('>='):
241 self._numeric_constraint = version.LooseVersion(
242 spec.lstrip('>=R'))
243 self._version_gte_constraint = True
244 elif spec.startswith('<='):
245 self._numeric_constraint = version.LooseVersion(
246 spec.lstrip('<=R'))
247 self._version_lte_constraint = True
248 elif spec.startswith('=='):
249 self._version_equal_constraint = True
250 self._numeric_constraint = version.LooseVersion(
251 spec.lstrip('==R'))
252 else:
253 self._bare_branches.append(spec)
254
255 def _fits_spec(self, branch):
256 """Check if a branch is deemed OK by this task's branch specs.
257
258 Will return whether a branch 'fits' the specifications stored in this task.
259
260 Examples:
261 Assuming tot=R40
262 t = Task('Name', 'suite', ['factory', '>=tot-1'])
263 t._fits_spec('factory') # True
264 t._fits_spec('40') # True
265 t._fits_spec('38') # False
266 t._fits_spec('firmware') # False
267
268 Args:
269 branch: the branch to check.
270
271 Returns:
272 True if branch 'fits' with stored specs, False otherwise.
273 """
274 if branch in build_lib.BARE_BRANCHES:
275 return branch in self._bare_branches
276
277 if self._numeric_constraint:
278 if self._version_equal_constraint:
279 return version.LooseVersion(branch) == self._numeric_constraint
280 elif self._version_gte_constraint:
281 return version.LooseVersion(branch) >= self._numeric_constraint
282 elif self._version_lte_constraint:
283 return version.LooseVersion(branch) <= self._numeric_constraint
284 else:
285 return version.LooseVersion(branch) >= self._numeric_constraint
286 else:
287 return False
288
289 def _get_latest_firmware_build_from_db(self, spec, board, db_client):
290 """Get the latest firmware build from CIDB database.
291
292 Args:
293 spec: a string build spec for RO or RW firmware, eg. firmware,
294 cros. For RO firmware, the value can also be released_ro_X.
295 board: the board against which this task will run suite job.
296 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
297
298 Returns:
299 the latest firmware build.
300
301 Raises:
302 MySQLdb.OperationalError: if connection operations are not valid.
303 """
304 build_type = 'release' if spec == 'cros' else spec
305 # TODO(xixuan): not all firmware are saved in cidb.
306 build = db_client.get_latest_passed_builds('%s-%s' % (board, build_type))
307
308 if build is None:
309 return None
310 else:
311 latest_build = str(build_lib.CrOSBuild(
312 board, build_type, build.milestone, build.platform))
313 logging.debug('latest firmware build for %s-%s: %s', board,
314 build_type, latest_build)
315 return latest_build
316
317 def _get_latest_firmware_build_from_lab_config(self, spec, board,
318 lab_config):
319 """Get latest firmware from lab config file.
320
321 Args:
322 spec: a string build spec for RO or RW firmware, eg. firmware,
323 cros. For RO firmware, the value can also be released_ro_X.
324 board: a string board against which this task will run suite job.
325 lab_config: a config.LabConfig object, to read lab config file.
326
327 Returns:
328 A string latest firmware build.
329
330 Raises:
331 ValueError: if no firmware build list is found in lab config file.
332 """
333 index = int(spec[len(_RELEASE_RO_FIRMWARE_SPEC):])
334 released_ro_builds = lab_config.get_firmware_ro_build_list(
335 'RELEASED_RO_BUILDS_%s' % board).split(',')
336 if len(released_ro_builds) < index:
337 raise ValueError('No %dth ro_builds in the lab_config firmware '
338 'list %r' % (index, released_ro_builds))
339
340 logging.debug('Get ro_build: %s', released_ro_builds[index - 1])
341 return released_ro_builds[index - 1]
342
343 def _get_firmware_build(self, spec, board, lab_config, db_client):
344 """Get the firmware build name to test with ChromeOS build.
345
346 Args:
347 spec: a string build spec for RO or RW firmware, eg. firmware,
348 cros. For RO firmware, the value can also be released_ro_X.
349 board: a string board against which this task will run suite job.
350 lab_config: a config.LabConfig object, to read lab config file.
351 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
352
353 Returns:
354 A string firmware build name.
355
356 Raises:
357 ValueError: if failing to get firmware from lab config file;
358 MySQLdb.OperationalError: if DB connection is not available.
359 """
360 if not spec or spec == 'stable':
361 # TODO(crbug.com/577316): Query stable RO firmware.
362 logging.debug('%s RO firmware build is not supported.', spec)
363 return None
364
365 try:
366 if spec.startswith(_RELEASE_RO_FIRMWARE_SPEC):
367 # For RO firmware whose value is released_ro_X, where X is the index of
368 # the list defined in lab config file:
369 # CROS/RELEASED_RO_BUILDS_[board].
370 # For example, for spec 'released_ro_2', and lab config file
371 # CROS/RELEASED_RO_BUILDS_veyron_jerry: build1,build2,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600372 # return firmware RO build should be 'build2'.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700373 return self._get_latest_firmware_build_from_lab_config(
374 spec, board, lab_config)
375 else:
376 return self._get_latest_firmware_build_from_db(spec, board, db_client)
377 except ValueError as e:
378 logging.warning('Failed to get firmware from lab config file'
379 'for spec %s, board %s: %s', spec, board, str(e))
380 return None
381 except MySQLdb.OperationalError as e:
382 logging.warning('Failed to get firmware from cidb for spec %s, '
383 'board %s: %s', spec, board, str(e))
384 return None
385
C Shapiro7f24a002017-12-05 14:25:09 -0700386 def _push_suite(
387 self,
388 board=None,
389 model=None,
390 cros_build=None,
391 firmware_rw_build=None,
392 firmware_ro_build=None,
393 test_source_build=None,
394 launch_control_build=None,
Xixuan Wubb74a372018-08-21 17:37:08 -0700395 run_prod_code=False,
396 is_skylab=False):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700397 """Schedule suite job for the task by pushing suites to SuiteQueue.
398
399 Args:
400 board: the board against which this suite job run.
C Shapiro7f24a002017-12-05 14:25:09 -0700401 model: the model name for unibuild.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700402 cros_build: the CrOS build of this suite job.
403 firmware_rw_build: Firmware RW build to run this suite job with.
404 firmware_ro_build: Firmware RO build to run this suite job with.
405 test_source_build: Test source build, used for server-side
406 packaging of this suite job.
407 launch_control_build: the launch control build of this suite job.
408 run_prod_code: If True, the suite will run the test code that lives
409 in prod aka the test code currently on the lab servers. If
410 False, the control files and test code for this suite run will
411 be retrieved from the build artifacts. Default is False.
Xixuan Wubb74a372018-08-21 17:37:08 -0700412 is_skylab: If True, schedule this suite to skylab, otherwise schedule
413 it to AFE. Default is False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700414 """
415 android_build = None
416 testbed_build = None
417
418 if self.testbed_dut_count:
419 launch_control_build = '%s#%d' % (launch_control_build,
420 self.testbed_dut_count)
421 test_source_build = launch_control_build
422 board = '%s-%d' % (board, self.testbed_dut_count)
423
424 if launch_control_build:
425 if not self.testbed_dut_count:
426 android_build = launch_control_build
427 else:
428 testbed_build = launch_control_build
429
430 suite_job_parameters = {
431 'suite': self.suite,
432 'board': board,
C Shapiro7f24a002017-12-05 14:25:09 -0700433 'model': model,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700434 build_lib.BuildVersionKey.CROS_VERSION: cros_build,
435 build_lib.BuildVersionKey.FW_RW_VERSION: firmware_rw_build,
436 build_lib.BuildVersionKey.FW_RO_VERSION: firmware_ro_build,
437 build_lib.BuildVersionKey.ANDROID_BUILD_VERSION: android_build,
438 build_lib.BuildVersionKey.TESTBED_BUILD_VERSION: testbed_build,
439 'num': self.num,
440 'pool': self.pool,
441 'priority': self.priority,
442 'timeout': self.timeout,
443 'timeout_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
444 'max_runtime_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
Xixuan Wu2ba72652017-09-15 15:49:42 -0700445 'no_wait_for_results': not self.job_retry,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700446 'test_source_build': test_source_build,
447 'job_retry': self.job_retry,
448 'no_delay': self.no_delay,
Xixuan Wu80531932017-10-12 17:26:51 -0700449 'force': self.force,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700450 'run_prod_code': run_prod_code,
Xixuan Wubb74a372018-08-21 17:37:08 -0700451 'is_skylab': is_skylab,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700452 }
453
454 task_executor.push(task_executor.SUITES_QUEUE, **suite_job_parameters)
455 logging.info('Pushing task %r into taskqueue', suite_job_parameters)
Xixuan Wu5451a662017-10-17 10:57:40 -0700456 self.is_pushed = True
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700457
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700458 def _schedule_cros_builds(self, build_dict, configs, db_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700459 """Schedule tasks with branch builds.
460
461 Args:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600462 build_dict: the build dict for ChromeOS boards, see return
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700463 value of |build_lib.get_cros_builds_since_date_from_db|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700464 configs: A config_reader.Configs object.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700465 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
466 """
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700467 lab_config = configs.lab_config
468 migration_config = configs.migration_config
C Shapiro7f24a002017-12-05 14:25:09 -0700469 models_by_board = lab_config.get_cros_model_map() if lab_config else {}
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700470 skylab_boards = (migration_config.get_skylab_board_list()
471 if migration_config else [])
472 skylab_suites = (migration_config.get_skylab_suite_list()
473 if migration_config else [])
474 skylab_models = (migration_config.get_skylab_model_map()
475 if migration_config else {})
Xixuan Wu83118dd2018-08-27 12:11:35 -0700476 logging.info('Skylab_boards: %r', skylab_boards)
477 logging.info('Skylab suites: %r', skylab_suites)
Xixuan Wu5ff0fac2019-01-07 10:06:35 -0800478 logging.info('Skylab models: %r', skylab_models)
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700479 for (board, passed_model, build_type,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600480 milestone), manifest in build_dict.iteritems():
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700481 cros_build = str(build_lib.CrOSBuild(board, build_type, milestone,
482 manifest))
483 logging.info('Running %s on %s', self.name, cros_build)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700484 if self.exclude_boards and board in self.exclude_boards:
485 logging.debug('Board %s is in excluded board list: %s',
486 board, self.exclude_boards)
487 continue
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700488
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700489 if self.boards and board not in self.boards:
490 logging.debug('Board %s is not in supported board list: %s',
491 board, self.boards)
492 continue
493
494 # Check the fitness of the build's branch for task
495 branch_build_spec = _pick_branch(build_type, milestone)
496 if not self._fits_spec(branch_build_spec):
497 logging.debug("branch_build spec %s doesn't fit this task's "
498 "requirement: %s", branch_build_spec, self.branch_specs)
499 continue
500
501 firmware_rw_build = None
502 firmware_ro_build = None
503 if self.firmware_rw_build_spec or self.firmware_ro_build_spec:
504 firmware_rw_build = self._get_firmware_build(
505 self.firmware_rw_build_spec, board, lab_config, db_client)
506 firmware_ro_build = self._get_firmware_build(
507 self.firmware_ro_build_spec, board, lab_config, db_client)
508
509 if not firmware_ro_build and self.firmware_ro_build_spec:
510 logging.debug('No firmware ro build to run, skip running')
511 continue
512
513 if self.test_source == build_lib.BuildType.FIRMWARE_RW:
514 test_source_build = firmware_rw_build
515 else:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700516 # Default test source build to CrOS build if it's not specified.
517 # Past versions chose based on run_prod_code, but we no longer respect
518 # that option and scheduler settings should always set it to False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700519 test_source_build = cros_build
520
Xixuan Wued878ea2019-03-18 15:32:16 -0700521 is_skylab = skylab.should_run_in_skylab(board,
522 passed_model,
523 self.suite,
524 skylab_boards,
525 skylab_models,
526 skylab_suites)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000527 models = models_by_board.get(board, [None])
C Shapiro7f24a002017-12-05 14:25:09 -0700528
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000529 for model in models:
530 if ((passed_model is not None and model == passed_model) or
531 passed_model is None):
532 self._push_suite(
533 board=board,
534 model=model,
535 cros_build=cros_build,
536 firmware_rw_build=firmware_rw_build,
537 firmware_ro_build=firmware_ro_build,
538 test_source_build=test_source_build,
539 is_skylab=is_skylab)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700540
541 def _schedule_launch_control_builds(self, launch_control_builds):
542 """Schedule tasks with launch control builds.
543
544 Args:
545 launch_control_builds: the build dict for Android boards.
546 """
547 for board, launch_control_build in launch_control_builds.iteritems():
548 logging.debug('Running %s on %s', self.name, board)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700549 if self.exclude_boards and board in self.exclude_boards:
550 logging.debug('Board %s is in excluded board list: %s',
551 board, self.exclude_boards)
552 continue
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700553 if self.boards and board not in self.boards:
554 logging.debug('Board %s is not in supported board list: %s',
555 board, self.boards)
556 continue
557
558 for android_build in launch_control_build:
559 if not any([branch in android_build
560 for branch in self.launch_control_branches]):
561 logging.debug('Branch %s is not required to run for task '
562 '%s', android_build, self.name)
563 continue
564
565 self._push_suite(board=board,
566 test_source_build=android_build,
567 launch_control_build=android_build)
568
569
570def _pick_branch(build_type, milestone):
571 """Select branch based on build type.
572
573 If the build_type is a bare branch, return build_type as the build spec.
574 If the build_type is a normal CrOS branch, return milestone as the build
575 spec.
576
577 Args:
578 build_type: a string builder name, like 'release'.
579 milestone: a string milestone, like '55'.
580
581 Returns:
582 A string milestone if build_type represents CrOS build, otherwise
583 return build_type.
584 """
585 return build_type if build_type in build_lib.BARE_BRANCHES else milestone