@@ -123,8 +123,9 @@ elapsed time in the summary line.
123
123
124
124
The rule for a match in the cache is that the run involves the same
125
125
test 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.
128
129
If a run of go test has any test or non-test flags outside this set,
129
130
the result is not cached. To disable test caching, use any test flag
130
131
or 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.
1336
1337
}
1337
1338
args := str .StringList (execCmd , a .Deps [0 ].BuiltTarget (), testlogArg , panicArg , fuzzArg , testArgs )
1338
1339
1340
+ var coverprofileFile string
1339
1341
if testCoverProfile != "" {
1340
1342
// Write coverage to temporary profile, for merging later.
1343
+ coverprofileFile = a .Objdir + "_cover_.out"
1341
1344
for i , arg := range args {
1342
1345
if strings .HasPrefix (arg , "-test.coverprofile=" ) {
1343
- args [i ] = "-test.coverprofile=" + a . Objdir + "_cover_.out"
1346
+ args [i ] = "-test.coverprofile=" + coverprofileFile
1344
1347
}
1345
1348
}
1346
1349
}
@@ -1417,7 +1420,9 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
1417
1420
a .TestOutput = & buf
1418
1421
t := fmt .Sprintf ("%.3fs" , time .Since (t0 ).Seconds ())
1419
1422
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
+ }
1421
1426
1422
1427
if err == nil {
1423
1428
norun := ""
@@ -1439,7 +1444,7 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
1439
1444
cmd .Stdout .Write ([]byte ("\n " ))
1440
1445
}
1441
1446
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 )
1443
1448
} else {
1444
1449
base .SetExitStatus (1 )
1445
1450
if len (out ) == 0 {
@@ -1520,7 +1525,14 @@ func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bo
1520
1525
// Note that this list is documented above,
1521
1526
// so if you add to this list, update the docs too.
1522
1527
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.
1524
1536
default :
1525
1537
// nothing else is cacheable
1526
1538
if cache .DebugTest {
@@ -1640,6 +1652,26 @@ func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bo
1640
1652
j ++
1641
1653
}
1642
1654
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
+
1643
1675
return true
1644
1676
}
1645
1677
@@ -1788,7 +1820,12 @@ func testAndInputKey(testID, testInputsID cache.ActionID) cache.ActionID {
1788
1820
return cache .Subkey (testID , fmt .Sprintf ("inputs:%x" , testInputsID ))
1789
1821
}
1790
1822
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 ) {
1792
1829
if c .id1 == (cache.ActionID {}) && c .id2 == (cache.ActionID {}) {
1793
1830
return
1794
1831
}
@@ -1809,19 +1846,35 @@ func (c *runCache) saveOutput(a *work.Action) {
1809
1846
if err != nil {
1810
1847
return
1811
1848
}
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
+ }
1812
1863
if c .id1 != (cache.ActionID {}) {
1813
1864
if cache .DebugTest {
1814
1865
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 ))
1815
1866
}
1816
1867
cache .Default ().PutNoVerify (c .id1 , bytes .NewReader (testlog ))
1817
1868
cache .Default ().PutNoVerify (testAndInputKey (c .id1 , testInputsID ), bytes .NewReader (a .TestOutput .Bytes ()))
1869
+ saveCoverProfile (c .id1 )
1818
1870
}
1819
1871
if c .id2 != (cache.ActionID {}) {
1820
1872
if cache .DebugTest {
1821
1873
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 ))
1822
1874
}
1823
1875
cache .Default ().PutNoVerify (c .id2 , bytes .NewReader (testlog ))
1824
1876
cache .Default ().PutNoVerify (testAndInputKey (c .id2 , testInputsID ), bytes .NewReader (a .TestOutput .Bytes ()))
1877
+ saveCoverProfile (c .id2 )
1825
1878
}
1826
1879
}
1827
1880
0 commit comments