blob: 9ed19e9045cbcdbb18604631e0045cd690a5a47c [file] [log] [blame]
"""This module defines a custom go_test macro that produces separate targets for manual tests."""
load("@io_bazel_rules_go//go:def.bzl", _go_test = "go_test")
def go_test(name, srcs, tags = [], args = [], **kwargs):
"""Wrapper around go_test that splits manual and non-manual tests into separate targets.
The purpose of this macro is to automatically create separate test targets for non-manual and
manual Go tests. The latter will be tagged as manual in order to exclude them from wildcard
queries such as "bazel test ...". It assumes that any manual test cases are placed in Go files
ending with "_manual_test.go", and that each such test case calls unittest.ManualTest().
In addition, this macro customizes some go_test arguments with better defaults.
This macro is not intended to be used directly. It is designed to be used with the
gazelle:map_kind directive, which customizes the kinds of rules generated by Gazelle. In
particular, it can be used to replace the default go_test rule (defined in the rules_go
repository) with this macro. See https://github.com/bazelbuild/bazel-gazelle#directives.
Suppose this macro is invoked with name = "example_test", and that the srcs attribute contains a
combination of non-manual and manual test cases:
```
# Macro invocation.
go_test(
name = "example_test",
srcs = [
"foo_test.go",
"bar_test.go",
"baz_test.go",
"delta_manual_test.go",
"omega_manual_test.go",
],
...
)
```
The above macro invocation will result in two rules_go's go_test targets, one named
"example_test" containing the non-manual tests (*_test.go), and one named "example_manual_test"
containing both the non-manual and manual tests (*_test.go and *_manual_test.go):
```
# Resulting rules_go's go_test targets:
go_test(
name = "example_test",
srcs = [
"foo_test.go",
"bar_test.go",
"baz_test.go",
],
...
)
go_test(
name = "example_manual_test",
srcs = [
"foo_test.go",
"bar_test.go",
"baz_test.go",
"delta_manual_test.go",
"omega_manual_test.go",
],
tags = ["manual"], # Exclude from Bazel wildcards, e.g. "bazel test ...".
args = ["--manual"], # Only run test cases that call unittest.ManualTest().
...
)
```
The reason why example_manual_test includes the non-manual tests as well is because they might
define auxiliary functions, test data, etc. shared between all tests, including the manual ones.
However, non-manual tests are excluded by passing the --manual flag to the test binary, which
skips any test cases that do not call unittest.ManualTest().
If this macro is invoked without any files ending with "_manual_test.go", it behaves exactly
like the default go_test rule from the rules_go repository.
Args:
name: Base name of the target(s) to generate.
srcs: Any *_test.go files.
tags: Any tags for the resulting go_test targets.
args: Any command-line arguments to pass to the test binaries of both go_test targets.
**kwargs: Any other arguments to pass to the resulting go_test targets.
"""
# Gazelle only includes files ending with _test.go in the srcs attribute of go_test targets.
# In order to prevent bugs, we fail loudly if this ceases to be true for any reason.
for src in srcs:
if not src.endswith("_test.go"):
fail("go_test called with a src file that does not end with \"_test.go\".")
# Make tests verbose by default. This improves error reporting in Infra-PerCommit-Test-Bazel-*
# for tests that time out, which by default fail silently without any indication of which test
# case caused the timeout.
#
# Note that Bazel omits the output of successful tests. This does not add noise to the logs.
args = args + ["--test.v"] # Equivalent to "go test [target] -v".
non_manual_test_srcs = [src for src in srcs if not src.endswith("_manual_test.go")]
# Generate the base go_test target, excluding any *_manual_test.go files.
_go_test(name = name, srcs = non_manual_test_srcs, tags = tags, args = args, **kwargs)
# Only generate the target for manual tests if there is at least one *_manual_test.go file.
if len(srcs) != len(non_manual_test_srcs):
_go_test(
name = name[:-4] + "manual_test", # Turn e.g. foo_test into foo_manual_test.
# Include *_manual_test.go and *_test.go sources as well, because the latter might
# contain functions, test data, etc. shared between the manual and non-manual tests.
# However, non-manual tests will not be executed because we pass the --manual flag to
# the test binary.
srcs = srcs,
tags = tags + ["manual"], # Exclude from Bazel wildcards, e.g. "bazel test ...".
args = args + ["--manual"], # Only run test cases that call unittest.ManualTest().
**kwargs
)