blob: 8a42265777bcaefa0b12774dc7c2320166a981d1 [file] [log] [blame]
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -07001# Copyright 2015 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"""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)
41 target.add_argument("--sysroot", type="path", help="Path to the sysroot.")
42 target.add_argument("--board", help="Board name.")
43 target.add_argument(
44 "--host", action="store_true", help="Run tests for the host SDK."
45 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -070046
Alex Klein1699fab2022-09-08 08:46:06 -060047 parser.add_argument(
48 "--pretend",
49 default=False,
50 action="store_true",
51 help="Show the list of packages to be tested and return.",
52 )
53 parser.add_argument(
54 "--noinstalled_only",
55 dest="installed",
56 default=True,
57 action="store_false",
58 help="Test all testable packages, even if they are not "
59 "currently installed.",
60 )
61 parser.add_argument(
62 "--package_file",
63 type="path",
64 help="Path to a file containing the list of packages "
65 "that should be tested.",
66 )
67 parser.add_argument(
68 "--packages", help="Space-separated list of packages to test."
69 )
70 parser.add_argument(
71 "--skip-packages",
72 help="Space-separated list of packages to NOT test even "
73 "if they otherwise would have been tested.",
74 )
75 parser.add_argument(
76 "--nowithdebug",
77 action="store_true",
78 help="Don't build the tests with USE=cros-debug",
79 )
80 parser.add_argument(
81 "--assume-empty-sysroot",
82 default=False,
83 action="store_true",
84 dest="empty_sysroot",
85 help="Set up dependencies and run unit tests for all "
86 "packages that could be installed on target board "
87 "without assuming that any packages have actually "
88 "been merged yet.",
89 )
90 parser.add_argument(
91 "-j",
92 "--jobs",
93 type=int,
94 default=multiprocessing.cpu_count(),
95 help="The limit for the number of possible concurrent jobs.",
96 )
97 parser.add_argument(
98 "--no-testable-packages-ok",
99 default=False,
100 action="store_true",
101 dest="testable_packages_optional",
102 help="If specified, do not fail if no testable packages are found.",
103 )
104 parser.add_argument(
105 "--filter-only-cros-workon",
106 default=False,
107 action="store_true",
108 help="If specified and packages are given, filters out non-cros_workon "
109 "packages.",
110 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700111
Alex Klein1699fab2022-09-08 08:46:06 -0600112 options = parser.parse_args(argv)
113 options.Freeze()
114 return options
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700115
116
Sloan Johnsona85640f2021-10-01 22:32:40 +0000117def determine_packages(sysroot, virtual_packages):
Alex Klein1699fab2022-09-08 08:46:06 -0600118 """Returns a set of the dependencies for the given packages"""
119 deps, _bdeps = cros_extract_deps.ExtractDeps(
120 sysroot, virtual_packages, include_bdepend=False
121 )
122 return set(
123 "%s/%s" % (atom["category"], atom["name"]) for atom in deps.values()
124 )
125
Chris McDonalde69db662018-11-15 12:50:18 -0700126
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800127def get_keep_going():
Alex Klein1699fab2022-09-08 08:46:06 -0600128 """Check if should enable keep_going parameter.
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800129
Alex Klein1699fab2022-09-08 08:46:06 -0600130 If the 'USE' environment contains 'coverage' then enable keep_going option
131 to prevent certain package failure from breaking the whole coverage
132 generation workflow, otherwise leave it to default settings
133 """
134 return "coverage" in os.environ.get("USE", "")
135
Chris McDonalde69db662018-11-15 12:50:18 -0700136
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700137def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600138 opts = ParseArgs(argv)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700139
Alex Klein1699fab2022-09-08 08:46:06 -0600140 cros_build_lib.AssertInsideChroot()
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700141
Alex Klein1699fab2022-09-08 08:46:06 -0600142 sysroot = (
143 opts.sysroot or "/"
144 if opts.host
145 else build_target_lib.get_default_sysroot_path(opts.board)
146 )
147 skipped_packages = set()
148 if opts.skip_packages:
149 skipped_packages |= set(opts.skip_packages.split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700150
Alex Klein1699fab2022-09-08 08:46:06 -0600151 packages = set()
152 # The list of packages to test can be passed as a file containing a
153 # space-separated list of package names.
154 # This is used by the builder to test only the packages that were uprevved.
155 if opts.package_file and os.path.exists(opts.package_file):
156 packages = set(osutils.ReadFile(opts.package_file).split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700157
Alex Klein1699fab2022-09-08 08:46:06 -0600158 if opts.packages:
159 packages |= set(opts.packages.split())
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700160
Alex Klein1699fab2022-09-08 08:46:06 -0600161 # If no packages were specified, use all testable packages.
162 if not (opts.packages or opts.package_file) and not opts.empty_sysroot:
163 workon = workon_helper.WorkonHelper(sysroot)
164 packages = (
165 workon.InstalledWorkonAtoms()
166 if opts.installed
167 else set(workon.ListAtoms(use_all=True))
168 )
Chris McDonalde69db662018-11-15 12:50:18 -0700169
Alex Klein1699fab2022-09-08 08:46:06 -0600170 if opts.empty_sysroot:
171 packages |= determine_packages(
172 sysroot,
173 SDK_VIRTUAL_PACKAGES if opts.host else BOARD_VIRTUAL_PACKAGES,
174 )
175 workon = workon_helper.WorkonHelper(sysroot)
176 workon_packages = set(workon.ListAtoms(use_all=True))
177 packages &= workon_packages
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700178
Alex Klein1699fab2022-09-08 08:46:06 -0600179 for cp in packages & skipped_packages:
180 logging.info("Skipping package %s.", cp)
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700181
Alex Klein1699fab2022-09-08 08:46:06 -0600182 packages = packages - skipped_packages
183 pkg_with_test = portage_util.PackagesWithTest(
184 sysroot, packages, opts.filter_only_cros_workon
185 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700186
Alex Klein1699fab2022-09-08 08:46:06 -0600187 if packages - pkg_with_test:
188 logging.warning(
189 "The following packages do not have tests:\n %s",
190 "\n ".join(sorted(packages - pkg_with_test)),
191 )
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700192
Alex Klein1699fab2022-09-08 08:46:06 -0600193 if not pkg_with_test:
194 if opts.testable_packages_optional:
195 logging.warning("No testable packages found!")
196 return 0
197 logging.error("No testable packages found!")
198 return 1
Mike Frysingerdcb680f2019-09-02 00:21:44 -0400199
Alex Klein1699fab2022-09-08 08:46:06 -0600200 if opts.pretend:
201 print("\n".join(sorted(pkg_with_test)))
202 return 0
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700203
Alex Klein1699fab2022-09-08 08:46:06 -0600204 env = {}
205 if opts.nowithdebug:
206 use_flags = os.environ.get("USE", "")
207 use_flags += " -cros-debug"
208 env["USE"] = use_flags
Navil Perez03dc71a2021-07-22 18:38:49 +0000209
Alex Klein1699fab2022-09-08 08:46:06 -0600210 keep_going = get_keep_going()
Hengxiang Hu2e33c712022-01-25 19:11:07 -0800211
Alex Klein1699fab2022-09-08 08:46:06 -0600212 metrics_dir = os.environ.get(constants.CROS_METRICS_DIR_ENVVAR)
213 if metrics_dir:
214 env[constants.CROS_METRICS_DIR_ENVVAR] = metrics_dir
Bertrand SIMONNETe025a0e2015-05-06 14:17:43 -0700215
Alex Klein1699fab2022-09-08 08:46:06 -0600216 if opts.empty_sysroot:
217 try:
218 chroot_util.Emerge(
219 list(IMPLICIT_TEST_DEPS),
220 sysroot,
221 rebuild_deps=False,
222 use_binary=False,
223 )
224 chroot_util.Emerge(
225 list(pkg_with_test),
226 sysroot,
227 rebuild_deps=False,
228 use_binary=False,
229 )
230 except cros_build_lib.RunCommandError:
231 logging.error("Failed building dependencies for unittests.")
232 return 1
233
Chris McDonalde69db662018-11-15 12:50:18 -0700234 try:
Alex Klein1699fab2022-09-08 08:46:06 -0600235 chroot_util.RunUnittests(
236 sysroot,
237 pkg_with_test,
238 extra_env=env,
239 keep_going=keep_going,
240 jobs=opts.jobs,
241 )
Chris McDonalde69db662018-11-15 12:50:18 -0700242 except cros_build_lib.RunCommandError:
Alex Klein1699fab2022-09-08 08:46:06 -0600243 logging.error("Unittests failed.")
244 return 1