marsh_grass 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +2 -2
- data/LICENSE.txt +1 -1
- data/README.md +109 -7
- data/lib/marsh_grass/rspec.rb +81 -42
- data/lib/marsh_grass/version.rb +1 -1
- data/marsh_grass.gemspec +12 -10
- metadata +51 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ed2c3a6f128c38e323853492d7edb4708c28baa992d65dbe4a2eb9f12b0214ce
|
4
|
+
data.tar.gz: 6af8c822dd47d3453a1ff2c1a04f8d70243b9422e4278447ff7b0873559936ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e160807e814ce374666835b7a8fa65411c294a892191fb32a4e6f75fd0c6740f694354d2d9028b59f31fe10278f8df0cdbaa67ecbad59b749a2a6ae483365fa
|
7
|
+
data.tar.gz: 14fb47d883f776c885cedf7d278ec7311f914423a8d1670d96146d1d183050bad816633ad7d2dd3a61b0a068f03fffbea48683ac0edc3638a3a6f6342952f823
|
data/.travis.yml
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,28 @@
|
|
1
1
|
# MarshGrass
|
2
2
|
|
3
|
-
|
3
|
+
Finally! A way to examine the behavior of intermittent failures in RSpec.
|
4
4
|
|
5
|
-
|
5
|
+
This gem allows you to subject an intermittently failing test to a variety of circumstances in an attempt to discern what combination of events leads to failure.
|
6
|
+
|
7
|
+
## Background
|
8
|
+
|
9
|
+
Intermittent failures are challenging because the failure conditions are more difficult to pinpoint than with tests that fail 100% of the time.
|
10
|
+
|
11
|
+
Intermittent failures are also more likely to make it into production. They often pass during CI testing and code review and then crop up days or weeks later.
|
12
|
+
|
13
|
+
In programming, there is no such thing as a "random" failure. Every intermittent failure actually fails consistently, every single time... under the right set of circumstances. Perhaps your test only fails on Friday afternoons. Or, 10% of the time under race conditions. We once had a test that failed on every power of 2 run: on the 2nd, 4th, 8th, 16th run, etc. The more we ran it, the more elusive it became.
|
14
|
+
|
15
|
+
Often, the first step in fixing such a failure is to make it fail consistently. That way, as you change your code, you can use the test to confirm when you've fixed the root cause. After all, that is the purpose of the test!
|
16
|
+
|
17
|
+
## Features
|
18
|
+
This gem subjects a given test to the following circumstances:
|
19
|
+
- repetitions
|
20
|
+
- range of speeds in execution
|
21
|
+
- execution at all times of day
|
22
|
+
- execution in all time zones
|
23
|
+
- execution at all the milliseconds surrounding a particular time of day
|
24
|
+
|
25
|
+
In our experience, repetitions is the option we use the most often. It gives the broadest feedback and is very effective at uncovering race conditions.
|
6
26
|
|
7
27
|
## Installation
|
8
28
|
|
@@ -21,18 +41,100 @@ Or install it yourself as:
|
|
21
41
|
$ gem install marsh_grass
|
22
42
|
|
23
43
|
## Usage
|
44
|
+
Feature use:
|
45
|
+
- N repetitions (default: 1000, or specify integer)
|
46
|
+
- Times of day (default: all hours, minutes, seconds or specify :hours, :minutes, :seconds)
|
47
|
+
- Time zones (executes against each time zone offset from ActiveSupport::TimeZone)
|
48
|
+
- Elapsed time during test execution (default: (1..10) execution slow-down multipliers or specify range)
|
49
|
+
- Surrounding time, i.e., clock change over during the test (must specify hour: <integer>, minute: <integer>, second: <integer>)
|
50
|
+
|
51
|
+
Surrounding time runs test at every millisecond from 1 sec before to 1 sec after specified time. This is particularly useful for discerning rate of failure near and at midnight.
|
52
|
+
|
53
|
+
### Examples
|
54
|
+
Simple examples:
|
55
|
+
```ruby
|
56
|
+
it 'uses default repetitions', :repetitions do
|
57
|
+
...
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'uses specific repetitions', repetitions: 20 do
|
61
|
+
...
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'uses just hours for default surrounding_time', :time_of_day do
|
65
|
+
...
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'uses each hour of day', time_of_day: :hours do
|
69
|
+
...
|
70
|
+
end
|
24
71
|
|
25
|
-
|
72
|
+
it 'uses each hour and minute of the day', time_of_day: [:hours, :minutes] do
|
73
|
+
...
|
74
|
+
end
|
26
75
|
|
27
|
-
|
76
|
+
it 'uses each second of current minute', time_of_day: :seconds do
|
77
|
+
...
|
78
|
+
end
|
28
79
|
|
29
|
-
|
80
|
+
it 'uses current time for default surrounding_time', :surrounding_time do
|
81
|
+
...
|
82
|
+
end
|
30
83
|
|
31
|
-
|
84
|
+
it 'uses each millisecond around hour of day', surrounding_time: { hour: 17 } do
|
85
|
+
...
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'uses each millisecond around specified time (noon)', surrounding_time: { hour: 12, minute: 0, second: 0 } do
|
89
|
+
...
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'uses 10 different speeds for default elapsed_time', :elapsed_time do
|
93
|
+
...
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'uses array of different speeds for elapsed_time', elapsed_time: [1, 5, 10] do
|
97
|
+
...
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'uses range of different speeds for elapsed_time', elapsed_time: (1..5) do
|
101
|
+
...
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'uses 34 different timezones for default time_zones', :time_zones do
|
105
|
+
...
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'uses single named timezone for time_zone (singular)', time_zone: 'Eastern Time (US & Canada)' do
|
109
|
+
...
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'uses a specific frozen time with a string', frozen_time: '2025-08-22 17:00:00' do
|
113
|
+
...
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'uses a specific frozen time with a Time', frozen_time: Time.new(2025, 8, 22, 17) do
|
117
|
+
...
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'uses a specific moving time with a string', moving_time: '2025-08-22 17:00:00' do
|
121
|
+
...
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'uses a specific moving time with a Time', moving_time: Time.new(2025, 8, 22, 17) do
|
125
|
+
...
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'uses a specific time scalar', scaling_time: 8 do
|
129
|
+
...
|
130
|
+
end
|
131
|
+
|
132
|
+
```
|
133
|
+
[Further Examples](./spec/marsh_grass_spec.rb) of tests using each feature.
|
32
134
|
|
33
135
|
## Contributing
|
34
136
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
137
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/RoleModel/marsh_grass.
|
36
138
|
|
37
139
|
## License
|
38
140
|
|
data/lib/marsh_grass/rspec.rb
CHANGED
@@ -1,13 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rspec'
|
4
|
+
require 'time'
|
4
5
|
require 'timecop'
|
5
|
-
require 'pry'
|
6
6
|
|
7
7
|
RSpec.configure do |config|
|
8
8
|
def untag_example(example, tag)
|
9
9
|
example.example_group.metadata.delete(tag) if example.metadata[:turnip]
|
10
|
-
example.metadata
|
10
|
+
return_value = example.metadata[tag]
|
11
|
+
example.metadata[tag] = false # Set to false to avoid recursive nested repetitions
|
12
|
+
return_value
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_example_to_group(original_example, test_description, metadata_overrides = {})
|
16
|
+
repetition = original_example.duplicate_with(metadata_overrides)
|
17
|
+
repetition.metadata[:description] = test_description
|
18
|
+
original_example.example_group.context.add_example(repetition)
|
11
19
|
end
|
12
20
|
|
13
21
|
def run_example_or_duplicate(original_example, test_description)
|
@@ -16,9 +24,7 @@ RSpec.configure do |config|
|
|
16
24
|
original_example.metadata[:description] = test_description
|
17
25
|
original_example.run
|
18
26
|
else
|
19
|
-
|
20
|
-
repetition.metadata[:description] = test_description
|
21
|
-
original_example.example_group.context.add_example(repetition)
|
27
|
+
add_example_to_group(original_example, test_description)
|
22
28
|
end
|
23
29
|
end
|
24
30
|
|
@@ -27,7 +33,7 @@ RSpec.configure do |config|
|
|
27
33
|
|
28
34
|
now = Time.now
|
29
35
|
time_of_day = untag_example(original_example, :time_of_day)
|
30
|
-
test_segments = time_of_day
|
36
|
+
test_segments = Array(time_of_day)
|
31
37
|
test_segments = [:hours] if test_segments == [true]
|
32
38
|
hours_to_run = test_segments.include?(:hours) ? (0..23) : [now.hour]
|
33
39
|
minutes_to_run = test_segments.include?(:minutes) ? (0..59) : [now.min]
|
@@ -36,13 +42,12 @@ RSpec.configure do |config|
|
|
36
42
|
hours_to_run.each do |hour|
|
37
43
|
minutes_to_run.each do |minute|
|
38
44
|
seconds_to_run.each do |second|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
45
|
+
frozen_time = Time.new(now.year, now.month, now.day, hour, minute, second)
|
46
|
+
test_description = "Run Time #{frozen_time.strftime('%H:%M:%S')}: #{shared_description}"
|
47
|
+
add_example_to_group(original_example, test_description, frozen_time: frozen_time)
|
48
|
+
|
49
|
+
# To avoid the original example being shown as "PENDING", mark it as executed
|
50
|
+
original_example.instance_variable_set(:@executed, true)
|
46
51
|
end
|
47
52
|
end
|
48
53
|
end
|
@@ -62,30 +67,27 @@ RSpec.configure do |config|
|
|
62
67
|
(-1000..1000).each do |millisecond|
|
63
68
|
# Travel to the specified hour, minute, second, and millisecond, allowing
|
64
69
|
# for time to elapse.
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
70
|
+
moving_time = Time.at(test_time_float + millisecond.to_f / 1000)
|
71
|
+
test_description = "Run Time #{moving_time.strftime('%H:%M:%S:%L')}: #{shared_description}"
|
72
|
+
add_example_to_group(original_example, test_description, moving_time: moving_time)
|
73
|
+
|
74
|
+
# To avoid the original example being shown as "PENDING", mark it as executed
|
75
|
+
original_example.instance_variable_set(:@executed, true)
|
72
76
|
end
|
73
77
|
end
|
74
78
|
|
75
79
|
config.around(elapsed_time: true) do |original_example|
|
76
80
|
shared_description = original_example.metadata[:description]
|
77
81
|
|
78
|
-
# Freeze time at the specified hour, minute, and/or second.
|
79
|
-
# We need to run the test within the Timecop.freeze block,
|
80
|
-
# in order to actually be affected by Timecop.
|
81
82
|
time_multipliers = untag_example(original_example, :elapsed_time)
|
82
83
|
time_multipliers = (1..10) unless time_multipliers.respond_to?(:each)
|
83
84
|
|
84
85
|
time_multipliers.each do |seconds_multiplier|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
86
|
+
test_description = "Run Speed #{seconds_multiplier}x Slower: #{shared_description}"
|
87
|
+
add_example_to_group(original_example, test_description, scaling_time: seconds_multiplier)
|
88
|
+
|
89
|
+
# To avoid the original example being shown as "PENDING", mark it as executed
|
90
|
+
original_example.instance_variable_set(:@executed, true)
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
@@ -93,21 +95,16 @@ RSpec.configure do |config|
|
|
93
95
|
shared_description = original_example.metadata[:description]
|
94
96
|
untag_example(original_example, :time_zones)
|
95
97
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
Timecop.travel(adjusted_time) do
|
107
|
-
test_description = "Time Zone Offset #{time_zone_hour}:#{time_zone_minute}: #{shared_description}"
|
108
|
-
run_example_or_duplicate(original_example, test_description)
|
109
|
-
end
|
110
|
-
end
|
98
|
+
timezone_hash = ActiveSupport::TimeZone.all.each_with_object({}) do |tz, memo|
|
99
|
+
memo[tz.formatted_offset] = tz.name
|
100
|
+
end
|
101
|
+
|
102
|
+
timezone_hash.each do |time_zone_offset, time_zone_name|
|
103
|
+
test_description = "Time Zone Offset #{time_zone_offset}: #{shared_description}"
|
104
|
+
add_example_to_group(original_example, test_description, time_zone: time_zone_name)
|
105
|
+
|
106
|
+
# To avoid the original example being shown as "PENDING", mark it as executed
|
107
|
+
original_example.instance_variable_set(:@executed, true)
|
111
108
|
end
|
112
109
|
end
|
113
110
|
|
@@ -122,4 +119,46 @@ RSpec.configure do |config|
|
|
122
119
|
run_example_or_duplicate(original_example, test_description)
|
123
120
|
end
|
124
121
|
end
|
122
|
+
|
123
|
+
config.before(:each, frozen_time: true) do |example|
|
124
|
+
time = example.metadata[:frozen_time]
|
125
|
+
time = Time.parse(example.metadata[:frozen_time]) if time.is_a?(String)
|
126
|
+
# Freeze time at the specified hour, minute, and/or second.
|
127
|
+
Timecop.freeze(time)
|
128
|
+
end
|
129
|
+
|
130
|
+
config.after(:each, frozen_time: true) do
|
131
|
+
Timecop.return
|
132
|
+
end
|
133
|
+
|
134
|
+
config.before(:each, moving_time: true) do |example|
|
135
|
+
time = example.metadata[:moving_time]
|
136
|
+
time = Time.parse(example.metadata[:moving_time]) if time.is_a?(String)
|
137
|
+
# Travel to time at the specified hour, minute, and/or second.
|
138
|
+
Timecop.travel(time)
|
139
|
+
end
|
140
|
+
|
141
|
+
config.after(:each, moving_time: true) do
|
142
|
+
Timecop.return
|
143
|
+
end
|
144
|
+
|
145
|
+
config.before(:each, scaling_time: true) do |example|
|
146
|
+
time_multiplier = example.metadata[:scaling_time]
|
147
|
+
# Scale time by the specified multiplier.
|
148
|
+
Timecop.scale(time_multiplier)
|
149
|
+
end
|
150
|
+
|
151
|
+
config.after(:each, scaling_time: true) do
|
152
|
+
Timecop.return
|
153
|
+
end
|
154
|
+
|
155
|
+
config.before(:each, time_zone: true) do |example|
|
156
|
+
ENV['OLD_TIME_ZONE'] = Time.zone&.name
|
157
|
+
# Switch to the given time zone for the duration of the example.
|
158
|
+
Time.zone = example.metadata[:time_zone]
|
159
|
+
end
|
160
|
+
|
161
|
+
config.after(:each, time_zone: true) do
|
162
|
+
Time.zone = ENV['OLD_TIME_ZONE']
|
163
|
+
end
|
125
164
|
end
|
data/lib/marsh_grass/version.rb
CHANGED
data/marsh_grass.gemspec
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# coding: utf-8
|
4
3
|
lib = File.expand_path('../lib', __FILE__)
|
5
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
5
|
require 'marsh_grass/version'
|
@@ -10,16 +9,16 @@ Gem::Specification.new do |spec|
|
|
10
9
|
spec.version = MarshGrass::VERSION
|
11
10
|
spec.authors = [
|
12
11
|
'Wes Rich',
|
13
|
-
'Amanda
|
12
|
+
'Amanda Pouget'
|
14
13
|
]
|
15
14
|
spec.email = [
|
16
15
|
'wes.rich@rolemodelsoftware.com',
|
17
|
-
'amanda.
|
16
|
+
'amanda.pouget@rolemodelsoftware.com'
|
18
17
|
]
|
19
18
|
|
20
|
-
spec.summary =
|
21
|
-
spec.description =
|
22
|
-
spec.homepage =
|
19
|
+
spec.summary = 'A set of tools to help diagnose random test failures.'
|
20
|
+
spec.description = 'Currently works with RSpec tags to run against possible test failure scenarios.'
|
21
|
+
spec.homepage = 'https://github.com/RoleModel/marsh_grass'
|
23
22
|
spec.license = 'MIT'
|
24
23
|
|
25
24
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
@@ -29,10 +28,13 @@ Gem::Specification.new do |spec|
|
|
29
28
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
29
|
spec.require_paths = ['lib']
|
31
30
|
|
32
|
-
spec.
|
33
|
-
|
31
|
+
spec.required_ruby_version = '>= 3.0'
|
32
|
+
|
33
|
+
spec.add_development_dependency 'bundler', '>= 2.0', '< 5.0'
|
34
34
|
spec.add_development_dependency 'pry-byebug', '~> 3'
|
35
|
-
spec.add_development_dependency '
|
35
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
36
|
+
spec.add_dependency 'activesupport', '>= 7.1', '< 8.1'
|
36
37
|
spec.add_dependency 'rspec', '~> 3.6'
|
37
|
-
spec.add_dependency '
|
38
|
+
spec.add_dependency 'rspec-rails', '~> 6'
|
39
|
+
spec.add_dependency 'timecop', '~> 0.9'
|
38
40
|
end
|
metadata
CHANGED
@@ -1,72 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marsh_grass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wes Rich
|
8
|
-
- Amanda
|
9
|
-
autorequire:
|
8
|
+
- Amanda Pouget
|
10
9
|
bindir: exe
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bundler
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
16
|
requirements:
|
18
|
-
- - "
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
- - "<"
|
19
21
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
22
|
+
version: '5.0'
|
21
23
|
type: :development
|
22
24
|
prerelease: false
|
23
25
|
version_requirements: !ruby/object:Gem::Requirement
|
24
26
|
requirements:
|
25
|
-
- - "
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.0'
|
30
|
+
- - "<"
|
26
31
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
32
|
+
version: '5.0'
|
28
33
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
34
|
+
name: pry-byebug
|
30
35
|
requirement: !ruby/object:Gem::Requirement
|
31
36
|
requirements:
|
32
37
|
- - "~>"
|
33
38
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
39
|
+
version: '3'
|
35
40
|
type: :development
|
36
41
|
prerelease: false
|
37
42
|
version_requirements: !ruby/object:Gem::Requirement
|
38
43
|
requirements:
|
39
44
|
- - "~>"
|
40
45
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
46
|
+
version: '3'
|
42
47
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
48
|
+
name: rake
|
44
49
|
requirement: !ruby/object:Gem::Requirement
|
45
50
|
requirements:
|
46
51
|
- - "~>"
|
47
52
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
53
|
+
version: '13.0'
|
49
54
|
type: :development
|
50
55
|
prerelease: false
|
51
56
|
version_requirements: !ruby/object:Gem::Requirement
|
52
57
|
requirements:
|
53
58
|
- - "~>"
|
54
59
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
60
|
+
version: '13.0'
|
56
61
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
62
|
+
name: activesupport
|
58
63
|
requirement: !ruby/object:Gem::Requirement
|
59
64
|
requirements:
|
60
|
-
- - "
|
65
|
+
- - ">="
|
61
66
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
63
|
-
|
67
|
+
version: '7.1'
|
68
|
+
- - "<"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '8.1'
|
71
|
+
type: :runtime
|
64
72
|
prerelease: false
|
65
73
|
version_requirements: !ruby/object:Gem::Requirement
|
66
74
|
requirements:
|
67
|
-
- - "
|
75
|
+
- - ">="
|
68
76
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
77
|
+
version: '7.1'
|
78
|
+
- - "<"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '8.1'
|
70
81
|
- !ruby/object:Gem::Dependency
|
71
82
|
name: rspec
|
72
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,25 +92,39 @@ dependencies:
|
|
81
92
|
- - "~>"
|
82
93
|
- !ruby/object:Gem::Version
|
83
94
|
version: '3.6'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: rspec-rails
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '6'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '6'
|
84
109
|
- !ruby/object:Gem::Dependency
|
85
110
|
name: timecop
|
86
111
|
requirement: !ruby/object:Gem::Requirement
|
87
112
|
requirements:
|
88
113
|
- - "~>"
|
89
114
|
- !ruby/object:Gem::Version
|
90
|
-
version: '0'
|
115
|
+
version: '0.9'
|
91
116
|
type: :runtime
|
92
117
|
prerelease: false
|
93
118
|
version_requirements: !ruby/object:Gem::Requirement
|
94
119
|
requirements:
|
95
120
|
- - "~>"
|
96
121
|
- !ruby/object:Gem::Version
|
97
|
-
version: '0'
|
122
|
+
version: '0.9'
|
98
123
|
description: Currently works with RSpec tags to run against possible test failure
|
99
124
|
scenarios.
|
100
125
|
email:
|
101
126
|
- wes.rich@rolemodelsoftware.com
|
102
|
-
- amanda.
|
127
|
+
- amanda.pouget@rolemodelsoftware.com
|
103
128
|
executables: []
|
104
129
|
extensions: []
|
105
130
|
extra_rdoc_files: []
|
@@ -115,11 +140,10 @@ files:
|
|
115
140
|
- lib/marsh_grass/rspec.rb
|
116
141
|
- lib/marsh_grass/version.rb
|
117
142
|
- marsh_grass.gemspec
|
118
|
-
homepage:
|
143
|
+
homepage: https://github.com/RoleModel/marsh_grass
|
119
144
|
licenses:
|
120
145
|
- MIT
|
121
146
|
metadata: {}
|
122
|
-
post_install_message:
|
123
147
|
rdoc_options: []
|
124
148
|
require_paths:
|
125
149
|
- lib
|
@@ -127,16 +151,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
127
151
|
requirements:
|
128
152
|
- - ">="
|
129
153
|
- !ruby/object:Gem::Version
|
130
|
-
version: '0'
|
154
|
+
version: '3.0'
|
131
155
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
156
|
requirements:
|
133
157
|
- - ">="
|
134
158
|
- !ruby/object:Gem::Version
|
135
159
|
version: '0'
|
136
160
|
requirements: []
|
137
|
-
|
138
|
-
rubygems_version: 2.6.13
|
139
|
-
signing_key:
|
161
|
+
rubygems_version: 3.7.1
|
140
162
|
specification_version: 4
|
141
163
|
summary: A set of tools to help diagnose random test failures.
|
142
164
|
test_files: []
|