blob: 1c37292a1bcc64a7c6b6072ea28cea6a38d968b5 [file] [log] [blame]
Alex Miller9979b5a2012-11-01 17:36:12 -07001# Copyright (c) 2013 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
6import collections
7import logging
Alex Miller3ccd77d2013-08-08 01:39:20 -07008import os
Alex Miller9979b5a2012-11-01 17:36:12 -07009
10import common
11from autotest_lib.client.common_lib import global_config
12from autotest_lib.server.cros.dynamic_suite import reimager
13from autotest_lib.site_utils import suite_preprocessor
14
15
16default_num = global_config.global_config.get_config_value(
17 "CROS", "sharding_factor", default=1, type=int)
18
19
20def NumOfTask(task):
21 """
22 Take a run and produce the number of machines it will run across.
23
24 This seems easy, because |task.num| exists. However, it is |None| for any
25 suite that doesn't specify |num|. This is needed so that we know when to pass
26 in a num, and when not to because the server can override the default
27 sharding factor locally. Therefore, we need to compensate for this when doing
28 our local analysis here and provide the default sharding factor if we see
29 |num| is None.
30
31 @param task The task to get the |num| for.
32 @return |num| for this task.
33 """
34 if task.num is None:
35 return default_num
36 else:
Alex Miller4a163282013-01-15 18:18:54 -080037 return int(task.num)
Alex Miller9979b5a2012-11-01 17:36:12 -070038
39
40# TODO(milleral): crosbug.com/37623
41# DEPENDENCIES-related code needs to be refactored a bit so that trying to
42# gather all the dependencies and analyze them doesn't require reaching into
43# random pieces of code across the codebase nor reaching into other object's
44# private methods.
45
46def CheckDependencies(tasks):
47 """
48 Iterate through all of the tasks that suite_scheduler will process, and warn
49 if any of the tasks are set to run a suite with a |num| such that the suite
50 will not be able to satisfy all of its HostSpecs. This can happen when a
51 new test is added to a suite that increases the overall number of
52 HostSpecs, and |num| was not bumped up accordingly.
53
54 If the default sharding_factor is ever changed in the shadow_config on the
55 server, this sanity check will no longer give correct results.
56
57 @param tasks The list of tasks to check.
58 @return 0 if no problems are found
59 1 if problems are found
60 """
61 test_deps = suite_preprocessor.calculate_dependencies(common.autotest_dir)
62
63 by_suite = collections.defaultdict(list)
64 for task in tasks:
65 by_suite.setdefault(task.suite, []).append(task)
66
67 corrections = []
68 for suitename, control_deps in test_deps.items():
69 if not suitename:
70 continue
Vadim Bendebury4d6981b2013-01-08 13:01:40 -080071 imager = reimager.OsReimager(common.autotest_dir, 'none')
Alex Miller9979b5a2012-11-01 17:36:12 -070072
73 # Figure out what kind of hosts we need to grab.
74 per_test_specs = imager._build_host_specs_from_dependencies(
75 None, None, control_deps).values()
76
77 hostspecs = len(set([x for x in per_test_specs]))
78
79 for task in by_suite[suitename]:
80 if hostspecs > NumOfTask(task):
81 corrections.append((task.name, hostspecs))
82
83 for c in corrections:
84 # Failures to parse a config entry result in a logging.warn(),
85 # so let's keep the output the same across different errors
86 logging.warn("Increase %s to |num: %d|", c[0], c[1])
87
88 return 1 if corrections else 0
Alex Miller3ccd77d2013-08-08 01:39:20 -070089
90
91def CheckControlFileExistance(tasks):
92 """
93 Make sure that for any task that schedules a suite, that
94 test_suites/control.<suite> exists. this prevents people from accidentally
95 adding a suite to suite_scheduler.ini but not adding an actual suite
96 control file, thus resulting in their suite not running and the lab team
97 getting lots of email
98
99 @param tasks The list of tasks to check.
100 @return 0 if no missing control files are found
101 1 if there are at least one missing control files
102 """
103 corrections = False
104
105 for task in tasks:
106 suite_path = os.path.join(common.autotest_dir,
107 'test_suites', 'control.'+task.suite)
108 if not os.path.exists(suite_path):
109 corrections = True
110 logging.warn("No suite control file for %s", task.suite)
111
112 return 1 if corrections else 0