mirror of https://github.com/golang/go.git
cmd/cover: run tests in parallel, don't change source directory
This speeds up the cmd/cover testsuite by about 40% on my laptop. Updates #26473 Updates #28386 Change-Id: I853b1b3b8c98dc89440f7b7bf5c0ade1d3d66802 Reviewed-on: https://go-review.googlesource.com/c/152817 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
ec0077c54d
commit
4a801cdd31
|
|
@ -19,43 +19,103 @@ import (
|
|||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
// Data directory, also the package directory for the test.
|
||||
testdata = "testdata"
|
||||
|
||||
// Binaries we compile.
|
||||
testcover = "./testcover.exe"
|
||||
)
|
||||
|
||||
var (
|
||||
// Files we use.
|
||||
// Input files.
|
||||
testMain = filepath.Join(testdata, "main.go")
|
||||
testTest = filepath.Join(testdata, "test.go")
|
||||
coverInput = filepath.Join(testdata, "test_line.go")
|
||||
coverOutput = filepath.Join(testdata, "test_cover.go")
|
||||
coverProfile = filepath.Join(testdata, "profile.cov")
|
||||
|
||||
// The HTML test files are in a separate directory
|
||||
// so they are a complete package.
|
||||
htmlProfile = filepath.Join(testdata, "html", "html.cov")
|
||||
htmlHTML = filepath.Join(testdata, "html", "html.html")
|
||||
htmlGolden = filepath.Join(testdata, "html", "html.golden")
|
||||
htmlGolden = filepath.Join(testdata, "html", "html.golden")
|
||||
|
||||
// Temporary files.
|
||||
tmpTestMain string
|
||||
coverInput string
|
||||
coverOutput string
|
||||
htmlProfile string
|
||||
htmlHTML string
|
||||
)
|
||||
|
||||
var (
|
||||
// testTempDir is a temporary directory created in TestMain.
|
||||
testTempDir string
|
||||
|
||||
// testcover is a newly built version of the cover program.
|
||||
testcover string
|
||||
|
||||
// testcoverErr records an error building testcover.
|
||||
testcoverErr error
|
||||
|
||||
// testcoverOnce is used to build testcover once.
|
||||
testcoverOnce sync.Once
|
||||
)
|
||||
|
||||
var debug = flag.Bool("debug", false, "keep rewritten files for debugging")
|
||||
|
||||
// We use TestMain to set up a temporary directory and remove it when
|
||||
// the tests are done.
|
||||
func TestMain(m *testing.M) {
|
||||
dir, err := ioutil.TempDir("", "gotestcover")
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testTempDir = dir
|
||||
|
||||
tmpTestMain = filepath.Join(dir, "main.go")
|
||||
coverInput = filepath.Join(dir, "test_line.go")
|
||||
coverOutput = filepath.Join(dir, "test_cover.go")
|
||||
htmlProfile = filepath.Join(dir, "html.cov")
|
||||
htmlHTML = filepath.Join(dir, "html.html")
|
||||
|
||||
status := m.Run()
|
||||
|
||||
if !*debug {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
|
||||
os.Exit(status)
|
||||
}
|
||||
|
||||
// buildCover builds a version of the cover program for testing.
|
||||
// This ensures that "go test cmd/cover" tests the current cmd/cover.
|
||||
func buildCover(t *testing.T) {
|
||||
t.Helper()
|
||||
testenv.MustHaveGoBuild(t)
|
||||
testcoverOnce.Do(func() {
|
||||
testcover = filepath.Join(testTempDir, "testcover.exe")
|
||||
t.Logf("running [go build -o %s]", testcover)
|
||||
out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", testcover).CombinedOutput()
|
||||
t.Logf("%s", out)
|
||||
testcoverErr = err
|
||||
})
|
||||
if testcoverErr != nil {
|
||||
t.Fatal("failed to build testcover program:", testcoverErr)
|
||||
}
|
||||
}
|
||||
|
||||
// Run this shell script, but do it in Go so it can be run by "go test".
|
||||
//
|
||||
// replace the word LINE with the line number < testdata/test.go > testdata/test_line.go
|
||||
// go build -o ./testcover
|
||||
// ./testcover -mode=count -var=CoverTest -o ./testdata/test_cover.go testdata/test_line.go
|
||||
// go build -o testcover
|
||||
// testcover -mode=count -var=CoverTest -o ./testdata/test_cover.go testdata/test_line.go
|
||||
// go run ./testdata/main.go ./testdata/test.go
|
||||
//
|
||||
func TestCover(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
t.Parallel()
|
||||
testenv.MustHaveGoRun(t)
|
||||
buildCover(t)
|
||||
|
||||
// Read in the test file (testTest) and write it, with LINEs specified, to coverInput.
|
||||
file, err := ioutil.ReadFile(testTest)
|
||||
|
|
@ -81,29 +141,22 @@ func TestCover(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// defer removal of test_line.go
|
||||
if !*debug {
|
||||
defer os.Remove(coverInput)
|
||||
// testcover -mode=count -var=thisNameMustBeVeryLongToCauseOverflowOfCounterIncrementStatementOntoNextLineForTest -o ./testdata/test_cover.go testdata/test_line.go
|
||||
cmd := exec.Command(testcover, "-mode=count", "-var=thisNameMustBeVeryLongToCauseOverflowOfCounterIncrementStatementOntoNextLineForTest", "-o", coverOutput, coverInput)
|
||||
run(cmd, t)
|
||||
|
||||
// Copy testmain to testTempDir, so that it is in the same directory
|
||||
// as coverOutput.
|
||||
b, err := ioutil.ReadFile(testMain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// go build -o testcover
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", testcover)
|
||||
run(cmd, t)
|
||||
|
||||
// defer removal of testcover
|
||||
defer os.Remove(testcover)
|
||||
|
||||
// ./testcover -mode=count -var=thisNameMustBeVeryLongToCauseOverflowOfCounterIncrementStatementOntoNextLineForTest -o ./testdata/test_cover.go testdata/test_line.go
|
||||
cmd = exec.Command(testcover, "-mode=count", "-var=thisNameMustBeVeryLongToCauseOverflowOfCounterIncrementStatementOntoNextLineForTest", "-o", coverOutput, coverInput)
|
||||
run(cmd, t)
|
||||
|
||||
// defer removal of ./testdata/test_cover.go
|
||||
if !*debug {
|
||||
defer os.Remove(coverOutput)
|
||||
if err := ioutil.WriteFile(tmpTestMain, b, 0444); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// go run ./testdata/main.go ./testdata/test.go
|
||||
cmd = exec.Command(testenv.GoToolPath(t), "run", testMain, coverOutput)
|
||||
cmd = exec.Command(testenv.GoToolPath(t), "run", tmpTestMain, coverOutput)
|
||||
run(cmd, t)
|
||||
|
||||
file, err = ioutil.ReadFile(coverOutput)
|
||||
|
|
@ -131,6 +184,9 @@ func TestCover(t *testing.T) {
|
|||
// above those declarations, even if they are not part of the block of
|
||||
// documentation comments.
|
||||
func TestDirectives(t *testing.T) {
|
||||
t.Parallel()
|
||||
buildCover(t)
|
||||
|
||||
// Read the source file and find all the directives. We'll keep
|
||||
// track of whether each one has been seen in the output.
|
||||
testDirectives := filepath.Join(testdata, "directives.go")
|
||||
|
|
@ -140,8 +196,8 @@ func TestDirectives(t *testing.T) {
|
|||
}
|
||||
sourceDirectives := findDirectives(source)
|
||||
|
||||
// go tool cover -mode=atomic ./testdata/directives.go
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "tool", "cover", "-mode=atomic", testDirectives)
|
||||
// testcover -mode=atomic ./testdata/directives.go
|
||||
cmd := exec.Command(testcover, "-mode=atomic", testDirectives)
|
||||
cmd.Stderr = os.Stderr
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
|
|
@ -247,8 +303,10 @@ func findDirectives(source []byte) []directiveInfo {
|
|||
// Makes sure that `cover -func=profile.cov` reports accurate coverage.
|
||||
// Issue #20515.
|
||||
func TestCoverFunc(t *testing.T) {
|
||||
// go tool cover -func ./testdata/profile.cov
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "tool", "cover", "-func", coverProfile)
|
||||
t.Parallel()
|
||||
buildCover(t)
|
||||
// testcover -func ./testdata/profile.cov
|
||||
cmd := exec.Command(testcover, "-func", coverProfile)
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
if ee, ok := err.(*exec.ExitError); ok {
|
||||
|
|
@ -266,19 +324,14 @@ func TestCoverFunc(t *testing.T) {
|
|||
// Check that cover produces correct HTML.
|
||||
// Issue #25767.
|
||||
func TestCoverHTML(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
if !*debug {
|
||||
defer os.Remove(testcover)
|
||||
defer os.Remove(htmlProfile)
|
||||
defer os.Remove(htmlHTML)
|
||||
}
|
||||
// go build -o testcover
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", testcover)
|
||||
run(cmd, t)
|
||||
t.Parallel()
|
||||
testenv.MustHaveGoRun(t)
|
||||
buildCover(t)
|
||||
|
||||
// go test -coverprofile testdata/html/html.cov cmd/cover/testdata/html
|
||||
cmd = exec.Command(testenv.GoToolPath(t), "test", "-coverprofile", htmlProfile, "cmd/cover/testdata/html")
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "test", "-coverprofile", htmlProfile, "cmd/cover/testdata/html")
|
||||
run(cmd, t)
|
||||
// ./testcover -html testdata/html/html.cov -o testdata/html/html.html
|
||||
// testcover -html testdata/html/html.cov -o testdata/html/html.html
|
||||
cmd = exec.Command(testcover, "-html", htmlProfile, "-o", htmlHTML)
|
||||
run(cmd, t)
|
||||
|
||||
|
|
@ -303,6 +356,9 @@ func TestCoverHTML(t *testing.T) {
|
|||
in = false
|
||||
}
|
||||
}
|
||||
if scan.Err() != nil {
|
||||
t.Error(scan.Err())
|
||||
}
|
||||
golden, err := ioutil.ReadFile(htmlGolden)
|
||||
if err != nil {
|
||||
t.Fatalf("reading golden file: %v", err)
|
||||
|
|
@ -331,6 +387,7 @@ func TestCoverHTML(t *testing.T) {
|
|||
|
||||
func run(c *exec.Cmd, t *testing.T) {
|
||||
t.Helper()
|
||||
t.Log("running", c.Args)
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
err := c.Run()
|
||||
|
|
|
|||
Loading…
Reference in New Issue