Skip to content

Commit 0cd6a8c

Browse files
committed
ensure the coverprofile flag is not empty before retrieving the cover profile cache data
1 parent 948f23b commit 0cd6a8c

File tree

2 files changed

+31
-45
lines changed

2 files changed

+31
-45
lines changed

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ import (
1414
"sync"
1515
)
1616

17-
// coverMerge manages the state for merging test coverage profiles.
18-
// It ensures thread-safe operations on a single coverage profile file
19-
// across multiple test runs and packages.
2017
var coverMerge struct {
2118
f *os.File
2219
sync.Mutex // for f.Write

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

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,7 +1672,7 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action)
16721672
a.TestOutput = &buf
16731673
t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
16741674

1675-
mergeCoverProfile(a.Objdir + "_cover_.out")
1675+
mergeCoverProfile(coverProfTempFile(a))
16761676

16771677
if err == nil {
16781678
norun := ""
@@ -1694,7 +1694,7 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action)
16941694
cmd.Stdout.Write([]byte("\n"))
16951695
}
16961696
fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun)
1697-
r.c.saveOutput(a, coverProfTempFile(a))
1697+
r.c.saveOutput(a)
16981698
} else {
16991699
if testFailFast {
17001700
testShouldFailFast.Store(true)
@@ -1794,14 +1794,7 @@ func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bo
17941794
cacheArgs = append(cacheArgs, arg)
17951795
case "-test.coverprofile",
17961796
"-test.outputdir":
1797-
// The `-coverprofile` and `-outputdir` arguments, which
1798-
// only affect the location of profile output, are cacheable. This
1799-
// is based on the process where, upon a cache hit, stored profile
1800-
// data is copied to the specified output location. This mechanism
1801-
// ensures that output location preferences are honored without
1802-
// modifying the profile's content, thereby justifying their
1803-
// cacheability without impacting cache integrity. This allows
1804-
// cached coverage profiles to be written to different files.
1797+
// These are cacheable and do not invalidate the cache when they change.
18051798
// Note that this list is documented above,
18061799
// so if you add to this list, update the docs too.
18071800
default:
@@ -1875,6 +1868,20 @@ func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bo
18751868
// Parse cached result in preparation for changing run time to "(cached)".
18761869
// If we can't parse the cached result, don't use it.
18771870
data, entry, err = cache.GetBytes(cache.Default(), testAndInputKey(testID, testInputsID))
1871+
1872+
// Merge cached cover profile data to cover profile.
1873+
if testCoverProfile != "" {
1874+
// Specifically ignore entry as it will be the same as above.
1875+
cpData, _, err := cache.GetFile(cache.Default(), coverProfileAndInputKey(testID, testInputsID))
1876+
if err != nil {
1877+
if cache.DebugTest {
1878+
fmt.Fprintf(os.Stderr, "testcache: %s: cached cover profile missing: %v\n", a.Package.ImportPath, err)
1879+
}
1880+
return false
1881+
}
1882+
mergeCoverProfile(cpData)
1883+
}
1884+
18781885
if len(data) == 0 || data[len(data)-1] != '\n' {
18791886
if cache.DebugTest {
18801887
if err != nil {
@@ -1915,21 +1922,6 @@ func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bo
19151922
j++
19161923
}
19171924
c.buf.Write(data[j:])
1918-
1919-
// Write coverage data to profile.
1920-
if cfg.BuildCover {
1921-
// The cached coverprofile has the same expiration time as the
1922-
// test result it corresponds to. That time is already checked
1923-
// above, so we can ignore the entry returned by GetFile here.
1924-
f, _, err := cache.GetFile(cache.Default(), coverProfileAndInputKey(testID, testInputsID))
1925-
if err != nil {
1926-
if cache.DebugTest {
1927-
fmt.Fprintf(os.Stderr, "testcache: %s: cached test result valid but cached coverage profile missing: %v\n", a.Package.ImportPath, err)
1928-
}
1929-
return false
1930-
}
1931-
mergeCoverProfile(f)
1932-
}
19331925
return true
19341926
}
19351927

@@ -2083,7 +2075,7 @@ func coverProfileAndInputKey(testID, testInputsID cache.ActionID) cache.ActionID
20832075
return cache.Subkey(testAndInputKey(testID, testInputsID), "coverprofile")
20842076
}
20852077

2086-
func (c *runCache) saveOutput(a *work.Action, coverProfileFile string) {
2078+
func (c *runCache) saveOutput(a *work.Action) {
20872079
if c.id1 == (cache.ActionID{}) && c.id2 == (cache.ActionID{}) {
20882080
return
20892081
}
@@ -2104,21 +2096,14 @@ func (c *runCache) saveOutput(a *work.Action, coverProfileFile string) {
21042096
if err != nil {
21052097
return
21062098
}
2107-
var saveCoverProfile = func(testID cache.ActionID) {}
2108-
if coverProfileFile != "" {
2109-
coverProfile, err := os.Open(coverProfileFile)
2110-
if err == nil {
2111-
saveCoverProfile = func(testID cache.ActionID) {
2112-
cache.Default().Put(coverProfileAndInputKey(testID, testInputsID), coverProfile)
2099+
var coverProfile []byte
2100+
if testCoverProfile != "" {
2101+
coverProfile, err = os.ReadFile(coverProfTempFile(a))
2102+
if err != nil && !os.IsNotExist(err) {
2103+
if cache.DebugTest {
2104+
fmt.Fprintf(os.Stderr, "testcache: %s: reading cover profile: %v\n", a.Package.ImportPath, err)
21132105
}
2114-
defer func() {
2115-
if err := coverProfile.Close(); err != nil && cache.DebugTest {
2116-
base.Errorf("closing temporary coverprofile: %v", err)
2117-
}
2118-
}()
2119-
} else if cache.DebugTest {
2120-
// Not indicative of a problem, as the test may not have generated a cover profile yet.
2121-
fmt.Fprintf(os.Stderr, "testcache: %s: opening temporary coverprofile: %s\n", a.Package.ImportPath, err)
2106+
return
21222107
}
21232108
}
21242109
if c.id1 != (cache.ActionID{}) {
@@ -2127,15 +2112,19 @@ func (c *runCache) saveOutput(a *work.Action, coverProfileFile string) {
21272112
}
21282113
cache.PutNoVerify(cache.Default(), c.id1, bytes.NewReader(testlog))
21292114
cache.PutNoVerify(cache.Default(), testAndInputKey(c.id1, testInputsID), bytes.NewReader(a.TestOutput.Bytes()))
2130-
saveCoverProfile(c.id1)
2115+
if coverProfile != nil {
2116+
cache.PutNoVerify(cache.Default(), coverProfileAndInputKey(c.id1, testInputsID), bytes.NewReader(coverProfile))
2117+
}
21312118
}
21322119
if c.id2 != (cache.ActionID{}) {
21332120
if cache.DebugTest {
21342121
fmt.Fprintf(os.Stderr, "testcache: %s: save test ID %x => input ID %x => %x\n", a.Package.ImportPath, c.id2, testInputsID, testAndInputKey(c.id2, testInputsID))
21352122
}
21362123
cache.PutNoVerify(cache.Default(), c.id2, bytes.NewReader(testlog))
21372124
cache.PutNoVerify(cache.Default(), testAndInputKey(c.id2, testInputsID), bytes.NewReader(a.TestOutput.Bytes()))
2138-
saveCoverProfile(c.id2)
2125+
if coverProfile != nil {
2126+
cache.PutNoVerify(cache.Default(), coverProfileAndInputKey(c.id2, testInputsID), bytes.NewReader(coverProfile))
2127+
}
21392128
}
21402129
}
21412130

0 commit comments

Comments
 (0)