@@ -123,8 +123,9 @@ elapsed time in the summary line.
123123
124124The rule for a match in the cache is that the run involves the same
125125test binary and the flags on the command line come entirely from a
126- restricted set of 'cacheable' test flags, defined as -benchtime, -cpu,
127- -list, -parallel, -run, -short, -timeout, -failfast, and -v.
126+ restricted set of 'cacheable' test flags, defined as -benchtime, -cover,
127+ -covermode, -coverprofile, -cpu, -list, -parallel, -run, -short, -timeout,
128+ -failfast, -v, -vet and -outputdir.
128129If a run of go test has any test or non-test flags outside this set,
129130the result is not cached. To disable test caching, use any test flag
130131or argument other than the cacheable flags. The idiomatic way to disable
@@ -1336,11 +1337,13 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
13361337 }
13371338 args := str .StringList (execCmd , a .Deps [0 ].BuiltTarget (), testlogArg , panicArg , fuzzArg , testArgs )
13381339
1340+ var coverprofileFile string
13391341 if testCoverProfile != "" {
13401342 // Write coverage to temporary profile, for merging later.
1343+ coverprofileFile = a .Objdir + "_cover_.out"
13411344 for i , arg := range args {
13421345 if strings .HasPrefix (arg , "-test.coverprofile=" ) {
1343- args [i ] = "-test.coverprofile=" + a . Objdir + "_cover_.out"
1346+ args [i ] = "-test.coverprofile=" + coverprofileFile
13441347 }
13451348 }
13461349 }
@@ -1417,7 +1420,9 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
14171420 a .TestOutput = & buf
14181421 t := fmt .Sprintf ("%.3fs" , time .Since (t0 ).Seconds ())
14191422
1420- mergeCoverProfile (cmd .Stdout , a .Objdir + "_cover_.out" )
1423+ if coverErr := mergeCoverProfile (coverprofileFile ); coverErr != nil {
1424+ fmt .Fprintf (cmd .Stdout , "error: %v\n " , coverErr )
1425+ }
14211426
14221427 if err == nil {
14231428 norun := ""
@@ -1439,7 +1444,7 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
14391444 cmd .Stdout .Write ([]byte ("\n " ))
14401445 }
14411446 fmt .Fprintf (cmd .Stdout , "ok \t %s\t %s%s%s\n " , a .Package .ImportPath , t , coveragePercentage (out ), norun )
1442- c .saveOutput (a )
1447+ c .saveOutput (a , coverprofileFile )
14431448 } else {
14441449 base .SetExitStatus (1 )
14451450 if len (out ) == 0 {
@@ -1520,7 +1525,14 @@ func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bo
15201525 // Note that this list is documented above,
15211526 // so if you add to this list, update the docs too.
15221527 cacheArgs = append (cacheArgs , arg )
1523-
1528+ case "-test.coverprofile" ,
1529+ "-test.outputdir" :
1530+ // The -coverprofile and -outputdir arguments are cacheable but
1531+ // only change where profiles are written. They don't change the
1532+ // profile contents, so they aren't added to the cacheArgs. This
1533+ // allows cached coverage profiles to be written to different files.
1534+ // Note that this list is documented above,
1535+ // so if you add to this list, update the docs too.
15241536 default :
15251537 // nothing else is cacheable
15261538 if cache .DebugTest {
@@ -1640,6 +1652,26 @@ func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bo
16401652 j ++
16411653 }
16421654 c .buf .Write (data [j :])
1655+
1656+ // Write coverage data to profile.
1657+ if testCover {
1658+ // coverprofile cache expiration time should be coupled with the test data above, so
1659+ // the entry can be ignored.
1660+ f , _ , err := cache .Default ().GetFile (testCoverProfileKey (testID , testInputsID ))
1661+ if err != nil {
1662+ if cache .DebugTest {
1663+ fmt .Fprintf (os .Stderr , "testcache: %s: test coverage profile not found: %v\n " , a .Package .ImportPath , err )
1664+ }
1665+ return false
1666+ }
1667+ if err := mergeCoverProfile (f ); err != nil {
1668+ if cache .DebugTest {
1669+ fmt .Fprintf (os .Stderr , "testcache: %s: test coverage profile not merged: %v\n " , a .Package .ImportPath , err )
1670+ }
1671+ return false
1672+ }
1673+ }
1674+
16431675 return true
16441676}
16451677
@@ -1788,7 +1820,12 @@ func testAndInputKey(testID, testInputsID cache.ActionID) cache.ActionID {
17881820 return cache .Subkey (testID , fmt .Sprintf ("inputs:%x" , testInputsID ))
17891821}
17901822
1791- func (c * runCache ) saveOutput (a * work.Action ) {
1823+ // testCoverProfileKey returns the "coverprofile" cache key for the pair (testID, testInputsID).
1824+ func testCoverProfileKey (testID , testInputsID cache.ActionID ) cache.ActionID {
1825+ return cache .Subkey (testAndInputKey (testID , testInputsID ), "coverprofile" )
1826+ }
1827+
1828+ func (c * runCache ) saveOutput (a * work.Action , coverprofileFile string ) {
17921829 if c .id1 == (cache.ActionID {}) && c .id2 == (cache.ActionID {}) {
17931830 return
17941831 }
@@ -1809,19 +1846,35 @@ func (c *runCache) saveOutput(a *work.Action) {
18091846 if err != nil {
18101847 return
18111848 }
1849+ saveCoverProfile := func (testID cache.ActionID ) {
1850+ if coverprofileFile == "" {
1851+ return
1852+ }
1853+ coverprof , err := os .Open (coverprofileFile )
1854+ if err != nil {
1855+ if cache .DebugTest {
1856+ fmt .Fprintf (os .Stderr , "testcache: %s: failed to open temporary coverprofile file: %s" , a .Package .ImportPath , err )
1857+ }
1858+ return
1859+ }
1860+ defer coverprof .Close ()
1861+ cache .Default ().Put (testCoverProfileKey (testID , testInputsID ), coverprof )
1862+ }
18121863 if c .id1 != (cache.ActionID {}) {
18131864 if cache .DebugTest {
18141865 fmt .Fprintf (os .Stderr , "testcache: %s: save test ID %x => input ID %x => %x\n " , a .Package .ImportPath , c .id1 , testInputsID , testAndInputKey (c .id1 , testInputsID ))
18151866 }
18161867 cache .Default ().PutNoVerify (c .id1 , bytes .NewReader (testlog ))
18171868 cache .Default ().PutNoVerify (testAndInputKey (c .id1 , testInputsID ), bytes .NewReader (a .TestOutput .Bytes ()))
1869+ saveCoverProfile (c .id1 )
18181870 }
18191871 if c .id2 != (cache.ActionID {}) {
18201872 if cache .DebugTest {
18211873 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 ))
18221874 }
18231875 cache .Default ().PutNoVerify (c .id2 , bytes .NewReader (testlog ))
18241876 cache .Default ().PutNoVerify (testAndInputKey (c .id2 , testInputsID ), bytes .NewReader (a .TestOutput .Bytes ()))
1877+ saveCoverProfile (c .id2 )
18251878 }
18261879}
18271880
0 commit comments