blob: 8167bdcfc3fc514dccce1e96744a6c28ace25dbc [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2015 The ChromiumOS Authors
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Tool to run ebuild unittests."""
6
Chris McDonald59650c32021-07-20 15:29:28 -06007import logging
Aviv Keshet01fcca42016-07-25 16:34:59 -07008import multiprocessing
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -07009import os
10
Anuj Jamwal2a2aac92023-08-21 16:40:28 +000011from chromite.third_party.opentelemetry import trace
12
Mike Frysinger06a51c82021-04-06 11:39:17 -040013from chromite.lib import build_target_lib
Anuj Jamwal2a2aac92023-08-21 16:40:28 +000014from chromite.lib import chromite_config
Chris McDonald59650c32021-07-20 15:29:28 -060015from chromite.lib import chroot_util
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070016from chromite.lib import commandline
Chris McDonalde69db662018-11-15 12:50:18 -070017from chromite.lib import constants
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070018from chromite.lib import cros_build_lib
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070019from chromite.lib import osutils
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070020from chromite.lib import portage_util
Chris McDonald59650c32021-07-20 15:29:28 -060021from chromite.lib import workon_helper
Chris McDonalde69db662018-11-15 12:50:18 -070022from chromite.scripts import cros_extract_deps
Anuj Jamwal2a2aac92023-08-21 16:40:28 +000023from chromite.utils import telemetry
24
25
26tracer = trace.get_tracer(__name__)
Chris McDonalde69db662018-11-15 12:50:18 -070027
Mike Frysinger6a2b0f22020-02-20 13:34:07 -050028
Alex Klein1699fab2022-09-08 08:46:06 -060029BOARD_VIRTUAL_PACKAGES = (
30 constants.TARGET_OS_PKG,
31 constants.TARGET_OS_DEV_PKG,
32 constants.TARGET_OS_TEST_PKG,
33 constants.TARGET_OS_FACTORY_PKG,
34)
Sloan Johnsona85640f2021-10-01 22:32:40 +000035SDK_VIRTUAL_PACKAGES = (constants.TARGET_SDK,)
Alex Klein1699fab2022-09-08 08:46:06 -060036IMPLICIT_TEST_DEPS = ("virtual/implicit-system",)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070037
38
39def ParseArgs(argv):
Alex Klein1699fab2022-09-08 08:46:06 -060040 """Parse arguments.
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070041
Alex Klein1699fab2022-09-08 08:46:06 -060042 Args:
Trent Apted66736d82023-05-25 10:38:28 +100043 argv: array of arguments passed to the script.
Alex Klein1699fab2022-09-08 08:46:06 -060044 """
45 parser = commandline.ArgumentParser(description=__doc__)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070046
Alex Klein1699fab2022-09-08 08:46:06 -060047 target = parser.add_mutually_exclusive_group(required=True)
George Engelbrecht9476deb2022-10-14 09:59:20 -060048
Alex Klein1699fab2022-09-08 08:46:06 -060049 target.add_argument("--sysroot", type="path", help="Path to the sysroot.")
50 target.add_argument("--board", help="Board name.")
51 target.add_argument(
52 "--host", action="store_true", help="Run tests for the host SDK."
53 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070054
Alex Klein1699fab2022-09-08 08:46:06 -060055 parser.add_argument(
George Engelbrecht9476deb2022-10-14 09:59:20 -060056 "--emerge-verbose",
57 default=False,
58 action="store_true",
59 help="Output emerge details.",
60 )
61
62 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -060063 "--pretend",
64 default=False,
65 action="store_true",
66 help="Show the list of packages to be tested and return.",
67 )
68 parser.add_argument(
69 "--noinstalled_only",
70 dest="installed",
71 default=True,
72 action="store_false",
Trent Apted66736d82023-05-25 10:38:28 +100073 help=(
74 "Test all testable packages, even if they are not "
75 "currently installed."
76 ),
Alex Klein1699fab2022-09-08 08:46:06 -060077 )
78 parser.add_argument(
79 "--package_file",
80 type="path",
Trent Apted66736d82023-05-25 10:38:28 +100081 help=(
82 "Path to a file containing the list of packages "
83 "that should be tested."
84 ),
Alex Klein1699fab2022-09-08 08:46:06 -060085 )
86 parser.add_argument(
87 "--packages", help="Space-separated list of packages to test."
88 )
89 parser.add_argument(
90 "--skip-packages",
Trent Apted66736d82023-05-25 10:38:28 +100091 help=(
92 "Space-separated list of packages to NOT test even "
93 "if they otherwise would have been tested."
94 ),
Alex Klein1699fab2022-09-08 08:46:06 -060095 )
96 parser.add_argument(
97 "--nowithdebug",
98 action="store_true",
99 help="Don't build the tests with USE=cros-debug",
100 )
101 parser.add_argument(
102 "--assume-empty-sysroot",
103 default=False,
104 action="store_true",
105 dest="empty_sysroot",
Trent Apted66736d82023-05-25 10:38:28 +1000106 help=(
107 "Set up dependencies and run unit tests for all "
108 "packages that could be installed on target board "
109 "without assuming that any packages have actually "
110 "been merged yet."
111 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600112 )
113 parser.add_argument(
114 "-j",
115 "--jobs",
116 type=int,
117 default=multiprocessing.cpu_count(),
118 help="The limit for the number of possible concurrent jobs.",
119 )
120 parser.add_argument(
121 "--no-testable-packages-ok",
122 default=False,
123 action="store_true",
124 dest="testable_packages_optional",
125 help="If specified, do not fail if no testable packages are found.",
126 )
127 parser.add_argument(
128 "--filter-only-cros-workon",
129 default=False,
130 action="store_true",
Trent Apted66736d82023-05-25 10:38:28 +1000131 help=(
132 "If specified and packages are given, filters out non-cros_workon "
133 "packages."
134 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600135 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700136
Alex Klein1699fab2022-09-08 08:46:06 -0600137 options = parser.parse_args(argv)
138 options.Freeze()
139 return options
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700140
141
Sloan Johnsona85640f2021-10-01 22:32:40 +0000142def determine_packages(sysroot, virtual_packages):
Alex Klein1699fab2022-09-08 08:46:06 -0600143 """Returns a set of the dependencies for the given packages"""
144 deps, _bdeps = cros_extract_deps.ExtractDeps(
145 sysroot, virtual_packages, include_bdepend=False
146 )
147 return set(
148 "%s/%s" % (atom["category"], atom["name"]) for atom in deps.values()
149 )
150
Chris McDonalde69db662018-11-15 12:50:18 -0700151
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800152def get_keep_going():
Alex Klein1699fab2022-09-08 08:46:06 -0600153 """Check if should enable keep_going parameter.
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800154
Alex Klein1699fab2022-09-08 08:46:06 -0600155 If the 'USE' environment contains 'coverage' then enable keep_going option
156 to prevent certain package failure from breaking the whole coverage
157 generation workflow, otherwise leave it to default settings
158 """
159 return "coverage" in os.environ.get("USE", "")
160
Chris McDonalde69db662018-11-15 12:50:18 -0700161
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700162def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600163 opts = ParseArgs(argv)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700164
Alex Klein1699fab2022-09-08 08:46:06 -0600165 cros_build_lib.AssertInsideChroot()
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700166
Anuj Jamwal2a2aac92023-08-21 16:40:28 +0000167 chromite_config.initialize()
168 telemetry.initialize(chromite_config.TELEMETRY_CONFIG, debug=opts.debug)
169
Anuj Jamwalb4666682023-09-12 14:24:54 +0000170 with tracer.start_as_current_span("scripts.cros_run_unit_tests"):
171 inner_main(opts)
Anuj Jamwal2a2aac92023-08-21 16:40:28 +0000172
173
174def inner_main(opts: commandline.ArgumentNamespace):
175 """The inner main to run cros unit tests."""
176
177 span = trace.get_current_span()
178
Alex Klein1699fab2022-09-08 08:46:06 -0600179 sysroot = (
180 opts.sysroot or "/"
181 if opts.host
182 else build_target_lib.get_default_sysroot_path(opts.board)
183 )
184 skipped_packages = set()
185 if opts.skip_packages:
186 skipped_packages |= set(opts.skip_packages.split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700187
Alex Klein1699fab2022-09-08 08:46:06 -0600188 packages = set()
189 # The list of packages to test can be passed as a file containing a
190 # space-separated list of package names.
191 # This is used by the builder to test only the packages that were uprevved.
192 if opts.package_file and os.path.exists(opts.package_file):
193 packages = set(osutils.ReadFile(opts.package_file).split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700194
Alex Klein1699fab2022-09-08 08:46:06 -0600195 if opts.packages:
196 packages |= set(opts.packages.split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700197
Alex Klein1699fab2022-09-08 08:46:06 -0600198 # If no packages were specified, use all testable packages.
199 if not (opts.packages or opts.package_file) and not opts.empty_sysroot:
200 workon = workon_helper.WorkonHelper(sysroot)
201 packages = (
202 workon.InstalledWorkonAtoms()
203 if opts.installed
204 else set(workon.ListAtoms(use_all=True))
205 )
Chris McDonalde69db662018-11-15 12:50:18 -0700206
Alex Klein1699fab2022-09-08 08:46:06 -0600207 if opts.empty_sysroot:
208 packages |= determine_packages(
209 sysroot,
210 SDK_VIRTUAL_PACKAGES if opts.host else BOARD_VIRTUAL_PACKAGES,
211 )
212 workon = workon_helper.WorkonHelper(sysroot)
213 workon_packages = set(workon.ListAtoms(use_all=True))
214 packages &= workon_packages
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700215
Alex Klein1699fab2022-09-08 08:46:06 -0600216 for cp in packages & skipped_packages:
217 logging.info("Skipping package %s.", cp)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700218
Alex Klein1699fab2022-09-08 08:46:06 -0600219 packages = packages - skipped_packages
220 pkg_with_test = portage_util.PackagesWithTest(
221 sysroot, packages, opts.filter_only_cros_workon
222 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700223
Alex Klein1699fab2022-09-08 08:46:06 -0600224 if packages - pkg_with_test:
225 logging.warning(
226 "The following packages do not have tests:\n %s",
227 "\n ".join(sorted(packages - pkg_with_test)),
228 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700229
Anuj Jamwal2a2aac92023-08-21 16:40:28 +0000230 span.set_attributes(
231 {
232 "sysroot": sysroot,
233 "packages": pkg_with_test,
234 "pretend": opts.pretend,
235 "jobs": opts.jobs,
236 "empty_sysroot": opts.empty_sysroot,
237 }
238 )
239
Alex Klein1699fab2022-09-08 08:46:06 -0600240 if not pkg_with_test:
241 if opts.testable_packages_optional:
242 logging.warning("No testable packages found!")
243 return 0
244 logging.error("No testable packages found!")
245 return 1
Mike Frysingerdcb680f2019-09-02 00:21:44 -0400246
Alex Klein1699fab2022-09-08 08:46:06 -0600247 if opts.pretend:
248 print("\n".join(sorted(pkg_with_test)))
249 return 0
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700250
Alex Klein1699fab2022-09-08 08:46:06 -0600251 env = {}
252 if opts.nowithdebug:
253 use_flags = os.environ.get("USE", "")
254 use_flags += " -cros-debug"
255 env["USE"] = use_flags
Navil Perez03dc71a2021-07-22 18:38:49 +0000256
Artem Sumaneev337b5f62023-02-28 15:38:58 +0000257 features_flags = os.environ.get("FEATURES", "")
258 if features_flags:
259 env["FEATURES"] = features_flags
260
Alex Klein1699fab2022-09-08 08:46:06 -0600261 keep_going = get_keep_going()
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800262
Alex Klein1699fab2022-09-08 08:46:06 -0600263 metrics_dir = os.environ.get(constants.CROS_METRICS_DIR_ENVVAR)
264 if metrics_dir:
265 env[constants.CROS_METRICS_DIR_ENVVAR] = metrics_dir
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700266
Alex Klein1699fab2022-09-08 08:46:06 -0600267 if opts.empty_sysroot:
268 try:
269 chroot_util.Emerge(
270 list(IMPLICIT_TEST_DEPS),
271 sysroot,
272 rebuild_deps=False,
273 use_binary=False,
274 )
275 chroot_util.Emerge(
276 list(pkg_with_test),
277 sysroot,
278 rebuild_deps=False,
279 use_binary=False,
280 )
281 except cros_build_lib.RunCommandError:
282 logging.error("Failed building dependencies for unittests.")
Anuj Jamwal2a2aac92023-08-21 16:40:28 +0000283 span.set_status(trace.StatusCode.ERROR, "FAILED_DEPS_BUILD")
Alex Klein1699fab2022-09-08 08:46:06 -0600284 return 1
285
Chris McDonalde69db662018-11-15 12:50:18 -0700286 try:
Alex Klein1699fab2022-09-08 08:46:06 -0600287 chroot_util.RunUnittests(
288 sysroot,
289 pkg_with_test,
290 extra_env=env,
291 keep_going=keep_going,
292 jobs=opts.jobs,
George Engelbrecht9476deb2022-10-14 09:59:20 -0600293 verbose=opts.emerge_verbose,
Alex Klein1699fab2022-09-08 08:46:06 -0600294 )
Chris McDonalde69db662018-11-15 12:50:18 -0700295 except cros_build_lib.RunCommandError:
Alex Klein1699fab2022-09-08 08:46:06 -0600296 logging.error("Unittests failed.")
Anuj Jamwal2a2aac92023-08-21 16:40:28 +0000297 span.set_status(trace.StatusCode.ERROR, "FAILED_UNITTESTS")
Alex Klein1699fab2022-09-08 08:46:06 -0600298 return 1