Skip to content

Commit e017802

Browse files
committed
cmd/vet: parallelize tests
Was 2.3 seconds. Now 1.4 seconds. Next win would be not running a child process and refactoring main so it could be called from tests easily. But that would also require rewriting the errchk written in Perl. This appears to be the last user of errchk in the tree. Updates #17751 Change-Id: Id7c3cec76f438590789b994e756f55b5397be07f Reviewed-on: https://go-review.googlesource.com/32754 Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Rob Pike <[email protected]>
1 parent 2b445c7 commit e017802

File tree

15 files changed

+92
-34
lines changed

15 files changed

+92
-34
lines changed
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package testdata

src/cmd/vet/vet_test.go

+91-34
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"os/exec"
1414
"path/filepath"
1515
"runtime"
16+
"sync"
1617
"testing"
1718
)
1819

@@ -40,19 +41,22 @@ func MustHavePerl(t *testing.T) {
4041
}
4142

4243
var (
43-
built = false // We have built the binary.
44-
failed = false // We have failed to build the binary, don't try again.
44+
buildMu sync.Mutex // guards following
45+
built = false // We have built the binary.
46+
failed = false // We have failed to build the binary, don't try again.
4547
)
4648

4749
func Build(t *testing.T) {
48-
testenv.MustHaveGoBuild(t)
49-
MustHavePerl(t)
50+
buildMu.Lock()
51+
defer buildMu.Unlock()
5052
if built {
5153
return
5254
}
5355
if failed {
5456
t.Skip("cannot run on this environment")
5557
}
58+
testenv.MustHaveGoBuild(t)
59+
MustHavePerl(t)
5660
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", binary)
5761
output, err := cmd.CombinedOutput()
5862
if err != nil {
@@ -83,69 +87,122 @@ func Vet(t *testing.T, files []string) {
8387
// rm testvet
8488
//
8589

90+
// TestVet tests self-contained files in testdata/*.go.
91+
//
92+
// If a file contains assembly or has inter-dependencies, it should be
93+
// in its own test, like TestVetAsm, TestDivergentPackagesExamples,
94+
// etc below.
8695
func TestVet(t *testing.T) {
8796
Build(t)
97+
t.Parallel()
8898

8999
// errchk ./testvet
90100
gos, err := filepath.Glob(filepath.Join(dataDir, "*.go"))
91101
if err != nil {
92102
t.Fatal(err)
93103
}
94-
asms, err := filepath.Glob(filepath.Join(dataDir, "*.s"))
95-
if err != nil {
96-
t.Fatal(err)
104+
wide := runtime.GOMAXPROCS(0)
105+
if wide > len(gos) {
106+
wide = len(gos)
107+
}
108+
batch := make([][]string, wide)
109+
for i, file := range gos {
110+
batch[i%wide] = append(batch[i%wide], file)
111+
}
112+
for i, files := range batch {
113+
files := files
114+
t.Run(fmt.Sprint(i), func(t *testing.T) {
115+
t.Parallel()
116+
t.Logf("files: %q", files)
117+
Vet(t, files)
118+
})
97119
}
98-
files := append(gos, asms...)
99-
Vet(t, files)
100120
}
101121

102-
func TestDivergentPackagesExamples(t *testing.T) {
122+
func TestVetAsm(t *testing.T) {
103123
Build(t)
124+
125+
asmDir := filepath.Join(dataDir, "asm")
126+
gos, err := filepath.Glob(filepath.Join(asmDir, "*.go"))
127+
if err != nil {
128+
t.Fatal(err)
129+
}
130+
asms, err := filepath.Glob(filepath.Join(asmDir, "*.s"))
131+
if err != nil {
132+
t.Fatal(err)
133+
}
134+
135+
t.Parallel()
104136
// errchk ./testvet
105-
Vet(t, []string{"testdata/divergent"})
137+
Vet(t, append(gos, asms...))
106138
}
107139

108-
func TestIncompleteExamples(t *testing.T) {
140+
func TestVetDirs(t *testing.T) {
141+
t.Parallel()
109142
Build(t)
110-
// errchk ./testvet
111-
Vet(t, []string{"testdata/incomplete/examples_test.go"})
143+
for _, dir := range []string{
144+
"testingpkg",
145+
"divergent",
146+
"buildtag",
147+
"incomplete", // incomplete examples
148+
} {
149+
dir := dir
150+
t.Run(dir, func(t *testing.T) {
151+
t.Parallel()
152+
gos, err := filepath.Glob(filepath.Join("testdata", dir, "*.go"))
153+
if err != nil {
154+
t.Fatal(err)
155+
}
156+
Vet(t, gos)
157+
})
158+
}
112159
}
113160

114161
func run(c *exec.Cmd, t *testing.T) bool {
115162
output, err := c.CombinedOutput()
116-
os.Stderr.Write(output)
117163
if err != nil {
164+
t.Logf("vet output:\n%s", output)
118165
t.Fatal(err)
119166
}
120167
// Errchk delights by not returning non-zero status if it finds errors, so we look at the output.
121168
// It prints "BUG" if there is a failure.
122169
if !c.ProcessState.Success() {
170+
t.Logf("vet output:\n%s", output)
123171
return false
124172
}
125-
return !bytes.Contains(output, []byte("BUG"))
173+
ok := !bytes.Contains(output, []byte("BUG"))
174+
if !ok {
175+
t.Logf("vet output:\n%s", output)
176+
}
177+
return ok
126178
}
127179

128180
// TestTags verifies that the -tags argument controls which files to check.
129181
func TestTags(t *testing.T) {
182+
t.Parallel()
130183
Build(t)
131184
for _, tag := range []string{"testtag", "x testtag y", "x,testtag,y"} {
132-
t.Logf("-tags=%s", tag)
133-
args := []string{
134-
"-tags=" + tag,
135-
"-v", // We're going to look at the files it examines.
136-
"testdata/tagtest",
137-
}
138-
cmd := exec.Command("./"+binary, args...)
139-
output, err := cmd.CombinedOutput()
140-
if err != nil {
141-
t.Fatal(err)
142-
}
143-
// file1 has testtag and file2 has !testtag.
144-
if !bytes.Contains(output, []byte(filepath.Join("tagtest", "file1.go"))) {
145-
t.Error("file1 was excluded, should be included")
146-
}
147-
if bytes.Contains(output, []byte(filepath.Join("tagtest", "file2.go"))) {
148-
t.Error("file2 was included, should be excluded")
149-
}
185+
tag := tag
186+
t.Run(tag, func(t *testing.T) {
187+
t.Parallel()
188+
t.Logf("-tags=%s", tag)
189+
args := []string{
190+
"-tags=" + tag,
191+
"-v", // We're going to look at the files it examines.
192+
"testdata/tagtest",
193+
}
194+
cmd := exec.Command("./"+binary, args...)
195+
output, err := cmd.CombinedOutput()
196+
if err != nil {
197+
t.Fatal(err)
198+
}
199+
// file1 has testtag and file2 has !testtag.
200+
if !bytes.Contains(output, []byte(filepath.Join("tagtest", "file1.go"))) {
201+
t.Error("file1 was excluded, should be included")
202+
}
203+
if bytes.Contains(output, []byte(filepath.Join("tagtest", "file2.go"))) {
204+
t.Error("file2 was included, should be excluded")
205+
}
206+
})
150207
}
151208
}

0 commit comments

Comments
 (0)