Skip to content

Commit 29208ce

Browse files
committed
cmd/go: fix coverage rebuild corner case
If you have a package p1 with an xtest (package p1_test) that imports p2, where p2 itself imports p1, then when trying to do coverage for p1 we need to make sure to recompile p2. The problem was that the overall package import graph looked like: main -> p1_test -> p2 -> p1 Since we were recompiling p1 with coverage, we correctly figured out that because p2 depends on a package being recompiled due to coverage, p2 also needs to be split (forked) to insert the dependency on the modified p1. But then we used the same logic to split p1_test and main, with the effect that the changes to p2 and p1_test and main were lost, since the caller was still holding on to the original main, not the split version. Change the code to treat main and p1_test as "already split" and just update them in place. Fixes #23314. Change-Id: If7edeca6e39cdaeb5b9380d00b0c7d8c5891f086 Reviewed-on: https://go-review.googlesource.com/86237 Run-TryBot: Russ Cox <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 5d647f2 commit 29208ce

File tree

5 files changed

+37
-3
lines changed

5 files changed

+37
-3
lines changed

src/cmd/go/go_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2471,6 +2471,17 @@ func TestCoverageSyncAtomicImport(t *testing.T) {
24712471
tg.run("test", "-short", "-cover", "-covermode=atomic", "-coverpkg=coverdep/p1", "coverdep")
24722472
}
24732473

2474+
func TestCoverageDepLoop(t *testing.T) {
2475+
tg := testgo(t)
2476+
defer tg.cleanup()
2477+
tg.parallel()
2478+
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
2479+
// coverdep2/p1's xtest imports coverdep2/p2 which imports coverdep2/p1.
2480+
// Make sure that coverage on coverdep2/p2 recompiles coverdep2/p2.
2481+
tg.run("test", "-short", "-cover", "coverdep2/p1")
2482+
tg.grepStdout("coverage: 100.0% of statements", "expected 100.0% coverage")
2483+
}
2484+
24742485
func TestCoverageImportMainLoop(t *testing.T) {
24752486
tg := testgo(t)
24762487
defer tg.cleanup()

src/cmd/go/internal/test/test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,7 +1003,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
10031003
// This will cause extra compilation, so for now we only do it
10041004
// when testCover is set. The conditions are more general, though,
10051005
// and we may find that we need to do it always in the future.
1006-
recompileForTest(pmain, p, ptest)
1006+
recompileForTest(pmain, p, ptest, pxtest)
10071007
}
10081008

10091009
for _, cp := range pmain.Internal.Imports {
@@ -1159,14 +1159,17 @@ Search:
11591159
return stk
11601160
}
11611161

1162-
func recompileForTest(pmain, preal, ptest *load.Package) {
1162+
func recompileForTest(pmain, preal, ptest, pxtest *load.Package) {
11631163
// The "test copy" of preal is ptest.
11641164
// For each package that depends on preal, make a "test copy"
11651165
// that depends on ptest. And so on, up the dependency tree.
11661166
testCopy := map[*load.Package]*load.Package{preal: ptest}
11671167
for _, p := range load.PackageList([]*load.Package{pmain}) {
1168+
if p == preal {
1169+
continue
1170+
}
11681171
// Copy on write.
1169-
didSplit := false
1172+
didSplit := p == pmain || p == pxtest
11701173
split := func() {
11711174
if didSplit {
11721175
return
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package p1
2+
3+
func F() int { return 1 }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package p1_test
2+
3+
import (
4+
"coverdep2/p2"
5+
"testing"
6+
)
7+
8+
func Test(t *testing.T) {
9+
p2.F()
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package p2
2+
3+
import "coverdep2/p1"
4+
5+
func F() {
6+
p1.F()
7+
}

0 commit comments

Comments
 (0)