blob: c49fe9ecae4c172638b10b852e00337afb7f1561 [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
Mike Frysinger06a51c82021-04-06 11:39:17 -040011from chromite.lib import build_target_lib
Chris McDonald59650c32021-07-20 15:29:28 -060012from chromite.lib import chroot_util
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070013from chromite.lib import commandline
Chris McDonalde69db662018-11-15 12:50:18 -070014from chromite.lib import constants
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070015from chromite.lib import cros_build_lib
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070016from chromite.lib import osutils
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070017from chromite.lib import portage_util
Chris McDonald59650c32021-07-20 15:29:28 -060018from chromite.lib import workon_helper
Chris McDonalde69db662018-11-15 12:50:18 -070019from chromite.scripts import cros_extract_deps
20
Mike Frysinger6a2b0f22020-02-20 13:34:07 -050021
Alex Klein1699fab2022-09-08 08:46:06 -060022BOARD_VIRTUAL_PACKAGES = (
23 constants.TARGET_OS_PKG,
24 constants.TARGET_OS_DEV_PKG,
25 constants.TARGET_OS_TEST_PKG,
26 constants.TARGET_OS_FACTORY_PKG,
27)
Sloan Johnsona85640f2021-10-01 22:32:40 +000028SDK_VIRTUAL_PACKAGES = (constants.TARGET_SDK,)
Alex Klein1699fab2022-09-08 08:46:06 -060029IMPLICIT_TEST_DEPS = ("virtual/implicit-system",)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070030
31
32def ParseArgs(argv):
Alex Klein1699fab2022-09-08 08:46:06 -060033 """Parse arguments.
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070034
Alex Klein1699fab2022-09-08 08:46:06 -060035 Args:
Trent Apted66736d82023-05-25 10:38:28 +100036 argv: array of arguments passed to the script.
Alex Klein1699fab2022-09-08 08:46:06 -060037 """
38 parser = commandline.ArgumentParser(description=__doc__)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070039
Alex Klein1699fab2022-09-08 08:46:06 -060040 target = parser.add_mutually_exclusive_group(required=True)
George Engelbrecht9476deb2022-10-14 09:59:20 -060041
Alex Klein1699fab2022-09-08 08:46:06 -060042 target.add_argument("--sysroot", type="path", help="Path to the sysroot.")
43 target.add_argument("--board", help="Board name.")
44 target.add_argument(
45 "--host", action="store_true", help="Run tests for the host SDK."
46 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070047
Alex Klein1699fab2022-09-08 08:46:06 -060048 parser.add_argument(
George Engelbrecht9476deb2022-10-14 09:59:20 -060049 "--emerge-verbose",
50 default=False,
51 action="store_true",
52 help="Output emerge details.",
53 )
54
55 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -060056 "--pretend",
57 default=False,
58 action="store_true",
59 help="Show the list of packages to be tested and return.",
60 )
61 parser.add_argument(
62 "--noinstalled_only",
63 dest="installed",
64 default=True,
65 action="store_false",
Trent Apted66736d82023-05-25 10:38:28 +100066 help=(
67 "Test all testable packages, even if they are not "
68 "currently installed."
69 ),
Alex Klein1699fab2022-09-08 08:46:06 -060070 )
71 parser.add_argument(
72 "--package_file",
73 type="path",
Trent Apted66736d82023-05-25 10:38:28 +100074 help=(
75 "Path to a file containing the list of packages "
76 "that should be tested."
77 ),
Alex Klein1699fab2022-09-08 08:46:06 -060078 )
79 parser.add_argument(
80 "--packages", help="Space-separated list of packages to test."
81 )
82 parser.add_argument(
83 "--skip-packages",
Trent Apted66736d82023-05-25 10:38:28 +100084 help=(
85 "Space-separated list of packages to NOT test even "
86 "if they otherwise would have been tested."
87 ),
Alex Klein1699fab2022-09-08 08:46:06 -060088 )
89 parser.add_argument(
90 "--nowithdebug",
91 action="store_true",
92 help="Don't build the tests with USE=cros-debug",
93 )
94 parser.add_argument(
95 "--assume-empty-sysroot",
96 default=False,
97 action="store_true",
98 dest="empty_sysroot",
Trent Apted66736d82023-05-25 10:38:28 +100099 help=(
100 "Set up dependencies and run unit tests for all "
101 "packages that could be installed on target board "
102 "without assuming that any packages have actually "
103 "been merged yet."
104 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600105 )
106 parser.add_argument(
107 "-j",
108 "--jobs",
109 type=int,
110 default=multiprocessing.cpu_count(),
111 help="The limit for the number of possible concurrent jobs.",
112 )
113 parser.add_argument(
114 "--no-testable-packages-ok",
115 default=False,
116 action="store_true",
117 dest="testable_packages_optional",
118 help="If specified, do not fail if no testable packages are found.",
119 )
120 parser.add_argument(
121 "--filter-only-cros-workon",
122 default=False,
123 action="store_true",
Trent Apted66736d82023-05-25 10:38:28 +1000124 help=(
125 "If specified and packages are given, filters out non-cros_workon "
126 "packages."
127 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600128 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700129
Alex Klein1699fab2022-09-08 08:46:06 -0600130 options = parser.parse_args(argv)
131 options.Freeze()
132 return options
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700133
134
Sloan Johnsona85640f2021-10-01 22:32:40 +0000135def determine_packages(sysroot, virtual_packages):
Alex Klein1699fab2022-09-08 08:46:06 -0600136 """Returns a set of the dependencies for the given packages"""
137 deps, _bdeps = cros_extract_deps.ExtractDeps(
138 sysroot, virtual_packages, include_bdepend=False
139 )
140 return set(
141 "%s/%s" % (atom["category"], atom["name"]) for atom in deps.values()
142 )
143
Chris McDonalde69db662018-11-15 12:50:18 -0700144
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800145def get_keep_going():
Alex Klein1699fab2022-09-08 08:46:06 -0600146 """Check if should enable keep_going parameter.
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800147
Alex Klein1699fab2022-09-08 08:46:06 -0600148 If the 'USE' environment contains 'coverage' then enable keep_going option
149 to prevent certain package failure from breaking the whole coverage
150 generation workflow, otherwise leave it to default settings
151 """
152 return "coverage" in os.environ.get("USE", "")
153
Chris McDonalde69db662018-11-15 12:50:18 -0700154
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700155def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600156 opts = ParseArgs(argv)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700157
Alex Klein1699fab2022-09-08 08:46:06 -0600158 cros_build_lib.AssertInsideChroot()
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700159
Alex Klein1699fab2022-09-08 08:46:06 -0600160 sysroot = (
161 opts.sysroot or "/"
162 if opts.host
163 else build_target_lib.get_default_sysroot_path(opts.board)
164 )
165 skipped_packages = set()
166 if opts.skip_packages:
167 skipped_packages |= set(opts.skip_packages.split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700168
Alex Klein1699fab2022-09-08 08:46:06 -0600169 packages = set()
170 # The list of packages to test can be passed as a file containing a
171 # space-separated list of package names.
172 # This is used by the builder to test only the packages that were uprevved.
173 if opts.package_file and os.path.exists(opts.package_file):
174 packages = set(osutils.ReadFile(opts.package_file).split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700175
Alex Klein1699fab2022-09-08 08:46:06 -0600176 if opts.packages:
177 packages |= set(opts.packages.split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700178
Alex Klein1699fab2022-09-08 08:46:06 -0600179 # If no packages were specified, use all testable packages.
180 if not (opts.packages or opts.package_file) and not opts.empty_sysroot:
181 workon = workon_helper.WorkonHelper(sysroot)
182 packages = (
183 workon.InstalledWorkonAtoms()
184 if opts.installed
185 else set(workon.ListAtoms(use_all=True))
186 )
Chris McDonalde69db662018-11-15 12:50:18 -0700187
Alex Klein1699fab2022-09-08 08:46:06 -0600188 if opts.empty_sysroot:
189 packages |= determine_packages(
190 sysroot,
191 SDK_VIRTUAL_PACKAGES if opts.host else BOARD_VIRTUAL_PACKAGES,
192 )
193 workon = workon_helper.WorkonHelper(sysroot)
194 workon_packages = set(workon.ListAtoms(use_all=True))
195 packages &= workon_packages
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700196
Alex Klein1699fab2022-09-08 08:46:06 -0600197 for cp in packages & skipped_packages:
198 logging.info("Skipping package %s.", cp)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700199
Alex Klein1699fab2022-09-08 08:46:06 -0600200 packages = packages - skipped_packages
201 pkg_with_test = portage_util.PackagesWithTest(
202 sysroot, packages, opts.filter_only_cros_workon
203 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700204
Alex Klein1699fab2022-09-08 08:46:06 -0600205 if packages - pkg_with_test:
206 logging.warning(
207 "The following packages do not have tests:\n %s",
208 "\n ".join(sorted(packages - pkg_with_test)),
209 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700210
Alex Klein1699fab2022-09-08 08:46:06 -0600211 if not pkg_with_test:
212 if opts.testable_packages_optional:
213 logging.warning("No testable packages found!")
214 return 0
215 logging.error("No testable packages found!")
216 return 1
Mike Frysingerdcb680f2019-09-02 00:21:44 -0400217
Alex Klein1699fab2022-09-08 08:46:06 -0600218 if opts.pretend:
219 print("\n".join(sorted(pkg_with_test)))
220 return 0
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700221
Alex Klein1699fab2022-09-08 08:46:06 -0600222 env = {}
223 if opts.nowithdebug:
224 use_flags = os.environ.get("USE", "")
225 use_flags += " -cros-debug"
226 env["USE"] = use_flags
Navil Perez03dc71a2021-07-22 18:38:49 +0000227
Artem Sumaneev337b5f62023-02-28 15:38:58 +0000228 features_flags = os.environ.get("FEATURES", "")
229 if features_flags:
230 env["FEATURES"] = features_flags
231
Alex Klein1699fab2022-09-08 08:46:06 -0600232 keep_going = get_keep_going()
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800233
Alex Klein1699fab2022-09-08 08:46:06 -0600234 metrics_dir = os.environ.get(constants.CROS_METRICS_DIR_ENVVAR)
235 if metrics_dir:
236 env[constants.CROS_METRICS_DIR_ENVVAR] = metrics_dir
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700237
Alex Klein1699fab2022-09-08 08:46:06 -0600238 if opts.empty_sysroot:
239 try:
240 chroot_util.Emerge(
241 list(IMPLICIT_TEST_DEPS),
242 sysroot,
243 rebuild_deps=False,
244 use_binary=False,
245 )
246 chroot_util.Emerge(
247 list(pkg_with_test),
248 sysroot,
249 rebuild_deps=False,
250 use_binary=False,
251 )
252 except cros_build_lib.RunCommandError:
253 logging.error("Failed building dependencies for unittests.")
254 return 1
255
Chris McDonalde69db662018-11-15 12:50:18 -0700256 try:
Alex Klein1699fab2022-09-08 08:46:06 -0600257 chroot_util.RunUnittests(
258 sysroot,
259 pkg_with_test,
260 extra_env=env,
261 keep_going=keep_going,
262 jobs=opts.jobs,
George Engelbrecht9476deb2022-10-14 09:59:20 -0600263 verbose=opts.emerge_verbose,
Alex Klein1699fab2022-09-08 08:46:06 -0600264 )
Chris McDonalde69db662018-11-15 12:50:18 -0700265 except cros_build_lib.RunCommandError:
Alex Klein1699fab2022-09-08 08:46:06 -0600266 logging.error("Unittests failed.")
267 return 1