rspec-tracer 1.2.3 → 2.0.0.pre.2
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/CHANGELOG.md +384 -67
- data/README.md +454 -429
- data/bin/rspec-tracer +15 -0
- data/lib/rspec_tracer/cache/Rakefile +43 -0
- data/lib/rspec_tracer/cli/cache_clear.rb +111 -0
- data/lib/rspec_tracer/cli/cache_info.rb +104 -0
- data/lib/rspec_tracer/cli/doctor.rb +284 -0
- data/lib/rspec_tracer/cli/explain.rb +158 -0
- data/lib/rspec_tracer/cli/report_open.rb +82 -0
- data/lib/rspec_tracer/cli.rb +116 -0
- data/lib/rspec_tracer/configuration.rb +1196 -3
- data/lib/rspec_tracer/engine.rb +1168 -0
- data/lib/rspec_tracer/example.rb +141 -11
- data/lib/rspec_tracer/filter.rb +35 -0
- data/lib/rspec_tracer/line_stub.rb +61 -0
- data/lib/rspec_tracer/load_config.rb +2 -2
- data/lib/rspec_tracer/logger.rb +15 -0
- data/lib/rspec_tracer/rails/README.md +78 -0
- data/lib/rspec_tracer/rails/i18n_tracking.rb +137 -0
- data/lib/rspec_tracer/rails/notifications.rb +263 -0
- data/lib/rspec_tracer/rails/preset.rb +94 -0
- data/lib/rspec_tracer/rails/railtie.rb +22 -0
- data/lib/rspec_tracer/rails.rb +15 -0
- data/lib/rspec_tracer/remote_cache/README.md +140 -0
- data/lib/rspec_tracer/remote_cache/Rakefile +35 -11
- data/lib/rspec_tracer/remote_cache/archive.rb +137 -0
- data/lib/rspec_tracer/remote_cache/backend.rb +73 -0
- data/lib/rspec_tracer/remote_cache/git_ancestry.rb +241 -0
- data/lib/rspec_tracer/remote_cache/local_fs_backend.rb +439 -0
- data/lib/rspec_tracer/remote_cache/redis_backend.rb +554 -0
- data/lib/rspec_tracer/remote_cache/s3_backend.rb +712 -0
- data/lib/rspec_tracer/remote_cache/user_tasks.rb +436 -0
- data/lib/rspec_tracer/remote_cache/validator.rb +40 -62
- data/lib/rspec_tracer/remote_cache.rb +22 -0
- data/lib/rspec_tracer/reporters/README.md +103 -0
- data/lib/rspec_tracer/reporters/base.rb +87 -0
- data/lib/rspec_tracer/reporters/coverage_json_reporter.rb +338 -0
- data/lib/rspec_tracer/reporters/html/.gitignore +19 -0
- data/lib/rspec_tracer/reporters/html/.prettierignore +4 -0
- data/lib/rspec_tracer/reporters/html/.prettierrc.json +9 -0
- data/lib/rspec_tracer/reporters/html/README.md +80 -0
- data/lib/rspec_tracer/reporters/html/dist/assets/index.css +2 -0
- data/lib/rspec_tracer/reporters/html/dist/assets/index.js +1 -0
- data/lib/rspec_tracer/reporters/html/dist/index.html +24 -0
- data/lib/rspec_tracer/reporters/html/eslint.config.js +62 -0
- data/lib/rspec_tracer/reporters/html/package-lock.json +4941 -0
- data/lib/rspec_tracer/reporters/html/package.json +29 -0
- data/lib/rspec_tracer/reporters/html/src/app.jsx +130 -0
- data/lib/rspec_tracer/reporters/html/src/components/AllExamples.jsx +86 -0
- data/lib/rspec_tracer/reporters/html/src/components/DuplicateExamples.jsx +68 -0
- data/lib/rspec_tracer/reporters/html/src/components/ExamplesDependency.jsx +78 -0
- data/lib/rspec_tracer/reporters/html/src/components/FilesDependency.jsx +72 -0
- data/lib/rspec_tracer/reporters/html/src/components/FlakyExamples.jsx +42 -0
- data/lib/rspec_tracer/reporters/html/src/components/ReportTable.jsx +131 -0
- data/lib/rspec_tracer/reporters/html/src/components/SearchBar.jsx +19 -0
- data/lib/rspec_tracer/reporters/html/src/index.html +23 -0
- data/lib/rspec_tracer/reporters/html/src/main.jsx +37 -0
- data/lib/rspec_tracer/reporters/html/src/styles.css +434 -0
- data/lib/rspec_tracer/reporters/html/vite.config.js +42 -0
- data/lib/rspec_tracer/reporters/html_reporter.rb +266 -0
- data/lib/rspec_tracer/reporters/json_reporter.rb +88 -0
- data/lib/rspec_tracer/reporters/payload_builder.rb +235 -0
- data/lib/rspec_tracer/reporters/registry.rb +120 -0
- data/lib/rspec_tracer/reporters/terminal_reporter.rb +264 -0
- data/lib/rspec_tracer/rspec/README.md +73 -0
- data/lib/rspec_tracer/rspec/installation.rb +97 -0
- data/lib/rspec_tracer/rspec/metadata.rb +96 -0
- data/lib/rspec_tracer/rspec/parallel_tests.rb +459 -0
- data/lib/rspec_tracer/rspec/reporter_hook.rb +84 -0
- data/lib/rspec_tracer/rspec/runner_hook.rb +239 -0
- data/lib/rspec_tracer/source_file.rb +24 -7
- data/lib/rspec_tracer/storage/README.md +35 -0
- data/lib/rspec_tracer/storage/backend.rb +130 -0
- data/lib/rspec_tracer/storage/json_backend.rb +884 -0
- data/lib/rspec_tracer/storage/lazy_snapshot.rb +65 -0
- data/lib/rspec_tracer/storage/schema.rb +50 -0
- data/lib/rspec_tracer/storage/serializer/json.rb +41 -0
- data/lib/rspec_tracer/storage/serializer/msgpack.rb +167 -0
- data/lib/rspec_tracer/storage/snapshot.rb +141 -0
- data/lib/rspec_tracer/storage/sqlite_backend.rb +693 -0
- data/lib/rspec_tracer/time_formatter.rb +37 -18
- data/lib/rspec_tracer/tracker/README.md +36 -0
- data/lib/rspec_tracer/tracker/coverage_adapter.rb +174 -0
- data/lib/rspec_tracer/tracker/declared_globs.rb +100 -0
- data/lib/rspec_tracer/tracker/dependency_graph.rb +134 -0
- data/lib/rspec_tracer/tracker/env_matcher.rb +127 -0
- data/lib/rspec_tracer/tracker/env_snapshot.rb +77 -0
- data/lib/rspec_tracer/tracker/example_registry.rb +153 -0
- data/lib/rspec_tracer/tracker/file_digest.rb +61 -0
- data/lib/rspec_tracer/tracker/filter.rb +127 -0
- data/lib/rspec_tracer/tracker/input.rb +99 -0
- data/lib/rspec_tracer/tracker/io_hooks/file.rb +55 -0
- data/lib/rspec_tracer/tracker/io_hooks/io.rb +24 -0
- data/lib/rspec_tracer/tracker/io_hooks/json.rb +23 -0
- data/lib/rspec_tracer/tracker/io_hooks/kernel.rb +26 -0
- data/lib/rspec_tracer/tracker/io_hooks/yaml.rb +38 -0
- data/lib/rspec_tracer/tracker/io_hooks.rb +195 -0
- data/lib/rspec_tracer/tracker/loaded_files_tracker.rb +295 -0
- data/lib/rspec_tracer/tracker/new_file_detector.rb +62 -0
- data/lib/rspec_tracer/tracker/whole_suite_invalidators.rb +96 -0
- data/lib/rspec_tracer/version.rb +4 -1
- data/lib/rspec_tracer.rb +231 -491
- metadata +94 -43
- data/lib/rspec_tracer/cache.rb +0 -207
- data/lib/rspec_tracer/coverage_merger.rb +0 -42
- data/lib/rspec_tracer/coverage_reporter.rb +0 -187
- data/lib/rspec_tracer/coverage_writer.rb +0 -58
- data/lib/rspec_tracer/html_reporter/Rakefile +0 -18
- data/lib/rspec_tracer/html_reporter/assets/javascripts/application.js +0 -56
- data/lib/rspec_tracer/html_reporter/assets/javascripts/libraries/jquery.js +0 -10881
- data/lib/rspec_tracer/html_reporter/assets/javascripts/plugins/datatables.js +0 -15381
- data/lib/rspec_tracer/html_reporter/assets/stylesheets/application.css +0 -196
- data/lib/rspec_tracer/html_reporter/assets/stylesheets/plugins/datatables.css +0 -459
- data/lib/rspec_tracer/html_reporter/assets/stylesheets/plugins/jquery-ui.css +0 -436
- data/lib/rspec_tracer/html_reporter/assets/stylesheets/print.css +0 -92
- data/lib/rspec_tracer/html_reporter/assets/stylesheets/reset.css +0 -265
- data/lib/rspec_tracer/html_reporter/public/application.css +0 -5
- data/lib/rspec_tracer/html_reporter/public/application.js +0 -6
- data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_asc.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_asc_disabled.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_both.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_desc.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_desc_disabled.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/favicon.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/loading.gif +0 -0
- data/lib/rspec_tracer/html_reporter/reporter.rb +0 -242
- data/lib/rspec_tracer/html_reporter/views/duplicate_examples.erb +0 -34
- data/lib/rspec_tracer/html_reporter/views/examples.erb +0 -58
- data/lib/rspec_tracer/html_reporter/views/examples_dependency.erb +0 -36
- data/lib/rspec_tracer/html_reporter/views/files_dependency.erb +0 -36
- data/lib/rspec_tracer/html_reporter/views/flaky_examples.erb +0 -38
- data/lib/rspec_tracer/html_reporter/views/layout.erb +0 -38
- data/lib/rspec_tracer/remote_cache/aws.rb +0 -176
- data/lib/rspec_tracer/remote_cache/cache.rb +0 -75
- data/lib/rspec_tracer/remote_cache/repo.rb +0 -210
- data/lib/rspec_tracer/report_generator.rb +0 -158
- data/lib/rspec_tracer/report_merger.rb +0 -68
- data/lib/rspec_tracer/report_writer.rb +0 -141
- data/lib/rspec_tracer/reporter.rb +0 -204
- data/lib/rspec_tracer/rspec_reporter.rb +0 -41
- data/lib/rspec_tracer/rspec_runner.rb +0 -56
- data/lib/rspec_tracer/ruby_coverage.rb +0 -9
- data/lib/rspec_tracer/runner.rb +0 -278
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RSpecTracer
|
|
4
|
-
class Reporter
|
|
5
|
-
attr_reader :all_examples, :interrupted_examples, :duplicate_examples,
|
|
6
|
-
:possibly_flaky_examples, :flaky_examples, :pending_examples,
|
|
7
|
-
:skipped_examples, :failed_examples, :all_files, :modified_files,
|
|
8
|
-
:deleted_files, :dependency, :examples_coverage
|
|
9
|
-
|
|
10
|
-
attr_accessor :reverse_dependency, :last_run
|
|
11
|
-
|
|
12
|
-
def initialize
|
|
13
|
-
initialize_examples
|
|
14
|
-
initialize_files
|
|
15
|
-
initialize_dependency
|
|
16
|
-
initialize_coverage
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def register_example(example)
|
|
20
|
-
@all_examples[example[:example_id]] = example
|
|
21
|
-
@duplicate_examples[example[:example_id]] << example
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def deregister_duplicate_examples
|
|
25
|
-
@duplicate_examples.select! { |_, examples| examples.count > 1 }
|
|
26
|
-
|
|
27
|
-
return if @duplicate_examples.empty?
|
|
28
|
-
|
|
29
|
-
@all_examples.reject! { |example_id, _| @duplicate_examples.key?(example_id) }
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def on_example_skipped(example_id)
|
|
33
|
-
@skipped_examples << example_id
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def on_example_passed(example_id, result)
|
|
37
|
-
return if @duplicate_examples.key?(example_id)
|
|
38
|
-
|
|
39
|
-
@passed_examples << example_id
|
|
40
|
-
@all_examples[example_id][:execution_result] = formatted_execution_result(result)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def on_example_failed(example_id, result)
|
|
44
|
-
return if @duplicate_examples.key?(example_id)
|
|
45
|
-
|
|
46
|
-
@failed_examples << example_id
|
|
47
|
-
@all_examples[example_id][:execution_result] = formatted_execution_result(result)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def on_example_pending(example_id, result)
|
|
51
|
-
return if @duplicate_examples.key?(example_id)
|
|
52
|
-
|
|
53
|
-
@pending_examples << example_id
|
|
54
|
-
@all_examples[example_id][:execution_result] = formatted_execution_result(result)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def register_interrupted_examples
|
|
58
|
-
@all_examples.each_pair do |example_id, example|
|
|
59
|
-
next if example.key?(:execution_result)
|
|
60
|
-
|
|
61
|
-
@interrupted_examples << example_id
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
return if @interrupted_examples.empty?
|
|
65
|
-
|
|
66
|
-
RSpecTracer.logger.info "RSpec tracer is not processing #{@interrupted_examples.count} interrupted examples"
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def register_deleted_examples(seen_examples)
|
|
70
|
-
@deleted_examples = seen_examples.keys.to_set - (@skipped_examples | @all_examples.keys)
|
|
71
|
-
@deleted_examples -= @interrupted_examples
|
|
72
|
-
|
|
73
|
-
@deleted_examples.select! do |example_id|
|
|
74
|
-
example = seen_examples[example_id]
|
|
75
|
-
|
|
76
|
-
file_changed?(example[:file_name]) || file_changed?(example[:rerun_file_name])
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def register_possibly_flaky_example(example_id)
|
|
81
|
-
@possibly_flaky_examples << example_id
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def register_flaky_example(example_id)
|
|
85
|
-
@flaky_examples << example_id
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def register_failed_example(example_id)
|
|
89
|
-
@failed_examples << example_id
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def register_pending_example(example_id)
|
|
93
|
-
@pending_examples << example_id
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def duplicate_example?(example_id)
|
|
97
|
-
@duplicate_examples.key?(example_id)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def example_interrupted?(example_id)
|
|
101
|
-
@interrupted_examples.include?(example_id)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def example_passed?(example_id)
|
|
105
|
-
@passed_examples.include?(example_id)
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def example_skipped?(example_id)
|
|
109
|
-
@skipped_examples.include?(example_id)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def example_failed?(example_id)
|
|
113
|
-
@failed_examples.include?(example_id)
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def example_pending?(example_id)
|
|
117
|
-
@pending_examples.include?(example_id)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def example_deleted?(example_id)
|
|
121
|
-
@deleted_examples.include?(example_id)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def register_source_file(source_file)
|
|
125
|
-
@all_files[source_file[:file_name]] = source_file
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def on_file_deleted(file_name)
|
|
129
|
-
@deleted_files << file_name
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def on_file_modified(file_name)
|
|
133
|
-
@modified_files << file_name
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def file_deleted?(file_name)
|
|
137
|
-
@deleted_files.include?(file_name)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def file_modified?(file_name)
|
|
141
|
-
@modified_files.include?(file_name)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def file_changed?(file_name)
|
|
145
|
-
file_deleted?(file_name) || file_modified?(file_name)
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def register_dependency(example_id, file_name)
|
|
149
|
-
@dependency[example_id] << file_name
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def register_examples_coverage(examples_coverage)
|
|
153
|
-
@examples_coverage = examples_coverage
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
private
|
|
157
|
-
|
|
158
|
-
def initialize_examples
|
|
159
|
-
@all_examples = {}
|
|
160
|
-
@duplicate_examples = Hash.new { |examples, example_id| examples[example_id] = [] }
|
|
161
|
-
@interrupted_examples = Set.new
|
|
162
|
-
@passed_examples = Set.new
|
|
163
|
-
@possibly_flaky_examples = Set.new
|
|
164
|
-
@flaky_examples = Set.new
|
|
165
|
-
@failed_examples = Set.new
|
|
166
|
-
@skipped_examples = Set.new
|
|
167
|
-
@pending_examples = Set.new
|
|
168
|
-
@deleted_examples = Set.new
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
def initialize_files
|
|
172
|
-
@all_files = {}
|
|
173
|
-
@modified_files = Set.new
|
|
174
|
-
@deleted_files = Set.new
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def initialize_dependency
|
|
178
|
-
@dependency = Hash.new { |hash, key| hash[key] = Set.new }
|
|
179
|
-
@reverse_dependency = Hash.new do |examples, file_name|
|
|
180
|
-
examples[file_name] = {
|
|
181
|
-
example_count: 0,
|
|
182
|
-
examples: Hash.new(0)
|
|
183
|
-
}
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
def initialize_coverage
|
|
188
|
-
@examples_coverage = Hash.new do |examples, example_id|
|
|
189
|
-
examples[example_id] = Hash.new do |files, file_name|
|
|
190
|
-
files[file_name] = {}
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
def formatted_execution_result(result)
|
|
196
|
-
{
|
|
197
|
-
started_at: result.started_at.utc,
|
|
198
|
-
finished_at: result.finished_at.utc,
|
|
199
|
-
run_time: result.run_time,
|
|
200
|
-
status: result.status.to_s
|
|
201
|
-
}
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
end
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RSpecTracer
|
|
4
|
-
module RSpecReporter
|
|
5
|
-
def example_started(example)
|
|
6
|
-
RSpecTracer.coverage_reporter.record_coverage
|
|
7
|
-
RSpecTracer.start_example_trace
|
|
8
|
-
|
|
9
|
-
super
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def example_finished(example)
|
|
13
|
-
example_id = example.metadata[:rspec_tracer_example_id]
|
|
14
|
-
RSpecTracer.stop_example_trace(example_id)
|
|
15
|
-
RSpecTracer.coverage_reporter.compute_diff(example_id)
|
|
16
|
-
|
|
17
|
-
super
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def example_passed(example)
|
|
21
|
-
example_id = example.metadata[:rspec_tracer_example_id]
|
|
22
|
-
RSpecTracer.runner.on_example_passed(example_id, example.execution_result)
|
|
23
|
-
|
|
24
|
-
super
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def example_failed(example)
|
|
28
|
-
example_id = example.metadata[:rspec_tracer_example_id]
|
|
29
|
-
RSpecTracer.runner.on_example_failed(example_id, example.execution_result)
|
|
30
|
-
|
|
31
|
-
super
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def example_pending(example)
|
|
35
|
-
example_id = example.metadata[:rspec_tracer_example_id]
|
|
36
|
-
RSpecTracer.runner.on_example_pending(example_id, example.execution_result)
|
|
37
|
-
|
|
38
|
-
super
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RSpecTracer
|
|
4
|
-
module RSpecRunner
|
|
5
|
-
def run_specs(example_groups)
|
|
6
|
-
actual_count = RSpec.world.example_count
|
|
7
|
-
|
|
8
|
-
if _no_examples?(actual_count)
|
|
9
|
-
super
|
|
10
|
-
|
|
11
|
-
return
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
15
|
-
filtered_examples, filtered_example_groups = RSpecTracer.filter_examples
|
|
16
|
-
|
|
17
|
-
if _duplicate_examples?
|
|
18
|
-
super([])
|
|
19
|
-
|
|
20
|
-
return
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
RSpec.world.instance_variable_set(:@filtered_examples, filtered_examples)
|
|
24
|
-
RSpec.world.instance_variable_set(:@example_groups, filtered_example_groups)
|
|
25
|
-
|
|
26
|
-
current_count = RSpec.world.example_count
|
|
27
|
-
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
28
|
-
elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
|
|
29
|
-
|
|
30
|
-
RSpecTracer.logger.info <<-EXAMPLES.strip.gsub(/\s+/, ' ')
|
|
31
|
-
RSpec tracer is running #{current_count} examples (actual: #{actual_count},
|
|
32
|
-
skipped: #{actual_count - current_count}) (took #{elapsed})
|
|
33
|
-
EXAMPLES
|
|
34
|
-
|
|
35
|
-
RSpecTracer.running = true
|
|
36
|
-
|
|
37
|
-
super(filtered_example_groups)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def _no_examples?(actual_count)
|
|
41
|
-
return false unless actual_count.zero?
|
|
42
|
-
|
|
43
|
-
RSpecTracer.running = true
|
|
44
|
-
RSpecTracer.no_examples = true
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def _duplicate_examples?
|
|
48
|
-
return false if RSpecTracer.runner.reporter.duplicate_examples.empty?
|
|
49
|
-
|
|
50
|
-
RSpecTracer.report_writer.print_duplicate_examples
|
|
51
|
-
|
|
52
|
-
RSpecTracer.running = true
|
|
53
|
-
RSpecTracer.duplicate_examples = RSpecTracer.fail_on_duplicates
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
data/lib/rspec_tracer/runner.rb
DELETED
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'cache'
|
|
4
|
-
require_relative 'reporter'
|
|
5
|
-
|
|
6
|
-
module RSpecTracer
|
|
7
|
-
class Runner
|
|
8
|
-
EXAMPLE_RUN_REASON = {
|
|
9
|
-
explicit_run: 'Explicit run',
|
|
10
|
-
no_cache: 'No cache',
|
|
11
|
-
interrupted: 'Interrupted previously',
|
|
12
|
-
flaky_example: 'Flaky example',
|
|
13
|
-
failed_example: 'Failed previously',
|
|
14
|
-
pending_example: 'Pending previously',
|
|
15
|
-
files_changed: 'Files changed'
|
|
16
|
-
}.freeze
|
|
17
|
-
|
|
18
|
-
attr_reader :cache, :reporter
|
|
19
|
-
|
|
20
|
-
def initialize
|
|
21
|
-
@cache = RSpecTracer::Cache.new
|
|
22
|
-
@reporter = RSpecTracer::Reporter.new
|
|
23
|
-
@filtered_examples = {}
|
|
24
|
-
|
|
25
|
-
@cache.load_cache_for_run
|
|
26
|
-
filter_examples_to_run
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def run_example?(example_id)
|
|
30
|
-
return true if RSpecTracer.run_all_examples
|
|
31
|
-
|
|
32
|
-
!@cache.all_examples.key?(example_id) || @filtered_examples.key?(example_id)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def run_example_reason(example_id)
|
|
36
|
-
return EXAMPLE_RUN_REASON[:explicit_run] if RSpecTracer.run_all_examples
|
|
37
|
-
|
|
38
|
-
@filtered_examples[example_id] || EXAMPLE_RUN_REASON[:no_cache]
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def register_example(example)
|
|
42
|
-
@reporter.register_example(example)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def deregister_duplicate_examples
|
|
46
|
-
@reporter.deregister_duplicate_examples
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def on_example_skipped(example_id)
|
|
50
|
-
@reporter.on_example_skipped(example_id)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def on_example_passed(example_id, execution_result)
|
|
54
|
-
@reporter.on_example_passed(example_id, execution_result)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def on_example_failed(example_id, execution_result)
|
|
58
|
-
@reporter.on_example_failed(example_id, execution_result)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def on_example_pending(example_id, execution_result)
|
|
62
|
-
@reporter.on_example_pending(example_id, execution_result)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def register_interrupted_examples
|
|
66
|
-
@reporter.register_interrupted_examples
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def register_deleted_examples
|
|
70
|
-
@reporter.register_deleted_examples(@cache.all_examples)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
|
74
|
-
def generate_missed_coverage
|
|
75
|
-
missed_coverage = Hash.new do |files_coverage, file_path|
|
|
76
|
-
files_coverage[file_path] = Hash.new do |strength, line_number|
|
|
77
|
-
strength[line_number] = 0
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
(@cache.cached_examples_coverage || {}).each_pair do |example_id, example_coverage|
|
|
82
|
-
example_coverage.each_pair do |file_path, line_coverage|
|
|
83
|
-
next if @reporter.example_interrupted?(example_id) ||
|
|
84
|
-
@reporter.duplicate_example?(example_id)
|
|
85
|
-
|
|
86
|
-
next unless @reporter.example_skipped?(example_id)
|
|
87
|
-
|
|
88
|
-
file_name = RSpecTracer::SourceFile.file_name(file_path)
|
|
89
|
-
|
|
90
|
-
next if @reporter.file_deleted?(file_name)
|
|
91
|
-
|
|
92
|
-
line_coverage.each_pair do |line_number, strength|
|
|
93
|
-
missed_coverage[file_path][line_number] += strength || 0
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
missed_coverage
|
|
99
|
-
end
|
|
100
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
|
101
|
-
|
|
102
|
-
def register_dependency(examples_coverage)
|
|
103
|
-
filtered_files = Set.new
|
|
104
|
-
|
|
105
|
-
examples_coverage.each_pair do |example_id, example_coverage|
|
|
106
|
-
next if @reporter.example_interrupted?(example_id) ||
|
|
107
|
-
@reporter.duplicate_example?(example_id)
|
|
108
|
-
|
|
109
|
-
register_example_files_dependency(example_id)
|
|
110
|
-
|
|
111
|
-
example_coverage.each_key do |file_path|
|
|
112
|
-
next if filtered_files.include?(file_path)
|
|
113
|
-
|
|
114
|
-
filtered_files << file_path unless register_file_dependency(example_id, file_path)
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
@reporter.pending_examples.each do |example_id|
|
|
119
|
-
register_example_files_dependency(example_id)
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def register_traced_dependency(examples_traced_files)
|
|
124
|
-
rspec_required_files = fetch_rspec_required_files
|
|
125
|
-
|
|
126
|
-
examples_traced_files.each_pair do |example_id, traced_files|
|
|
127
|
-
required_files = traced_files | rspec_required_files
|
|
128
|
-
|
|
129
|
-
required_files.each { |file_path| register_file_dependency(example_id, file_path) }
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def register_examples_coverage(examples_coverage)
|
|
134
|
-
@reporter.register_examples_coverage(examples_coverage)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
private
|
|
138
|
-
|
|
139
|
-
def filter_examples_to_run
|
|
140
|
-
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
141
|
-
@changed_files = fetch_changed_files
|
|
142
|
-
|
|
143
|
-
filter_by_example_status
|
|
144
|
-
filter_by_files_changed
|
|
145
|
-
|
|
146
|
-
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
147
|
-
elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
|
|
148
|
-
|
|
149
|
-
RSpecTracer.logger.debug "RSpec tracer processed cache (took #{elapsed})"
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def filter_by_example_status
|
|
153
|
-
add_previously_interrupted_examples
|
|
154
|
-
add_previously_flaky_examples
|
|
155
|
-
add_previously_failed_examples
|
|
156
|
-
add_previously_pending_examples
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def filter_by_files_changed
|
|
160
|
-
@cache.dependency.each_pair do |example_id, files|
|
|
161
|
-
next if @filtered_examples.key?(example_id)
|
|
162
|
-
next unless @changed_files.intersect?(files)
|
|
163
|
-
|
|
164
|
-
@filtered_examples[example_id] = EXAMPLE_RUN_REASON[:files_changed]
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def add_previously_interrupted_examples
|
|
169
|
-
@cache.interrupted_examples.each do |example_id|
|
|
170
|
-
@filtered_examples[example_id] = EXAMPLE_RUN_REASON[:interrupted]
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def add_previously_flaky_examples
|
|
175
|
-
@cache.flaky_examples.each do |example_id|
|
|
176
|
-
@filtered_examples[example_id] = EXAMPLE_RUN_REASON[:flaky_example]
|
|
177
|
-
|
|
178
|
-
next unless @cache.dependency.key?(example_id)
|
|
179
|
-
next if @changed_files.intersect?(@cache.dependency[example_id])
|
|
180
|
-
|
|
181
|
-
@reporter.register_possibly_flaky_example(example_id)
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def add_previously_failed_examples
|
|
186
|
-
@cache.failed_examples.each do |example_id|
|
|
187
|
-
next if @filtered_examples.key?(example_id)
|
|
188
|
-
|
|
189
|
-
@filtered_examples[example_id] = EXAMPLE_RUN_REASON[:failed_example]
|
|
190
|
-
|
|
191
|
-
next unless @cache.dependency.key?(example_id)
|
|
192
|
-
next if @changed_files.intersect?(@cache.dependency[example_id])
|
|
193
|
-
|
|
194
|
-
@reporter.register_possibly_flaky_example(example_id)
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
def add_previously_pending_examples
|
|
199
|
-
@cache.pending_examples.each do |example_id|
|
|
200
|
-
@filtered_examples[example_id] = EXAMPLE_RUN_REASON[:pending_example]
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def fetch_changed_files
|
|
205
|
-
@cache.all_files.each_value do |cached_file|
|
|
206
|
-
file_name = cached_file[:file_name]
|
|
207
|
-
source_file = RSpecTracer::SourceFile.from_name(file_name)
|
|
208
|
-
|
|
209
|
-
if source_file.nil?
|
|
210
|
-
@reporter.on_file_deleted(file_name)
|
|
211
|
-
elsif cached_file[:digest] != source_file[:digest]
|
|
212
|
-
@reporter.on_file_modified(file_name)
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
@reporter.modified_files | @reporter.deleted_files
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
def fetch_rspec_required_files
|
|
220
|
-
rspec_root = RSpec::Core::RubyProject.root
|
|
221
|
-
rspec_path = RSpec.configuration.default_path
|
|
222
|
-
|
|
223
|
-
RSpec.configuration.requires.each_with_object([]) do |file_name, required_files|
|
|
224
|
-
file_name = "#{file_name}.rb" if File.extname(file_name).empty?
|
|
225
|
-
file_path = File.join(rspec_root, rspec_path, file_name)
|
|
226
|
-
|
|
227
|
-
required_files << file_path if File.file?(file_path)
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
def register_example_files_dependency(example_id)
|
|
232
|
-
return if @reporter.example_interrupted?(example_id) ||
|
|
233
|
-
@reporter.duplicate_example?(example_id)
|
|
234
|
-
|
|
235
|
-
example = @reporter.all_examples[example_id]
|
|
236
|
-
|
|
237
|
-
register_example_file_dependency(example_id, example[:file_name])
|
|
238
|
-
|
|
239
|
-
return if example[:rerun_file_name] == example[:file_name]
|
|
240
|
-
|
|
241
|
-
register_example_file_dependency(example_id, example[:rerun_file_name])
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
def register_example_file_dependency(example_id, file_name)
|
|
245
|
-
return if @reporter.example_interrupted?(example_id) ||
|
|
246
|
-
@reporter.duplicate_example?(example_id)
|
|
247
|
-
|
|
248
|
-
source_file = RSpecTracer::SourceFile.from_name(file_name)
|
|
249
|
-
|
|
250
|
-
if source_file.nil?
|
|
251
|
-
RSpecTracer.logger.debug "Skipping missing source file #{file_name} for example #{example_id}"
|
|
252
|
-
return
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
@reporter.register_source_file(source_file)
|
|
256
|
-
@reporter.register_dependency(example_id, file_name)
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
def register_file_dependency(example_id, file_path)
|
|
260
|
-
return if @reporter.example_interrupted?(example_id) ||
|
|
261
|
-
@reporter.duplicate_example?(example_id)
|
|
262
|
-
|
|
263
|
-
source_file = RSpecTracer::SourceFile.from_path(file_path)
|
|
264
|
-
|
|
265
|
-
if source_file.nil?
|
|
266
|
-
RSpecTracer.logger.debug "Skipping missing source file #{file_path} for example #{example_id}"
|
|
267
|
-
return false
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
return false if RSpecTracer.filters.any? { |filter| filter.match?(source_file) }
|
|
271
|
-
|
|
272
|
-
@reporter.register_source_file(source_file)
|
|
273
|
-
@reporter.register_dependency(example_id, source_file[:file_name])
|
|
274
|
-
|
|
275
|
-
true
|
|
276
|
-
end
|
|
277
|
-
end
|
|
278
|
-
end
|