rspec-retryable 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/README.md +35 -0
- data/Rakefile +8 -0
- data/lib/rspec/retryable/example.rb +81 -0
- data/lib/rspec/retryable/handlers.rb +27 -0
- data/lib/rspec/retryable/metadata.rb +31 -0
- data/lib/rspec/retryable/payload.rb +24 -0
- data/lib/rspec/retryable/version.rb +7 -0
- data/lib/rspec/retryable.rb +21 -0
- metadata +69 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a4780f14d90cc2bdce6da95e999e53bc8d7161b298840726e88c509bdddfbafc
|
4
|
+
data.tar.gz: cd5346007d8ce02a9ae49186bd0b5e6f81938641a191bafe7f882e15e47adc4f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: '0927eb2492bd7c287d2c96a10bbfc1eb811a61d4ac39dd4fc632f7416a112ef623227f0a6813a126332b961dfefdd3a0000f074659b16c12992fc6f8dcbf9bd6'
|
7
|
+
data.tar.gz: a2feafa640ee50b563983f25554a53281726aa557ff7ac7a4e4b52db699e7ceac3d0de4f1de21192fd6b25ca18a9d869f6d272470e6dfc97b7d471e2440a4255
|
data/.rspec
ADDED
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# RSpec::Retryable
|
2
|
+
|
3
|
+
TODO: Delete this and the text below, and describe your gem
|
4
|
+
|
5
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rspec/retryable`. To experiment with that code, run `bin/console` for an interactive prompt.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
|
10
|
+
|
11
|
+
Install the gem and add to the application's Gemfile by executing:
|
12
|
+
|
13
|
+
```bash
|
14
|
+
bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
|
15
|
+
```
|
16
|
+
|
17
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
18
|
+
|
19
|
+
```bash
|
20
|
+
gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
|
21
|
+
```
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ngan/rspec-retryable.
|
data/Rakefile
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec/retryable/metadata'
|
4
|
+
require 'rspec/retryable/payload'
|
5
|
+
|
6
|
+
module RSpec
|
7
|
+
module Retryable
|
8
|
+
module Example
|
9
|
+
def finish(reporter)
|
10
|
+
metadata[:retryable] ||= Metadata.new
|
11
|
+
|
12
|
+
if @exception
|
13
|
+
state = :failed
|
14
|
+
execution_result.exception = @exception
|
15
|
+
record_finished :failed, reporter
|
16
|
+
elsif execution_result.pending_message
|
17
|
+
state = :pending
|
18
|
+
record_finished :pending, reporter
|
19
|
+
else
|
20
|
+
state = :passed
|
21
|
+
record_finished :passed, reporter
|
22
|
+
end
|
23
|
+
|
24
|
+
@payload = RSpec::Retryable::Payload.new(self, state)
|
25
|
+
|
26
|
+
RSpec::Retryable.handlers.invoke(@payload)
|
27
|
+
|
28
|
+
if @payload.retry
|
29
|
+
# Replaced the final result by the retry result
|
30
|
+
@payload.result = retry_example
|
31
|
+
end
|
32
|
+
|
33
|
+
# Notify reporter only if it's not handled by the handlers
|
34
|
+
notify_reporter if @payload.notify
|
35
|
+
|
36
|
+
@payload.result
|
37
|
+
end
|
38
|
+
|
39
|
+
# https://github.com/rspec/rspec-core/blob/3-10-maintenance/lib/rspec/core/example.rb#L433-L441
|
40
|
+
# Used internally to set an exception and fail without actually executing
|
41
|
+
# the example when an exception is raised in before(:context).
|
42
|
+
def fail_with_exception(...)
|
43
|
+
@failed_in_context = true
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
def failed_in_context?
|
48
|
+
!!@failed_in_context
|
49
|
+
end
|
50
|
+
|
51
|
+
def retry_example
|
52
|
+
metadata[:retryable].failures << @exception
|
53
|
+
metadata[:retryable].attempts += 1
|
54
|
+
# Every retry turns off the retry and notify flag, it's up to the handler to turn them back on or not.
|
55
|
+
@payload.retry = false
|
56
|
+
@payload.notify = false
|
57
|
+
# Duplicate the example for re-run
|
58
|
+
new_example = duplicate_with(metadata)
|
59
|
+
new_example.instance_variable_set(:@id, id)
|
60
|
+
# Taken from https://github.com/rspec/rspec-core/blob/main/lib/rspec/core/example_group.rb#L644-L646
|
61
|
+
instance = new_example.example_group.new(new_example.inspect_output)
|
62
|
+
new_example.example_group.set_ivars(instance, new_example.example_group.before_context_ivars)
|
63
|
+
# Use same reporter from example instead of the one passing in to behave like
|
64
|
+
# a fresh new example.
|
65
|
+
|
66
|
+
new_example.run(instance, reporter)
|
67
|
+
end
|
68
|
+
|
69
|
+
def notify_reporter
|
70
|
+
case @payload.state
|
71
|
+
when :failed
|
72
|
+
reporter.example_failed self
|
73
|
+
when :pending
|
74
|
+
reporter.example_pending self
|
75
|
+
when :passed
|
76
|
+
reporter.example_passed self
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Retryable
|
5
|
+
class Handlers
|
6
|
+
def initialize
|
7
|
+
@handlers = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def register(klass, *args, **kwargs)
|
11
|
+
@handlers << klass.new(*args, **kwargs)
|
12
|
+
end
|
13
|
+
|
14
|
+
def invoke(payload)
|
15
|
+
traverse(0, payload)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def traverse(index, payload)
|
21
|
+
@handlers[index]&.call(payload) do
|
22
|
+
traverse(index + 1, payload)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Retryable
|
5
|
+
class Metadata
|
6
|
+
attr_writer :attempts, :retry, :failures
|
7
|
+
|
8
|
+
def attempts
|
9
|
+
@attempts ||= 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def retry
|
13
|
+
return @retry if defined?(@retry)
|
14
|
+
|
15
|
+
@retry = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def failures
|
19
|
+
@failures ||= []
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_h
|
23
|
+
{
|
24
|
+
attempts: attempts,
|
25
|
+
retry: @retry,
|
26
|
+
failures: failures,
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Retryable
|
5
|
+
class Payload
|
6
|
+
attr_reader :example
|
7
|
+
attr_accessor :notify, :result, :retry, :state
|
8
|
+
|
9
|
+
# Default payload with:
|
10
|
+
# - example: RSpec example
|
11
|
+
# - state: Current state of the example, can be alterted by handlers
|
12
|
+
# - notify: default to `true`, if set to `false`, reporter will not be notified
|
13
|
+
# - result: this is the final result returned to RSpec runner
|
14
|
+
# - retry: default to `false`, if set to `true`, the example will be retried
|
15
|
+
def initialize(example, state)
|
16
|
+
@example = example
|
17
|
+
@state = state
|
18
|
+
@notify = true
|
19
|
+
@result = state == :failed ? false : true
|
20
|
+
@retry = false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec/retryable/version'
|
4
|
+
require 'rspec/retryable/example'
|
5
|
+
require 'rspec/retryable/handlers'
|
6
|
+
|
7
|
+
module RSpec
|
8
|
+
module Retryable
|
9
|
+
class << self
|
10
|
+
def handlers
|
11
|
+
@handlers ||= Handlers.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def bind
|
15
|
+
require 'rspec/core'
|
16
|
+
|
17
|
+
::RSpec::Core::Example.prepend(RSpec::Retryable::Example)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rspec-retryable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ngan Pham
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-08-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec-core
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- ngan@users.noreply.github.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".rspec"
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- lib/rspec/retryable.rb
|
38
|
+
- lib/rspec/retryable/example.rb
|
39
|
+
- lib/rspec/retryable/handlers.rb
|
40
|
+
- lib/rspec/retryable/metadata.rb
|
41
|
+
- lib/rspec/retryable/payload.rb
|
42
|
+
- lib/rspec/retryable/version.rb
|
43
|
+
homepage: https://github.com/Gusto/rspec-retryable
|
44
|
+
licenses: []
|
45
|
+
metadata:
|
46
|
+
allowed_push_host: https://rubygems.org
|
47
|
+
homepage_uri: https://github.com/Gusto/rspec-retryable
|
48
|
+
source_code_uri: https://github.com/Gusto/rspec-retryable
|
49
|
+
changelog_uri: https://github.com/Gusto/rspec-retryable/releases
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: 3.0.0
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
requirements: []
|
65
|
+
rubygems_version: 3.5.0
|
66
|
+
signing_key:
|
67
|
+
specification_version: 4
|
68
|
+
summary: Adds ability to fully control RSpec retrying
|
69
|
+
test_files: []
|