mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
testing: introduce testing/internal/testdeps for holding testmain dependencies
Currently, we don't have package testing to import package regexp directly,
because then regexp can't have internal tests (or at least they become more
difficult to write), for fear of an import cycle. The solution we've been using
is for the generated test main package (pseudo-import path "testmain", package main)
to import regexp and pass in a matchString function for use by testing when
implementing the -run flags. This lets testing use regexp but without depending
on regexp and creating unnecessary cycles.
We want to add a few dependencies to runtime/pprof, notably regexp
but also compress/gzip, without causing those packages to have to work
hard to write internal tests.
Restructure the (dare I say it) dependency injection of regexp.MatchString
to be more general, and use it for the runtime/pprof functionality in addition
to the regexp functionality. The new package testing/internal/testdeps is
the root for the testing dependencies handled this way.
Code using testing.MainStart will have to change from passing in a matchString
implementation to passing in testdeps.TestDeps{}. Users of 'go test' don't do this,
but other build systems that have recreated 'go test' (for example, Blaze/Bazel)
may need to be updated. The new testdeps setup should make future updates
unnecessary, but even so we keep the comment about MainStart not being
subject to Go 1 compatibility.
Change-Id: Iec821d2afde10c79f95f3b23de5e71b219f47b92
Reviewed-on: https://go-review.googlesource.com/32455
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
5ad3bd99b5
commit
c56cc9b3b5
6 changed files with 166 additions and 91 deletions
|
|
@ -204,13 +204,13 @@ package testing
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"runtime/pprof"
|
||||
"runtime/trace"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -739,29 +739,57 @@ func (c *testContext) release() {
|
|||
c.startParallel <- true // Pick a waiting test to be run.
|
||||
}
|
||||
|
||||
// An internal function but exported because it is cross-package; part of the implementation
|
||||
// of the "go test" command.
|
||||
// No one should be using func Main anymore.
|
||||
// See the doc comment on func Main and use MainStart instead.
|
||||
var errMain = errors.New("testing: unexpected use of func Main")
|
||||
|
||||
type matchStringOnly func(pat, str string) (bool, error)
|
||||
|
||||
func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
|
||||
func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
|
||||
func (f matchStringOnly) StopCPUProfile() {}
|
||||
func (f matchStringOnly) WriteHeapProfile(w io.Writer) error { return errMain }
|
||||
func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
|
||||
|
||||
// Main is an internal function, part of the implementation of the "go test" command.
|
||||
// It was exported because it is cross-package and predates "internal" packages.
|
||||
// It is no longer used by "go test" but preserved, as much as possible, for other
|
||||
// systems that simulate "go test" using Main, but Main sometimes cannot be updated as
|
||||
// new functionality is added to the testing package.
|
||||
// Systems simulating "go test" should be updated to use MainStart.
|
||||
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
|
||||
os.Exit(MainStart(matchString, tests, benchmarks, examples).Run())
|
||||
os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, examples).Run())
|
||||
}
|
||||
|
||||
// M is a type passed to a TestMain function to run the actual tests.
|
||||
type M struct {
|
||||
matchString func(pat, str string) (bool, error)
|
||||
tests []InternalTest
|
||||
benchmarks []InternalBenchmark
|
||||
examples []InternalExample
|
||||
deps testDeps
|
||||
tests []InternalTest
|
||||
benchmarks []InternalBenchmark
|
||||
examples []InternalExample
|
||||
}
|
||||
|
||||
// testDeps is an internal interface of functionality that is
|
||||
// passed into this package by a test's generated main package.
|
||||
// The canonical implementation of this interface is
|
||||
// testing/internal/testdeps's TestDeps.
|
||||
type testDeps interface {
|
||||
MatchString(pat, str string) (bool, error)
|
||||
StartCPUProfile(io.Writer) error
|
||||
StopCPUProfile()
|
||||
WriteHeapProfile(io.Writer) error
|
||||
WriteProfileTo(string, io.Writer, int) error
|
||||
}
|
||||
|
||||
// MainStart is meant for use by tests generated by 'go test'.
|
||||
// It is not meant to be called directly and is not subject to the Go 1 compatibility document.
|
||||
// It may change signature from release to release.
|
||||
func MainStart(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
|
||||
func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
|
||||
return &M{
|
||||
matchString: matchString,
|
||||
tests: tests,
|
||||
benchmarks: benchmarks,
|
||||
examples: examples,
|
||||
deps: deps,
|
||||
tests: tests,
|
||||
benchmarks: benchmarks,
|
||||
examples: examples,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -774,22 +802,22 @@ func (m *M) Run() int {
|
|||
|
||||
parseCpuList()
|
||||
|
||||
before()
|
||||
m.before()
|
||||
startAlarm()
|
||||
haveExamples = len(m.examples) > 0
|
||||
testRan, testOk := runTests(m.matchString, m.tests)
|
||||
exampleRan, exampleOk := runExamples(m.matchString, m.examples)
|
||||
testRan, testOk := runTests(m.deps.MatchString, m.tests)
|
||||
exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
|
||||
if !testRan && !exampleRan && *matchBenchmarks == "" {
|
||||
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
|
||||
}
|
||||
if !testOk || !exampleOk || !runBenchmarks(m.matchString, m.benchmarks) {
|
||||
if !testOk || !exampleOk || !runBenchmarks(m.deps.MatchString, m.benchmarks) {
|
||||
fmt.Println("FAIL")
|
||||
after()
|
||||
m.after()
|
||||
return 1
|
||||
}
|
||||
|
||||
fmt.Println("PASS")
|
||||
after()
|
||||
m.after()
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
@ -850,7 +878,7 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT
|
|||
}
|
||||
|
||||
// before runs before all testing.
|
||||
func before() {
|
||||
func (m *M) before() {
|
||||
if *memProfileRate > 0 {
|
||||
runtime.MemProfileRate = *memProfileRate
|
||||
}
|
||||
|
|
@ -860,7 +888,7 @@ func before() {
|
|||
fmt.Fprintf(os.Stderr, "testing: %s", err)
|
||||
return
|
||||
}
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
if err := m.deps.StartCPUProfile(f); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err)
|
||||
f.Close()
|
||||
return
|
||||
|
|
@ -893,9 +921,9 @@ func before() {
|
|||
}
|
||||
|
||||
// after runs after all testing.
|
||||
func after() {
|
||||
func (m *M) after() {
|
||||
if *cpuProfile != "" {
|
||||
pprof.StopCPUProfile() // flushes profile to disk
|
||||
m.deps.StopCPUProfile() // flushes profile to disk
|
||||
}
|
||||
if *traceFile != "" {
|
||||
trace.Stop() // flushes trace to disk
|
||||
|
|
@ -907,7 +935,7 @@ func after() {
|
|||
os.Exit(2)
|
||||
}
|
||||
runtime.GC() // materialize all statistics
|
||||
if err = pprof.WriteHeapProfile(f); err != nil {
|
||||
if err = m.deps.WriteHeapProfile(f); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
|
@ -919,7 +947,7 @@ func after() {
|
|||
fmt.Fprintf(os.Stderr, "testing: %s\n", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
if err = pprof.Lookup("block").WriteTo(f, 0); err != nil {
|
||||
if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
|
@ -931,7 +959,7 @@ func after() {
|
|||
fmt.Fprintf(os.Stderr, "testing: %s\n", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
if err = pprof.Lookup("mutex").WriteTo(f, 0); err != nil {
|
||||
if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue