mirror of
https://github.com/golang/go
synced 2024-11-24 08:00:12 -07:00
5451fff475
The tests in doc/progs appear to have been originally written for use with the old test driver. At some later point, they acquired their own test driver. Both ran tests in serial. This CL rewrites the current test driver in Go, runs tests concurrently, and cleans up historical artifacts from the old drivers. The primary motivation is to speed up all.bash. On my laptop, using tip, this CL reduces doc/progs test wall time from 26s to 7s. The savings will remain even when the compiler gets faster. Using Go 1.4, this CL reduces test wall time from 15s to 4s. Change-Id: Iae945a8490222beee76e8a2118a0d7956092f543 Reviewed-on: https://go-review.googlesource.com/8410 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
221 lines
4.7 KiB
Go
Executable File
221 lines
4.7 KiB
Go
Executable File
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// run runs the docs tests found in this directory.
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
const usage = `go run run.go [tests]
|
|
|
|
run.go runs the docs tests in this directory.
|
|
If no tests are provided, it runs all tests.
|
|
Tests may be specified without their .go suffix.
|
|
`
|
|
|
|
func main() {
|
|
flag.Usage = func() {
|
|
fmt.Fprintf(os.Stderr, usage)
|
|
flag.PrintDefaults()
|
|
os.Exit(2)
|
|
}
|
|
|
|
flag.Parse()
|
|
if flag.NArg() == 0 {
|
|
// run all tests
|
|
fixcgo()
|
|
} else {
|
|
// run specified tests
|
|
onlyTest(flag.Args()...)
|
|
}
|
|
|
|
// ratec limits the number of tests running concurrently.
|
|
// None of the tests are intensive, so don't bother
|
|
// trying to manually adjust for slow builders.
|
|
ratec := make(chan bool, runtime.NumCPU())
|
|
errc := make(chan error, len(tests))
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
ratec <- true
|
|
go func() {
|
|
errc <- test(tt.file, tt.want)
|
|
<-ratec
|
|
}()
|
|
}
|
|
|
|
var rc int
|
|
for range tests {
|
|
if err := <-errc; err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
rc = 1
|
|
}
|
|
}
|
|
os.Exit(rc)
|
|
}
|
|
|
|
// test builds the test in the given file.
|
|
// If want is non-empty, test also runs the test
|
|
// and checks that the output matches the regexp want.
|
|
func test(file, want string) error {
|
|
// Build the program.
|
|
cmd := exec.Command("go", "build", file+".go")
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("go build %s.go failed: %v\nOutput:\n%s", file, err, out)
|
|
}
|
|
defer os.Remove(file)
|
|
|
|
// Only run the test if we have output to check.
|
|
if want == "" {
|
|
return nil
|
|
}
|
|
|
|
cmd = exec.Command("./" + file)
|
|
out, err = cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("./%s failed: %v\nOutput:\n%s", file, err, out)
|
|
}
|
|
|
|
// Canonicalize output.
|
|
out = bytes.TrimRight(out, "\n")
|
|
out = bytes.Replace(out, []byte{'\n'}, []byte{' '}, -1)
|
|
|
|
// Check the result.
|
|
match, err := regexp.Match(want, out)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse regexp %q: %v", want, err)
|
|
}
|
|
if !match {
|
|
return fmt.Errorf("%s.go:\n%q\ndoes not match %s", file, out, want)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type testcase struct {
|
|
file string
|
|
want string
|
|
}
|
|
|
|
var tests = []testcase{
|
|
// defer_panic_recover
|
|
{"defer", `^0 3210 2$`},
|
|
{"defer2", `^Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f.$`},
|
|
|
|
// effective_go
|
|
{"eff_bytesize", `^1.00YB 9.09TB$`},
|
|
{"eff_qr", ""},
|
|
{"eff_sequence", `^\[-1 2 6 16 44\]$`},
|
|
{"eff_unused2", ""},
|
|
|
|
// error_handling
|
|
{"error", ""},
|
|
{"error2", ""},
|
|
{"error3", ""},
|
|
{"error4", ""},
|
|
|
|
// law_of_reflection
|
|
{"interface", ""},
|
|
{"interface2", `^type: float64$`},
|
|
|
|
// c_go_cgo
|
|
{"cgo1", ""},
|
|
{"cgo2", ""},
|
|
{"cgo3", ""},
|
|
{"cgo4", ""},
|
|
|
|
// timeout
|
|
{"timeout1", ""},
|
|
{"timeout2", ""},
|
|
|
|
// gobs
|
|
{"gobs1", ""},
|
|
{"gobs2", ""},
|
|
|
|
// json
|
|
{"json1", `^$`},
|
|
{"json2", `the reciprocal of i is`},
|
|
{"json3", `Age is int 6`},
|
|
{"json4", `^$`},
|
|
{"json5", ""},
|
|
|
|
// image_package
|
|
{"image_package1", `^X is 2 Y is 1$`},
|
|
{"image_package2", `^3 4 false$`},
|
|
{"image_package3", `^3 4 true$`},
|
|
{"image_package4", `^image.Point{X:2, Y:1}$`},
|
|
{"image_package5", `^{255 0 0 255}$`},
|
|
{"image_package6", `^8 4 true$`},
|
|
|
|
// other
|
|
{"go1", `^Christmas is a holiday: true Sleeping for 0.123s.*go1.go already exists$`},
|
|
{"slices", ""},
|
|
}
|
|
|
|
func onlyTest(files ...string) {
|
|
var new []testcase
|
|
NextFile:
|
|
for _, file := range files {
|
|
file = strings.TrimSuffix(file, ".go")
|
|
for _, tt := range tests {
|
|
if tt.file == file {
|
|
new = append(new, tt)
|
|
continue NextFile
|
|
}
|
|
}
|
|
fmt.Fprintf(os.Stderr, "test %s.go not found\n", file)
|
|
os.Exit(1)
|
|
}
|
|
tests = new
|
|
}
|
|
|
|
func skipTest(file string) {
|
|
for i, tt := range tests {
|
|
if tt.file == file {
|
|
copy(tests[i:], tests[i+1:])
|
|
tests = tests[:len(tests)-1]
|
|
return
|
|
}
|
|
}
|
|
panic("delete(" + file + "): not found")
|
|
}
|
|
|
|
func fixcgo() {
|
|
if os.Getenv("CGO_ENABLED") != "1" {
|
|
skipTest("cgo1")
|
|
skipTest("cgo2")
|
|
skipTest("cgo3")
|
|
skipTest("cgo4")
|
|
return
|
|
}
|
|
|
|
switch runtime.GOOS {
|
|
case "freebsd":
|
|
// cgo1 and cgo2 don't run on freebsd, srandom has a different signature
|
|
skipTest("cgo1")
|
|
skipTest("cgo2")
|
|
case "netbsd":
|
|
// cgo1 and cgo2 don't run on netbsd, srandom has a different signature
|
|
skipTest("cgo1")
|
|
skipTest("cgo2")
|
|
// cgo3 and cgo4 don't run on netbsd, since cgo cannot handle stdout correctly
|
|
skipTest("cgo3")
|
|
skipTest("cgo4")
|
|
case "openbsd":
|
|
// cgo3 and cgo4 don't run on openbsd and solaris, since cgo cannot handle stdout correctly
|
|
skipTest("cgo3")
|
|
skipTest("cgo4")
|
|
}
|
|
}
|