From 0eed963c6323410f50d753551b0f17e3a57213f4 Mon Sep 17 00:00:00 2001 From: Matthew Rothenberg Date: Tue, 25 Apr 2017 11:42:40 -0400 Subject: [PATCH] switch Random opt from bool to int64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows for us to propagate the seed value around, and not have to have two different values in Options when we want to allow specification of seed. It does introduce some “magic values”, but the document them in the Options struct docstrings. --- options.go | 15 ++++++++++----- run.go | 26 ++++++++++++++++---------- suite.go | 4 ++-- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/options.go b/options.go index 5858428..a1235ee 100644 --- a/options.go +++ b/options.go @@ -13,12 +13,17 @@ type Options struct { // Print step definitions found and exit ShowStepDefinitions bool - // Run scenarios in random order. + // RandomSeed, if not `0`, will be used to run scenarios in a random order. // - // This is especially helpful for detecting situations - // where you have state leaking between scenarios, which - // can cause flickering or fragile tests. - RandomOrder bool + // Randomizing scenario order is especially helpful for detecting + // situations where you have state leaking between scenarios, which can + // cause flickering or fragile tests. + // + // The default value of `0` means "do not randomize". + // + // The magic value of `-1` means "pick a random seed for me", the resulting + // seed will only be between `1-99999` for ease of specification. + RandomSeed int64 // Stops on the first failure StopOnFailure bool diff --git a/run.go b/run.go index 50f93b2..bae334a 100644 --- a/run.go +++ b/run.go @@ -13,7 +13,7 @@ import ( type initializer func(*Suite) type runner struct { - randomOrder bool + randomSeed int64 stopOnFailure bool features []*feature fmt Formatter @@ -33,7 +33,7 @@ func (r *runner) concurrent(rate int) (failed bool) { } suite := &Suite{ fmt: r.fmt, - randomOrder: r.randomOrder, + randomSeed: r.randomSeed, stopOnFailure: r.stopOnFailure, features: []*feature{feat}, } @@ -58,7 +58,7 @@ func (r *runner) concurrent(rate int) (failed bool) { func (r *runner) run() (failed bool) { suite := &Suite{ fmt: r.fmt, - randomOrder: r.randomOrder, + randomSeed: r.randomSeed, stopOnFailure: r.stopOnFailure, features: r.features, } @@ -111,20 +111,26 @@ func RunWithOptions(suite string, contextInitializer func(suite *Suite), opt Opt features, err := parseFeatures(opt.Tags, opt.Paths) fatal(err) + seed := opt.RandomSeed + if seed == -1 { + // if RandomSeed opt is -1, means pick a memorable rand seed as default + // the docStrings for Option specify this should be 1-99999 (same as ruby Cucumber) + r := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) + seed = r.Int63n(99998) + 1 + } + if seed != 0 { + // init global rand module (concurrent safe) with our seed + rand.Seed(seed) + } + r := runner{ fmt: formatter(suite, output), initializer: contextInitializer, features: features, - randomOrder: opt.RandomOrder, + randomSeed: seed, stopOnFailure: opt.StopOnFailure, } - if opt.RandomOrder { - // TODO(mroth): allow for seed to be specified in options, - // and print it at the end of a run for replication purposes - rand.Seed(time.Now().UTC().UnixNano()) - } - var failed bool if opt.Concurrency > 1 { failed = r.concurrent(opt.Concurrency) diff --git a/suite.go b/suite.go index 18cd7f8..e386f75 100644 --- a/suite.go +++ b/suite.go @@ -50,7 +50,7 @@ type Suite struct { fmt Formatter failed bool - randomOrder bool + randomSeed int64 stopOnFailure bool // suite event handlers @@ -336,7 +336,7 @@ func (s *Suite) runFeature(f *feature) { // make a local copy of the feature scenario defenitions, // then shuffle it if we are randomizing scenarios scenarios := make([]interface{}, len(f.ScenarioDefinitions)) - if s.randomOrder { + if s.randomSeed != 0 { perm := rand.Perm(len(f.ScenarioDefinitions)) for i, v := range perm { scenarios[v] = f.ScenarioDefinitions[i]