blob: a468a05794bc5341fab626c69ea854b2dd1a7e21 [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
170 with tracer.start_as_current_span("scripts.cros_run_unit_tests") as span:
171 try:
172 inner_main(opts)
173 except KeyboardInterrupt as e:
174 span.record_exception(e)
175 span.set_status(trace.StatusCode.OK, "KeyboardInterrupt")
176 raise
177
178
179def inner_main(opts: commandline.ArgumentNamespace):
180 """The inner main to run cros unit tests."""
181
182 span = trace.get_current_span()
183
Alex Klein1699fab2022-09-08 08:46:06 -0600184 sysroot = (
185 opts.sysroot or "/"
186 if opts.host
187 else build_target_lib.get_default_sysroot_path(opts.board)
188 )
189 skipped_packages = set()
190 if opts.skip_packages:
191 skipped_packages |= set(opts.skip_packages.split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700192
Alex Klein1699fab2022-09-08 08:46:06 -0600193 packages = set()
194 # The list of packages to test can be passed as a file containing a
195 # space-separated list of package names.
196 # This is used by the builder to test only the packages that were uprevved.
197 if opts.package_file and os.path.exists(opts.package_file):
198 packages = set(osutils.ReadFile(opts.package_file).split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700199
Alex Klein1699fab2022-09-08 08:46:06 -0600200 if opts.packages:
201 packages |= set(opts.packages.split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700202
Alex Klein1699fab2022-09-08 08:46:06 -0600203 # If no packages were specified, use all testable packages.
204 if not (opts.packages or opts.package_file) and not opts.empty_sysroot:
205 workon = workon_helper.WorkonHelper(sysroot)
206 packages = (
207 workon.InstalledWorkonAtoms()
208 if opts.installed
209 else set(workon.ListAtoms(use_all=True))
210 )
Chris McDonalde69db662018-11-15 12:50:18 -0700211
Alex Klein1699fab2022-09-08 08:46:06 -0600212 if opts.empty_sysroot:
213 packages |= determine_packages(
214 sysroot,
215 SDK_VIRTUAL_PACKAGES if opts.host else BOARD_VIRTUAL_PACKAGES,
216 )
217 workon = workon_helper.WorkonHelper(sysroot)
218 workon_packages = set(workon.ListAtoms(use_all=True))
219 packages &= workon_packages
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700220
Alex Klein1699fab2022-09-08 08:46:06 -0600221 for cp in packages & skipped_packages:
222 logging.info("Skipping package %s.", cp)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700223
Alex Klein1699fab2022-09-08 08:46:06 -0600224 packages = packages - skipped_packages
225 pkg_with_test = portage_util.PackagesWithTest(
226 sysroot, packages, opts.filter_only_cros_workon
227 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700228
Alex Klein1699fab2022-09-08 08:46:06 -0600229 if packages - pkg_with_test:
230 logging.warning(
231 "The following packages do not have tests:\n %s",
232 "\n ".join(sorted(packages - pkg_with_test)),
233 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700234
Anuj Jamwal2a2aac92023-08-21 16:40:28 +0000235 span.set_attributes(
236 {
237 "sysroot": sysroot,
238 "packages": pkg_with_test,
239 "pretend": opts.pretend,
240 "jobs": opts.jobs,
241 "empty_sysroot": opts.empty_sysroot,
242 }
243 )
244
Alex Klein1699fab2022-09-08 08:46:06 -0600245 if not pkg_with_test:
246 if opts.testable_packages_optional:
247 logging.warning("No testable packages found!")
248 return 0
249 logging.error("No testable packages found!")
250 return 1
Mike Frysingerdcb680f2019-09-02 00:21:44 -0400251
Alex Klein1699fab2022-09-08 08:46:06 -0600252 if opts.pretend:
253 print("\n".join(sorted(pkg_with_test)))
254 return 0
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700255
Alex Klein1699fab2022-09-08 08:46:06 -0600256 env = {}
257 if opts.nowithdebug:
258 use_flags = os.environ.get("USE", "")
259 use_flags += " -cros-debug"
260 env["USE"] = use_flags
Navil Perez03dc71a2021-07-22 18:38:49 +0000261
Artem Sumaneev337b5f62023-02-28 15:38:58 +0000262 features_flags = os.environ.get("FEATURES", "")
263 if features_flags:
264 env["FEATURES"] = features_flags
265
Alex Klein1699fab2022-09-08 08:46:06 -0600266 keep_going = get_keep_going()
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800267
Alex Klein1699fab2022-09-08 08:46:06 -0600268 metrics_dir = os.environ.get(constants.CROS_METRICS_DIR_ENVVAR)
269 if metrics_dir:
270 env[constants.CROS_METRICS_DIR_ENVVAR] = metrics_dir
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700271
Alex Klein1699fab2022-09-08 08:46:06 -0600272 if opts.empty_sysroot:
273 try:
274 chroot_util.Emerge(
275 list(IMPLICIT_TEST_DEPS),
276 sysroot,
277 rebuild_deps=False,
278 use_binary=False,
279 )
280 chroot_util.Emerge(
281 list(pkg_with_test),
282 sysroot,
283 rebuild_deps=False,
284 use_binary=False,
285 )
286 except cros_build_lib.RunCommandError:
287 logging.error("Failed building dependencies for unittests.")
Anuj Jamwal2a2aac92023-08-21 16:40:28 +0000288 span.set_status(trace.StatusCode.ERROR, "FAILED_DEPS_BUILD")
Alex Klein1699fab2022-09-08 08:46:06 -0600289 return 1
290
Chris McDonalde69db662018-11-15 12:50:18 -0700291 try:
Alex Klein1699fab2022-09-08 08:46:06 -0600292 chroot_util.RunUnittests(
293 sysroot,
294 pkg_with_test,
295 extra_env=env,
296 keep_going=keep_going,
297 jobs=opts.jobs,
George Engelbrecht9476deb2022-10-14 09:59:20 -0600298 verbose=opts.emerge_verbose,
Alex Klein1699fab2022-09-08 08:46:06 -0600299 )
Chris McDonalde69db662018-11-15 12:50:18 -0700300 except cros_build_lib.RunCommandError:
Alex Klein1699fab2022-09-08 08:46:06 -0600301 logging.error("Unittests failed.")
Anuj Jamwal2a2aac92023-08-21 16:40:28 +0000302 span.set_status(trace.StatusCode.ERROR, "FAILED_UNITTESTS")
Alex Klein1699fab2022-09-08 08:46:06 -0600303 return 1