xref: /aosp_15_r20/external/grpc-grpc/tools/bazelify_tests/build_defs.bzl (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1# Copyright 2023 The gRPC Authors
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"""
16Contains macros used for running bazelified tests.
17"""
18
19load(":dockerimage_current_versions.bzl", "DOCKERIMAGE_CURRENT_VERSIONS")
20load("@bazel_toolchains//rules/exec_properties:exec_properties.bzl", "create_rbe_exec_properties_dict")
21
22def _dockerized_sh_test(name, srcs = [], args = [], data = [], size = "medium", timeout = None, tags = [], exec_compatible_with = [], flaky = None, docker_image_version = None, docker_run_as_root = False, env = {}):
23    """Runs sh_test under docker either via RBE or via docker sandbox."""
24    if docker_image_version:
25        image_spec = DOCKERIMAGE_CURRENT_VERSIONS.get(docker_image_version, None)
26        if not image_spec:
27            fail("Version info for docker image '%s' not found in dockerimage_current_versions.bzl" % docker_image_version)
28    else:
29        fail("docker_image_version attribute not set for dockerized test '%s'" % name)
30
31    exec_properties = create_rbe_exec_properties_dict(
32        labels = {
33            "workload": "misc",
34            "machine_size": "misc_large",
35        },
36        docker_network = "standard",
37        container_image = image_spec,
38        # TODO(jtattermusch): note that docker sandbox doesn't currently support "docker_run_as_root"
39        docker_run_as_root = docker_run_as_root,
40    )
41
42    # since the tests require special bazel args, only run them when explicitly requested
43    tags = ["manual"] + tags
44
45    # TODO(jtattermusch): find a way to ensure that action can only run under docker sandbox or remotely
46    # to avoid running it outside of a docker container by accident.
47
48    test_args = {
49        "name": name,
50        "srcs": srcs,
51        "tags": tags,
52        "args": args,
53        "flaky": flaky,
54        "data": data,
55        "size": size,
56        "env": env,
57        "timeout": timeout,
58        "exec_compatible_with": exec_compatible_with,
59        "exec_properties": exec_properties,
60    }
61
62    native.sh_test(
63        **test_args
64    )
65
66def _dockerized_genrule(name, cmd, outs, srcs = [], tags = [], exec_compatible_with = [], docker_image_version = None, docker_run_as_root = False):
67    """Runs genrule under docker either via RBE or via docker sandbox."""
68    if docker_image_version:
69        image_spec = DOCKERIMAGE_CURRENT_VERSIONS.get(docker_image_version, None)
70        if not image_spec:
71            fail("Version info for docker image '%s' not found in dockerimage_current_versions.bzl" % docker_image_version)
72    else:
73        fail("docker_image_version attribute not set for dockerized test '%s'" % name)
74
75    exec_properties = create_rbe_exec_properties_dict(
76        labels = {
77            "workload": "misc",
78            "machine_size": "misc_large",
79        },
80        docker_network = "standard",
81        container_image = image_spec,
82        # TODO(jtattermusch): note that docker sandbox doesn't currently support "docker_run_as_root"
83        docker_run_as_root = docker_run_as_root,
84    )
85
86    # since the tests require special bazel args, only run them when explicitly requested
87    tags = ["manual"] + tags
88
89    # TODO(jtattermusch): find a way to ensure that action can only run under docker sandbox or remotely
90    # to avoid running it outside of a docker container by accident.
91
92    genrule_args = {
93        "name": name,
94        "cmd": cmd,
95        "srcs": srcs,
96        "tags": tags,
97        "exec_compatible_with": exec_compatible_with,
98        "exec_properties": exec_properties,
99        "outs": outs,
100    }
101
102    native.genrule(
103        **genrule_args
104    )
105
106def grpc_run_tests_harness_test(name, args = [], data = [], size = "medium", timeout = None, tags = [], exec_compatible_with = [], flaky = None, docker_image_version = None, use_login_shell = None, prepare_script = None):
107    """Execute an run_tests.py-harness style test under bazel.
108
109    Args:
110        name: The name of the test.
111        args: The args to supply to the test binary.
112        data: Data dependencies.
113        size: The size of the test.
114        timeout: The test timeout.
115        tags: The tags for the test.
116        exec_compatible_with: A list of constraint values that must be
117            satisifed for the platform.
118        flaky: Whether this test is flaky.
119        docker_image_version: The docker .current_version file to use for docker containerization.
120        use_login_shell: If True, the run_tests.py command will run under a login shell.
121        prepare_script: Optional script that will be sourced before run_tests.py runs.
122    """
123
124    data = [
125        "//tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz",
126    ] + data
127
128    args = [
129        "$(location //tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz)",
130    ] + args
131
132    srcs = [
133        "//tools/bazelify_tests:grpc_run_tests_harness_test.sh",
134    ]
135
136    env = {}
137
138    if use_login_shell:
139        env["GRPC_RUNTESTS_USE_LOGIN_SHELL"] = "1"
140
141    if prepare_script:
142        data = data + [prepare_script]
143        env["GRPC_RUNTESTS_PREPARE_SCRIPT"] = "$(location " + prepare_script + ")"
144
145    # Enable ccache by default. This is important for speeding up the C++ cmake build,
146    # which isn't very efficient and tends to recompile some source files multiple times.
147    # Even though only the local disk cache is enabled (local to the docker container,
148    # so will be thrown away after the bazel actions finishes), ccache still speeds up
149    # the C++ build significantly.
150    # TODO(jtattermusch): find a cleaner way to toggle ccache for builds.
151    env["GRPC_BUILD_ENABLE_CCACHE"] = "true"
152
153    _dockerized_sh_test(name = name, srcs = srcs, args = args, data = data, size = size, timeout = timeout, tags = tags, exec_compatible_with = exec_compatible_with, flaky = flaky, docker_image_version = docker_image_version, env = env)
154
155def grpc_run_bazel_distribtest_test(name, args = [], data = [], size = "medium", timeout = None, tags = [], exec_compatible_with = [], flaky = None, docker_image_version = None):
156    """Execute bazel distribtest under bazel (an entire bazel build/test will run in a container as a single bazel action)
157
158    Args:
159        name: The name of the test.
160        args: The args to supply to the test binary.
161        data: Data dependencies.
162        size: The size of the test.
163        timeout: The test timeout.
164        tags: The tags for the test.
165        exec_compatible_with: A list of constraint values that must be
166            satisifed for the platform.
167        flaky: Whether this test is flaky.
168        docker_image_version: The docker .current_version file to use for docker containerization.
169    """
170
171    data = [
172        "//tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz",
173    ] + data
174
175    args = [
176        "$(location //tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz)",
177    ] + args
178
179    srcs = [
180        "//tools/bazelify_tests:grpc_run_bazel_distribtest_test.sh",
181    ]
182    env = {}
183    _dockerized_sh_test(name = name, srcs = srcs, args = args, data = data, size = size, timeout = timeout, tags = tags, exec_compatible_with = exec_compatible_with, flaky = flaky, docker_image_version = docker_image_version, env = env)
184
185def grpc_run_cpp_distribtest_test(name, args = [], data = [], size = "medium", timeout = None, tags = [], exec_compatible_with = [], flaky = None, docker_image_version = None):
186    """Execute an C++ distribtest under bazel.
187
188    Args:
189        name: The name of the test.
190        args: The args to supply to the test binary.
191        data: Data dependencies.
192        size: The size of the test.
193        timeout: The test timeout.
194        tags: The tags for the test.
195        exec_compatible_with: A list of constraint values that must be
196            satisifed for the platform.
197        flaky: Whether this test is flaky.
198        docker_image_version: The docker .current_version file to use for docker containerization.
199    """
200
201    data = [
202        "//tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz",
203    ] + data
204
205    args = [
206        "$(location //tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz)",
207    ] + args
208
209    srcs = [
210        "//tools/bazelify_tests:grpc_run_cpp_distribtest_test.sh",
211    ]
212
213    # TODO(jtattermusch): revisit running docker as root (but currently some distribtests need to install stuff inside the docker container)
214    env = {}
215    _dockerized_sh_test(name = name, srcs = srcs, args = args, data = data, size = size, timeout = timeout, tags = tags, exec_compatible_with = exec_compatible_with, flaky = flaky, docker_image_version = docker_image_version, env = env, docker_run_as_root = True)
216
217def grpc_run_simple_command_test(name, args = [], data = [], size = "medium", timeout = None, tags = [], exec_compatible_with = [], flaky = None, docker_image_version = None):
218    """Execute the specified test command under grpc workspace (and under a docker container)
219
220    Args:
221        name: The name of the test.
222        args: The command to run.
223        data: Data dependencies.
224        size: The size of the test.
225        timeout: The test timeout.
226        tags: The tags for the test.
227        exec_compatible_with: A list of constraint values that must be
228            satisifed for the platform.
229        flaky: Whether this test is flaky.
230        docker_image_version: The docker .current_version file to use for docker containerization.
231    """
232
233    data = [
234        "//tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz",
235    ] + data
236
237    args = [
238        "$(location //tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz)",
239    ] + args
240
241    srcs = [
242        "//tools/bazelify_tests:grpc_run_simple_command_test.sh",
243    ]
244
245    env = {}
246    _dockerized_sh_test(name = name, srcs = srcs, args = args, data = data, size = size, timeout = timeout, tags = tags, exec_compatible_with = exec_compatible_with, flaky = flaky, docker_image_version = docker_image_version, env = env, docker_run_as_root = False)
247
248def grpc_build_artifact_task(name, timeout = None, artifact_deps = [], tags = [], exec_compatible_with = [], flaky = None, docker_image_version = None, build_script = None):
249    """Execute a build artifact task and a corresponding 'build test'.
250
251    The artifact is built by a genrule that always succeeds (Even if the underlying build fails)
252    and an sh_test (with "_build_test" suffix) that presents the result of the artifact build
253    in the result UI (by displaying the the build status, the log, and artifacts produced).
254    Such layout helps to easily build artifacts and run distribtests that depend on other artifacts,
255    while making the test results well structured and easy to interpret.
256
257    Args:
258        name: The name of the target.
259        timeout: The test timeout for the build.
260        artifact_deps: List of dependencies on artifacts built by another grpc_build_artifact_task.
261        tags: The tags for the target.
262        exec_compatible_with: A list of constraint values that must be
263            satisifed for the platform.
264        flaky: Whether this artifact build is flaky.
265        docker_image_version: The docker .current_version file to use for docker containerization.
266        build_script: The script that builds the aritfacts.
267    """
268
269    out_exitcode_file = str(name + "_exit_code")
270    out_build_log = str(name + "_build_log.txt")
271    out_archive_name = str(name + ".tar.gz")
272
273    genrule_outs = [
274        out_exitcode_file,
275        out_build_log,
276        out_archive_name,
277    ]
278
279    genrule_srcs = [
280        "//tools/bazelify_tests:grpc_build_artifact_task.sh",
281        "//tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz",
282        build_script,
283    ]
284
285    cmd = "$(location //tools/bazelify_tests:grpc_build_artifact_task.sh) $(location //tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz) $(location " + build_script + ") $(location " + out_exitcode_file + ") $(location " + out_build_log + ") $(location " + out_archive_name + ")"
286
287    # for each artifact task we depends on, use the correponding tar.gz as extra src and pass its location as an extra cmdline arg.
288    for dep in artifact_deps:
289        dep_archive_name = str(dep + ".tar.gz")
290        cmd = cmd + " $(location " + dep_archive_name + ")"
291        genrule_srcs.append(dep_archive_name)
292
293    _dockerized_genrule(name = name, cmd = cmd, outs = genrule_outs, srcs = genrule_srcs, tags = tags, exec_compatible_with = exec_compatible_with, docker_image_version = docker_image_version, docker_run_as_root = False)
294
295    # The genrule above always succeeds (even if the underlying build fails), so that we can create rules that depend
296    # on multiple artifact builds (of which some can fail). The actual build status (exitcode) and the log of the build
297    # will be reported by an associated sh_test (that gets displayed in the UI in a much nicer way than a genrule).
298    # Note that in bazel you cannot declare a test that has declared outputs and you also cannot make other rules
299    # depend on a test - which is the reason why we need a separate genrule to represent the build itself.
300    test_name = str(name + "_build_test")
301    test_srcs = [
302        "//tools/bazelify_tests:grpc_build_artifact_task_build_test.sh",
303    ]
304    test_data = [
305        out_exitcode_file,
306        out_build_log,
307        out_archive_name,
308    ]
309    test_env = {}
310    test_args = [
311        "$(location " + out_exitcode_file + ")",
312        "$(location " + out_build_log + ")",
313        "$(location " + out_archive_name + ")",
314    ]
315    _dockerized_sh_test(name = test_name, srcs = test_srcs, args = test_args, data = test_data, size = "small", tags = tags, exec_compatible_with = exec_compatible_with, flaky = flaky, docker_image_version = docker_image_version, env = test_env, docker_run_as_root = False)
316
317def grpc_run_distribtest_test(name, artifact_deps = [], size = "medium", timeout = None, tags = [], exec_compatible_with = [], flaky = None, docker_image_version = None, build_script = None, docker_run_as_root = False):
318    """Run a distribtest for a previously built artifact/package
319
320    Args:
321        name: The name of the test.
322        artifact_deps: List of dependencies on artifacts built by another grpc_build_artifact_task.
323        size: The size of the test.
324        timeout: The test timeout.
325        tags: The tags for the test.
326        exec_compatible_with: A list of constraint values that must be
327            satisifed for the platform.
328        flaky: Whether this test is flaky.
329        docker_image_version: The docker .current_version file to use for docker containerization.
330        build_script: The script that runs the test.
331        docker_run_as_root: If True, the test will run under docker as root.
332    """
333
334    data = [
335        "//tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz",
336        build_script,
337    ]
338
339    args = [
340        "$(location //tools/bazelify_tests:grpc_repo_archive_with_submodules.tar.gz)",
341        "$(location " + build_script + ")",
342    ]
343
344    # for each artifact task we depends on, use the correponding tar.gz as extra data item and pass its location as an extra arg.
345    for dep in artifact_deps:
346        dep_archive_name = str(dep + ".tar.gz")
347        args.append("$(location " + dep_archive_name + ")")
348        data.append(dep_archive_name)
349
350    srcs = [
351        "//tools/bazelify_tests:grpc_run_distribtest_test.sh",
352    ]
353
354    env = {}
355    _dockerized_sh_test(name = name, srcs = srcs, args = args, data = data, size = size, timeout = timeout, tags = tags, exec_compatible_with = exec_compatible_with, flaky = flaky, docker_image_version = docker_image_version, env = env, docker_run_as_root = docker_run_as_root)
356