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"Define a rule for running bazel test under Bazel" 16 17load("//:version.bzl", "SUPPORTED_BAZEL_VERSIONS", "bazel_version_to_binary_label") 18load("//python:defs.bzl", "py_test") 19 20BAZEL_BINARY = bazel_version_to_binary_label(SUPPORTED_BAZEL_VERSIONS[0]) 21 22_ATTRS = { 23 "bazel_binary": attr.label( 24 default = BAZEL_BINARY, 25 doc = """The bazel binary files to test against. 26 27It is assumed by the test runner that the bazel binary is found at label_workspace/bazel (wksp/bazel.exe on Windows)""", 28 ), 29 "bazel_commands": attr.string_list( 30 default = ["info", "test --test_output=errors ..."], 31 doc = """The list of bazel commands to run. 32 33Note that if a command contains a bare `--` argument, the --test_arg passed to Bazel will appear before it. 34""", 35 ), 36 "bzlmod": attr.bool( 37 default = False, 38 doc = """Whether the test uses bzlmod.""", 39 ), 40 "workspace_files": attr.label( 41 doc = """A filegroup of all files in the workspace-under-test necessary to run the test.""", 42 ), 43} 44 45def _config_impl(ctx): 46 if len(SUPPORTED_BAZEL_VERSIONS) > 1: 47 fail(""" 48 bazel_integration_test doesn't support multiple Bazel versions to test against yet. 49 """) 50 if len(ctx.files.workspace_files) == 0: 51 fail(""" 52No files were found to run under integration testing. See comment in /.bazelrc. 53You probably need to run 54 tools/bazel_integration_test/update_deleted_packages.sh 55""") 56 57 # Serialize configuration file for test runner 58 config = ctx.actions.declare_file("%s.json" % ctx.attr.name) 59 ctx.actions.write( 60 output = config, 61 content = """ 62{{ 63 "workspaceRoot": "{TMPL_workspace_root}", 64 "bazelBinaryWorkspace": "{TMPL_bazel_binary_workspace}", 65 "bazelCommands": [ {TMPL_bazel_commands} ], 66 "bzlmod": {TMPL_bzlmod} 67}} 68""".format( 69 TMPL_workspace_root = ctx.files.workspace_files[0].dirname, 70 TMPL_bazel_binary_workspace = ctx.attr.bazel_binary.label.workspace_name, 71 TMPL_bazel_commands = ", ".join(["\"%s\"" % s for s in ctx.attr.bazel_commands]), 72 TMPL_bzlmod = str(ctx.attr.bzlmod).lower(), 73 ), 74 ) 75 76 return [DefaultInfo( 77 files = depset([config]), 78 runfiles = ctx.runfiles(files = [config]), 79 )] 80 81_config = rule( 82 implementation = _config_impl, 83 doc = "Configures an integration test that runs a specified version of bazel against an external workspace.", 84 attrs = _ATTRS, 85) 86 87def bazel_integration_test(name, override_bazel_version = None, bzlmod = False, dirname = None, **kwargs): 88 """Wrapper macro to set default srcs and run a py_test with config 89 90 Args: 91 name: name of the resulting py_test 92 override_bazel_version: bazel version to use in test 93 bzlmod: whether the test uses bzlmod 94 dirname: the directory name of the test. Defaults to value of `name` after trimming the `_example` suffix. 95 **kwargs: additional attributes like timeout and visibility 96 """ 97 98 # By default, we assume sources for "pip_example" are in examples/pip/**/* 99 dirname = dirname or name[:-len("_example")] 100 native.filegroup( 101 name = "_%s_sources" % name, 102 srcs = native.glob( 103 ["%s/**/*" % dirname], 104 exclude = ["%s/bazel-*/**" % dirname], 105 ), 106 ) 107 workspace_files = kwargs.pop("workspace_files", "_%s_sources" % name) 108 109 bazel_binary = BAZEL_BINARY if not override_bazel_version else bazel_version_to_binary_label(override_bazel_version) 110 _config( 111 name = "_%s_config" % name, 112 workspace_files = workspace_files, 113 bazel_binary = bazel_binary, 114 bzlmod = bzlmod, 115 ) 116 117 tags = kwargs.pop("tags", []) 118 tags.append("integration-test") 119 120 py_test( 121 name = name, 122 srcs = [Label("//tools/bazel_integration_test:test_runner.py")], 123 main = "test_runner.py", 124 args = [native.package_name() + "/_%s_config.json" % name], 125 deps = [Label("//python/runfiles")], 126 data = [ 127 bazel_binary, 128 "//:distribution", 129 "_%s_config" % name, 130 workspace_files, 131 ], 132 tags = tags, 133 **kwargs 134 ) 135