You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Support integration test coverage system (coverageredesign) (#4397)
go1.25 removes the current runtime code coverage system adopted by
rules_go (nocoverageredesign)
https://go-review.googlesource.com/c/go/+/644997
which makes rules_go incompatible with the latest upcoming version of
go.
The change completely adopts the new integration test friendly
coverageredesign
system (https://go.dev/blog/integration-test-coverage) in rules_go.
Below I describe how the current rules_go coverage system currently
works, what
changes in the new coverage redesign, and what needs to change as a
result in
rules_go.
How nocoverageredesign currently works:
- rules_go invokes `go tool cover` to generate instrumented source files
that
are then passed to the Go compiler (in compilepkg.go). Instrumented
source
files update generated package variable counters.
- The rules_go generated test main (generate_test_main.go) calls
testing.RegisterCover to set a global variable that tracks references to
coverage generated package local variables that coverage instrumented
code
modify (ref:
https://github.com/golang/go/blob/go1.24.5/src/testing/cover.go#L72)
This replicates the behavior in go test's generated test main
(cmd/go/internal/load/test.go)
- rules_go specially adds a call to coverdata.RegisterFile call to all
coverage
instrumented files which connects each of the file coverage counter
variables
with a global object and enables rules_go to customize the file name
that
coverage variables are associated with.
- It's important to note that because rules_go accesses to this global
coverage struct,
it's able to manipulate the file path name associated with coverage
counter variables.
This is important because the lcov format that bazel uses expect exec
root relative files.
- When a test exits, This global object is flushed in a call to
`testing.coverReport()` to
generate a coverage report. This reports gets written a file configured
in
test.coverprofile flag.
- Via a special SetPanicOnExit0 hook, the coverage file set in
test.coverprofile
is coverted to a Bazel friendly Lcov format via logic in
bzltestutil/lcov.go
What changes in coverageredesign:
- A new flexible system for configuring coverage behavior. Instead of a
single
esting.RegisterCover function, there is a new testdeps package that
exposes hooks
to configure behavior.
- The global variable
(https://github.com/golang/go/blob/go1.24.5/src/testing/cover.go#L72)
that tracked all coverage data is completely removed. Instead, functions
in https://pkg.go.dev/internal/coverage/cfile that are called when
writing coverage reports on test exit are internally aware of and able
to access coverage counter variable data.
- Functionality to flush coverage counter variables write to an
intermediate
coverage directory in a binary format. Hooks configured in the testdeps
package
are responsible for translating this binary format into a human readable
coverage
output file.
- 'go tool cover' takes a new package based configuration "pkgcfg"
option that
enables this new coverage instrumentation logic in coverage source
files.
- Coverage counters can be flushed on demand via the APIs of
"runtime/coverage"
This allows coverage to work outside of test situations where coverage
used to rely on exit hooks generated into test mains to flush and write
coverage data.
What needs to change in rules_go as a result:
- Use the new testdeps configuration system in the rules_go generated
test main.
We can following the example of the go test generated test main.
ref:
https://github.com/golang/go/blob/go1.24.5/src/cmd/go/internal/load/test.go#L986
- Invoke 'go tool cover' with the new -pkgcfg flag. We can follow the
example of
how the go toolchain invokes coverage redesign instrumentation in
https://github.com/golang/go/blob/go1.24.5/src/cmd/go/internal/work/exec.go#L1932
- Not strictly necessary but removes technical debt, call
bzltestutil.ConvertCoverToLcov
inside of testdeps.CoverProcessTestDirFunc hook wrapper instead of the
bzltestutil.LcovTestDeps SetPanicOnExit0 hook.
- Adjust the output of lcov profile to make file path keys in coverage
files
execution root relative.
Implementation Note:
Unfortunately, we still need
github.com/bazelbuild/rules_go/go/tools/coverdata
dependencies in coverage source files because the lcov coverage format
expects file paths associated with coverage data to be execution root
relative. coverageredesign writes Go coverage file data in the format of
`importpath/file_name` which is not execution root (e.g. `src/`)
relative.
During compilation is the only place we have the information to map
`importpath/file_name` to an execution root relative path so we have
to continue to use the trick of generating code that corrects the
file path coverage mapping at runtime.
This makes it hard for coverage to work outside of tests because depend
on a special
github.com/bazelbuild/rules_go/go/tools/coverdata dependency that can't
be
guaranteed because we don't control a generated test main in these
situations.
If Go coverage filepaths can be configured during invocations of the `go
tool cover`, we can break this dependency. I've filed an upstream go
ticket
to descrbe this issue golang/go#74749.
ref #3513
0 commit comments