knapsack_pro 5.6.0 → 6.0.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 +4 -4
- data/.circleci/config.yml +2 -0
- data/CHANGELOG.md +18 -0
- data/README.md +1 -1
- data/bin/test +15 -0
- data/knapsack_pro.gemspec +5 -5
- data/lib/knapsack_pro/adapters/base_adapter.rb +8 -0
- data/lib/knapsack_pro/adapters/rspec_adapter.rb +74 -44
- data/lib/knapsack_pro/base_allocator_builder.rb +6 -25
- data/lib/knapsack_pro/formatters/rspec_queue_summary_formatter.rb +6 -3
- data/lib/knapsack_pro/formatters/time_tracker.rb +161 -0
- data/lib/knapsack_pro/formatters/time_tracker_fetcher.rb +12 -0
- data/lib/knapsack_pro/presenter.rb +3 -2
- data/lib/knapsack_pro/report.rb +13 -9
- data/lib/knapsack_pro/runners/queue/rspec_runner.rb +25 -14
- data/lib/knapsack_pro/runners/rspec_runner.rb +19 -3
- data/lib/knapsack_pro/tracker.rb +1 -9
- data/lib/knapsack_pro/version.rb +1 -1
- data/lib/knapsack_pro.rb +0 -1
- data/spec/knapsack_pro/adapters/base_adapter_spec.rb +12 -0
- data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +143 -158
- data/spec/knapsack_pro/base_allocator_builder_spec.rb +22 -48
- data/spec/knapsack_pro/client/connection_spec.rb +54 -7
- data/spec/knapsack_pro/formatters/time_tracker_specs.rb +453 -0
- data/spec/knapsack_pro/runners/queue/rspec_runner_spec.rb +71 -32
- data/spec/knapsack_pro/runners/rspec_runner_spec.rb +2 -5
- data/spec/knapsack_pro/tracker_spec.rb +0 -21
- metadata +9 -7
- data/lib/knapsack_pro/extensions/time.rb +0 -9
- data/spec/knapsack_pro/extensions/time_spec.rb +0 -5
@@ -117,8 +117,8 @@ describe KnapsackPro::BaseAllocatorBuilder do
|
|
117
117
|
describe '#fast_and_slow_test_files_to_run' do
|
118
118
|
subject { allocator_builder.fast_and_slow_test_files_to_run }
|
119
119
|
|
120
|
-
context 'when
|
121
|
-
it do
|
120
|
+
context 'when split by test cases disabled' do
|
121
|
+
it 'returns test files to run based on test files on the disk' do
|
122
122
|
test_file_pattern = double
|
123
123
|
expect(KnapsackPro::TestFilePattern).to receive(:call).with(adapter_class).and_return(test_file_pattern)
|
124
124
|
|
@@ -129,70 +129,44 @@ describe KnapsackPro::BaseAllocatorBuilder do
|
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
|
-
context 'when
|
133
|
-
let(:adapter_class) { KnapsackPro::Adapters::RSpecAdapter }
|
132
|
+
context 'when split by test cases enabled' do
|
134
133
|
let(:test_files_to_run) { double }
|
135
|
-
let(:cmd) { 'RACK_ENV=test RAILS_ENV=test bundle exec rake knapsack_pro:rspec_test_example_detector' }
|
136
134
|
|
137
|
-
before
|
138
|
-
expect(
|
135
|
+
before do
|
136
|
+
expect(adapter_class).to receive(:split_by_test_cases_enabled?).and_return(true)
|
139
137
|
|
140
138
|
test_file_pattern = double
|
141
139
|
expect(KnapsackPro::TestFilePattern).to receive(:call).with(adapter_class).and_return(test_file_pattern)
|
142
140
|
|
143
141
|
expect(KnapsackPro::TestFileFinder).to receive(:call).with(test_file_pattern).and_return(test_files_to_run)
|
144
|
-
end
|
145
142
|
|
146
|
-
|
147
|
-
before do
|
148
|
-
stub_const('RSpec::Core::Version::STRING', '3.2.0')
|
149
|
-
end
|
150
|
-
|
151
|
-
it do
|
152
|
-
expect { subject }.to raise_error RuntimeError, 'RSpec >= 3.3.0 is required to split test files by test examples. Learn more: https://knapsackpro.com/perma/ruby/split-by-test-examples'
|
153
|
-
end
|
143
|
+
expect(allocator_builder).to receive(:get_slow_test_files).and_return(slow_test_files)
|
154
144
|
end
|
155
145
|
|
156
|
-
context 'when
|
157
|
-
let(:slow_test_files)
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
before do
|
164
|
-
expect(allocator_builder).to receive(:get_slow_test_files).and_return(slow_test_files)
|
165
|
-
|
166
|
-
expect(KnapsackPro).to receive(:logger).and_return(logger)
|
167
|
-
|
168
|
-
expect(Kernel).to receive(:system).with(cmd).and_return(cmd_result)
|
169
|
-
|
170
|
-
rspec_test_example_detector = instance_double(KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector)
|
171
|
-
expect(KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector).to receive(:new).and_return(rspec_test_example_detector)
|
172
|
-
expect(rspec_test_example_detector).to receive(:test_file_example_paths).and_return(test_file_example_paths)
|
173
|
-
|
174
|
-
expect(KnapsackPro::TestFilesWithTestCasesComposer).to receive(:call).with(test_files_to_run, slow_test_files, test_file_example_paths).and_return(test_files_with_test_cases)
|
146
|
+
context 'when slow test files are detected' do
|
147
|
+
let(:slow_test_files) do
|
148
|
+
[
|
149
|
+
'1_spec.rb',
|
150
|
+
'2_spec.rb',
|
151
|
+
]
|
175
152
|
end
|
176
153
|
|
177
|
-
it do
|
178
|
-
|
154
|
+
it 'returns test files with test cases' do
|
155
|
+
test_file_cases = double
|
156
|
+
expect(adapter_class).to receive(:test_file_cases_for).with(slow_test_files).and_return(test_file_cases)
|
157
|
+
|
158
|
+
test_files_with_test_cases = double
|
159
|
+
expect(KnapsackPro::TestFilesWithTestCasesComposer).to receive(:call).with(test_files_to_run, slow_test_files, test_file_cases).and_return(test_files_with_test_cases)
|
179
160
|
|
180
161
|
expect(subject).to eq test_files_with_test_cases
|
181
162
|
end
|
182
163
|
end
|
183
164
|
|
184
|
-
context 'when
|
185
|
-
let(:slow_test_files) {
|
186
|
-
let(:cmd_result) { false }
|
187
|
-
|
188
|
-
before do
|
189
|
-
expect(allocator_builder).to receive(:get_slow_test_files).and_return(slow_test_files)
|
190
|
-
|
191
|
-
expect(Kernel).to receive(:system).with(cmd).and_return(cmd_result)
|
192
|
-
end
|
165
|
+
context 'when slow test files are not detected' do
|
166
|
+
let(:slow_test_files) { [] }
|
193
167
|
|
194
|
-
it do
|
195
|
-
expect
|
168
|
+
it 'returns test files without test cases' do
|
169
|
+
expect(subject).to eq test_files_to_run
|
196
170
|
end
|
197
171
|
end
|
198
172
|
end
|
@@ -282,15 +282,17 @@ describe KnapsackPro::Client::Connection do
|
|
282
282
|
request_hash: request_hash)
|
283
283
|
end
|
284
284
|
let(:test_suite_token) { '3fa64859337f6e56409d49f865d13fd7' }
|
285
|
-
|
286
285
|
let(:connection) { described_class.new(action) }
|
287
|
-
|
288
|
-
|
289
|
-
stub_const('ENV', {
|
286
|
+
let(:headers) do
|
287
|
+
{
|
290
288
|
'KNAPSACK_PRO_ENDPOINT' => 'http://api.knapsackpro.test:3000',
|
291
289
|
'KNAPSACK_PRO_TEST_SUITE_TOKEN' => test_suite_token,
|
292
290
|
'GITHUB_ACTIONS' => 'true',
|
293
|
-
}
|
291
|
+
}
|
292
|
+
end
|
293
|
+
|
294
|
+
before do
|
295
|
+
stub_const('ENV', headers)
|
294
296
|
end
|
295
297
|
|
296
298
|
describe '#call' do
|
@@ -311,7 +313,7 @@ describe KnapsackPro::Client::Connection do
|
|
311
313
|
expect(http).to receive(:read_timeout=).with(15)
|
312
314
|
end
|
313
315
|
|
314
|
-
context 'when http method is POST' do
|
316
|
+
context 'when http method is POST on GitHub Actions' do
|
315
317
|
let(:http_method) { :post }
|
316
318
|
|
317
319
|
before do
|
@@ -334,7 +336,30 @@ describe KnapsackPro::Client::Connection do
|
|
334
336
|
end
|
335
337
|
end
|
336
338
|
|
337
|
-
context 'when http method is
|
339
|
+
context 'when http method is POST and CI is undetected' do
|
340
|
+
let(:http_method) { :post }
|
341
|
+
|
342
|
+
let(:headers) do
|
343
|
+
{
|
344
|
+
'KNAPSACK_PRO_ENDPOINT' => 'http://api.knapsackpro.test:3000',
|
345
|
+
'KNAPSACK_PRO_TEST_SUITE_TOKEN' => test_suite_token,
|
346
|
+
}
|
347
|
+
end
|
348
|
+
|
349
|
+
before do
|
350
|
+
expect(http).to receive(:post).with(
|
351
|
+
anything,
|
352
|
+
anything,
|
353
|
+
hash_not_including('KNAPSACK-PRO-CI-PROVIDER')
|
354
|
+
).and_return(http_response)
|
355
|
+
end
|
356
|
+
|
357
|
+
it_behaves_like 'when request got response from API' do
|
358
|
+
let(:expected_http_method) { 'POST' }
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
context 'when http method is GET on GitHub Actions' do
|
338
363
|
let(:http_method) { :get }
|
339
364
|
|
340
365
|
before do
|
@@ -358,6 +383,28 @@ describe KnapsackPro::Client::Connection do
|
|
358
383
|
end
|
359
384
|
end
|
360
385
|
|
386
|
+
context 'when http method is GET and CI is undetected' do
|
387
|
+
let(:http_method) { :get }
|
388
|
+
|
389
|
+
let(:headers) do
|
390
|
+
{
|
391
|
+
'KNAPSACK_PRO_ENDPOINT' => 'http://api.knapsackpro.test:3000',
|
392
|
+
'KNAPSACK_PRO_TEST_SUITE_TOKEN' => test_suite_token,
|
393
|
+
}
|
394
|
+
end
|
395
|
+
|
396
|
+
before do
|
397
|
+
expect(http).to receive(:get).with(
|
398
|
+
anything,
|
399
|
+
hash_not_including('KNAPSACK-PRO-CI-PROVIDER')
|
400
|
+
).and_return(http_response)
|
401
|
+
end
|
402
|
+
|
403
|
+
it_behaves_like 'when request got response from API' do
|
404
|
+
let(:expected_http_method) { 'GET' }
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
361
408
|
context 'when retry request for http method POST' do
|
362
409
|
let(:http_method) { :post }
|
363
410
|
|
@@ -0,0 +1,453 @@
|
|
1
|
+
# Named _specs.rb on purpose because it hangs if run as part of `bundle exec rspec`.
|
2
|
+
# Use `bundle exec ruby spec/knapsack_pro/formatters/time_tracker_specs.rb` instead.
|
3
|
+
|
4
|
+
require 'rspec/core'
|
5
|
+
require 'knapsack_pro'
|
6
|
+
require 'stringio'
|
7
|
+
require_relative '../../../lib/knapsack_pro/formatters/time_tracker'
|
8
|
+
|
9
|
+
class TestTimeTracker
|
10
|
+
def test_single_example
|
11
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
spec = <<~SPEC
|
16
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
17
|
+
it do
|
18
|
+
sleep 0.1
|
19
|
+
expect(1).to eq 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
SPEC
|
23
|
+
|
24
|
+
run_specs(spec) do |spec_paths, times|
|
25
|
+
raise unless times.size == 1
|
26
|
+
raise unless times[0]["path"] == spec_paths.first
|
27
|
+
raise unless times[0]["time_execution"] > 0.10
|
28
|
+
raise unless times[0]["time_execution"] < 0.15
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_two_files
|
33
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
34
|
+
false
|
35
|
+
end
|
36
|
+
|
37
|
+
spec_1 = <<~SPEC
|
38
|
+
describe "KnapsackPro::Formatters::TimeTracker 1" do
|
39
|
+
it do
|
40
|
+
sleep 0.1
|
41
|
+
expect(1).to eq 1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
SPEC
|
45
|
+
|
46
|
+
spec_2 = <<~SPEC
|
47
|
+
describe "KnapsackPro::Formatters::TimeTracker 2" do
|
48
|
+
it do
|
49
|
+
sleep 0.2
|
50
|
+
expect(1).to eq 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
SPEC
|
54
|
+
|
55
|
+
run_specs([spec_1, spec_2]) do |spec_paths, times|
|
56
|
+
raise unless times.size == 2
|
57
|
+
raise unless times.first["path"] == spec_paths.first
|
58
|
+
raise unless times.first["time_execution"] > 0.10
|
59
|
+
raise unless times.first["time_execution"] < 0.15
|
60
|
+
raise unless times.last["path"] == spec_paths.last
|
61
|
+
raise unless times.last["time_execution"] > 0.20
|
62
|
+
raise unless times.last["time_execution"] < 0.25
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_failing_example
|
67
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
68
|
+
false
|
69
|
+
end
|
70
|
+
|
71
|
+
spec = <<~SPEC
|
72
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
73
|
+
it do
|
74
|
+
sleep 0.1
|
75
|
+
expect(1).to eq 2
|
76
|
+
end
|
77
|
+
end
|
78
|
+
SPEC
|
79
|
+
|
80
|
+
run_specs(spec) do |spec_paths, times|
|
81
|
+
raise unless times.size == 1
|
82
|
+
raise unless times[0]["path"] == spec_paths.first
|
83
|
+
raise unless times[0]["time_execution"] > 0.10
|
84
|
+
raise unless times[0]["time_execution"] < 0.15
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_pending_example
|
89
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
90
|
+
false
|
91
|
+
end
|
92
|
+
|
93
|
+
spec = <<~SPEC
|
94
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
95
|
+
xit do
|
96
|
+
sleep 0.1
|
97
|
+
expect(1).to eq 2
|
98
|
+
end
|
99
|
+
end
|
100
|
+
SPEC
|
101
|
+
|
102
|
+
run_specs(spec) do |spec_paths, times|
|
103
|
+
raise unless times.size == 1
|
104
|
+
raise unless times[0]["path"] == spec_paths.first
|
105
|
+
raise unless times[0]["time_execution"] == 0.0
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_multiple_top_level_groups
|
110
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
111
|
+
false
|
112
|
+
end
|
113
|
+
|
114
|
+
spec = <<~SPEC
|
115
|
+
describe "KnapsackPro::Formatters::TimeTracker 1" do
|
116
|
+
it do
|
117
|
+
sleep 0.1
|
118
|
+
expect(1).to eq 1
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "KnapsackPro::Formatters::TimeTracker 2" do
|
123
|
+
it do
|
124
|
+
sleep 0.2
|
125
|
+
expect(1).to eq 1
|
126
|
+
end
|
127
|
+
end
|
128
|
+
SPEC
|
129
|
+
|
130
|
+
run_specs(spec) do |spec_paths, times|
|
131
|
+
raise unless times.size == 1
|
132
|
+
raise unless times[0]["path"] == spec_paths.first
|
133
|
+
raise unless times[0]["time_execution"] > 0.30
|
134
|
+
raise unless times[0]["time_execution"] < 0.35
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_rspec_split_by_test_example
|
139
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
140
|
+
true
|
141
|
+
end
|
142
|
+
|
143
|
+
spec = <<~SPEC
|
144
|
+
describe "KnapsackPro::Formatters::TimeTracker 1" do
|
145
|
+
it do
|
146
|
+
expect(1).to eq 1
|
147
|
+
end
|
148
|
+
|
149
|
+
it do
|
150
|
+
sleep 0.1
|
151
|
+
expect(1).to eq 1
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "KnapsackPro::Formatters::TimeTracker 2" do
|
156
|
+
it do
|
157
|
+
sleep 0.2
|
158
|
+
expect(1).to eq 1
|
159
|
+
end
|
160
|
+
|
161
|
+
it do
|
162
|
+
sleep 0.3
|
163
|
+
expect(1).to eq 1
|
164
|
+
end
|
165
|
+
end
|
166
|
+
SPEC
|
167
|
+
|
168
|
+
run_specs(spec) do |spec_paths, times|
|
169
|
+
raise unless times.size == 4
|
170
|
+
spec_path = spec_paths.first
|
171
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:1]" }["time_execution"] < 0.05
|
172
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:2]" }["time_execution"] > 0.10
|
173
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:2]" }["time_execution"] < 0.15
|
174
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[2:1]" }["time_execution"] > 0.20
|
175
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[2:1]" }["time_execution"] < 0.25
|
176
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[2:2]" }["time_execution"] > 0.30
|
177
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[2:2]" }["time_execution"] < 0.35
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_hooks
|
182
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
183
|
+
false
|
184
|
+
end
|
185
|
+
|
186
|
+
spec = <<~SPEC
|
187
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
188
|
+
before(:all) do
|
189
|
+
sleep 0.1
|
190
|
+
end
|
191
|
+
|
192
|
+
before(:each) do
|
193
|
+
sleep 0.1
|
194
|
+
end
|
195
|
+
|
196
|
+
after(:each) do
|
197
|
+
sleep 0.1
|
198
|
+
end
|
199
|
+
|
200
|
+
it do
|
201
|
+
expect(1).to eq 1
|
202
|
+
end
|
203
|
+
|
204
|
+
it do
|
205
|
+
expect(1).to eq 1
|
206
|
+
end
|
207
|
+
|
208
|
+
after(:all) do
|
209
|
+
sleep 0.1
|
210
|
+
end
|
211
|
+
end
|
212
|
+
SPEC
|
213
|
+
|
214
|
+
run_specs(spec) do |spec_paths, times|
|
215
|
+
raise unless times.size == 1
|
216
|
+
raise unless times[0]["path"] == spec_paths.first
|
217
|
+
raise unless times[0]["time_execution"] > 0.60
|
218
|
+
raise unless times[0]["time_execution"] < 0.65
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_hooks_with_rspec_split_by_test_example
|
223
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
224
|
+
true
|
225
|
+
end
|
226
|
+
|
227
|
+
spec = <<~SPEC
|
228
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
229
|
+
before(:all) do
|
230
|
+
sleep 0.1
|
231
|
+
end
|
232
|
+
|
233
|
+
before(:each) do
|
234
|
+
sleep 0.1
|
235
|
+
end
|
236
|
+
|
237
|
+
after(:each) do
|
238
|
+
sleep 0.1
|
239
|
+
end
|
240
|
+
|
241
|
+
it do
|
242
|
+
expect(1).to eq 1
|
243
|
+
end
|
244
|
+
|
245
|
+
it do
|
246
|
+
expect(1).to eq 1
|
247
|
+
end
|
248
|
+
|
249
|
+
after(:all) do
|
250
|
+
sleep 0.1
|
251
|
+
end
|
252
|
+
end
|
253
|
+
SPEC
|
254
|
+
|
255
|
+
run_specs(spec) do |spec_paths, times|
|
256
|
+
raise unless times.size == 2
|
257
|
+
spec_path = spec_paths.first
|
258
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:1]" }["time_execution"] > 0.40
|
259
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:1]" }["time_execution"] < 0.45
|
260
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:2]" }["time_execution"] > 0.40
|
261
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:2]" }["time_execution"] < 0.45
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def test_unknown_path
|
266
|
+
KnapsackPro::Formatters::TimeTracker.class_eval do
|
267
|
+
alias_method :original_file_path_for, :file_path_for
|
268
|
+
|
269
|
+
define_method(:file_path_for) do |_example|
|
270
|
+
""
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
spec = <<~SPEC
|
275
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
276
|
+
it do
|
277
|
+
expect(1).to eq 1
|
278
|
+
end
|
279
|
+
end
|
280
|
+
SPEC
|
281
|
+
|
282
|
+
run_specs(spec) do |spec_paths, times|
|
283
|
+
raise unless times.size == 2
|
284
|
+
raise unless times[0]["path"] == "UNKNOWN_PATH"
|
285
|
+
raise unless times[1]["path"] == spec_paths.first
|
286
|
+
end
|
287
|
+
|
288
|
+
ensure
|
289
|
+
KnapsackPro::Formatters::TimeTracker.class_eval do
|
290
|
+
undef :file_path_for
|
291
|
+
alias_method :file_path_for, :original_file_path_for
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_empty_group
|
296
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
297
|
+
false
|
298
|
+
end
|
299
|
+
|
300
|
+
spec = <<~SPEC
|
301
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
302
|
+
end
|
303
|
+
SPEC
|
304
|
+
|
305
|
+
run_specs(spec) do |spec_paths, times|
|
306
|
+
raise unless times.size == 1
|
307
|
+
raise unless times[0]["path"] == spec_paths.first
|
308
|
+
raise unless times[0]["time_execution"] == 0.0
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_duration
|
313
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
314
|
+
false
|
315
|
+
end
|
316
|
+
|
317
|
+
spec = <<~SPEC
|
318
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
319
|
+
it do
|
320
|
+
expect(1).to eq 1
|
321
|
+
end
|
322
|
+
end
|
323
|
+
SPEC
|
324
|
+
|
325
|
+
run_specs(spec) do |_, _, time_tracker|
|
326
|
+
raise unless time_tracker.duration > 0.0
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_batch_duration
|
331
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
332
|
+
false
|
333
|
+
end
|
334
|
+
|
335
|
+
spec = <<~SPEC
|
336
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
337
|
+
it do
|
338
|
+
expect(1).to eq 1
|
339
|
+
end
|
340
|
+
end
|
341
|
+
SPEC
|
342
|
+
|
343
|
+
run_specs(spec) do |_, _, time_tracker|
|
344
|
+
raise unless time_tracker.batch_duration > 0.0
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def test_unexecuted_test_files
|
349
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
350
|
+
false
|
351
|
+
end
|
352
|
+
|
353
|
+
spec = <<~SPEC
|
354
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
355
|
+
xit do
|
356
|
+
end
|
357
|
+
end
|
358
|
+
SPEC
|
359
|
+
|
360
|
+
run_specs(spec) do |spec_paths, _, time_tracker|
|
361
|
+
unexecuted_test_files = ["foo_spec.rb", "bar_spec.rb"]
|
362
|
+
# Need to filter because RSpec keeps accumulating state.
|
363
|
+
files = time_tracker
|
364
|
+
.unexecuted_test_files(spec_paths + unexecuted_test_files)
|
365
|
+
.filter { |file| spec_paths.include?(file) || unexecuted_test_files.include?(file) }
|
366
|
+
|
367
|
+
raise unless files.size == 3
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_subset
|
372
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
373
|
+
false
|
374
|
+
end
|
375
|
+
KnapsackPro::Formatters::TimeTracker.class_eval do
|
376
|
+
alias_method :original_stop, :stop
|
377
|
+
|
378
|
+
# In Regular Mode, #subset is called before #stop.
|
379
|
+
# This test makes #stop a noop to simulate that behavior.
|
380
|
+
define_method(:stop) do |_|
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
spec = <<~SPEC
|
385
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
386
|
+
it "works" do
|
387
|
+
sleep 0.1
|
388
|
+
expect(1).to eq 1
|
389
|
+
end
|
390
|
+
end
|
391
|
+
SPEC
|
392
|
+
|
393
|
+
run_specs(spec) do |spec_paths, times, time_tracker|
|
394
|
+
# Need to filter because RSpec keeps accumulating state.
|
395
|
+
files = time_tracker
|
396
|
+
.batch
|
397
|
+
.filter { |file| spec_paths.include?(file["path"]) }
|
398
|
+
|
399
|
+
raise unless files.size == 1
|
400
|
+
raise unless files[0]["path"] == spec_paths.first
|
401
|
+
raise unless files[0]["time_execution"] > 0.10
|
402
|
+
raise unless files[0]["time_execution"] < 0.15
|
403
|
+
end
|
404
|
+
|
405
|
+
ensure
|
406
|
+
KnapsackPro::Formatters::TimeTracker.class_eval do
|
407
|
+
undef :stop
|
408
|
+
alias_method :stop, :original_stop
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
private
|
413
|
+
|
414
|
+
def run_specs(specs)
|
415
|
+
paths = Array(specs).map.with_index do |spec, i|
|
416
|
+
path = "spec/knapsack_pro/formatters/#{i}_#{SecureRandom.uuid}_spec.rb"
|
417
|
+
File.open(path, 'w') { |file| file.write(spec) }
|
418
|
+
path
|
419
|
+
end
|
420
|
+
|
421
|
+
options = ::RSpec::Core::ConfigurationOptions.new([
|
422
|
+
"--format", KnapsackPro::Formatters::TimeTracker.to_s,
|
423
|
+
*paths,
|
424
|
+
])
|
425
|
+
runner = ::RSpec::Core::Runner.new(options)
|
426
|
+
runner.run(StringIO.new, StringIO.new)
|
427
|
+
|
428
|
+
time_tracker = runner.configuration.formatters.find { |f| f.class.to_s == KnapsackPro::Formatters::TimeTracker.to_s }
|
429
|
+
# Need to filter because RSpec keeps accumulating state.
|
430
|
+
times = time_tracker
|
431
|
+
.queue(paths)
|
432
|
+
.sort_by { |time| time["path"] }
|
433
|
+
.filter do |time|
|
434
|
+
paths.any? { |path| time["path"].start_with?(path) || time["path"] == "UNKNOWN_PATH" }
|
435
|
+
end
|
436
|
+
yield(paths, times, time_tracker)
|
437
|
+
|
438
|
+
ensure
|
439
|
+
paths.each { |path| File.delete(path) }
|
440
|
+
# Need to reset because RSpec keeps reusing the same instance.
|
441
|
+
time_tracker.instance_variable_set(:@queue, {}) if time_tracker
|
442
|
+
time_tracker.instance_variable_set(:@started, time_tracker.send(:now)) if time_tracker
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
TestTimeTracker
|
447
|
+
.instance_methods
|
448
|
+
.filter { |method| method.to_s.start_with?("test_") }
|
449
|
+
.shuffle
|
450
|
+
.each do |method|
|
451
|
+
puts method
|
452
|
+
TestTimeTracker.new.public_send(method)
|
453
|
+
end
|