From 5edea4601f8bd0f1f550ffe0c69f834655d1daed Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 9 Oct 2026 15:24:01 +0200 Subject: [PATCH] go: Add go.test to run a project's Go tests A Go project's tests have no rule in tine. A consumer runs go test in a relaxed box, where go downloads the modules again and compiles the project a second time. Add test_packages to go.package. The build action compiles the tests of those packages with go test -c, using the go build cache that the build of the binaries already filled. go.test runs the test binaries in the package's box without network. Signed-off-by: Daan De Meyer --- docs/design/architecture.md | 8 ++ docs/user/go.md | 35 ++++++ examples/image-go-project/BUCK | 14 +++ .../hello/cmd/hello-cli/main_test.go | 17 +++ examples/image-go-project/nodeps/main_test.go | 12 ++ go/BUCK | 13 +++ go/build.py | 107 ++++++++++++++--- go/build_test.py | 108 ++++++++++++++++++ go/defs.bzl | 3 +- go/rules.bzl | 64 ++++++++++- go/runner.py | 63 ++++++++++ go/runner_test.py | 84 ++++++++++++++ 12 files changed, 510 insertions(+), 18 deletions(-) create mode 100644 examples/image-go-project/hello/cmd/hello-cli/main_test.go create mode 100644 examples/image-go-project/nodeps/main_test.go create mode 100755 go/runner.py create mode 100644 go/runner_test.py diff --git a/docs/design/architecture.md b/docs/design/architecture.md index 692eda67..3e7976d8 100644 --- a/docs/design/architecture.md +++ b/docs/design/architecture.md @@ -1059,6 +1059,14 @@ sources are. For a mount buck keeps it too, so a dependency bump downloads only module versions accumulate but are inert, since go takes only what `go.sum` names out of the proxy view. Otherwise buck clears it before the fetch, and the cache content depends only on the fetch's inputs. +A `go.package()` that sets `test_packages` also compiles the tests of those packages in `go_build`, with +`go test -c`, one test binary per package. The test binaries use go's build cache of the same action, so the +project's packages compile once for the binaries and the tests. A test that does not compile fails the +build. The test compile runs without vet, because a vet finding would fail the build too. `go.test()` runs +each test binary under `buck test` in the package's box, in the package's directory, with the sources +read-only. A pattern in `test_packages` that matches a package outside `src` fails the build, because that +package's directory does not exist when the tests run. + ### Filesystem layer representation Buck directory artifacts cannot faithfully store overlay whiteout devices, opaque-directory xattrs, or a diff --git a/docs/user/go.md b/docs/user/go.md index 58b74056..3505288e 100644 --- a/docs/user/go.md +++ b/docs/user/go.md @@ -100,6 +100,41 @@ go.package( ) ``` +## Running a project's tests + +Set `test_packages` on the `go.package()` to compile the project's tests in its build, and declare a +`go.test()` that runs them: + +```Starlark +go.package( + name = "hello", + box = ":go.box", + packages = {"hello-cli": "./cmd/hello-cli"}, + test_packages = ["./..."], +) + +go.test( + name = "hello-test", + package = ":hello", +) +``` + +`buck test :hello-test` runs the tests in the package's box, without network. + +- `test_packages` lists Go package patterns relative to the module root, such as `["./..."]` or + `["./pkg/...", "./internal/store"]`. The build compiles one test binary for each matched package that has + `_test.go` files, with the same tags, cgo setting and `linker_flags` as the binaries. Building the + binaries also compiles the tests. +- A test that does not compile fails the build of the `go.package()`, and with it the binaries. go's vet + checks do not run, so a vet finding fails neither the build nor the tests. +- A pattern that matches a package outside `src`, such as a dependency's package, fails the build. +- Each test binary runs in its package's directory, as with `go test`, so a test finds its `testdata/`. + The sources are read-only while the tests run, so a test that writes into its package directory fails. +- `args` passes arguments to every test binary. A test binary takes the `-test.` form of the `go test` + flags, such as `["-test.short", "-test.skip=TestNetwork"]`. Each binary has a timeout of 10 minutes, + which `-test.timeout` overrides. +- `labels` are passed to the test runner, so `buck test --exclude