• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2022 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"""This module contains the definition for the toolchains testing rules.
16"""
17
18load("//python:versions.bzl", "PLATFORMS", "TOOL_VERSIONS")
19
20_WINDOWS_RUNNER_TEMPLATE = """\
21@ECHO OFF
22set PATHEXT=.COM;.EXE;.BAT
23powershell.exe -c "& ./{interpreter_path} {run_acceptance_test_py}"
24"""
25
26def _acceptance_test_impl(ctx):
27    workspace = ctx.actions.declare_file("/".join([ctx.attr.python_version, "WORKSPACE"]))
28    ctx.actions.expand_template(
29        template = ctx.file._workspace_tmpl,
30        output = workspace,
31        substitutions = {"%python_version%": ctx.attr.python_version},
32    )
33
34    build_bazel = ctx.actions.declare_file("/".join([ctx.attr.python_version, "BUILD.bazel"]))
35    ctx.actions.expand_template(
36        template = ctx.file._build_bazel_tmpl,
37        output = build_bazel,
38        substitutions = {"%python_version%": ctx.attr.python_version},
39    )
40
41    python_version_test = ctx.actions.declare_file("/".join([ctx.attr.python_version, "python_version_test.py"]))
42    ctx.actions.symlink(
43        target_file = ctx.file._python_version_test,
44        output = python_version_test,
45    )
46
47    run_acceptance_test_py = ctx.actions.declare_file("/".join([ctx.attr.python_version, "run_acceptance_test.py"]))
48    ctx.actions.expand_template(
49        template = ctx.file._run_acceptance_test_tmpl,
50        output = run_acceptance_test_py,
51        substitutions = {
52            "%is_windows%": str(ctx.attr.is_windows),
53            "%python_version%": ctx.attr.python_version,
54            "%test_location%": "/".join([ctx.attr.test_location, ctx.attr.python_version]),
55        },
56    )
57
58    toolchain = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"]
59    py3_runtime = toolchain.py3_runtime
60    interpreter_path = py3_runtime.interpreter_path
61    if not interpreter_path:
62        interpreter_path = py3_runtime.interpreter.short_path
63
64    if ctx.attr.is_windows:
65        executable = ctx.actions.declare_file("run_test_{}.bat".format(ctx.attr.python_version))
66        ctx.actions.write(
67            output = executable,
68            content = _WINDOWS_RUNNER_TEMPLATE.format(
69                interpreter_path = interpreter_path.replace("../", "external/"),
70                run_acceptance_test_py = run_acceptance_test_py.short_path,
71            ),
72            is_executable = True,
73        )
74    else:
75        executable = ctx.actions.declare_file("run_test_{}.sh".format(ctx.attr.python_version))
76        ctx.actions.write(
77            output = executable,
78            content = "exec '{interpreter_path}' '{run_acceptance_test_py}'".format(
79                interpreter_path = interpreter_path,
80                run_acceptance_test_py = run_acceptance_test_py.short_path,
81            ),
82            is_executable = True,
83        )
84
85    files = [
86        build_bazel,
87        executable,
88        python_version_test,
89        run_acceptance_test_py,
90        workspace,
91    ] + ctx.files._distribution
92    return [DefaultInfo(
93        executable = executable,
94        files = depset(
95            direct = files,
96            transitive = [py3_runtime.files],
97        ),
98        runfiles = ctx.runfiles(
99            files = files,
100            transitive_files = py3_runtime.files,
101        ),
102    )]
103
104_acceptance_test = rule(
105    implementation = _acceptance_test_impl,
106    doc = "A rule for the toolchain acceptance tests.",
107    attrs = {
108        "is_windows": attr.bool(
109            doc = "(Provided by the macro) Whether this is running under Windows or not.",
110            mandatory = True,
111        ),
112        "python_version": attr.string(
113            doc = "The Python version to be used when requesting the toolchain.",
114            mandatory = True,
115        ),
116        "test_location": attr.string(
117            doc = "(Provided by the macro) The value of native.package_name().",
118            mandatory = True,
119        ),
120        "_build_bazel_tmpl": attr.label(
121            doc = "The BUILD.bazel template.",
122            allow_single_file = True,
123            default = Label("//python/tests/toolchains/workspace_template:BUILD.bazel.tmpl"),
124        ),
125        "_distribution": attr.label(
126            doc = "The rules_python source distribution.",
127            default = Label("//:distribution"),
128        ),
129        "_python_version_test": attr.label(
130            doc = "The python_version_test.py used to test the Python version.",
131            allow_single_file = True,
132            default = Label("//python/tests/toolchains/workspace_template:python_version_test.py"),
133        ),
134        "_run_acceptance_test_tmpl": attr.label(
135            doc = "The run_acceptance_test.py template.",
136            allow_single_file = True,
137            default = Label("//python/tests/toolchains:run_acceptance_test.py.tmpl"),
138        ),
139        "_workspace_tmpl": attr.label(
140            doc = "The WORKSPACE template.",
141            allow_single_file = True,
142            default = Label("//python/tests/toolchains/workspace_template:WORKSPACE.tmpl"),
143        ),
144    },
145    test = True,
146    toolchains = ["@bazel_tools//tools/python:toolchain_type"],
147)
148
149def acceptance_test(python_version, **kwargs):
150    _acceptance_test(
151        is_windows = select({
152            "@bazel_tools//src/conditions:host_windows": True,
153            "//conditions:default": False,
154        }),
155        python_version = python_version,
156        test_location = native.package_name(),
157        **kwargs
158    )
159
160# buildifier: disable=unnamed-macro
161def acceptance_tests():
162    """Creates a matrix of acceptance_test targets for all the toolchains.
163    """
164    for python_version in TOOL_VERSIONS.keys():
165        for platform, meta in PLATFORMS.items():
166            if platform not in TOOL_VERSIONS[python_version]["sha256"]:
167                continue
168            acceptance_test(
169                name = "python_{python_version}_{platform}_test".format(
170                    python_version = python_version.replace(".", "_"),
171                    platform = platform,
172                ),
173                python_version = python_version,
174                target_compatible_with = meta.compatible_with,
175                tags = ["acceptance-test"],
176            )
177