Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fixed the broken --random flag #317

Merged
merged 1 commit into from
Jun 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions run.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package godog
import (
"fmt"
"io"
"math/rand"
"os"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -158,13 +159,30 @@ func (r *runner) scenarioConcurrent(rate int) (failed bool) {

queue := make(chan int, rate)
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)
}

if len(pickles) == 0 {
r.fmt.Feature(ft.GherkinDocument, ft.Uri, ft.content)
}

for i, p := range ft.pickles {
for i, p := range pickles {
pickle := *p

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) {
defer func() {
<-queue // free a space in queue
Expand Down
92 changes: 87 additions & 5 deletions run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"io"
"io/ioutil"
"os"
"regexp"
"strconv"
"strings"
"testing"

Expand Down Expand Up @@ -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) {
const concurrency = 100
const noRandomFlag = 0
const format = "progress"

const expected = `...................................................................... 70
Expand Down Expand Up @@ -285,7 +340,8 @@ func Test_AllFeaturesRun(t *testing.T) {

actualStatus, actualOutput = testRun(t,
fmtOutputScenarioInitializer,
format, concurrency, []string{"features"},
format, concurrency,
noRandomFlag, []string{"features"},
)

assert.Equal(t, exitSuccess, actualStatus)
Expand All @@ -304,6 +360,8 @@ func TestFormatterConcurrencyRun(t *testing.T) {
featurePaths := []string{"formatter-tests/features"}

const concurrency = 100
const noRandomFlag = 0
const noConcurrency = 1

fmtOutputSuiteInitializer := func(s *Suite) {
s.Step(`^(?:a )?failing step`, failingStepDef)
Expand All @@ -325,7 +383,7 @@ func TestFormatterConcurrencyRun(t *testing.T) {
func(t *testing.T) {
expectedStatus, expectedOutput := testRunWithOptions(t,
fmtOutputSuiteInitializer,
formatter, 1, featurePaths,
formatter, noConcurrency, featurePaths,
)
actualStatus, actualOutput := testRunWithOptions(t,
fmtOutputSuiteInitializer,
Expand All @@ -337,11 +395,13 @@ func TestFormatterConcurrencyRun(t *testing.T) {

expectedStatus, expectedOutput = testRun(t,
fmtOutputScenarioInitializer,
formatter, 1, featurePaths,
formatter, noConcurrency,
noRandomFlag, featurePaths,
)
actualStatus, actualOutput = testRun(t,
fmtOutputScenarioInitializer,
formatter, concurrency, featurePaths,
formatter, concurrency,
noRandomFlag, featurePaths,
)

assert.Equal(t, expectedStatus, actualStatus)
Expand Down Expand Up @@ -370,14 +430,22 @@ func testRunWithOptions(t *testing.T, initializer func(*Suite), format string, c
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)

opts := Options{
Format: format,
NoColors: true,
Paths: featurePaths,
Concurrency: concurrency,
Randomize: randomSeed,
Output: output,
}

Expand Down Expand Up @@ -471,3 +539,17 @@ func oddOrEven(odd, even int) error {
func pendingStepDef() error { return ErrPending }

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
}
14 changes: 13 additions & 1 deletion suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package godog

import (
"fmt"
"math/rand"
"reflect"
"regexp"
"strings"
Expand Down Expand Up @@ -424,7 +425,18 @@ func (s *Suite) shouldFail(err error) bool {
func (s *Suite) runFeature(f *feature) {
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)
if s.shouldFail(err) {
s.failed = true
Expand Down