Skip to content

Commit 6da4539

Browse files
authored
[Fix #39] Handle Interrupts (#40)
RSpec tracer does not corrupt cache on interrupts.
1 parent 055347f commit 6da4539

File tree

5 files changed

+74
-10
lines changed

5 files changed

+74
-10
lines changed

lib/rspec_tracer.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ def generate_reports
196196
def process_dependency
197197
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
198198

199+
runner.register_interrupted_examples
199200
runner.register_deleted_examples
200201
runner.register_dependency(coverage_reporter.examples_coverage)
201202
runner.register_untraced_dependency(@traced_files)

lib/rspec_tracer/cache.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
module RSpecTracer
44
class Cache
5-
attr_reader :all_examples, :flaky_examples, :failed_examples, :pending_examples,
6-
:all_files, :dependency, :run_id
5+
attr_reader :all_examples, :interrupted_examples, :flaky_examples, :failed_examples,
6+
:pending_examples, :all_files, :dependency, :run_id
77

88
def initialize
99
@run_id = last_run_id
@@ -12,6 +12,7 @@ def initialize
1212
@cached = false
1313

1414
@all_examples = {}
15+
@interrupted_examples = Set.new
1516
@flaky_examples = Set.new
1617
@failed_examples = Set.new
1718
@pending_examples = Set.new
@@ -74,7 +75,11 @@ def load_all_examples_cache
7475
end
7576

7677
@all_examples.each_value do |example|
77-
example[:execution_result].transform_keys!(&:to_sym)
78+
if example.key?(:execution_result)
79+
example[:execution_result].transform_keys!(&:to_sym)
80+
else
81+
@interrupted_examples << example[:example_id]
82+
end
7883

7984
example[:run_reason] = nil
8085
end

lib/rspec_tracer/html_reporter/reporter.rb

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,19 @@ def format_examples
6060
id: example_id,
6161
description: example[:full_description],
6262
location: example_location(example[:rerun_file_name], example[:rerun_line_number]),
63-
status: example[:run_reason] || 'Skipped',
63+
status: example[:run_reason] || 'Skipped'
64+
}.merge(example_result(example_id, example))
65+
end
66+
end
67+
68+
def example_result(example_id, example)
69+
if example[:execution_result].nil?
70+
{
71+
result: @reporter.example_interrupted?(example_id) ? 'Interrupted' : '_',
72+
last_run: '_'
73+
}
74+
else
75+
{
6476
result: example[:execution_result][:status].capitalize,
6577
last_run: example_run_local_time(example[:execution_result][:finished_at])
6678
}
@@ -176,7 +188,7 @@ def template(name)
176188

177189
def example_status_css_class(example_status)
178190
case example_status.split.first
179-
when 'Failed', 'Flaky'
191+
when 'Failed', 'Flaky', 'Interrupted'
180192
'red'
181193
when 'Pending'
182194
'yellow'
@@ -189,7 +201,7 @@ def example_result_css_class(example_result)
189201
case example_result
190202
when 'Passed'
191203
'green'
192-
when 'Failed'
204+
when 'Failed', 'Interrupted'
193205
'red'
194206
when 'Pending'
195207
'yellow'

lib/rspec_tracer/reporter.rb

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
module RSpecTracer
44
class Reporter
5-
attr_reader :all_examples, :possibly_flaky_examples, :flaky_examples, :pending_examples,
6-
:all_files, :modified_files, :deleted_files, :dependency, :reverse_dependency,
7-
:examples_coverage, :last_run
5+
attr_reader :all_examples, :interrupted_examples, :possibly_flaky_examples,
6+
:flaky_examples, :pending_examples, :all_files, :modified_files,
7+
:deleted_files, :dependency, :reverse_dependency, :examples_coverage,
8+
:last_run
89

910
def initialize
1011
initialize_examples
@@ -37,8 +38,21 @@ def on_example_pending(example_id, result)
3738
@all_examples[example_id][:execution_result] = formatted_execution_result(result)
3839
end
3940

41+
def register_interrupted_examples
42+
@all_examples.each_pair do |example_id, example|
43+
next if example.key?(:execution_result)
44+
45+
@interrupted_examples << example_id
46+
end
47+
48+
return if @interrupted_examples.empty?
49+
50+
puts "RSpec tracer is not processing #{@interrupted_examples.count} interrupted examples"
51+
end
52+
4053
def register_deleted_examples(seen_examples)
4154
@deleted_examples = seen_examples.keys.to_set - (@skipped_examples | @all_examples.keys)
55+
@deleted_examples -= @interrupted_examples
4256

4357
@deleted_examples.select! do |example_id|
4458
example = seen_examples[example_id]
@@ -63,6 +77,10 @@ def register_pending_example(example_id)
6377
@pending_examples << example_id
6478
end
6579

80+
def example_interrupted?(example_id)
81+
@interrupted_examples.include?(example_id)
82+
end
83+
6684
def example_passed?(example_id)
6785
@passed_examples.include?(example_id)
6886
end
@@ -128,6 +146,8 @@ def register_examples_coverage(examples_coverage)
128146

129147
def generate_reverse_dependency_report
130148
@dependency.each_pair do |example_id, files|
149+
next if @interrupted_examples.include?(example_id)
150+
131151
example_file = @all_examples[example_id][:rerun_file_name]
132152

133153
files.each do |file_name|
@@ -145,9 +165,11 @@ def generate_last_run_report
145165
pid: RSpecTracer.pid,
146166
actual_count: RSpec.world.example_count + @skipped_examples.count,
147167
example_count: RSpec.world.example_count,
168+
interrupted_examples: @interrupted_examples.count,
148169
failed_examples: @failed_examples.count,
149170
skipped_examples: @skipped_examples.count,
150-
pending_examples: @pending_examples.count
171+
pending_examples: @pending_examples.count,
172+
flaky_examples: @flaky_examples.count
151173
}
152174
end
153175

@@ -182,6 +204,7 @@ def write_reports
182204
def initialize_examples
183205
@all_examples = {}
184206
@duplicate_examples = Hash.new { |examples, example_id| examples[example_id] = [] }
207+
@interrupted_examples = Set.new
185208
@passed_examples = Set.new
186209
@possibly_flaky_examples = Set.new
187210
@flaky_examples = Set.new

lib/rspec_tracer/runner.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class Runner
88
EXAMPLE_RUN_REASON = {
99
explicit_run: 'Explicit run',
1010
no_cache: 'No cache',
11+
interrupted: 'Interrupted previously',
1112
flaky_example: 'Flaky example',
1213
failed_example: 'Failed previously',
1314
pending_example: 'Pending previously',
@@ -59,6 +60,10 @@ def on_example_pending(example_id, execution_result)
5960
@reporter.on_example_pending(example_id, execution_result)
6061
end
6162

63+
def register_interrupted_examples
64+
@reporter.register_interrupted_examples
65+
end
66+
6267
def register_deleted_examples
6368
@reporter.register_deleted_examples(@cache.all_examples)
6469
end
@@ -77,6 +82,7 @@ def generate_missed_coverage
7782

7883
@cache.cached_examples_coverage.each_pair do |example_id, example_coverage|
7984
example_coverage.each_pair do |file_path, line_coverage|
85+
next if @reporter.example_interrupted?(example_id)
8086
next unless @reporter.example_skipped?(example_id)
8187

8288
file_name = RSpecTracer::SourceFile.file_name(file_path)
@@ -97,6 +103,8 @@ def register_dependency(examples_coverage)
97103
filtered_files = Set.new
98104

99105
examples_coverage.each_pair do |example_id, example_coverage|
106+
next if @reporter.example_interrupted?(example_id)
107+
100108
register_example_files_dependency(example_id)
101109

102110
example_coverage.each_key do |file_path|
@@ -122,6 +130,8 @@ def register_untraced_dependency(trace_point_files)
122130
@reporter.register_source_file(source_file)
123131

124132
@reporter.all_examples.each_key do |example_id|
133+
next if @reporter.example_interrupted?(example_id)
134+
125135
@reporter.register_dependency(example_id, source_file[:file_name])
126136
end
127137
end
@@ -169,6 +179,7 @@ def filter_examples_to_run
169179
end
170180

171181
def filter_by_example_status
182+
add_previously_interrupted_examples
172183
add_previously_flaky_examples
173184
add_previously_failed_examples
174185
add_previously_pending_examples
@@ -183,6 +194,12 @@ def filter_by_files_changed
183194
end
184195
end
185196

197+
def add_previously_interrupted_examples
198+
@cache.interrupted_examples.each do |example_id|
199+
@filtered_examples[example_id] = EXAMPLE_RUN_REASON[:interrupted]
200+
end
201+
end
202+
186203
def add_previously_flaky_examples
187204
@cache.flaky_examples.each do |example_id|
188205
@filtered_examples[example_id] = EXAMPLE_RUN_REASON[:flaky_example]
@@ -249,6 +266,8 @@ def fetch_rspec_required_files
249266
end
250267

251268
def register_example_files_dependency(example_id)
269+
return if @reporter.example_interrupted?(example_id)
270+
252271
example = @reporter.all_examples[example_id]
253272

254273
register_example_file_dependency(example_id, example[:file_name])
@@ -259,13 +278,17 @@ def register_example_files_dependency(example_id)
259278
end
260279

261280
def register_example_file_dependency(example_id, file_name)
281+
return if @reporter.example_interrupted?(example_id)
282+
262283
source_file = RSpecTracer::SourceFile.from_name(file_name)
263284

264285
@reporter.register_source_file(source_file)
265286
@reporter.register_dependency(example_id, file_name)
266287
end
267288

268289
def register_file_dependency(example_id, file_path)
290+
return if @reporter.example_interrupted?(example_id)
291+
269292
source_file = RSpecTracer::SourceFile.from_path(file_path)
270293

271294
return false if RSpecTracer.filters.any? { |filter| filter.match?(source_file) }

0 commit comments

Comments
 (0)