aboutsummaryrefslogtreecommitdiff
path: root/tools/bazel_integration_test/bazel_integration_test.bzl
blob: c0165513199b0e04e5a5aaf6efbac635deb7d725 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# Copyright 2023 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"Define a rule for running bazel test under Bazel"

load("//:version.bzl", "SUPPORTED_BAZEL_VERSIONS", "bazel_version_to_binary_label")
load("//python:defs.bzl", "py_test")

BAZEL_BINARY = bazel_version_to_binary_label(SUPPORTED_BAZEL_VERSIONS[0])

_ATTRS = {
    "bazel_binary": attr.label(
        default = BAZEL_BINARY,
        doc = """The bazel binary files to test against.

It is assumed by the test runner that the bazel binary is found at label_workspace/bazel (wksp/bazel.exe on Windows)""",
    ),
    "bazel_commands": attr.string_list(
        default = ["info", "test --test_output=errors ..."],
        doc = """The list of bazel commands to run.

Note that if a command contains a bare `--` argument, the --test_arg passed to Bazel will appear before it.
""",
    ),
    "bzlmod": attr.bool(
        default = False,
        doc = """Whether the test uses bzlmod.""",
    ),
    "workspace_files": attr.label(
        doc = """A filegroup of all files in the workspace-under-test necessary to run the test.""",
    ),
}

def _config_impl(ctx):
    if len(SUPPORTED_BAZEL_VERSIONS) > 1:
        fail("""
        bazel_integration_test doesn't support multiple Bazel versions to test against yet.
        """)
    if len(ctx.files.workspace_files) == 0:
        fail("""
No files were found to run under integration testing. See comment in /.bazelrc.
You probably need to run 
    tools/bazel_integration_test/update_deleted_packages.sh
""")

    # Serialize configuration file for test runner
    config = ctx.actions.declare_file("%s.json" % ctx.attr.name)
    ctx.actions.write(
        output = config,
        content = """
{{
    "workspaceRoot": "{TMPL_workspace_root}",
    "bazelBinaryWorkspace": "{TMPL_bazel_binary_workspace}",
    "bazelCommands": [ {TMPL_bazel_commands} ],
    "bzlmod": {TMPL_bzlmod}
}}
""".format(
            TMPL_workspace_root = ctx.files.workspace_files[0].dirname,
            TMPL_bazel_binary_workspace = ctx.attr.bazel_binary.label.workspace_name,
            TMPL_bazel_commands = ", ".join(["\"%s\"" % s for s in ctx.attr.bazel_commands]),
            TMPL_bzlmod = str(ctx.attr.bzlmod).lower(),
        ),
    )

    return [DefaultInfo(
        files = depset([config]),
        runfiles = ctx.runfiles(files = [config]),
    )]

_config = rule(
    implementation = _config_impl,
    doc = "Configures an integration test that runs a specified version of bazel against an external workspace.",
    attrs = _ATTRS,
)

def bazel_integration_test(name, override_bazel_version = None, bzlmod = False, dirname = None, **kwargs):
    """Wrapper macro to set default srcs and run a py_test with config

    Args:
        name: name of the resulting py_test
        override_bazel_version: bazel version to use in test
        bzlmod: whether the test uses bzlmod
        dirname: the directory name of the test. Defaults to value of `name` after trimming the `_example` suffix.
        **kwargs: additional attributes like timeout and visibility
    """

    # By default, we assume sources for "pip_example" are in examples/pip/**/*
    dirname = dirname or name[:-len("_example")]
    native.filegroup(
        name = "_%s_sources" % name,
        srcs = native.glob(
            ["%s/**/*" % dirname],
            exclude = ["%s/bazel-*/**" % dirname],
        ),
    )
    workspace_files = kwargs.pop("workspace_files", "_%s_sources" % name)

    bazel_binary = BAZEL_BINARY if not override_bazel_version else bazel_version_to_binary_label(override_bazel_version)
    _config(
        name = "_%s_config" % name,
        workspace_files = workspace_files,
        bazel_binary = bazel_binary,
        bzlmod = bzlmod,
    )

    tags = kwargs.pop("tags", [])
    tags.append("integration-test")

    py_test(
        name = name,
        srcs = [Label("//tools/bazel_integration_test:test_runner.py")],
        main = "test_runner.py",
        args = [native.package_name() + "/_%s_config.json" % name],
        deps = [Label("//python/runfiles")],
        data = [
            bazel_binary,
            "//:distribution",
            "_%s_config" % name,
            workspace_files,
        ],
        tags = tags,
        **kwargs
    )