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"""Helpers for running bazel-in-bazel integration tests.""" 15 16load("@bazel_binaries//:defs.bzl", "bazel_binaries") 17load( 18 "@rules_bazel_integration_test//bazel_integration_test:defs.bzl", 19 "bazel_integration_test", 20 "integration_test_utils", 21) 22load("//python:py_test.bzl", "py_test") 23 24def _test_runner(*, name, bazel_version, py_main, bzlmod, gazelle_plugin): 25 if py_main: 26 test_runner = "{}_bazel_{}_py_runner".format(name, bazel_version) 27 py_test( 28 name = test_runner, 29 srcs = [py_main], 30 main = py_main, 31 deps = [":runner_lib"], 32 # Hide from ... patterns; should only be run as part 33 # of the bazel integration test 34 tags = ["manual"], 35 ) 36 return test_runner 37 38 if bazel_version.startswith("6") and not bzlmod: 39 if gazelle_plugin: 40 return "//tests/integration:bazel_6_4_workspace_test_runner_gazelle_plugin" 41 else: 42 return "//tests/integration:bazel_6_4_workspace_test_runner" 43 44 if bzlmod and gazelle_plugin: 45 return "//tests/integration:test_runner_gazelle_plugin" 46 elif bzlmod: 47 return "//tests/integration:test_runner" 48 elif gazelle_plugin: 49 return "//tests/integration:workspace_test_runner_gazelle_plugin" 50 else: 51 return "//tests/integration:workspace_test_runner" 52 53def rules_python_integration_test( 54 name, 55 workspace_path = None, 56 bzlmod = True, 57 gazelle_plugin = False, 58 tags = None, 59 py_main = None, 60 bazel_versions = None, 61 **kwargs): 62 """Runs a bazel-in-bazel integration test. 63 64 Args: 65 name: Name of the test. This gets appended by the bazel version. 66 workspace_path: The directory name. Defaults to `name` without the 67 `_test` suffix. 68 bzlmod: bool, default True. If true, run with bzlmod enabled, otherwise 69 disable bzlmod. 70 gazelle_plugin: Whether the test uses the gazelle plugin. 71 tags: Test tags. 72 py_main: Optional `.py` file to run tests using. When specified, a 73 python based test runner is used, and this source file is the main 74 entry point and responsible for executing tests. 75 bazel_versions: `list[str] | None`, the bazel versions to test. I 76 not specified, defaults to all configured bazel versions. 77 **kwargs: Passed to the upstream `bazel_integration_tests` rule. 78 """ 79 workspace_path = workspace_path or name.removesuffix("_test") 80 81 # Because glob expansion happens at loading time, the bazel-* symlinks 82 # in the workspaces can recursively expand to tens-of-thousands of entries, 83 # which consumes lots of CPU and RAM and can render the system unusable. 84 # To help prevent that, cap the size of the glob expansion. 85 workspace_files = integration_test_utils.glob_workspace_files(workspace_path) 86 if len(workspace_files) > 1000: 87 fail("Workspace {} has too many files. This likely means a bazel-* " + 88 "symlink is being followed when it should be ignored.") 89 90 # bazel_integration_tests creates a separate file group target of the workspace 91 # files for each bazel version, even though the file groups are the same 92 # for each one. 93 # To avoid that, manually create a single filegroup once and re-use it. 94 native.filegroup( 95 name = name + "_workspace_files", 96 srcs = workspace_files + [ 97 "//:distribution", 98 ], 99 ) 100 kwargs.setdefault("size", "enormous") 101 for bazel_version in bazel_versions or bazel_binaries.versions.all: 102 test_runner = _test_runner( 103 name = name, 104 bazel_version = bazel_version, 105 py_main = py_main, 106 bzlmod = bzlmod, 107 gazelle_plugin = gazelle_plugin, 108 ) 109 bazel_integration_test( 110 name = "{}_bazel_{}".format(name, bazel_version), 111 workspace_path = workspace_path, 112 test_runner = test_runner, 113 bazel_version = bazel_version, 114 workspace_files = [name + "_workspace_files"], 115 # Override the tags so that the `manual` tag isn't applied. 116 tags = (tags or []) + [ 117 # These tests are very heavy weight, so much so that only a couple 118 # can be run in parallel without harming their reliability, 119 # overall runtime, and the system's stability. Unfortunately, 120 # there doesn't appear to be a way to tell Bazel to limit their 121 # concurrency, only disable it entirely with exclusive. 122 "exclusive", 123 # The default_test_runner() assumes it can write to the user's home 124 # directory for caching purposes. Give it access. 125 "no-sandbox", 126 # The CI RBE setup can't successfully run these tests remotely. 127 "no-remote-exec", 128 # A special tag is used so CI can run them as a separate job. 129 "integration-test", 130 ], 131 **kwargs 132 ) 133