Skip to content

Commit dbc6c04

Browse files
authored
tests: make toolchain tests run in the same build instead of bazel-in-bazel integration tests (bazel-contrib#2095)
This changes the //tests/toolchains tests to run in the same Bazel build instance instead of being bazel-in-bazel integration tests. This is done by using a transition to set the python version to match the desired toolchain. This makes running the tests **much** cheaper -- there were 37 sub-bazel processes being started (one for each python version), which was very expensive. Debugging is also much easier because they aren't part of a bazel-in-bazel invocation.
1 parent ff1dfed commit dbc6c04

File tree

15 files changed

+133
-441
lines changed

15 files changed

+133
-441
lines changed

MODULE.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ bazel_dep(name = "rules_testing", version = "0.6.0", dev_dependency = True)
7676
bazel_dep(name = "rules_go", version = "0.41.0", dev_dependency = True, repo_name = "io_bazel_rules_go")
7777
bazel_dep(name = "gazelle", version = "0.33.0", dev_dependency = True, repo_name = "bazel_gazelle")
7878

79+
dev_python = use_extension(
80+
"//python/extensions:python.bzl",
81+
"python",
82+
dev_dependency = True,
83+
)
84+
dev_python.rules_python_private_testing(
85+
register_all_versions = True,
86+
)
87+
7988
dev_pip = use_extension(
8089
"//python/private/pypi:pip.bzl",
8190
"pip_internal",

WORKSPACE

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ load("//:internal_setup.bzl", "rules_python_internal_setup")
4242
rules_python_internal_setup()
4343

4444
load("//python:repositories.bzl", "python_register_multi_toolchains")
45-
load("//python:versions.bzl", "MINOR_MAPPING")
45+
load("//python:versions.bzl", "MINOR_MAPPING", "TOOL_VERSIONS")
4646

4747
python_register_multi_toolchains(
4848
name = "python",
4949
default_version = MINOR_MAPPING.values()[-2],
50-
python_versions = MINOR_MAPPING.values(),
50+
# Integration tests verify each version, so register all of them.
51+
python_versions = TOOL_VERSIONS.keys(),
5152
)
5253

5354
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")

python/private/python.bzl

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
load("@bazel_features//:features.bzl", "bazel_features")
1818
load("//python:repositories.bzl", "python_register_toolchains")
19+
load("//python:versions.bzl", "TOOL_VERSIONS")
1920
load(":pythons_hub.bzl", "hub_repo")
2021
load(":text_util.bzl", "render")
2122
load(":toolchains_repo.bzl", "multi_toolchain_aliases")
@@ -78,7 +79,9 @@ def _python_impl(module_ctx):
7879
for mod in module_ctx.modules:
7980
module_toolchain_versions = []
8081

81-
for toolchain_attr in mod.tags.toolchain:
82+
toolchain_attr_structs = _create_toolchain_attr_structs(mod)
83+
84+
for toolchain_attr in toolchain_attr_structs:
8285
toolchain_version = toolchain_attr.python_version
8386
toolchain_name = "python_" + toolchain_version.replace(".", "_")
8487

@@ -95,9 +98,7 @@ def _python_impl(module_ctx):
9598
# * rules_python needs to set a soft default in case the root module doesn't,
9699
# e.g. if the root module doesn't use Python itself.
97100
# * The root module is allowed to override the rules_python default.
98-
99-
# A single toolchain is treated as the default because it's unambiguous.
100-
is_default = toolchain_attr.is_default or len(mod.tags.toolchain) == 1
101+
is_default = toolchain_attr.is_default
101102

102103
# Also only the root module should be able to decide ignore_root_user_error.
103104
# Modules being depended upon don't know the final environment, so they aren't
@@ -251,6 +252,43 @@ def _fail_multiple_default_toolchains(first, second):
251252
second = second,
252253
))
253254

255+
def _create_toolchain_attr_structs(mod):
256+
arg_structs = []
257+
seen_versions = {}
258+
for tag in mod.tags.toolchain:
259+
arg_structs.append(_create_toolchain_attrs_struct(tag = tag, toolchain_tag_count = len(mod.tags.toolchain)))
260+
seen_versions[tag.python_version] = True
261+
262+
if mod.is_root:
263+
register_all = False
264+
for tag in mod.tags.rules_python_private_testing:
265+
if tag.register_all_versions:
266+
register_all = True
267+
break
268+
if register_all:
269+
arg_structs.extend([
270+
_create_toolchain_attrs_struct(python_version = v)
271+
for v in TOOL_VERSIONS.keys()
272+
if v not in seen_versions
273+
])
274+
return arg_structs
275+
276+
def _create_toolchain_attrs_struct(*, tag = None, python_version = None, toolchain_tag_count = None):
277+
if tag and python_version:
278+
fail("Only one of tag and python version can be specified")
279+
if tag:
280+
# A single toolchain is treated as the default because it's unambiguous.
281+
is_default = tag.is_default or toolchain_tag_count == 1
282+
else:
283+
is_default = False
284+
285+
return struct(
286+
is_default = is_default,
287+
python_version = python_version if python_version else tag.python_version,
288+
configure_coverage_tool = getattr(tag, "configure_coverage_tool", False),
289+
ignore_root_user_error = getattr(tag, "ignore_root_user_error", False),
290+
)
291+
254292
def _get_bazel_version_specific_kwargs():
255293
kwargs = {}
256294

@@ -264,6 +302,11 @@ python = module_extension(
264302
""",
265303
implementation = _python_impl,
266304
tag_classes = {
305+
"rules_python_private_testing": tag_class(
306+
attrs = {
307+
"register_all_versions": attr.bool(default = False),
308+
},
309+
),
267310
"toolchain": tag_class(
268311
doc = """Tag class used to register Python toolchains.
269312
Use this tag class to register one or more Python toolchains. This class

tests/support/sh_py_run_test.bzl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,33 @@ without the overhead of a bazel-in-bazel integration test.
2020
load("//python:py_binary.bzl", "py_binary")
2121
load("//python:py_test.bzl", "py_test")
2222
load("//python/private:toolchain_types.bzl", "TARGET_TOOLCHAIN_TYPE") # buildifier: disable=bzl-visibility
23+
load("//tests/support:support.bzl", "VISIBLE_FOR_TESTING")
2324

2425
def _perform_transition_impl(input_settings, attr):
2526
settings = dict(input_settings)
27+
settings[VISIBLE_FOR_TESTING] = True
2628
settings["//command_line_option:build_python_zip"] = attr.build_python_zip
2729
if attr.bootstrap_impl:
2830
settings["//python/config_settings:bootstrap_impl"] = attr.bootstrap_impl
2931
if attr.extra_toolchains:
3032
settings["//command_line_option:extra_toolchains"] = attr.extra_toolchains
31-
else:
32-
settings["//command_line_option:extra_toolchains"] = input_settings["//command_line_option:extra_toolchains"]
33+
if attr.python_version:
34+
settings["//python/config_settings:python_version"] = attr.python_version
3335
return settings
3436

3537
_perform_transition = transition(
3638
implementation = _perform_transition_impl,
3739
inputs = [
3840
"//python/config_settings:bootstrap_impl",
3941
"//command_line_option:extra_toolchains",
42+
"//python/config_settings:python_version",
4043
],
4144
outputs = [
4245
"//command_line_option:build_python_zip",
4346
"//command_line_option:extra_toolchains",
4447
"//python/config_settings:bootstrap_impl",
48+
"//python/config_settings:python_version",
49+
VISIBLE_FOR_TESTING,
4550
],
4651
)
4752

@@ -99,6 +104,7 @@ to make the RBE presubmits happy, which disable auto-detection of a CC
99104
toolchain.
100105
""",
101106
),
107+
"python_version": attr.string(),
102108
"target": attr.label(executable = True, cfg = "target"),
103109
"_allowlist_function_transition": attr.label(
104110
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
@@ -125,7 +131,10 @@ def py_reconfig_test(*, name, **kwargs):
125131
reconfig_kwargs = {}
126132
reconfig_kwargs["bootstrap_impl"] = kwargs.pop("bootstrap_impl", None)
127133
reconfig_kwargs["extra_toolchains"] = kwargs.pop("extra_toolchains", None)
134+
reconfig_kwargs["python_version"] = kwargs.pop("python_version", None)
128135
reconfig_kwargs["env"] = kwargs.get("env")
136+
reconfig_kwargs["target_compatible_with"] = kwargs.get("target_compatible_with")
137+
129138
inner_name = "_{}_inner" + name
130139
_py_reconfig_test(
131140
name = name,
@@ -178,6 +187,7 @@ def _current_build_settings_impl(ctx):
178187
"short_path": runtime.interpreter.short_path if runtime.interpreter else None,
179188
},
180189
"interpreter_path": runtime.interpreter_path,
190+
"toolchain_label": str(getattr(toolchain, "toolchain_label", None)),
181191
}),
182192
)
183193
return [DefaultInfo(

tests/toolchains/BUILD.bazel

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
load(":defs.bzl", "acceptance_tests")
16-
load(":versions_test.bzl", "versions_test_suite")
15+
load(":defs.bzl", "define_toolchain_tests")
1716

18-
versions_test_suite(name = "versions_test")
19-
20-
acceptance_tests()
17+
define_toolchain_tests(
18+
name = "toolchain_tests",
19+
)

0 commit comments

Comments
 (0)