Fixed the broken --random flag

Этот коммит содержится в:
Fredrik Lönnblad 2020-06-21 13:21:44 +02:00
родитель 9795588012
коммит 376280cfc6
3 изменённых файлов: 120 добавлений и 8 удалений

22
run.go
Просмотреть файл

@ -3,6 +3,7 @@ package godog
import ( import (
"fmt" "fmt"
"io" "io"
"math/rand"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@ -158,13 +159,30 @@ func (r *runner) scenarioConcurrent(rate int) (failed bool) {
queue := make(chan int, rate) queue := make(chan int, rate)
for _, ft := range r.features { for _, ft := range r.features {
r.fmt.Feature(ft.GherkinDocument, ft.Uri, ft.content) pickles := make([]*messages.Pickle, len(ft.pickles))
if r.randomSeed != 0 {
r := rand.New(rand.NewSource(r.randomSeed))
perm := r.Perm(len(ft.pickles))
for i, v := range perm {
pickles[v] = ft.pickles[i]
}
} else {
copy(pickles, ft.pickles)
}
for i, p := range ft.pickles { if len(pickles) == 0 {
r.fmt.Feature(ft.GherkinDocument, ft.Uri, ft.content)
}
for i, p := range pickles {
pickle := *p pickle := *p
queue <- i // reserve space in queue queue <- i // reserve space in queue
if i == 0 {
r.fmt.Feature(ft.GherkinDocument, ft.Uri, ft.content)
}
go func(fail *bool, pickle *messages.Pickle) { go func(fail *bool, pickle *messages.Pickle) {
defer func() { defer func() {
<-queue // free a space in queue <-queue // free a space in queue

Просмотреть файл

@ -6,6 +6,8 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"regexp"
"strconv"
"strings" "strings"
"testing" "testing"
@ -256,8 +258,61 @@ func TestFeatureFilePathParser(t *testing.T) {
} }
} }
func Test_RandomizeRun(t *testing.T) {
const noRandomFlag = 0
const createRandomSeedFlag = -1
const noConcurrencyFlag = 1
const formatter = "pretty"
const featurePath = "formatter-tests/features/with_few_empty_scenarios.feature"
fmtOutputScenarioInitializer := func(ctx *ScenarioContext) {
ctx.Step(`^(?:a )?failing step`, failingStepDef)
ctx.Step(`^(?:a )?pending step$`, pendingStepDef)
ctx.Step(`^(?:a )?passing step$`, passingStepDef)
ctx.Step(`^odd (\d+) and even (\d+) number$`, oddEvenStepDef)
}
expectedStatus, expectedOutput := testRun(t,
fmtOutputScenarioInitializer,
formatter, noConcurrencyFlag,
noRandomFlag, []string{featurePath},
)
actualStatus, actualOutput := testRun(t,
fmtOutputScenarioInitializer,
formatter, noConcurrencyFlag,
createRandomSeedFlag, []string{featurePath},
)
expectedSeed := parseSeed(actualOutput)
assert.NotZero(t, expectedSeed)
// Removes "Randomized with seed: <seed>" part of the output
actualOutputSplit := strings.Split(actualOutput, "\n")
actualOutputSplit = actualOutputSplit[:len(actualOutputSplit)-2]
actualOutputReduced := strings.Join(actualOutputSplit, "\n")
assert.NotEqual(t, expectedOutput, actualOutputReduced)
assertOutput(t, formatter, expectedOutput, actualOutputReduced)
expectedStatus, expectedOutput = actualStatus, actualOutput
actualStatus, actualOutput = testRun(t,
fmtOutputScenarioInitializer,
formatter, noConcurrencyFlag,
expectedSeed, []string{featurePath},
)
actualSeed := parseSeed(actualOutput)
assert.Equal(t, expectedSeed, actualSeed)
assert.Equal(t, expectedStatus, actualStatus)
assert.Equal(t, expectedOutput, actualOutput)
}
func Test_AllFeaturesRun(t *testing.T) { func Test_AllFeaturesRun(t *testing.T) {
const concurrency = 100 const concurrency = 100
const noRandomFlag = 0
const format = "progress" const format = "progress"
const expected = `...................................................................... 70 const expected = `...................................................................... 70
@ -285,7 +340,8 @@ func Test_AllFeaturesRun(t *testing.T) {
actualStatus, actualOutput = testRun(t, actualStatus, actualOutput = testRun(t,
fmtOutputScenarioInitializer, fmtOutputScenarioInitializer,
format, concurrency, []string{"features"}, format, concurrency,
noRandomFlag, []string{"features"},
) )
assert.Equal(t, exitSuccess, actualStatus) assert.Equal(t, exitSuccess, actualStatus)
@ -304,6 +360,8 @@ func TestFormatterConcurrencyRun(t *testing.T) {
featurePaths := []string{"formatter-tests/features"} featurePaths := []string{"formatter-tests/features"}
const concurrency = 100 const concurrency = 100
const noRandomFlag = 0
const noConcurrency = 1
fmtOutputSuiteInitializer := func(s *Suite) { fmtOutputSuiteInitializer := func(s *Suite) {
s.Step(`^(?:a )?failing step`, failingStepDef) s.Step(`^(?:a )?failing step`, failingStepDef)
@ -325,7 +383,7 @@ func TestFormatterConcurrencyRun(t *testing.T) {
func(t *testing.T) { func(t *testing.T) {
expectedStatus, expectedOutput := testRunWithOptions(t, expectedStatus, expectedOutput := testRunWithOptions(t,
fmtOutputSuiteInitializer, fmtOutputSuiteInitializer,
formatter, 1, featurePaths, formatter, noConcurrency, featurePaths,
) )
actualStatus, actualOutput := testRunWithOptions(t, actualStatus, actualOutput := testRunWithOptions(t,
fmtOutputSuiteInitializer, fmtOutputSuiteInitializer,
@ -337,11 +395,13 @@ func TestFormatterConcurrencyRun(t *testing.T) {
expectedStatus, expectedOutput = testRun(t, expectedStatus, expectedOutput = testRun(t,
fmtOutputScenarioInitializer, fmtOutputScenarioInitializer,
formatter, 1, featurePaths, formatter, noConcurrency,
noRandomFlag, featurePaths,
) )
actualStatus, actualOutput = testRun(t, actualStatus, actualOutput = testRun(t,
fmtOutputScenarioInitializer, fmtOutputScenarioInitializer,
formatter, concurrency, featurePaths, formatter, concurrency,
noRandomFlag, featurePaths,
) )
assert.Equal(t, expectedStatus, actualStatus) assert.Equal(t, expectedStatus, actualStatus)
@ -370,7 +430,14 @@ func testRunWithOptions(t *testing.T, initializer func(*Suite), format string, c
return status, string(actual) return status, string(actual)
} }
func testRun(t *testing.T, scenarioInitializer func(*ScenarioContext), format string, concurrency int, featurePaths []string) (int, string) { func testRun(
t *testing.T,
scenarioInitializer func(*ScenarioContext),
format string,
concurrency int,
randomSeed int64,
featurePaths []string,
) (int, string) {
output := new(bytes.Buffer) output := new(bytes.Buffer)
opts := Options{ opts := Options{
@ -378,6 +445,7 @@ func testRun(t *testing.T, scenarioInitializer func(*ScenarioContext), format st
NoColors: true, NoColors: true,
Paths: featurePaths, Paths: featurePaths,
Concurrency: concurrency, Concurrency: concurrency,
Randomize: randomSeed,
Output: output, Output: output,
} }
@ -471,3 +539,17 @@ func oddOrEven(odd, even int) error {
func pendingStepDef() error { return ErrPending } func pendingStepDef() error { return ErrPending }
func failingStepDef() error { return fmt.Errorf("step failed") } func failingStepDef() error { return fmt.Errorf("step failed") }
func parseSeed(str string) (seed int64) {
re := regexp.MustCompile(`Randomized with seed: (\d*)`)
match := re.FindStringSubmatch(str)
if len(match) > 0 {
var err error
if seed, err = strconv.ParseInt(match[1], 10, 64); err != nil {
seed = 0
}
}
return
}

Просмотреть файл

@ -2,6 +2,7 @@ package godog
import ( import (
"fmt" "fmt"
"math/rand"
"reflect" "reflect"
"regexp" "regexp"
"strings" "strings"
@ -424,7 +425,18 @@ func (s *Suite) shouldFail(err error) bool {
func (s *Suite) runFeature(f *feature) { func (s *Suite) runFeature(f *feature) {
s.fmt.Feature(f.GherkinDocument, f.Uri, f.content) s.fmt.Feature(f.GherkinDocument, f.Uri, f.content)
for _, pickle := range f.pickles { pickles := make([]*messages.Pickle, len(f.pickles))
if s.randomSeed != 0 {
r := rand.New(rand.NewSource(s.randomSeed))
perm := r.Perm(len(f.pickles))
for i, v := range perm {
pickles[v] = f.pickles[i]
}
} else {
copy(pickles, f.pickles)
}
for _, pickle := range pickles {
err := s.runPickle(pickle) err := s.runPickle(pickle)
if s.shouldFail(err) { if s.shouldFail(err) {
s.failed = true s.failed = true