Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(testing): testing utility for running the gazelle binary. #1183

Merged
5 changes: 5 additions & 0 deletions def.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,16 @@ load(
"//internal:gazelle_binary.bzl",
_gazelle_binary = "gazelle_binary_wrapper",
)
load(
"//internal/generationtest:generation_test.bzl",
_gazelle_generation_test = "gazelle_generation_test",
)

go_repository = _go_repository
git_repository = _git_repository
http_archive = _http_archive
gazelle_binary = _gazelle_binary
gazelle_generation_test = _gazelle_generation_test

DEFAULT_LANGUAGES = [
"@bazel_gazelle//language/proto:go_default_library",
Expand Down
42 changes: 42 additions & 0 deletions extend.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,48 @@ To extend Gazelle, you must do three things:
`bazel run //:gazelle`, your binary will be built and executed instead of
the default binary.

Tests
-----

To write tests for your gazelle extension, you can use `gazelle_generation_test`,
which will run a gazelle binary of your choosing on a set of test workspaces.

```starlark
load("@bazel_gazelle//:def.bzl", "gazelle_generation_test")

gazelle_generation_test(
name = "my_generation_test",
# The name of the gazelle binary target in your repo.
gazelle_binary_name = "gazelle_local",
# Optional, the workspace relative path to the gazelle binary.
# Defaults to the root of the workspace.
gazelle_binary_dir = "",
test_data = glob([
"testdata_full_gen_test/**",
]),
test_data_dir = "path/to/testdata_full_gen_test",
)
```

The generation test expects a file structure like the following.
```
|-- <testDataPath>
|-- some_test
|-- WORKSPACE
|-- README.md --> README describing what the test does.
|-- expectedStdout.txt --> Expected stdout for this test.
|-- expectedStderr.txt --> Expected stderr for this test.
|-- expectedExitCode.txt --> Expected exit code for this test.
|-- app
|-- sourceFile.foo
|-- BUILD.in --> BUILD file prior to running gazelle.
|-- BUILD.out --> BUILD file expected after running gazelle.
```

To run update your desired BUILD.out files, you can run:

`UPDATE_SNAPSHOTS=true bazel run //path/to:my_generation_test`.

Supported languages
-------------------

Expand Down
1 change: 1 addition & 0 deletions internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ filegroup(
"overlay_repository.bzl",
"repository_rules_test_errors.patch",
"//internal/gazellebinarytest:all_files",
"//internal/generationtest:all_files",
"//internal/language:all_files",
"//internal/version:all_files",
"//internal/wspace:all_files",
Expand Down
42 changes: 42 additions & 0 deletions internal/extend_docs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,48 @@ To extend Gazelle, you must do three things:
`bazel run //:gazelle`, your binary will be built and executed instead of
the default binary.

Tests
-----

To write tests for your gazelle extension, you can use `gazelle_generation_test`,
which will run a gazelle binary of your choosing on a set of test workspaces.

```starlark
load("@bazel_gazelle//:def.bzl", "gazelle_generation_test")

gazelle_generation_test(
name = "my_generation_test",
# The name of the gazelle binary target in your repo.
gazelle_binary_name = "gazelle_local",
aptenodytes-forsteri marked this conversation as resolved.
Show resolved Hide resolved
# Optional, the workspace relative path to the gazelle binary.
# Defaults to the root of the workspace.
gazelle_binary_dir = "",
test_data = glob([
"testdata_full_gen_test/**",
]),
test_data_dir = "path/to/testdata_full_gen_test",
)
```

The generation test expects a file structure like the following.
```
|-- <testDataPath>
|-- some_test
|-- WORKSPACE
|-- README.md --> README describing what the test does.
|-- expectedStdout.txt --> Expected stdout for this test.
|-- expectedStderr.txt --> Expected stderr for this test.
|-- expectedExitCode.txt --> Expected exit code for this test.
|-- app
|-- sourceFile.foo
|-- BUILD.in --> BUILD file prior to running gazelle.
|-- BUILD.out --> BUILD file expected after running gazelle.
```

To run update your desired BUILD.out files, you can run:

`UPDATE_SNAPSHOTS=true bazel run //path/to:my_generation_test`.

Supported languages
-------------------

Expand Down
27 changes: 27 additions & 0 deletions internal/generationtest/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
load("@io_bazel_rules_go//go:def.bzl", "go_test")

exports_files([
"generation_test.go",
"generation_test_manifest.yaml.tpl",
])

go_test(
name = "generationtest_test",
srcs = ["generation_test.go"],
tags = ["manual"],
deps = [
"//testtools",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
],
)

filegroup(
name = "all_files",
testonly = True,
srcs = [
"BUILD.bazel",
"generation_test.bzl",
"generation_test.go",
],
visibility = ["//visibility:public"],
)
38 changes: 38 additions & 0 deletions internal/generationtest/generation_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
Test for generating rules from gazelle.
"""

load("@io_bazel_rules_go//go:def.bzl", "go_test")

def gazelle_generation_test(name, gazelle_binary, test_data, build_in_suffix = ".in", build_out_suffix = ".out"):
"""
gazelle_generation_test is a macro for testing gazelle against workspaces.

Args:
name: the name of the test.
gazelle_binary: the name of the gazelle binary target. For example, //path/to:my_gazelle.
test_data: a target of the test data files you will pass to the test.
This can be a https://bazel.build/reference/be/general#filegroup.
build_in_suffix: the suffix for the input BUILD.bazel files. Defaults to .in.
By default, will use files named BUILD.in as the BUILD files before running gazelle.
build_out_suffix: the suffix for the expected BUILD.bazel files after running gazelle. Defaults to .out.
By default, will use files named check the results of the gazelle run against files named BUILD.out.
"""
go_test(
name = name,
srcs = ["//internal/generationtest:generation_test.go"],
deps = [
"//testtools",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
"@in_gopkg_yaml_v2//:yaml_v2",
],
args = [
"-gazelle_binary_path=$(rootpath %s)" % gazelle_binary,
"-build_in_suffix=%s" % build_in_suffix,
"-build_out_suffix=%s" % build_out_suffix,
],
data = [
test_data,
gazelle_binary,
],
)
64 changes: 64 additions & 0 deletions internal/generationtest/generation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package generationtest

import (
"flag"
"path"
"testing"

"github.com/bazelbuild/bazel-gazelle/testtools"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)

var (
gazelleBinaryPath = flag.String("gazelle_binary_path", "", "Path to the gazelle binary to test.")
buildInSuffix = flag.String("build_in_suffix", ".in", "The suffix on the test input BUILD.bazel files. Defaults to .in. "+
" By default, will use files named BUILD.in as the BUILD files before running gazelle.")
buildOutSuffix = flag.String("build_out_suffix", ".out", "The suffix on the expected BUILD.bazel files after running gazelle. Defaults to .out. "+
" By default, will use files named BUILD.out as the expected results of the gazelle run.")
)

aptenodytes-forsteri marked this conversation as resolved.
Show resolved Hide resolved
// TestFullGeneration runs the gazelle binary on a few example
// workspaces and confirms that the generated BUILD files match expectation.
func TestFullGeneration(t *testing.T) {
tests := []*testtools.TestGazelleGenerationArgs{}
runfiles, err := bazel.ListRunfiles()
if err != nil {
t.Fatalf("bazel.ListRunfiles() error: %v", err)
}
// Convert workspace relative path for gazelle binary into an absolute path.
// E.g. path/to/gazelle_binary -> /absolute/path/to/workspace/path/to/gazelle/binary.
absoluteGazelleBinary, err := bazel.Runfile(*gazelleBinaryPath)
if err != nil {
t.Fatalf("Could not convert gazelle binary path %s to absolute path. Error: %v", *gazelleBinaryPath, err)
}
for _, f := range runfiles {
// Look through runfiles for WORKSPACE files. Each WORKSPACE is a test case.
if path.Base(f.Path) == "WORKSPACE" {
// absolutePathToTestDirectory is the absolute
// path to the test case directory. For example, /home/<user>/wksp/path/to/test_data/my_test_case
absolutePathToTestDirectory := path.Dir(f.Path)
// relativePathToTestDirectory is the workspace relative path
// to this test case directory. For example, path/to/test_data/my_test_case
relativePathToTestDirectory := path.Dir(f.ShortPath)
// name is the name of the test directory. For example, my_test_case.
// The name of the directory doubles as the name of the test.
name := path.Base(absolutePathToTestDirectory)

tests = append(tests, &testtools.TestGazelleGenerationArgs{
Name: name,
TestDataPathAbsolute: absolutePathToTestDirectory,
TestDataPathRelative: relativePathToTestDirectory,
GazelleBinaryPath: absoluteGazelleBinary,
BuildInSuffix: *buildInSuffix,
BuildOutSuffix: *buildOutSuffix,
})
}
}
if len(tests) == 0 {
t.Fatal("no tests found")
}

for _, args := range tests {
testtools.TestGazelleGenerationOnPath(t, args)
}
}
1 change: 1 addition & 0 deletions internal/go_repository_tools_srcs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ GO_REPOSITORY_TOOLS_SRCS = [
"@bazel_gazelle//internal:BUILD.bazel",
"@bazel_gazelle//internal/gazellebinarytest:BUILD.bazel",
"@bazel_gazelle//internal/gazellebinarytest:xlang.go",
"@bazel_gazelle//internal/generationtest:BUILD.bazel",
"@bazel_gazelle//internal/language:BUILD.bazel",
"@bazel_gazelle//internal/language/test_filegroup:BUILD.bazel",
"@bazel_gazelle//internal/language/test_filegroup:lang.go",
Expand Down
Loading