From abc6b65c1cecb69dda766cd8a8b9ecd8a19f21b7 Mon Sep 17 00:00:00 2001 From: gedi Date: Thu, 16 Jun 2016 12:01:58 +0300 Subject: [PATCH] sort feature files by path when executing, separate the concurrent runner --- features/load.feature | 2 +- run.go | 44 ++++++++++++++++++++++++++++++------------- suite.go | 8 ++++++++ utils.go | 2 +- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/features/load.feature b/features/load.feature index f7752b5..ac434a1 100644 --- a/features/load.feature +++ b/features/load.feature @@ -42,6 +42,6 @@ Feature: load features When I parse features Then I should have 2 feature files: """ - features/load.feature features/events.feature + features/load.feature """ diff --git a/run.go b/run.go index 9e11709..4f32573 100644 --- a/run.go +++ b/run.go @@ -3,29 +3,24 @@ package godog import ( "fmt" "os" - "sync" ) type initializer func(*Suite) type runner struct { - sync.WaitGroup - - semaphore chan int stopOnFailure bool features []*feature fmt Formatter // needs to support concurrency initializer initializer } -func (r *runner) run() (failed bool) { - r.Add(len(r.features)) - for _, ft := range r.features { +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) { - r.semaphore <- 1 defer func() { - r.Done() - <-r.semaphore + <-queue // free a space in queue }() if r.stopOnFailure && *fail { return @@ -42,12 +37,30 @@ func (r *runner) run() (failed bool) { } }(&failed, ft) } - r.Wait() + // 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() (failed bool) { + suite := &Suite{ + fmt: r.fmt, + stopOnFailure: r.stopOnFailure, + features: r.features, + } + r.initializer(suite) + suite.run() + + r.fmt.Summary() + return suite.failed +} + // Run creates and runs the feature suite. // uses contextInitializer to register contexts // @@ -94,12 +107,17 @@ func Run(contextInitializer func(suite *Suite)) int { r := runner{ fmt: formatter, initializer: contextInitializer, - semaphore: make(chan int, concurrency), features: features, stopOnFailure: sof, } - if failed := r.run(); failed { + var failed bool + if concurrency > 1 { + failed = r.concurrent(concurrency) + } else { + failed = r.run() + } + if failed { return 1 } return 0 diff --git a/suite.go b/suite.go index 865031a..3ceaba5 100644 --- a/suite.go +++ b/suite.go @@ -6,6 +6,7 @@ import ( "path/filepath" "reflect" "regexp" + "sort" "strconv" "strings" "unicode/utf8" @@ -445,9 +446,16 @@ func parseFeatures(filter string, paths []string) (features []*feature, err erro return features, err } } + sort.Sort(featuresSortedByPath(features)) return } +type featuresSortedByPath []*feature + +func (s featuresSortedByPath) Len() int { return len(s) } +func (s featuresSortedByPath) Less(i, j int) bool { return s[i].Path < s[j].Path } +func (s featuresSortedByPath) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + func applyTagFilter(tags string, ft *gherkin.Feature) { if len(tags) == 0 { return diff --git a/utils.go b/utils.go index 0f27db3..d51ab21 100644 --- a/utils.go +++ b/utils.go @@ -44,7 +44,7 @@ func s(n int) string { // checks the error and exits with error status code func fatal(err error) { if err != nil { - fmt.Println(err) + fmt.Fprintln(os.Stderr, err) os.Exit(1) } }