]> Cypherpunks repositories - gostls13.git/commit
cmd/go: fix percent covered problems with -coverpkg
authorThan McIntosh <thanm@google.com>
Tue, 16 May 2023 17:31:11 +0000 (13:31 -0400)
committerThan McIntosh <thanm@google.com>
Sat, 30 Sep 2023 12:33:44 +0000 (12:33 +0000)
commit36e75f67ab380f5414ecbf017e14cc4f54d4ca6d
tree27d5e18f7af4dc92b5a1068f06e3e139bc108b09
parentd1cb5c06057ef4d315895a91cf1bad067343e599
cmd/go: fix percent covered problems with -coverpkg

This patch fixes some problems with how "go test -cover" was handling
tests involving A) multiple package tests and B) multiple packages
matched by "-coverpkg". In such scenarios the expectation is that the
percent statements covered metric for each package needs to be
relative to all statements in all packages matched by the -coverpkg
arg (this aspect of the reporting here was broken as part of
GOEXPERIMENT=coverageredesign).

The new scheme works as follows.  If -coverpkg is in effect and is
matching multiple packages, and we have multiple test targets, then:

  - each time a package is built for coverage, capture a meta-data
    file fragment corresponding to just the meta-data for that package.

  - create a new "writeCoverMeta" action, and interpose it between the
    build actions for the covered packages and the run actions. The
    "writeCoverMeta" action at runtime will emit a file
    "metafiles.txt" containing a table mapping each covered package
    (by import path) to its corresponding meta-data file fragment.

  - pass in the "metafiles.txt" file to each run action, so that
    when the test finishes running it will have an accurate picture
    of _all_ covered packages, permitting it to calculate the correct
    percentage.

Concrete example: suppose we have a top level directory with three
package subdirs, "a", "b", and "c", and from the top level, a user
runs "go test -coverpkg=./... ./...". This will result in (roughly)
the following action graph:

  build("a")       build("b")         build("c")
      |               |                   |
  link("a.test")   link("b.test")     link("c.test")
      |               |                   |
  run("a.test")    run("b.test")      run("c.test")
      |               |                   |
    print          print              print

With the new scheme, the action graph is augmented with a
writeCoverMeta action and additional dependence edges to form

  build("a")       build("b")         build("c")
      |   \       /   |               /   |
      |    v     v    |              /    |
      | writecovmeta<-|-------------+     |
      |         |||   |                   |
      |         ||\   |                   |
  link("a.test")/\ \  link("b.test")      link("c.test")
      |        /  \ +-|--------------+    |
      |       /    \  |               \   |
      |      v      v |                v  |
  run("a.test")    run("b.test")      run("c.test")
      |               |                   |
    print          print              print

A note on init functions: prior to GOEXPERIMENT=coverageredesign
the "-coverpkg=..." flag was implemented by force-importing
all packages matched by "-coverpkg" into each instrumented package.
This meant that for the example above, when executing "a.test",
the init function for package "c" would fire even if package "a"
did not ordinarily import package "c".  The new implementation
does not do this sort of forced importing, meaning that the coverage
percentages can be slightly different between 1.21 and 1.19 if
there are user-written init funcs.

Fixes #58770.
Updates #24570.

Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest
Change-Id: I7749ed205dce81b96ad7f74ab98bc1e90e377302
Reviewed-on: https://go-review.googlesource.com/c/go/+/495452
Reviewed-by: Bryan Mills <bcmills@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
src/cmd/go/internal/test/test.go
src/cmd/go/internal/work/cover.go
src/cmd/go/internal/work/exec.go
src/cmd/go/internal/work/gccgo.go
src/cmd/go/testdata/script/cover_coverpkg_partial.txt [new file with mode: 0644]
src/cmd/go/testdata/script/cover_coverpkg_with_init.txt [new file with mode: 0644]