blob: e14714d272924cbb1996646a037fcb9dcc94d32f [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:
36 argv: array of arguments passed to the script.
37 """
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",
66 help="Test all testable packages, even if they are not "
67 "currently installed.",
68 )
69 parser.add_argument(
70 "--package_file",
71 type="path",
72 help="Path to a file containing the list of packages "
73 "that should be tested.",
74 )
75 parser.add_argument(
76 "--packages", help="Space-separated list of packages to test."
77 )
78 parser.add_argument(
79 "--skip-packages",
80 help="Space-separated list of packages to NOT test even "
81 "if they otherwise would have been tested.",
82 )
83 parser.add_argument(
84 "--nowithdebug",
85 action="store_true",
86 help="Don't build the tests with USE=cros-debug",
87 )
88 parser.add_argument(
89 "--assume-empty-sysroot",
90 default=False,
91 action="store_true",
92 dest="empty_sysroot",
93 help="Set up dependencies and run unit tests for all "
94 "packages that could be installed on target board "
95 "without assuming that any packages have actually "
96 "been merged yet.",
97 )
98 parser.add_argument(
99 "-j",
100 "--jobs",
101 type=int,
102 default=multiprocessing.cpu_count(),
103 help="The limit for the number of possible concurrent jobs.",
104 )
105 parser.add_argument(
106 "--no-testable-packages-ok",
107 default=False,
108 action="store_true",
109 dest="testable_packages_optional",
110 help="If specified, do not fail if no testable packages are found.",
111 )
112 parser.add_argument(
113 "--filter-only-cros-workon",
114 default=False,
115 action="store_true",
116 help="If specified and packages are given, filters out non-cros_workon "
117 "packages.",
118 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700119
Alex Klein1699fab2022-09-08 08:46:06 -0600120 options = parser.parse_args(argv)
121 options.Freeze()
122 return options
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700123
124
Sloan Johnsona85640f2021-10-01 22:32:40 +0000125def determine_packages(sysroot, virtual_packages):
Alex Klein1699fab2022-09-08 08:46:06 -0600126 """Returns a set of the dependencies for the given packages"""
127 deps, _bdeps = cros_extract_deps.ExtractDeps(
128 sysroot, virtual_packages, include_bdepend=False
129 )
130 return set(
131 "%s/%s" % (atom["category"], atom["name"]) for atom in deps.values()
132 )
133
Chris McDonalde69db662018-11-15 12:50:18 -0700134
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800135def get_keep_going():
Alex Klein1699fab2022-09-08 08:46:06 -0600136 """Check if should enable keep_going parameter.
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800137
Alex Klein1699fab2022-09-08 08:46:06 -0600138 If the 'USE' environment contains 'coverage' then enable keep_going option
139 to prevent certain package failure from breaking the whole coverage
140 generation workflow, otherwise leave it to default settings
141 """
142 return "coverage" in os.environ.get("USE", "")
143
Chris McDonalde69db662018-11-15 12:50:18 -0700144
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700145def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600146 opts = ParseArgs(argv)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700147
Alex Klein1699fab2022-09-08 08:46:06 -0600148 cros_build_lib.AssertInsideChroot()
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700149
Alex Klein1699fab2022-09-08 08:46:06 -0600150 sysroot = (
151 opts.sysroot or "/"
152 if opts.host
153 else build_target_lib.get_default_sysroot_path(opts.board)
154 )
155 skipped_packages = set()
156 if opts.skip_packages:
157 skipped_packages |= set(opts.skip_packages.split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700158
Alex Klein1699fab2022-09-08 08:46:06 -0600159 packages = set()
160 # The list of packages to test can be passed as a file containing a
161 # space-separated list of package names.
162 # This is used by the builder to test only the packages that were uprevved.
163 if opts.package_file and os.path.exists(opts.package_file):
164 packages = set(osutils.ReadFile(opts.package_file).split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700165
Alex Klein1699fab2022-09-08 08:46:06 -0600166 if opts.packages:
167 packages |= set(opts.packages.split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700168
Alex Klein1699fab2022-09-08 08:46:06 -0600169 # If no packages were specified, use all testable packages.
170 if not (opts.packages or opts.package_file) and not opts.empty_sysroot:
171 workon = workon_helper.WorkonHelper(sysroot)
172 packages = (
173 workon.InstalledWorkonAtoms()
174 if opts.installed
175 else set(workon.ListAtoms(use_all=True))
176 )
Chris McDonalde69db662018-11-15 12:50:18 -0700177
Alex Klein1699fab2022-09-08 08:46:06 -0600178 if opts.empty_sysroot:
179 packages |= determine_packages(
180 sysroot,
181 SDK_VIRTUAL_PACKAGES if opts.host else BOARD_VIRTUAL_PACKAGES,
182 )
183 workon = workon_helper.WorkonHelper(sysroot)
184 workon_packages = set(workon.ListAtoms(use_all=True))
185 packages &= workon_packages
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700186
Alex Klein1699fab2022-09-08 08:46:06 -0600187 for cp in packages & skipped_packages:
188 logging.info("Skipping package %s.", cp)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700189
Alex Klein1699fab2022-09-08 08:46:06 -0600190 packages = packages - skipped_packages
191 pkg_with_test = portage_util.PackagesWithTest(
192 sysroot, packages, opts.filter_only_cros_workon
193 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700194
Alex Klein1699fab2022-09-08 08:46:06 -0600195 if packages - pkg_with_test:
196 logging.warning(
197 "The following packages do not have tests:\n %s",
198 "\n ".join(sorted(packages - pkg_with_test)),
199 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700200
Alex Klein1699fab2022-09-08 08:46:06 -0600201 if not pkg_with_test:
202 if opts.testable_packages_optional:
203 logging.warning("No testable packages found!")
204 return 0
205 logging.error("No testable packages found!")
206 return 1
Mike Frysingerdcb680f2019-09-02 00:21:44 -0400207
Alex Klein1699fab2022-09-08 08:46:06 -0600208 if opts.pretend:
209 print("\n".join(sorted(pkg_with_test)))
210 return 0
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700211
Alex Klein1699fab2022-09-08 08:46:06 -0600212 env = {}
213 if opts.nowithdebug:
214 use_flags = os.environ.get("USE", "")
215 use_flags += " -cros-debug"
216 env["USE"] = use_flags
Navil Perez03dc71a2021-07-22 18:38:49 +0000217
Artem Sumaneev337b5f62023-02-28 15:38:58 +0000218 features_flags = os.environ.get("FEATURES", "")
219 if features_flags:
220 env["FEATURES"] = features_flags
221
Alex Klein1699fab2022-09-08 08:46:06 -0600222 keep_going = get_keep_going()
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800223
Alex Klein1699fab2022-09-08 08:46:06 -0600224 metrics_dir = os.environ.get(constants.CROS_METRICS_DIR_ENVVAR)
225 if metrics_dir:
226 env[constants.CROS_METRICS_DIR_ENVVAR] = metrics_dir
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700227
Alex Klein1699fab2022-09-08 08:46:06 -0600228 if opts.empty_sysroot:
229 try:
230 chroot_util.Emerge(
231 list(IMPLICIT_TEST_DEPS),
232 sysroot,
233 rebuild_deps=False,
234 use_binary=False,
235 )
236 chroot_util.Emerge(
237 list(pkg_with_test),
238 sysroot,
239 rebuild_deps=False,
240 use_binary=False,
241 )
242 except cros_build_lib.RunCommandError:
243 logging.error("Failed building dependencies for unittests.")
244 return 1
245
Chris McDonalde69db662018-11-15 12:50:18 -0700246 try:
Alex Klein1699fab2022-09-08 08:46:06 -0600247 chroot_util.RunUnittests(
248 sysroot,
249 pkg_with_test,
250 extra_env=env,
251 keep_going=keep_going,
252 jobs=opts.jobs,
George Engelbrecht9476deb2022-10-14 09:59:20 -0600253 verbose=opts.emerge_verbose,
Alex Klein1699fab2022-09-08 08:46:06 -0600254 )
Chris McDonalde69db662018-11-15 12:50:18 -0700255 except cros_build_lib.RunCommandError:
Alex Klein1699fab2022-09-08 08:46:06 -0600256 logging.error("Unittests failed.")
257 return 1