flakey_spec_catcher 0.11.0 → 0.12.1
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 +4 -4
- data/flakey_spec_catcher.gemspec +8 -3
- data/lib/flakey_spec_catcher/change_capsule.rb +19 -6
- data/lib/flakey_spec_catcher/cli_override.rb +5 -1
- data/lib/flakey_spec_catcher/rerun_manager.rb +11 -0
- data/lib/flakey_spec_catcher/rspec_result.rb +28 -9
- data/lib/flakey_spec_catcher/rspec_result_manager.rb +12 -1
- data/lib/flakey_spec_catcher/runner.rb +25 -6
- data/lib/flakey_spec_catcher/timecop_manager.rb +72 -0
- data/lib/flakey_spec_catcher/user_config.rb +13 -15
- data/lib/flakey_spec_catcher/version.rb +1 -1
- metadata +24 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c372506dc001281381c2da00adfbb57630541aec3ef03a537becb9330da6a47
|
4
|
+
data.tar.gz: '041469dd05911ac067396527eed5bc5de0c480c3e981a1d6688eb4070abe188d'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4390187c9364ebe61355e0de7f821bfac2331baa85435ec7afceffe02500baea8b79ccc126d448c5f97cb20093e4bcbf097ba281e81fdc7461f18c06bacca337
|
7
|
+
data.tar.gz: 7599cda6777957328931ba99f50369ca6c567e8f1d947c85862971ac504170e256617ac61de68e099b22516d5af133c0736044d3809d711f2df891dff282c481
|
data/flakey_spec_catcher.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# rubocop:disable Layout/ExtraSpacing, Layout/SpaceAroundOperators
|
3
|
+
# rubocop:disable Layout/ExtraSpacing, Layout/SpaceAroundOperators, Metrics/BlockLength
|
4
4
|
require './lib/flakey_spec_catcher/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
@@ -27,14 +27,19 @@ Gem::Specification.new do |gem|
|
|
27
27
|
gem.executables = 'flakey_spec_catcher'
|
28
28
|
gem.require_paths = ['lib']
|
29
29
|
|
30
|
-
gem.metadata
|
30
|
+
gem.metadata = {
|
31
|
+
'allowed_push_host' => 'https://rubygems.org',
|
32
|
+
'rubygems_mfa_required' => 'true'
|
33
|
+
}
|
34
|
+
|
31
35
|
gem.required_ruby_version = '>= 2.6'
|
32
36
|
|
33
37
|
gem.add_dependency 'rspec', '~> 3.10'
|
38
|
+
gem.add_dependency 'timecop', '~> 0.9'
|
34
39
|
gem.add_development_dependency 'byebug', '~> 11.1'
|
35
40
|
gem.add_development_dependency 'climate_control', '~> 0.2'
|
36
41
|
gem.add_development_dependency 'rake', '~> 13.0'
|
37
42
|
gem.add_development_dependency 'rubocop', '~> 0.93.1'
|
38
43
|
gem.add_development_dependency 'simplecov', '~> 0.19'
|
39
44
|
end
|
40
|
-
# rubocop:enable Layout/ExtraSpacing, Layout/SpaceAroundOperators
|
45
|
+
# rubocop:enable Layout/ExtraSpacing, Layout/SpaceAroundOperators, Metrics/BlockLength
|
@@ -24,23 +24,30 @@ module FlakeySpecCatcher
|
|
24
24
|
@change_contexts.map(&:rerun_info)
|
25
25
|
end
|
26
26
|
|
27
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
27
28
|
def fill_contexts
|
28
29
|
change_context_stack = []
|
29
30
|
ignore_scope_closure = 0
|
30
31
|
lines_in_file = File.read(@file_name).split("\n")
|
31
32
|
lines_in_file.each_with_index do |line, index|
|
33
|
+
shared_example_identified = false
|
34
|
+
|
32
35
|
# Check if line matches an rspec example or examplegroup format
|
33
36
|
if line =~ spec_scope
|
34
37
|
handle_change_context(line, index, change_context_stack)
|
35
38
|
# Else, ignore other blocks that might pollute context stack
|
39
|
+
elsif line =~ shared_example_scope
|
40
|
+
handle_change_context(line, index, change_context_stack)
|
41
|
+
shared_example_identified = true
|
36
42
|
elsif line_matches_method_or_block(line)
|
37
43
|
ignore_scope_closure += 1
|
38
44
|
end
|
39
45
|
|
40
46
|
fill_context(line, index, change_context_stack)
|
41
47
|
|
42
|
-
|
43
|
-
|
48
|
+
if shared_example_identified
|
49
|
+
change_context_stack.pop
|
50
|
+
elsif line =~ pop_scope
|
44
51
|
if ignore_scope_closure.positive?
|
45
52
|
ignore_scope_closure -= 1
|
46
53
|
else
|
@@ -49,6 +56,7 @@ module FlakeySpecCatcher
|
|
49
56
|
end
|
50
57
|
end
|
51
58
|
end
|
59
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
52
60
|
|
53
61
|
private
|
54
62
|
|
@@ -70,14 +78,15 @@ module FlakeySpecCatcher
|
|
70
78
|
end
|
71
79
|
|
72
80
|
def spec_scope
|
73
|
-
# Not sure if we need to check for description in quotes
|
74
|
-
# spec_scope = /^\s*(#{SCOPE_SPECIFIERS.join("|")})\s*('.*'|".*").*do\s*$/
|
75
|
-
|
76
81
|
/\s*(#{SCOPE_SPECIFIERS.join("|")}).*\s+do.*$/
|
77
82
|
end
|
78
83
|
|
84
|
+
def shared_example_scope
|
85
|
+
/\s*(#{SHARED_EXAMPLES.join("|")}).*\s+.*$/
|
86
|
+
end
|
87
|
+
|
79
88
|
def line_matches_method_or_block(line)
|
80
|
-
return true if line =~ /\s*do(\s+|$)/ || line =~ /^\s*def\s+/ || line =~ /^\s*if\s+/
|
89
|
+
return true if line =~ /\s*do(\s+|$)/ || line =~ /^\s*def\s+/ || line =~ /^\s*if\s+/ || line =~ /^\s*class\s+/
|
81
90
|
|
82
91
|
false
|
83
92
|
end
|
@@ -122,6 +131,10 @@ module FlakeySpecCatcher
|
|
122
131
|
|
123
132
|
current_scope = change_contexts[-1].rerun_info
|
124
133
|
parent_scope = change_contexts[-2].rerun_info
|
134
|
+
|
135
|
+
# Don't build the file level context into spec tree
|
136
|
+
return unless parent_scope =~ /:/
|
137
|
+
|
125
138
|
@spec_tree[parent_scope] = if @spec_tree[parent_scope]
|
126
139
|
@spec_tree[parent_scope] << current_scope
|
127
140
|
else
|
@@ -9,7 +9,7 @@ module FlakeySpecCatcher
|
|
9
9
|
class CliOverride
|
10
10
|
attr_reader :rerun_patterns, :rerun_usage, :repeat_factor, :enable_runs, :excluded_tags, :use_parent, :dry_run
|
11
11
|
attr_reader :output_file, :split_nodes, :split_index, :verbose, :test_options, :break_on_first_failure
|
12
|
-
attr_reader :list_child_specs
|
12
|
+
attr_reader :list_child_specs, :random_timing
|
13
13
|
|
14
14
|
def initialize
|
15
15
|
@dry_run = false
|
@@ -65,6 +65,10 @@ module FlakeySpecCatcher
|
|
65
65
|
@list_child_specs = list_child_specs
|
66
66
|
end
|
67
67
|
|
68
|
+
opts.on('--random-timing', 'Run Specs at random times') do |random_timing|
|
69
|
+
@random_timing = random_timing
|
70
|
+
end
|
71
|
+
|
68
72
|
opts.on('-e', '--excluded-tags=EXCLUDED_TAGS',
|
69
73
|
'Specify tags to exclude in a comma separated list') do |tags|
|
70
74
|
@excluded_tags = parse_tags(tags)
|
@@ -173,11 +173,22 @@ module FlakeySpecCatcher
|
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
|
+
def transform_file_level_change(test, tree)
|
177
|
+
# Map file level changes to the highest level Example Group in the tree
|
178
|
+
if test =~ /:/
|
179
|
+
test
|
180
|
+
else
|
181
|
+
tree.keys.first
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
176
185
|
def transform_parent_specs(tests)
|
177
186
|
transformed_tests = []
|
187
|
+
|
178
188
|
tests.each do |test|
|
179
189
|
capsule = @git_controller.capsule_manager.change_capsules.find { |c| c.file_name == test.split(':')[0] }
|
180
190
|
spec_tree = capsule.spec_tree
|
191
|
+
test = transform_file_level_change(test, spec_tree)
|
181
192
|
# If test is a key in the spec_tree, it's an example group, so we queue up its descendant examples
|
182
193
|
if spec_tree[test]
|
183
194
|
spec_tree[test].each do |child|
|
@@ -13,13 +13,15 @@ module FlakeySpecCatcher
|
|
13
13
|
# This class will then organize and output the results accordingly.
|
14
14
|
class RspecResult
|
15
15
|
attr_accessor :description, :location, :total_times_run, :total_failures
|
16
|
+
attr_reader :spec_start_times, :failures
|
16
17
|
|
17
|
-
def initialize(description, location, exception_message = nil)
|
18
|
+
def initialize(description, location, spec_start_times, exception_message = nil)
|
18
19
|
@description = description
|
19
20
|
@location = location
|
20
21
|
@total_times_run = 1
|
21
22
|
@total_failures = exception_message ? 1 : 0
|
22
23
|
@failures = []
|
24
|
+
@spec_start_times = spec_start_times
|
23
25
|
add_failure(exception_message) if exception_message
|
24
26
|
end
|
25
27
|
|
@@ -34,30 +36,47 @@ module FlakeySpecCatcher
|
|
34
36
|
|
35
37
|
def add_failure(exception_message)
|
36
38
|
failure = @failures.find { |f| f.exception_message == exception_message }
|
37
|
-
|
39
|
+
if failure
|
40
|
+
failure.add_failure(current_spec_start_time)
|
41
|
+
else
|
42
|
+
@failures.push(RSpecFailure.new(exception_message, current_spec_start_time))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def current_spec_start_time
|
47
|
+
@spec_start_times[@total_times_run - 1]
|
38
48
|
end
|
39
49
|
|
40
50
|
def print_results
|
41
51
|
puts "\n#{@description.yellow} (#{location})
|
42
52
|
\nFAILED #{total_failures} / #{total_times_run} times"
|
43
53
|
|
44
|
-
@failures.each
|
45
|
-
puts "#{f.count.to_s.indent(2)} times with exception message:"
|
46
|
-
puts f.exception_message.indent(4).red.to_s
|
47
|
-
end
|
54
|
+
@failures.each { |failure| puts failure.failure_summary }
|
48
55
|
end
|
49
56
|
|
50
57
|
# Simple class to contain failed example data
|
51
58
|
class RSpecFailure
|
52
|
-
attr_reader :exception_message, :count
|
59
|
+
attr_reader :exception_message, :count, :spec_start_times
|
53
60
|
|
54
|
-
def initialize(exception_message)
|
61
|
+
def initialize(exception_message, spec_start_time = nil)
|
55
62
|
@exception_message = exception_message
|
56
63
|
@count = 1
|
64
|
+
@spec_start_times = [spec_start_time].compact
|
57
65
|
end
|
58
66
|
|
59
|
-
def add_failure
|
67
|
+
def add_failure(spec_start_time = nil)
|
60
68
|
@count += 1
|
69
|
+
@spec_start_times.push(spec_start_time) unless spec_start_time.nil?
|
70
|
+
end
|
71
|
+
|
72
|
+
def failure_summary
|
73
|
+
summary = "#{count.to_s.indent(2)} times with exception message:\n"
|
74
|
+
summary += exception_message.indent(4).red.to_s
|
75
|
+
return summary if spec_start_times.empty?
|
76
|
+
|
77
|
+
summary += "\n\nFailed at the following times:\n".indent(2)
|
78
|
+
summary += spec_start_times.map { |time| time.indent(4).yellow.to_s }.join("\n").to_s
|
79
|
+
summary
|
61
80
|
end
|
62
81
|
end
|
63
82
|
end
|
@@ -12,14 +12,25 @@ module FlakeySpecCatcher
|
|
12
12
|
# distinct example. It also provides helpers for adding new results,
|
13
13
|
# displaying aggregate results, and checking the state of the collection.
|
14
14
|
class RspecResultManager
|
15
|
+
attr_reader :results
|
16
|
+
|
15
17
|
def initialize(rspec_result_class)
|
16
18
|
@result_class = rspec_result_class
|
17
19
|
@results = []
|
20
|
+
@spec_start_times = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def track_spec_start_times(spec_times)
|
24
|
+
@spec_start_times = spec_times
|
18
25
|
end
|
19
26
|
|
20
27
|
def add_result(desc, location, message = nil)
|
21
28
|
result = @results.find { |r| r.location == location }
|
22
|
-
|
29
|
+
if result
|
30
|
+
result.add_run(message)
|
31
|
+
else
|
32
|
+
@results.push(@result_class.new(desc, location, @spec_start_times, message))
|
33
|
+
end
|
23
34
|
end
|
24
35
|
|
25
36
|
def print_results
|
@@ -7,10 +7,11 @@ require_relative './user_config'
|
|
7
7
|
require_relative './rerun_manager'
|
8
8
|
require_relative './rspec_result_manager'
|
9
9
|
require_relative './event_listener.rb'
|
10
|
+
require_relative './timecop_manager.rb'
|
10
11
|
|
11
12
|
module FlakeySpecCatcher
|
12
13
|
class Runner
|
13
|
-
attr_reader :user_config, :rerun_manager, :git_controller, :test_run_count
|
14
|
+
attr_reader :user_config, :rerun_manager, :git_controller, :test_run_count, :random_dates
|
14
15
|
|
15
16
|
def initialize(test_mode: false,
|
16
17
|
user_config: FlakeySpecCatcher::UserConfig.new,
|
@@ -18,17 +19,17 @@ module FlakeySpecCatcher
|
|
18
19
|
result_manager: FlakeySpecCatcher::RspecResultManager.new(FlakeySpecCatcher::RspecResult),
|
19
20
|
rerun_manager: FlakeySpecCatcher::RerunManager.new(git_controller: git_controller,
|
20
21
|
user_config: user_config))
|
21
|
-
|
22
22
|
@git_controller = git_controller
|
23
23
|
@user_config = user_config
|
24
24
|
@rerun_manager = rerun_manager
|
25
25
|
@rspec_result_manager = result_manager
|
26
26
|
@test_run_count = 0
|
27
27
|
@temp_output_file = @user_config.output_file + 'temp' unless @user_config.output_file == File::NULL
|
28
|
+
enable_random_timing
|
28
29
|
end
|
29
30
|
|
30
31
|
# Debug Methods
|
31
|
-
# rubocop:disable Metrics/AbcSize
|
32
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
32
33
|
def show_settings
|
33
34
|
puts 'Flakey Spec Catcher Settings:'
|
34
35
|
puts " Current Branch: #{@git_controller.branch}" unless @user_config.use_parent
|
@@ -39,12 +40,13 @@ module FlakeySpecCatcher
|
|
39
40
|
puts " Break on first failure: #{@user_config.break_on_first_failure}" if @user_config.break_on_first_failure
|
40
41
|
puts " Node Total: #{@user_config.split_nodes}" if @user_config.split_nodes
|
41
42
|
puts " Node Index: #{@user_config.split_index}" if @user_config.split_index
|
43
|
+
puts ' Random Timing: Enabled' if @user_config.random_timing
|
42
44
|
puts " Changed Specs Detected: #{@git_controller.changed_examples}"
|
43
45
|
return if @user_config.output_file == File::NULL
|
44
46
|
|
45
47
|
puts " Verbose Output Path: #{@user_config.output_file}"
|
46
48
|
end
|
47
|
-
# rubocop:enable Metrics/AbcSize
|
49
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
48
50
|
|
49
51
|
def rerun_preview
|
50
52
|
puts "\n********************************************"
|
@@ -73,8 +75,8 @@ module FlakeySpecCatcher
|
|
73
75
|
|
74
76
|
status = 0
|
75
77
|
@rerun_manager.rerun_capsules.sort.each do |capsule|
|
76
|
-
@user_config.repeat_factor.times do
|
77
|
-
iteration_status =
|
78
|
+
@user_config.repeat_factor.times do |iteration|
|
79
|
+
iteration_status = timecop_wrapper(capsule, iteration)
|
78
80
|
status = [status, iteration_status].max
|
79
81
|
break if @user_config.break_on_first_failure && !status.zero?
|
80
82
|
end
|
@@ -127,6 +129,23 @@ module FlakeySpecCatcher
|
|
127
129
|
end
|
128
130
|
end
|
129
131
|
|
132
|
+
def enable_random_timing
|
133
|
+
@random_dates = if @user_config.random_timing
|
134
|
+
FlakeySpecCatcher::TimecopManager.generate_dates(@user_config.repeat_factor)
|
135
|
+
else
|
136
|
+
[]
|
137
|
+
end
|
138
|
+
@rspec_result_manager.track_spec_start_times(@random_dates)
|
139
|
+
end
|
140
|
+
|
141
|
+
def timecop_wrapper(capsule, iteration)
|
142
|
+
if @user_config.random_timing
|
143
|
+
FlakeySpecCatcher::TimecopManager.randomly_travel_in_time(@random_dates[iteration]) { handle_capsule_rerun(capsule) }
|
144
|
+
else
|
145
|
+
handle_capsule_rerun(capsule)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
130
149
|
def print_flakey_specs_detected_message
|
131
150
|
puts "\n**********************************************".magenta
|
132
151
|
puts ' Flakiness Detected!'.magenta
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'time'
|
5
|
+
require 'timecop'
|
6
|
+
|
7
|
+
module FlakeySpecCatcher
|
8
|
+
class TimecopManager
|
9
|
+
def self.randomly_travel_in_time(date)
|
10
|
+
status = 0
|
11
|
+
Timecop.travel(date) do
|
12
|
+
status = yield
|
13
|
+
end
|
14
|
+
status
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.current_month
|
18
|
+
Time.now.month
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.current_year
|
22
|
+
Time.now.year
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.random_month
|
26
|
+
(current_month..12).to_a.sample
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.random_seconds
|
30
|
+
[0, 59].sample
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.random_minutes
|
34
|
+
[0, (1..58).to_a.sample, 59].sample
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.random_day(year, month)
|
38
|
+
last_day = last_day_of_month(year, month).day
|
39
|
+
[1, (1..last_day).to_a.sample, last_day].sample
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.last_day_of_month(year, month)
|
43
|
+
day = Date.new(year, month, -1).day
|
44
|
+
Time.local(year, month, day, 23, 59, 59)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.last_day_of_year(year)
|
48
|
+
Time.local(year, 12, 31, 11, 59, 59)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.random_hour
|
52
|
+
[0, (1..22).to_a.sample, 23].sample
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.random_date
|
56
|
+
year = current_year
|
57
|
+
month = random_month
|
58
|
+
day = random_day(year, month)
|
59
|
+
Time.local(year, month, day, random_hour, random_minutes, random_seconds)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.prioritized_dates
|
63
|
+
[last_day_of_month(current_year, current_month), last_day_of_year(current_year)]
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.generate_dates(count)
|
67
|
+
dates = prioritized_dates
|
68
|
+
(count - prioritized_dates.count).times { dates << random_date }
|
69
|
+
dates.map(&:iso8601).slice(0, count)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -3,20 +3,18 @@
|
|
3
3
|
require_relative './cli_override'
|
4
4
|
module FlakeySpecCatcher
|
5
5
|
# UserConfig class
|
6
|
-
#
|
7
6
|
# Captures user-defined settings to configure RSpec re-run settings.
|
8
7
|
|
9
8
|
class UserConfig
|
10
|
-
attr_reader :repeat_factor, :ignore_files, :ignore_branches, :silent_mode
|
11
|
-
attr_reader :
|
12
|
-
attr_reader :
|
13
|
-
attr_reader :
|
14
|
-
attr_reader :split_nodes, :split_index, :verbose, :test_options
|
15
|
-
attr_reader :break_on_first_failure, :list_child_specs
|
9
|
+
attr_reader :repeat_factor, :ignore_files, :ignore_branches, :silent_mode, :rerun_file_only, :rspec_usage_patterns
|
10
|
+
attr_reader :excluded_tags, :manual_rerun_patterns, :manual_rerun_usage, :enable_runs, :output_file
|
11
|
+
attr_reader :use_parent, :dry_run, :split_nodes, :split_index, :verbose, :test_options, :break_on_first_failure
|
12
|
+
attr_reader :list_child_specs, :random_timing
|
16
13
|
|
17
14
|
USER_CONFIG_ENV_VARS = %w[FSC_REPEAT_FACTOR FSC_IGNORE_FILES FSC_IGNORE_BRANCHES
|
18
15
|
FSC_SILENT_MODE FSC_RERUN_FILE_ONLY FSC_USAGE_PATTERNS
|
19
|
-
FSC_EXCLUDED_TAGS FSC_OUTPUT_FILE FSC_LIST_CHILD_SPECS
|
16
|
+
FSC_EXCLUDED_TAGS FSC_OUTPUT_FILE FSC_LIST_CHILD_SPECS
|
17
|
+
FSC_RANDOM_TIMING].freeze
|
20
18
|
|
21
19
|
def initialize(cli_override: CliOverride.new)
|
22
20
|
apply_env_var_settings
|
@@ -26,7 +24,7 @@ module FlakeySpecCatcher
|
|
26
24
|
|
27
25
|
private
|
28
26
|
|
29
|
-
# rubocop:disable Metrics/AbcSize
|
27
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
30
28
|
def apply_env_var_settings
|
31
29
|
@repeat_factor = initialize_repeat_factor(ENV['FSC_REPEAT_FACTOR'])
|
32
30
|
@ignore_files = env_var_string_to_array(ENV['FSC_IGNORE_FILES'])
|
@@ -34,6 +32,7 @@ module FlakeySpecCatcher
|
|
34
32
|
@silent_mode = env_var_string_to_bool(ENV['FSC_SILENT_MODE'])
|
35
33
|
@rerun_file_only = env_var_string_to_bool(ENV['FSC_RERUN_FILE_ONLY'])
|
36
34
|
@list_child_specs = env_var_string_to_bool(ENV['FSC_LIST_CHILD_SPECS'])
|
35
|
+
@random_timing = env_var_string_to_bool(ENV['FSC_RANDOM_TIMING'])
|
37
36
|
@rspec_usage_patterns = env_var_string_to_pairs(ENV['FSC_USAGE_PATTERNS'])
|
38
37
|
@excluded_tags = env_var_string_to_tags(ENV['FSC_EXCLUDED_TAGS'])
|
39
38
|
@output_file = ENV['FSC_OUTPUT_FILE']
|
@@ -48,6 +47,7 @@ module FlakeySpecCatcher
|
|
48
47
|
@repeat_factor = @cli_override.repeat_factor if @cli_override.repeat_factor.to_i.positive?
|
49
48
|
@break_on_first_failure = @cli_override.break_on_first_failure
|
50
49
|
@list_child_specs = @cli_override.list_child_specs unless @cli_override.list_child_specs.nil?
|
50
|
+
@random_timing = @cli_override.random_timing unless @cli_override.random_timing.nil?
|
51
51
|
@enable_runs = @cli_override.enable_runs
|
52
52
|
@dry_run = @cli_override.dry_run
|
53
53
|
@split_nodes = @cli_override.split_nodes unless @cli_override.split_nodes.nil?
|
@@ -61,7 +61,7 @@ module FlakeySpecCatcher
|
|
61
61
|
@verbose = @cli_override.verbose
|
62
62
|
@test_options = @cli_override.test_options
|
63
63
|
end
|
64
|
-
# rubocop:enable Metrics/AbcSize
|
64
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
65
65
|
|
66
66
|
def override_settings
|
67
67
|
apply_cli_override
|
@@ -109,11 +109,7 @@ module FlakeySpecCatcher
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def env_var_string_to_bool(env_var)
|
112
|
-
|
113
|
-
true
|
114
|
-
else
|
115
|
-
false
|
116
|
-
end
|
112
|
+
env_var.to_s.casecmp('true').zero?
|
117
113
|
end
|
118
114
|
|
119
115
|
def env_var_string_to_pairs(env_var)
|
@@ -187,6 +183,8 @@ module FlakeySpecCatcher
|
|
187
183
|
@rerun_file_only = env_var_string_to_bool(env_value)
|
188
184
|
when 'FSC_LIST_CHILD_SPECS'
|
189
185
|
@list_child_specs = env_var_string_to_bool(env_value)
|
186
|
+
when 'FSC_RANDOM_TIMING'
|
187
|
+
@random_timing = env_var_string_to_bool(env_value)
|
190
188
|
when 'FSC_USAGE_PATTERNS'
|
191
189
|
@rspec_usage_patterns = env_var_string_to_pairs(env_value)
|
192
190
|
when 'FSC_EXCLUDED_TAGS'
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flakey_spec_catcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Watson
|
8
8
|
- Mikey Hargiss
|
9
9
|
- Ben Nelson
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2021-
|
13
|
+
date: 2021-11-15 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -26,6 +26,20 @@ dependencies:
|
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '3.10'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: timecop
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0.9'
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0.9'
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: byebug
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,7 +110,7 @@ dependencies:
|
|
96
110
|
- - "~>"
|
97
111
|
- !ruby/object:Gem::Version
|
98
112
|
version: '0.19'
|
99
|
-
description:
|
113
|
+
description:
|
100
114
|
email:
|
101
115
|
- bwatson@instructure.com
|
102
116
|
- mhargiss@instructure.com
|
@@ -126,16 +140,18 @@ files:
|
|
126
140
|
- lib/flakey_spec_catcher/rspec_result.rb
|
127
141
|
- lib/flakey_spec_catcher/rspec_result_manager.rb
|
128
142
|
- lib/flakey_spec_catcher/runner.rb
|
143
|
+
- lib/flakey_spec_catcher/timecop_manager.rb
|
129
144
|
- lib/flakey_spec_catcher/user_config.rb
|
130
145
|
- lib/flakey_spec_catcher/version.rb
|
131
146
|
- lib/helpers/colorize.rb
|
132
147
|
- lib/helpers/indent_string.rb
|
133
|
-
homepage:
|
148
|
+
homepage:
|
134
149
|
licenses:
|
135
150
|
- MIT
|
136
151
|
metadata:
|
137
152
|
allowed_push_host: https://rubygems.org
|
138
|
-
|
153
|
+
rubygems_mfa_required: 'true'
|
154
|
+
post_install_message:
|
139
155
|
rdoc_options: []
|
140
156
|
require_paths:
|
141
157
|
- lib
|
@@ -150,8 +166,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
166
|
- !ruby/object:Gem::Version
|
151
167
|
version: '0'
|
152
168
|
requirements: []
|
153
|
-
rubygems_version: 3.
|
154
|
-
signing_key:
|
169
|
+
rubygems_version: 3.1.6
|
170
|
+
signing_key:
|
155
171
|
specification_version: 4
|
156
172
|
summary: Run new or changed specs many times to prevent unreliable specs
|
157
173
|
test_files: []
|