• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2024 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""
16
17load("@rules_testing//lib:test_suite.bzl", "test_suite")
18load("//python/private:glob_excludes.bzl", "glob_excludes")  # buildifier: disable=bzl-visibility
19load("//python/private/pypi:whl_library_targets.bzl", "whl_library_targets")  # buildifier: disable=bzl-visibility
20
21_tests = []
22
23def _test_filegroups(env):
24    calls = []
25
26    def glob(match, *, allow_empty):
27        env.expect.that_bool(allow_empty).equals(True)
28        return match
29
30    whl_library_targets(
31        name = "",
32        dep_template = "",
33        native = struct(
34            filegroup = lambda **kwargs: calls.append(kwargs),
35            glob = glob,
36        ),
37        rules = struct(),
38    )
39
40    env.expect.that_collection(calls).contains_exactly([
41        {
42            "name": "dist_info",
43            "srcs": ["site-packages/*.dist-info/**"],
44            "visibility": ["//visibility:public"],
45        },
46        {
47            "name": "data",
48            "srcs": ["data/**"],
49            "visibility": ["//visibility:public"],
50        },
51        {
52            "name": "whl",
53            "srcs": [""],
54            "data": [],
55            "visibility": ["//visibility:public"],
56        },
57    ])  # buildifier: @unsorted-dict-items
58
59_tests.append(_test_filegroups)
60
61def _test_platforms(env):
62    calls = []
63
64    whl_library_targets(
65        name = "",
66        dep_template = None,
67        dependencies_by_platform = {
68            "@//python/config_settings:is_python_3.9": ["py39_dep"],
69            "@platforms//cpu:aarch64": ["arm_dep"],
70            "@platforms//os:windows": ["win_dep"],
71            "cp310_linux_ppc": ["py310_linux_ppc_dep"],
72            "cp39_anyos_aarch64": ["py39_arm_dep"],
73            "cp39_linux_anyarch": ["py39_linux_dep"],
74            "linux_x86_64": ["linux_intel_dep"],
75        },
76        filegroups = {},
77        native = struct(
78            config_setting = lambda **kwargs: calls.append(kwargs),
79        ),
80        rules = struct(),
81    )
82
83    env.expect.that_collection(calls).contains_exactly([
84        {
85            "name": "is_python_3.10_linux_ppc",
86            "flag_values": {
87                "@rules_python//python/config_settings:python_version_major_minor": "3.10",
88            },
89            "constraint_values": [
90                "@platforms//cpu:ppc",
91                "@platforms//os:linux",
92            ],
93            "visibility": ["//visibility:private"],
94        },
95        {
96            "name": "is_python_3.9_anyos_aarch64",
97            "flag_values": {
98                "@rules_python//python/config_settings:python_version_major_minor": "3.9",
99            },
100            "constraint_values": ["@platforms//cpu:aarch64"],
101            "visibility": ["//visibility:private"],
102        },
103        {
104            "name": "is_python_3.9_linux_anyarch",
105            "flag_values": {
106                "@rules_python//python/config_settings:python_version_major_minor": "3.9",
107            },
108            "constraint_values": ["@platforms//os:linux"],
109            "visibility": ["//visibility:private"],
110        },
111        {
112            "name": "is_linux_x86_64",
113            "constraint_values": [
114                "@platforms//cpu:x86_64",
115                "@platforms//os:linux",
116            ],
117            "visibility": ["//visibility:private"],
118        },
119    ])  # buildifier: @unsorted-dict-items
120
121_tests.append(_test_platforms)
122
123def _test_copy(env):
124    calls = []
125
126    whl_library_targets(
127        name = "",
128        dep_template = None,
129        dependencies_by_platform = {},
130        filegroups = {},
131        copy_files = {"file_src": "file_dest"},
132        copy_executables = {"exec_src": "exec_dest"},
133        native = struct(),
134        rules = struct(
135            copy_file = lambda **kwargs: calls.append(kwargs),
136        ),
137    )
138
139    env.expect.that_collection(calls).contains_exactly([
140        {
141            "name": "file_dest.copy",
142            "out": "file_dest",
143            "src": "file_src",
144            "visibility": ["//visibility:public"],
145        },
146        {
147            "is_executable": True,
148            "name": "exec_dest.copy",
149            "out": "exec_dest",
150            "src": "exec_src",
151            "visibility": ["//visibility:public"],
152        },
153    ])
154
155_tests.append(_test_copy)
156
157def _test_entrypoints(env):
158    calls = []
159
160    whl_library_targets(
161        name = "",
162        dep_template = None,
163        dependencies_by_platform = {},
164        filegroups = {},
165        entry_points = {
166            "fizz": "buzz.py",
167        },
168        native = struct(),
169        rules = struct(
170            py_binary = lambda **kwargs: calls.append(kwargs),
171        ),
172    )
173
174    env.expect.that_collection(calls).contains_exactly([
175        {
176            "name": "rules_python_wheel_entry_point_fizz",
177            "srcs": ["buzz.py"],
178            "deps": [":pkg"],
179            "imports": ["."],
180            "visibility": ["//visibility:public"],
181        },
182    ])  # buildifier: @unsorted-dict-items
183
184_tests.append(_test_entrypoints)
185
186def _test_whl_and_library_deps(env):
187    filegroup_calls = []
188    py_library_calls = []
189
190    whl_library_targets(
191        name = "foo.whl",
192        dep_template = "@pypi_{name}//:{target}",
193        dependencies = ["foo", "bar-baz"],
194        dependencies_by_platform = {
195            "@//python/config_settings:is_python_3.9": ["py39_dep"],
196            "@platforms//cpu:aarch64": ["arm_dep"],
197            "@platforms//os:windows": ["win_dep"],
198            "cp310_linux_ppc": ["py310_linux_ppc_dep"],
199            "cp39_anyos_aarch64": ["py39_arm_dep"],
200            "cp39_linux_anyarch": ["py39_linux_dep"],
201            "linux_x86_64": ["linux_intel_dep"],
202        },
203        data_exclude = [],
204        tags = ["tag1", "tag2"],
205        # Overrides for testing
206        filegroups = {},
207        native = struct(
208            filegroup = lambda **kwargs: filegroup_calls.append(kwargs),
209            config_setting = lambda **_: None,
210            glob = _glob,
211            select = _select,
212        ),
213        rules = struct(
214            py_library = lambda **kwargs: py_library_calls.append(kwargs),
215        ),
216    )
217
218    env.expect.that_collection(filegroup_calls).contains_exactly([
219        {
220            "name": "whl",
221            "srcs": ["foo.whl"],
222            "data": [
223                "@pypi_bar_baz//:whl",
224                "@pypi_foo//:whl",
225            ] + _select(
226                {
227                    Label("//python/config_settings:is_python_3.9"): ["@pypi_py39_dep//:whl"],
228                    "@platforms//cpu:aarch64": ["@pypi_arm_dep//:whl"],
229                    "@platforms//os:windows": ["@pypi_win_dep//:whl"],
230                    ":is_python_3.10_linux_ppc": ["@pypi_py310_linux_ppc_dep//:whl"],
231                    ":is_python_3.9_anyos_aarch64": ["@pypi_py39_arm_dep//:whl"],
232                    ":is_python_3.9_linux_anyarch": ["@pypi_py39_linux_dep//:whl"],
233                    ":is_linux_x86_64": ["@pypi_linux_intel_dep//:whl"],
234                    "//conditions:default": [],
235                },
236            ),
237            "visibility": ["//visibility:public"],
238        },
239    ])  # buildifier: @unsorted-dict-items
240    env.expect.that_collection(py_library_calls).contains_exactly([
241        {
242            "name": "pkg",
243            "srcs": _glob(
244                ["site-packages/**/*.py"],
245                exclude = [],
246                allow_empty = True,
247            ),
248            "data": [] + _glob(
249                ["site-packages/**/*"],
250                exclude = [
251                    "**/*.py",
252                    "**/*.pyc",
253                    "**/*.pyc.*",
254                    "**/*.dist-info/RECORD",
255                ] + glob_excludes.version_dependent_exclusions(),
256            ),
257            "imports": ["site-packages"],
258            "deps": [
259                "@pypi_bar_baz//:pkg",
260                "@pypi_foo//:pkg",
261            ] + _select(
262                {
263                    Label("//python/config_settings:is_python_3.9"): ["@pypi_py39_dep//:pkg"],
264                    "@platforms//cpu:aarch64": ["@pypi_arm_dep//:pkg"],
265                    "@platforms//os:windows": ["@pypi_win_dep//:pkg"],
266                    ":is_python_3.10_linux_ppc": ["@pypi_py310_linux_ppc_dep//:pkg"],
267                    ":is_python_3.9_anyos_aarch64": ["@pypi_py39_arm_dep//:pkg"],
268                    ":is_python_3.9_linux_anyarch": ["@pypi_py39_linux_dep//:pkg"],
269                    ":is_linux_x86_64": ["@pypi_linux_intel_dep//:pkg"],
270                    "//conditions:default": [],
271                },
272            ),
273            "tags": ["tag1", "tag2"],
274            "visibility": ["//visibility:public"],
275        },
276    ])  # buildifier: @unsorted-dict-items
277
278_tests.append(_test_whl_and_library_deps)
279
280def _test_group(env):
281    alias_calls = []
282    py_library_calls = []
283
284    whl_library_targets(
285        name = "foo.whl",
286        dep_template = "@pypi_{name}//:{target}",
287        dependencies = ["foo", "bar-baz", "qux"],
288        dependencies_by_platform = {
289            "linux_x86_64": ["box", "box-amd64"],
290            "windows_x86_64": ["fox"],
291            "@platforms//os:linux": ["box"],  # buildifier: disable=unsorted-dict-items to check that we sort inside the test
292        },
293        tags = [],
294        entry_points = {},
295        data_exclude = [],
296        group_name = "qux",
297        group_deps = ["foo", "fox", "qux"],
298        # Overrides for testing
299        filegroups = {},
300        native = struct(
301            config_setting = lambda **_: None,
302            glob = _glob,
303            alias = lambda **kwargs: alias_calls.append(kwargs),
304            select = _select,
305        ),
306        rules = struct(
307            py_library = lambda **kwargs: py_library_calls.append(kwargs),
308        ),
309    )
310
311    env.expect.that_collection(alias_calls).contains_exactly([
312        {"name": "pkg", "actual": "@pypi__groups//:qux_pkg", "visibility": ["//visibility:public"]},
313        {"name": "whl", "actual": "@pypi__groups//:qux_whl", "visibility": ["//visibility:public"]},
314    ])  # buildifier: @unsorted-dict-items
315    env.expect.that_collection(py_library_calls).contains_exactly([
316        {
317            "name": "_pkg",
318            "srcs": _glob(["site-packages/**/*.py"], exclude = [], allow_empty = True),
319            "data": [] + _glob(
320                ["site-packages/**/*"],
321                exclude = [
322                    "**/*.py",
323                    "**/*.pyc",
324                    "**/*.pyc.*",
325                    "**/*.dist-info/RECORD",
326                ] + glob_excludes.version_dependent_exclusions(),
327            ),
328            "imports": ["site-packages"],
329            "deps": ["@pypi_bar_baz//:pkg"] + _select({
330                "@platforms//os:linux": ["@pypi_box//:pkg"],
331                ":is_linux_x86_64": ["@pypi_box//:pkg", "@pypi_box_amd64//:pkg"],
332                "//conditions:default": [],
333            }),
334            "tags": [],
335            "visibility": ["@pypi__groups//:__pkg__"],
336        },
337    ])  # buildifier: @unsorted-dict-items
338
339_tests.append(_test_group)
340
341def _glob(*args, **kwargs):
342    return [struct(
343        glob = args,
344        kwargs = kwargs,
345    )]
346
347def _select(*args, **kwargs):
348    """We need to have this mock select because we still need to support bazel 6."""
349    return [struct(
350        select = args,
351        kwargs = kwargs,
352    )]
353
354def whl_library_targets_test_suite(name):
355    """create the test suite.
356
357    args:
358        name: the name of the test suite
359    """
360    test_suite(name = name, basic_tests = _tests)
361