-
Notifications
You must be signed in to change notification settings - Fork 260
Implement retry flaky steps #684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
* retry failed pickles * revert some changes * use example steps from cck * update example * implement retry with godog.ErrRetry * unit test for retry flaky * Update flaky feature description * add --retry to CLI option * update test * update test for --retry cli option * update test * handle err without printing retry steps * storage methods to upsert step result * rename wording * revert change * update feature test (will remove this feature) * revert unused files * revert unused files * improve readability * remove unused code * cleanup
* retry failed pickles * revert some changes * use example steps from cck * update example * implement retry with godog.ErrRetry * unit test for retry flaky * Update flaky feature description * add --retry to CLI option * update test * update test for --retry cli option * update test * handle err without printing retry steps * storage methods to upsert step result * rename wording * revert change * update feature test (will remove this feature) * revert unused files * revert unused files * improve readability * remove unused code * cleanup * update changelog
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor fixes suggested. However a larger question is, are you seeking conformance with standard cucumber execution / cck conformance (I know you might not be there yet).
The reason why, is that a lot of your implementation details surrounding the specific status is unique and not what all standard implementors do
_examples/retry-flaky/godogs_test.go
Outdated
sc.Step(`^a step that passes the second time`, func(ctx context.Context) (context.Context, error) { | ||
secondTimePass++ | ||
if secondTimePass < 2 { | ||
return ctx, fmt.Errorf("unexpected network connection, %w", godog.ErrRetry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For stuff that will inevitably become part of living documentation I would make this more informative than obfuscating.
See https://github.com/cucumber/compatibility-kit/blob/main/devkit/samples/retry/retry.feature.ts (Which in itself probably could be a bit better)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I think I should just return godog.ErrRetry instead.
_examples/retry-flaky/godogs_test.go
Outdated
return ctx, nil | ||
}) | ||
|
||
fifthTimePass := 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be removed as we want this always to fail. The conditional below should also be removed. It should always return the formatted error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I agree, this folder is for examples, I should not add this case here (this case is supposed to be in unit test over here only).
internal/flags/flags.go
Outdated
@@ -46,4 +46,6 @@ built-in formatters are: | |||
specify SEED to reproduce the shuffling from a previous run | |||
--random=5738`) | |||
flagSet.Lookup(prefix + "random").NoOptDefVal = "-1" | |||
|
|||
flagSet.IntVar(&opts.MaxRetries, prefix+"retry", opts.MaxRetries, "retry n times when a step encounter error") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flagSet.IntVar(&opts.MaxRetries, prefix+"retry", opts.MaxRetries, "retry n times when a step encounter error") | |
flagSet.IntVar(&opts.MaxRetries, prefix+"retry", opts.MaxRetries, "Specify the number of times to retry failing tests (default: 0)") |
Make sure this is defaulting to 0
If you want to see where the original config parser is set with all of the messages check here: https://github.com/cucumber/cucumber-ruby/blob/main/lib/cucumber/cli/options.rb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it will be default 0. I'll update the message.
internal/flags/options.go
Outdated
@@ -80,6 +80,9 @@ type Options struct { | |||
|
|||
// ShowHelp enables suite to show CLI flags usage help and exit. | |||
ShowHelp bool | |||
|
|||
// MaxRetries is used to retry the number of time when a step is failed. Default is 0 retry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// MaxRetries is used to retry the number of time when a step is failed. Default is 0 retry. | |
// MaxRetries is the number of times you can retry failing tests. Default is 0. |
|
||
fifthTimePass := 0 | ||
ctx.Step(`^a step that always fails`, func(ctx context.Context) (context.Context, error) { | ||
fifthTimePass++ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like duplicate info from above. Is there a way to avoid defining this twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I forgot, this file is unit tests for the framework itself. So this case here is to cover the case step retried all attempts but still fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So based on what I've seen earlier, this should ideally live in a separate folder called compatibility and you should look towards CCK conformance imo.
Maybe come and discuss this on discord. See what the desired avenue is in the go community
@luke-hill I agree that this implementation works for the specific status Do you mean that other standard implementors will also implement such approaches as well? If it is the case, then this PR is to implement the approach using So I do want to conform the cucumber standard for implementations, but I don't want to make so many different changes in one PR 😄 |
hi @vearutop @luke-hill if you have time, please help me review this PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done another pass at a review but at this point I think the "goal" needs to be understood better with regards to conformance / non-conformance
Feature: Godog should be able to retry flaky tests | ||
In order to help Go developers deal with flaky tests | ||
As a test suite | ||
I need to be able to return godog.Err to mark which steps should be retry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more a question, but usually in feature files if it's a technical term you're referencing you'd use backticks or something else.
But maybe you don't do that here 🤷♂️
@@ -0,0 +1,19 @@ | |||
Feature: Godog should be able to retry flaky tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whilst the principle here is good, I'd lean more on you implementing the CCK for things like this, so that you can use the conformance element there
@@ -80,6 +80,9 @@ type Options struct { | |||
|
|||
// ShowHelp enables suite to show CLI flags usage help and exit. | |||
ShowHelp bool | |||
|
|||
// MaxRetries is the number of times you can retry failing tests. Default is 0 retry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// MaxRetries is the number of times you can retry failing tests. Default is 0 retry. | |
// MaxRetries is the number of times you can retry failing tests. Default is 0 retries. |
@@ -37,6 +37,7 @@ var ( | |||
undefined = models.Undefined | |||
pending = models.Pending | |||
ambiguous = models.Ambiguous | |||
retry = models.Retry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whilst this is godog, and you are allowed to do your own thing, if your ultimate goal is cucumber conformance, this would need to go.
We have a concept called "flaky" which is something that passed after retries, maybe this can be renamed or adapted I don't know
@@ -74,6 +79,8 @@ const ( | |||
Pending | |||
// Ambiguous ... | |||
Ambiguous | |||
// Retry ... | |||
Retry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might / should be altered too
@@ -105,6 +112,8 @@ func (st StepResultStatus) String() string { | |||
return "pending" | |||
case Ambiguous: | |||
return "ambiguous" | |||
case Retry: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here also
@@ -336,3 +345,15 @@ func (s *Storage) mustGet(table, index string, args ...interface{}) memdb.Result | |||
|
|||
return it | |||
} | |||
|
|||
func (s *Storage) first(table, index string, args ...interface{}) interface{} { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am writing this comment to let you know I don't understand this bit. But I'm assuming it does something important 😅
|
||
fifthTimePass := 0 | ||
ctx.Step(`^a step that always fails`, func(ctx context.Context) (context.Context, error) { | ||
fifthTimePass++ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So based on what I've seen earlier, this should ideally live in a separate folder called compatibility and you should look towards CCK conformance imo.
Maybe come and discuss this on discord. See what the desired avenue is in the go community
🤔 What's changed?
ErrRetry
MaxRetries
attempts⚡️ What's your motivation?
Discussed here.
🏷️ What kind of change is this?
♻️ Anything particular you want feedback on?
📋 Checklist:
This text was originally generated from a template, then edited by hand. You can modify the template here.