171 строка
3,7 КиБ
Go
171 строка
3,7 КиБ
Go
package godog
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strconv"
|
|
|
|
"github.com/DATA-DOG/godog/colors"
|
|
)
|
|
|
|
type initializer func(*Suite)
|
|
|
|
type runner struct {
|
|
randomSeed int64
|
|
stopOnFailure bool
|
|
features []*feature
|
|
fmt Formatter
|
|
initializer initializer
|
|
}
|
|
|
|
func (r *runner) concurrent(rate int) (failed bool) {
|
|
queue := make(chan int, rate)
|
|
for i, ft := range r.features {
|
|
queue <- i // reserve space in queue
|
|
go func(fail *bool, feat *feature) {
|
|
defer func() {
|
|
<-queue // free a space in queue
|
|
}()
|
|
if r.stopOnFailure && *fail {
|
|
return
|
|
}
|
|
suite := &Suite{
|
|
fmt: r.fmt,
|
|
randomSeed: r.randomSeed,
|
|
stopOnFailure: r.stopOnFailure,
|
|
features: []*feature{feat},
|
|
}
|
|
r.initializer(suite)
|
|
suite.run()
|
|
if suite.failed {
|
|
*fail = true
|
|
}
|
|
}(&failed, ft)
|
|
}
|
|
// wait until last are processed
|
|
for i := 0; i < rate; i++ {
|
|
queue <- i
|
|
}
|
|
close(queue)
|
|
|
|
// print summary
|
|
r.fmt.Summary()
|
|
return
|
|
}
|
|
|
|
func (r *runner) run() bool {
|
|
suite := &Suite{
|
|
fmt: r.fmt,
|
|
randomSeed: r.randomSeed,
|
|
stopOnFailure: r.stopOnFailure,
|
|
features: r.features,
|
|
}
|
|
r.initializer(suite)
|
|
suite.run()
|
|
|
|
r.fmt.Summary()
|
|
return suite.failed
|
|
}
|
|
|
|
// RunWithOptions is same as Run function, except
|
|
// it uses Options provided in order to run the
|
|
// test suite without parsing flags
|
|
//
|
|
// This method is useful in case if you run
|
|
// godog in for example TestMain function together
|
|
// with go tests
|
|
func RunWithOptions(suite string, contextInitializer func(suite *Suite), opt Options) int {
|
|
var output io.Writer = os.Stdout
|
|
if nil != opt.Output {
|
|
output = opt.Output
|
|
}
|
|
|
|
if opt.NoColors {
|
|
output = colors.Uncolored(output)
|
|
} else {
|
|
output = colors.Colored(output)
|
|
}
|
|
|
|
if opt.ShowStepDefinitions {
|
|
s := &Suite{}
|
|
contextInitializer(s)
|
|
s.printStepDefinitions(output)
|
|
return 0
|
|
}
|
|
|
|
if len(opt.Paths) == 0 {
|
|
inf, err := os.Stat("features")
|
|
if err == nil && inf.IsDir() {
|
|
opt.Paths = []string{"features"}
|
|
}
|
|
}
|
|
|
|
if opt.Concurrency > 1 && !supportsConcurrency(opt.Format) {
|
|
fatal(fmt.Errorf("format \"%s\" does not support concurrent execution", opt.Format))
|
|
}
|
|
formatter, err := findFmt(opt.Format)
|
|
fatal(err)
|
|
|
|
features, err := parseFeatures(opt.Tags, opt.Paths)
|
|
fatal(err)
|
|
|
|
r := runner{
|
|
fmt: formatter(suite, output),
|
|
initializer: contextInitializer,
|
|
features: features,
|
|
randomSeed: opt.Randomize,
|
|
stopOnFailure: opt.StopOnFailure,
|
|
}
|
|
|
|
// store chosen seed in environment, so it could be seen in formatter summary report
|
|
os.Setenv("GODOG_SEED", strconv.FormatInt(r.randomSeed, 10))
|
|
|
|
var failed bool
|
|
if opt.Concurrency > 1 {
|
|
failed = r.concurrent(opt.Concurrency)
|
|
} else {
|
|
failed = r.run()
|
|
}
|
|
if failed && opt.Format != "events" {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// Run creates and runs the feature suite.
|
|
// Reads all configuration options from flags.
|
|
// uses contextInitializer to register contexts
|
|
//
|
|
// the concurrency option allows runner to
|
|
// initialize a number of suites to be run
|
|
// separately. Only progress formatter
|
|
// is supported when concurrency level is
|
|
// higher than 1
|
|
//
|
|
// contextInitializer must be able to register
|
|
// the step definitions and event handlers.
|
|
func Run(suite string, contextInitializer func(suite *Suite)) int {
|
|
var opt Options
|
|
opt.Output = colors.Colored(os.Stdout)
|
|
flagSet := FlagSet(&opt)
|
|
err := flagSet.Parse(os.Args[1:])
|
|
fatal(err)
|
|
|
|
opt.Paths = flagSet.Args()
|
|
|
|
return RunWithOptions(suite, contextInitializer, opt)
|
|
}
|
|
|
|
func supportsConcurrency(format string) bool {
|
|
switch format {
|
|
case "events":
|
|
case "junit":
|
|
case "pretty":
|
|
case "cucumber":
|
|
default:
|
|
return true // supports concurrency
|
|
}
|
|
|
|
return true // all custom formatters are treated as supporting concurrency
|
|
}
|