sort feature files by path when executing, separate the concurrent runner
Этот коммит содержится в:
родитель
a6a318322b
коммит
abc6b65c1c
4 изменённых файлов: 41 добавлений и 15 удалений
|
@ -42,6 +42,6 @@ Feature: load features
|
||||||
When I parse features
|
When I parse features
|
||||||
Then I should have 2 feature files:
|
Then I should have 2 feature files:
|
||||||
"""
|
"""
|
||||||
features/load.feature
|
|
||||||
features/events.feature
|
features/events.feature
|
||||||
|
features/load.feature
|
||||||
"""
|
"""
|
||||||
|
|
44
run.go
44
run.go
|
@ -3,29 +3,24 @@ package godog
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type initializer func(*Suite)
|
type initializer func(*Suite)
|
||||||
|
|
||||||
type runner struct {
|
type runner struct {
|
||||||
sync.WaitGroup
|
|
||||||
|
|
||||||
semaphore chan int
|
|
||||||
stopOnFailure bool
|
stopOnFailure bool
|
||||||
features []*feature
|
features []*feature
|
||||||
fmt Formatter // needs to support concurrency
|
fmt Formatter // needs to support concurrency
|
||||||
initializer initializer
|
initializer initializer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) run() (failed bool) {
|
func (r *runner) concurrent(rate int) (failed bool) {
|
||||||
r.Add(len(r.features))
|
queue := make(chan int, rate)
|
||||||
for _, ft := range r.features {
|
for i, ft := range r.features {
|
||||||
|
queue <- i // reserve space in queue
|
||||||
go func(fail *bool, feat *feature) {
|
go func(fail *bool, feat *feature) {
|
||||||
r.semaphore <- 1
|
|
||||||
defer func() {
|
defer func() {
|
||||||
r.Done()
|
<-queue // free a space in queue
|
||||||
<-r.semaphore
|
|
||||||
}()
|
}()
|
||||||
if r.stopOnFailure && *fail {
|
if r.stopOnFailure && *fail {
|
||||||
return
|
return
|
||||||
|
@ -42,12 +37,30 @@ func (r *runner) run() (failed bool) {
|
||||||
}
|
}
|
||||||
}(&failed, ft)
|
}(&failed, ft)
|
||||||
}
|
}
|
||||||
r.Wait()
|
// wait until last are processed
|
||||||
|
for i := 0; i < rate; i++ {
|
||||||
|
queue <- i
|
||||||
|
}
|
||||||
|
close(queue)
|
||||||
|
|
||||||
|
// print summary
|
||||||
r.fmt.Summary()
|
r.fmt.Summary()
|
||||||
return
|
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.
|
// Run creates and runs the feature suite.
|
||||||
// uses contextInitializer to register contexts
|
// uses contextInitializer to register contexts
|
||||||
//
|
//
|
||||||
|
@ -94,12 +107,17 @@ func Run(contextInitializer func(suite *Suite)) int {
|
||||||
r := runner{
|
r := runner{
|
||||||
fmt: formatter,
|
fmt: formatter,
|
||||||
initializer: contextInitializer,
|
initializer: contextInitializer,
|
||||||
semaphore: make(chan int, concurrency),
|
|
||||||
features: features,
|
features: features,
|
||||||
stopOnFailure: sof,
|
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 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
|
|
8
suite.go
8
suite.go
|
@ -6,6 +6,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
@ -445,9 +446,16 @@ func parseFeatures(filter string, paths []string) (features []*feature, err erro
|
||||||
return features, err
|
return features, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sort.Sort(featuresSortedByPath(features))
|
||||||
return
|
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) {
|
func applyTagFilter(tags string, ft *gherkin.Feature) {
|
||||||
if len(tags) == 0 {
|
if len(tags) == 0 {
|
||||||
return
|
return
|
||||||
|
|
2
utils.go
2
utils.go
|
@ -44,7 +44,7 @@ func s(n int) string {
|
||||||
// checks the error and exits with error status code
|
// checks the error and exits with error status code
|
||||||
func fatal(err error) {
|
func fatal(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче