8000 tests(pystar): py_runtime_pair and py_runtime analysis tests (#1441) · geaden/rules_python@21b54b2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 21b54b2

Browse files
authored
tests(pystar): py_runtime_pair and py_runtime analysis tests (bazel-contrib#1441)
These analysis tests verify that `py_runtime` and `py_runtime_pair` are working as intended for both the native Bazel and Starlark implementations. Work towards bazel-contrib#1069
1 parent 4dfb78d commit 21b54b2

File tree

8 files changed

+475
-3
lines changed

8 files changed

+475
-3
lines changed

python/BUILD.bazel

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,11 @@ bzl_library(
147147
bzl_library(
148148
name = "py_runtime_pair_bzl",
149149
srcs = ["py_runtime_pair.bzl"],
150-
deps = ["//python/private:bazel_tools_bzl"],
150+
deps = [
151+
"//python/private:bazel_tools_bzl",
152+
"//python/private:py_runtime_pair_macro_bzl",
153+
"@rules_python_internal//:rules_python_config_bzl",
154+
],
151155
)
152156

153157
bzl_library(

python/private/BUILD.bazel

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ bzl_library(
104104

105105
bzl_library(
106106
name = "py_runtime_pair_macro_bzl",
107-
srcs = ["py_runtime_pair_rule.bzl"],
107+
srcs = ["py_runtime_pair_macro.bzl"],
108+
visibility = ["//:__subpackages__"],
108109
deps = [":py_runtime_pair_rule_bzl"],
109110
)
110111

python/py_runtime_pair.bzl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414

1515
"""Public entry point for py_runtime_pair."""
1616

17-
load("@bazel_tools//tools/python:toolchain.bzl", _py_runtime_pair = "py_runtime_pair")
17+
load("@bazel_tools//tools/python:toolchain.bzl", _bazel_tools_impl = "py_runtime_pair")
18+
load("@rules_python_internal//:rules_python_config.bzl", "config")
19+
load("//python/private:py_runtime_pair_macro.bzl", _starlark_impl = "py_runtime_pair")
20+
21+
_py_runtime_pair = _bazel_tools_impl if not config.enable_pystar else _starlark_impl
1822

1923
# NOTE: This doc is copy/pasted from the builtin py_runtime_pair rule so our
2024
# doc generator gives useful API docs.

tests/py_runtime/BUILD.bazel

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright 2023 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
load(":py_runtime_tests.bzl", "py_runtime_test_suite")
16+
17+
py_runtime_test_suite(name = "py_runtime_tests")

tests/py_runtime/py_runtime_tests.bzl

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
# Copyright 2023 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""Starlark tests for py_runtime rule."""
15+
16+
load("@rules_python_internal//:rules_python_config.bzl", "config")
17+
load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
18+
load("@rules_testing//lib:test_suite.bzl", "test_suite")
19+
load("@rules_testing//lib:truth.bzl", "matching")
20+
load("@rules_testing//lib:util.bzl", rt_util = "util")
21+
load("//python:py_runtime.bzl", "py_runtime")
22+
load("//python:py_runtime_info.bzl", "PyRuntimeInfo")
23+
load("//tests:py_runtime_info_subject.bzl", "py_runtime_info_subject")
24+
load("//tests/base_rules:util.bzl", br_util = "util")
25+
26+
_tests = []
27+
28+
_SKIP_TEST = {
29+
"target_compatible_with": ["@platforms//:incompatible"],
30+
}
31+
32+
def _test_bootstrap_template(name):
33+
# The bootstrap_template arg isn't present in older Bazel versions, so
34+
# we have to conditionally pass the arg and mark the test incompatible.
35+
if config.enable_pystar:
36+
py_runtime_kwargs = {"bootstrap_template": "bootstrap.txt"}
37+
attr_values = {}
38+
else:
39+
py_runtime_kwargs = {}
40+
attr_values = _SKIP_TEST
41+
42+
rt_util.helper_target(
43+
py_runtime,
44+
name = name + "_subject",
45+
interpreter_path = "/py",
46+
python_version = "PY3",
47+
**py_runtime_kwargs
48+
)
49+
analysis_test(
50+
name = name,
51+
target = name + "_subject",
52+
impl = _test_bootstrap_template_impl,
53+
attr_values = attr_values,
54+
)
55+
56+
def _test_bootstrap_template_impl(env, target):
57+
env.expect.that_target(target).provider(
58+
PyRuntimeInfo,
59+
factory = py_runtime_info_subject,
60+
).bootstrap_template().path().contains("bootstrap.txt")
61+
62+
_tests.append(_test_bootstrap_template)
63+
64+
def _test_cannot_have_both_inbuild_and_system_interpreter(name):
65+
if br_util.is_bazel_6_or_higher():
66+
py_runtime_kwargs = {
67+
"interpreter": "fake_interpreter",
68+
"interpreter_path": "/some/path",
69+
}
70+
attr_values = {}
71+
else:
72+
py_runtime_kwargs = {
73+
"interpreter_path": "/some/path",
74+
}
75+
attr_values = _SKIP_TEST
76+
rt_util.helper_target(
77+
py_runtime,
78+
name = name + "_subject",
79+
python_version = "PY3",
80+
**py_runtime_kwargs
81+
)
82+
analysis_test(
83+
name = name,
84+
target = name + "_subject",
85+
impl = _test_cannot_have_both_inbuild_and_system_interpreter_impl,
86+
expect_failure = True,
87+
attr_values = attr_values,
88+
)
89+
90+
def _test_cannot_have_both_inbuild_and_system_interpreter_impl(env, target):
91+
env.expect.that_target(target).failures().contains_predicate(
92+
matching.str_matches("one of*interpreter*interpreter_path"),
93+
)
94+
95+
_tests.append(_test_cannot_have_both_inbuild_and_system_interpreter)
96+
97+
def _test_cannot_specify_files_for_system_interpreter(name):
98+
if br_util.is_bazel_6_or_higher():
99+
py_runtime_kwargs = {"files": ["foo.txt"]}
100+
attr_values = {}
101+
else:
102+
py_runtime_kwargs = {}
103+
attr_values = _SKIP_TEST
104+
rt_util.helper_target(
105+
py_runtime,
106+
name = name + "_subject",
107+
interpreter_path = "/foo",
108+
python_version = "PY3",
109+
**py_runtime_kwargs
110+
)
111+
analysis_test(
112+
name = name,
113+
target = name + "_subject",
114+
impl = _test_cannot_specify_files_for_system_interpreter_impl,
115+
expect_failure = True,
116+
attr_values = attr_values,
117+
)
118+
119+
def _test_cannot_specify_files_for_system_interpreter_impl(env, target):
120+
env.expect.that_target(target).failures().contains_predicate(
121+
matching.str_matches("files*must be empty"),
122+
)
123+
124+
_tests.append(_test_cannot_specify_files_for_system_interpreter)
125+
126+
def _test_in_build_interpreter(name):
127+
rt_util.helper_target(
128+
py_runtime,
129+
name = name + "_subject",
130+
interpreter = "fake_interpreter",
131+
python_version = "PY3",
132+
files = ["file1.txt"],
133+
)
134+
analysis_test(
135+
name = name,
136+
target = name + "_subject",
137+
impl = _test_in_build_interpreter_impl,
138+
)
139+
140+
def _test_in_build_interpreter_impl(env, target):
141+
info = env.expect.that_target(target).provider(PyRuntimeInfo, factory = py_runtime_info_subject)
142+
info.python_version().equals("PY3")
143+
info.files().contains_predicate(matching.file_basename_equals("file1.txt"))
144+
info.interpreter().path().contains("fake_interpreter")
145+
146+
_tests.append(_test_in_build_interpreter)
147+
148+
def _test_must_have_either_inbuild_or_system_interpreter(name):
149+
if br_util.is_bazel_6_or_higher():
150+
py_runtime_kwargs = {}
151+
attr_values = {}
152+
else:
153+
py_runtime_kwargs = {
154+
"interpreter_path": "/some/path",
155+
}
156+
attr_values = _SKIP_TEST
157+
rt_util.helper_target(
158+
py_runtime,
159+
name = name + "_subject",
160+
python_version = "PY3",
161+
**py_runtime_kwargs
162+
)
163+
analysis_test(
164+
name = name,
165+
target = name + "_subject",
166+
impl = _test_must_have_either_inbuild_or_system_interpreter_impl,
167+
expect_failure = True,
168+
attr_values = attr_values,
169+
)
170+
171+
def _test_must_have_either_inbuild_or_system_interpreter_impl(env, target):
172+
env.expect.that_target(target).failures().contains_predicate(
173+
matching.str_matches("one of*interpreter*interpreter_path"),
174+
)
175+
176+
_tests.append(_test_must_have_either_inbuild_or_system_interpreter)
177+
178+
def _test_python_version_required(name):
179+
# Bazel 5.4 will entirely crash when python_version is missing.
180+
if br_util.is_bazel_6_or_higher():
181+
py_runtime_kwargs = {}
182+
attr_values = {}
183+
else:
184+
py_runtime_kwargs = {"python_version": "PY3"}
185+
attr_values = _SKIP_TEST
186+
rt_util.helper_target(
187+
py_runtime,
188+
name = name + "_subject",
189+
interpreter_path = "/math/pi",
190+
**py_runtime_kwargs
191+
)
192+
analysis_test(
193+
name = name,
194+
target = name + "_subject",
195+
impl = _test_python_version_required_impl,
196+
expect_failure = True,
197+
attr_values = attr_values,
198+
)
199+
200+
def _test_python_version_required_impl(env, target):
201+
env.expect.that_target(target).failures().contains_predicate(
202+
matching.str_matches("must be set*PY2*PY3"),
203+
)
204+
205+
_tests.append(_test_python_version_required)
206+
207+
def _test_system_interpreter(name):
208+
rt_util.helper_target(
209+
py_runtime,
210+
name = name + "_subject",
211+
interpreter_path = "/system/python",
212+
python_version = "PY3",
213+
)
214+
analysis_test(
215+
name = name,
216+
target = name + "_subject",
217+
impl = _test_system_interpreter_impl,
218+
)
219+
220+
def _test_system_interpreter_impl(env, target):
221+
env.expect.that_target(target).provider(
222+
PyRuntimeInfo,
223+
factory = py_runtime_info_subject,
224+
).interpreter_path().equals("/system/python")
225+
226+
_tests.append(_test_system_interpreter)
227+
228+
def _test_system_interpreter_must_be_absolute(name):
229+
# Bazel 5.4 will entirely crash when an invalid interpreter_path
230+
# is given.
231+
if br_util.is_bazel_6_or_higher():
232+
py_runtime_kwargs = {"interpreter_path": "relative/path"}
233+
attr_values = {}
234+
else:
235+
py_runtime_kwargs = {"interpreter_path": "/junk/value/for/bazel5.4"}
236+
attr_values = _SKIP_TEST
237+
rt_util.helper_target(
238+
py_runtime,
239+
name = name + "_subject",
240+
python_version = "PY3",
241+
**py_runtime_kwargs
242+
)
243+
analysis_test(
244+
name = name,
245+
target = name + "_subject",
246+
impl = _test_system_interpreter_must_be_absolute_impl,
247+
expect_failure = True,
248+
attr_values = attr_values,
249+
)
250+
251+
def _test_system_interpreter_must_be_absolute_impl(env, target):
252+
env.expect.that_target(target).failures().contains_predicate(
253+
matching.str_matches("must be*absolute"),
254+
)
255+
256+
_tests.append(_test_system_interpreter_must_be_absolute)
257+
258+
def py_runtime_test_suite(name):
259+
test_suite(
260+
name = name,
261+
tests = _tests,
262+
)

0 commit comments

Comments
 (0)
0