diff options
author | Ian Lance Taylor <iant@golang.org> | 2018-12-05 17:24:41 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2018-12-06 22:06:55 +0000 |
commit | 4a801cdd319dc25a2bcdced0b70377c2dfa1464f (patch) | |
tree | a224e818ddab955a967c07cb3a893590d553b1e7 /src/cmd/cover | |
parent | ec0077c54d6261ba5cbab2c5dc2e80345068233f (diff) | |
download | go-4a801cdd319dc25a2bcdced0b70377c2dfa1464f.tar.gz go-4a801cdd319dc25a2bcdced0b70377c2dfa1464f.zip |
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>
Diffstat (limited to 'src/cmd/cover')
-rw-r--r-- | src/cmd/cover/cover_test.go | 147 |
1 files changed, 102 insertions, 45 deletions
diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go index 8eb7124aad..a374dc4e9b 100644 --- a/src/cmd/cover/cover_test.go +++ b/src/cmd/cover/cover_test.go @@ -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) - } - - // go build -o testcover - cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", 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 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) + // 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) + } + 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() |