Skip to content

Commit d3aec71

Browse files
authored
Improve example with concurrency support (#573)
1 parent 75d5cab commit d3aec71

File tree

3 files changed

+82
-21
lines changed

3 files changed

+82
-21
lines changed

_examples/godogs/godogs.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,37 @@
11
package godogs
22

3-
// Godogs available to eat.
4-
var Godogs int
3+
import (
4+
"fmt"
5+
)
6+
7+
// Godogs is an example behavior holder.
8+
type Godogs int
9+
10+
// Add increments Godogs count.
11+
func (g *Godogs) Add(n int) {
12+
*g = *g + Godogs(n)
13+
}
14+
15+
// Eat decrements Godogs count or fails if there is not enough available.
16+
func (g *Godogs) Eat(n int) error {
17+
ng := Godogs(n)
18+
19+
if (g == nil && ng > 0) || ng > *g {
20+
return fmt.Errorf("you cannot eat %d godogs, there are %d available", n, g.Available())
21+
}
22+
23+
if ng > 0 {
24+
*g = *g - ng
25+
}
26+
27+
return nil
28+
}
29+
30+
// Available returns the number of currently available Godogs.
31+
func (g *Godogs) Available() int {
32+
if g == nil {
33+
return 0
34+
}
35+
36+
return int(*g)
37+
}

_examples/godogs/godogs_test.go

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package godogs
1+
package godogs_test
22

33
// This example shows how to set up test suite runner with Go subtests and godog command line parameters.
44
// Sample commands:
@@ -15,14 +15,18 @@ import (
1515
"context"
1616
"flag"
1717
"fmt"
18+
"github.com/cucumber/godog/_examples/godogs"
1819
"os"
1920
"testing"
2021

2122
"github.com/cucumber/godog"
2223
"github.com/cucumber/godog/colors"
2324
)
2425

25-
var opts = godog.Options{Output: colors.Colored(os.Stdout)}
26+
var opts = godog.Options{
27+
Output: colors.Colored(os.Stdout),
28+
Concurrency: 4,
29+
}
2630

2731
func init() {
2832
godog.BindFlags("godog.", flag.CommandLine, &opts)
@@ -48,38 +52,54 @@ func TestFeatures(t *testing.T) {
4852
}
4953
}
5054

51-
func thereAreGodogs(available int) error {
52-
Godogs = available
53-
return nil
55+
type godogsCtxKey struct{}
56+
57+
func godogsToContext(ctx context.Context, g godogs.Godogs) context.Context {
58+
return context.WithValue(ctx, godogsCtxKey{}, &g)
5459
}
5560

56-
func iEat(num int) error {
57-
if Godogs < num {
58-
return fmt.Errorf("you cannot eat %d godogs, there are %d available", num, Godogs)
59-
}
60-
Godogs -= num
61-
return nil
61+
func godogsFromContext(ctx context.Context) *godogs.Godogs {
62+
g, _ := ctx.Value(godogsCtxKey{}).(*godogs.Godogs)
63+
64+
return g
65+
}
66+
67+
// Concurrent execution of scenarios may lead to race conditions on shared resources.
68+
// Use context to maintain data separation and avoid data races.
69+
70+
// Step definition can optionally receive context as a first argument.
71+
72+
func thereAreGodogs(ctx context.Context, available int) {
73+
godogsFromContext(ctx).Add(available)
6274
}
6375

64-
func thereShouldBeRemaining(remaining int) error {
65-
if Godogs != remaining {
66-
return fmt.Errorf("expected %d godogs to be remaining, but there is %d", remaining, Godogs)
76+
// Step definition can return error, context, context and error, or nothing.
77+
78+
func iEat(ctx context.Context, num int) error {
79+
return godogsFromContext(ctx).Eat(num)
80+
}
81+
82+
func thereShouldBeRemaining(ctx context.Context, remaining int) error {
83+
available := godogsFromContext(ctx).Available()
84+
if available != remaining {
85+
return fmt.Errorf("expected %d godogs to be remaining, but there is %d", remaining, available)
6786
}
87+
6888
return nil
6989
}
7090

71-
func thereShouldBeNoneRemaining() error {
72-
return thereShouldBeRemaining(0)
91+
func thereShouldBeNoneRemaining(ctx context.Context) error {
92+
return thereShouldBeRemaining(ctx, 0)
7393
}
7494

7595
func InitializeTestSuite(ctx *godog.TestSuiteContext) {
76-
ctx.BeforeSuite(func() { Godogs = 0 })
96+
ctx.BeforeSuite(func() { fmt.Println("Get the party started!") })
7797
}
7898

7999
func InitializeScenario(ctx *godog.ScenarioContext) {
80100
ctx.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) {
81-
Godogs = 0 // clean the state before every scenario
82-
return ctx, nil
101+
// Add initial godogs to context.
102+
return godogsToContext(ctx, 0), nil
83103
})
84104

85105
ctx.Step(`^there are (\d+) godogs$`, thereAreGodogs)

_examples/incorrect-project-structure/go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,33 @@
11
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
2+
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
23
github.com/cucumber/gherkin/go/v26 v26.0.2 h1:DjNKtTIv5VG0F1XaJ2xYNk+ck8pJWRNFzyajkc/Y4l4=
34
github.com/cucumber/gherkin/go/v26 v26.0.2/go.mod h1:Xf+SrSuFbivEDZvmHjTShord3zlEkqsj7QB4sxl1SuU=
5+
github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0=
46
github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI=
57
github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s=
8+
github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs=
69
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
710
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
811
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
912
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
1013
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
14+
github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
1115
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
1216
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
1317
github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
1418
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
1519
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
1620
github.com/hashicorp/go-memdb v1.3.2 h1:RBKHOsnSszpU6vxq80LzC2BaQjuuvoyaQbkLTf7V7g8=
1721
github.com/hashicorp/go-memdb v1.3.2/go.mod h1:Mluclgwib3R93Hk5fxEfiRhB+6Dar64wWh71LpNSe3g=
22+
github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg=
1823
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
1924
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
2025
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
2126
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
2227
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
2328
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
2429
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
30+
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
2531
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
2632
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
2733
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
@@ -37,6 +43,7 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
3743
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
3844
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
3945
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
46+
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
4047
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
4148
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
4249
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -46,6 +53,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
4653
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
4754
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
4855
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
56+
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
4957
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
5058
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
5159
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

0 commit comments

Comments
 (0)