bump(github.com/onsi/gingko):bb93381d543b0e5725244abe752214a110791d01

Adds support for extracting stdout and stderr from failed tests runs
into junit, which makes junit more effective for debugging failures.
This commit is contained in:
Clayton Coleman
2017-02-22 23:58:02 -05:00
parent 452420484c
commit 4e24e82b13
35 changed files with 1396 additions and 131 deletions

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
@@ -15,11 +16,15 @@ import (
)
func BuildBootstrapCommand() *Command {
var agouti, noDot, internal bool
var (
agouti, noDot, internal bool
customBootstrapFile string
)
flagSet := flag.NewFlagSet("bootstrap", flag.ExitOnError)
flagSet.BoolVar(&agouti, "agouti", false, "If set, bootstrap will generate a bootstrap file for writing Agouti tests")
flagSet.BoolVar(&noDot, "nodot", false, "If set, bootstrap will generate a bootstrap file that does not . import ginkgo and gomega")
flagSet.BoolVar(&internal, "internal", false, "If set, generate will generate a test file that uses the regular package name")
flagSet.StringVar(&customBootstrapFile, "template", "", "If specified, generate will use the contents of the file passed as the bootstrap template")
return &Command{
Name: "bootstrap",
@@ -30,7 +35,7 @@ func BuildBootstrapCommand() *Command {
"Accepts the following flags:",
},
Command: func(args []string, additionalArgs []string) {
generateBootstrap(agouti, noDot, internal)
generateBootstrap(agouti, noDot, internal, customBootstrapFile)
},
}
}
@@ -132,7 +137,7 @@ func fileExists(path string) bool {
return false
}
func generateBootstrap(agouti, noDot, internal bool) {
func generateBootstrap(agouti, noDot, internal bool, customBootstrapFile string) {
packageName, bootstrapFilePrefix, formattedName := getPackageAndFormattedName()
data := bootstrapData{
Package: determinePackageName(packageName, internal),
@@ -162,7 +167,13 @@ func generateBootstrap(agouti, noDot, internal bool) {
defer f.Close()
var templateText string
if agouti {
if customBootstrapFile != "" {
tpl, err := ioutil.ReadFile(customBootstrapFile)
if err != nil {
panic(err.Error())
}
templateText = string(tpl)
} else if agouti {
templateText = agoutiBootstrapText
} else {
templateText = bootstrapText

View File

@@ -46,7 +46,7 @@ func (r *SpecBuilder) BuildSpecs(args []string, additionalArgs []string) {
passed := true
for _, suite := range suites {
runner := testrunner.New(suite, 1, false, r.commandFlags.Race, r.commandFlags.Cover, r.commandFlags.CoverPkg, r.commandFlags.Tags, r.commandFlags.GCFlags, nil)
runner := testrunner.New(suite, 1, false, r.commandFlags.GoOpts, nil)
fmt.Printf("Compiling %s...\n", suite.PackageName)
path, _ := filepath.Abs(filepath.Join(suite.Path, fmt.Sprintf("%s.test", suite.PackageName)))

View File

@@ -34,7 +34,7 @@ func BuildGenerateCommand() *Command {
var specText = `package {{.Package}}
import (
. "{{.PackageImportPath}}"
{{if .DotImportPackage}}. "{{.PackageImportPath}}"{{end}}
{{if .IncludeImports}}. "github.com/onsi/ginkgo"{{end}}
{{if .IncludeImports}}. "github.com/onsi/gomega"{{end}}
@@ -48,7 +48,7 @@ var _ = Describe("{{.Subject}}", func() {
var agoutiSpecText = `package {{.Package}}_test
import (
. "{{.PackageImportPath}}"
{{if .DotImportPackage}}. "{{.PackageImportPath}}"{{end}}
{{if .IncludeImports}}. "github.com/onsi/ginkgo"{{end}}
{{if .IncludeImports}}. "github.com/onsi/gomega"{{end}}
@@ -76,6 +76,7 @@ type specData struct {
Subject string
PackageImportPath string
IncludeImports bool
DotImportPackage bool
}
func generateSpec(args []string, agouti, noDot, internal bool) {
@@ -118,6 +119,7 @@ func generateSpecForSubject(subject string, agouti, noDot, internal bool) error
Subject: formattedName,
PackageImportPath: getPackageImportPath(),
IncludeImports: !noDot,
DotImportPackage: !internal,
}
targetFile := fmt.Sprintf("%s_test.go", specFilePrefix)

View File

@@ -234,7 +234,7 @@ func complainAndQuit(complaint string) {
os.Exit(1)
}
func findSuites(args []string, recurse bool, skipPackage string, allowPrecompiled bool) ([]testsuite.TestSuite, []string) {
func findSuites(args []string, recurseForAll bool, skipPackage string, allowPrecompiled bool) ([]testsuite.TestSuite, []string) {
suites := []testsuite.TestSuite{}
if len(args) > 0 {
@@ -246,10 +246,15 @@ func findSuites(args []string, recurse bool, skipPackage string, allowPrecompile
continue
}
}
suites = append(suites, testsuite.SuitesInDir(arg, recurse)...)
recurseForSuite := recurseForAll
if strings.HasSuffix(arg, "/...") && arg != "/..." {
arg = arg[:len(arg)-4]
recurseForSuite = true
}
suites = append(suites, testsuite.SuitesInDir(arg, recurseForSuite)...)
}
} else {
suites = testsuite.SuitesInDir(".", recurse)
suites = testsuite.SuitesInDir(".", recurseForAll)
}
skippedPackages := []string{}

View File

@@ -71,7 +71,7 @@ func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) {
runners := []*testrunner.TestRunner{}
for _, suite := range suites {
runners = append(runners, testrunner.New(suite, r.commandFlags.NumCPU, r.commandFlags.ParallelStream, r.commandFlags.Race, r.commandFlags.Cover, r.commandFlags.CoverPkg, r.commandFlags.Tags, r.commandFlags.GCFlags, additionalArgs))
runners = append(runners, testrunner.New(suite, r.commandFlags.NumCPU, r.commandFlags.ParallelStream, r.commandFlags.GoOpts, additionalArgs))
}
numSuites := 0

View File

@@ -9,12 +9,8 @@ import (
type RunWatchAndBuildCommandFlags struct {
Recurse bool
Race bool
Cover bool
CoverPkg string
SkipPackage string
Tags string
GCFlags string
GoOpts map[string]interface{}
//for run and watch commands
NumCPU int
@@ -88,16 +84,57 @@ func (c *RunWatchAndBuildCommandFlags) computeNodes() {
}
}
func (c *RunWatchAndBuildCommandFlags) stringSlot(slot string) *string {
var opt string
c.GoOpts[slot] = &opt
return &opt
}
func (c *RunWatchAndBuildCommandFlags) boolSlot(slot string) *bool {
var opt bool
c.GoOpts[slot] = &opt
return &opt
}
func (c *RunWatchAndBuildCommandFlags) intSlot(slot string) *int {
var opt int
c.GoOpts[slot] = &opt
return &opt
}
func (c *RunWatchAndBuildCommandFlags) flags(mode int) {
c.GoOpts = make(map[string]interface{})
onWindows := (runtime.GOOS == "windows")
c.FlagSet.BoolVar(&(c.Recurse), "r", false, "Find and run test suites under the current directory recursively")
c.FlagSet.BoolVar(&(c.Race), "race", false, "Run tests with race detection enabled")
c.FlagSet.BoolVar(&(c.Cover), "cover", false, "Run tests with coverage analysis, will generate coverage profiles with the package name in the current directory")
c.FlagSet.StringVar(&(c.CoverPkg), "coverpkg", "", "Run tests with coverage on the given external modules")
c.FlagSet.BoolVar(&(c.Recurse), "r", false, "Find and run test suites under the current directory recursively.")
c.FlagSet.BoolVar(c.boolSlot("race"), "race", false, "Run tests with race detection enabled.")
c.FlagSet.BoolVar(c.boolSlot("cover"), "cover", false, "Run tests with coverage analysis, will generate coverage profiles with the package name in the current directory.")
c.FlagSet.StringVar(c.stringSlot("coverpkg"), "coverpkg", "", "Run tests with coverage on the given external modules.")
c.FlagSet.StringVar(&(c.SkipPackage), "skipPackage", "", "A comma-separated list of package names to be skipped. If any part of the package's path matches, that package is ignored.")
c.FlagSet.StringVar(&(c.Tags), "tags", "", "A list of build tags to consider satisfied during the build")
c.FlagSet.StringVar(&(c.GCFlags), "gcflags", "", "Arguments to pass on each go tool compile invocation.")
c.FlagSet.StringVar(c.stringSlot("tags"), "tags", "", "A list of build tags to consider satisfied during the build.")
c.FlagSet.StringVar(c.stringSlot("gcflags"), "gcflags", "", "Arguments to pass on each go tool compile invocation.")
c.FlagSet.StringVar(c.stringSlot("covermode"), "covermode", "", "Set the mode for coverage analysis.")
c.FlagSet.BoolVar(c.boolSlot("a"), "a", false, "Force rebuilding of packages that are already up-to-date.")
c.FlagSet.BoolVar(c.boolSlot("n"), "n", false, "Have `go test` print the commands but do not run them.")
c.FlagSet.BoolVar(c.boolSlot("msan"), "msan", false, "Enable interoperation with memory sanitizer.")
c.FlagSet.BoolVar(c.boolSlot("x"), "x", false, "Have `go test` print the commands.")
c.FlagSet.BoolVar(c.boolSlot("work"), "work", false, "Print the name of the temporary work directory and do not delete it when exiting.")
c.FlagSet.StringVar(c.stringSlot("asmflags"), "asmflags", "", "Arguments to pass on each go tool asm invocation.")
c.FlagSet.StringVar(c.stringSlot("buildmode"), "buildmode", "", "Build mode to use. See 'go help buildmode' for more.")
c.FlagSet.StringVar(c.stringSlot("compiler"), "compiler", "", "Name of compiler to use, as in runtime.Compiler (gccgo or gc).")
c.FlagSet.StringVar(c.stringSlot("gccgoflags"), "gccgoflags", "", "Arguments to pass on each gccgo compiler/linker invocation.")
c.FlagSet.StringVar(c.stringSlot("installsuffix"), "installsuffix", "", "A suffix to use in the name of the package installation directory.")
c.FlagSet.StringVar(c.stringSlot("ldflags"), "ldflags", "", "Arguments to pass on each go tool link invocation.")
c.FlagSet.BoolVar(c.boolSlot("linkshared"), "linkshared", false, "Link against shared libraries previously created with -buildmode=shared.")
c.FlagSet.StringVar(c.stringSlot("pkgdir"), "pkgdir", "", "install and load all packages from the given dir instead of the usual locations.")
c.FlagSet.StringVar(c.stringSlot("toolexec"), "toolexec", "", "a program to use to invoke toolchain programs like vet and asm.")
c.FlagSet.IntVar(c.intSlot("blockprofilerate"), "blockprofilerate", 1, "Control the detail provided in goroutine blocking profiles by calling runtime.SetBlockProfileRate with the given value.")
c.FlagSet.StringVar(c.stringSlot("coverprofile"), "coverprofile", "", "Write a coverage profile to the specified file after all tests have passed.")
c.FlagSet.StringVar(c.stringSlot("cpuprofile"), "cpuprofile", "", "Write a CPU profile to the specified file before exiting.")
c.FlagSet.StringVar(c.stringSlot("memprofile"), "memprofile", "", "Write a memory profile to the specified file after all tests have passed.")
c.FlagSet.IntVar(c.intSlot("memprofilerate"), "memprofilerate", 0, "Enable more precise (and expensive) memory profiles by setting runtime.MemProfileRate.")
c.FlagSet.StringVar(c.stringSlot("outputdir"), "outputdir", "", "Place output files from profiling in the specified directory.")
if mode == runMode || mode == watchMode {
config.Flags(c.FlagSet, "", false)

View File

@@ -9,6 +9,7 @@ import (
"github.com/onsi/ginkgo/ginkgo/interrupthandler"
"github.com/onsi/ginkgo/ginkgo/testrunner"
"github.com/onsi/ginkgo/ginkgo/testsuite"
colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable"
)
type compilationInput struct {
@@ -166,7 +167,7 @@ func (r *SuiteRunner) listFailedSuites(suitesThatFailed []testsuite.TestSuite) {
if config.DefaultReporterConfig.NoColor {
fmt.Printf("\t"+packageNameFormatter+" %s\n", suite.PackageName, suite.Path)
} else {
fmt.Printf("\t%s"+packageNameFormatter+"%s %s%s%s\n", redColor, suite.PackageName, defaultStyle, lightGrayColor, suite.Path, defaultStyle)
fmt.Fprintf(colorable.NewColorableStdout(), "\t%s"+packageNameFormatter+"%s %s%s%s\n", redColor, suite.PackageName, defaultStyle, lightGrayColor, suite.Path, defaultStyle)
}
}
}

View File

@@ -29,25 +29,17 @@ type TestRunner struct {
numCPU int
parallelStream bool
race bool
cover bool
coverPkg string
tags string
gcFlags string
goOpts map[string]interface{}
additionalArgs []string
}
func New(suite testsuite.TestSuite, numCPU int, parallelStream bool, race bool, cover bool, coverPkg string, tags string, gcFlags string, additionalArgs []string) *TestRunner {
func New(suite testsuite.TestSuite, numCPU int, parallelStream bool, goOpts map[string]interface{}, additionalArgs []string) *TestRunner {
runner := &TestRunner{
Suite: suite,
numCPU: numCPU,
parallelStream: parallelStream,
race: race,
cover: cover,
coverPkg: coverPkg,
tags: tags,
goOpts: goOpts,
additionalArgs: additionalArgs,
gcFlags: gcFlags,
}
if !suite.Precompiled {
@@ -65,6 +57,70 @@ func (t *TestRunner) Compile() error {
return t.CompileTo(t.compilationTargetPath)
}
func (t *TestRunner) BuildArgs(path string) []string {
args := []string{"test", "-c", "-i", "-o", path, t.Suite.Path}
if *t.goOpts["covermode"].(*string) != "" {
args = append(args, "-cover", fmt.Sprintf("-covermode=%s", *t.goOpts["covermode"].(*string)))
} else {
if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" {
args = append(args, "-cover", "-covermode=atomic")
}
}
boolOpts := []string{
"a",
"n",
"msan",
"race",
"x",
"work",
"linkshared",
}
for _, opt := range boolOpts {
if s, found := t.goOpts[opt].(*bool); found && *s {
args = append(args, fmt.Sprintf("-%s", opt))
}
}
intOpts := []string{
"memprofilerate",
"blockprofilerate",
}
for _, opt := range intOpts {
if s, found := t.goOpts[opt].(*int); found {
args = append(args, fmt.Sprintf("-%s=%d", opt, *s))
}
}
stringOpts := []string{
"asmflags",
"buildmode",
"compiler",
"gccgoflags",
"installsuffix",
"ldflags",
"pkgdir",
"toolexec",
"coverprofile",
"cpuprofile",
"memprofile",
"outputdir",
"coverpkg",
"tags",
"gcflags",
}
for _, opt := range stringOpts {
if s, found := t.goOpts[opt].(*string); found && *s != "" {
args = append(args, fmt.Sprintf("-%s=%s", opt, *s))
}
}
return args
}
func (t *TestRunner) CompileTo(path string) error {
if t.compiled {
return nil
@@ -74,23 +130,7 @@ func (t *TestRunner) CompileTo(path string) error {
return nil
}
args := []string{"test", "-c", "-i", "-o", path, t.Suite.Path}
if t.race {
args = append(args, "-race")
}
if t.cover || t.coverPkg != "" {
args = append(args, "-cover", "-covermode=atomic")
}
if t.coverPkg != "" {
args = append(args, fmt.Sprintf("-coverpkg=%s", t.coverPkg))
}
if t.tags != "" {
args = append(args, fmt.Sprintf("-tags=%s", t.tags))
}
if t.gcFlags != "" {
args = append(args, fmt.Sprintf("-gcflags=%s", t.gcFlags))
}
args := t.BuildArgs(path)
cmd := exec.Command("go", args...)
output, err := cmd.CombinedOutput()
@@ -189,6 +229,7 @@ fixCompilationOutput..... rewrites the output to fix the paths.
yeah......
*/
func fixCompilationOutput(output string, relToPath string) string {
relToPath = filepath.Join(relToPath)
re := regexp.MustCompile(`^(\S.*\.go)\:\d+\:`)
lines := strings.Split(output, "\n")
for i, line := range lines {
@@ -198,8 +239,10 @@ func fixCompilationOutput(output string, relToPath string) string {
}
path := line[indices[2]:indices[3]]
path = filepath.Join(relToPath, path)
lines[i] = path + line[indices[3]:]
if filepath.Dir(path) != relToPath {
path = filepath.Join(relToPath, path)
lines[i] = path + line[indices[3]:]
}
}
return strings.Join(lines, "\n")
}
@@ -281,7 +324,7 @@ func (t *TestRunner) runAndStreamParallelGinkgoSuite() RunResult {
os.Stdout.Sync()
if t.cover || t.coverPkg != "" {
if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" || *t.goOpts["covermode"].(*string) != "" {
t.combineCoverprofiles()
}
@@ -294,7 +337,7 @@ func (t *TestRunner) runParallelGinkgoSuite() RunResult {
writers := make([]*logWriter, t.numCPU)
reports := make([]*bytes.Buffer, t.numCPU)
stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor)
stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1)
aggregator := remote.NewAggregator(t.numCPU, result, config.DefaultReporterConfig, stenographer)
server, err := remote.NewServer(t.numCPU)
@@ -363,7 +406,7 @@ func (t *TestRunner) runParallelGinkgoSuite() RunResult {
os.Stdout.Sync()
}
if t.cover || t.coverPkg != "" {
if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" || *t.goOpts["covermode"].(*string) != "" {
t.combineCoverprofiles()
}
@@ -372,7 +415,7 @@ func (t *TestRunner) runParallelGinkgoSuite() RunResult {
func (t *TestRunner) cmd(ginkgoArgs []string, stream io.Writer, node int) *exec.Cmd {
args := []string{"--test.timeout=24h"}
if t.cover || t.coverPkg != "" {
if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" || *t.goOpts["covermode"].(*string) != "" {
coverprofile := "--test.coverprofile=" + t.Suite.PackageName + ".coverprofile"
if t.numCPU > 1 {
coverprofile = fmt.Sprintf("%s.%d", coverprofile, node)

View File

@@ -10,6 +10,7 @@ import (
"github.com/onsi/ginkgo/ginkgo/testrunner"
"github.com/onsi/ginkgo/ginkgo/testsuite"
"github.com/onsi/ginkgo/ginkgo/watch"
colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable"
)
func BuildWatchCommand() *Command {
@@ -57,7 +58,7 @@ func (w *SpecWatcher) runnersForSuites(suites []testsuite.TestSuite, additionalA
runners := []*testrunner.TestRunner{}
for _, suite := range suites {
runners = append(runners, testrunner.New(suite, w.commandFlags.NumCPU, w.commandFlags.ParallelStream, w.commandFlags.Race, w.commandFlags.Cover, w.commandFlags.CoverPkg, w.commandFlags.Tags, w.commandFlags.GCFlags, additionalArgs))
runners = append(runners, testrunner.New(suite, w.commandFlags.NumCPU, w.commandFlags.ParallelStream, w.commandFlags.GoOpts, additionalArgs))
}
return runners
@@ -96,29 +97,30 @@ func (w *SpecWatcher) WatchSuites(args []string, additionalArgs []string) {
case <-ticker.C:
suites, _ := findSuites(args, w.commandFlags.Recurse, w.commandFlags.SkipPackage, false)
delta, _ := deltaTracker.Delta(suites)
coloredStream := colorable.NewColorableStdout()
suitesToRun := []testsuite.TestSuite{}
if len(delta.NewSuites) > 0 {
fmt.Printf(greenColor+"Detected %d new %s:\n"+defaultStyle, len(delta.NewSuites), pluralizedWord("suite", "suites", len(delta.NewSuites)))
fmt.Fprintf(coloredStream, greenColor+"Detected %d new %s:\n"+defaultStyle, len(delta.NewSuites), pluralizedWord("suite", "suites", len(delta.NewSuites)))
for _, suite := range delta.NewSuites {
suitesToRun = append(suitesToRun, suite.Suite)
fmt.Println(" " + suite.Description())
fmt.Fprintln(coloredStream, " "+suite.Description())
}
}
modifiedSuites := delta.ModifiedSuites()
if len(modifiedSuites) > 0 {
fmt.Println(greenColor + "\nDetected changes in:" + defaultStyle)
fmt.Fprintln(coloredStream, greenColor+"\nDetected changes in:"+defaultStyle)
for _, pkg := range delta.ModifiedPackages {
fmt.Println(" " + pkg)
fmt.Fprintln(coloredStream, " "+pkg)
}
fmt.Printf(greenColor+"Will run %d %s:\n"+defaultStyle, len(modifiedSuites), pluralizedWord("suite", "suites", len(modifiedSuites)))
fmt.Fprintf(coloredStream, greenColor+"Will run %d %s:\n"+defaultStyle, len(modifiedSuites), pluralizedWord("suite", "suites", len(modifiedSuites)))
for _, suite := range modifiedSuites {
suitesToRun = append(suitesToRun, suite.Suite)
fmt.Println(" " + suite.Description())
fmt.Fprintln(coloredStream, " "+suite.Description())
}
fmt.Println("")
fmt.Fprintln(coloredStream, "")
}
if len(suitesToRun) > 0 {
@@ -136,7 +138,7 @@ func (w *SpecWatcher) WatchSuites(args []string, additionalArgs []string) {
if result.Passed {
color = greenColor
}
fmt.Println(color + "\nDone. Resuming watch..." + defaultStyle)
fmt.Fprintln(coloredStream, color+"\nDone. Resuming watch..."+defaultStyle)
}
}