knapsack_pro 3.8.0 → 7.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 +377 -23
- data/.github/dependabot.yml +11 -0
- data/.github/pull_request_template.md +22 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +325 -1
- data/Gemfile +9 -0
- data/README.md +3 -10
- data/bin/test +15 -0
- data/knapsack_pro.gemspec +7 -6
- data/lib/knapsack_pro/adapters/base_adapter.rb +17 -2
- data/lib/knapsack_pro/adapters/cucumber_adapter.rb +3 -3
- data/lib/knapsack_pro/adapters/minitest_adapter.rb +2 -0
- data/lib/knapsack_pro/adapters/rspec_adapter.rb +88 -49
- data/lib/knapsack_pro/adapters/spinach_adapter.rb +2 -0
- data/lib/knapsack_pro/adapters/test_unit_adapter.rb +2 -0
- data/lib/knapsack_pro/allocator.rb +2 -0
- data/lib/knapsack_pro/allocator_builder.rb +2 -0
- data/lib/knapsack_pro/base_allocator_builder.rb +8 -25
- data/lib/knapsack_pro/build_distribution_fetcher.rb +2 -0
- data/lib/knapsack_pro/client/api/action.rb +2 -0
- data/lib/knapsack_pro/client/api/v1/base.rb +2 -0
- data/lib/knapsack_pro/client/api/v1/build_distributions.rb +5 -0
- data/lib/knapsack_pro/client/api/v1/build_subsets.rb +2 -0
- data/lib/knapsack_pro/client/api/v1/queues.rb +6 -1
- data/lib/knapsack_pro/client/connection.rb +5 -6
- data/lib/knapsack_pro/config/ci/app_veyor.rb +18 -0
- data/lib/knapsack_pro/config/ci/base.rb +27 -0
- data/lib/knapsack_pro/config/ci/buildkite.rb +18 -0
- data/lib/knapsack_pro/config/ci/circle.rb +18 -0
- data/lib/knapsack_pro/config/ci/cirrus_ci.rb +18 -0
- data/lib/knapsack_pro/config/ci/codefresh.rb +18 -0
- data/lib/knapsack_pro/config/ci/codeship.rb +18 -0
- data/lib/knapsack_pro/config/ci/github_actions.rb +26 -0
- data/lib/knapsack_pro/config/ci/gitlab_ci.rb +20 -1
- data/lib/knapsack_pro/config/ci/heroku.rb +18 -0
- data/lib/knapsack_pro/config/ci/semaphore.rb +16 -0
- data/lib/knapsack_pro/config/ci/semaphore2.rb +19 -0
- data/lib/knapsack_pro/config/ci/travis.rb +18 -0
- data/lib/knapsack_pro/config/env.rb +46 -22
- data/lib/knapsack_pro/config/env_generator.rb +2 -0
- data/lib/knapsack_pro/config/temp_files.rb +8 -4
- data/lib/knapsack_pro/crypto/branch_encryptor.rb +2 -0
- data/lib/knapsack_pro/crypto/decryptor.rb +2 -0
- data/lib/knapsack_pro/crypto/digestor.rb +2 -0
- data/lib/knapsack_pro/crypto/encryptor.rb +2 -0
- data/lib/knapsack_pro/extensions/rspec_extension.rb +137 -0
- data/lib/knapsack_pro/formatters/rspec_json_formatter.rb +2 -0
- data/lib/knapsack_pro/formatters/time_tracker.rb +152 -0
- data/lib/knapsack_pro/formatters/time_tracker_fetcher.rb +20 -0
- data/lib/knapsack_pro/hooks/queue.rb +2 -0
- data/lib/knapsack_pro/logger_wrapper.rb +2 -0
- data/lib/knapsack_pro/mask_string.rb +9 -0
- data/lib/knapsack_pro/presenter.rb +6 -3
- data/lib/knapsack_pro/pure/queue/rspec_pure.rb +92 -0
- data/lib/knapsack_pro/queue_allocator.rb +2 -0
- data/lib/knapsack_pro/queue_allocator_builder.rb +2 -0
- data/lib/knapsack_pro/railtie.rb +2 -0
- data/lib/knapsack_pro/report.rb +15 -9
- data/lib/knapsack_pro/repository_adapter_initiator.rb +2 -0
- data/lib/knapsack_pro/repository_adapters/base_adapter.rb +2 -0
- data/lib/knapsack_pro/repository_adapters/env_adapter.rb +2 -0
- data/lib/knapsack_pro/repository_adapters/git_adapter.rb +50 -0
- data/lib/knapsack_pro/runners/base_runner.rb +2 -0
- data/lib/knapsack_pro/runners/cucumber_runner.rb +2 -0
- data/lib/knapsack_pro/runners/minitest_runner.rb +2 -0
- data/lib/knapsack_pro/runners/queue/base_runner.rb +29 -0
- data/lib/knapsack_pro/runners/queue/cucumber_runner.rb +9 -6
- data/lib/knapsack_pro/runners/queue/minitest_runner.rb +13 -6
- data/lib/knapsack_pro/runners/queue/rspec_runner.rb +128 -135
- data/lib/knapsack_pro/runners/rspec_runner.rb +22 -3
- data/lib/knapsack_pro/runners/spinach_runner.rb +2 -0
- data/lib/knapsack_pro/runners/test_unit_runner.rb +2 -0
- data/lib/knapsack_pro/slow_test_file_determiner.rb +2 -0
- data/lib/knapsack_pro/slow_test_file_finder.rb +2 -0
- data/lib/knapsack_pro/task_loader.rb +2 -0
- data/lib/knapsack_pro/test_case_detectors/rspec_test_example_detector.rb +2 -0
- data/lib/knapsack_pro/test_case_mergers/base_merger.rb +2 -0
- data/lib/knapsack_pro/test_case_mergers/rspec_merger.rb +2 -0
- data/lib/knapsack_pro/test_file_cleaner.rb +2 -0
- data/lib/knapsack_pro/test_file_finder.rb +2 -0
- data/lib/knapsack_pro/test_file_pattern.rb +2 -0
- data/lib/knapsack_pro/test_file_presenter.rb +2 -0
- data/lib/knapsack_pro/test_files_with_test_cases_composer.rb +2 -0
- data/lib/knapsack_pro/test_flat_distributor.rb +2 -0
- data/lib/knapsack_pro/tracker.rb +3 -3
- data/lib/knapsack_pro/urls.rb +4 -0
- data/lib/knapsack_pro/utils.rb +2 -0
- data/lib/knapsack_pro/version.rb +3 -1
- data/lib/knapsack_pro.rb +5 -3
- data/lib/tasks/cucumber.rake +2 -0
- data/lib/tasks/encrypted_branch_names.rake +2 -0
- data/lib/tasks/encrypted_test_file_names.rake +2 -0
- data/lib/tasks/minitest.rake +2 -0
- data/lib/tasks/queue/cucumber.rake +13 -0
- data/lib/tasks/queue/minitest.rake +13 -0
- data/lib/tasks/queue/rspec.rake +13 -0
- data/lib/tasks/rspec.rake +5 -0
- data/lib/tasks/salt.rake +2 -0
- data/lib/tasks/spinach.rake +2 -0
- data/lib/tasks/test_unit.rake +2 -0
- data/spec/integration/api/build_distributions_subset_spec.rb +1 -0
- data/spec/integration/runners/queue/rspec_runner.rb +80 -0
- data/spec/integration/runners/queue/rspec_runner_spec.rb +2232 -0
- data/spec/knapsack_pro/adapters/base_adapter_spec.rb +30 -11
- data/spec/knapsack_pro/adapters/cucumber_adapter_spec.rb +2 -5
- data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +146 -174
- data/spec/knapsack_pro/base_allocator_builder_spec.rb +22 -48
- data/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb +19 -27
- data/spec/knapsack_pro/client/api/v1/queues_spec.rb +23 -43
- data/spec/knapsack_pro/client/connection_spec.rb +59 -7
- data/spec/knapsack_pro/config/ci/app_veyor_spec.rb +22 -8
- data/spec/knapsack_pro/config/ci/base_spec.rb +1 -0
- data/spec/knapsack_pro/config/ci/buildkite_spec.rb +51 -16
- data/spec/knapsack_pro/config/ci/circle_spec.rb +48 -13
- data/spec/knapsack_pro/config/ci/cirrus_ci_spec.rb +12 -12
- data/spec/knapsack_pro/config/ci/codefresh_spec.rb +21 -6
- data/spec/knapsack_pro/config/ci/codeship_spec.rb +20 -6
- data/spec/knapsack_pro/config/ci/github_actions_spec.rb +37 -10
- data/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb +48 -13
- data/spec/knapsack_pro/config/ci/heroku_spec.rb +12 -12
- data/spec/knapsack_pro/config/ci/semaphore2_spec.rb +11 -11
- data/spec/knapsack_pro/config/ci/semaphore_spec.rb +12 -12
- data/spec/knapsack_pro/config/ci/travis_spec.rb +8 -8
- data/spec/knapsack_pro/config/env_spec.rb +204 -124
- data/spec/knapsack_pro/formatters/time_tracker_specs.rb +424 -0
- data/spec/knapsack_pro/hooks/queue_spec.rb +2 -2
- data/spec/knapsack_pro/presenter_spec.rb +1 -1
- data/spec/knapsack_pro/pure/queue/rspec_pure_spec.rb +224 -0
- data/spec/knapsack_pro/repository_adapters/git_adapter_spec.rb +72 -0
- data/spec/knapsack_pro/runners/queue/cucumber_runner_spec.rb +18 -16
- data/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb +17 -14
- data/spec/knapsack_pro/runners/rspec_runner_spec.rb +40 -23
- data/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb +1 -0
- data/spec/knapsack_pro/tracker_spec.rb +0 -4
- data/spec/knapsack_pro_spec.rb +3 -3
- data/spec/spec_helper.rb +0 -1
- metadata +26 -23
- data/lib/knapsack_pro/config/ci/snap_ci.rb +0 -35
- data/lib/knapsack_pro/config/ci/solano_ci.rb +0 -32
- data/lib/knapsack_pro/extensions/time.rb +0 -7
- data/lib/knapsack_pro/formatters/rspec_queue_profile_formatter_extension.rb +0 -56
- data/lib/knapsack_pro/formatters/rspec_queue_summary_formatter.rb +0 -112
- data/spec/knapsack_pro/config/ci/snap_ci_spec.rb +0 -104
- data/spec/knapsack_pro/config/ci/solano_ci_spec.rb +0 -73
- data/spec/knapsack_pro/extensions/time_spec.rb +0 -5
- data/spec/knapsack_pro/runners/queue/rspec_runner_spec.rb +0 -342
|
@@ -0,0 +1,424 @@
|
|
|
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 'tempfile'
|
|
8
|
+
require_relative '../../../lib/knapsack_pro/formatters/time_tracker'
|
|
9
|
+
|
|
10
|
+
class TestTimeTracker
|
|
11
|
+
def test_single_example
|
|
12
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
spec = <<~SPEC
|
|
17
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
|
18
|
+
it do
|
|
19
|
+
sleep 0.1
|
|
20
|
+
expect(1).to eq 1
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
SPEC
|
|
24
|
+
|
|
25
|
+
run_specs(spec) do |spec_paths, times|
|
|
26
|
+
raise unless times.size == 1
|
|
27
|
+
raise unless times[0]["path"] == spec_paths.first
|
|
28
|
+
raise unless times[0]["time_execution"] > 0.10
|
|
29
|
+
raise unless times[0]["time_execution"] < 0.15
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_two_files
|
|
34
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
35
|
+
false
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
spec_1 = <<~SPEC
|
|
39
|
+
describe "KnapsackPro::Formatters::TimeTracker 1" do
|
|
40
|
+
it do
|
|
41
|
+
sleep 0.1
|
|
42
|
+
expect(1).to eq 1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
SPEC
|
|
46
|
+
|
|
47
|
+
spec_2 = <<~SPEC
|
|
48
|
+
describe "KnapsackPro::Formatters::TimeTracker 2" do
|
|
49
|
+
it do
|
|
50
|
+
sleep 0.2
|
|
51
|
+
expect(1).to eq 1
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
SPEC
|
|
55
|
+
|
|
56
|
+
run_specs([spec_1, spec_2]) do |spec_paths, times|
|
|
57
|
+
raise unless times.size == 2
|
|
58
|
+
raise unless times.first["path"] == spec_paths.first
|
|
59
|
+
raise unless times.first["time_execution"] > 0.10
|
|
60
|
+
raise unless times.first["time_execution"] < 0.15
|
|
61
|
+
raise unless times.last["path"] == spec_paths.last
|
|
62
|
+
raise unless times.last["time_execution"] > 0.20
|
|
63
|
+
raise unless times.last["time_execution"] < 0.25
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def test_failing_example
|
|
68
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
69
|
+
false
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
spec = <<~SPEC
|
|
73
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
|
74
|
+
it do
|
|
75
|
+
sleep 0.1
|
|
76
|
+
expect(1).to eq 2
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
SPEC
|
|
80
|
+
|
|
81
|
+
run_specs(spec) do |spec_paths, times|
|
|
82
|
+
raise unless times.size == 1
|
|
83
|
+
raise unless times[0]["path"] == spec_paths.first
|
|
84
|
+
raise unless times[0]["time_execution"] > 0.10
|
|
85
|
+
raise unless times[0]["time_execution"] < 0.15
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def test_pending_example
|
|
90
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
91
|
+
false
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
spec = <<~SPEC
|
|
95
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
|
96
|
+
xit do
|
|
97
|
+
sleep 0.1
|
|
98
|
+
expect(1).to eq 2
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
SPEC
|
|
102
|
+
|
|
103
|
+
run_specs(spec) do |spec_paths, times|
|
|
104
|
+
raise unless times.size == 1
|
|
105
|
+
raise unless times[0]["path"] == spec_paths.first
|
|
106
|
+
raise unless times[0]["time_execution"] == 0.0
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_multiple_top_level_groups
|
|
111
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
112
|
+
false
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
spec = <<~SPEC
|
|
116
|
+
describe "KnapsackPro::Formatters::TimeTracker 1" do
|
|
117
|
+
it do
|
|
118
|
+
sleep 0.1
|
|
119
|
+
expect(1).to eq 1
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
describe "KnapsackPro::Formatters::TimeTracker 2" do
|
|
124
|
+
it do
|
|
125
|
+
sleep 0.2
|
|
126
|
+
expect(1).to eq 1
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
SPEC
|
|
130
|
+
|
|
131
|
+
run_specs(spec) do |spec_paths, times|
|
|
132
|
+
raise unless times.size == 1
|
|
133
|
+
raise unless times[0]["path"] == spec_paths.first
|
|
134
|
+
raise unless times[0]["time_execution"] > 0.30
|
|
135
|
+
raise unless times[0]["time_execution"] < 0.35
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def test_rspec_split_by_test_example
|
|
140
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
141
|
+
true
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
spec = <<~SPEC
|
|
145
|
+
describe "KnapsackPro::Formatters::TimeTracker 1" do
|
|
146
|
+
it do
|
|
147
|
+
expect(1).to eq 1
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it do
|
|
151
|
+
sleep 0.1
|
|
152
|
+
expect(1).to eq 1
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
describe "KnapsackPro::Formatters::TimeTracker 2" do
|
|
157
|
+
it do
|
|
158
|
+
sleep 0.2
|
|
159
|
+
expect(1).to eq 1
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it do
|
|
163
|
+
sleep 0.3
|
|
164
|
+
expect(1).to eq 1
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
SPEC
|
|
168
|
+
|
|
169
|
+
run_specs(spec) do |spec_paths, times|
|
|
170
|
+
raise unless times.size == 4
|
|
171
|
+
spec_path = spec_paths.first
|
|
172
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:1]" }["time_execution"] < 0.05
|
|
173
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:2]" }["time_execution"] > 0.10
|
|
174
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:2]" }["time_execution"] < 0.15
|
|
175
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[2:1]" }["time_execution"] > 0.20
|
|
176
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[2:1]" }["time_execution"] < 0.25
|
|
177
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[2:2]" }["time_execution"] > 0.30
|
|
178
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[2:2]" }["time_execution"] < 0.35
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def test_hooks
|
|
183
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
184
|
+
false
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
spec = <<~SPEC
|
|
188
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
|
189
|
+
before(:all) do
|
|
190
|
+
sleep 0.1
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
before(:each) do
|
|
194
|
+
sleep 0.1
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
after(:each) do
|
|
198
|
+
sleep 0.1
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it do
|
|
202
|
+
expect(1).to eq 1
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it do
|
|
206
|
+
expect(1).to eq 1
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
after(:all) do
|
|
210
|
+
sleep 0.1
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
SPEC
|
|
214
|
+
|
|
215
|
+
run_specs(spec) do |spec_paths, times|
|
|
216
|
+
raise unless times.size == 1
|
|
217
|
+
raise unless times[0]["path"] == spec_paths.first
|
|
218
|
+
raise unless times[0]["time_execution"] > 0.60
|
|
219
|
+
raise unless times[0]["time_execution"] < 0.65
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def test_hooks_with_rspec_split_by_test_example
|
|
224
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
225
|
+
true
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
spec = <<~SPEC
|
|
229
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
|
230
|
+
before(:all) do
|
|
231
|
+
sleep 0.1
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
before(:each) do
|
|
235
|
+
sleep 0.1
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
after(:each) do
|
|
239
|
+
sleep 0.1
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it do
|
|
243
|
+
expect(1).to eq 1
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it do
|
|
247
|
+
expect(1).to eq 1
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
after(:all) do
|
|
251
|
+
sleep 0.1
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
SPEC
|
|
255
|
+
|
|
256
|
+
run_specs(spec) do |spec_paths, times|
|
|
257
|
+
raise unless times.size == 2
|
|
258
|
+
spec_path = spec_paths.first
|
|
259
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:1]" }["time_execution"] > 0.40
|
|
260
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:1]" }["time_execution"] < 0.45
|
|
261
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:2]" }["time_execution"] > 0.40
|
|
262
|
+
raise unless times.find { |time| time["path"] == "#{spec_path}[1:2]" }["time_execution"] < 0.45
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def test_unknown_path
|
|
267
|
+
KnapsackPro::Formatters::TimeTracker.class_eval do
|
|
268
|
+
alias_method :original_file_path_for, :file_path_for
|
|
269
|
+
|
|
270
|
+
define_method(:file_path_for) do |_example|
|
|
271
|
+
""
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
spec = <<~SPEC
|
|
276
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
|
277
|
+
it do
|
|
278
|
+
expect(1).to eq 1
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
SPEC
|
|
282
|
+
|
|
283
|
+
run_specs(spec) do |spec_paths, times|
|
|
284
|
+
raise unless times.size == 1
|
|
285
|
+
raise unless times[0]["path"] == spec_paths.first
|
|
286
|
+
raise unless times[0]["time_execution"] == 0.0
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
ensure
|
|
290
|
+
KnapsackPro::Formatters::TimeTracker.class_eval do
|
|
291
|
+
undef :file_path_for
|
|
292
|
+
alias_method :file_path_for, :original_file_path_for
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def test_empty_group
|
|
297
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
298
|
+
false
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
spec = <<~SPEC
|
|
302
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
|
303
|
+
end
|
|
304
|
+
SPEC
|
|
305
|
+
|
|
306
|
+
run_specs(spec) do |spec_paths, times|
|
|
307
|
+
raise unless times.size == 1
|
|
308
|
+
raise unless times[0]["path"] == spec_paths.first
|
|
309
|
+
raise unless times[0]["time_execution"] == 0.0
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def test_duration
|
|
314
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
315
|
+
false
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
spec = <<~SPEC
|
|
319
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
|
320
|
+
it do
|
|
321
|
+
expect(1).to eq 1
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
SPEC
|
|
325
|
+
|
|
326
|
+
run_specs(spec) do |_, _, time_tracker|
|
|
327
|
+
raise unless time_tracker.duration > 0.0
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def test_unexecuted_test_files
|
|
332
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
333
|
+
false
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
spec = <<~SPEC
|
|
337
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
|
338
|
+
xit do
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
SPEC
|
|
342
|
+
|
|
343
|
+
run_specs(spec) do |spec_paths, _, time_tracker|
|
|
344
|
+
unexecuted_test_files = ["foo_spec.rb", "bar_spec.rb"]
|
|
345
|
+
# Need to filter because RSpec keeps accumulating state.
|
|
346
|
+
files = time_tracker
|
|
347
|
+
.unexecuted_test_files(spec_paths + unexecuted_test_files)
|
|
348
|
+
.filter { |file| spec_paths.include?(file) || unexecuted_test_files.include?(file) }
|
|
349
|
+
|
|
350
|
+
raise unless files.size == 3
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def test_subset
|
|
355
|
+
KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
|
|
356
|
+
false
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
spec = <<~SPEC
|
|
360
|
+
describe "KnapsackPro::Formatters::TimeTracker" do
|
|
361
|
+
it "works" do
|
|
362
|
+
sleep 0.1
|
|
363
|
+
expect(1).to eq 1
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
SPEC
|
|
367
|
+
|
|
368
|
+
run_specs(spec) do |spec_paths, times, time_tracker|
|
|
369
|
+
# Need to filter because RSpec keeps accumulating state.
|
|
370
|
+
files = time_tracker
|
|
371
|
+
.batch
|
|
372
|
+
.filter { |file| spec_paths.include?(file["path"]) }
|
|
373
|
+
|
|
374
|
+
raise unless files.size == 1
|
|
375
|
+
raise unless files[0]["path"] == spec_paths.first
|
|
376
|
+
raise unless files[0]["time_execution"] > 0.10
|
|
377
|
+
raise unless files[0]["time_execution"] < 0.15
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
private
|
|
382
|
+
|
|
383
|
+
def run_specs(specs)
|
|
384
|
+
files = Array(specs).map.with_index do |spec, i|
|
|
385
|
+
file = Tempfile.new(["time_tracker_#{i}", "_spec.rb"], "./spec/knapsack_pro/formatters/")
|
|
386
|
+
file.write(spec)
|
|
387
|
+
file.rewind
|
|
388
|
+
file
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
paths = files.map(&:path).map { _1.sub("./", "") }
|
|
392
|
+
|
|
393
|
+
options = ::RSpec::Core::ConfigurationOptions.new([
|
|
394
|
+
"--format", KnapsackPro::Formatters::TimeTracker.to_s,
|
|
395
|
+
*paths,
|
|
396
|
+
])
|
|
397
|
+
runner = ::RSpec::Core::Runner.new(options)
|
|
398
|
+
runner.run(StringIO.new, StringIO.new)
|
|
399
|
+
|
|
400
|
+
time_tracker = runner.configuration.formatters.find { |f| f.class.to_s == KnapsackPro::Formatters::TimeTracker.to_s }
|
|
401
|
+
# Need to filter because RSpec keeps accumulating state.
|
|
402
|
+
times = time_tracker
|
|
403
|
+
.queue(paths)
|
|
404
|
+
.sort_by { |time| time["path"] }
|
|
405
|
+
.filter do |time|
|
|
406
|
+
paths.any? { |path| time["path"].start_with?(path) }
|
|
407
|
+
end
|
|
408
|
+
yield(paths, times, time_tracker)
|
|
409
|
+
|
|
410
|
+
ensure
|
|
411
|
+
# Need to reset because RSpec keeps reusing the same instance.
|
|
412
|
+
time_tracker.instance_variable_set(:@queue, {}) if time_tracker
|
|
413
|
+
time_tracker.instance_variable_set(:@started, time_tracker.send(:now)) if time_tracker
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
TestTimeTracker
|
|
418
|
+
.instance_methods
|
|
419
|
+
.filter { |method| method.to_s.start_with?("test_") }
|
|
420
|
+
.shuffle
|
|
421
|
+
.each do |method|
|
|
422
|
+
puts method
|
|
423
|
+
TestTimeTracker.new.public_send(method)
|
|
424
|
+
end
|
|
@@ -93,8 +93,8 @@ describe KnapsackPro::Hooks::Queue do
|
|
|
93
93
|
let(:subset_queue_id) { double }
|
|
94
94
|
|
|
95
95
|
before do
|
|
96
|
-
expect(KnapsackPro::Config::Env).to receive(:queue_id).
|
|
97
|
-
expect(KnapsackPro::Config::Env).to receive(:subset_queue_id).
|
|
96
|
+
expect(KnapsackPro::Config::Env).to receive(:queue_id).at_least(:once).and_return(queue_id)
|
|
97
|
+
expect(KnapsackPro::Config::Env).to receive(:subset_queue_id).at_least(:once).and_return(subset_queue_id)
|
|
98
98
|
|
|
99
99
|
$expected_called_blocks = []
|
|
100
100
|
|
|
@@ -8,7 +8,7 @@ describe KnapsackPro::Presenter do
|
|
|
8
8
|
expect(KnapsackPro).to receive(:tracker).and_return(tracker)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
it { should eql "Global
|
|
11
|
+
it { should eql "Global test execution duration: 01h 02m 03s" }
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
describe '.pretty_seconds' do
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
require(KnapsackPro.root + '/lib/knapsack_pro/formatters/time_tracker')
|
|
2
|
+
require(KnapsackPro.root + '/lib/knapsack_pro/extensions/rspec_extension')
|
|
3
|
+
|
|
4
|
+
describe KnapsackPro::Pure::Queue::RSpecPure do
|
|
5
|
+
let(:rspec_pure) { described_class.new }
|
|
6
|
+
|
|
7
|
+
describe '#add_knapsack_pro_formatters_to' do
|
|
8
|
+
subject { rspec_pure.add_knapsack_pro_formatters_to(spec_opts) }
|
|
9
|
+
|
|
10
|
+
context 'when no spec_opts' do
|
|
11
|
+
let(:spec_opts) { nil }
|
|
12
|
+
|
|
13
|
+
it 'returns no spec_opts' do
|
|
14
|
+
expect(subject).to be nil
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context 'when spec_opts have Knapsack Pro formatters' do
|
|
19
|
+
let(:spec_opts) { '--color --format d --format KnapsackPro::Formatters::TimeTracker' }
|
|
20
|
+
|
|
21
|
+
it 'returns spec_opts' do
|
|
22
|
+
expect(subject).to eq spec_opts
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context 'when spec_opts have no Knapsack Pro formatters' do
|
|
27
|
+
let(:spec_opts) { '--color --format d' }
|
|
28
|
+
|
|
29
|
+
it 'returns spec_opts with added Knapsack Pro formatters' do
|
|
30
|
+
expect(subject).to eq '--color --format d --format KnapsackPro::Formatters::TimeTracker'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe '#error_exit_code' do
|
|
36
|
+
subject { rspec_pure.error_exit_code(rspec_error_exit_code) }
|
|
37
|
+
|
|
38
|
+
context 'when RSpec has no defined error exit code' do
|
|
39
|
+
let(:rspec_error_exit_code) { nil }
|
|
40
|
+
|
|
41
|
+
it 'returns 1 as the default exit code' do
|
|
42
|
+
expect(subject).to eq 1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context 'when RSpec has a defined error exit code' do
|
|
47
|
+
let(:rspec_error_exit_code) { 2 }
|
|
48
|
+
|
|
49
|
+
it 'returns the custom exit code' do
|
|
50
|
+
expect(subject).to eq rspec_error_exit_code
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe '#args_with_seed_option_added_when_viable' do
|
|
56
|
+
let(:order_option) { KnapsackPro::Adapters::RSpecAdapter.order_option(args) }
|
|
57
|
+
|
|
58
|
+
subject { rspec_pure.args_with_seed_option_added_when_viable(order_option, seed, args) }
|
|
59
|
+
|
|
60
|
+
context 'when the order option is not random' do
|
|
61
|
+
let(:args) { ['--order', 'defined'] }
|
|
62
|
+
let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: nil, used?: false) }
|
|
63
|
+
|
|
64
|
+
it 'does not add the seed option to args' do
|
|
65
|
+
expect(subject).to eq ['--order', 'defined']
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
['random', 'rand'].each do |random_option_value|
|
|
70
|
+
context "when the order option is `#{random_option_value}`" do
|
|
71
|
+
let(:args) { ['--order', random_option_value] }
|
|
72
|
+
|
|
73
|
+
context 'when the seed is not used' do
|
|
74
|
+
let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: '123', used?: false) }
|
|
75
|
+
|
|
76
|
+
it 'does not add the seed option to args' do
|
|
77
|
+
expect(subject).to eq ['--order', random_option_value]
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context 'when the seed is used' do
|
|
82
|
+
let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: '123', used?: true) }
|
|
83
|
+
|
|
84
|
+
it 'adds the seed option to args' do
|
|
85
|
+
expect(subject).to eq ['--order', random_option_value, '--seed', '123']
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context 'when the order option is `rand:123`' do
|
|
92
|
+
let(:args) { ['--order', 'rand:123'] }
|
|
93
|
+
let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: '123', used?: true) }
|
|
94
|
+
|
|
95
|
+
it 'does not add the seed option to args' do
|
|
96
|
+
expect(subject).to eq ['--order', 'rand:123']
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context 'when the order option is not set in args AND seed is used' do
|
|
101
|
+
let(:args) { ['--format', 'documentation'] }
|
|
102
|
+
let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: '123', used?: true) }
|
|
103
|
+
|
|
104
|
+
it 'adds the seed option to args' do
|
|
105
|
+
expect(subject).to eq ['--format', 'documentation', '--seed', '123']
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
context 'when the order option is not set in args AND seed is not used' do
|
|
110
|
+
let(:args) { ['--format', 'documentation'] }
|
|
111
|
+
let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: '123', used?: false) }
|
|
112
|
+
|
|
113
|
+
it 'does not add the seed option to args' do
|
|
114
|
+
expect(subject).to eq ['--format', 'documentation']
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe '#prepare_cli_args' do
|
|
120
|
+
subject { rspec_pure.prepare_cli_args(args, has_format_option, test_dir) }
|
|
121
|
+
|
|
122
|
+
context 'when no args' do
|
|
123
|
+
let(:args) { nil }
|
|
124
|
+
let(:has_format_option) { false }
|
|
125
|
+
let(:test_dir) { 'spec' }
|
|
126
|
+
|
|
127
|
+
it 'adds the default progress formatter and the default path and the time tracker formatter' do
|
|
128
|
+
expect(subject).to eq [
|
|
129
|
+
'--format', 'progress',
|
|
130
|
+
'--default-path', 'spec',
|
|
131
|
+
'--format', 'KnapsackPro::Formatters::TimeTracker',
|
|
132
|
+
]
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
context 'when args are present and a custom test directory is set' do
|
|
137
|
+
let(:args) { '--color --profile' }
|
|
138
|
+
let(:has_format_option) { false }
|
|
139
|
+
let(:test_dir) { 'custom_spec_dir' }
|
|
140
|
+
|
|
141
|
+
it do
|
|
142
|
+
expect(subject).to eq [
|
|
143
|
+
'--color',
|
|
144
|
+
'--profile',
|
|
145
|
+
'--format', 'progress',
|
|
146
|
+
'--default-path', 'custom_spec_dir',
|
|
147
|
+
'--format', 'KnapsackPro::Formatters::TimeTracker',
|
|
148
|
+
]
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
context 'when args are present and has format option' do
|
|
153
|
+
let(:args) { '--color --profile --format d' }
|
|
154
|
+
let(:has_format_option) { true }
|
|
155
|
+
let(:test_dir) { 'spec' }
|
|
156
|
+
|
|
157
|
+
it 'uses the format option from args instead of the default formatter' do
|
|
158
|
+
expect(subject).to eq [
|
|
159
|
+
'--color',
|
|
160
|
+
'--profile',
|
|
161
|
+
'--format', 'd',
|
|
162
|
+
'--default-path', 'spec',
|
|
163
|
+
'--format', 'KnapsackPro::Formatters::TimeTracker',
|
|
164
|
+
]
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
describe '#rspec_command' do
|
|
170
|
+
let(:args) { ['--format', 'documentation'] }
|
|
171
|
+
let(:test_file_paths) { ['a_spec.rb', 'b_spec.rb'] }
|
|
172
|
+
|
|
173
|
+
subject { rspec_pure.rspec_command(args, test_file_paths, scope) }
|
|
174
|
+
|
|
175
|
+
context 'when there are no test file paths' do
|
|
176
|
+
let(:scope) { :queue_finished }
|
|
177
|
+
let(:test_file_paths) { [] }
|
|
178
|
+
|
|
179
|
+
it 'returns no messages' do
|
|
180
|
+
expect(subject).to eq []
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
context 'when a subset of queue (a batch of tests fetched from the Queue API)' do
|
|
185
|
+
let(:scope) { :batch_finished }
|
|
186
|
+
|
|
187
|
+
it 'returns messages with the RSpec command' do
|
|
188
|
+
expect(subject).to eq([
|
|
189
|
+
'To retry the last batch of tests fetched from the Queue API, please run the following command on your machine:',
|
|
190
|
+
'bundle exec rspec --format documentation "a_spec.rb" "b_spec.rb"',
|
|
191
|
+
])
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
context 'when all tests fetched from the Queue API' do
|
|
196
|
+
let(:scope) { :queue_finished }
|
|
197
|
+
|
|
198
|
+
it 'returns messages with the RSpec command' do
|
|
199
|
+
expect(subject).to eq([
|
|
200
|
+
'To retry all the tests assigned to this CI node, please run the following command on your machine:',
|
|
201
|
+
'bundle exec rspec --format documentation "a_spec.rb" "b_spec.rb"',
|
|
202
|
+
])
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
describe '#exit_summary' do
|
|
207
|
+
subject { rspec_pure.exit_summary(unexecuted_test_files) }
|
|
208
|
+
|
|
209
|
+
context 'when there are no unexecuted test files' do
|
|
210
|
+
let(:unexecuted_test_files) { [] }
|
|
211
|
+
|
|
212
|
+
it { expect(subject).to be_nil }
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
context 'when there are unexecuted test files' do
|
|
216
|
+
let(:unexecuted_test_files) { ['b_spec.rb', 'c_spec.rb'] }
|
|
217
|
+
|
|
218
|
+
it 'returns a warning message' do
|
|
219
|
+
expect(subject).to eq 'Unexecuted tests on this CI node (including pending tests): b_spec.rb c_spec.rb'
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|